first draft loop/recur, seems to work?
This commit is contained in:
parent
db7eb5965d
commit
74cc0025d6
|
@ -20,6 +20,7 @@ pub enum Op {
|
||||||
PopN,
|
PopN,
|
||||||
PushBinding,
|
PushBinding,
|
||||||
Store,
|
Store,
|
||||||
|
StoreAt,
|
||||||
Load,
|
Load,
|
||||||
ResetMatch,
|
ResetMatch,
|
||||||
MatchNil,
|
MatchNil,
|
||||||
|
@ -67,6 +68,7 @@ impl std::fmt::Display for Op {
|
||||||
PopN => "pop_n",
|
PopN => "pop_n",
|
||||||
PushBinding => "push_binding",
|
PushBinding => "push_binding",
|
||||||
Store => "store",
|
Store => "store",
|
||||||
|
StoreAt => "store_at",
|
||||||
Load => "load",
|
Load => "load",
|
||||||
MatchNil => "match_nil",
|
MatchNil => "match_nil",
|
||||||
MatchTrue => "match_true",
|
MatchTrue => "match_true",
|
||||||
|
@ -134,7 +136,7 @@ impl Chunk {
|
||||||
}
|
}
|
||||||
PushBinding | MatchTuple | MatchList | MatchDict | LoadDictValue | PushTuple
|
PushBinding | MatchTuple | MatchList | MatchDict | LoadDictValue | PushTuple
|
||||||
| PushDict | PushList | PushBox | Jump | JumpIfFalse | JumpIfNoMatch | JumpIfMatch
|
| PushDict | PushList | PushBox | Jump | JumpIfFalse | JumpIfNoMatch | JumpIfMatch
|
||||||
| JumpBack | JumpIfZero | MatchDepth | PopN => {
|
| JumpBack | JumpIfZero | MatchDepth | PopN | StoreAt => {
|
||||||
let next = self.bytecode[i + 1];
|
let next = self.bytecode[i + 1];
|
||||||
println!("{i:04}: {:16} {next:04}", op.to_string());
|
println!("{i:04}: {:16} {next:04}", op.to_string());
|
||||||
}
|
}
|
||||||
|
@ -319,22 +321,22 @@ impl Compiler {
|
||||||
|
|
||||||
fn enter_loop(&mut self) {
|
fn enter_loop(&mut self) {
|
||||||
self.loop_info
|
self.loop_info
|
||||||
.push(LoopInfo::new(self.len(), self.bindings.len()));
|
.push(LoopInfo::new(self.len(), self.stack_depth));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leave_loop(&mut self) {
|
fn leave_loop(&mut self) {
|
||||||
self.loop_info.pop();
|
self.loop_info.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loop_info(&mut self) -> LoopInfo {
|
fn loop_info(&self) -> LoopInfo {
|
||||||
self.loop_info.last().unwrap().clone()
|
self.loop_info.last().unwrap().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loop_idx(&mut self) -> usize {
|
fn loop_idx(&self) -> usize {
|
||||||
self.loop_info.last().unwrap().start
|
self.loop_info.last().unwrap().start
|
||||||
}
|
}
|
||||||
|
|
||||||
fn loop_root(&mut self) -> usize {
|
fn loop_root(&self) -> usize {
|
||||||
self.loop_info.last().unwrap().stack_root
|
self.loop_info.last().unwrap().stack_root
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -825,58 +827,96 @@ impl Compiler {
|
||||||
self.emit_constant(Value::Nil);
|
self.emit_constant(Value::Nil);
|
||||||
}
|
}
|
||||||
Loop(value, clauses) => {
|
Loop(value, clauses) => {
|
||||||
todo!();
|
|
||||||
//algo:
|
//algo:
|
||||||
//first, put the values on the stack
|
//first, put the values on the stack
|
||||||
let (Ast::Tuple(members), _) = value.as_ref() else {
|
let (Ast::Tuple(members), _) = value.as_ref() else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
for member in members {
|
for (i, member) in members.iter().enumerate() {
|
||||||
self.visit(member);
|
self.visit(member);
|
||||||
|
self.emit_op(Op::StoreAt);
|
||||||
|
self.emit_byte(i);
|
||||||
}
|
}
|
||||||
let arity = members.len();
|
let arity = members.len();
|
||||||
|
let stack_depth = self.stack_depth;
|
||||||
//then, save the beginning of the loop
|
//then, save the beginning of the loop
|
||||||
|
self.emit_op(Op::Load);
|
||||||
self.enter_loop();
|
self.enter_loop();
|
||||||
self.emit_op(Op::ResetMatch);
|
self.stack_depth += arity;
|
||||||
//next, compile each clause:
|
//next, compile each clause:
|
||||||
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, _, body), _)) = clauses.next() {
|
while let Some((Ast::MatchClause(pattern, _, body), _)) = clauses.next() {
|
||||||
|
self.emit_op(Op::ResetMatch);
|
||||||
self.scope_depth += 1;
|
self.scope_depth += 1;
|
||||||
let (Ast::TuplePattern(members), _) = pattern.as_ref() else {
|
let (Ast::TuplePattern(members), _) = pattern.as_ref() else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
let mut match_depth = arity;
|
self.match_depth = arity;
|
||||||
let mut members = members.iter();
|
let mut tup_jump_idxes = vec![];
|
||||||
while match_depth > 0 {
|
for member in members {
|
||||||
|
self.match_depth -= 1;
|
||||||
self.emit_op(Op::MatchDepth);
|
self.emit_op(Op::MatchDepth);
|
||||||
self.emit_byte(match_depth - 1);
|
self.emit_byte(self.match_depth);
|
||||||
self.visit(members.next().unwrap());
|
self.visit(member);
|
||||||
match_depth -= 1;
|
self.emit_op(Op::JumpIfNoMatch);
|
||||||
|
tup_jump_idxes.push(self.len());
|
||||||
|
self.emit_byte(0xff);
|
||||||
}
|
}
|
||||||
|
self.emit_op(Op::Jump);
|
||||||
|
let jump_idx = self.len();
|
||||||
|
self.emit_byte(0xff);
|
||||||
|
for idx in tup_jump_idxes {
|
||||||
|
self.chunk.bytecode[idx] = self.len() as u8 - idx as u8 - 2;
|
||||||
|
}
|
||||||
|
for _ in 0..arity {
|
||||||
|
self.emit_op(Op::Pop);
|
||||||
|
}
|
||||||
|
self.chunk.bytecode[jump_idx] = self.len() as u8 - jump_idx as u8 - 1;
|
||||||
self.emit_op(Op::JumpIfNoMatch);
|
self.emit_op(Op::JumpIfNoMatch);
|
||||||
let jnm_idx = self.len();
|
let jnm_idx = self.len();
|
||||||
self.emit_byte(0xff);
|
self.emit_byte(0xff);
|
||||||
self.visit(body);
|
self.visit(body);
|
||||||
|
self.emit_op(Op::Store);
|
||||||
|
self.scope_depth -= 1;
|
||||||
|
while let Some(binding) = self.bindings.last() {
|
||||||
|
if binding.depth > self.scope_depth {
|
||||||
|
self.bindings.pop();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while self.stack_depth > stack_depth + arity {
|
||||||
|
self.pop();
|
||||||
|
}
|
||||||
|
self.stack_depth -= arity;
|
||||||
self.emit_op(Op::Jump);
|
self.emit_op(Op::Jump);
|
||||||
self.emit_byte(0xff);
|
|
||||||
jump_idxes.push(self.len());
|
jump_idxes.push(self.len());
|
||||||
|
self.emit_byte(0xff);
|
||||||
self.chunk.bytecode[jnm_idx] = self.len() as u8 - jnm_idx as u8;
|
self.chunk.bytecode[jnm_idx] = self.len() as u8 - jnm_idx as u8;
|
||||||
self.scope_depth -= 1;
|
self.scope_depth -= 1;
|
||||||
}
|
}
|
||||||
self.emit_op(Op::PanicNoMatch);
|
self.emit_op(Op::PanicNoMatch);
|
||||||
|
for idx in jump_idxes {
|
||||||
// TODO: fix up jump indexes a la match
|
self.chunk.bytecode[idx] = self.len() as u8 - idx as u8 - 1;
|
||||||
|
}
|
||||||
|
self.emit_op(Op::PopN);
|
||||||
|
self.emit_byte(arity);
|
||||||
|
self.stack_depth -= arity;
|
||||||
|
self.emit_op(Op::Load);
|
||||||
|
self.stack_depth += 1;
|
||||||
self.leave_loop();
|
self.leave_loop();
|
||||||
}
|
}
|
||||||
Recur(args) => {
|
Recur(args) => {
|
||||||
// algo
|
for (i, arg) in args.iter().enumerate() {
|
||||||
// visit each member of the arguments
|
self.visit(arg);
|
||||||
|
self.emit_op(Op::StoreAt);
|
||||||
// then store those in the return register
|
self.emit_byte(i);
|
||||||
// then pop back to loop stack root
|
}
|
||||||
// then jump to loop start
|
self.emit_op(Op::PopN);
|
||||||
|
self.emit_byte(self.loop_root());
|
||||||
|
self.emit_op(Op::JumpBack);
|
||||||
|
self.emit_byte(self.len() - self.loop_idx());
|
||||||
}
|
}
|
||||||
Interpolated(..)
|
Interpolated(..)
|
||||||
| Arguments(..)
|
| Arguments(..)
|
||||||
|
@ -911,7 +951,7 @@ impl Compiler {
|
||||||
}
|
}
|
||||||
PushBinding | MatchTuple | MatchList | PushTuple | PushDict | PushList
|
PushBinding | MatchTuple | MatchList | PushTuple | PushDict | PushList
|
||||||
| MatchDict | LoadDictValue | PushBox | Jump | JumpIfFalse | JumpIfNoMatch
|
| MatchDict | LoadDictValue | PushBox | Jump | JumpIfFalse | JumpIfNoMatch
|
||||||
| JumpIfMatch | JumpBack | JumpIfZero | MatchDepth | PopN => {
|
| JumpIfMatch | JumpBack | JumpIfZero | MatchDepth | PopN | StoreAt => {
|
||||||
let (_, next) = codes.next().unwrap();
|
let (_, next) = codes.next().unwrap();
|
||||||
println!("{i:04}: {:16} {next:04}", op.to_string());
|
println!("{i:04}: {:16} {next:04}", op.to_string());
|
||||||
}
|
}
|
||||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -74,7 +74,16 @@ 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 = "
|
||||||
123
|
loop (true) with {
|
||||||
|
(false) -> :done
|
||||||
|
(true) -> recur (42)
|
||||||
|
(42) -> recur (:thingie)
|
||||||
|
(:thingie) -> {
|
||||||
|
let x = false
|
||||||
|
12
|
||||||
|
recur (x)
|
||||||
|
}
|
||||||
|
}
|
||||||
";
|
";
|
||||||
run(src);
|
run(src);
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,6 +193,11 @@ impl<'a> Vm<'a> {
|
||||||
self.push(Value::Nothing);
|
self.push(Value::Nothing);
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
}
|
}
|
||||||
|
StoreAt => {
|
||||||
|
let i = self.chunk.bytecode[self.ip + 1] as usize;
|
||||||
|
self.return_register[i] = self.pop();
|
||||||
|
self.ip += 2;
|
||||||
|
}
|
||||||
Load => {
|
Load => {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < 8 && self.return_register[i] != Value::Nothing {
|
while i < 8 && self.return_register[i] != Value::Nothing {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user