maybe actually fix the loop stuff; lots of QOL improvements

This commit is contained in:
Scott Richmond 2025-06-22 19:42:25 -04:00
parent 86de66c4d2
commit e4a948ba94
6 changed files with 2825 additions and 71 deletions

View File

@ -1,13 +1,14 @@
let test = 2 let test = 3
loop ([1, 2, 3]) with { let quux = loop ([1, 2]) with {
([]) -> false ([]) -> false
([x]) -> eq? (x, test) ([x]) -> eq? (x, test)
([x, ...xs]) -> if eq? (x, test) ([x, ...xs]) -> if eq? (x, test)
then true then :yes
else recur (xs) else recur (xs)
} }
let foo = :bar let foo = :bar
fn not { fn not {
@ -16,11 +17,15 @@ fn not {
(_) -> false (_) -> false
} }
& loop ([1, 2, 3]) with { let frob = loop ([1, 2, 3]) with {
& ([]) -> false ([]) -> false
& ([y]) -> eq? (y, test) ([y]) -> eq? (y, test)
& ([y, ...ys]) -> if not (eq? (y, test)) ([y, ...ys]) -> if not (eq? (y, test))
& then recur (ys) then recur (ys)
& else true else true
& } }
[quux, frob]

2379
sandbox_run.txt Normal file

File diff suppressed because it is too large Load Diff

86
src/chunk.rs Normal file
View File

@ -0,0 +1,86 @@
use crate::op::Op;
use crate::value::Value;
use imbl::HashMap;
use num_traits::FromPrimitive;
use regex::Regex;
#[derive(Clone, Debug)]
pub struct StrPattern {
pub words: Vec<String>,
pub re: Regex,
}
#[derive(Clone, Debug)]
pub struct Chunk {
pub constants: Vec<Value>,
pub bytecode: Vec<u8>,
pub keywords: Vec<&'static str>,
pub string_patterns: Vec<StrPattern>,
pub env: HashMap<&'static str, Value>,
pub msgs: Vec<String>,
}
impl Chunk {
pub fn dissasemble_instr(&self, i: &mut usize) {
let op = Op::from_u8(self.bytecode[*i]).unwrap();
use Op::*;
match op {
Pop | Store | Stash | Load | Nil | True | False | MatchNil | MatchTrue | MatchFalse
| PanicIfNoMatch | ResetMatch | GetKey | PanicNoWhen | PanicNoMatch | TypeOf
| Duplicate | Decrement | Truncate | Noop | LoadTuple | LoadList | Eq | Add | Sub
| Mult | Div | Unbox | BoxStore | Assert | Get | At | Not | Panic | EmptyString
| ConcatStrings | Stringify | MatchType | Return | Match | Print | AppendList
| ConcatList | PushList | PushDict | AppendDict | ConcatDict | Nothing | PushGlobal
| SetUpvalue => {
println!("{i:04}: {op}")
}
Constant | MatchConstant => {
let high = self.bytecode[*i + 1];
let low = self.bytecode[*i + 2];
let idx = ((high as usize) << 8) + low as usize;
let value = &self.constants[idx].show();
println!("{i:04}: {:16} {idx:05}: {value}", op.to_string());
*i += 2;
}
Msg => {
let msg_idx = self.bytecode[*i + 1];
let msg = &self.msgs[msg_idx as usize];
println!("{i:04}: {msg}");
*i += 1;
}
PushBinding | MatchTuple | MatchSplattedTuple | LoadSplattedTuple | MatchList
| MatchSplattedList | LoadSplattedList | MatchDict | MatchSplattedDict
| DropDictEntry | LoadDictValue | PushTuple | PushBox | MatchDepth | PopN | StoreN
| Call | GetUpvalue | Partial | MatchString | PushStringMatches | TailCall | LoadN => {
let next = self.bytecode[*i + 1];
println!("{i:04}: {:16} {next:03}", op.to_string());
*i += 1;
}
Jump | JumpIfFalse | JumpIfTrue | JumpIfNoMatch | JumpIfMatch | JumpBack
| JumpIfZero => {
let high = self.bytecode[*i + 1];
let low = self.bytecode[*i + 2];
let len = ((high as u16) << 8) + low as u16;
println!("{i:04}: {:16} {len:05}", op.to_string());
*i += 2;
}
}
}
pub fn dissasemble(&self) {
println!("IDX | CODE | INFO");
let mut i = 0;
while i < self.bytecode.len() {
self.dissasemble_instr(&mut i);
i += 1;
}
}
// pub fn kw_from(&self, kw: &str) -> Option<Value> {
// self.kw_index_from(kw).map(Value::Keyword)
// }
// pub fn kw_index_from(&self, kw: &str) -> Option<usize> {
// self.keywords.iter().position(|s| *s == kw)
// }
}

View File

@ -17,6 +17,12 @@ pub struct Binding {
stack_pos: usize, stack_pos: usize,
} }
impl std::fmt::Display for Binding {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}@{}//{}", self.name, self.stack_pos, self.depth)
}
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Upvalue { pub struct Upvalue {
name: &'static str, name: &'static str,
@ -147,6 +153,11 @@ impl<'a> Compiler<'a> {
} }
fn stub_jump(&mut self, op: Op) -> usize { fn stub_jump(&mut self, op: Op) -> usize {
use Op::*;
match op {
JumpIfFalse | JumpIfTrue | JumpIfZero => self.stack_depth -= 1,
_ => (),
}
let out = self.chunk.bytecode.len(); let out = self.chunk.bytecode.len();
self.emit_op(op); self.emit_op(op);
self.emit_byte(0xff); self.emit_byte(0xff);
@ -183,6 +194,11 @@ impl<'a> Compiler<'a> {
self.stack_depth += 1; self.stack_depth += 1;
} }
fn reset_match(&mut self) {
self.emit_op(Op::ResetMatch);
self.match_depth = 0;
}
fn match_constant(&mut self, val: Value) { fn match_constant(&mut self, val: Value) {
let const_idx = match self.chunk.constants.iter().position(|v| *v == val) { let const_idx = match self.chunk.constants.iter().position(|v| *v == val) {
Some(idx) => idx, Some(idx) => idx,
@ -234,7 +250,14 @@ impl<'a> Compiler<'a> {
stack_pos: self.stack_depth - self.match_depth - 1, stack_pos: self.stack_depth - self.match_depth - 1,
}; };
self.bindings.push(binding); self.bindings.push(binding);
self.msg(format!("locals are now: {:?}", self.bindings)); self.msg(format!(
"new locals: {}",
self.bindings
.iter()
.map(|binding| format!("{binding}"))
.collect::<Vec<_>>()
.join("|")
));
} }
fn resolve_local(&self, name: &'static str) -> Option<usize> { fn resolve_local(&self, name: &'static str) -> Option<usize> {
@ -252,8 +275,13 @@ impl<'a> Compiler<'a> {
fn resolve_binding(&mut self, name: &'static str) { fn resolve_binding(&mut self, name: &'static str) {
self.msg(format!( self.msg(format!(
"resolving binding `{name}` in {}\nlocals: {:?}", "resolving binding `{name}` in {}\nlocals: {}",
self.name, self.bindings self.name,
self.bindings
.iter()
.map(|binding| format!("{binding}"))
.collect::<Vec<_>>()
.join("|")
)); ));
if let Some(pos) = self.resolve_local(name) { if let Some(pos) = self.resolve_local(name) {
self.msg(format!("at locals position {pos}")); self.msg(format!("at locals position {pos}"));
@ -299,6 +327,28 @@ impl<'a> Compiler<'a> {
} }
} }
fn store(&mut self) {
self.emit_op(Op::Store);
self.stack_depth -= 1;
}
fn store_n(&mut self, n: usize) {
self.emit_op(Op::StoreN);
self.emit_byte(n);
self.stack_depth -= n;
}
fn load(&mut self) {
self.emit_op(Op::Load);
self.stack_depth += 1;
}
fn load_n(&mut self, n: usize) {
self.emit_op(Op::LoadN);
self.emit_byte(n);
self.stack_depth += n;
}
fn enter_scope(&mut self) { fn enter_scope(&mut self) {
self.scope_depth += 1; self.scope_depth += 1;
} }
@ -308,7 +358,7 @@ impl<'a> Compiler<'a> {
while let Some(binding) = self.bindings.last() { while let Some(binding) = self.bindings.last() {
if binding.depth == self.scope_depth { if binding.depth == self.scope_depth {
let unbound = self.bindings.pop(); let unbound = self.bindings.pop();
self.msg(format!("releasing binding {:?}", unbound)); self.msg(format!("releasing binding {}", unbound.unwrap()));
} else { } else {
break; break;
} }
@ -316,9 +366,9 @@ impl<'a> Compiler<'a> {
self.scope_depth -= 1; self.scope_depth -= 1;
} }
fn enter_loop(&mut self) { fn enter_loop(&mut self, arity: usize) {
self.loop_info self.loop_info
.push(LoopInfo::new(self.len(), self.stack_depth)); .push(LoopInfo::new(self.len(), self.stack_depth - arity));
} }
fn leave_loop(&mut self) { fn leave_loop(&mut self) {
@ -340,6 +390,7 @@ impl<'a> Compiler<'a> {
fn msg(&mut self, str: String) { fn msg(&mut self, str: String) {
self.emit_op(Op::Msg); self.emit_op(Op::Msg);
self.emit_byte(self.chunk.msgs.len()); self.emit_byte(self.chunk.msgs.len());
println!("{str}");
self.chunk.msgs.push(str); self.chunk.msgs.push(str);
} }
@ -397,11 +448,12 @@ impl<'a> Compiler<'a> {
// return the evaluated rhs instead of whatever is last on the stack // return the evaluated rhs instead of whatever is last on the stack
// we do this by pretending it's a binding // we do this by pretending it's a binding
(Let(patt, expr), _) => { (Let(patt, expr), _) => {
self.match_depth = 0; // self.match_depth = 0;
self.emit_op(Op::ResetMatch); // self.emit_op(Op::ResetMatch);
self.visit(expr); self.visit(expr);
let expr_pos = self.stack_depth - 1; let expr_pos = self.stack_depth - 1;
self.report_ast("let binding: matching".to_string(), patt); self.report_ast("let binding: matching".to_string(), patt);
self.reset_match();
self.visit(patt); self.visit(patt);
self.emit_op(Op::PanicIfNoMatch); self.emit_op(Op::PanicIfNoMatch);
self.emit_op(Op::PushBinding); self.emit_op(Op::PushBinding);
@ -419,7 +471,8 @@ impl<'a> Compiler<'a> {
self.stack_depth += 1; self.stack_depth += 1;
// store the value in the return register // store the value in the return register
self.emit_op(Op::Store); // self.emit_op(Op::Store);
self.store();
// reset the scope // reset the scope
self.leave_scope(); self.leave_scope();
@ -434,7 +487,8 @@ impl<'a> Compiler<'a> {
// reset the stack // reset the stack
self.pop_n(self.stack_depth - stack_depth - 1); self.pop_n(self.stack_depth - stack_depth - 1);
// load the value from the return register // load the value from the return register
self.emit_op(Op::Load); self.load();
// self.emit_op(Op::Load);
} }
If(cond, then, r#else) => { If(cond, then, r#else) => {
let tail_pos = self.tail_pos; let tail_pos = self.tail_pos;
@ -442,7 +496,7 @@ impl<'a> Compiler<'a> {
self.visit(cond); self.visit(cond);
self.report_depth("after condition"); self.report_depth("after condition");
let jif_idx = self.stub_jump(Op::JumpIfFalse); let jif_idx = self.stub_jump(Op::JumpIfFalse);
self.stack_depth -= 1; // self.stack_depth -= 1;
self.tail_pos = tail_pos; self.tail_pos = tail_pos;
self.visit(then); self.visit(then);
self.report_depth("after consequent"); self.report_depth("after consequent");
@ -459,11 +513,12 @@ impl<'a> Compiler<'a> {
} }
Let(patt, expr) => { Let(patt, expr) => {
self.report_depth("before let binding"); self.report_depth("before let binding");
self.match_depth = 0; // self.match_depth = 0;
self.emit_op(Op::ResetMatch); // self.emit_op(Op::ResetMatch);
self.visit(expr); self.visit(expr);
self.report_depth("after let expr"); self.report_depth("after let expr");
self.report_ast("let binding: matching".to_string(), patt); self.report_ast("let binding: matching".to_string(), patt);
self.reset_match();
self.visit(patt); self.visit(patt);
self.emit_op(Op::PanicIfNoMatch); self.emit_op(Op::PanicIfNoMatch);
self.report_depth("after let binding"); self.report_depth("after let binding");
@ -819,7 +874,8 @@ impl<'a> Compiler<'a> {
for idx in jump_idxes { for idx in jump_idxes {
self.patch_jump(idx, self.len() - idx); self.patch_jump(idx, self.len() - idx);
} }
self.emit_op(Op::Load); // self.emit_op(Op::Load);
self.load();
} else { } else {
self.emit_op(Op::False); self.emit_op(Op::False);
} }
@ -837,7 +893,8 @@ impl<'a> Compiler<'a> {
for idx in jump_idxes { for idx in jump_idxes {
self.patch_jump(idx, self.len() - idx); self.patch_jump(idx, self.len() - idx);
} }
self.emit_op(Op::Load); // self.emit_op(Op::Load);
self.load();
} else { } else {
self.emit_op(Op::True); self.emit_op(Op::True);
} }
@ -961,7 +1018,8 @@ impl<'a> Compiler<'a> {
} }
self.tail_pos = tail_pos; self.tail_pos = tail_pos;
self.visit(body); self.visit(body);
self.emit_op(Op::Store); // self.emit_op(Op::Store);
self.store();
self.leave_scope(); self.leave_scope();
// self.scope_depth -= 1; // self.scope_depth -= 1;
// while let Some(binding) = self.bindings.last() { // while let Some(binding) = self.bindings.last() {
@ -1047,7 +1105,8 @@ impl<'a> Compiler<'a> {
self.chunk.env.clone(), self.chunk.env.clone(),
self.debug, self.debug,
); );
compiler.emit_op(Op::ResetMatch); compiler.reset_match();
// compiler.emit_op(Op::ResetMatch);
compilers.insert(arity, compiler); compilers.insert(arity, compiler);
compilers.get_mut(&arity).unwrap() compilers.get_mut(&arity).unwrap()
} }
@ -1090,7 +1149,8 @@ impl<'a> Compiler<'a> {
} }
compiler.tail_pos = true; compiler.tail_pos = true;
compiler.visit(clause_body); compiler.visit(clause_body);
compiler.emit_op(Op::Store); // compiler.emit_op(Op::Store);
compiler.store();
compiler.scope_depth -= 1; compiler.scope_depth -= 1;
while let Some(binding) = compiler.bindings.last() { while let Some(binding) = compiler.bindings.last() {
if binding.depth > compiler.scope_depth { if binding.depth > compiler.scope_depth {
@ -1217,28 +1277,25 @@ impl<'a> Compiler<'a> {
self.visit(member); self.visit(member);
} }
self.report_depth("after loop args"); self.report_depth("after loop args");
self.emit_op(Op::StoreN);
self.emit_byte(members.len());
let arity = members.len(); let arity = members.len();
// self.emit_op(Op::StoreN);
// self.emit_byte(members.len());
self.store_n(arity);
let stack_depth = self.stack_depth; let stack_depth = self.stack_depth;
self.msg(format!( self.report_depth("loop: after store");
"***after store, stack depth is now {}",
self.stack_depth
));
//then, save the beginning of the loop //then, save the beginning of the loop
self.emit_op(Op::Load); // self.emit_op(Op::Load);
self.enter_loop(); self.load_n(arity);
self.enter_loop(arity);
// self.stack_depth += arity; // self.stack_depth += arity;
//next, compile each clause: //next, compile each clause:
self.msg(format!(
"***after load, stack depth is now {}",
self.stack_depth
));
let mut clauses = clauses.iter(); let mut clauses = clauses.iter();
let mut jump_idxes = vec![]; let mut jump_idxes = vec![];
while let Some((Ast::MatchClause(pattern, guard, body), _)) = clauses.next() { while let Some((Ast::MatchClause(pattern, guard, body), _)) = clauses.next() {
self.tail_pos = false; self.tail_pos = false;
self.emit_op(Op::ResetMatch); self.report_depth("loop: after load");
self.reset_match();
// self.emit_op(Op::ResetMatch);
self.enter_scope(); self.enter_scope();
// self.scope_depth += 1; // self.scope_depth += 1;
let (Ast::TuplePattern(members), _) = pattern.as_ref() else { let (Ast::TuplePattern(members), _) = pattern.as_ref() else {
@ -1259,19 +1316,17 @@ impl<'a> Compiler<'a> {
Box::leak(Box::new(guard.clone().unwrap())); Box::leak(Box::new(guard.clone().unwrap()));
self.visit(guard_expr); self.visit(guard_expr);
jnm_idxes.push(self.stub_jump(Op::JumpIfFalse)); jnm_idxes.push(self.stub_jump(Op::JumpIfFalse));
self.stack_depth -= 1;
} }
self.tail_pos = tail_pos; self.tail_pos = tail_pos;
self.msg(format!( self.report_depth("loop: before body");
"***before visiting body, the stack depth is {}",
self.stack_depth
));
self.visit(body); self.visit(body);
self.report_depth("after loop body, before store"); self.report_depth("loop: after body, before store");
self.emit_op(Op::Store); // self.emit_op(Op::Store);
self.store();
self.report_depth("loop: after body, after store");
self.leave_scope(); self.leave_scope();
self.report_depth_str(format!( self.report_depth_str(format!(
"resetting the stack after loop from {stack_depth} to {}", "resetting the stack after loop from {} to {stack_depth}",
self.stack_depth, self.stack_depth,
)); ));
self.pop_n(self.stack_depth - stack_depth); self.pop_n(self.stack_depth - stack_depth);
@ -1282,26 +1337,26 @@ impl<'a> Compiler<'a> {
for idx in jnm_idxes { for idx in jnm_idxes {
self.patch_jump(idx, self.len() - idx - 3); self.patch_jump(idx, self.len() - idx - 3);
} }
// self.scope_depth -= 1; self.stack_depth += arity;
} }
self.emit_op(Op::PanicNoMatch); self.emit_op(Op::PanicNoMatch);
for idx in jump_idxes { for idx in jump_idxes {
self.patch_jump(idx, self.len() - idx - 3); self.patch_jump(idx, self.len() - idx - 3);
} }
self.report_depth("before loop arity adjustment");
self.stack_depth -= arity; self.stack_depth -= arity;
// pop back to the original depth before load // pop back to the original depth before load
// i.e. clear loop args // i.e. clear loop args
self.pop(); // self.pop();
self.emit_op(Op::Load); // self.emit_op(Op::Load);
self.stack_depth += 1; self.load();
// self.stack_depth += 1;
self.leave_loop(); self.leave_loop();
self.report_depth("at very end of loop after load");
} }
Recur(args) => { Recur(args) => {
// self.emit_op(Op::Nothing); // self.emit_op(Op::Nothing);
self.msg(format!( self.report_depth("recur: before args");
"before visiting recur args the compiler thinks the stack depth is {}",
self.stack_depth
));
let tail_pos = self.tail_pos; let tail_pos = self.tail_pos;
self.tail_pos = false; self.tail_pos = false;
let mut argnum = 0; let mut argnum = 0;
@ -1310,15 +1365,14 @@ impl<'a> Compiler<'a> {
argnum += 1; argnum += 1;
self.visit(arg); self.visit(arg);
} }
self.msg(format!( self.report_depth("recur: after args");
"after visiting recur args the compiler thinks the stack depth is {}", self.store_n(args.len());
self.stack_depth, self.report_depth("recur: after store");
)); self.msg(format!("loop root depth: {}", self.loop_root()));
self.emit_op(Op::StoreN); self.pop_n(self.stack_depth - self.loop_root());
self.emit_byte(args.len()); self.report_depth("recur: after stack reset");
self.emit_op(Op::PopN); self.load_n(args.len());
self.emit_byte(self.stack_depth - self.loop_root()); self.report_depth("recur: after load, end of compilation");
self.emit_op(Op::Load);
self.jump(Op::JumpBack, self.len() - self.loop_idx()); self.jump(Op::JumpBack, self.len() - self.loop_idx());
self.tail_pos = tail_pos; self.tail_pos = tail_pos;
} }

226
src/op.rs Normal file
View File

@ -0,0 +1,226 @@
use num_derive::{FromPrimitive, ToPrimitive};
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)]
pub enum Op {
Noop,
Nothing,
Nil,
True,
False,
Constant,
Jump,
JumpIfFalse,
JumpIfTrue,
Pop,
PopN,
PushBinding,
PushGlobal,
Store,
StoreN,
Stash,
Load,
LoadN,
ResetMatch,
Match,
MatchNil,
MatchTrue,
MatchFalse,
PanicIfNoMatch,
MatchConstant,
MatchString,
PushStringMatches,
MatchType,
MatchTuple,
MatchSplattedTuple,
PushTuple,
LoadTuple,
LoadSplattedTuple,
MatchList,
MatchSplattedList,
LoadList,
LoadSplattedList,
PushList,
AppendList,
ConcatList,
PushDict,
AppendDict,
ConcatDict,
LoadDictValue,
MatchDict,
MatchSplattedDict,
DropDictEntry,
PushBox,
GetKey,
PanicNoWhen,
JumpIfNoMatch,
JumpIfMatch,
PanicNoMatch,
TypeOf,
JumpBack,
JumpIfZero,
Duplicate,
Decrement,
Truncate,
MatchDepth,
Panic,
EmptyString,
ConcatStrings,
Stringify,
Call,
TailCall,
Return,
Partial,
Eq,
Add,
Sub,
Mult,
Div,
Unbox,
BoxStore,
Assert,
Get,
At,
Not,
Print,
SetUpvalue,
GetUpvalue,
Msg,
// Inc,
// Dec,
// Gt,
// Gte,
// Lt,
// Lte,
// Mod,
// Round,
// Ceil,
// Floor,
// Random,
// Sqrt,
// Assoc,
// Concat,
// Conj,
// Count,
// Disj,
// Dissoc,
// Range,
// Rest,
// Slice,
// "atan_2" math/atan2
// "chars" chars
// "cos" math/cos
// "doc" doc
// "downcase" string/ascii-lower
// "pi" math/pi
// "show" show
// "sin" math/sin
// "split" string/split
// "str_slice" string/slice
// "tan" math/tan
// "trim" string/trim
// "triml" string/triml
// "trimr" string/trimr
// "upcase" string/ascii-upper
}
impl std::fmt::Display for Op {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use Op::*;
let rep = match self {
Msg => "msg",
Noop => "noop",
Nothing => "nothing",
Nil => "nil",
True => "true",
False => "false",
Constant => "constant",
Jump => "jump",
JumpIfFalse => "jump_if_false",
JumpIfTrue => "jump_if_true",
Pop => "pop",
PopN => "pop_n",
PushBinding => "push_binding",
PushGlobal => "push_global",
Store => "store",
StoreN => "store_n",
Stash => "stash",
Load => "load",
LoadN => "load_n",
Match => "match",
MatchNil => "match_nil",
MatchTrue => "match_true",
MatchFalse => "match_false",
ResetMatch => "reset_match",
PanicIfNoMatch => "panic_if_no_match",
MatchConstant => "match_constant",
MatchString => "match_string",
PushStringMatches => "push_string_matches",
MatchType => "match_type",
MatchTuple => "match_tuple",
MatchSplattedTuple => "match_splatted_tuple",
PushTuple => "push_tuple",
LoadTuple => "load_tuple",
LoadSplattedTuple => "load_splatted_tuple",
MatchList => "match_list",
MatchSplattedList => "match_splatted_list",
LoadList => "load_list",
LoadSplattedList => "load_splatted_list",
PushList => "push_list",
AppendList => "append_list",
ConcatList => "concat_list",
PushDict => "push_dict",
AppendDict => "append_dict",
ConcatDict => "concat_dict",
LoadDictValue => "load_dict_value",
MatchDict => "match_dict",
MatchSplattedDict => "match_splatted_dict",
DropDictEntry => "drop_dict_entry",
PushBox => "push_box",
GetKey => "get_key",
PanicNoWhen => "panic_no_when",
JumpIfNoMatch => "jump_if_no_match",
JumpIfMatch => "jump_if_match",
PanicNoMatch => "panic_no_match",
TypeOf => "type_of",
JumpBack => "jump_back",
JumpIfZero => "jump_if_zero",
Decrement => "decrement",
Truncate => "truncate",
Duplicate => "duplicate",
MatchDepth => "match_depth",
Panic => "panic",
EmptyString => "empty_string",
ConcatStrings => "concat_strings",
Stringify => "stringify",
Print => "print",
Eq => "eq",
Add => "add",
Sub => "sub",
Mult => "mult",
Div => "div",
Unbox => "unbox",
BoxStore => "box_store",
Assert => "assert",
Get => "get",
At => "at",
Not => "not",
Call => "call",
Return => "return",
Partial => "partial",
TailCall => "tail_call",
SetUpvalue => "set_upvalue",
GetUpvalue => "get_upvalue",
};
write!(f, "{rep}")
}
}

View File

@ -326,7 +326,6 @@ impl Vm {
} }
Store => { Store => {
self.return_register[0] = self.pop(); self.return_register[0] = self.pop();
self.push(Value::Nothing);
self.ip += 1; self.ip += 1;
} }
StoreN => { StoreN => {
@ -341,14 +340,19 @@ impl Vm {
self.ip += 1; self.ip += 1;
} }
Load => { Load => {
let mut i = 0; let mut value = Value::Nothing;
while i < 8 && self.return_register[i] != Value::Nothing { swap(&mut self.return_register[0], &mut value);
self.push(value);
self.ip += 1;
}
LoadN => {
let n = self.chunk().bytecode[self.ip + 1] as usize;
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);
i += 1;
} }
self.ip += 1; self.ip += 2;
} }
ResetMatch => { ResetMatch => {
self.matches = false; self.matches = false;