vm.chunk -> vm.callframe.chunk
This commit is contained in:
parent
de3d7e834c
commit
22d1ceb3e8
30
src/main.rs
30
src/main.rs
|
@ -57,26 +57,28 @@ pub fn run(src: &'static str) {
|
|||
println!("\n\n")
|
||||
}
|
||||
|
||||
// if DEBUG_RUN {
|
||||
// println!("=== vm run: test ===");
|
||||
// }
|
||||
if DEBUG_RUN {
|
||||
println!("=== vm run: test ===");
|
||||
}
|
||||
|
||||
// let mut vm = Vm::new(&compiler.chunk);
|
||||
// let result = vm.run();
|
||||
// let output = match result {
|
||||
// Ok(val) => val.show(&compiler.chunk),
|
||||
// Err(panic) => format!("Ludus panicked! {panic}"),
|
||||
// };
|
||||
// vm.print_stack();
|
||||
// println!("{output}");
|
||||
// TODO: investigate lifeteims and remove this clone
|
||||
let show_chunk = compiler.chunk.clone();
|
||||
let vm_chunk = compiler.chunk;
|
||||
|
||||
let mut vm = Vm::new(vm_chunk);
|
||||
let result = vm.run();
|
||||
let output = match result {
|
||||
Ok(val) => val.show(&show_chunk),
|
||||
Err(panic) => format!("Ludus panicked! {panic}"),
|
||||
};
|
||||
vm.print_stack();
|
||||
println!("{output}");
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
env::set_var("RUST_BACKTRACE", "1");
|
||||
let src = "
|
||||
fn foo () -> :bar
|
||||
|
||||
foo ()
|
||||
(1, 2, 3)
|
||||
";
|
||||
run(src);
|
||||
}
|
||||
|
|
124
src/vm.rs
124
src/vm.rs
|
@ -1,10 +1,11 @@
|
|||
use crate::compiler::{Chunk, Op};
|
||||
use crate::parser::Ast;
|
||||
use crate::spans::Spanned;
|
||||
use crate::value::Value;
|
||||
use crate::value::{LFn, Value};
|
||||
use chumsky::prelude::SimpleSpan;
|
||||
use imbl::{HashMap, Vector};
|
||||
use num_traits::FromPrimitive;
|
||||
use std::cell::OnceCell;
|
||||
use std::cell::RefCell;
|
||||
use std::fmt;
|
||||
use std::mem::swap;
|
||||
|
@ -43,9 +44,44 @@ pub struct Trace {
|
|||
pub src: &'static str,
|
||||
}
|
||||
|
||||
pub struct Vm<'a> {
|
||||
pub struct CallFrame {
|
||||
pub function: Value,
|
||||
pub arity: u8,
|
||||
pub stack_base: usize,
|
||||
pub ip: usize,
|
||||
}
|
||||
|
||||
impl CallFrame {
|
||||
pub fn chunk(&self) -> &Chunk {
|
||||
let Value::Fn(ref function) = self.function else {
|
||||
unreachable!()
|
||||
};
|
||||
&function
|
||||
.get()
|
||||
.unwrap()
|
||||
.chunks
|
||||
.iter()
|
||||
.find(|(arity, _)| *arity == self.arity)
|
||||
.unwrap()
|
||||
.1
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for CallFrame {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let Value::Fn(ref function) = self.function else {
|
||||
unreachable!()
|
||||
};
|
||||
let inner_fn = function.get().unwrap();
|
||||
let name = inner_fn.name;
|
||||
write!(f, "CallFrame: {name}/{} @ {}", self.arity, self.ip)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Vm {
|
||||
pub stack: Vec<Value>,
|
||||
pub chunk: &'a Chunk,
|
||||
pub call_stack: Vec<CallFrame>,
|
||||
pub frame: CallFrame,
|
||||
pub ip: usize,
|
||||
pub return_register: [Value; 7],
|
||||
pub matches: bool,
|
||||
|
@ -53,11 +89,27 @@ pub struct Vm<'a> {
|
|||
pub result: Option<Result<Value, Panic>>,
|
||||
}
|
||||
|
||||
impl<'a> Vm<'a> {
|
||||
pub fn new(chunk: &'a Chunk) -> Vm<'a> {
|
||||
impl Vm {
|
||||
pub fn new(chunk: Chunk) -> Vm {
|
||||
let cell = OnceCell::new();
|
||||
let lfn = LFn {
|
||||
name: "user script",
|
||||
doc: None,
|
||||
chunks: vec![(0, chunk)],
|
||||
closed: vec![],
|
||||
};
|
||||
let _ = cell.set(lfn);
|
||||
let base_fn = Value::Fn(Rc::new(cell));
|
||||
let base_frame = CallFrame {
|
||||
function: base_fn.clone(),
|
||||
stack_base: 1,
|
||||
ip: 0,
|
||||
arity: 0,
|
||||
};
|
||||
Vm {
|
||||
chunk,
|
||||
stack: vec![],
|
||||
call_stack: Vec::with_capacity(64),
|
||||
frame: base_frame,
|
||||
ip: 0,
|
||||
return_register: [
|
||||
Value::Nothing,
|
||||
|
@ -74,6 +126,10 @@ impl<'a> Vm<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn chunk(&self) -> &Chunk {
|
||||
self.frame.chunk()
|
||||
}
|
||||
|
||||
pub fn push(&mut self, value: Value) {
|
||||
self.stack.push(value);
|
||||
}
|
||||
|
@ -105,7 +161,7 @@ impl<'a> Vm<'a> {
|
|||
fn print_debug(&self) {
|
||||
self.print_stack();
|
||||
let mut ip = self.ip;
|
||||
self.chunk.dissasemble_instr(&mut ip);
|
||||
self.chunk().dissasemble_instr(&mut ip);
|
||||
}
|
||||
|
||||
pub fn run(&mut self) -> &Result<Value, Panic> {
|
||||
|
@ -124,7 +180,7 @@ impl<'a> Vm<'a> {
|
|||
}
|
||||
|
||||
pub fn interpret(&mut self) {
|
||||
let Some(byte) = self.chunk.bytecode.get(self.ip) else {
|
||||
let Some(byte) = self.chunk().bytecode.get(self.ip) else {
|
||||
self.result = Some(Ok(self.stack.pop().unwrap()));
|
||||
return;
|
||||
};
|
||||
|
@ -150,21 +206,21 @@ impl<'a> Vm<'a> {
|
|||
self.ip += 1;
|
||||
}
|
||||
Constant => {
|
||||
let const_idx = self.chunk.bytecode[self.ip + 1];
|
||||
let value = self.chunk.constants[const_idx as usize].clone();
|
||||
let const_idx = self.chunk().bytecode[self.ip + 1];
|
||||
let value = self.chunk().constants[const_idx as usize].clone();
|
||||
self.push(value);
|
||||
self.ip += 2;
|
||||
}
|
||||
Jump => {
|
||||
let jump_len = self.chunk.bytecode[self.ip + 1];
|
||||
let jump_len = self.chunk().bytecode[self.ip + 1];
|
||||
self.ip += jump_len as usize + 2;
|
||||
}
|
||||
JumpBack => {
|
||||
let jump_len = self.chunk.bytecode[self.ip + 1];
|
||||
let jump_len = self.chunk().bytecode[self.ip + 1];
|
||||
self.ip -= jump_len as usize;
|
||||
}
|
||||
JumpIfFalse => {
|
||||
let jump_len = self.chunk.bytecode[self.ip + 1];
|
||||
let jump_len = self.chunk().bytecode[self.ip + 1];
|
||||
let cond = self.pop();
|
||||
match cond {
|
||||
Value::Nil | Value::False => {
|
||||
|
@ -176,7 +232,7 @@ impl<'a> Vm<'a> {
|
|||
}
|
||||
}
|
||||
JumpIfTrue => {
|
||||
let jump_len = self.chunk.bytecode[self.ip + 1];
|
||||
let jump_len = self.chunk().bytecode[self.ip + 1];
|
||||
let cond = self.pop();
|
||||
match cond {
|
||||
Value::Nil | Value::False => {
|
||||
|
@ -188,7 +244,7 @@ impl<'a> Vm<'a> {
|
|||
}
|
||||
}
|
||||
JumpIfZero => {
|
||||
let jump_len = self.chunk.bytecode[self.ip + 1];
|
||||
let jump_len = self.chunk().bytecode[self.ip + 1];
|
||||
let cond = self.pop();
|
||||
match cond {
|
||||
Value::Number(0.0) => {
|
||||
|
@ -207,12 +263,12 @@ impl<'a> Vm<'a> {
|
|||
self.ip += 1;
|
||||
}
|
||||
PopN => {
|
||||
let n = self.chunk.bytecode[self.ip + 1] as usize;
|
||||
let n = self.chunk().bytecode[self.ip + 1] as usize;
|
||||
self.stack.truncate(self.stack.len() - n);
|
||||
self.ip += 2;
|
||||
}
|
||||
PushBinding => {
|
||||
let binding_idx = self.chunk.bytecode[self.ip + 1] as usize;
|
||||
let binding_idx = self.chunk().bytecode[self.ip + 1] as usize;
|
||||
let binding_value = self.stack[binding_idx].clone();
|
||||
self.push(binding_value);
|
||||
self.ip += 2;
|
||||
|
@ -223,7 +279,7 @@ impl<'a> Vm<'a> {
|
|||
self.ip += 1;
|
||||
}
|
||||
StoreAt => {
|
||||
let i = self.chunk.bytecode[self.ip + 1] as usize;
|
||||
let i = self.chunk().bytecode[self.ip + 1] as usize;
|
||||
self.return_register[i] = self.pop();
|
||||
self.ip += 2;
|
||||
}
|
||||
|
@ -254,7 +310,7 @@ impl<'a> Vm<'a> {
|
|||
let as_type = self.pop();
|
||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||
let val_type = self.stack[idx].type_of();
|
||||
let val_type = self.chunk.kw_from(val_type).unwrap();
|
||||
let val_type = self.chunk().kw_from(val_type).unwrap();
|
||||
self.matches = val_type == as_type;
|
||||
self.ip += 1;
|
||||
self.interpret()
|
||||
|
@ -289,14 +345,14 @@ impl<'a> Vm<'a> {
|
|||
}
|
||||
}
|
||||
MatchConstant => {
|
||||
let const_idx = self.chunk.bytecode[self.ip + 1];
|
||||
let const_idx = self.chunk().bytecode[self.ip + 1];
|
||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||
self.matches = self.stack[idx] == self.chunk.constants[const_idx as usize];
|
||||
self.matches = self.stack[idx] == self.chunk().constants[const_idx as usize];
|
||||
self.ip += 2;
|
||||
}
|
||||
MatchTuple => {
|
||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||
let tuple_len = self.chunk.bytecode[self.ip + 1];
|
||||
let tuple_len = self.chunk().bytecode[self.ip + 1];
|
||||
let scrutinee = self.stack[idx].clone();
|
||||
match scrutinee {
|
||||
Value::Tuple(members) => self.matches = members.len() == tuple_len as usize,
|
||||
|
@ -305,7 +361,7 @@ impl<'a> Vm<'a> {
|
|||
self.ip += 2;
|
||||
}
|
||||
PushTuple => {
|
||||
let tuple_len = self.chunk.bytecode[self.ip + 1];
|
||||
let tuple_len = self.chunk().bytecode[self.ip + 1];
|
||||
let tuple_members = self.stack.split_off(self.stack.len() - tuple_len as usize);
|
||||
let tuple = Value::Tuple(Rc::new(tuple_members));
|
||||
self.stack.push(tuple);
|
||||
|
@ -325,7 +381,7 @@ impl<'a> Vm<'a> {
|
|||
self.ip += 1;
|
||||
}
|
||||
PushList => {
|
||||
let list_len = self.chunk.bytecode[self.ip + 1];
|
||||
let list_len = self.chunk().bytecode[self.ip + 1];
|
||||
let list_members = self.stack.split_off(self.stack.len() - list_len as usize);
|
||||
let list = Value::List(Box::new(Vector::from(list_members)));
|
||||
self.stack.push(list);
|
||||
|
@ -333,7 +389,7 @@ impl<'a> Vm<'a> {
|
|||
}
|
||||
MatchList => {
|
||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||
let tuple_len = self.chunk.bytecode[self.ip + 1];
|
||||
let tuple_len = self.chunk().bytecode[self.ip + 1];
|
||||
let scrutinee = self.stack[idx].clone();
|
||||
match scrutinee {
|
||||
Value::List(members) => self.matches = members.len() == tuple_len as usize,
|
||||
|
@ -355,7 +411,7 @@ impl<'a> Vm<'a> {
|
|||
self.ip += 1;
|
||||
}
|
||||
PushDict => {
|
||||
let dict_len = self.chunk.bytecode[self.ip + 1] as usize * 2;
|
||||
let dict_len = self.chunk().bytecode[self.ip + 1] as usize * 2;
|
||||
let dict_members = self.stack.split_off(self.stack.len() - dict_len);
|
||||
let mut dict = HashMap::new();
|
||||
let mut dict_iter = dict_members.iter();
|
||||
|
@ -370,7 +426,7 @@ impl<'a> Vm<'a> {
|
|||
self.ip += 2;
|
||||
}
|
||||
LoadDictValue => {
|
||||
let dict_idx = self.chunk.bytecode[self.ip + 1] as usize;
|
||||
let dict_idx = self.chunk().bytecode[self.ip + 1] as usize;
|
||||
let Value::Dict(dict) = self.stack[dict_idx].clone() else {
|
||||
unreachable!("expected dict, got something else")
|
||||
};
|
||||
|
@ -383,7 +439,7 @@ impl<'a> Vm<'a> {
|
|||
}
|
||||
MatchDict => {
|
||||
let idx = self.stack.len() - self.match_depth as usize - 1;
|
||||
let dict_len = self.chunk.bytecode[self.ip + 1];
|
||||
let dict_len = self.chunk().bytecode[self.ip + 1];
|
||||
let scrutinee = self.stack[idx].clone();
|
||||
match scrutinee {
|
||||
Value::Dict(members) => self.matches = members.len() == dict_len as usize,
|
||||
|
@ -410,7 +466,7 @@ impl<'a> Vm<'a> {
|
|||
self.ip += 1;
|
||||
}
|
||||
JumpIfNoMatch => {
|
||||
let jump_len = self.chunk.bytecode[self.ip + 1] as usize;
|
||||
let jump_len = self.chunk().bytecode[self.ip + 1] as usize;
|
||||
if !self.matches {
|
||||
self.ip += jump_len + 2;
|
||||
} else {
|
||||
|
@ -418,7 +474,7 @@ impl<'a> Vm<'a> {
|
|||
}
|
||||
}
|
||||
JumpIfMatch => {
|
||||
let jump_len = self.chunk.bytecode[self.ip + 1] as usize;
|
||||
let jump_len = self.chunk().bytecode[self.ip + 1] as usize;
|
||||
if self.matches {
|
||||
self.ip += jump_len + 2;
|
||||
} else {
|
||||
|
@ -427,7 +483,7 @@ impl<'a> Vm<'a> {
|
|||
}
|
||||
TypeOf => {
|
||||
let val = self.pop();
|
||||
let type_of = self.chunk.kw_from(val.type_of()).unwrap();
|
||||
let type_of = self.chunk().kw_from(val.type_of()).unwrap();
|
||||
self.push(type_of);
|
||||
self.ip += 1;
|
||||
}
|
||||
|
@ -456,7 +512,7 @@ impl<'a> Vm<'a> {
|
|||
self.interpret()
|
||||
}
|
||||
MatchDepth => {
|
||||
self.match_depth = self.chunk.bytecode[self.ip + 1];
|
||||
self.match_depth = self.chunk().bytecode[self.ip + 1];
|
||||
self.ip += 2;
|
||||
self.interpret()
|
||||
}
|
||||
|
@ -582,7 +638,7 @@ impl<'a> Vm<'a> {
|
|||
self.ip += 1;
|
||||
}
|
||||
Panic => {
|
||||
let msg = self.pop().show(self.chunk);
|
||||
let msg = self.pop().show(self.chunk());
|
||||
self.panic_with(msg);
|
||||
}
|
||||
EmptyString => {
|
||||
|
@ -606,7 +662,7 @@ impl<'a> Vm<'a> {
|
|||
}
|
||||
Stringify => {
|
||||
let to_stringify = self.pop();
|
||||
let the_string = to_stringify.stringify(self.chunk);
|
||||
let the_string = to_stringify.stringify(self.chunk());
|
||||
let stringified = Value::String(Rc::new(the_string));
|
||||
self.push(stringified);
|
||||
self.ip += 1;
|
||||
|
|
Loading…
Reference in New Issue
Block a user