maybe actually fix the loop stuff; lots of QOL improvements
This commit is contained in:
parent
86de66c4d2
commit
e4a948ba94
25
sandbox.ld
25
sandbox.ld
|
@ -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
2379
sandbox_run.txt
Normal file
File diff suppressed because it is too large
Load Diff
86
src/chunk.rs
Normal file
86
src/chunk.rs
Normal 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)
|
||||||
|
// }
|
||||||
|
}
|
166
src/compiler.rs
166
src/compiler.rs
|
@ -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
226
src/op.rs
Normal 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}")
|
||||||
|
}
|
||||||
|
}
|
14
src/vm.rs
14
src/vm.rs
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user