save work

This commit is contained in:
Scott Richmond 2025-06-29 11:38:45 -04:00
parent f710beff46
commit 4dd47dd56c
2 changed files with 141 additions and 106 deletions

View File

@ -142,12 +142,12 @@ A few thoughts:
* That will get me a lot of the way there. What's left after that which might be challenging? * That will get me a lot of the way there. What's left after that which might be challenging?
- [x] string interpolation - [x] string interpolation
- [x] splats - [x] splats
- [ ] splatterns - [x] splatterns
- [x] string patterns - [x] string patterns
- [x] partial application - [x] partial application
- [ ] tail calls - [x] tail calls
- [ ] stack traces in panics - [-] stack traces in panics
- [ ] actually good lexing, parsing, and validation errors. I got some of the way there in the fall, but everything needs to be "good enough." - [-] actually good lexing, parsing, and validation errors. I got some of the way there in the fall, but everything needs to be "good enough."
* After that, we're in integration hell: taking this thing and putting it together for Computer Class 1. Other things that I want (e.g., `test` forms) are for later on. * After that, we're in integration hell: taking this thing and putting it together for Computer Class 1. Other things that I want (e.g., `test` forms) are for later on.
* There's then a whole host of things I'll need to get done for CC2: * There's then a whole host of things I'll need to get done for CC2:
- some kind of actual parsing strategy (that's good enough for "Dissociated Press"/Markov chains) - some kind of actual parsing strategy (that's good enough for "Dissociated Press"/Markov chains)
@ -243,41 +243,41 @@ To reiterate the punch list that *I would have needed for Computer Class 1*:
* [x] jump instructions need 16 bits of operand * [x] jump instructions need 16 bits of operand
- Whew, that took longer than I expected - Whew, that took longer than I expected
* [x] splatterns * [x] splatterns
- [ ] validator should ensure splatterns are the longest patterns in a form - [-] validator should ensure splatterns are the longest patterns in a form
* [ ] improve validator * [-] improve validator
- [ ] Tuples may not be longer than n members - [-] Tuples may not be longer than n members
- [ ] Loops may not have splatterns - [-] Loops may not have splatterns
- [ ] Identify others - [-] Identify others
* [x] add guards to loop forms * [x] add guards to loop forms
* [x] check loop forms against function calls: do they still work the way we want them to? * [x] check loop forms against function calls: do they still work the way we want them to?
* [x] tail call elimination * [x] tail call elimination
* [x] stack traces in panics * [x] stack traces in panics
* [ ] actually good error messages * [-] actually good error messages
- [ ] parsing - [-] parsing
- [ ] my memory is that validator messages are already good? - [-] my memory is that validator messages are already good?
- [ ] panics, esp. no match panics - [-] panics, esp. no match panics
* [ ] getting to prelude * [-] getting to prelude
- [ ] `base` should load into Prelude - [-] `base` should load into Prelude
- [ ] prelude should run properly - [-] prelude should run properly
- [ ] prelude should be loaded into every context - [-] prelude should be loaded into every context
* [ ] packaging things up * [-] packaging things up
- [ ] add a `to_json` method for values - [-] add a `to_json` method for values
- [ ] teach Rudus to speak our protocols (stdout and turtle graphics) - [-] teach Rudus to speak our protocols (stdout and turtle graphics)
- [ ] there should be a Rust function that takes Ludus source and returns valid Ludus status json - [-] there should be a Rust function that takes Ludus source and returns valid Ludus status json
- [ ] compile Rust to WASM - [-] compile Rust to WASM
- [ ] wire Rust-based WASM into JS - [-] wire Rust-based WASM into JS
- [ ] FINALLY, test Rudus against Ludus test cases - [-] FINALLY, test Rudus against Ludus test cases
So this is the work of the week of June 16, maybe? So this is the work of the week of June 16, maybe?
Just trying to get a sense of what needs to happen for CC2: Just trying to get a sense of what needs to happen for CC2:
* [ ] Actor model (objects, Spacewar!) * [x] Actor model (objects, Spacewar!)
* [ ] Animation hooked into the web frontend (Spacewar!) * [-] Animation hooked into the web frontend (Spacewar!)
* [ ] Text input (Spacewar!) * [-] Text input (Spacewar!)
- [ ] Makey makey for alternate input? - [-] Makey makey for alternate input?
* [ ] Saving and loading data into Ludus (perceptrons, dissociated press) * [-] Saving and loading data into Ludus (perceptrons, dissociated press)
* [ ] Finding corpuses for Dissociated Press * [-] Finding corpuses for Dissociated Press
### Final touches on semantics, or lots of bugs ### Final touches on semantics, or lots of bugs
#### 2025-06-19 #### 2025-06-19
@ -309,32 +309,32 @@ So this is my near-term TODO:
- [x] `base` should load into Prelude - [x] `base` should load into Prelude
- [x] write a mock prelude with a few key functions from real prelude - [x] write a mock prelude with a few key functions from real prelude
- [x] a prelude should be loaded into every context - [x] a prelude should be loaded into every context
- [ ] the full prelude should run properly - [?] the full prelude should run properly
* [ ] packaging things up * [x] packaging things up
- [ ] add a `to_json` method for values - [x] add a `to_json` method for values
- [ ] teach Rudus to speak our protocols (stdout and turtle graphics) - [x] teach Rudus to speak our protocols (stdout and turtle graphics)
- [ ] there should be a Rust function that takes Ludus source and returns valid Ludus status json - [x] there should be a Rust function that takes Ludus source and returns valid Ludus status json
- [ ] compile Rust to WASM - [x] compile Rust to WASM
- [ ] wire Rust-based WASM into JS - [x] wire Rust-based WASM into JS
- [ ] FINALLY, test Rudus against Ludus test cases - [-] FINALLY, test Rudus against Ludus test cases
And then: quality of life improvements: And then: quality of life improvements:
* [ ] refactor messes * [-] refactor messes
- [ ] The compiler should abstract over some of the very titchy bytecode instruction code - [x] The compiler should abstract over some of the very titchy bytecode instruction code
- [ ] Pull apart some gargantuan modules into smaller chunks: e.g., `Op` and `Chunk` should be their own modules - [x] Pull apart some gargantuan modules into smaller chunks: e.g., `Op` and `Chunk` should be their own modules
- [ ] Identify code smells - [x] Identify code smells
- [ ] Fix some of them - [x] Fix some of them
* [ ] improve validator * [-] improve validator
- [ ] Tuples may not be longer than n members - [-] Tuples may not be longer than n members
- [ ] Loops may not have splatterns - [-] Loops may not have splatterns
- [ ] Identify others - [-] Identify others
- [ ] Splats in functions must be the same arity, and greater than any explicit arity - [-] Splats in functions must be the same arity, and greater than any explicit arity
* [ ] actually good error messages * [-] actually good error messages
- [ ] parsing - [-] parsing
- [ ] my memory is that validator messages are already good? - [-] my memory is that validator messages are already good?
- [ ] panics, esp. no match panics - [-] panics, esp. no match panics
* [ ] panics should be able to refernce the line number where they fail * [-] panics should be able to refernce the line number where they fail
* [ ] that suggests that we need a mapping from bytecodes to AST nodes * [-] that suggests that we need a mapping from bytecodes to AST nodes
* The way I had been planning on doing this is having a vec that moves in lockstep with bytecode that's just references to ast nodes, which are `'static`, so that shouldn't be too bad. But this is per-chunk, which means we need a reference to that vec in the VM. My sense is that what we want is actually a separate data structure that holds the AST nodes--we'll only need them in the sad path, which can be slow. * The way I had been planning on doing this is having a vec that moves in lockstep with bytecode that's just references to ast nodes, which are `'static`, so that shouldn't be too bad. But this is per-chunk, which means we need a reference to that vec in the VM. My sense is that what we want is actually a separate data structure that holds the AST nodes--we'll only need them in the sad path, which can be slow.
### Bugs discovered while trying to compile prelude ### Bugs discovered while trying to compile prelude
@ -381,15 +381,15 @@ So here's a short punch list of things to do in that register:
* [x] Hook validator back in to both source AND prelude code * [x] Hook validator back in to both source AND prelude code
- [x] Validator should know about the environment for global/prelude function - [x] Validator should know about the environment for global/prelude function
- [x] Run validator on current prelude to fix current known errors - [x] Run validator on current prelude to fix current known errors
* [ ] Do what it takes to compile this interpreter into Ludus's JS environment * [x] Do what it takes to compile this interpreter into Ludus's JS environment
- [ ] JSONify Ludus values - [x] JSONify Ludus values
- [ ] Write a function that's source code to JSON result - [x] Write a function that's source code to JSON result
- [ ] Expose this to a WASM compiler - [x] Expose this to a WASM compiler
- [ ] Patch this into a JS file - [x] Patch this into a JS file
- [ ] Automate this build process - [-] Automate this build process
* [ ] Start testing against the cases in `ludus-test` * [-] Start testing against the cases in `ludus-test`
* [ ] Systematically debug prelude * [-] Systematically debug prelude
- [ ] Bring it in function by function, testing each in turn - [-] Bring it in function by function, testing each in turn
*** ***
I've started working on systematically going through the Prelude. I've started working on systematically going through the Prelude.
@ -486,19 +486,19 @@ I may be surprised, though.
Currently fixing little bugs in prelude. Currently fixing little bugs in prelude.
Here's a list of things that need doing: Here's a list of things that need doing:
* [ ] Escape characters in strings: \n, \t, and \{, \}. * [-] Escape characters in strings: \n, \t, and \{, \}.
* [ ] `doc!` needs to print the patterns of a function. * [-] `doc!` needs to print the patterns of a function.
* [ ] I need to return to the question of whether/how strings are ordered; do we use `at`, or do we want `char_at`? etc. * [-] I need to return to the question of whether/how strings are ordered; do we use `at`, or do we want `char_at`? etc.
* [ ] Original implementation of `butlast` is breaking stack discipline; I don't know why. It ends up returning from evaluating one of the arguments straight into a `load` instruction. Something about tail calls and ternary synthetic expressions and base functions. (For now, I can call `slice` instead of `base :slice` and it works.) * [-] Original implementation of `butlast` is breaking stack discipline; I don't know why. It ends up returning from evaluating one of the arguments straight into a `load` instruction. Something about tail calls and ternary synthetic expressions and base functions. (For now, I can call `slice` instead of `base :slice` and it works.)
- Original version of `update` also had this same problem with `assoc`; fixed it by calling the Ludus, rather than Rust, function. - Original version of `update` also had this same problem with `assoc`; fixed it by calling the Ludus, rather than Rust, function.
- I need this fixed for optimization reasons. - I need this fixed for optimization reasons.
- I _think_ I just fixed this by fixing tail position tracking in collections - I _think_ I just fixed this by fixing tail position tracking in collections
- [ ] test this - [-] test this
- I did not fix it. - I did not fix it.
* [x] Dict patterns are giving me stack discipline grief. Why is stack discipline so hard? * [x] Dict patterns are giving me stack discipline grief. Why is stack discipline so hard?
* [ ] This is in the service of getting turtle graphics working * [x] This is in the service of getting turtle graphics working
* Other forms in the language need help: * Other forms in the language need help:
* [ ] repeat needs its stack discipline updated, it currently crashes the compiler * xx] repeat needs its stack discipline updated, it currently crashes the compiler
### More closure problems ### More closure problems
#### 2025-06-23 #### 2025-06-23
@ -738,13 +738,13 @@ println!("line {line_no}: {}", lines[line_no - 1]);
#### 2025-06-25 #### 2025-06-25
* Web workers * Web workers
* My javascript wrapper needs to execute WASM in its own thread (ugh) * 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)? - [-] is this a thing that can be done easily in a platform-independent way (node vs. bun vs. browser)?
* Top priorities: * Top priorities:
- [ ] Get a node package out - [-] Get a node package out
- [ ] Stand up actors + threads, etc. - [-] Stand up actors + threads, etc.
- [ ] How to model keyboard input from p5? - [-] How to model keyboard input from p5?
* [ ] Model after the p5 keyboard input API * [-] Model after the p5 keyboard input API
* [ ] ludus keyboard API: `key_is_down(), key_pressed(), key_released()`, key code values (use a dict) * [-] ludus keyboard API: `key_is_down(), key_pressed(), key_released()`, key code values (use a dict)
- Assets: - Assets:
* We don't (for now) need to worry about serialization formats, since we're not doing perceptrons * 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. * We do need to read from URLs, which need in a *.ludus.dev.
@ -827,11 +827,11 @@ But everything else? Seems pretty straightforward.
I've implemented what I decribe above. It works! I'm low-key astonished. I've implemented what I decribe above. It works! I'm low-key astonished.
It perfectly handles an infinitely recurring process! What the fuck. It perfectly handles an infinitely recurring process! What the fuck.
Anyway, things left to do: Anyway, things left to do:
* [ ] `receive` forms are the big one: they require threading through the whole interpreter * [x] `receive` forms are the big one: they require threading through the whole interpreter
* [x] implement the missing process functions at the end of prelude * [x] implement the missing process functions at the end of prelude
* [ ] research how Elixir/Erlang's abstractions over processes work (I'm especially interested in how to make synchronous-looking calls); take a look especially at https://medium.com/qixxit-development/build-your-own-genserver-in-49-lines-of-code-1a9db07b6f13 * [-] research how Elixir/Erlang's abstractions over processes work (I'm especially interested in how to make synchronous-looking calls); take a look especially at https://medium.com/qixxit-development/build-your-own-genserver-in-49-lines-of-code-1a9db07b6f13
* [ ] write some examples just using these simple tools (not even GenServer, etc.) to see how they work, and to start building curriculum * [-] write some examples just using these simple tools (not even GenServer, etc.) to see how they work, and to start building curriculum
* [ ] develop a design for how to deal with asynchronous io with js * [-] develop a design for how to deal with asynchronous io with js
```ludus ```ludus
fn agent/get (pid) -> { fn agent/get (pid) -> {
@ -870,7 +870,7 @@ Two things that pop out to me:
### Rethinking reception ### Rethinking reception
#### 2025-06-27 #### 2025-06-27
So one thing that's stuck with me is that in Elixir, `receive` isn't a special form: it's a function that takes a block. So one thing that's stuck with me is that in Elixir, ~`receive` isn't a special form: it's a function that takes a block~ (**EDIT**: it is indeed a special form in Elixir, and it has to be on in Ludus.).
It may be a macro, but it's still mostly normalish, and doesn't invovle compiler shenanigans. It may be a macro, but it's still mostly normalish, and doesn't invovle compiler shenanigans.
So, this is what I want to write: So, this is what I want to write:
@ -955,7 +955,7 @@ So the flushing would need to happen in the receiver.
A few things that are wrong right now: A few things that are wrong right now:
* [ ] `loop`/`recur` is still giving me a very headache. It breaks stack discipline to avoid packing tuples into a heap-allocated vec. There may be a way to fix this in the current compiler scheme around how I do and don't handle arguments--make recur stupider and don't bother loading anything. A different solution would be to desugar loop into an anonymous function call. A final solution would be just to use a heap-allocated tuple. * [-] `loop`/`recur` is still giving me a very headache. It breaks stack discipline to avoid packing tuples into a heap-allocated vec. There may be a way to fix this in the current compiler scheme around how I do and don't handle arguments--make recur stupider and don't bother loading anything. A different solution would be to desugar loop into an anonymous function call. A final solution would be just to use a heap-allocated tuple.
Minimal failing case: Minimal failing case:
```ludus ```ludus
@ -965,16 +965,19 @@ match (nil) with {
} }
} }
``` ```
* [ ] The amount of sugar needed to get to `receive` without making a special form is too great. * [x] The amount of sugar needed to get to `receive` without making a special form is too great.
In particular, function arities need to be changed, flushes need to be inserted, anonymous lambdas need to be created (which can't be multi-clause), etc. In particular, function arities need to be changed, flushes need to be inserted, anonymous lambdas need to be created (which can't be multi-clause), etc.
~* [ ] There was another bug that I was going to write down and fix, but I forgot what it was. Something with processes.~ _This is now implemented._
* [ ] I remembered: I got some weird behaviour when `MAX_REDUCTIONS` was set to 100; I've increased it to 1000, but now need to test what happens when we yield because of reductions.
* [ ] Also: the `butlast` bug is still outstanding: `base :slice` causes a panic in that function, but not the call to the Ludus function. Still have to investigate that one. ~* [-] There was another bug that I was going to write down and fix, but I forgot what it was. Something with processes.~
* [-] I remembered: I got some weird behaviour when `MAX_REDUCTIONS` was set to 100; I've increased it to 1000, but now need to test what happens when we yield because of reductions.
* [ ] In testing this, it's looking like `match` is misbehaving; none of the matches that *should* happen in my fully sugarless `receive` testing are matching how they ought. * [-] Also: the `butlast` bug is still outstanding: `base :slice` causes a panic in that function, but not the call to the Ludus function. Still have to investigate that one.
* [x] In testing this, it's looking like `match` is misbehaving; none of the matches that *should* happen in my fully sugarless `receive` testing are matching how they ought.
- That is not what was happening. The mailbox
I haven't got to a minimal case, but here's what's not working: I haven't got to a minimal case, but here's what's not working:
```ludus ```ludus
@ -1098,3 +1101,47 @@ Here's some pseudobytecode to get us to where we need to be:
090 jump to 025 (not really in bytecode; this will be unrolled) 090 jump to 025 (not really in bytecode; this will be unrolled)
100 receive end 100 receive end
#### a short time later
Well, that worked! The real issue was the jump back if we're out of messages.
That leaves the following list:
* [a] research how Elixir/Erlang's abstractions over processes work (I'm especially interested in how to make synchronous-looking calls); take a look especially at https://medium.com/qixxit-development/build-your-own-genserver-in-49-lines-of-code-1a9db07b6f13
* [ ] write some examples just using these simple tools (not even GenServer, etc.) to see how they work, and to start building curriculum
* [a] develop a design for how to deal with asynchronous io with js
* [a] I got some weird behaviour when `MAX_REDUCTIONS` was set to 100; I've increased it to 1000, but now need to test what happens when we yield because of reductions.
* [a] Also: the `butlast` bug is still outstanding: `base :slice` causes a panic in that function, but not the call to the Ludus function. Still have to investigate that one.
- Original version of `update` also had this same problem with `assoc`; fixed it by calling the Ludus, rather than Rust, function.
* [a] `loop`/`recur` is still giving me a very headache. It breaks stack discipline to avoid packing tuples into a heap-allocated vec. There may be a way to fix this in the current compiler scheme around how I do and don't handle arguments--make recur stupider and don't bother loading anything. A different solution would be to desugar loop into an anonymous function call. A final solution would be just to use a heap-allocated tuple.
* 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
- [x] 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)
* [a] Escape characters in strings: \n, \t, and \{, \}.
* [ ] `doc!` needs to print the patterns of a function.
* [ ] I need to return to the question of whether/how strings are ordered; do we use `at`, or do we want `char_at`? etc.
* [ ] Automate this build process
* [ ] Start testing against the cases in `ludus-test`
* [ ] Systematically debug prelude
- [ ] Bring it in function by function, testing each in turn
* [ ] Animation hooked into the web frontend (Spacewar!)
* [ ] Text input (Spacewar!)
- [ ] Makey makey for alternate input?
* [ ] Saving and loading data into Ludus (perceptrons, dissociated press)
* [ ] Finding corpuses for Dissociated Press
* [ ] improve validator
- [ ] Tuples may not be longer than n members
- [ ] Loops may not have splatterns
- [ ] Identify others
- [ ] Splats in functions must be the same arity, and greater than any explicit arity
* [ ] actually good error messages
- [ ] parsing
- [ ] my memory is that validator messages are already good?
- [ ] panics, esp. no match panics
* [ ] panics should be able to refernce the line number where they fail
* [ ] that suggests that we need a mapping from bytecodes to AST nodes
* The way I had been planning on doing this is having a vec that moves in lockstep with bytecode that's just references to ast nodes, which are `'static`, so that shouldn't be too bad. But this is per-chunk, which means we need a reference to that vec in the VM. My sense is that what we want is actually a separate data structure that holds the AST nodes--we'll only need them in the sad path, which can be slow.

View File

@ -1222,30 +1222,18 @@ impl Creature {
NextMessage => { NextMessage => {
self.msg_idx += 1; self.msg_idx += 1;
} }
LoadMessage => { LoadMessage => match self.mbx.get(self.msg_idx) {
println!("loading message {} in {}", self.msg_idx, self.pid); Some(msg) => self.push(msg.clone()),
match self.mbx.get(self.msg_idx) {
Some(msg) => {
println!("loaded message: {msg}");
self.push(msg.clone())
}
None => { None => {
println!("no more messages in {}", self.pid);
self.msg_idx = 0; self.msg_idx = 0;
self.r#yield = true; self.r#yield = true;
self.ip -= 2; self.ip -= 2;
} }
} },
}
MatchMessage => { MatchMessage => {
let matched = self.mbx.remove(self.msg_idx).unwrap(); let matched = self.mbx.remove(self.msg_idx).unwrap();
println!(
"matched in {}: @idx {}, msg {matched}",
self.pid, self.msg_idx
);
} }
ClearMessage => { ClearMessage => {
println!("clearing messages in {}", self.pid);
self.msg_idx = 0; self.msg_idx = 0;
} }
} }