From 772c56a6df39e8f2218c1c5d679bc9cdcf3aa616 Mon Sep 17 00:00:00 2001 From: Scott Richmond Date: Mon, 23 Jun 2025 20:26:26 -0400 Subject: [PATCH] fix upvalue resolution for forward-declared functions --- assets/test_prelude.ld | 72 +++++++++++++++++++++++------------------- sandbox.ld | 39 +++++++++++++++++++++-- src/vm.rs | 11 +++++-- 3 files changed, 86 insertions(+), 36 deletions(-) diff --git a/assets/test_prelude.ld b/assets/test_prelude.ld index d45d78e..5c6702f 100644 --- a/assets/test_prelude.ld +++ b/assets/test_prelude.ld @@ -1029,10 +1029,16 @@ box turtle_state = turtle_init fn apply_command fn add_command! (command) -> { + print! ("adding {command}") update! (turtle_commands, append (_, command)) + print! ("added command to commands") + print! (turtle_commands) let prev = unbox (turtle_state) + print! ("previous state: {prev}") let curr = apply_command (prev, command) + print! ("new state: {curr}") store! (turtle_state, curr) + print! ("stored state: {turtle_state}") :ok } @@ -1146,38 +1152,40 @@ fn loadstate! { fn apply_command { "Takes a turtle state and a command and calculates a new state." - (state, command) -> 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 - } + (state, command) -> { + print!("apply_command:\n{state}\n{command}") + 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 + }} } & position () -> (x, y) diff --git a/sandbox.ld b/sandbox.ld index dd44575..b99e3d0 100644 --- a/sandbox.ld +++ b/sandbox.ld @@ -1,2 +1,37 @@ -let state = unbox (turtle_state) -apply_command(state, (:penup)) +fn apply_command { + "Takes a turtle state and a command and calculates a new state." + (state, command) -> 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 + } +} + +apply_command (turtle_init, (:penup)) diff --git a/src/vm.rs b/src/vm.rs index a5e3365..badc4a0 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -606,8 +606,15 @@ impl Vm { } LoadDictValue => { let dict_idx = self.chunk().bytecode[self.ip + 1] as usize; - let Value::Dict(dict) = self.stack[dict_idx].clone() else { - unreachable!("expected dict, got something else") + let dict = match self.stack[dict_idx].clone() { + Value::Dict(dict) => dict, + value => { + println!( + "internal Ludus error in function {}", + self.frame.function.as_fn().name() + ); + unreachable!("expected dict, got {value}") + } }; let Value::Keyword(key) = self.pop() else { unreachable!("expected keyword, got something else")