keep grinding; quality of life improvements to aid in grinding
This commit is contained in:
parent
813a79a415
commit
86de66c4d2
35
sandbox.ld
35
sandbox.ld
|
@ -1,16 +1,14 @@
|
||||||
let test = 2
|
let test = 2
|
||||||
|
|
||||||
& loop ([1, 2, 3]) with {
|
loop ([1, 2, 3]) with {
|
||||||
& ([]) -> false
|
([]) -> false
|
||||||
& ([x]) -> eq? (x, test)
|
([x]) -> eq? (x, test)
|
||||||
& ([x, ...xs]) -> {
|
([x, ...xs]) -> if eq? (x, test)
|
||||||
& let foo = :bar
|
then true
|
||||||
& when {
|
else recur (xs)
|
||||||
& eq? (x, test) -> true
|
}
|
||||||
& :else -> recur (xs)
|
|
||||||
& }
|
let foo = :bar
|
||||||
& }
|
|
||||||
& }
|
|
||||||
|
|
||||||
fn not {
|
fn not {
|
||||||
(false) -> true
|
(false) -> true
|
||||||
|
@ -18,12 +16,11 @@ fn not {
|
||||||
(_) -> false
|
(_) -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
loop ([1, 2, 3]) with {
|
& loop ([1, 2, 3]) with {
|
||||||
([]) -> false
|
& ([]) -> false
|
||||||
([x]) -> eq? (x, test)
|
& ([y]) -> eq? (y, test)
|
||||||
([x, ...xs]) -> if not (eq? (x, test))
|
& ([y, ...ys]) -> if not (eq? (y, test))
|
||||||
then recur (xs)
|
& then recur (ys)
|
||||||
else true
|
& else true
|
||||||
|
& }
|
||||||
}
|
|
||||||
|
|
||||||
|
|
432
src/compiler.rs
432
src/compiler.rs
|
@ -1,238 +1,15 @@
|
||||||
|
use crate::chunk::{Chunk, StrPattern};
|
||||||
|
use crate::op::Op;
|
||||||
use crate::parser::Ast;
|
use crate::parser::Ast;
|
||||||
use crate::parser::StringPart;
|
use crate::parser::StringPart;
|
||||||
use crate::spans::Spanned;
|
use crate::spans::Spanned;
|
||||||
use crate::value::*;
|
use crate::value::*;
|
||||||
use chumsky::prelude::SimpleSpan;
|
use chumsky::prelude::SimpleSpan;
|
||||||
use num_derive::{FromPrimitive, ToPrimitive};
|
|
||||||
use num_traits::FromPrimitive;
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[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,
|
|
||||||
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",
|
|
||||||
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}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct Binding {
|
pub struct Binding {
|
||||||
name: &'static str,
|
name: &'static str,
|
||||||
|
@ -246,87 +23,6 @@ pub struct Upvalue {
|
||||||
stack_pos: usize,
|
stack_pos: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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: imbl::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 => {
|
|
||||||
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)
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
struct LoopInfo {
|
struct LoopInfo {
|
||||||
start: usize,
|
start: usize,
|
||||||
|
@ -524,14 +220,21 @@ impl<'a> Compiler<'a> {
|
||||||
|
|
||||||
pub fn bind(&mut self, name: &'static str) {
|
pub fn bind(&mut self, name: &'static str) {
|
||||||
self.msg(format!("binding `{name}` in {}", self.name));
|
self.msg(format!("binding `{name}` in {}", self.name));
|
||||||
println!("stack: {}; match: {}", self.stack_depth, self.match_depth);
|
self.msg(format!(
|
||||||
|
"stack depth: {}; match depth: {}",
|
||||||
|
self.stack_depth, self.match_depth
|
||||||
|
));
|
||||||
|
self.msg(format!(
|
||||||
|
"at stack index: {}",
|
||||||
|
self.stack_depth - self.match_depth - 1
|
||||||
|
));
|
||||||
let binding = Binding {
|
let binding = Binding {
|
||||||
name,
|
name,
|
||||||
depth: self.scope_depth,
|
depth: self.scope_depth,
|
||||||
stack_pos: self.stack_depth - self.match_depth - 1,
|
stack_pos: self.stack_depth - self.match_depth - 1,
|
||||||
};
|
};
|
||||||
println!("{:?}", binding);
|
|
||||||
self.bindings.push(binding);
|
self.bindings.push(binding);
|
||||||
|
self.msg(format!("locals are now: {:?}", self.bindings));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_local(&self, name: &'static str) -> Option<usize> {
|
fn resolve_local(&self, name: &'static str) -> Option<usize> {
|
||||||
|
@ -548,24 +251,31 @@ impl<'a> Compiler<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_binding(&mut self, name: &'static str) {
|
fn resolve_binding(&mut self, name: &'static str) {
|
||||||
self.msg(format!("resolving binding `{name}` in {}", self.name));
|
self.msg(format!(
|
||||||
|
"resolving binding `{name}` in {}\nlocals: {:?}",
|
||||||
|
self.name, self.bindings
|
||||||
|
));
|
||||||
if let Some(pos) = self.resolve_local(name) {
|
if let Some(pos) = self.resolve_local(name) {
|
||||||
|
self.msg(format!("at locals position {pos}"));
|
||||||
self.emit_op(Op::PushBinding);
|
self.emit_op(Op::PushBinding);
|
||||||
self.emit_byte(pos);
|
self.emit_byte(pos);
|
||||||
self.stack_depth += 1;
|
self.stack_depth += 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if let Some(pos) = self.resolve_upvalue(name) {
|
if let Some(pos) = self.resolve_upvalue(name) {
|
||||||
|
self.msg(format!("as upvalue {pos}"));
|
||||||
self.emit_op(Op::GetUpvalue);
|
self.emit_op(Op::GetUpvalue);
|
||||||
self.emit_byte(pos);
|
self.emit_byte(pos);
|
||||||
self.stack_depth += 1;
|
self.stack_depth += 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if self.chunk.env.contains_key(name) {
|
if self.chunk.env.contains_key(name) {
|
||||||
|
self.msg("as global".to_string());
|
||||||
self.emit_constant(Value::Keyword(name));
|
self.emit_constant(Value::Keyword(name));
|
||||||
self.emit_op(Op::PushGlobal);
|
self.emit_op(Op::PushGlobal);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
self.msg(format!("as enclosing upvalue {}", self.upvalues.len()));
|
||||||
self.emit_op(Op::GetUpvalue);
|
self.emit_op(Op::GetUpvalue);
|
||||||
self.emit_byte(self.upvalues.len());
|
self.emit_byte(self.upvalues.len());
|
||||||
self.upvalues.push(name);
|
self.upvalues.push(name);
|
||||||
|
@ -589,6 +299,23 @@ impl<'a> Compiler<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn enter_scope(&mut self) {
|
||||||
|
self.scope_depth += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn leave_scope(&mut self) {
|
||||||
|
self.msg(format!("leaving scope {}", self.scope_depth));
|
||||||
|
while let Some(binding) = self.bindings.last() {
|
||||||
|
if binding.depth == self.scope_depth {
|
||||||
|
let unbound = self.bindings.pop();
|
||||||
|
self.msg(format!("releasing binding {:?}", unbound));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.scope_depth -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
fn enter_loop(&mut self) {
|
fn enter_loop(&mut self) {
|
||||||
self.loop_info
|
self.loop_info
|
||||||
.push(LoopInfo::new(self.len(), self.stack_depth));
|
.push(LoopInfo::new(self.len(), self.stack_depth));
|
||||||
|
@ -649,7 +376,8 @@ impl<'a> Compiler<'a> {
|
||||||
let tail_pos = self.tail_pos;
|
let tail_pos = self.tail_pos;
|
||||||
self.tail_pos = false;
|
self.tail_pos = false;
|
||||||
// increase the scope
|
// increase the scope
|
||||||
self.scope_depth += 1;
|
self.enter_scope();
|
||||||
|
// self.scope_depth += 1;
|
||||||
// stash the stack depth
|
// stash the stack depth
|
||||||
let stack_depth = self.stack_depth;
|
let stack_depth = self.stack_depth;
|
||||||
// evaluate all the lines but the last
|
// evaluate all the lines but the last
|
||||||
|
@ -694,14 +422,15 @@ impl<'a> Compiler<'a> {
|
||||||
self.emit_op(Op::Store);
|
self.emit_op(Op::Store);
|
||||||
|
|
||||||
// reset the scope
|
// reset the scope
|
||||||
self.scope_depth -= 1;
|
self.leave_scope();
|
||||||
while let Some(binding) = self.bindings.last() {
|
// self.scope_depth -= 1;
|
||||||
if binding.depth > self.scope_depth {
|
// while let Some(binding) = self.bindings.last() {
|
||||||
self.bindings.pop();
|
// if binding.depth > self.scope_depth {
|
||||||
} else {
|
// self.bindings.pop();
|
||||||
break;
|
// } else {
|
||||||
}
|
// break;
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
// 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
|
||||||
|
@ -729,12 +458,15 @@ impl<'a> Compiler<'a> {
|
||||||
self.patch_jump(jump_idx, jump_offset);
|
self.patch_jump(jump_idx, jump_offset);
|
||||||
}
|
}
|
||||||
Let(patt, expr) => {
|
Let(patt, expr) => {
|
||||||
|
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_ast("let binding: matching".to_string(), patt);
|
self.report_ast("let binding: matching".to_string(), patt);
|
||||||
self.visit(patt);
|
self.visit(patt);
|
||||||
self.emit_op(Op::PanicIfNoMatch);
|
self.emit_op(Op::PanicIfNoMatch);
|
||||||
|
self.report_depth("after let binding");
|
||||||
}
|
}
|
||||||
WordPattern(name) => {
|
WordPattern(name) => {
|
||||||
self.emit_op(Op::Match);
|
self.emit_op(Op::Match);
|
||||||
|
@ -1215,7 +947,8 @@ impl<'a> Compiler<'a> {
|
||||||
self.tail_pos = false;
|
self.tail_pos = false;
|
||||||
let mut no_match_jumps = vec![];
|
let mut no_match_jumps = vec![];
|
||||||
self.report_ast("match clause: ".to_string(), pattern);
|
self.report_ast("match clause: ".to_string(), pattern);
|
||||||
self.scope_depth += 1;
|
// self.scope_depth += 1;
|
||||||
|
self.enter_scope();
|
||||||
self.match_depth = 0;
|
self.match_depth = 0;
|
||||||
self.visit(pattern);
|
self.visit(pattern);
|
||||||
no_match_jumps.push(self.stub_jump(Op::JumpIfNoMatch));
|
no_match_jumps.push(self.stub_jump(Op::JumpIfNoMatch));
|
||||||
|
@ -1229,14 +962,15 @@ 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.scope_depth -= 1;
|
self.leave_scope();
|
||||||
while let Some(binding) = self.bindings.last() {
|
// self.scope_depth -= 1;
|
||||||
if binding.depth > self.scope_depth {
|
// while let Some(binding) = self.bindings.last() {
|
||||||
self.bindings.pop();
|
// if binding.depth > self.scope_depth {
|
||||||
} else {
|
// self.bindings.pop();
|
||||||
break;
|
// } else {
|
||||||
}
|
// break;
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
self.pop_n(self.stack_depth - stack_depth);
|
self.pop_n(self.stack_depth - stack_depth);
|
||||||
jump_idxes.push(self.stub_jump(Op::Jump));
|
jump_idxes.push(self.stub_jump(Op::Jump));
|
||||||
for idx in no_match_jumps {
|
for idx in no_match_jumps {
|
||||||
|
@ -1471,6 +1205,7 @@ impl<'a> Compiler<'a> {
|
||||||
self.emit_constant(Value::Nil);
|
self.emit_constant(Value::Nil);
|
||||||
}
|
}
|
||||||
Loop(value, clauses) => {
|
Loop(value, clauses) => {
|
||||||
|
self.report_depth("entering loop");
|
||||||
let tail_pos = self.tail_pos;
|
let tail_pos = self.tail_pos;
|
||||||
self.tail_pos = false;
|
self.tail_pos = false;
|
||||||
//algo:
|
//algo:
|
||||||
|
@ -1481,14 +1216,10 @@ impl<'a> Compiler<'a> {
|
||||||
for member in members {
|
for member in members {
|
||||||
self.visit(member);
|
self.visit(member);
|
||||||
}
|
}
|
||||||
self.msg(format!(
|
self.report_depth("after loop args");
|
||||||
"***entering loop with stack depth of {}",
|
|
||||||
self.stack_depth
|
|
||||||
));
|
|
||||||
self.emit_op(Op::StoreN);
|
self.emit_op(Op::StoreN);
|
||||||
self.emit_byte(members.len());
|
self.emit_byte(members.len());
|
||||||
let arity = members.len();
|
let arity = members.len();
|
||||||
// self.pop();
|
|
||||||
let stack_depth = self.stack_depth;
|
let stack_depth = self.stack_depth;
|
||||||
self.msg(format!(
|
self.msg(format!(
|
||||||
"***after store, stack depth is now {}",
|
"***after store, stack depth is now {}",
|
||||||
|
@ -1508,7 +1239,8 @@ impl<'a> Compiler<'a> {
|
||||||
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.emit_op(Op::ResetMatch);
|
||||||
self.scope_depth += 1;
|
self.enter_scope();
|
||||||
|
// self.scope_depth += 1;
|
||||||
let (Ast::TuplePattern(members), _) = pattern.as_ref() else {
|
let (Ast::TuplePattern(members), _) = pattern.as_ref() else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
@ -1535,37 +1267,31 @@ impl<'a> Compiler<'a> {
|
||||||
self.stack_depth
|
self.stack_depth
|
||||||
));
|
));
|
||||||
self.visit(body);
|
self.visit(body);
|
||||||
self.msg(format!(
|
self.report_depth("after loop body, before store");
|
||||||
"***after visiting loop body, the stack depth is {}",
|
|
||||||
self.stack_depth
|
|
||||||
));
|
|
||||||
self.emit_op(Op::Store);
|
self.emit_op(Op::Store);
|
||||||
self.scope_depth -= 1;
|
self.leave_scope();
|
||||||
self.msg("releasing loop bindings".to_string());
|
self.report_depth_str(format!(
|
||||||
while let Some(binding) = self.bindings.last() {
|
"resetting the stack after loop from {stack_depth} to {}",
|
||||||
if binding.depth > self.scope_depth {
|
self.stack_depth,
|
||||||
self.bindings.pop();
|
));
|
||||||
} else {
|
self.pop_n(self.stack_depth - stack_depth);
|
||||||
break;
|
// while self.stack_depth > stack_depth {
|
||||||
}
|
// self.pop();
|
||||||
}
|
// }
|
||||||
self.msg("resetting the stack after loop".to_string());
|
|
||||||
// self.emit_op(Op::PopN);
|
|
||||||
// self.emit_byte(self.stack_depth - stack_depth);
|
|
||||||
while self.stack_depth > stack_depth {
|
|
||||||
self.pop();
|
|
||||||
}
|
|
||||||
jump_idxes.push(self.stub_jump(Op::Jump));
|
jump_idxes.push(self.stub_jump(Op::Jump));
|
||||||
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.scope_depth -= 1;
|
||||||
}
|
}
|
||||||
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.stack_depth -= arity;
|
self.stack_depth -= arity;
|
||||||
|
// pop back to the original depth before load
|
||||||
|
// i.e. clear loop args
|
||||||
|
self.pop();
|
||||||
self.emit_op(Op::Load);
|
self.emit_op(Op::Load);
|
||||||
self.stack_depth += 1;
|
self.stack_depth += 1;
|
||||||
self.leave_loop();
|
self.leave_loop();
|
||||||
|
|
|
@ -25,6 +25,9 @@ use crate::validator::Validator;
|
||||||
mod errors;
|
mod errors;
|
||||||
use crate::errors::report_invalidation;
|
use crate::errors::report_invalidation;
|
||||||
|
|
||||||
|
mod chunk;
|
||||||
|
mod op;
|
||||||
|
|
||||||
mod compiler;
|
mod compiler;
|
||||||
use crate::compiler::Compiler;
|
use crate::compiler::Compiler;
|
||||||
|
|
||||||
|
@ -121,7 +124,7 @@ pub fn run(src: &'static str) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut compiler = Compiler::new(parsed, "test", src, None, prelude, DEBUG_SCRIPT_COMPILE);
|
let mut compiler = Compiler::new(parsed, "sandbox", src, None, prelude, DEBUG_SCRIPT_COMPILE);
|
||||||
// let base = base::make_base();
|
// let base = base::make_base();
|
||||||
// compiler.emit_constant(base);
|
// compiler.emit_constant(base);
|
||||||
// compiler.bind("base");
|
// compiler.bind("base");
|
||||||
|
@ -135,7 +138,7 @@ pub fn run(src: &'static str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if DEBUG_SCRIPT_RUN {
|
if DEBUG_SCRIPT_RUN {
|
||||||
println!("=== vm run: test ===");
|
println!("=== vm run ===");
|
||||||
}
|
}
|
||||||
|
|
||||||
let vm_chunk = compiler.chunk;
|
let vm_chunk = compiler.chunk;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::base::BaseFn;
|
use crate::base::BaseFn;
|
||||||
use crate::compiler::Chunk;
|
use crate::chunk::Chunk;
|
||||||
// use crate::parser::Ast;
|
// use crate::parser::Ast;
|
||||||
// use crate::spans::Spanned;
|
// use crate::spans::Spanned;
|
||||||
use imbl::{HashMap, Vector};
|
use imbl::{HashMap, Vector};
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::base::BaseFn;
|
use crate::base::BaseFn;
|
||||||
use crate::compiler::{Chunk, Op};
|
use crate::chunk::Chunk;
|
||||||
|
use crate::op::Op;
|
||||||
use crate::parser::Ast;
|
use crate::parser::Ast;
|
||||||
use crate::spans::Spanned;
|
use crate::spans::Spanned;
|
||||||
use crate::value::{LFn, Value};
|
use crate::value::{LFn, Value};
|
||||||
|
|
Loading…
Reference in New Issue
Block a user