Compare commits
2 Commits
1e1593298d
...
74cc0025d6
Author | SHA1 | Date | |
---|---|---|---|
|
74cc0025d6 | ||
|
db7eb5965d |
|
@ -20,6 +20,7 @@ pub enum Op {
|
|||
PopN,
|
||||
PushBinding,
|
||||
Store,
|
||||
StoreAt,
|
||||
Load,
|
||||
ResetMatch,
|
||||
MatchNil,
|
||||
|
@ -67,6 +68,7 @@ impl std::fmt::Display for Op {
|
|||
PopN => "pop_n",
|
||||
PushBinding => "push_binding",
|
||||
Store => "store",
|
||||
StoreAt => "store_at",
|
||||
Load => "load",
|
||||
MatchNil => "match_nil",
|
||||
MatchTrue => "match_true",
|
||||
|
@ -134,7 +136,7 @@ impl Chunk {
|
|||
}
|
||||
PushBinding | MatchTuple | MatchList | MatchDict | LoadDictValue | PushTuple
|
||||
| PushDict | PushList | PushBox | Jump | JumpIfFalse | JumpIfNoMatch | JumpIfMatch
|
||||
| JumpBack | JumpIfZero | MatchDepth | PopN => {
|
||||
| JumpBack | JumpIfZero | MatchDepth | PopN | StoreAt => {
|
||||
let next = self.bytecode[i + 1];
|
||||
println!("{i:04}: {:16} {next:04}", op.to_string());
|
||||
}
|
||||
|
@ -319,22 +321,22 @@ impl Compiler {
|
|||
|
||||
fn enter_loop(&mut self) {
|
||||
self.loop_info
|
||||
.push(LoopInfo::new(self.len(), self.bindings.len()));
|
||||
.push(LoopInfo::new(self.len(), self.stack_depth));
|
||||
}
|
||||
|
||||
fn leave_loop(&mut self) {
|
||||
self.loop_info.pop();
|
||||
}
|
||||
|
||||
fn loop_info(&mut self) -> LoopInfo {
|
||||
fn loop_info(&self) -> LoopInfo {
|
||||
self.loop_info.last().unwrap().clone()
|
||||
}
|
||||
|
||||
fn loop_idx(&mut self) -> usize {
|
||||
fn loop_idx(&self) -> usize {
|
||||
self.loop_info.last().unwrap().start
|
||||
}
|
||||
|
||||
fn loop_root(&mut self) -> usize {
|
||||
fn loop_root(&self) -> usize {
|
||||
self.loop_info.last().unwrap().stack_root
|
||||
}
|
||||
|
||||
|
@ -825,57 +827,96 @@ impl Compiler {
|
|||
self.emit_constant(Value::Nil);
|
||||
}
|
||||
Loop(value, clauses) => {
|
||||
todo!();
|
||||
//algo:
|
||||
//first, put the values on the stack
|
||||
let (Ast::Tuple(members), _) = value.as_ref() else {
|
||||
unreachable!()
|
||||
};
|
||||
for member in members {
|
||||
for (i, member) in members.iter().enumerate() {
|
||||
self.visit(member);
|
||||
self.emit_op(Op::StoreAt);
|
||||
self.emit_byte(i);
|
||||
}
|
||||
let arity = members.len();
|
||||
let stack_depth = self.stack_depth;
|
||||
//then, save the beginning of the loop
|
||||
self.emit_op(Op::Load);
|
||||
self.enter_loop();
|
||||
self.emit_op(Op::ResetMatch);
|
||||
self.stack_depth += arity;
|
||||
//next, compile each clause:
|
||||
let mut clauses = clauses.iter();
|
||||
let mut jump_idxes = vec![];
|
||||
while let Some((Ast::MatchClause(pattern, _, body), _)) = clauses.next() {
|
||||
self.emit_op(Op::ResetMatch);
|
||||
self.scope_depth += 1;
|
||||
let (Ast::TuplePattern(members), _) = pattern.as_ref() else {
|
||||
unreachable!()
|
||||
};
|
||||
let mut match_depth = arity;
|
||||
let mut members = members.iter();
|
||||
while match_depth > 0 {
|
||||
self.match_depth = arity;
|
||||
let mut tup_jump_idxes = vec![];
|
||||
for member in members {
|
||||
self.match_depth -= 1;
|
||||
self.emit_op(Op::MatchDepth);
|
||||
self.emit_byte(match_depth - 1);
|
||||
self.visit(members.next().unwrap());
|
||||
match_depth -= 1;
|
||||
self.emit_byte(self.match_depth);
|
||||
self.visit(member);
|
||||
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);
|
||||
let jnm_idx = self.len();
|
||||
self.emit_byte(0xff);
|
||||
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_byte(0xff);
|
||||
jump_idxes.push(self.len());
|
||||
self.emit_byte(0xff);
|
||||
self.chunk.bytecode[jnm_idx] = self.len() as u8 - jnm_idx as u8;
|
||||
self.scope_depth -= 1;
|
||||
}
|
||||
self.emit_op(Op::PanicNoMatch);
|
||||
|
||||
// TODO: fix up jump indexes a la match
|
||||
|
||||
for idx in jump_idxes {
|
||||
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();
|
||||
}
|
||||
Recur(_) => {
|
||||
// algo
|
||||
// visit each member of the arguments
|
||||
// then store those in the return register
|
||||
// then pop back to loop stack root
|
||||
// then jump to loop start
|
||||
Recur(args) => {
|
||||
for (i, arg) in args.iter().enumerate() {
|
||||
self.visit(arg);
|
||||
self.emit_op(Op::StoreAt);
|
||||
self.emit_byte(i);
|
||||
}
|
||||
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(..)
|
||||
| Arguments(..)
|
||||
|
@ -910,7 +951,7 @@ impl Compiler {
|
|||
}
|
||||
PushBinding | MatchTuple | MatchList | PushTuple | PushDict | PushList
|
||||
| MatchDict | LoadDictValue | PushBox | Jump | JumpIfFalse | JumpIfNoMatch
|
||||
| JumpIfMatch | JumpBack | JumpIfZero | MatchDepth | PopN => {
|
||||
| JumpIfMatch | JumpBack | JumpIfZero | MatchDepth | PopN | StoreAt => {
|
||||
let (_, next) = codes.next().unwrap();
|
||||
println!("{i:04}: {:16} {next:04}", op.to_string());
|
||||
}
|
||||
|
|
11
src/main.rs
11
src/main.rs
|
@ -74,8 +74,15 @@ pub fn run(src: &'static str) {
|
|||
pub fn main() {
|
||||
env::set_var("RUST_BACKTRACE", "1");
|
||||
let src = "
|
||||
repeat 4.8 {
|
||||
true
|
||||
loop (true) with {
|
||||
(false) -> :done
|
||||
(true) -> recur (42)
|
||||
(42) -> recur (:thingie)
|
||||
(:thingie) -> {
|
||||
let x = false
|
||||
12
|
||||
recur (x)
|
||||
}
|
||||
}
|
||||
";
|
||||
run(src);
|
||||
|
|
|
@ -25,6 +25,7 @@ impl LFn {
|
|||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Value {
|
||||
Nothing,
|
||||
Nil,
|
||||
True,
|
||||
False,
|
||||
|
@ -44,6 +45,7 @@ impl std::fmt::Display for Value {
|
|||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
use Value::*;
|
||||
match self {
|
||||
Nothing => write!(f, "_"),
|
||||
Nil => write!(f, "nil"),
|
||||
True => write!(f, "true"),
|
||||
False => write!(f, "false"),
|
||||
|
@ -130,6 +132,7 @@ impl Value {
|
|||
pub fn type_of(&self) -> &'static str {
|
||||
use Value::*;
|
||||
match self {
|
||||
Nothing => unreachable!(),
|
||||
Nil => "nil",
|
||||
True => "bool",
|
||||
False => "bool",
|
||||
|
|
40
src/vm.rs
40
src/vm.rs
|
@ -34,7 +34,7 @@ pub struct Vm<'a> {
|
|||
pub stack: Vec<Value>,
|
||||
pub chunk: &'a Chunk,
|
||||
pub ip: usize,
|
||||
pub return_register: Value,
|
||||
pub return_register: [Value; 8],
|
||||
pub matches: bool,
|
||||
pub match_depth: u8,
|
||||
pub result: Option<Result<Value, Panic>>,
|
||||
|
@ -46,7 +46,16 @@ impl<'a> Vm<'a> {
|
|||
chunk,
|
||||
stack: vec![],
|
||||
ip: 0,
|
||||
return_register: Value::Nil,
|
||||
return_register: [
|
||||
Value::Nothing,
|
||||
Value::Nothing,
|
||||
Value::Nothing,
|
||||
Value::Nothing,
|
||||
Value::Nothing,
|
||||
Value::Nothing,
|
||||
Value::Nothing,
|
||||
Value::Nothing,
|
||||
],
|
||||
matches: false,
|
||||
match_depth: 0,
|
||||
result: None,
|
||||
|
@ -72,7 +81,13 @@ impl<'a> Vm<'a> {
|
|||
.map(|val| val.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("|");
|
||||
println!("{:04}: [{inner}] {}", self.ip, self.return_register);
|
||||
let register = self
|
||||
.return_register
|
||||
.iter()
|
||||
.map(|val| val.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(",");
|
||||
println!("{:04}: [{inner}] ({register})", self.ip);
|
||||
}
|
||||
|
||||
fn print_debug(&self) {
|
||||
|
@ -174,14 +189,23 @@ impl<'a> Vm<'a> {
|
|||
self.ip += 2;
|
||||
}
|
||||
Store => {
|
||||
self.return_register = self.pop();
|
||||
self.push(Value::Nil);
|
||||
self.return_register[0] = self.pop();
|
||||
self.push(Value::Nothing);
|
||||
self.ip += 1;
|
||||
}
|
||||
StoreAt => {
|
||||
let i = self.chunk.bytecode[self.ip + 1] as usize;
|
||||
self.return_register[i] = self.pop();
|
||||
self.ip += 2;
|
||||
}
|
||||
Load => {
|
||||
let mut value = Value::Nil;
|
||||
swap(&mut self.return_register, &mut value);
|
||||
self.push(value);
|
||||
let mut i = 0;
|
||||
while i < 8 && self.return_register[i] != Value::Nothing {
|
||||
let mut value = Value::Nothing;
|
||||
swap(&mut self.return_register[i], &mut value);
|
||||
self.push(value);
|
||||
i += 1;
|
||||
}
|
||||
self.ip += 1;
|
||||
}
|
||||
ResetMatch => {
|
||||
|
|
Loading…
Reference in New Issue
Block a user