Compare commits

..

2 Commits

Author SHA1 Message Date
Scott Richmond
f09caabfcb wip: sorting out diect pattern stack discipline 2025-06-23 00:38:51 -04:00
Scott Richmond
e4b385d2fb fix tail position in collection forms 2025-06-23 00:27:50 -04:00
4 changed files with 57 additions and 12 deletions

View File

@ -492,4 +492,7 @@ Here's a list of things that need doing:
* [ ] 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
- [ ] test this
* [ ] Dict patterns are giving me stack discipline grief. Why is stack discipline so hard?

View File

@ -1,3 +1,40 @@
let #{a, b, ...} = #{:a 1, :b 2, :c 3} & let state = #{:position (0, 0), :heading 0, :pencolor :white}
& let command = (:forward, 10)
& match command with {
& (:goto, (x, y)) -> assoc (state, :position, (x, y))
& & (:home) -> do state >
& & assoc (_, :position, (0, 0)) >
& & assoc (_, :heading, 0)
& & (:clear) -> do state >
& & assoc (state, :position, (0, 0)) >
& & assoc (_, :heading, 0)
& (:right, turns) -> update (state, :heading, add (_, turns))
& (:left, turns) -> update (state, :heading, sub (_, turns))
& (:forward, steps) -> {
& let #{heading, position, ...} = state
& let unit = heading/vector (heading)
& let vect = mult (steps, unit)
& update (state, :position, add (vect, _))
& }
& (:back, steps) -> {
& let #{heading, position, ...} = state
& let unit = heading/vector (heading)
& let vect = mult (steps, unit)
& update (state, :position, sub (_, vect))
& }
& & (:penup) -> assoc (state, :pendown?, false)
& & (:pendown) -> assoc (state, :pendown?, true)
& & (:penwidth, pixels) -> assoc (state, :penwidth, pixels)
& & (:pencolor, color) -> assoc (state, :pencolor, color)
& & (:setheading, heading) -> assoc (state, :heading, heading)
& & (:loadstate, position, heading, visible?, pendown?, penwidth, pencolor) -> #{position, heading, visible?, pendown?, penwidth, pencolor}
& & (:show) -> assoc (state, :visible?, true)
& & (:hide) -> assoc (state, :visible?, false)
& & (:background, _) -> state
& }
let foo = #{:a 1, :b 2, :c 3}
let #{a, b, ...c} = foo
(a, b)

View File

@ -739,9 +739,9 @@ impl<'a> Compiler<'a> {
self.patch_jump(idx, self.len() - idx - 3); self.patch_jump(idx, self.len() - idx - 3);
} }
self.pop_n(pairs.len()); // do this explicitly to keep compiler & vm stacks in sync
// self.emit_op(Op::PopN); self.emit_op(Op::Pop);
// self.emit_byte(pairs.len()); self.emit_byte(pairs.len());
self.patch_jump(before_load_dict_idx, self.len() - before_load_dict_idx - 3); self.patch_jump(before_load_dict_idx, self.len() - before_load_dict_idx - 3);
self.patch_jump(jump_idx, self.len() - jump_idx - 3); self.patch_jump(jump_idx, self.len() - jump_idx - 3);
@ -796,6 +796,7 @@ impl<'a> Compiler<'a> {
} }
PairPattern(_, _) => unreachable!(), PairPattern(_, _) => unreachable!(),
Tuple(members) => { Tuple(members) => {
self.tail_pos = false;
for member in members { for member in members {
self.visit(member); self.visit(member);
} }
@ -804,6 +805,7 @@ impl<'a> Compiler<'a> {
self.stack_depth = self.stack_depth + 1 - members.len(); self.stack_depth = self.stack_depth + 1 - members.len();
} }
List(members) => { List(members) => {
self.tail_pos = false;
self.emit_op(Op::PushList); self.emit_op(Op::PushList);
self.stack_depth += 1; self.stack_depth += 1;
for member in members { for member in members {
@ -817,11 +819,13 @@ impl<'a> Compiler<'a> {
} }
} }
LBox(name, expr) => { LBox(name, expr) => {
self.tail_pos = false;
self.visit(expr); self.visit(expr);
self.emit_op(Op::PushBox); self.emit_op(Op::PushBox);
self.bind(name); self.bind(name);
} }
Dict(pairs) => { Dict(pairs) => {
self.tail_pos = false;
self.emit_op(Op::PushDict); self.emit_op(Op::PushDict);
self.stack_depth += 1; self.stack_depth += 1;
for pair in pairs.iter().rev() { for pair in pairs.iter().rev() {
@ -836,6 +840,7 @@ impl<'a> Compiler<'a> {
} }
} }
Pair(key, value) => { Pair(key, value) => {
self.tail_pos = false;
self.emit_constant(Value::Keyword(key)); self.emit_constant(Value::Keyword(key));
self.visit(value); self.visit(value);
} }

View File

@ -968,13 +968,13 @@ impl Vm {
} }
_ => return self.panic("internal ludus error"), _ => return self.panic("internal ludus error"),
}; };
// algo: // // algo:
// clear the stack // // clear the stack
self.stack.truncate(self.frame.stack_base); // self.stack.truncate(self.frame.stack_base);
// then pop back out to the enclosing stack frame // // then pop back out to the enclosing stack frame
self.frame = self.call_stack.pop().unwrap(); // self.frame = self.call_stack.pop().unwrap();
self.ip = self.frame.ip; // self.ip = self.frame.ip;
// finally, throw the value on the stack // // finally, throw the value on the stack
self.push(value); self.push(value);
println!( println!(
"=== returning to {} ===", "=== returning to {} ===",