so many things: DRY out VM, fix repeat tail calls, etc.
This commit is contained in:
parent
0290bb3bf2
commit
d9f0b44bed
|
@ -1029,16 +1029,10 @@ box turtle_state = turtle_init
|
||||||
fn apply_command
|
fn apply_command
|
||||||
|
|
||||||
fn add_command! (command) -> {
|
fn add_command! (command) -> {
|
||||||
print! ("adding {command}")
|
|
||||||
update! (turtle_commands, append (_, command))
|
update! (turtle_commands, append (_, command))
|
||||||
print! ("added command to commands")
|
|
||||||
print! (turtle_commands)
|
|
||||||
let prev = unbox (turtle_state)
|
let prev = unbox (turtle_state)
|
||||||
print! ("previous state: {prev}")
|
|
||||||
let curr = apply_command (prev, command)
|
let curr = apply_command (prev, command)
|
||||||
print! ("new state: {curr}")
|
|
||||||
store! (turtle_state, curr)
|
store! (turtle_state, curr)
|
||||||
print! ("stored state: {turtle_state}")
|
|
||||||
:ok
|
:ok
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1153,7 +1147,6 @@ fn loadstate! {
|
||||||
fn apply_command {
|
fn apply_command {
|
||||||
"Takes a turtle state and a command and calculates a new state."
|
"Takes a turtle state and a command and calculates a new state."
|
||||||
(state, command) -> {
|
(state, command) -> {
|
||||||
print!("apply_command:\n{state}\n{command}")
|
|
||||||
match command with {
|
match command with {
|
||||||
(:goto, (x, y)) -> assoc (state, :position, (x, y))
|
(:goto, (x, y)) -> assoc (state, :position, (x, y))
|
||||||
(:home) -> do state >
|
(:home) -> do state >
|
||||||
|
|
|
@ -518,3 +518,8 @@ PROBLEM: forward-declared functions weren't at the top of the stack when `Op::Se
|
||||||
So all of `apply_command`'s upvalues were being attached to the function declared before it (which was sitting right there at the top of the stack.)
|
So all of `apply_command`'s upvalues were being attached to the function declared before it (which was sitting right there at the top of the stack.)
|
||||||
|
|
||||||
SOLUTION: test to see if the function has been forward-declared, and if it has, bring it to the top fo the stack.
|
SOLUTION: test to see if the function has been forward-declared, and if it has, bring it to the top fo the stack.
|
||||||
|
|
||||||
|
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.
|
||||||
|
This is the thing I am about to do
|
||||||
|
|
46
sandbox.ld
46
sandbox.ld
|
@ -1,41 +1,11 @@
|
||||||
& fn apply_command {
|
box foos = []
|
||||||
& "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
|
|
||||||
& }
|
|
||||||
& }
|
|
||||||
|
|
||||||
fn many_args (_, _, x, _) -> x
|
fn foo! () -> update! (foos, append (_, :foo))
|
||||||
|
|
||||||
let fewer_args = many_args (:foo, :bar, _, :baz)
|
fn foos! () -> repeat 4 {
|
||||||
|
foo! ()
|
||||||
|
}
|
||||||
|
|
||||||
fewer_args(:quux)
|
foos! ()
|
||||||
|
|
||||||
|
unbox (foos)
|
||||||
|
|
793
sandbox_run.txt
793
sandbox_run.txt
|
@ -1,19 +1,32 @@
|
||||||
{
|
{
|
||||||
|
|
||||||
:foo
|
box foos = []
|
||||||
|
fn foo! {
|
||||||
|
() -> update! (foos, append (_, :foo) )
|
||||||
}
|
}
|
||||||
closing over in type at 1: #{:cos fn cos/base, ...
|
fn foos! {
|
||||||
closing over in eq? at 1: #{:cos fn cos/base, ...
|
() -> repeat 4 {
|
||||||
|
{
|
||||||
|
|
||||||
|
foo! ()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foos! ()
|
||||||
|
unbox (foos)
|
||||||
|
}
|
||||||
|
closing over in type at 1: #{:list fn list/base...
|
||||||
|
closing over in eq? at 1: #{:list fn list/base...
|
||||||
closing over in eq? at 2: fn eq?
|
closing over in eq? at 2: fn eq?
|
||||||
closing over in first at 1: #{:cos fn cos/base, ...
|
closing over in first at 1: #{:list fn list/base...
|
||||||
closing over in rest at 1: #{:cos fn cos/base, ...
|
closing over in rest at 1: #{:list fn list/base...
|
||||||
closing over in inc at 1: #{:cos fn cos/base, ...
|
closing over in inc at 1: #{:list fn list/base...
|
||||||
closing over in dec at 1: #{:cos fn cos/base, ...
|
closing over in dec at 1: #{:list fn list/base...
|
||||||
closing over in count at 1: #{:cos fn cos/base, ...
|
closing over in count at 1: #{:list fn list/base...
|
||||||
closing over in any? at 1: fn empty?
|
closing over in any? at 1: fn empty?
|
||||||
closing over in any? at 2: fn not
|
closing over in any? at 2: fn not
|
||||||
closing over in list at 1: #{:cos fn cos/base, ...
|
closing over in list at 1: #{:list fn list/base...
|
||||||
closing over in append at 1: #{:cos fn cos/base, ...
|
closing over in append at 1: #{:list fn list/base...
|
||||||
closing over in fold at 1: fn fold
|
closing over in fold at 1: fn fold
|
||||||
closing over in fold at 2: fn first
|
closing over in fold at 2: fn first
|
||||||
closing over in fold at 3: fn rest
|
closing over in fold at 3: fn rest
|
||||||
|
@ -28,18 +41,18 @@ closing over in filter at 2: fn append
|
||||||
closing over in filter at 3: fn fold
|
closing over in filter at 3: fn fold
|
||||||
closing over in keep at 1: fn some?
|
closing over in keep at 1: fn some?
|
||||||
closing over in keep at 2: fn filter
|
closing over in keep at 2: fn filter
|
||||||
closing over in concat at 1: #{:cos fn cos/base, ...
|
closing over in concat at 1: #{:list fn list/base...
|
||||||
closing over in concat at 2: fn concat
|
closing over in concat at 2: fn concat
|
||||||
closing over in concat at 3: fn fold
|
closing over in concat at 3: fn fold
|
||||||
closing over in contains? at 1: fn first
|
closing over in contains? at 1: fn first
|
||||||
closing over in contains? at 2: fn eq?
|
closing over in contains? at 2: fn eq?
|
||||||
closing over in contains? at 3: fn rest
|
closing over in contains? at 3: fn rest
|
||||||
closing over in print! at 1: #{:cos fn cos/base, ...
|
closing over in print! at 1: #{:list fn list/base...
|
||||||
closing over in show at 1: #{:cos fn cos/base, ...
|
closing over in show at 1: #{:list fn list/base...
|
||||||
closing over in report! at 1: fn print!
|
closing over in report! at 1: fn print!
|
||||||
closing over in report! at 2: fn show
|
closing over in report! at 2: fn show
|
||||||
closing over in report! at 3: fn concat
|
closing over in report! at 3: fn concat
|
||||||
closing over in doc! at 1: #{:cos fn cos/base, ...
|
closing over in doc! at 1: #{:list fn list/base...
|
||||||
closing over in doc! at 2: fn print!
|
closing over in doc! at 2: fn print!
|
||||||
closing over in string at 1: fn show
|
closing over in string at 1: fn show
|
||||||
closing over in string at 2: fn string
|
closing over in string at 2: fn string
|
||||||
|
@ -47,12 +60,12 @@ closing over in string at 3: fn concat
|
||||||
closing over in join at 1: fn join
|
closing over in join at 1: fn join
|
||||||
closing over in join at 2: fn concat
|
closing over in join at 2: fn concat
|
||||||
closing over in join at 3: fn fold
|
closing over in join at 3: fn fold
|
||||||
closing over in split at 1: #{:cos fn cos/base, ...
|
closing over in split at 1: #{:list fn list/base...
|
||||||
closing over in trim at 1: #{:cos fn cos/base, ...
|
closing over in trim at 1: #{:list fn list/base...
|
||||||
closing over in upcase at 1: #{:cos fn cos/base, ...
|
closing over in upcase at 1: #{:list fn list/base...
|
||||||
closing over in downcase at 1: #{:cos fn cos/base, ...
|
closing over in downcase at 1: #{:list fn list/base...
|
||||||
closing over in chars at 1: #{:cos fn cos/base, ...
|
closing over in chars at 1: #{:list fn list/base...
|
||||||
closing over in chars/safe at 1: #{:cos fn cos/base, ...
|
closing over in chars/safe at 1: #{:list fn list/base...
|
||||||
closing over in strip at 1: fn strip
|
closing over in strip at 1: fn strip
|
||||||
closing over in words at 1: fn strip
|
closing over in words at 1: fn strip
|
||||||
closing over in words at 2: fn split
|
closing over in words at 2: fn split
|
||||||
|
@ -60,25 +73,25 @@ closing over in words at 3: fn empty?
|
||||||
closing over in words at 4: fn append
|
closing over in words at 4: fn append
|
||||||
closing over in words at 5: fn fold
|
closing over in words at 5: fn fold
|
||||||
closing over in sentence at 1: fn join
|
closing over in sentence at 1: fn join
|
||||||
closing over in to_number at 1: #{:cos fn cos/base, ...
|
closing over in to_number at 1: #{:list fn list/base...
|
||||||
closing over in unbox at 1: #{:cos fn cos/base, ...
|
closing over in unbox at 1: #{:list fn list/base...
|
||||||
closing over in store! at 1: #{:cos fn cos/base, ...
|
closing over in store! at 1: #{:list fn list/base...
|
||||||
closing over in update! at 1: fn unbox
|
closing over in update! at 1: fn unbox
|
||||||
closing over in update! at 2: fn store!
|
closing over in update! at 2: fn store!
|
||||||
closing over in add at 1: #{:cos fn cos/base, ...
|
closing over in add at 1: #{:list fn list/base...
|
||||||
closing over in add at 2: fn add
|
closing over in add at 2: fn add
|
||||||
closing over in add at 3: fn fold
|
closing over in add at 3: fn fold
|
||||||
closing over in sub at 1: #{:cos fn cos/base, ...
|
closing over in sub at 1: #{:list fn list/base...
|
||||||
closing over in sub at 2: fn sub
|
closing over in sub at 2: fn sub
|
||||||
closing over in sub at 3: fn fold
|
closing over in sub at 3: fn fold
|
||||||
closing over in mult at 1: #{:cos fn cos/base, ...
|
closing over in mult at 1: #{:list fn list/base...
|
||||||
closing over in mult at 2: fn mult
|
closing over in mult at 2: fn mult
|
||||||
closing over in mult at 3: fn fold
|
closing over in mult at 3: fn fold
|
||||||
closing over in div at 1: #{:cos fn cos/base, ...
|
closing over in div at 1: #{:list fn list/base...
|
||||||
closing over in div at 2: fn mult
|
closing over in div at 2: fn mult
|
||||||
closing over in div at 3: fn fold
|
closing over in div at 3: fn fold
|
||||||
closing over in div at 4: fn div
|
closing over in div at 4: fn div
|
||||||
closing over in div/0 at 1: #{:cos fn cos/base, ...
|
closing over in div/0 at 1: #{:list fn list/base...
|
||||||
closing over in div/0 at 2: fn mult
|
closing over in div/0 at 2: fn mult
|
||||||
closing over in div/0 at 3: fn fold
|
closing over in div/0 at 3: fn fold
|
||||||
closing over in div/0 at 4: fn div/0
|
closing over in div/0 at 4: fn div/0
|
||||||
|
@ -90,10 +103,10 @@ closing over in inv at 1: fn div
|
||||||
closing over in inv/0 at 1: fn div/0
|
closing over in inv/0 at 1: fn div/0
|
||||||
closing over in inv/safe at 1: fn div/safe
|
closing over in inv/safe at 1: fn div/safe
|
||||||
closing over in neg at 1: fn mult
|
closing over in neg at 1: fn mult
|
||||||
closing over in gt? at 1: #{:cos fn cos/base, ...
|
closing over in gt? at 1: #{:list fn list/base...
|
||||||
closing over in gte? at 1: #{:cos fn cos/base, ...
|
closing over in gte? at 1: #{:list fn list/base...
|
||||||
closing over in lt? at 1: #{:cos fn cos/base, ...
|
closing over in lt? at 1: #{:list fn list/base...
|
||||||
closing over in lte? at 1: #{:cos fn cos/base, ...
|
closing over in lte? at 1: #{:list fn list/base...
|
||||||
closing over in between? at 1: fn gte?
|
closing over in between? at 1: fn gte?
|
||||||
closing over in between? at 2: fn lt?
|
closing over in between? at 2: fn lt?
|
||||||
closing over in neg? at 1: fn lt?
|
closing over in neg? at 1: fn lt?
|
||||||
|
@ -113,13 +126,13 @@ closing over in rad/deg at 1: 6.283185307179586
|
||||||
closing over in rad/deg at 2: fn div
|
closing over in rad/deg at 2: fn div
|
||||||
closing over in rad/deg at 3: fn mult
|
closing over in rad/deg at 3: fn mult
|
||||||
closing over in sin at 1: fn turn/rad
|
closing over in sin at 1: fn turn/rad
|
||||||
closing over in sin at 2: #{:cos fn cos/base, ...
|
closing over in sin at 2: #{:list fn list/base...
|
||||||
closing over in sin at 3: fn deg/rad
|
closing over in sin at 3: fn deg/rad
|
||||||
closing over in cos at 1: fn turn/rad
|
closing over in cos at 1: fn turn/rad
|
||||||
closing over in cos at 2: #{:cos fn cos/base, ...
|
closing over in cos at 2: #{:list fn list/base...
|
||||||
closing over in cos at 3: fn deg/rad
|
closing over in cos at 3: fn deg/rad
|
||||||
closing over in tan at 1: fn turn/rad
|
closing over in tan at 1: fn turn/rad
|
||||||
closing over in tan at 2: #{:cos fn cos/base, ...
|
closing over in tan at 2: #{:list fn list/base...
|
||||||
closing over in tan at 3: fn deg/rad
|
closing over in tan at 3: fn deg/rad
|
||||||
closing over in rotate at 1: fn rotate
|
closing over in rotate at 1: fn rotate
|
||||||
closing over in rotate at 2: fn cos
|
closing over in rotate at 2: fn cos
|
||||||
|
@ -127,15 +140,15 @@ closing over in rotate at 3: fn mult
|
||||||
closing over in rotate at 4: fn sin
|
closing over in rotate at 4: fn sin
|
||||||
closing over in rotate at 5: fn sub
|
closing over in rotate at 5: fn sub
|
||||||
closing over in rotate at 6: fn add
|
closing over in rotate at 6: fn add
|
||||||
closing over in atan/2 at 1: #{:cos fn cos/base, ...
|
closing over in atan/2 at 1: #{:list fn list/base...
|
||||||
closing over in atan/2 at 2: fn rad/turn
|
closing over in atan/2 at 2: fn rad/turn
|
||||||
closing over in atan/2 at 3: fn atan/2
|
closing over in atan/2 at 3: fn atan/2
|
||||||
closing over in atan/2 at 4: fn rad/deg
|
closing over in atan/2 at 4: fn rad/deg
|
||||||
closing over in angle at 1: fn atan/2
|
closing over in angle at 1: fn atan/2
|
||||||
closing over in angle at 2: fn sub
|
closing over in angle at 2: fn sub
|
||||||
closing over in mod at 1: #{:cos fn cos/base, ...
|
closing over in mod at 1: #{:list fn list/base...
|
||||||
closing over in mod/0 at 1: #{:cos fn cos/base, ...
|
closing over in mod/0 at 1: #{:list fn list/base...
|
||||||
closing over in mod/safe at 1: #{:cos fn cos/base, ...
|
closing over in mod/safe at 1: #{:list fn list/base...
|
||||||
closing over in even? at 1: fn mod
|
closing over in even? at 1: fn mod
|
||||||
closing over in even? at 2: fn eq?
|
closing over in even? at 2: fn eq?
|
||||||
closing over in odd? at 1: fn mod
|
closing over in odd? at 1: fn mod
|
||||||
|
@ -143,10 +156,10 @@ closing over in odd? at 2: fn eq?
|
||||||
closing over in square at 1: fn mult
|
closing over in square at 1: fn mult
|
||||||
closing over in sqrt at 1: fn neg?
|
closing over in sqrt at 1: fn neg?
|
||||||
closing over in sqrt at 2: fn not
|
closing over in sqrt at 2: fn not
|
||||||
closing over in sqrt at 3: #{:cos fn cos/base, ...
|
closing over in sqrt at 3: #{:list fn list/base...
|
||||||
closing over in sqrt/safe at 1: fn neg?
|
closing over in sqrt/safe at 1: fn neg?
|
||||||
closing over in sqrt/safe at 2: fn not
|
closing over in sqrt/safe at 2: fn not
|
||||||
closing over in sqrt/safe at 3: #{:cos fn cos/base, ...
|
closing over in sqrt/safe at 3: #{:list fn list/base...
|
||||||
closing over in sum_of_squares at 1: fn square
|
closing over in sum_of_squares at 1: fn square
|
||||||
closing over in sum_of_squares at 2: fn add
|
closing over in sum_of_squares at 2: fn add
|
||||||
closing over in sum_of_squares at 3: fn sum_of_squares
|
closing over in sum_of_squares at 3: fn sum_of_squares
|
||||||
|
@ -158,11 +171,11 @@ closing over in heading/vector at 1: fn neg
|
||||||
closing over in heading/vector at 2: fn add
|
closing over in heading/vector at 2: fn add
|
||||||
closing over in heading/vector at 3: fn cos
|
closing over in heading/vector at 3: fn cos
|
||||||
closing over in heading/vector at 4: fn sin
|
closing over in heading/vector at 4: fn sin
|
||||||
closing over in floor at 1: #{:cos fn cos/base, ...
|
closing over in floor at 1: #{:list fn list/base...
|
||||||
closing over in ceil at 1: #{:cos fn cos/base, ...
|
closing over in ceil at 1: #{:list fn list/base...
|
||||||
closing over in round at 1: #{:cos fn cos/base, ...
|
closing over in round at 1: #{:list fn list/base...
|
||||||
closing over in range at 1: #{:cos fn cos/base, ...
|
closing over in range at 1: #{:list fn list/base...
|
||||||
closing over in at at 1: #{:cos fn cos/base, ...
|
closing over in at at 1: #{:list fn list/base...
|
||||||
closing over in second at 1: fn ordered?
|
closing over in second at 1: fn ordered?
|
||||||
closing over in second at 2: fn at
|
closing over in second at 2: fn at
|
||||||
closing over in last at 1: fn ordered?
|
closing over in last at 1: fn ordered?
|
||||||
|
@ -174,14 +187,14 @@ closing over in slice at 2: fn gte?
|
||||||
closing over in slice at 3: fn count
|
closing over in slice at 3: fn count
|
||||||
closing over in slice at 4: fn gt?
|
closing over in slice at 4: fn gt?
|
||||||
closing over in slice at 5: fn neg?
|
closing over in slice at 5: fn neg?
|
||||||
closing over in slice at 6: #{:cos fn cos/base, ...
|
closing over in slice at 6: #{:list fn list/base...
|
||||||
closing over in butlast at 1: fn count
|
closing over in butlast at 1: fn count
|
||||||
closing over in butlast at 2: fn dec
|
closing over in butlast at 2: fn dec
|
||||||
closing over in butlast at 3: fn slice
|
closing over in butlast at 3: fn slice
|
||||||
closing over in assoc at 1: #{:cos fn cos/base, ...
|
closing over in assoc at 1: #{:list fn list/base...
|
||||||
closing over in dissoc at 1: #{:cos fn cos/base, ...
|
closing over in dissoc at 1: #{:list fn list/base...
|
||||||
closing over in get at 1: fn get
|
closing over in get at 1: fn get
|
||||||
closing over in get at 2: #{:cos fn cos/base, ...
|
closing over in get at 2: #{:list fn list/base...
|
||||||
closing over in update at 1: fn get
|
closing over in update at 1: fn get
|
||||||
closing over in update at 2: fn assoc
|
closing over in update at 2: fn assoc
|
||||||
closing over in keys at 1: fn list
|
closing over in keys at 1: fn list
|
||||||
|
@ -198,7 +211,7 @@ closing over in dict at 2: fn fold
|
||||||
closing over in dict at 3: fn list
|
closing over in dict at 3: fn list
|
||||||
closing over in dict at 4: fn dict
|
closing over in dict at 4: fn dict
|
||||||
closing over in each! at 1: fn each!
|
closing over in each! at 1: fn each!
|
||||||
closing over in random at 1: #{:cos fn cos/base, ...
|
closing over in random at 1: #{:list fn list/base...
|
||||||
closing over in random at 2: fn random
|
closing over in random at 2: fn random
|
||||||
closing over in random at 3: fn mult
|
closing over in random at 3: fn mult
|
||||||
closing over in random at 4: fn sub
|
closing over in random at 4: fn sub
|
||||||
|
@ -213,7 +226,7 @@ closing over in random_int at 2: fn floor
|
||||||
closing over in add_command! at 1: box { [] }
|
closing over in add_command! at 1: box { [] }
|
||||||
closing over in add_command! at 2: fn append
|
closing over in add_command! at 2: fn append
|
||||||
closing over in add_command! at 3: fn update!
|
closing over in add_command! at 3: fn update!
|
||||||
closing over in add_command! at 4: box { #{:pendown? tr...
|
closing over in add_command! at 4: box { #{:position (0...
|
||||||
closing over in add_command! at 5: fn unbox
|
closing over in add_command! at 5: fn unbox
|
||||||
closing over in add_command! at 6: fn apply_command
|
closing over in add_command! at 6: fn apply_command
|
||||||
closing over in add_command! at 7: fn store!
|
closing over in add_command! at 7: fn store!
|
||||||
|
@ -234,21 +247,671 @@ closing over in setheading! at 1: fn add_command!
|
||||||
closing over in showturtle! at 1: fn add_command!
|
closing over in showturtle! at 1: fn add_command!
|
||||||
closing over in hideturtle! at 1: fn add_command!
|
closing over in hideturtle! at 1: fn add_command!
|
||||||
closing over in loadstate! at 1: fn add_command!
|
closing over in loadstate! at 1: fn add_command!
|
||||||
closing over in foo at 1: fn hideturtle!
|
closing over in apply_command at 1: fn assoc
|
||||||
closing over in foo at 2: fn assoc
|
closing over in apply_command at 2: fn add
|
||||||
closing over in foo at 3: fn add
|
closing over in apply_command at 3: fn update
|
||||||
closing over in foo at 4: fn update
|
closing over in apply_command at 4: fn sub
|
||||||
closing over in foo at 5: fn sub
|
closing over in apply_command at 5: fn heading/vector
|
||||||
closing over in foo at 6: fn heading/vector
|
closing over in apply_command at 6: fn mult
|
||||||
closing over in foo at 7: fn mult
|
closing over in position at 1: box { #{:position (0...
|
||||||
closing over in position at 1: box { #{:pendown? tr...
|
|
||||||
closing over in position at 2: fn unbox
|
closing over in position at 2: fn unbox
|
||||||
closing over in heading at 1: box { #{:pendown? tr...
|
closing over in heading at 1: box { #{:position (0...
|
||||||
closing over in heading at 2: fn unbox
|
closing over in heading at 2: fn unbox
|
||||||
closing over in pendown? at 1: box { #{:pendown? tr...
|
closing over in pendown? at 1: box { #{:position (0...
|
||||||
closing over in pendown? at 2: fn unbox
|
closing over in pendown? at 2: fn unbox
|
||||||
closing over in pencolor at 1: box { #{:pendown? tr...
|
closing over in pencolor at 1: box { #{:position (0...
|
||||||
closing over in pencolor at 2: fn unbox
|
closing over in pencolor at 2: fn unbox
|
||||||
closing over in penwidth at 1: box { #{:pendown? tr...
|
closing over in penwidth at 1: box { #{:position (0...
|
||||||
closing over in penwidth at 2: fn unbox
|
closing over in penwidth at 2: fn unbox
|
||||||
:foo
|
binding `foos` in sandbox
|
||||||
|
stack depth: 1; match depth: 0
|
||||||
|
at stack index: 0
|
||||||
|
new locals: foos@0//0
|
||||||
|
binding `foo!` in sandbox
|
||||||
|
stack depth: 2; match depth: 0
|
||||||
|
at stack index: 1
|
||||||
|
new locals: foos@0//0|foo!@1//0
|
||||||
|
***function clause matching: : ()
|
||||||
|
***calling function update! stack depth: 0
|
||||||
|
resolving binding `foos` in foo!
|
||||||
|
locals:
|
||||||
|
as enclosing upvalue 0
|
||||||
|
***calling function append stack depth: 1
|
||||||
|
resolving binding `append` in foo!
|
||||||
|
locals:
|
||||||
|
as enclosing upvalue 1
|
||||||
|
resolving binding `update!` in foo!
|
||||||
|
locals:
|
||||||
|
as enclosing upvalue 2
|
||||||
|
***after 2 args stack depth: 3
|
||||||
|
=== function chuncktion: foo!/0 ===
|
||||||
|
IDX | CODE | INFO
|
||||||
|
0000: reset_match
|
||||||
|
0001: ***function clause matching: : ()
|
||||||
|
0003: match
|
||||||
|
0004: jump 00000
|
||||||
|
0007: jump_if_no_match 00034
|
||||||
|
0010: ***calling function update! stack depth: 0
|
||||||
|
0012: resolving binding `foos` in foo!
|
||||||
|
locals:
|
||||||
|
0014: as enclosing upvalue 0
|
||||||
|
0016: get_upvalue 000
|
||||||
|
0018: ***calling function append stack depth: 1
|
||||||
|
0020: nothing
|
||||||
|
0021: constant 00000: :foo
|
||||||
|
0024: resolving binding `append` in foo!
|
||||||
|
locals:
|
||||||
|
0026: as enclosing upvalue 1
|
||||||
|
0028: get_upvalue 001
|
||||||
|
0030: partial 002
|
||||||
|
0032: resolving binding `update!` in foo!
|
||||||
|
locals:
|
||||||
|
0034: as enclosing upvalue 2
|
||||||
|
0036: get_upvalue 002
|
||||||
|
0038: ***after 2 args stack depth: 3
|
||||||
|
0040: tail_call 002
|
||||||
|
0042: store
|
||||||
|
0043: return
|
||||||
|
0044: panic_no_match
|
||||||
|
resolving binding `foos` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0
|
||||||
|
at locals position 0
|
||||||
|
resolving binding `append` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0
|
||||||
|
as global
|
||||||
|
resolving binding `update!` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0
|
||||||
|
as global
|
||||||
|
binding `foos!` in sandbox
|
||||||
|
stack depth: 3; match depth: 0
|
||||||
|
at stack index: 2
|
||||||
|
new locals: foos@0//0|foo!@1//0|foos!@2//0
|
||||||
|
***function clause matching: : ()
|
||||||
|
***calling function foo! stack depth: 1
|
||||||
|
resolving binding `foo!` in foos!
|
||||||
|
locals:
|
||||||
|
as enclosing upvalue 0
|
||||||
|
***after 0 args stack depth: 2
|
||||||
|
leaving scope 1
|
||||||
|
***leaving block before pop stack depth: 1
|
||||||
|
popping back from 1 to 1
|
||||||
|
=== function chuncktion: foos!/0 ===
|
||||||
|
IDX | CODE | INFO
|
||||||
|
0000: reset_match
|
||||||
|
0001: ***function clause matching: : ()
|
||||||
|
0003: match
|
||||||
|
0004: jump 00000
|
||||||
|
0007: jump_if_no_match 00042
|
||||||
|
0010: constant 00000: 4
|
||||||
|
0013: truncate
|
||||||
|
0014: jump 00001
|
||||||
|
0017: decrement
|
||||||
|
0018: duplicate
|
||||||
|
0019: jump_if_zero 00024
|
||||||
|
0022: ***calling function foo! stack depth: 1
|
||||||
|
0024: resolving binding `foo!` in foos!
|
||||||
|
locals:
|
||||||
|
0026: as enclosing upvalue 0
|
||||||
|
0028: get_upvalue 000
|
||||||
|
0030: ***after 0 args stack depth: 2
|
||||||
|
0032: tail_call 000
|
||||||
|
0034: store
|
||||||
|
0035: leaving scope 1
|
||||||
|
0037: ***leaving block before pop stack depth: 1
|
||||||
|
0039: popping back from 1 to 1
|
||||||
|
0041: load
|
||||||
|
0042: pop
|
||||||
|
0043: jump_back 00026
|
||||||
|
0046: pop
|
||||||
|
0047: constant 00001: nil
|
||||||
|
0050: store
|
||||||
|
0051: return
|
||||||
|
0052: panic_no_match
|
||||||
|
resolving binding `foo!` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0|foos!@2//0
|
||||||
|
at locals position 1
|
||||||
|
***calling function foos! stack depth: 3
|
||||||
|
resolving binding `foos!` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0|foos!@2//0
|
||||||
|
at locals position 2
|
||||||
|
***after 0 args stack depth: 4
|
||||||
|
***calling function unbox stack depth: 3
|
||||||
|
resolving binding `foos` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0|foos!@2//0
|
||||||
|
at locals position 0
|
||||||
|
resolving binding `unbox` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0|foos!@2//0
|
||||||
|
as global
|
||||||
|
***after 1 args stack depth: 5
|
||||||
|
leaving scope 0
|
||||||
|
releasing binding foos!@2//0
|
||||||
|
releasing binding foo!@1//0
|
||||||
|
releasing binding foos@0//0
|
||||||
|
***leaving block before pop stack depth: 3
|
||||||
|
popping back from 3 to 0
|
||||||
|
=== source code ===
|
||||||
|
box foos = []
|
||||||
|
|
||||||
|
fn foo! () -> update! (foos, append (_, :foo))
|
||||||
|
|
||||||
|
fn foos! () -> repeat 4 {
|
||||||
|
foo! ()
|
||||||
|
}
|
||||||
|
|
||||||
|
foos! ()
|
||||||
|
|
||||||
|
unbox (foos)
|
||||||
|
|
||||||
|
=== chunk: sandbox ===
|
||||||
|
IDX | CODE | INFO
|
||||||
|
0000: push_list
|
||||||
|
0001: push_box 082
|
||||||
|
0003: noop
|
||||||
|
0004: stack depth: 1; match depth: 0
|
||||||
|
0006: at stack index: 0
|
||||||
|
0008: new locals: foos@0//0
|
||||||
|
0010: constant 00000: fn foo!
|
||||||
|
0013: binding `foo!` in sandbox
|
||||||
|
0015: stack depth: 2; match depth: 0
|
||||||
|
0017: at stack index: 1
|
||||||
|
0019: new locals: foos@0//0|foo!@1//0
|
||||||
|
0021: resolving binding `foos` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0
|
||||||
|
0023: at locals position 0
|
||||||
|
0025: push_binding 000
|
||||||
|
0027: set_upvalue
|
||||||
|
0028: resolving binding `append` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0
|
||||||
|
0030: as global
|
||||||
|
0032: constant 00001: :append
|
||||||
|
0035: push_global
|
||||||
|
0036: set_upvalue
|
||||||
|
0037: resolving binding `update!` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0
|
||||||
|
0039: as global
|
||||||
|
0041: constant 00002: :update!
|
||||||
|
0044: push_global
|
||||||
|
0045: set_upvalue
|
||||||
|
0046: constant 00003: fn foos!
|
||||||
|
0049: binding `foos!` in sandbox
|
||||||
|
0051: stack depth: 3; match depth: 0
|
||||||
|
0053: at stack index: 2
|
||||||
|
0055: new locals: foos@0//0|foo!@1//0|foos!@2//0
|
||||||
|
0057: resolving binding `foo!` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0|foos!@2//0
|
||||||
|
0059: at locals position 1
|
||||||
|
0061: push_binding 001
|
||||||
|
0063: set_upvalue
|
||||||
|
0064: ***calling function foos! stack depth: 3
|
||||||
|
0066: resolving binding `foos!` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0|foos!@2//0
|
||||||
|
0068: at locals position 2
|
||||||
|
0070: push_binding 002
|
||||||
|
0072: ***after 0 args stack depth: 4
|
||||||
|
0074: call 000
|
||||||
|
0076: pop
|
||||||
|
0077: ***calling function unbox stack depth: 3
|
||||||
|
0079: resolving binding `foos` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0|foos!@2//0
|
||||||
|
0081: at locals position 0
|
||||||
|
0083: push_binding 000
|
||||||
|
0085: resolving binding `unbox` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0|foos!@2//0
|
||||||
|
0087: as global
|
||||||
|
0089: constant 00004: :unbox
|
||||||
|
0092: push_global
|
||||||
|
0093: ***after 1 args stack depth: 5
|
||||||
|
0095: call 001
|
||||||
|
0097: store
|
||||||
|
0098: leaving scope 0
|
||||||
|
0100: releasing binding foos!@2//0
|
||||||
|
0102: releasing binding foo!@1//0
|
||||||
|
0104: releasing binding foos@0//0
|
||||||
|
0106: ***leaving block before pop stack depth: 3
|
||||||
|
0108: popping back from 3 to 0
|
||||||
|
0110: pop_n 003
|
||||||
|
0112: load
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
=== vm run ===
|
||||||
|
0000: [] (_,_,_,_,_,_,_,_)
|
||||||
|
0000: push_list
|
||||||
|
0001: [->[]<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0001: push_box 082
|
||||||
|
0002: [->box { [] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0002: binding `foos` in sandbox
|
||||||
|
0004: [->box { [] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0004: stack depth: 1; match depth: 0
|
||||||
|
0006: [->box { [] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0006: at stack index: 0
|
||||||
|
0008: [->box { [] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0008: new locals: foos@0//0
|
||||||
|
0010: [->box { [] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0010: constant 00000: fn foo!
|
||||||
|
0013: [->box { [] }<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0013: binding `foo!` in sandbox
|
||||||
|
0015: [->box { [] }<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0015: stack depth: 2; match depth: 0
|
||||||
|
0017: [->box { [] }<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0017: at stack index: 1
|
||||||
|
0019: [->box { [] }<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0019: new locals: foos@0//0|foo!@1//0
|
||||||
|
0021: [->box { [] }<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0021: resolving binding `foos` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0
|
||||||
|
0023: [->box { [] }<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0023: at locals position 0
|
||||||
|
0025: [->box { [] }<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0025: push_binding 000
|
||||||
|
0027: [->box { [] }<-|fn foo!|box { [] }] (_,_,_,_,_,_,_,_)
|
||||||
|
0027: set_upvalue
|
||||||
|
closing over in foo! at 1: box { [] }
|
||||||
|
0028: [->box { [] }<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0028: resolving binding `append` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0
|
||||||
|
0030: [->box { [] }<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0030: as global
|
||||||
|
0032: [->box { [] }<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0032: constant 00001: :append
|
||||||
|
0035: [->box { [] }<-|fn foo!|:append] (_,_,_,_,_,_,_,_)
|
||||||
|
0035: push_global
|
||||||
|
0036: [->box { [] }<-|fn foo!|fn append] (_,_,_,_,_,_,_,_)
|
||||||
|
0036: set_upvalue
|
||||||
|
closing over in foo! at 2: fn append
|
||||||
|
0037: [->box { [] }<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0037: resolving binding `update!` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0
|
||||||
|
0039: [->box { [] }<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0039: as global
|
||||||
|
0041: [->box { [] }<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0041: constant 00002: :update!
|
||||||
|
0044: [->box { [] }<-|fn foo!|:update!] (_,_,_,_,_,_,_,_)
|
||||||
|
0044: push_global
|
||||||
|
0045: [->box { [] }<-|fn foo!|fn update!] (_,_,_,_,_,_,_,_)
|
||||||
|
0045: set_upvalue
|
||||||
|
closing over in foo! at 3: fn update!
|
||||||
|
0046: [->box { [] }<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0046: constant 00003: fn foos!
|
||||||
|
0049: [->box { [] }<-|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0049: binding `foos!` in sandbox
|
||||||
|
0051: [->box { [] }<-|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0051: stack depth: 3; match depth: 0
|
||||||
|
0053: [->box { [] }<-|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0053: at stack index: 2
|
||||||
|
0055: [->box { [] }<-|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0055: new locals: foos@0//0|foo!@1//0|foos!@2//0
|
||||||
|
0057: [->box { [] }<-|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0057: resolving binding `foo!` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0|foos!@2//0
|
||||||
|
0059: [->box { [] }<-|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0059: at locals position 1
|
||||||
|
0061: [->box { [] }<-|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0061: push_binding 001
|
||||||
|
0063: [->box { [] }<-|fn foo!|fn foos!|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0063: set_upvalue
|
||||||
|
closing over in foos! at 1: fn foo!
|
||||||
|
0064: [->box { [] }<-|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0064: ***calling function foos! stack depth: 3
|
||||||
|
0066: [->box { [] }<-|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0066: resolving binding `foos!` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0|foos!@2//0
|
||||||
|
0068: [->box { [] }<-|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0068: at locals position 2
|
||||||
|
0070: [->box { [] }<-|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0070: push_binding 002
|
||||||
|
0072: [->box { [] }<-|fn foo!|fn foos!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0072: ***after 0 args stack depth: 4
|
||||||
|
0074: [->box { [] }<-|fn foo!|fn foos!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0074: call 000
|
||||||
|
=== calling into fn foos!/0 ===
|
||||||
|
0000: [box { [] }|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0000: reset_match
|
||||||
|
0001: [box { [] }|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0001: ***function clause matching: : ()
|
||||||
|
0003: [box { [] }|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0003: match
|
||||||
|
0004: [box { [] }|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0004: jump 00000
|
||||||
|
0007: [box { [] }|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0007: jump_if_no_match 00042
|
||||||
|
0010: [box { [] }|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0010: constant 00000: 4
|
||||||
|
0013: [box { [] }|fn foo!|fn foos!|->4<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0013: truncate
|
||||||
|
0014: [box { [] }|fn foo!|fn foos!|->4<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0014: jump 00001
|
||||||
|
0018: [box { [] }|fn foo!|fn foos!|->4<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0018: duplicate
|
||||||
|
0019: [box { [] }|fn foo!|fn foos!|->4<-|4] (_,_,_,_,_,_,_,_)
|
||||||
|
0019: jump_if_zero 00024
|
||||||
|
0022: [box { [] }|fn foo!|fn foos!|->4<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0022: ***calling function foo! stack depth: 1
|
||||||
|
0024: [box { [] }|fn foo!|fn foos!|->4<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0024: resolving binding `foo!` in foos!
|
||||||
|
locals:
|
||||||
|
0026: [box { [] }|fn foo!|fn foos!|->4<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0026: as enclosing upvalue 0
|
||||||
|
0028: [box { [] }|fn foo!|fn foos!|->4<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0028: get_upvalue 000
|
||||||
|
0030: [box { [] }|fn foo!|fn foos!|->4<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0030: ***after 0 args stack depth: 2
|
||||||
|
0032: [box { [] }|fn foo!|fn foos!|->4<-|fn foo!] (_,_,_,_,_,_,_,_)
|
||||||
|
0032: tail_call 000
|
||||||
|
=== tail call into fn foo!/0 from foos! ===
|
||||||
|
0000: [box { [] }|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0000: reset_match
|
||||||
|
0001: [box { [] }|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0001: ***function clause matching: : ()
|
||||||
|
0003: [box { [] }|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0003: match
|
||||||
|
0004: [box { [] }|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0004: jump 00000
|
||||||
|
0007: [box { [] }|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0007: jump_if_no_match 00034
|
||||||
|
0010: [box { [] }|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0010: ***calling function update! stack depth: 0
|
||||||
|
0012: [box { [] }|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0012: resolving binding `foos` in foo!
|
||||||
|
locals:
|
||||||
|
0014: [box { [] }|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0014: as enclosing upvalue 0
|
||||||
|
0016: [box { [] }|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0016: get_upvalue 000
|
||||||
|
0018: [box { [] }|fn foo!|fn foos!|->box { [] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0018: ***calling function append stack depth: 1
|
||||||
|
0020: [box { [] }|fn foo!|fn foos!|->box { [] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0020: nothing
|
||||||
|
0021: [box { [] }|fn foo!|fn foos!|->box { [] }<-|_] (_,_,_,_,_,_,_,_)
|
||||||
|
0021: constant 00000: :foo
|
||||||
|
0024: [box { [] }|fn foo!|fn foos!|->box { [] }<-|_|:foo] (_,_,_,_,_,_,_,_)
|
||||||
|
0024: resolving binding `append` in foo!
|
||||||
|
locals:
|
||||||
|
0026: [box { [] }|fn foo!|fn foos!|->box { [] }<-|_|:foo] (_,_,_,_,_,_,_,_)
|
||||||
|
0026: as enclosing upvalue 1
|
||||||
|
0028: [box { [] }|fn foo!|fn foos!|->box { [] }<-|_|:foo] (_,_,_,_,_,_,_,_)
|
||||||
|
0028: get_upvalue 001
|
||||||
|
0030: [box { [] }|fn foo!|fn foos!|->box { [] }<-|_|:foo|fn append] (_,_,_,_,_,_,_,_)
|
||||||
|
0030: partial 002
|
||||||
|
0032: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial] (_,_,_,_,_,_,_,_)
|
||||||
|
0032: resolving binding `update!` in foo!
|
||||||
|
locals:
|
||||||
|
0034: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial] (_,_,_,_,_,_,_,_)
|
||||||
|
0034: as enclosing upvalue 2
|
||||||
|
0036: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial] (_,_,_,_,_,_,_,_)
|
||||||
|
0036: get_upvalue 002
|
||||||
|
0038: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|fn update!] (_,_,_,_,_,_,_,_)
|
||||||
|
0038: ***after 2 args stack depth: 3
|
||||||
|
0040: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|fn update!] (_,_,_,_,_,_,_,_)
|
||||||
|
0040: tail_call 002
|
||||||
|
=== tail call into fn update!/2 from foo! ===
|
||||||
|
0000: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial] (_,_,_,_,_,_,_,_)
|
||||||
|
0000: reset_match
|
||||||
|
0001: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial] (_,_,_,_,_,_,_,_)
|
||||||
|
0001: match_depth 001
|
||||||
|
0003: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial] (_,_,_,_,_,_,_,_)
|
||||||
|
0003: constant 00000: :box
|
||||||
|
0006: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|:box] (_,_,_,_,_,_,_,_)
|
||||||
|
0006: match_type
|
||||||
|
0007: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial] (_,_,_,_,_,_,_,_)
|
||||||
|
0007: jump_if_no_match 00012
|
||||||
|
0010: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial] (_,_,_,_,_,_,_,_)
|
||||||
|
0010: match_depth 000
|
||||||
|
0012: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial] (_,_,_,_,_,_,_,_)
|
||||||
|
0012: constant 00001: :fn
|
||||||
|
0015: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|:fn] (_,_,_,_,_,_,_,_)
|
||||||
|
0015: match_type
|
||||||
|
0016: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial] (_,_,_,_,_,_,_,_)
|
||||||
|
0016: jump_if_no_match 00003
|
||||||
|
0019: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial] (_,_,_,_,_,_,_,_)
|
||||||
|
0019: jump 00000
|
||||||
|
0022: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial] (_,_,_,_,_,_,_,_)
|
||||||
|
0022: jump_if_no_match 00034
|
||||||
|
0025: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial] (_,_,_,_,_,_,_,_)
|
||||||
|
0025: push_binding 000
|
||||||
|
0027: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|box { [] }] (_,_,_,_,_,_,_,_)
|
||||||
|
0027: get_upvalue 000
|
||||||
|
0029: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|box { [] }|fn unbox] (_,_,_,_,_,_,_,_)
|
||||||
|
0029: call 001
|
||||||
|
=== calling into fn unbox/1 ===
|
||||||
|
0000: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0000: reset_match
|
||||||
|
0001: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0001: match_depth 000
|
||||||
|
0003: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0003: constant 00000: :box
|
||||||
|
0006: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-|:box] (_,_,_,_,_,_,_,_)
|
||||||
|
0006: match_type
|
||||||
|
0007: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0007: jump_if_no_match 00003
|
||||||
|
0010: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0010: jump 00000
|
||||||
|
0013: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0013: jump_if_no_match 00015
|
||||||
|
0016: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0016: get_upvalue 000
|
||||||
|
0018: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-|#{:list fn list/base...] (_,_,_,_,_,_,_,_)
|
||||||
|
0018: constant 00001: :unbox
|
||||||
|
0021: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-|#{:list fn list/base...|:unbox] (_,_,_,_,_,_,_,_)
|
||||||
|
0021: get_key
|
||||||
|
0022: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-|fn unbox/base] (_,_,_,_,_,_,_,_)
|
||||||
|
0022: store
|
||||||
|
0023: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-] (fn unbox/base,_,_,_,_,_,_,_)
|
||||||
|
0023: push_binding 000
|
||||||
|
0025: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-|box { [] }] (fn unbox/base,_,_,_,_,_,_,_)
|
||||||
|
0025: load
|
||||||
|
0026: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-|box { [] }|fn unbox/base] (_,_,_,_,_,_,_,_)
|
||||||
|
0026: tail_call 001
|
||||||
|
=== tail call into fn unbox/base/1 from unbox ===
|
||||||
|
0028: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-|[]] (_,_,_,_,_,_,_,_)
|
||||||
|
0028: store
|
||||||
|
0029: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|->box { [] }<-] ([],_,_,_,_,_,_,_)
|
||||||
|
0029: pop
|
||||||
|
0030: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial] ([],_,_,_,_,_,_,_)
|
||||||
|
0030: return
|
||||||
|
== returning from fn unbox ==
|
||||||
|
0031: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|[]] (_,_,_,_,_,_,_,_)
|
||||||
|
0031: reset_match
|
||||||
|
0032: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|[]] (_,_,_,_,_,_,_,_)
|
||||||
|
0032: match
|
||||||
|
0033: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|[]] (_,_,_,_,_,_,_,_)
|
||||||
|
0033: panic_if_no_match
|
||||||
|
0034: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|[]] (_,_,_,_,_,_,_,_)
|
||||||
|
0034: push_binding 002
|
||||||
|
0036: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|[]|[]] (_,_,_,_,_,_,_,_)
|
||||||
|
0036: push_binding 001
|
||||||
|
0038: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|[]|[]|fn append/partial] (_,_,_,_,_,_,_,_)
|
||||||
|
0038: call 001
|
||||||
|
=== calling into fn append/partial/1 ===
|
||||||
|
0000: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo] (_,_,_,_,_,_,_,_)
|
||||||
|
0000: reset_match
|
||||||
|
0001: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo] (_,_,_,_,_,_,_,_)
|
||||||
|
0001: match_depth 001
|
||||||
|
0003: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo] (_,_,_,_,_,_,_,_)
|
||||||
|
0003: constant 00000: :list
|
||||||
|
0006: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo|:list] (_,_,_,_,_,_,_,_)
|
||||||
|
0006: match_type
|
||||||
|
0007: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo] (_,_,_,_,_,_,_,_)
|
||||||
|
0007: jump_if_no_match 00009
|
||||||
|
0010: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo] (_,_,_,_,_,_,_,_)
|
||||||
|
0010: match_depth 000
|
||||||
|
0012: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo] (_,_,_,_,_,_,_,_)
|
||||||
|
0012: match
|
||||||
|
0013: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo] (_,_,_,_,_,_,_,_)
|
||||||
|
0013: jump_if_no_match 00003
|
||||||
|
0016: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo] (_,_,_,_,_,_,_,_)
|
||||||
|
0016: jump 00000
|
||||||
|
0019: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo] (_,_,_,_,_,_,_,_)
|
||||||
|
0019: jump_if_no_match 00018
|
||||||
|
0022: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo] (_,_,_,_,_,_,_,_)
|
||||||
|
0022: get_upvalue 000
|
||||||
|
0024: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo|#{:list fn list/base...] (_,_,_,_,_,_,_,_)
|
||||||
|
0024: constant 00001: :append
|
||||||
|
0027: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo|#{:list fn list/base...|:append] (_,_,_,_,_,_,_,_)
|
||||||
|
0027: get_key
|
||||||
|
0028: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo|fn append/base] (_,_,_,_,_,_,_,_)
|
||||||
|
0028: store
|
||||||
|
0029: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo] (fn append/base,_,_,_,_,_,_,_)
|
||||||
|
0029: push_binding 000
|
||||||
|
0031: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo|[]] (fn append/base,_,_,_,_,_,_,_)
|
||||||
|
0031: push_binding 001
|
||||||
|
0033: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo|[]|:foo] (fn append/base,_,_,_,_,_,_,_)
|
||||||
|
0033: load
|
||||||
|
0034: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo|[]|:foo|fn append/base] (_,_,_,_,_,_,_,_)
|
||||||
|
0034: tail_call 002
|
||||||
|
=== tail call into fn append/base/2 from append ===
|
||||||
|
0036: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0036: store
|
||||||
|
0037: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]|->[]<-|:foo] ([:foo],_,_,_,_,_,_,_)
|
||||||
|
0037: pop_n 002
|
||||||
|
0039: [box { [] }|fn foo!|fn foos!|box { [] }|fn append/partial|[]] ([:foo],_,_,_,_,_,_,_)
|
||||||
|
0039: return
|
||||||
|
== returning from fn append ==
|
||||||
|
0040: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|[]|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0040: reset_match
|
||||||
|
0041: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|[]|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0041: match
|
||||||
|
0042: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|[]|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0042: panic_if_no_match
|
||||||
|
0043: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|[]|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0043: push_binding 000
|
||||||
|
0045: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|[]|[:foo]|box { [] }] (_,_,_,_,_,_,_,_)
|
||||||
|
0045: push_binding 003
|
||||||
|
0047: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|[]|[:foo]|box { [] }|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0047: get_upvalue 001
|
||||||
|
0049: [box { [] }|fn foo!|fn foos!|->box { [] }<-|fn append/partial|[]|[:foo]|box { [] }|[:foo]|fn store!] (_,_,_,_,_,_,_,_)
|
||||||
|
0049: tail_call 002
|
||||||
|
=== tail call into fn store!/2 from update! ===
|
||||||
|
0000: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0000: reset_match
|
||||||
|
0001: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0001: match_depth 001
|
||||||
|
0003: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0003: constant 00000: :box
|
||||||
|
0006: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]|:box] (_,_,_,_,_,_,_,_)
|
||||||
|
0006: match_type
|
||||||
|
0007: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0007: jump_if_no_match 00009
|
||||||
|
0010: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0010: match_depth 000
|
||||||
|
0012: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0012: match
|
||||||
|
0013: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0013: jump_if_no_match 00003
|
||||||
|
0016: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0016: jump 00000
|
||||||
|
0019: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0019: jump_if_no_match 00023
|
||||||
|
0022: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0022: get_upvalue 000
|
||||||
|
0024: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]|#{:list fn list/base...] (_,_,_,_,_,_,_,_)
|
||||||
|
0024: constant 00001: :store!
|
||||||
|
0027: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]|#{:list fn list/base...|:store!] (_,_,_,_,_,_,_,_)
|
||||||
|
0027: get_key
|
||||||
|
0028: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]|fn store!/base] (_,_,_,_,_,_,_,_)
|
||||||
|
0028: store
|
||||||
|
0029: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]] (fn store!/base,_,_,_,_,_,_,_)
|
||||||
|
0029: push_binding 000
|
||||||
|
0031: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]|box { [] }] (fn store!/base,_,_,_,_,_,_,_)
|
||||||
|
0031: push_binding 001
|
||||||
|
0033: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]|box { [] }|[:foo]] (fn store!/base,_,_,_,_,_,_,_)
|
||||||
|
0033: load
|
||||||
|
0034: [box { [] }|fn foo!|fn foos!|->box { [] }<-|[:foo]|box { [] }|[:foo]|fn store!/base] (_,_,_,_,_,_,_,_)
|
||||||
|
0034: call 002
|
||||||
|
=== calling into fn store!/base/2 ===
|
||||||
|
0036: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-|[:foo]|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0036: pop
|
||||||
|
0037: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0037: push_binding 001
|
||||||
|
0039: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-|[:foo]|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0039: store
|
||||||
|
0040: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-|[:foo]] ([:foo],_,_,_,_,_,_,_)
|
||||||
|
0040: load
|
||||||
|
0041: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-|[:foo]|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0041: store
|
||||||
|
0042: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-|[:foo]] ([:foo],_,_,_,_,_,_,_)
|
||||||
|
0042: pop_n 002
|
||||||
|
0044: [box { [:foo] }|fn foo!|fn foos!] ([:foo],_,_,_,_,_,_,_)
|
||||||
|
0044: return
|
||||||
|
== returning from fn store! ==
|
||||||
|
0076: [->box { [:foo] }<-|fn foo!|fn foos!|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0076: pop
|
||||||
|
0077: [->box { [:foo] }<-|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0077: ***calling function unbox stack depth: 3
|
||||||
|
0079: [->box { [:foo] }<-|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0079: resolving binding `foos` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0|foos!@2//0
|
||||||
|
0081: [->box { [:foo] }<-|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0081: at locals position 0
|
||||||
|
0083: [->box { [:foo] }<-|fn foo!|fn foos!] (_,_,_,_,_,_,_,_)
|
||||||
|
0083: push_binding 000
|
||||||
|
0085: [->box { [:foo] }<-|fn foo!|fn foos!|box { [:foo] }] (_,_,_,_,_,_,_,_)
|
||||||
|
0085: resolving binding `unbox` in sandbox
|
||||||
|
locals: foos@0//0|foo!@1//0|foos!@2//0
|
||||||
|
0087: [->box { [:foo] }<-|fn foo!|fn foos!|box { [:foo] }] (_,_,_,_,_,_,_,_)
|
||||||
|
0087: as global
|
||||||
|
0089: [->box { [:foo] }<-|fn foo!|fn foos!|box { [:foo] }] (_,_,_,_,_,_,_,_)
|
||||||
|
0089: constant 00004: :unbox
|
||||||
|
0092: [->box { [:foo] }<-|fn foo!|fn foos!|box { [:foo] }|:unbox] (_,_,_,_,_,_,_,_)
|
||||||
|
0092: push_global
|
||||||
|
0093: [->box { [:foo] }<-|fn foo!|fn foos!|box { [:foo] }|fn unbox] (_,_,_,_,_,_,_,_)
|
||||||
|
0093: ***after 1 args stack depth: 5
|
||||||
|
0095: [->box { [:foo] }<-|fn foo!|fn foos!|box { [:foo] }|fn unbox] (_,_,_,_,_,_,_,_)
|
||||||
|
0095: call 001
|
||||||
|
=== calling into fn unbox/1 ===
|
||||||
|
0000: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0000: reset_match
|
||||||
|
0001: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0001: match_depth 000
|
||||||
|
0003: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0003: constant 00000: :box
|
||||||
|
0006: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-|:box] (_,_,_,_,_,_,_,_)
|
||||||
|
0006: match_type
|
||||||
|
0007: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0007: jump_if_no_match 00003
|
||||||
|
0010: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0010: jump 00000
|
||||||
|
0013: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0013: jump_if_no_match 00015
|
||||||
|
0016: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-] (_,_,_,_,_,_,_,_)
|
||||||
|
0016: get_upvalue 000
|
||||||
|
0018: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-|#{:list fn list/base...] (_,_,_,_,_,_,_,_)
|
||||||
|
0018: constant 00001: :unbox
|
||||||
|
0021: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-|#{:list fn list/base...|:unbox] (_,_,_,_,_,_,_,_)
|
||||||
|
0021: get_key
|
||||||
|
0022: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-|fn unbox/base] (_,_,_,_,_,_,_,_)
|
||||||
|
0022: store
|
||||||
|
0023: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-] (fn unbox/base,_,_,_,_,_,_,_)
|
||||||
|
0023: push_binding 000
|
||||||
|
0025: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-|box { [:foo] }] (fn unbox/base,_,_,_,_,_,_,_)
|
||||||
|
0025: load
|
||||||
|
0026: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-|box { [:foo] }|fn unbox/base] (_,_,_,_,_,_,_,_)
|
||||||
|
0026: tail_call 001
|
||||||
|
=== tail call into fn unbox/base/1 from unbox ===
|
||||||
|
0028: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0028: store
|
||||||
|
0029: [box { [:foo] }|fn foo!|fn foos!|->box { [:foo] }<-] ([:foo],_,_,_,_,_,_,_)
|
||||||
|
0029: pop
|
||||||
|
0030: [box { [:foo] }|fn foo!|fn foos!] ([:foo],_,_,_,_,_,_,_)
|
||||||
|
0030: return
|
||||||
|
== returning from fn unbox ==
|
||||||
|
0097: [->box { [:foo] }<-|fn foo!|fn foos!|[:foo]] (_,_,_,_,_,_,_,_)
|
||||||
|
0097: store
|
||||||
|
0098: [->box { [:foo] }<-|fn foo!|fn foos!] ([:foo],_,_,_,_,_,_,_)
|
||||||
|
0098: leaving scope 0
|
||||||
|
0100: [->box { [:foo] }<-|fn foo!|fn foos!] ([:foo],_,_,_,_,_,_,_)
|
||||||
|
0100: releasing binding foos!@2//0
|
||||||
|
0102: [->box { [:foo] }<-|fn foo!|fn foos!] ([:foo],_,_,_,_,_,_,_)
|
||||||
|
0102: releasing binding foo!@1//0
|
||||||
|
0104: [->box { [:foo] }<-|fn foo!|fn foos!] ([:foo],_,_,_,_,_,_,_)
|
||||||
|
0104: releasing binding foos@0//0
|
||||||
|
0106: [->box { [:foo] }<-|fn foo!|fn foos!] ([:foo],_,_,_,_,_,_,_)
|
||||||
|
0106: ***leaving block before pop stack depth: 3
|
||||||
|
0108: [->box { [:foo] }<-|fn foo!|fn foos!] ([:foo],_,_,_,_,_,_,_)
|
||||||
|
0108: popping back from 3 to 0
|
||||||
|
0110: [->box { [:foo] }<-|fn foo!|fn foos!] ([:foo],_,_,_,_,_,_,_)
|
||||||
|
0110: pop_n 003
|
||||||
|
0112: [] ([:foo],_,_,_,_,_,_,_)
|
||||||
|
0112: load
|
||||||
|
0112: [] (_,_,_,_,_,_,_,_)
|
||||||
|
[:foo]
|
||||||
|
|
|
@ -27,11 +27,11 @@ impl Chunk {
|
||||||
match op {
|
match op {
|
||||||
Pop | Store | Stash | Load | Nil | True | False | MatchNil | MatchTrue | MatchFalse
|
Pop | Store | Stash | Load | Nil | True | False | MatchNil | MatchTrue | MatchFalse
|
||||||
| PanicIfNoMatch | ResetMatch | GetKey | PanicNoWhen | PanicNoMatch | TypeOf
|
| PanicIfNoMatch | ResetMatch | GetKey | PanicNoWhen | PanicNoMatch | TypeOf
|
||||||
| Duplicate | Decrement | Truncate | Noop | LoadTuple | LoadList | Eq | Add | Sub
|
| Duplicate | Decrement | ToInt | Noop | LoadTuple | LoadList | Eq | Add | Sub
|
||||||
| Mult | Div | Unbox | BoxStore | Assert | Get | At | Not | Panic | EmptyString
|
| Mult | Div | Unbox | BoxStore | Assert | Get | At | Not | Panic | EmptyString
|
||||||
| ConcatStrings | Stringify | MatchType | Return | Match | Print | AppendList
|
| ConcatStrings | Stringify | MatchType | Return | UnconditionalMatch | Print
|
||||||
| ConcatList | PushList | PushDict | AppendDict | ConcatDict | Nothing | PushGlobal
|
| AppendList | ConcatList | PushList | PushDict | AppendDict | ConcatDict | Nothing
|
||||||
| SetUpvalue => {
|
| PushGlobal | SetUpvalue => {
|
||||||
println!("{i:04}: {op}")
|
println!("{i:04}: {op}")
|
||||||
}
|
}
|
||||||
Constant | MatchConstant => {
|
Constant | MatchConstant => {
|
||||||
|
|
|
@ -521,12 +521,12 @@ impl Compiler {
|
||||||
self.report_depth("after let binding");
|
self.report_depth("after let binding");
|
||||||
}
|
}
|
||||||
WordPattern(name) => {
|
WordPattern(name) => {
|
||||||
self.emit_op(Op::Match);
|
self.emit_op(Op::UnconditionalMatch);
|
||||||
self.bind(name);
|
self.bind(name);
|
||||||
}
|
}
|
||||||
Word(name) | Splat(name) => self.resolve_binding(name),
|
Word(name) | Splat(name) => self.resolve_binding(name),
|
||||||
PlaceholderPattern => {
|
PlaceholderPattern => {
|
||||||
self.emit_op(Op::Match);
|
self.emit_op(Op::UnconditionalMatch);
|
||||||
}
|
}
|
||||||
NilPattern => {
|
NilPattern => {
|
||||||
self.emit_op(Op::MatchNil);
|
self.emit_op(Op::MatchNil);
|
||||||
|
@ -1124,7 +1124,7 @@ impl Compiler {
|
||||||
tup_jump_idxes.push(compiler.stub_jump(Op::JumpIfNoMatch));
|
tup_jump_idxes.push(compiler.stub_jump(Op::JumpIfNoMatch));
|
||||||
}
|
}
|
||||||
if pattern.is_empty() {
|
if pattern.is_empty() {
|
||||||
compiler.emit_op(Op::Match);
|
compiler.emit_op(Op::UnconditionalMatch);
|
||||||
}
|
}
|
||||||
let jump_idx = compiler.stub_jump(Op::Jump);
|
let jump_idx = compiler.stub_jump(Op::Jump);
|
||||||
for idx in tup_jump_idxes {
|
for idx in tup_jump_idxes {
|
||||||
|
@ -1239,8 +1239,10 @@ impl Compiler {
|
||||||
}
|
}
|
||||||
FnBody(_) => unreachable!(),
|
FnBody(_) => unreachable!(),
|
||||||
Repeat(times, body) => {
|
Repeat(times, body) => {
|
||||||
|
let tail_pos = self.tail_pos;
|
||||||
|
self.tail_pos = false;
|
||||||
self.visit(times);
|
self.visit(times);
|
||||||
self.emit_op(Op::Truncate);
|
self.emit_op(Op::ToInt);
|
||||||
// skip the decrement the first time
|
// skip the decrement the first time
|
||||||
self.emit_op(Op::Jump);
|
self.emit_op(Op::Jump);
|
||||||
self.emit_byte(0);
|
self.emit_byte(0);
|
||||||
|
@ -1260,6 +1262,7 @@ impl Compiler {
|
||||||
self.patch_jump(jiz_idx, self.len() - repeat_begin - 4);
|
self.patch_jump(jiz_idx, self.len() - repeat_begin - 4);
|
||||||
self.pop();
|
self.pop();
|
||||||
self.emit_constant(Value::Nil);
|
self.emit_constant(Value::Nil);
|
||||||
|
self.tail_pos = tail_pos;
|
||||||
}
|
}
|
||||||
Loop(value, clauses) => {
|
Loop(value, clauses) => {
|
||||||
self.report_depth("entering loop");
|
self.report_depth("entering loop");
|
||||||
|
|
|
@ -3,7 +3,7 @@ use imbl::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
const DEBUG_SCRIPT_COMPILE: bool = false;
|
const DEBUG_SCRIPT_COMPILE: bool = true;
|
||||||
const DEBUG_SCRIPT_RUN: bool = true;
|
const DEBUG_SCRIPT_RUN: bool = true;
|
||||||
const DEBUG_PRELUDE_COMPILE: bool = false;
|
const DEBUG_PRELUDE_COMPILE: bool = false;
|
||||||
const DEBUG_PRELUDE_RUN: bool = false;
|
const DEBUG_PRELUDE_RUN: bool = false;
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub enum Op {
|
||||||
Load,
|
Load,
|
||||||
LoadN,
|
LoadN,
|
||||||
ResetMatch,
|
ResetMatch,
|
||||||
Match,
|
UnconditionalMatch,
|
||||||
MatchNil,
|
MatchNil,
|
||||||
MatchTrue,
|
MatchTrue,
|
||||||
MatchFalse,
|
MatchFalse,
|
||||||
|
@ -60,7 +60,7 @@ pub enum Op {
|
||||||
JumpIfZero,
|
JumpIfZero,
|
||||||
Duplicate,
|
Duplicate,
|
||||||
Decrement,
|
Decrement,
|
||||||
Truncate,
|
ToInt,
|
||||||
MatchDepth,
|
MatchDepth,
|
||||||
Panic,
|
Panic,
|
||||||
EmptyString,
|
EmptyString,
|
||||||
|
@ -152,7 +152,7 @@ impl std::fmt::Display for Op {
|
||||||
Stash => "stash",
|
Stash => "stash",
|
||||||
Load => "load",
|
Load => "load",
|
||||||
LoadN => "load_n",
|
LoadN => "load_n",
|
||||||
Match => "match",
|
UnconditionalMatch => "match",
|
||||||
MatchNil => "match_nil",
|
MatchNil => "match_nil",
|
||||||
MatchTrue => "match_true",
|
MatchTrue => "match_true",
|
||||||
MatchFalse => "match_false",
|
MatchFalse => "match_false",
|
||||||
|
@ -191,7 +191,7 @@ impl std::fmt::Display for Op {
|
||||||
JumpBack => "jump_back",
|
JumpBack => "jump_back",
|
||||||
JumpIfZero => "jump_if_zero",
|
JumpIfZero => "jump_if_zero",
|
||||||
Decrement => "decrement",
|
Decrement => "decrement",
|
||||||
Truncate => "truncate",
|
ToInt => "truncate",
|
||||||
Duplicate => "duplicate",
|
Duplicate => "duplicate",
|
||||||
MatchDepth => "match_depth",
|
MatchDepth => "match_depth",
|
||||||
Panic => "panic",
|
Panic => "panic",
|
||||||
|
|
|
@ -29,7 +29,9 @@ impl LFn {
|
||||||
let shown = value.show();
|
let shown = value.show();
|
||||||
closed.borrow_mut().push(value);
|
closed.borrow_mut().push(value);
|
||||||
let pos = closed.borrow().len();
|
let pos = closed.borrow().len();
|
||||||
println!("closing over in {} at {pos}: {shown}", self.name(),);
|
if crate::DEBUG_SCRIPT_RUN {
|
||||||
|
println!("closing over in {} at {pos}: {shown}", self.name(),);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
392
src/vm.rs
392
src/vm.rs
|
@ -90,6 +90,7 @@ pub struct Vm {
|
||||||
pub match_depth: u8,
|
pub match_depth: u8,
|
||||||
pub result: Option<Result<Value, Panic>>,
|
pub result: Option<Result<Value, Panic>>,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
|
last_code: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Vm {
|
impl Vm {
|
||||||
|
@ -119,6 +120,7 @@ impl Vm {
|
||||||
match_depth: 0,
|
match_depth: 0,
|
||||||
result: None,
|
result: None,
|
||||||
debug,
|
debug,
|
||||||
|
last_code: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,24 +150,18 @@ impl Vm {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let inner = inner.join("|");
|
let inner = inner.join("|");
|
||||||
// let inner = self
|
|
||||||
// .stack
|
|
||||||
// .iter()
|
|
||||||
// .map(|val| val.show())
|
|
||||||
// .collect::<Vec<_>>()
|
|
||||||
// .join("|");
|
|
||||||
let register = self
|
let register = self
|
||||||
.return_register
|
.return_register
|
||||||
.iter()
|
.iter()
|
||||||
.map(|val| val.to_string())
|
.map(|val| val.to_string())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join(",");
|
.join(",");
|
||||||
println!("{:04}: [{inner}] ({register})", self.ip);
|
println!("{:04}: [{inner}] ({register})", self.last_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_debug(&self) {
|
fn print_debug(&self) {
|
||||||
self.print_stack();
|
self.print_stack();
|
||||||
let mut ip = self.ip;
|
let mut ip = self.last_code;
|
||||||
self.chunk().dissasemble_instr(&mut ip);
|
self.chunk().dissasemble_instr(&mut ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,120 +196,104 @@ impl Vm {
|
||||||
self.result = Some(Err(Panic::String(msg)));
|
self.result = Some(Err(Panic::String(msg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_value_at(&mut self, idx: u8) -> Value {
|
||||||
|
let idx = idx as usize;
|
||||||
|
let idx = idx + self.frame.stack_base;
|
||||||
|
self.stack[idx].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_scrutinee(&mut self) -> Value {
|
||||||
|
let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||||
|
self.stack[idx].clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read(&mut self) -> u8 {
|
||||||
|
let code = self.chunk().bytecode[self.ip];
|
||||||
|
self.ip += 1;
|
||||||
|
code
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read2(&mut self) -> usize {
|
||||||
|
let high = self.read();
|
||||||
|
let low = self.read();
|
||||||
|
combine_bytes(high, low)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn at_end(&mut self) -> bool {
|
||||||
|
self.ip >= self.chunk().bytecode.len()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn interpret(&mut self) {
|
pub fn interpret(&mut self) {
|
||||||
loop {
|
loop {
|
||||||
let Some(byte) = self.chunk().bytecode.get(self.ip) else {
|
if self.at_end() {
|
||||||
self.result = Some(Ok(self.stack.pop().unwrap()));
|
self.result = Some(Ok(self.stack.pop().unwrap()));
|
||||||
return;
|
return;
|
||||||
};
|
}
|
||||||
|
let code = self.read();
|
||||||
if self.debug {
|
if self.debug {
|
||||||
|
self.last_code = self.ip - 1;
|
||||||
self.print_debug();
|
self.print_debug();
|
||||||
}
|
}
|
||||||
let op = Op::from_u8(*byte).unwrap();
|
let op = Op::from_u8(code).unwrap();
|
||||||
use Op::*;
|
use Op::*;
|
||||||
match op {
|
match op {
|
||||||
Noop => {
|
Noop => (),
|
||||||
self.ip += 1;
|
Nil => self.push(Value::Nil),
|
||||||
}
|
Nothing => self.push(Value::Nothing),
|
||||||
Nil => {
|
True => self.push(Value::True),
|
||||||
self.push(Value::Nil);
|
False => self.push(Value::False),
|
||||||
self.ip += 1;
|
Msg => {
|
||||||
}
|
let _ = self.read();
|
||||||
Nothing => {
|
|
||||||
self.push(Value::Nothing);
|
|
||||||
self.ip += 1;
|
|
||||||
}
|
|
||||||
True => {
|
|
||||||
self.push(Value::True);
|
|
||||||
self.ip += 1;
|
|
||||||
}
|
|
||||||
False => {
|
|
||||||
self.push(Value::False);
|
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Constant => {
|
Constant => {
|
||||||
let high = self.chunk().bytecode[self.ip + 1];
|
let const_idx = self.read2();
|
||||||
let low = self.chunk().bytecode[self.ip + 2];
|
|
||||||
let const_idx = combine_bytes(high, low);
|
|
||||||
let value = self.chunk().constants[const_idx].clone();
|
let value = self.chunk().constants[const_idx].clone();
|
||||||
self.push(value);
|
self.push(value);
|
||||||
self.ip += 3;
|
|
||||||
}
|
}
|
||||||
Jump => {
|
Jump => {
|
||||||
let high = self.chunk().bytecode[self.ip + 1];
|
let jump_len = self.read2();
|
||||||
let low = self.chunk().bytecode[self.ip + 2];
|
self.ip += jump_len;
|
||||||
let jump_len = combine_bytes(high, low);
|
|
||||||
// let jump_len = self.chunk().bytecode[self.ip + 1];
|
|
||||||
self.ip += jump_len + 3;
|
|
||||||
}
|
}
|
||||||
JumpBack => {
|
JumpBack => {
|
||||||
let high = self.chunk().bytecode[self.ip + 1];
|
let jump_len = self.read2();
|
||||||
let low = self.chunk().bytecode[self.ip + 2];
|
self.ip -= jump_len + 3;
|
||||||
let jump_len = combine_bytes(high, low);
|
|
||||||
// let jump_len = self.chunk().bytecode[self.ip + 1];
|
|
||||||
self.ip -= jump_len;
|
|
||||||
}
|
}
|
||||||
JumpIfFalse => {
|
JumpIfFalse => {
|
||||||
let high = self.chunk().bytecode[self.ip + 1];
|
let jump_len = self.read2();
|
||||||
let low = self.chunk().bytecode[self.ip + 2];
|
|
||||||
let jump_len = combine_bytes(high, low);
|
|
||||||
// let jump_len = self.chunk().bytecode[self.ip + 1];
|
|
||||||
let cond = self.pop();
|
let cond = self.pop();
|
||||||
match cond {
|
match cond {
|
||||||
Value::Nil | Value::False => {
|
Value::Nil | Value::False => self.ip += jump_len,
|
||||||
self.ip += jump_len + 3;
|
_ => (),
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.ip += 3;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JumpIfTrue => {
|
JumpIfTrue => {
|
||||||
let high = self.chunk().bytecode[self.ip + 1];
|
let jump_len = self.read2();
|
||||||
let low = self.chunk().bytecode[self.ip + 2];
|
|
||||||
let jump_len = combine_bytes(high, low);
|
|
||||||
// let jump_len = self.chunk().bytecode[self.ip + 1];
|
|
||||||
let cond = self.pop();
|
let cond = self.pop();
|
||||||
match cond {
|
match cond {
|
||||||
Value::Nil | Value::False => {
|
Value::Nil | Value::False => (),
|
||||||
self.ip += 3;
|
_ => self.ip += jump_len,
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.ip += jump_len + 3;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JumpIfZero => {
|
JumpIfZero => {
|
||||||
let high = self.chunk().bytecode[self.ip + 1];
|
let jump_len = self.read2();
|
||||||
let low = self.chunk().bytecode[self.ip + 2];
|
|
||||||
let jump_len = combine_bytes(high, low);
|
|
||||||
// let jump_len = self.chunk().bytecode[self.ip + 1];
|
|
||||||
let cond = self.pop();
|
let cond = self.pop();
|
||||||
match cond {
|
match cond {
|
||||||
Value::Number(x) if x <= 0.0 => {
|
Value::Number(x) if x <= 0.0 => self.ip += jump_len,
|
||||||
self.ip += jump_len + 3;
|
Value::Number(..) => (),
|
||||||
}
|
|
||||||
Value::Number(..) => {
|
|
||||||
self.ip += 3;
|
|
||||||
}
|
|
||||||
_ => return self.panic("repeat requires a number"),
|
_ => return self.panic("repeat requires a number"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Pop => {
|
Pop => {
|
||||||
self.pop();
|
self.pop();
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
PopN => {
|
PopN => {
|
||||||
let n = self.chunk().bytecode[self.ip + 1] as usize;
|
let n = self.read() as usize;
|
||||||
self.stack.truncate(self.stack.len() - n);
|
self.stack.truncate(self.stack.len() - n);
|
||||||
self.ip += 2;
|
|
||||||
}
|
}
|
||||||
PushBinding => {
|
PushBinding => {
|
||||||
let binding_idx =
|
let idx = self.read();
|
||||||
self.chunk().bytecode[self.ip + 1] as usize + self.frame.stack_base;
|
let value = self.get_value_at(idx);
|
||||||
let binding_value = self.stack[binding_idx].clone();
|
self.push(value);
|
||||||
self.push(binding_value);
|
|
||||||
self.ip += 2;
|
|
||||||
}
|
}
|
||||||
PushGlobal => {
|
PushGlobal => {
|
||||||
let key = self.pop();
|
let key = self.pop();
|
||||||
|
@ -322,98 +302,74 @@ impl Vm {
|
||||||
};
|
};
|
||||||
let value = self.chunk().env.get(name).unwrap();
|
let value = self.chunk().env.get(name).unwrap();
|
||||||
self.push(value.clone());
|
self.push(value.clone());
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Store => {
|
Store => {
|
||||||
self.return_register[0] = self.pop();
|
self.return_register[0] = self.pop();
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
StoreN => {
|
StoreN => {
|
||||||
let n = self.chunk().bytecode[self.ip + 1] as usize;
|
let n = self.read() as usize;
|
||||||
for i in (0..n).rev() {
|
for i in (0..n).rev() {
|
||||||
self.return_register[i] = self.pop();
|
self.return_register[i] = self.pop();
|
||||||
}
|
}
|
||||||
self.ip += 2;
|
|
||||||
}
|
}
|
||||||
Stash => {
|
Stash => {
|
||||||
self.return_register[0] = self.peek().clone();
|
self.return_register[0] = self.peek().clone();
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Load => {
|
Load => {
|
||||||
let mut value = Value::Nothing;
|
let mut value = Value::Nothing;
|
||||||
swap(&mut self.return_register[0], &mut value);
|
swap(&mut self.return_register[0], &mut value);
|
||||||
self.push(value);
|
self.push(value);
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
LoadN => {
|
LoadN => {
|
||||||
let n = self.chunk().bytecode[self.ip + 1] as usize;
|
let n = self.read() as usize;
|
||||||
for i in 0..n {
|
for i in 0..n {
|
||||||
let mut value = Value::Nothing;
|
let mut value = Value::Nothing;
|
||||||
swap(&mut self.return_register[i], &mut value);
|
swap(&mut self.return_register[i], &mut value);
|
||||||
self.push(value);
|
self.push(value);
|
||||||
}
|
}
|
||||||
self.ip += 2;
|
|
||||||
}
|
}
|
||||||
ResetMatch => {
|
ResetMatch => {
|
||||||
self.matches = false;
|
self.matches = false;
|
||||||
self.match_depth = 0;
|
self.match_depth = 0;
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Match => {
|
UnconditionalMatch => {
|
||||||
self.matches = true;
|
self.matches = true;
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
MatchType => {
|
MatchType => {
|
||||||
let as_type = self.pop();
|
let as_type = self.pop();
|
||||||
let Value::Keyword(as_type) = as_type else {
|
let Value::Keyword(as_type) = as_type else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
let value = self.get_scrutinee();
|
||||||
let val_type = self.stack[idx].type_of();
|
let val_type = value.type_of();
|
||||||
self.matches = val_type == as_type;
|
self.matches = val_type == as_type;
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
MatchNil => {
|
MatchNil => {
|
||||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
let value = self.get_scrutinee();
|
||||||
if self.stack[idx] == Value::Nil {
|
self.matches = value == Value::Nil;
|
||||||
self.matches = true;
|
|
||||||
};
|
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
MatchTrue => {
|
MatchTrue => {
|
||||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
let value = self.get_scrutinee();
|
||||||
if self.stack[idx] == Value::True {
|
self.matches = value == Value::True;
|
||||||
self.matches = true;
|
|
||||||
};
|
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
MatchFalse => {
|
MatchFalse => {
|
||||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
let value = self.get_scrutinee();
|
||||||
if self.stack[idx] == Value::False {
|
self.matches = value == Value::False;
|
||||||
self.matches = true;
|
|
||||||
}
|
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
PanicIfNoMatch => {
|
PanicIfNoMatch => {
|
||||||
if !self.matches {
|
if !self.matches {
|
||||||
return self.panic("no match");
|
return self.panic("no match");
|
||||||
} else {
|
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MatchConstant => {
|
MatchConstant => {
|
||||||
let high = self.chunk().bytecode[self.ip + 1];
|
let const_idx = self.read2();
|
||||||
let low = self.chunk().bytecode[self.ip + 2];
|
let scrutinee = self.get_scrutinee();
|
||||||
let const_idx = combine_bytes(high, low);
|
// let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
self.matches = scrutinee == self.chunk().constants[const_idx];
|
||||||
self.matches = self.stack[idx] == self.chunk().constants[const_idx];
|
|
||||||
self.ip += 3;
|
|
||||||
}
|
}
|
||||||
MatchString => {
|
MatchString => {
|
||||||
let pattern_idx = self.chunk().bytecode[self.ip + 1];
|
let pattern_idx = self.read();
|
||||||
self.ip += 2;
|
let scrutinee = self.get_scrutinee();
|
||||||
let scrutinee_idx = self.stack.len() - self.match_depth as usize - 1;
|
|
||||||
let scrutinee = self.stack[scrutinee_idx].clone();
|
|
||||||
self.matches = match scrutinee {
|
self.matches = match scrutinee {
|
||||||
Value::String(str) => self.chunk().string_patterns[pattern_idx as usize]
|
Value::String(str) => self.chunk().string_patterns[pattern_idx as usize]
|
||||||
.re
|
.re
|
||||||
|
@ -425,13 +381,12 @@ impl Vm {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
PushStringMatches => {
|
PushStringMatches => {
|
||||||
let pattern_idx = self.chunk().bytecode[self.ip + 1];
|
let pattern_idx = self.read();
|
||||||
self.ip += 2;
|
|
||||||
let pattern_len = self.chunk().string_patterns[pattern_idx as usize]
|
let pattern_len = self.chunk().string_patterns[pattern_idx as usize]
|
||||||
.words
|
.words
|
||||||
.len();
|
.len();
|
||||||
let scrutinee_idx = self.stack.len() - self.match_depth as usize - 1;
|
// let scrutinee_idx = self.stack.len() - self.match_depth as usize - 1;
|
||||||
let scrutinee = self.stack[scrutinee_idx].clone();
|
let scrutinee = self.get_scrutinee();
|
||||||
let scrutinee = match scrutinee {
|
let scrutinee = match scrutinee {
|
||||||
Value::String(str) => str.as_ref().clone(),
|
Value::String(str) => str.as_ref().clone(),
|
||||||
Value::Interned(str) => str.to_string(),
|
Value::Interned(str) => str.to_string(),
|
||||||
|
@ -447,35 +402,32 @@ impl Vm {
|
||||||
self.match_depth += pattern_len as u8;
|
self.match_depth += pattern_len as u8;
|
||||||
}
|
}
|
||||||
MatchTuple => {
|
MatchTuple => {
|
||||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
// let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||||
let tuple_len = self.chunk().bytecode[self.ip + 1];
|
let tuple_len = self.read() as usize;
|
||||||
let scrutinee = self.stack[idx].clone();
|
let scrutinee = self.get_scrutinee();
|
||||||
match scrutinee {
|
match scrutinee {
|
||||||
Value::Tuple(members) => self.matches = members.len() == tuple_len as usize,
|
Value::Tuple(members) => self.matches = members.len() == tuple_len,
|
||||||
_ => self.matches = false,
|
_ => self.matches = false,
|
||||||
};
|
};
|
||||||
self.ip += 2;
|
|
||||||
}
|
}
|
||||||
MatchSplattedTuple => {
|
MatchSplattedTuple => {
|
||||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
let patt_len = self.read() as usize;
|
||||||
let patt_len = self.chunk().bytecode[self.ip + 1];
|
let scrutinee = self.get_scrutinee();
|
||||||
let scrutinee = self.stack[idx].clone();
|
|
||||||
match scrutinee {
|
match scrutinee {
|
||||||
Value::Tuple(members) => self.matches = members.len() >= patt_len as usize,
|
Value::Tuple(members) => self.matches = members.len() >= patt_len,
|
||||||
_ => self.matches = false,
|
_ => self.matches = false,
|
||||||
}
|
}
|
||||||
self.ip += 2;
|
|
||||||
}
|
}
|
||||||
PushTuple => {
|
PushTuple => {
|
||||||
let tuple_len = self.chunk().bytecode[self.ip + 1];
|
let tuple_len = self.read() as usize;
|
||||||
let tuple_members = self.stack.split_off(self.stack.len() - tuple_len as usize);
|
let tuple_members = self.stack.split_off(self.stack.len() - tuple_len);
|
||||||
let tuple = Value::Tuple(Rc::new(tuple_members));
|
let tuple = Value::Tuple(Rc::new(tuple_members));
|
||||||
self.push(tuple);
|
self.push(tuple);
|
||||||
self.ip += 2;
|
|
||||||
}
|
}
|
||||||
LoadTuple => {
|
LoadTuple => {
|
||||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
// let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||||
let tuple = self.stack[idx].clone();
|
// let tuple = self.stack[idx].clone();
|
||||||
|
let tuple = self.get_scrutinee();
|
||||||
match tuple {
|
match tuple {
|
||||||
Value::Tuple(members) => {
|
Value::Tuple(members) => {
|
||||||
for member in members.iter() {
|
for member in members.iter() {
|
||||||
|
@ -484,12 +436,10 @@ impl Vm {
|
||||||
}
|
}
|
||||||
_ => return self.panic("internal error: expected tuple"),
|
_ => return self.panic("internal error: expected tuple"),
|
||||||
};
|
};
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
LoadSplattedTuple => {
|
LoadSplattedTuple => {
|
||||||
let load_len = self.chunk().bytecode[self.ip + 1] as usize;
|
let load_len = self.read() as usize;
|
||||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
let tuple = self.get_scrutinee();
|
||||||
let tuple = self.stack[idx].clone();
|
|
||||||
let Value::Tuple(members) = tuple else {
|
let Value::Tuple(members) = tuple else {
|
||||||
return self.panic("internal error: expected tuple");
|
return self.panic("internal error: expected tuple");
|
||||||
};
|
};
|
||||||
|
@ -501,11 +451,9 @@ impl Vm {
|
||||||
splatted.push_back(members[i].clone());
|
splatted.push_back(members[i].clone());
|
||||||
}
|
}
|
||||||
self.push(Value::List(Box::new(splatted)));
|
self.push(Value::List(Box::new(splatted)));
|
||||||
self.ip += 2;
|
|
||||||
}
|
}
|
||||||
PushList => {
|
PushList => {
|
||||||
self.push(Value::List(Box::new(Vector::new())));
|
self.push(Value::List(Box::new(Vector::new())));
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
AppendList => {
|
AppendList => {
|
||||||
let value = self.pop();
|
let value = self.pop();
|
||||||
|
@ -515,7 +463,6 @@ impl Vm {
|
||||||
};
|
};
|
||||||
list.push_back(value);
|
list.push_back(value);
|
||||||
self.push(Value::List(list));
|
self.push(Value::List(list));
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
ConcatList => {
|
ConcatList => {
|
||||||
let splatted = self.pop();
|
let splatted = self.pop();
|
||||||
|
@ -528,31 +475,28 @@ impl Vm {
|
||||||
};
|
};
|
||||||
target.append(*splatted);
|
target.append(*splatted);
|
||||||
self.push(Value::List(target));
|
self.push(Value::List(target));
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
MatchList => {
|
MatchList => {
|
||||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
// let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||||
let list_len = self.chunk().bytecode[self.ip + 1];
|
let list_len = self.read() as usize;
|
||||||
let scrutinee = self.stack[idx].clone();
|
let scrutinee = self.get_scrutinee();
|
||||||
match scrutinee {
|
match scrutinee {
|
||||||
Value::List(members) => self.matches = members.len() == list_len as usize,
|
Value::List(members) => self.matches = members.len() == list_len,
|
||||||
_ => self.matches = false,
|
_ => self.matches = false,
|
||||||
};
|
};
|
||||||
self.ip += 2;
|
|
||||||
}
|
}
|
||||||
MatchSplattedList => {
|
MatchSplattedList => {
|
||||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
// let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||||
let patt_len = self.chunk().bytecode[self.ip + 1];
|
let patt_len = self.read() as usize;
|
||||||
let scrutinee = self.stack[idx].clone();
|
let scrutinee = self.get_scrutinee();
|
||||||
match scrutinee {
|
match scrutinee {
|
||||||
Value::List(members) => self.matches = members.len() >= patt_len as usize,
|
Value::List(members) => self.matches = members.len() >= patt_len,
|
||||||
_ => self.matches = false,
|
_ => self.matches = false,
|
||||||
}
|
}
|
||||||
self.ip += 2;
|
|
||||||
}
|
}
|
||||||
LoadList => {
|
LoadList => {
|
||||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
// let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||||
let list = self.stack[idx].clone();
|
let list = self.get_scrutinee();
|
||||||
match list {
|
match list {
|
||||||
Value::List(members) => {
|
Value::List(members) => {
|
||||||
for member in members.iter() {
|
for member in members.iter() {
|
||||||
|
@ -561,12 +505,10 @@ impl Vm {
|
||||||
}
|
}
|
||||||
_ => return self.panic("internal error: expected list"),
|
_ => return self.panic("internal error: expected list"),
|
||||||
};
|
};
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
LoadSplattedList => {
|
LoadSplattedList => {
|
||||||
let loaded_len = self.chunk().bytecode[self.ip + 1] as usize;
|
let loaded_len = self.read() as usize;
|
||||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
let list = self.get_scrutinee();
|
||||||
let list = self.stack[idx].clone();
|
|
||||||
let Value::List(members) = list else {
|
let Value::List(members) = list else {
|
||||||
return self.panic("internal error: expected list");
|
return self.panic("internal error: expected list");
|
||||||
};
|
};
|
||||||
|
@ -575,11 +517,9 @@ impl Vm {
|
||||||
}
|
}
|
||||||
let splatted = Value::List(Box::new(members.skip(loaded_len - 1)));
|
let splatted = Value::List(Box::new(members.skip(loaded_len - 1)));
|
||||||
self.push(splatted);
|
self.push(splatted);
|
||||||
self.ip += 2;
|
|
||||||
}
|
}
|
||||||
PushDict => {
|
PushDict => {
|
||||||
self.push(Value::Dict(Box::new(HashMap::new())));
|
self.push(Value::Dict(Box::new(HashMap::new())));
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
AppendDict => {
|
AppendDict => {
|
||||||
let value = self.pop();
|
let value = self.pop();
|
||||||
|
@ -591,7 +531,6 @@ impl Vm {
|
||||||
};
|
};
|
||||||
dict.insert(key, value);
|
dict.insert(key, value);
|
||||||
self.push(Value::Dict(dict));
|
self.push(Value::Dict(dict));
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
ConcatDict => {
|
ConcatDict => {
|
||||||
let Value::Dict(splatted) = self.pop() else {
|
let Value::Dict(splatted) = self.pop() else {
|
||||||
|
@ -602,11 +541,10 @@ impl Vm {
|
||||||
};
|
};
|
||||||
let union = splatted.union(*target);
|
let union = splatted.union(*target);
|
||||||
self.push(Value::Dict(Box::new(union)));
|
self.push(Value::Dict(Box::new(union)));
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
LoadDictValue => {
|
LoadDictValue => {
|
||||||
let dict_idx = self.chunk().bytecode[self.ip + 1] as usize;
|
let dict_idx = self.read();
|
||||||
let dict = match self.stack[dict_idx].clone() {
|
let dict = match self.get_value_at(dict_idx) {
|
||||||
Value::Dict(dict) => dict,
|
Value::Dict(dict) => dict,
|
||||||
value => {
|
value => {
|
||||||
println!(
|
println!(
|
||||||
|
@ -621,27 +559,24 @@ impl Vm {
|
||||||
};
|
};
|
||||||
let value = dict.get(&key).unwrap_or(&Value::Nil);
|
let value = dict.get(&key).unwrap_or(&Value::Nil);
|
||||||
self.push(value.clone());
|
self.push(value.clone());
|
||||||
self.ip += 2;
|
|
||||||
}
|
}
|
||||||
MatchDict => {
|
MatchDict => {
|
||||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
// let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||||
let dict_len = self.chunk().bytecode[self.ip + 1];
|
let dict_len = self.read();
|
||||||
let scrutinee = self.stack[idx].clone();
|
let scrutinee = self.get_scrutinee();
|
||||||
match scrutinee {
|
match scrutinee {
|
||||||
Value::Dict(members) => self.matches = members.len() == dict_len as usize,
|
Value::Dict(members) => self.matches = members.len() == dict_len as usize,
|
||||||
_ => self.matches = false,
|
_ => self.matches = false,
|
||||||
};
|
};
|
||||||
self.ip += 2;
|
|
||||||
}
|
}
|
||||||
MatchSplattedDict => {
|
MatchSplattedDict => {
|
||||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
// let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||||
let patt_len = self.chunk().bytecode[self.ip + 1];
|
let patt_len = self.read() as usize;
|
||||||
let scrutinee = self.stack[idx].clone();
|
let scrutinee = self.get_scrutinee();
|
||||||
match scrutinee {
|
match scrutinee {
|
||||||
Value::Dict(members) => self.matches = members.len() >= patt_len as usize,
|
Value::Dict(members) => self.matches = members.len() >= patt_len,
|
||||||
_ => self.matches = false,
|
_ => self.matches = false,
|
||||||
}
|
}
|
||||||
self.ip += 2;
|
|
||||||
}
|
}
|
||||||
DropDictEntry => {
|
DropDictEntry => {
|
||||||
let Value::Keyword(key_to_drop) = self.pop() else {
|
let Value::Keyword(key_to_drop) = self.pop() else {
|
||||||
|
@ -652,12 +587,10 @@ impl Vm {
|
||||||
};
|
};
|
||||||
dict.remove(key_to_drop);
|
dict.remove(key_to_drop);
|
||||||
self.push(Value::Dict(dict));
|
self.push(Value::Dict(dict));
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
PushBox => {
|
PushBox => {
|
||||||
let val = self.pop();
|
let val = self.pop();
|
||||||
self.push(Value::Box(Rc::new(RefCell::new(val))));
|
self.push(Value::Box(Rc::new(RefCell::new(val))));
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
GetKey => {
|
GetKey => {
|
||||||
let key = self.pop();
|
let key = self.pop();
|
||||||
|
@ -670,40 +603,29 @@ impl Vm {
|
||||||
_ => Value::Nil,
|
_ => Value::Nil,
|
||||||
};
|
};
|
||||||
self.push(value);
|
self.push(value);
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
JumpIfNoMatch => {
|
JumpIfNoMatch => {
|
||||||
let high = self.chunk().bytecode[self.ip + 1];
|
let jump_len = self.read2();
|
||||||
let low = self.chunk().bytecode[self.ip + 2];
|
|
||||||
let jump_len = combine_bytes(high, low);
|
|
||||||
// let jump_len = self.chunk().bytecode[self.ip + 1] as usize;
|
// let jump_len = self.chunk().bytecode[self.ip + 1] as usize;
|
||||||
if !self.matches {
|
if !self.matches {
|
||||||
self.ip += jump_len + 3;
|
self.ip += jump_len
|
||||||
} else {
|
|
||||||
self.ip += 3;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JumpIfMatch => {
|
JumpIfMatch => {
|
||||||
let high = self.chunk().bytecode[self.ip + 1];
|
let jump_len = self.read2();
|
||||||
let low = self.chunk().bytecode[self.ip + 2];
|
|
||||||
let jump_len = combine_bytes(high, low);
|
|
||||||
if self.matches {
|
if self.matches {
|
||||||
self.ip += jump_len + 3;
|
self.ip += jump_len;
|
||||||
} else {
|
|
||||||
self.ip += 3;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TypeOf => {
|
TypeOf => {
|
||||||
let val = self.pop();
|
let val = self.pop();
|
||||||
let type_of = Value::Keyword(val.type_of());
|
let type_of = Value::Keyword(val.type_of());
|
||||||
self.push(type_of);
|
self.push(type_of);
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Truncate => {
|
ToInt => {
|
||||||
let val = self.pop();
|
let val = self.pop();
|
||||||
if let Value::Number(x) = val {
|
if let Value::Number(x) = val {
|
||||||
self.push(Value::Number(x as usize as f64));
|
self.push(Value::Number(x as usize as f64));
|
||||||
self.ip += 1;
|
|
||||||
} else {
|
} else {
|
||||||
return self.panic("repeat requires a number");
|
return self.panic("repeat requires a number");
|
||||||
}
|
}
|
||||||
|
@ -712,18 +634,15 @@ impl Vm {
|
||||||
let val = self.pop();
|
let val = self.pop();
|
||||||
if let Value::Number(x) = val {
|
if let Value::Number(x) = val {
|
||||||
self.push(Value::Number(x - 1.0));
|
self.push(Value::Number(x - 1.0));
|
||||||
self.ip += 1;
|
|
||||||
} else {
|
} else {
|
||||||
return self.panic("you may only decrement a number");
|
return self.panic("you may only decrement a number");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Duplicate => {
|
Duplicate => {
|
||||||
self.push(self.peek().clone());
|
self.push(self.peek().clone());
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
MatchDepth => {
|
MatchDepth => {
|
||||||
self.match_depth = self.chunk().bytecode[self.ip + 1];
|
self.match_depth = self.read();
|
||||||
self.ip += 2;
|
|
||||||
}
|
}
|
||||||
PanicNoWhen | PanicNoMatch => {
|
PanicNoWhen | PanicNoMatch => {
|
||||||
return self.panic("no match");
|
return self.panic("no match");
|
||||||
|
@ -736,7 +655,6 @@ impl Vm {
|
||||||
} else {
|
} else {
|
||||||
self.push(Value::False)
|
self.push(Value::False)
|
||||||
}
|
}
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Add => {
|
Add => {
|
||||||
let first = self.pop();
|
let first = self.pop();
|
||||||
|
@ -746,7 +664,6 @@ impl Vm {
|
||||||
} else {
|
} else {
|
||||||
return self.panic("`add` requires two numbers");
|
return self.panic("`add` requires two numbers");
|
||||||
}
|
}
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Sub => {
|
Sub => {
|
||||||
let first = self.pop();
|
let first = self.pop();
|
||||||
|
@ -756,7 +673,6 @@ impl Vm {
|
||||||
} else {
|
} else {
|
||||||
return self.panic("`sub` requires two numbers");
|
return self.panic("`sub` requires two numbers");
|
||||||
}
|
}
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Mult => {
|
Mult => {
|
||||||
let first = self.pop();
|
let first = self.pop();
|
||||||
|
@ -766,7 +682,6 @@ impl Vm {
|
||||||
} else {
|
} else {
|
||||||
return self.panic("`mult` requires two numbers");
|
return self.panic("`mult` requires two numbers");
|
||||||
}
|
}
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Div => {
|
Div => {
|
||||||
let first = self.pop();
|
let first = self.pop();
|
||||||
|
@ -779,7 +694,6 @@ impl Vm {
|
||||||
} else {
|
} else {
|
||||||
return self.panic("`div` requires two numbers");
|
return self.panic("`div` requires two numbers");
|
||||||
}
|
}
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Unbox => {
|
Unbox => {
|
||||||
let the_box = self.pop();
|
let the_box = self.pop();
|
||||||
|
@ -789,7 +703,6 @@ impl Vm {
|
||||||
return self.panic("`unbox` requires a box");
|
return self.panic("`unbox` requires a box");
|
||||||
};
|
};
|
||||||
self.push(inner);
|
self.push(inner);
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
BoxStore => {
|
BoxStore => {
|
||||||
let new_value = self.pop();
|
let new_value = self.pop();
|
||||||
|
@ -800,14 +713,12 @@ impl Vm {
|
||||||
return self.panic("`store` requires a box");
|
return self.panic("`store` requires a box");
|
||||||
}
|
}
|
||||||
self.push(new_value);
|
self.push(new_value);
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Assert => {
|
Assert => {
|
||||||
let value = self.stack.last().unwrap();
|
let value = self.stack.last().unwrap();
|
||||||
if let Value::Nil | Value::False = value {
|
if let Value::Nil | Value::False = value {
|
||||||
return self.panic("asserted falsy value");
|
return self.panic("asserted falsy value");
|
||||||
}
|
}
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Get => {
|
Get => {
|
||||||
let key = self.pop();
|
let key = self.pop();
|
||||||
|
@ -820,7 +731,6 @@ impl Vm {
|
||||||
_ => return self.panic("keys must be keywords"),
|
_ => return self.panic("keys must be keywords"),
|
||||||
};
|
};
|
||||||
self.push(value);
|
self.push(value);
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
At => {
|
At => {
|
||||||
let idx = self.pop();
|
let idx = self.pop();
|
||||||
|
@ -836,7 +746,6 @@ impl Vm {
|
||||||
_ => return self.panic("indexes must be numbers"),
|
_ => return self.panic("indexes must be numbers"),
|
||||||
};
|
};
|
||||||
self.push(value);
|
self.push(value);
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Not => {
|
Not => {
|
||||||
let value = self.pop();
|
let value = self.pop();
|
||||||
|
@ -845,7 +754,6 @@ impl Vm {
|
||||||
_ => Value::False,
|
_ => Value::False,
|
||||||
};
|
};
|
||||||
self.push(negated);
|
self.push(negated);
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Panic => {
|
Panic => {
|
||||||
let msg = self.pop().show();
|
let msg = self.pop().show();
|
||||||
|
@ -853,7 +761,6 @@ impl Vm {
|
||||||
}
|
}
|
||||||
EmptyString => {
|
EmptyString => {
|
||||||
self.push(Value::String(Rc::new("".to_string())));
|
self.push(Value::String(Rc::new("".to_string())));
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
//TODO: don't use the schlemiel's algo here
|
//TODO: don't use the schlemiel's algo here
|
||||||
ConcatStrings => {
|
ConcatStrings => {
|
||||||
|
@ -868,18 +775,15 @@ impl Vm {
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
self.push(combined);
|
self.push(combined);
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Stringify => {
|
Stringify => {
|
||||||
let to_stringify = self.pop();
|
let to_stringify = self.pop();
|
||||||
let the_string = to_stringify.stringify();
|
let the_string = to_stringify.stringify();
|
||||||
let stringified = Value::String(Rc::new(the_string));
|
let stringified = Value::String(Rc::new(the_string));
|
||||||
self.push(stringified);
|
self.push(stringified);
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
Partial => {
|
Partial => {
|
||||||
let arity = self.chunk().bytecode[self.ip + 1];
|
let arity = self.read();
|
||||||
self.ip += 2;
|
|
||||||
let the_fn = self.pop();
|
let the_fn = self.pop();
|
||||||
let Value::Fn(ref inner) = the_fn else {
|
let Value::Fn(ref inner) = the_fn else {
|
||||||
return self.panic("only functions may be partially applied");
|
return self.panic("only functions may be partially applied");
|
||||||
|
@ -893,24 +797,23 @@ impl Vm {
|
||||||
self.push(Value::Partial(Rc::new(partial)));
|
self.push(Value::Partial(Rc::new(partial)));
|
||||||
}
|
}
|
||||||
TailCall => {
|
TailCall => {
|
||||||
let arity = self.chunk().bytecode[self.ip + 1];
|
let arity = self.read();
|
||||||
self.ip += 2;
|
|
||||||
|
|
||||||
let val = self.pop();
|
let called = self.pop();
|
||||||
|
|
||||||
if self.debug {
|
if self.debug {
|
||||||
println!(
|
println!(
|
||||||
"=== tail call into {val}/{arity} from {} ===",
|
"=== tail call into {called}/{arity} from {} ===",
|
||||||
self.frame.function.as_fn().name()
|
self.frame.function.as_fn().name()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
match val {
|
match called {
|
||||||
Value::Fn(_) => {
|
Value::Fn(_) => {
|
||||||
if !val.as_fn().accepts(arity) {
|
if !called.as_fn().accepts(arity) {
|
||||||
return self.panic_with(format!(
|
return self.panic_with(format!(
|
||||||
"wrong number of arguments to {} passing {arity} args",
|
"wrong number of arguments to {} passing {arity} args",
|
||||||
val.show()
|
called.show()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
// first put the arguments in the register
|
// first put the arguments in the register
|
||||||
|
@ -930,7 +833,7 @@ impl Vm {
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let splat_arity = val.as_fn().splat_arity();
|
let splat_arity = called.as_fn().splat_arity();
|
||||||
if splat_arity > 0 && arity >= splat_arity {
|
if splat_arity > 0 && arity >= splat_arity {
|
||||||
let splatted_args = self.stack.split_off(
|
let splatted_args = self.stack.split_off(
|
||||||
self.stack.len() - (arity - splat_arity) as usize - 1,
|
self.stack.len() - (arity - splat_arity) as usize - 1,
|
||||||
|
@ -945,7 +848,7 @@ impl Vm {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut frame = CallFrame {
|
let mut frame = CallFrame {
|
||||||
function: val,
|
function: called,
|
||||||
arity,
|
arity,
|
||||||
stack_base: self.stack.len() - arity as usize,
|
stack_base: self.stack.len() - arity as usize,
|
||||||
ip: 0,
|
ip: 0,
|
||||||
|
@ -1010,28 +913,29 @@ impl Vm {
|
||||||
self.call_stack.push(frame);
|
self.call_stack.push(frame);
|
||||||
self.ip = 0;
|
self.ip = 0;
|
||||||
}
|
}
|
||||||
_ => return self.panic_with(format!("{} is not a function", val.show())),
|
_ => {
|
||||||
|
return self.panic_with(format!("{} is not a function", called.show()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Call => {
|
Call => {
|
||||||
let arity = self.chunk().bytecode[self.ip + 1];
|
let arity = self.read();
|
||||||
self.ip += 2;
|
|
||||||
|
|
||||||
let val = self.pop();
|
let called = self.pop();
|
||||||
|
|
||||||
if self.debug {
|
if self.debug {
|
||||||
println!("=== calling into {val}/{arity} ===");
|
println!("=== calling into {called}/{arity} ===");
|
||||||
}
|
}
|
||||||
|
|
||||||
match val {
|
match called {
|
||||||
Value::Fn(_) => {
|
Value::Fn(_) => {
|
||||||
if !val.as_fn().accepts(arity) {
|
if !called.as_fn().accepts(arity) {
|
||||||
return self.panic_with(format!(
|
return self.panic_with(format!(
|
||||||
"wrong number of arguments to {} passing {arity} args",
|
"wrong number of arguments to {} passing {arity} args",
|
||||||
val.show()
|
called.show()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
let splat_arity = val.as_fn().splat_arity();
|
let splat_arity = called.as_fn().splat_arity();
|
||||||
if splat_arity > 0 && arity >= splat_arity {
|
if splat_arity > 0 && arity >= splat_arity {
|
||||||
let splatted_args = self.stack.split_off(
|
let splatted_args = self.stack.split_off(
|
||||||
self.stack.len() - (arity - splat_arity) as usize - 1,
|
self.stack.len() - (arity - splat_arity) as usize - 1,
|
||||||
|
@ -1045,7 +949,7 @@ impl Vm {
|
||||||
arity
|
arity
|
||||||
};
|
};
|
||||||
let mut frame = CallFrame {
|
let mut frame = CallFrame {
|
||||||
function: val,
|
function: called,
|
||||||
arity,
|
arity,
|
||||||
stack_base: self.stack.len() - arity as usize,
|
stack_base: self.stack.len() - arity as usize,
|
||||||
ip: 0,
|
ip: 0,
|
||||||
|
@ -1100,7 +1004,9 @@ impl Vm {
|
||||||
self.call_stack.push(frame);
|
self.call_stack.push(frame);
|
||||||
self.ip = 0;
|
self.ip = 0;
|
||||||
}
|
}
|
||||||
_ => return self.panic_with(format!("{} is not a function", val.show())),
|
_ => {
|
||||||
|
return self.panic_with(format!("{} is not a function", called.show()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Return => {
|
Return => {
|
||||||
|
@ -1116,7 +1022,6 @@ impl Vm {
|
||||||
Print => {
|
Print => {
|
||||||
println!("{}", self.pop().show());
|
println!("{}", self.pop().show());
|
||||||
self.push(Value::Keyword("ok"));
|
self.push(Value::Keyword("ok"));
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
SetUpvalue => {
|
SetUpvalue => {
|
||||||
let value = self.pop();
|
let value = self.pop();
|
||||||
|
@ -1124,20 +1029,15 @@ impl Vm {
|
||||||
panic!("expected function closing over value, got {}", self.peek());
|
panic!("expected function closing over value, got {}", self.peek());
|
||||||
};
|
};
|
||||||
lfn.close(value);
|
lfn.close(value);
|
||||||
self.ip += 1;
|
|
||||||
}
|
}
|
||||||
GetUpvalue => {
|
GetUpvalue => {
|
||||||
let idx = self.chunk().bytecode[self.ip + 1];
|
let idx = self.read();
|
||||||
self.ip += 2;
|
|
||||||
if let Value::Fn(ref inner) = self.frame.function {
|
if let Value::Fn(ref inner) = self.frame.function {
|
||||||
self.push(inner.as_ref().upvalue(idx));
|
self.push(inner.as_ref().upvalue(idx));
|
||||||
} else {
|
} else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg => {
|
|
||||||
self.ip += 2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user