Compare commits
No commits in common. "f6bfe0975b0695f8108f88bb7c3353fb4f8dee76" and "a5f2e2a9bd770868bbcb776f7f0a8e2da05a9505" have entirely different histories.
f6bfe0975b
...
a5f2e2a9bd
212
src/compiler.rs
212
src/compiler.rs
|
@ -410,7 +410,7 @@ impl<'a> Compiler<'a> {
|
||||||
self.chunk.bytecode.push(low);
|
self.chunk.bytecode.push(low);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stub_jump(&mut self, op: Op) -> usize {
|
fn jump_stub(&mut self, op: Op) -> usize {
|
||||||
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);
|
||||||
|
@ -554,15 +554,9 @@ impl<'a> Compiler<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop_n(&mut self, n: usize) {
|
fn pop_n(&mut self, n: usize) {
|
||||||
match n {
|
self.emit_op(Op::PopN);
|
||||||
0 => (),
|
self.emit_byte(n);
|
||||||
1 => self.pop(),
|
self.stack_depth -= n;
|
||||||
n => {
|
|
||||||
self.emit_op(Op::PopN);
|
|
||||||
self.emit_byte(n);
|
|
||||||
self.stack_depth -= n;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enter_loop(&mut self) {
|
fn enter_loop(&mut self) {
|
||||||
|
@ -663,10 +657,10 @@ impl<'a> Compiler<'a> {
|
||||||
}
|
}
|
||||||
If(cond, then, r#else) => {
|
If(cond, then, r#else) => {
|
||||||
self.visit(cond);
|
self.visit(cond);
|
||||||
let jif_idx = self.stub_jump(Op::JumpIfFalse);
|
let jif_idx = self.jump_stub(Op::JumpIfFalse);
|
||||||
self.stack_depth -= 1;
|
self.stack_depth -= 1;
|
||||||
self.visit(then);
|
self.visit(then);
|
||||||
let jump_idx = self.stub_jump(Op::Jump);
|
let jump_idx = self.jump_stub(Op::Jump);
|
||||||
self.visit(r#else);
|
self.visit(r#else);
|
||||||
self.stack_depth -= 1;
|
self.stack_depth -= 1;
|
||||||
let end_idx = self.len();
|
let end_idx = self.len();
|
||||||
|
@ -728,7 +722,7 @@ impl<'a> Compiler<'a> {
|
||||||
self.emit_op(Op::MatchTuple);
|
self.emit_op(Op::MatchTuple);
|
||||||
self.emit_byte(members.len());
|
self.emit_byte(members.len());
|
||||||
// skip everything if tuple lengths don't match
|
// skip everything if tuple lengths don't match
|
||||||
let before_load_tup_idx = self.stub_jump(Op::JumpIfNoMatch);
|
let before_load_tup_idx = self.jump_stub(Op::JumpIfNoMatch);
|
||||||
|
|
||||||
// set up the per-member conditional logic
|
// set up the per-member conditional logic
|
||||||
let mut jump_idxes = vec![];
|
let mut jump_idxes = vec![];
|
||||||
|
@ -749,11 +743,12 @@ impl<'a> Compiler<'a> {
|
||||||
// visit the pattern member
|
// visit the pattern member
|
||||||
self.visit(member);
|
self.visit(member);
|
||||||
// and jump if there's no match
|
// and jump if there's no match
|
||||||
jump_idxes.push(self.stub_jump(Op::JumpIfNoMatch));
|
jump_idxes.push(self.jump_stub(Op::JumpIfNoMatch));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we get here--not having jumped on no match--we're matched; jump the "no match" code
|
// if we get here--not having jumped on no match--we're matched; jump the "no match" code
|
||||||
let jump_idx = self.stub_jump(Op::Jump);
|
self.match_depth = match_depth + members.len();
|
||||||
|
let jump_idx = self.jump_stub(Op::Jump);
|
||||||
|
|
||||||
// patch up the previous no match jumps to jump to clean-up code
|
// patch up the previous no match jumps to jump to clean-up code
|
||||||
for idx in jump_idxes {
|
for idx in jump_idxes {
|
||||||
|
@ -771,52 +766,45 @@ impl<'a> Compiler<'a> {
|
||||||
|
|
||||||
// patch up the yes-matches unconditional jump
|
// patch up the yes-matches unconditional jump
|
||||||
self.patch_jump(jump_idx, self.len() - jump_idx - 3);
|
self.patch_jump(jump_idx, self.len() - jump_idx - 3);
|
||||||
|
|
||||||
// finally, for any further matches (e.g. nested lists/tuples)
|
|
||||||
// add increase the match depth, since we've added a bunch
|
|
||||||
// of bindings to the stack
|
|
||||||
self.match_depth = match_depth + members.len();
|
|
||||||
}
|
}
|
||||||
ListPattern(members) => {
|
ListPattern(members) => {
|
||||||
self.emit_op(Op::MatchList);
|
self.emit_op(Op::MatchList);
|
||||||
self.emit_byte(members.len());
|
self.emit_byte(members.len());
|
||||||
let before_load_tup_idx = self.stub_jump(Op::JumpIfNoMatch);
|
self.emit_op(Op::JumpIfNoMatch);
|
||||||
|
let before_load_list_idx = self.len();
|
||||||
|
self.emit_byte(0xff);
|
||||||
let mut jump_idxes = vec![];
|
let mut jump_idxes = vec![];
|
||||||
let match_depth = self.match_depth;
|
self.match_depth += members.len();
|
||||||
self.match_depth = members.len();
|
|
||||||
|
|
||||||
self.emit_op(Op::LoadList);
|
self.emit_op(Op::LoadList);
|
||||||
self.stack_depth += members.len();
|
self.stack_depth += members.len();
|
||||||
|
|
||||||
for member in members {
|
for member in members {
|
||||||
self.match_depth -= 1;
|
self.match_depth -= 1;
|
||||||
self.emit_op(Op::MatchDepth);
|
self.emit_op(Op::MatchDepth);
|
||||||
self.emit_byte(self.match_depth);
|
self.emit_byte(self.match_depth);
|
||||||
self.visit(member);
|
self.visit(member);
|
||||||
jump_idxes.push(self.stub_jump(Op::JumpIfNoMatch));
|
self.emit_op(Op::JumpIfNoMatch);
|
||||||
|
jump_idxes.push(self.len());
|
||||||
|
self.emit_byte(0xff);
|
||||||
}
|
}
|
||||||
|
self.emit_op(Op::Jump);
|
||||||
let jump_idx = self.stub_jump(Op::Jump);
|
let jump_idx = self.len();
|
||||||
|
self.emit_byte(0xff);
|
||||||
for idx in jump_idxes {
|
for idx in jump_idxes {
|
||||||
self.patch_jump(idx, self.len() - idx - 2)
|
self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1;
|
||||||
}
|
}
|
||||||
|
for _ in 0..members.len() {
|
||||||
self.emit_op(Op::PopN);
|
self.emit_op(Op::Pop);
|
||||||
self.emit_byte(members.len());
|
}
|
||||||
|
self.chunk.bytecode[before_load_list_idx] =
|
||||||
self.patch_jump(before_load_tup_idx, self.len() - before_load_tup_idx - 3);
|
(self.len() - before_load_list_idx) as u8 - 1;
|
||||||
|
self.chunk.bytecode[jump_idx] = (self.len() - jump_idx) as u8 - 1;
|
||||||
self.patch_jump(jump_idx, self.len() - jump_idx - 3);
|
|
||||||
|
|
||||||
self.match_depth = match_depth + members.len();
|
|
||||||
}
|
}
|
||||||
DictPattern(pairs) => {
|
DictPattern(pairs) => {
|
||||||
self.emit_op(Op::MatchDict);
|
self.emit_op(Op::MatchDict);
|
||||||
self.emit_byte(pairs.len());
|
self.emit_byte(pairs.len());
|
||||||
let before_load_dict_idx = self.stub_jump(Op::JumpIfNoMatch);
|
self.emit_op(Op::JumpIfNoMatch);
|
||||||
|
let before_load_dict_idx = self.len();
|
||||||
|
self.emit_byte(0xff);
|
||||||
let mut jump_idxes = vec![];
|
let mut jump_idxes = vec![];
|
||||||
let dict_stack_pos = self.stack_depth - 1;
|
let dict_stack_pos = self.stack_depth - 1;
|
||||||
for pair in pairs {
|
for pair in pairs {
|
||||||
|
@ -827,19 +815,22 @@ impl<'a> Compiler<'a> {
|
||||||
self.emit_op(Op::LoadDictValue);
|
self.emit_op(Op::LoadDictValue);
|
||||||
self.emit_byte(dict_stack_pos);
|
self.emit_byte(dict_stack_pos);
|
||||||
self.visit(pattern);
|
self.visit(pattern);
|
||||||
jump_idxes.push(self.stub_jump(Op::JumpIfNoMatch));
|
self.emit_op(Op::JumpIfNoMatch);
|
||||||
|
jump_idxes.push(self.len());
|
||||||
|
self.emit_byte(0xff);
|
||||||
}
|
}
|
||||||
let jump_idx = self.stub_jump(Op::Jump);
|
self.emit_op(Op::Jump);
|
||||||
|
let jump_idx = self.len();
|
||||||
|
self.emit_byte(0xff);
|
||||||
for idx in jump_idxes {
|
for idx in jump_idxes {
|
||||||
self.patch_jump(idx, self.len() - idx - 2);
|
self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1;
|
||||||
}
|
}
|
||||||
|
for _ in 0..pairs.len() {
|
||||||
self.emit_op(Op::PopN);
|
self.emit_op(Op::Pop);
|
||||||
self.emit_byte(pairs.len());
|
}
|
||||||
|
self.chunk.bytecode[before_load_dict_idx] =
|
||||||
self.patch_jump(before_load_dict_idx, self.len() - before_load_dict_idx - 3);
|
(self.len() - before_load_dict_idx) as u8 - 1;
|
||||||
self.patch_jump(jump_idx, self.len() - jump_idx - 3);
|
self.chunk.bytecode[jump_idx] = (self.len() - jump_idx) as u8 - 1;
|
||||||
}
|
}
|
||||||
Splattern(..) => {
|
Splattern(..) => {
|
||||||
todo!()
|
todo!()
|
||||||
|
@ -873,7 +864,9 @@ impl<'a> Compiler<'a> {
|
||||||
self.emit_op(Op::MatchString);
|
self.emit_op(Op::MatchString);
|
||||||
self.emit_byte(pattern_idx);
|
self.emit_byte(pattern_idx);
|
||||||
|
|
||||||
let jnm_idx = self.stub_jump(Op::JumpIfNoMatch);
|
self.emit_op(Op::JumpIfNoMatch);
|
||||||
|
let jnm_idx = self.len();
|
||||||
|
self.emit_byte(0xff);
|
||||||
|
|
||||||
self.emit_op(Op::PushStringMatches);
|
self.emit_op(Op::PushStringMatches);
|
||||||
self.emit_byte(pattern_idx);
|
self.emit_byte(pattern_idx);
|
||||||
|
@ -889,7 +882,7 @@ impl<'a> Compiler<'a> {
|
||||||
self.stack_depth += 1;
|
self.stack_depth += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.patch_jump(jnm_idx, self.len() - jnm_idx - 3);
|
self.chunk.bytecode[jnm_idx] = (self.len() - jnm_idx - 1) as u8;
|
||||||
}
|
}
|
||||||
PairPattern(_, _) => unreachable!(),
|
PairPattern(_, _) => unreachable!(),
|
||||||
Tuple(members) => {
|
Tuple(members) => {
|
||||||
|
@ -957,10 +950,12 @@ impl<'a> Compiler<'a> {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
self.visit(arg);
|
self.visit(arg);
|
||||||
self.emit_op(Op::Stash);
|
self.emit_op(Op::Stash);
|
||||||
jump_idxes.push(self.stub_jump(Op::JumpIfTrue));
|
self.emit_op(Op::JumpIfTrue);
|
||||||
|
jump_idxes.push(self.len());
|
||||||
|
self.emit_byte(0xff);
|
||||||
}
|
}
|
||||||
for idx in jump_idxes {
|
for idx in jump_idxes {
|
||||||
self.patch_jump(idx, self.len() - idx);
|
self.chunk.bytecode[idx] = (self.len() - idx + 2) as u8;
|
||||||
}
|
}
|
||||||
self.emit_op(Op::Load);
|
self.emit_op(Op::Load);
|
||||||
} else {
|
} else {
|
||||||
|
@ -975,10 +970,12 @@ impl<'a> Compiler<'a> {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
self.visit(arg);
|
self.visit(arg);
|
||||||
self.emit_op(Op::Stash);
|
self.emit_op(Op::Stash);
|
||||||
jump_idxes.push(self.stub_jump(Op::JumpIfFalse));
|
self.emit_op(Op::JumpIfFalse);
|
||||||
|
jump_idxes.push(self.len());
|
||||||
|
self.emit_byte(0xff);
|
||||||
}
|
}
|
||||||
for idx in jump_idxes {
|
for idx in jump_idxes {
|
||||||
self.patch_jump(idx, self.len() - idx);
|
self.chunk.bytecode[idx] = (self.len() - idx + 2) as u8;
|
||||||
}
|
}
|
||||||
self.emit_op(Op::Load);
|
self.emit_op(Op::Load);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1048,16 +1045,20 @@ impl<'a> Compiler<'a> {
|
||||||
let mut clauses = clauses.iter();
|
let mut clauses = clauses.iter();
|
||||||
while let Some((WhenClause(cond, body), _)) = clauses.next() {
|
while let Some((WhenClause(cond, body), _)) = clauses.next() {
|
||||||
self.visit(cond.as_ref());
|
self.visit(cond.as_ref());
|
||||||
let jif_jump_idx = self.stub_jump(Op::JumpIfFalse);
|
self.emit_op(Op::JumpIfFalse);
|
||||||
|
let jif_jump_idx = self.len();
|
||||||
|
self.emit_byte(0xff);
|
||||||
self.stack_depth -= 1;
|
self.stack_depth -= 1;
|
||||||
self.visit(body);
|
self.visit(body);
|
||||||
self.stack_depth -= 1;
|
self.stack_depth -= 1;
|
||||||
jump_idxes.push(self.stub_jump(Op::Jump));
|
self.emit_op(Op::Jump);
|
||||||
self.patch_jump(jif_jump_idx, self.len() - jif_jump_idx - 3);
|
jump_idxes.push(self.len());
|
||||||
|
self.emit_byte(0xff);
|
||||||
|
self.chunk.bytecode[jif_jump_idx] = (self.len() - jif_jump_idx) as u8 - 1;
|
||||||
}
|
}
|
||||||
self.emit_op(Op::PanicNoWhen);
|
self.emit_op(Op::PanicNoWhen);
|
||||||
for idx in jump_idxes {
|
for idx in jump_idxes {
|
||||||
self.patch_jump(idx, self.len() - idx - 3);
|
self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1;
|
||||||
}
|
}
|
||||||
self.stack_depth += 1;
|
self.stack_depth += 1;
|
||||||
}
|
}
|
||||||
|
@ -1072,12 +1073,16 @@ impl<'a> Compiler<'a> {
|
||||||
self.scope_depth += 1;
|
self.scope_depth += 1;
|
||||||
self.match_depth = 0;
|
self.match_depth = 0;
|
||||||
self.visit(pattern);
|
self.visit(pattern);
|
||||||
no_match_jumps.push(self.stub_jump(Op::JumpIfNoMatch));
|
self.emit_op(Op::JumpIfNoMatch);
|
||||||
|
no_match_jumps.push(self.len());
|
||||||
|
self.emit_byte(0xff);
|
||||||
if guard.is_some() {
|
if guard.is_some() {
|
||||||
let guard_expr: &'static Spanned<Ast> =
|
let guard_expr: &'static Spanned<Ast> =
|
||||||
Box::leak(Box::new(guard.clone().unwrap()));
|
Box::leak(Box::new(guard.clone().unwrap()));
|
||||||
self.visit(guard_expr);
|
self.visit(guard_expr);
|
||||||
no_match_jumps.push(self.stub_jump(Op::JumpIfFalse));
|
self.emit_op(Op::JumpIfFalse);
|
||||||
|
no_match_jumps.push(self.len());
|
||||||
|
self.emit_byte(0xff);
|
||||||
self.stack_depth -= 1;
|
self.stack_depth -= 1;
|
||||||
}
|
}
|
||||||
self.visit(body);
|
self.visit(body);
|
||||||
|
@ -1090,29 +1095,31 @@ impl<'a> Compiler<'a> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.pop_n(self.stack_depth - stack_depth);
|
while self.stack_depth > stack_depth {
|
||||||
jump_idxes.push(self.stub_jump(Op::Jump));
|
self.pop();
|
||||||
|
}
|
||||||
|
self.emit_op(Op::Jump);
|
||||||
|
jump_idxes.push(self.len());
|
||||||
|
self.emit_byte(0xff);
|
||||||
for idx in no_match_jumps {
|
for idx in no_match_jumps {
|
||||||
self.patch_jump(idx, self.len() - idx - 3);
|
self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 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.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1;
|
||||||
// self.chunk.bytecode[idx] = (self.len() - idx) as u8 - 1;
|
}
|
||||||
|
while self.stack_depth > stack_depth {
|
||||||
|
self.pop();
|
||||||
}
|
}
|
||||||
self.pop_n(self.stack_depth - stack_depth);
|
|
||||||
// while self.stack_depth > stack_depth {
|
|
||||||
// self.pop();
|
|
||||||
// }
|
|
||||||
self.emit_op(Op::Load);
|
self.emit_op(Op::Load);
|
||||||
self.stack_depth += 1;
|
self.stack_depth += 1;
|
||||||
}
|
}
|
||||||
MatchClause(..) => unreachable!(),
|
MatchClause(..) => unreachable!(),
|
||||||
Fn(name, body, doc) => {
|
Fn(name, body, doc) => {
|
||||||
let name = if name.is_empty() { "anonymous" } else { name };
|
let name = if name.is_empty() { "anonymous" } else { name };
|
||||||
|
// first, declare the function
|
||||||
|
// TODO: or, check if the function has already been declared!
|
||||||
let FnBody(fn_body) = &body.as_ref().0 else {
|
let FnBody(fn_body) = &body.as_ref().0 else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
@ -1154,26 +1161,35 @@ impl<'a> Compiler<'a> {
|
||||||
compiler.emit_op(Op::MatchDepth);
|
compiler.emit_op(Op::MatchDepth);
|
||||||
compiler.emit_byte(compiler.match_depth);
|
compiler.emit_byte(compiler.match_depth);
|
||||||
compiler.visit(member);
|
compiler.visit(member);
|
||||||
tup_jump_idxes.push(compiler.stub_jump(Op::JumpIfNoMatch));
|
compiler.emit_op(Op::JumpIfNoMatch);
|
||||||
|
tup_jump_idxes.push(compiler.len());
|
||||||
|
compiler.emit_byte(0xff);
|
||||||
}
|
}
|
||||||
if pattern.is_empty() {
|
if pattern.is_empty() {
|
||||||
compiler.emit_op(Op::Match);
|
compiler.emit_op(Op::Match);
|
||||||
}
|
}
|
||||||
let jump_idx = compiler.stub_jump(Op::Jump);
|
compiler.emit_op(Op::Jump);
|
||||||
|
let jump_idx = compiler.len();
|
||||||
|
compiler.emit_byte(0xff);
|
||||||
for idx in tup_jump_idxes {
|
for idx in tup_jump_idxes {
|
||||||
compiler.patch_jump(idx, compiler.len() - idx - 3);
|
compiler.chunk.bytecode[idx] = compiler.len() as u8 - idx as u8 - 2;
|
||||||
}
|
}
|
||||||
for _ in 0..arity {
|
for _ in 0..arity {
|
||||||
compiler.emit_op(Op::Pop);
|
compiler.emit_op(Op::Pop);
|
||||||
}
|
}
|
||||||
compiler.patch_jump(jump_idx, compiler.len() - jump_idx - 3);
|
compiler.chunk.bytecode[jump_idx] = compiler.len() as u8 - jump_idx as u8 - 1;
|
||||||
let mut no_match_jumps = vec![];
|
let mut no_match_jumps = vec![];
|
||||||
no_match_jumps.push(compiler.stub_jump(Op::JumpIfNoMatch));
|
compiler.emit_op(Op::JumpIfNoMatch);
|
||||||
|
// let jnm_idx = compiler.len();
|
||||||
|
no_match_jumps.push(compiler.len());
|
||||||
|
compiler.emit_byte(0xff);
|
||||||
if guard.is_some() {
|
if guard.is_some() {
|
||||||
let guard_expr: &'static Spanned<Ast> =
|
let guard_expr: &'static Spanned<Ast> =
|
||||||
Box::leak(Box::new(guard.clone().unwrap()));
|
Box::leak(Box::new(guard.clone().unwrap()));
|
||||||
compiler.visit(guard_expr);
|
compiler.visit(guard_expr);
|
||||||
no_match_jumps.push(compiler.stub_jump(Op::JumpIfFalse));
|
compiler.emit_op(Op::JumpIfFalse);
|
||||||
|
no_match_jumps.push(self.len());
|
||||||
|
compiler.emit_byte(0xff);
|
||||||
compiler.stack_depth -= 1;
|
compiler.stack_depth -= 1;
|
||||||
}
|
}
|
||||||
compiler.visit(clause_body);
|
compiler.visit(clause_body);
|
||||||
|
@ -1186,12 +1202,15 @@ impl<'a> Compiler<'a> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
compiler.pop_n(compiler.stack_depth);
|
while compiler.stack_depth > 0 {
|
||||||
|
compiler.pop();
|
||||||
|
}
|
||||||
compiler.stack_depth = 0;
|
compiler.stack_depth = 0;
|
||||||
compiler.emit_op(Op::Return);
|
compiler.emit_op(Op::Return);
|
||||||
for idx in no_match_jumps {
|
for idx in no_match_jumps {
|
||||||
compiler.patch_jump(idx, compiler.len() - idx - 3);
|
compiler.chunk.bytecode[idx] = compiler.len() as u8 - idx as u8 - 1;
|
||||||
}
|
}
|
||||||
|
// compiler.chunk.bytecode[jnm_idx] = compiler.len() as u8 - jnm_idx as u8 - 1;
|
||||||
compiler.scope_depth -= 1;
|
compiler.scope_depth -= 1;
|
||||||
|
|
||||||
std::mem::swap(&mut compiler.upvalues, &mut upvalues);
|
std::mem::swap(&mut compiler.upvalues, &mut upvalues);
|
||||||
|
@ -1232,27 +1251,42 @@ impl<'a> Compiler<'a> {
|
||||||
self.bind(name);
|
self.bind(name);
|
||||||
}
|
}
|
||||||
FnBody(_) => unreachable!(),
|
FnBody(_) => unreachable!(),
|
||||||
|
// TODO: add a check to make sure times >= 0
|
||||||
|
// TODO: fix this so that the algorithm is actually correct
|
||||||
|
// * truncate
|
||||||
|
// * check that it's 0 or more, panic if not
|
||||||
|
// * jump if 0 to end of loop
|
||||||
|
// * body
|
||||||
|
// * pop
|
||||||
|
// * decrement counter (which is now at the top of the stack)
|
||||||
|
// * jump back to jump if 0 instruction
|
||||||
Repeat(times, body) => {
|
Repeat(times, body) => {
|
||||||
self.visit(times);
|
self.visit(times);
|
||||||
self.emit_op(Op::Truncate);
|
self.emit_op(Op::Truncate);
|
||||||
// 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(1);
|
self.emit_byte(1);
|
||||||
// begin repeat
|
// begin repeat
|
||||||
self.emit_op(Op::Decrement);
|
self.emit_op(Op::Decrement);
|
||||||
let repeat_begin = self.len();
|
let repeat_begin = self.len();
|
||||||
self.emit_op(Op::Duplicate);
|
self.emit_op(Op::Duplicate);
|
||||||
let jiz_idx = self.stub_jump(Op::JumpIfZero);
|
// self.stack_depth += 1;
|
||||||
|
self.emit_op(Op::JumpIfZero);
|
||||||
|
self.emit_byte(0xff);
|
||||||
// compile the body
|
// compile the body
|
||||||
self.visit(body);
|
self.visit(body);
|
||||||
// pop whatever value the body returns
|
// pop whatever value the body returns
|
||||||
self.pop();
|
self.pop();
|
||||||
let jump_back = self.stub_jump(Op::JumpBack);
|
// self.emit_op(Op::Pop);
|
||||||
|
self.emit_op(Op::JumpBack);
|
||||||
// set jump points
|
// set jump points
|
||||||
self.patch_jump(jump_back, self.len() - repeat_begin - 2);
|
let repeat_end = self.len();
|
||||||
self.patch_jump(jiz_idx, self.len() - repeat_begin - 4);
|
self.emit_byte(repeat_end - repeat_begin);
|
||||||
self.pop();
|
self.chunk.bytecode[repeat_begin + 2] = (repeat_end - repeat_begin - 2) as u8;
|
||||||
|
// pop the counter
|
||||||
|
// self.pop();
|
||||||
|
// self.emit_op(Op::Pop);
|
||||||
|
// and emit nil
|
||||||
self.emit_constant(Value::Nil);
|
self.emit_constant(Value::Nil);
|
||||||
}
|
}
|
||||||
Loop(value, clauses) => {
|
Loop(value, clauses) => {
|
||||||
|
|
|
@ -73,11 +73,9 @@ pub fn run(src: &'static str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
env::set_var("RUST_BACKTRACE", "1");
|
// env::set_var("RUST_BACKTRACE", "1");
|
||||||
let src = "
|
let src = "
|
||||||
repeat 4 {
|
let ((1)) = ((1))
|
||||||
:foo
|
|
||||||
}
|
|
||||||
";
|
";
|
||||||
run(src);
|
run(src);
|
||||||
}
|
}
|
||||||
|
|
15
src/value.rs
15
src/value.rs
|
@ -45,13 +45,6 @@ impl LFn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn accepts(&self, arity: u8) -> bool {
|
|
||||||
match self {
|
|
||||||
LFn::Defined { chunks, .. } => chunks.iter().any(|(a, _)| *a == arity),
|
|
||||||
LFn::Declared { .. } => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn name(&self) -> &'static str {
|
pub fn name(&self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
LFn::Declared { name } | LFn::Defined { name, .. } => name,
|
LFn::Declared { name } | LFn::Defined { name, .. } => name,
|
||||||
|
@ -59,6 +52,7 @@ impl LFn {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn chunk(&self, arity: u8) -> &Chunk {
|
pub fn chunk(&self, arity: u8) -> &Chunk {
|
||||||
|
// println!("Getting chunk of {arity} from {:?}", self);
|
||||||
match self {
|
match self {
|
||||||
LFn::Declared { .. } => unreachable!(),
|
LFn::Declared { .. } => unreachable!(),
|
||||||
LFn::Defined { chunks, .. } => &chunks.iter().find(|(a, _)| *a == arity).unwrap().1,
|
LFn::Defined { chunks, .. } => &chunks.iter().find(|(a, _)| *a == arity).unwrap().1,
|
||||||
|
@ -274,11 +268,4 @@ impl Value {
|
||||||
Partial(..) => "fn",
|
Partial(..) => "fn",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_fn(&self) -> &LFn {
|
|
||||||
match self {
|
|
||||||
Value::Fn(inner) => inner.as_ref(),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -790,12 +790,6 @@ impl Vm {
|
||||||
|
|
||||||
match val {
|
match val {
|
||||||
Value::Fn(_) => {
|
Value::Fn(_) => {
|
||||||
if !val.as_fn().accepts(arity) {
|
|
||||||
return self.panic_with(format!(
|
|
||||||
"wrong number of arguments to {} passing {arity} args",
|
|
||||||
val.show()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
let mut frame = CallFrame {
|
let mut frame = CallFrame {
|
||||||
function: val,
|
function: val,
|
||||||
arity,
|
arity,
|
||||||
|
|
Loading…
Reference in New Issue
Block a user