From 87e58364e06fdd90249dda32d60a615170485379 Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Wed, 25 Jun 2025 13:34:59 -0400 Subject: [PATCH] meet with mnl --- may_2025_thoughts.md | 234 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) diff --git a/may_2025_thoughts.md b/may_2025_thoughts.md index ca7bc86..da2b546 100644 --- a/may_2025_thoughts.md +++ b/may_2025_thoughts.md @@ -522,4 +522,238 @@ SOLUTION: test to see if the function has been forward-declared, and if it has, NEW PROBLEM: a lot of instructions in the VM don't properly offset from the call frame's stack base, which leads to weirdness when doing things inside function calls. NEW SOLUTION: create a function that does the offset properly, and replace everywhere we directly access the stack. +<<<<<<< Updated upstream This is the thing I am about to do +||||||| Stash base +This is the thing I am about to do. + +### I think the interpreter, uh, works? +#### 2025-06-24 +I'm sure I'll find some small problems. +But right now the thing works. +At the moment, I'm thinking about how to get good error messages. +Panics are difficult. +And I'm worried about ariadne as the error reporting crate. +Since it writes to stdout, it has all kinds of escape codes. +I need a plain ass string, at least for the web frontend. +So. + +Current task, however, is how to get reasonable panic error messages. +Let's simplify the problem. + +First, let's get tracebacks and line numbers. +We use Chumsky spanned ASTs. +The span is just a range into an str. +What I can do is pretty stupidly just generate line numbers from the spans in the compiler, and from there, get a reasonable traceback. +So instead of using Ariadne's fancy report builder, let's just do something more what we already have here: + +``` +Ludus panicked! no match + on line 1 in input, + calling: add + with arguments: ("foo") + expected match with one of: + () + (x as :number) + (x as :number, y as :number) + (x, y, ...zs) + ((x1, y1), (x2, y2)) + >>> add ("foo") +......^ +``` +We need: +* the location of the function call in terms of the line number +* the arguments used +* the patterns expected to match (special cases: `let` vs `match` vs `fn`) + +That means, for bookkeeping, we need: +* In the compiler, line number +* In the VM, the arguments +* In the VM, the pattern AST node. + +In Janet-Ludus, there are only a few types of panic: +* `fn-no-match`: no match against a function call +* `let-no-match`: no match against a `let` binding +* `match-no-match`: no match against a `match` form +* `generic-panic`: everything else +* `runtime-error`: an internal Ludus error + +The first three are simply formatting differences. +There are no tracebacks. + +Tracebacks should be easy enough, although there's some fiddly bits. +While it's nice to have the carret, the brutalist attempt here should be just to give us the line--since the carret isn't exactly precise in the Janet interpereter. +And the traceback should look something like: + +``` + calling foo with (:bar, :baz) + at line 12 in input + calling bar with () + at line 34 in prelude + calling baz with (1, 2, 3) + at line 12 in input +``` + +Which means, again: function names, ip->line conversion, and arguments. + +The runtime needs a representation of the patterns in _any_ matching form. +The speed is so much greater now that I'm not so concerned about little optimizations. +So: a chunk needs a vec of patterns-representations. (I'm thinking simply a `Vec`.) +So does a function, for `doc!`. +Same same re: `Vec`. +A VM needs a register for the scrutinee (which with function calls is just the arguments, already captured). +A VM also needs a register for the pattern. +So when there's a no match, we just yank the pattern and the scrutinee out of these registers. + +This all seems very straightforward compared to the compiling & VM stuff. + +Here's some stub code I wrote for dealing with ranges, source, line numbers: + +```rust +let str = "foo bar baz\nquux frob\nthing thing thing"; +let range = 0..4; + +println!("{}", str.get(range).unwrap()); + +let lines: Vec<&str> = str.split_terminator("\n").collect(); + +println!("{:?}", lines); + +let idx = 20; + +let mut line_no = 1; +for i in 0..idx { + if str.chars().nth(i).unwrap() == '\n' { + line_no += 1; + } +} + +println!("line {line_no}: {}", lines[line_no - 1]); +``` + + +======= +This is the thing I am about to do. + +### I think the interpreter, uh, works? +#### 2025-06-24 +I'm sure I'll find some small problems. +But right now the thing works. +At the moment, I'm thinking about how to get good error messages. +Panics are difficult. +And I'm worried about ariadne as the error reporting crate. +Since it writes to stdout, it has all kinds of escape codes. +I need a plain ass string, at least for the web frontend. +So. + +Current task, however, is how to get reasonable panic error messages. +Let's simplify the problem. + +First, let's get tracebacks and line numbers. +We use Chumsky spanned ASTs. +The span is just a range into an str. +What I can do is pretty stupidly just generate line numbers from the spans in the compiler, and from there, get a reasonable traceback. +So instead of using Ariadne's fancy report builder, let's just do something more what we already have here: + +``` +Ludus panicked! no match + on line 1 in input, + calling: add + with arguments: ("foo") + expected match with one of: + () + (x as :number) + (x as :number, y as :number) + (x, y, ...zs) + ((x1, y1), (x2, y2)) + >>> add ("foo") +......^ +``` +We need: +* the location of the function call in terms of the line number +* the arguments used +* the patterns expected to match (special cases: `let` vs `match` vs `fn`) + +That means, for bookkeeping, we need: +* In the compiler, line number +* In the VM, the arguments +* In the VM, the pattern AST node. + +In Janet-Ludus, there are only a few types of panic: +* `fn-no-match`: no match against a function call +* `let-no-match`: no match against a `let` binding +* `match-no-match`: no match against a `match` form +* `generic-panic`: everything else +* `runtime-error`: an internal Ludus error + +The first three are simply formatting differences. +There are no tracebacks. + +Tracebacks should be easy enough, although there's some fiddly bits. +While it's nice to have the carret, the brutalist attempt here should be just to give us the line--since the carret isn't exactly precise in the Janet interpereter. +And the traceback should look something like: + +``` + calling foo with (:bar, :baz) + at line 12 in input + calling bar with () + at line 34 in prelude + calling baz with (1, 2, 3) + at line 12 in input +``` + +Which means, again: function names, ip->line conversion, and arguments. + +The runtime needs a representation of the patterns in _any_ matching form. +The speed is so much greater now that I'm not so concerned about little optimizations. +So: a chunk needs a vec of patterns-representations. (I'm thinking simply a `Vec`.) +So does a function, for `doc!`. +Same same re: `Vec`. +A VM needs a register for the scrutinee (which with function calls is just the arguments, already captured). +A VM also needs a register for the pattern. +So when there's a no match, we just yank the pattern and the scrutinee out of these registers. + +This all seems very straightforward compared to the compiling & VM stuff. + +Here's some stub code I wrote for dealing with ranges, source, line numbers: + +```rust +let str = "foo bar baz\nquux frob\nthing thing thing"; +let range = 0..4; + +println!("{}", str.get(range).unwrap()); + +let lines: Vec<&str> = str.split_terminator("\n").collect(); + +println!("{:?}", lines); + +let idx = 20; + +let mut line_no = 1; +for i in 0..idx { + if str.chars().nth(i).unwrap() == '\n' { + line_no += 1; + } +} + +println!("line {line_no}: {}", lines[line_no - 1]); +``` + +### Integration meeting with mnl +#### 2025-06-25 +* Web workers +* My javascript wrapper needs to execute WASM in its own thread (ugh) + - [ ] is this a thing that can be done easily in a platform-independent way (node vs. bun vs. browser)? +* Top priorities: + - [ ] Get a node package out + - [ ] Stand up actors + threads, etc. + - [ ] How to model keyboard input from p5? + * [ ] Model after the p5 keyboard input API + * [ ] ludus keyboard API: `key_is_down(), key_pressed(), key_released()`, key code values (use a dict) + - Assets: + * We don't (for now) need to worry about serialization formats, since we're not doing perceptrons + * We do need to read from URLs, which need in a *.ludus.dev. + * Users can create their own (public) repos and put stuff in there. + * We still want saving text output from web Ludus + * Later, with perceptrons & the book, we'll need additional solutions. +>>>>>>> Stashed changes