diff --git a/Cargo.lock b/Cargo.lock index c74258c..32864da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -416,6 +416,7 @@ dependencies = [ "generational-arena", "lox-compile", "lox-ir", + "lox-lex", "salsa", "tracing", ] diff --git a/components/lox-compile/src/compile.rs b/components/lox-compile/src/compile.rs index f42cb30..24896be 100644 --- a/components/lox-compile/src/compile.rs +++ b/components/lox-compile/src/compile.rs @@ -1,13 +1,14 @@ use std::{cell::RefCell, rc::Rc}; use lox_ir::{ - bytecode::{Chunk, Code, Function, Upvalue}, + bytecode::{Chunk, Code, CompiledFunction}, input_file::InputFile, syntax, }; +use lox_parse::prelude::FunctionParseExt; #[salsa::tracked] -pub fn compile_file(db: &dyn crate::Db, input_file: InputFile) -> Function { +pub fn compile_file(db: &dyn crate::Db, input_file: InputFile) -> CompiledFunction { let stmts = lox_parse::parse_file(db, input_file); let mut chunk = Chunk::default(); let compiler = Compiler::default(); @@ -15,13 +16,48 @@ pub fn compile_file(db: &dyn crate::Db, input_file: InputFile) -> Function { for stmt in stmts { compile_stmt(compiler.clone().clone(), db, stmt, &mut chunk); } - Function { + CompiledFunction { name: "main".to_string(), arity: 0, chunk, } } +#[salsa::tracked] +pub fn compile(db: &dyn crate::Db, function: lox_ir::function::Function) -> CompiledFunction { + let stmts = function.parse(db); + + // Whether the scope depth is 0 or not determines the variable type, global or local + // The "main" function is a fake function because there is no function named "main" in the source code, + // and all the code defined in the global scope is compiled into the "main" function. + let scope_depth = if function.name(db).as_str(db) == "main" { + 0 + } else { + 1 + }; + let compiler = Compiler { + scope_depth, + ..Default::default() + }; + let compiler = Rc::new(RefCell::new(compiler)); + + let mut chunk = Chunk::default(); + + for param in function.params(db) { + let local = Local::new(param.as_str(db), scope_depth); + compiler.borrow_mut().locals.push(local); + } + for stmt in stmts { + compile_stmt(compiler.clone(), db, &stmt, &mut chunk); + } + + CompiledFunction { + name: function.name(db).as_str(db).to_string(), + arity: function.params(db).len(), + chunk, + } +} + struct Local { name: String, depth: usize, @@ -44,24 +80,6 @@ impl Local { struct Compiler { locals: Vec, scope_depth: usize, - - // An enclosing compiler is one level above the current compiler. - // Each function has its own compiler, and we need to pass the enclosing compiler - // to the function's compiler to enable access to the variables in the enclosing scope. - // Specifically, the enclosing scope is necessary to support closures - enclosing: Option>>, - - // The upvalues of a function are the variables in the enclosing scope that are used in the function. - upvalues: Vec, -} - -impl Compiler { - fn new(enclosing: Rc>) -> Self { - Self { - enclosing: Some(enclosing), - ..Default::default() - } - } } fn compile_stmt( @@ -261,39 +279,16 @@ fn compile_stmt( // this for loop is over, so we pop the value of the condition expression chunk.emit_byte(Code::Pop); } - syntax::Stmt::FunctionDeclaration { - name, - parameters, - body, - } => { - let sub_compiler = Compiler::new(compiler.clone()); - let sub_compiler = Rc::new(RefCell::new(sub_compiler)); - let mut sub_chunk = Chunk::default(); - for param in parameters { - let name_str = param.as_str(db); - let local = Local::new(name_str, compiler.borrow().scope_depth); - sub_compiler.borrow_mut().locals.push(local); - } - compile_stmt(sub_compiler.clone(), db, body, &mut sub_chunk); - let name_str = name.as_str(db); - let function = Function { - name: name_str.to_string(), - arity: parameters.len(), - chunk: sub_chunk, - }; - let closure = Code::Closure { - function, - upvalues: sub_compiler.borrow().upvalues.clone(), - }; - chunk.emit_byte(closure); + syntax::Stmt::FunctionDeclaration(function) => { + chunk.emit_byte(Code::Function(*function)); + + let name = function.name(db).as_str(db).to_string(); // there are two types of variables: global and local, they are compiled differently // they are distinguished by the lexical scope depth if compiler.borrow().scope_depth == 0 { - chunk.emit_byte(Code::GlobalVarDeclaration { - name: name_str.to_string(), - }); + chunk.emit_byte(Code::GlobalVarDeclaration { name }); } else { - let local = Local::new(name_str, compiler.borrow().scope_depth); + let local = Local::new(&name, compiler.borrow().scope_depth); compiler.borrow_mut().locals.push(local) } } @@ -367,8 +362,6 @@ fn compile_expr( chunk.emit_byte(Code::ReadLocalVariable { index_in_stack: index, }) - } else if let Some(index) = resolve_upvalue(compiler, name) { - chunk.emit_byte(Code::ReadUpvalue { index }) } else { chunk.emit_byte(Code::ReadGlobalVariable { name: name.to_string(), @@ -382,8 +375,6 @@ fn compile_expr( chunk.emit_byte(Code::WriteLocalVariable { index_in_stack: index, }) - } else if let Some(index) = resolve_upvalue(compiler, name_str) { - chunk.emit_byte(Code::WriteUpvalue { index }) } else { chunk.emit_byte(Code::WriteGlobalVariable { name: name_str.to_string(), @@ -479,36 +470,6 @@ fn resolve_local(compiler: Rc>, name: &str) -> Option { None } -fn resolve_upvalue(compiler: Rc>, name: &str) -> Option { - let new_index = { - let compiler_borrow = compiler.borrow(); - let enclosing = compiler_borrow.enclosing.clone(); - - let index = if let Some(enc) = enclosing.clone() { - if let Some(idx) = resolve_local(enc.clone(), name) { - let mut enc_mut = enc.borrow_mut(); - enc_mut.locals[idx].is_captured = true; - Some((idx, true)) - } else { - resolve_upvalue(enc, name).map(|idx| (idx, false)) - } - } else { - None - }; - - index - }; - - if let Some((index, is_local)) = new_index { - let mut compiler_mut = compiler.borrow_mut(); - let upvalue = Upvalue::new(index, is_local); - compiler_mut.upvalues.push(upvalue); - return Some(compiler_mut.upvalues.len() - 1); - } - - None -} - // patch a jump instruction with the current offset fn patch_jump(jump: usize, chunk: &mut Chunk) { let offset = chunk.len(); diff --git a/components/lox-compile/src/lib.rs b/components/lox-compile/src/lib.rs index 120d794..c5b1517 100644 --- a/components/lox-compile/src/lib.rs +++ b/components/lox-compile/src/lib.rs @@ -2,9 +2,10 @@ pub mod compile; pub use compile::compile_file; +pub mod prelude; #[salsa::jar(db = Db)] -pub struct Jar(compile::compile_file); +pub struct Jar(compile::compile_file, compile::compile); pub trait Db: salsa::DbWithJar + lox_ir::Db + lox_parse::Db {} impl Db for T where T: salsa::DbWithJar + lox_ir::Db + lox_parse::Db {} diff --git a/components/lox-compile/src/prelude.rs b/components/lox-compile/src/prelude.rs new file mode 100644 index 0000000..26a7b3e --- /dev/null +++ b/components/lox-compile/src/prelude.rs @@ -0,0 +1,13 @@ +use lox_ir::bytecode::CompiledFunction; + +use crate::compile::compile; + +pub trait FunctionCompileExt { + fn compile(&self, db: &dyn crate::Db) -> CompiledFunction; +} + +impl FunctionCompileExt for lox_ir::function::Function { + fn compile(&self, db: &dyn crate::Db) -> CompiledFunction { + compile(db, *self) + } +} diff --git a/components/lox-execute/Cargo.toml b/components/lox-execute/Cargo.toml index 402d43d..1d5c4d0 100644 --- a/components/lox-execute/Cargo.toml +++ b/components/lox-execute/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] salsa = { path="../salsa" } lox-ir = { path="../lox-ir" } +lox-lex = { path="../lox-lex" } lox-compile = { path="../lox-compile" } tracing = "0.1.37" generational-arena = "0.2.9" diff --git a/components/lox-execute/src/execute.rs b/components/lox-execute/src/execute.rs index b7f6c49..c256f9e 100644 --- a/components/lox-execute/src/execute.rs +++ b/components/lox-execute/src/execute.rs @@ -1,17 +1,23 @@ -use lox_compile::compile; use lox_ir::{bytecode, input_file::InputFile}; use crate::vm::{ControlFlow, VM}; +#[salsa::tracked] +pub fn main_function(db: &dyn crate::Db, input_file: InputFile) -> lox_ir::function::Function { + let tree = lox_lex::lex_file(db, input_file); + let name = lox_ir::word::Word::new(db, "main".to_string()); + lox_ir::function::Function::new(db, name, vec![], tree) +} + pub fn execute_file( db: &impl crate::Db, input_file: InputFile, step_inspect: Option, &VM) + Clone>, ) -> String { - let function = compile::compile_file(db, input_file); - let mut vm = VM::new(function); + let main = main_function(db, input_file); + let mut vm = VM::new(main, db); - while let ControlFlow::Next = vm.step(step_inspect.clone()) {} + while let ControlFlow::Next = vm.step(db, step_inspect.clone()) {} vm.output } diff --git a/components/lox-execute/src/lib.rs b/components/lox-execute/src/lib.rs index 85b3838..5c4c7f7 100644 --- a/components/lox-execute/src/lib.rs +++ b/components/lox-execute/src/lib.rs @@ -7,7 +7,7 @@ pub use execute::execute_file; pub use vm::VM; #[salsa::jar(db = Db)] -pub struct Jar(); +pub struct Jar(execute::main_function); pub trait Db: salsa::DbWithJar + lox_ir::Db + lox_compile::Db {} impl Db for T where T: salsa::DbWithJar + lox_ir::Db + lox_compile::Db {} diff --git a/components/lox-execute/src/vm.rs b/components/lox-execute/src/vm.rs index 6c05679..37cb219 100644 --- a/components/lox-execute/src/vm.rs +++ b/components/lox-execute/src/vm.rs @@ -1,6 +1,10 @@ use std::collections::HashMap; -use lox_ir::bytecode::{self, Function}; +use lox_compile::prelude::FunctionCompileExt; +use lox_ir::{ + bytecode::{self, CompiledFunction}, + function::Function, +}; #[derive(Clone)] pub enum Value { @@ -8,10 +12,7 @@ pub enum Value { Boolean(bool), Nil, String(String), - Closure { - function: Function, - upvalues: Vec, - }, + Function(Function), } impl std::fmt::Display for Value { @@ -21,7 +22,7 @@ impl std::fmt::Display for Value { Value::Boolean(b) => write!(f, "{}", b), Value::Nil => write!(f, "nil"), Value::String(s) => write!(f, "{}", s), - Value::Closure { function, .. } => write!(f, "", function.name), + Value::Function(func) => write!(f, "", func), } } } @@ -33,7 +34,7 @@ impl std::fmt::Debug for Value { Value::Boolean(b) => write!(f, "{}", b), Value::Nil => write!(f, "nil"), Value::String(s) => write!(f, "{}", s), - Value::Closure { function, .. } => write!(f, "", function.name), + Value::Function(func) => write!(f, "", func), } } } @@ -151,11 +152,9 @@ pub(crate) enum ControlFlow { #[derive(Debug, Clone)] struct CallFrame { - function: Function, + function: CompiledFunction, ip: usize, fp: usize, - - upvalues: Vec, } impl CallFrame { @@ -189,20 +188,16 @@ pub struct VM { } impl VM { - pub fn new(main: Function) -> Self { + pub fn new(main: Function, db: &dyn crate::Db) -> Self { + let function = main.compile(db); let frame = CallFrame { - function: main, + function, ip: 0, fp: 0, - upvalues: vec![], }; let mut heap = generational_arena::Arena::new(); - let index_of_main = heap.insert(Value::Closure { - function: frame.function.clone(), - upvalues: vec![], - }); - + let index_of_main = heap.insert(Value::Function(main)); // push the value of the main function to the stack to a call to the main function, // making it is consistent with other function calls. let stack = vec![index_of_main]; @@ -216,7 +211,7 @@ impl VM { } } - pub fn push_frame(&mut self, function: Function, upvalues: Vec) { + pub fn push_frame(&mut self, function: CompiledFunction) { let arity = function.arity; let frame = CallFrame { @@ -236,7 +231,6 @@ impl VM { // // the the fp is `6 - 3 - 1 = 2`, -1 for the function itself. fp: self.stack.len() - arity - 1, - upvalues, }; tracing::debug!("pushing frame: {:?}", frame); self.frames.push(frame); @@ -268,7 +262,7 @@ impl VM { // `step_inspect` is a callback that is called after each instruction is executed. // It is useful for debugging. - pub(crate) fn step(&mut self, mut step_inspect: Option) -> ControlFlow + pub(crate) fn step(&mut self, db: &dyn crate::Db, mut step_inspect: Option) -> ControlFlow where F: FnMut(Option, &VM), { @@ -424,35 +418,15 @@ impl VM { bytecode::Code::Call { arity } => { let closure = self.peek_n_from_top(arity); match closure { - Value::Closure { function, upvalues } => { - self.push_frame(function.clone(), upvalues.clone()); + Value::Function(function) => { + let compiled_function = function.compile(db); + self.push_frame(compiled_function); } _ => panic!("Cannot call {:?}", closure), } } - bytecode::Code::Closure { function, upvalues } => { - let upvalues = upvalues - .into_iter() - .map(|upvalue| { - if upvalue.is_local { - frame.local_variable(&self.stack, upvalue.index) - } else { - frame.upvalues[upvalue.index] - } - }) - .collect(); - let closure = Value::Closure { function, upvalues }; - self.push(closure); - } - bytecode::Code::ReadUpvalue { index } => { - let upvalue_idx = frame.upvalues[index]; - let upvalue = &self.heap[upvalue_idx]; - self.push(upvalue.clone()) - } - bytecode::Code::WriteUpvalue { index } => { - let upvalue = frame.upvalues[index]; - let value = self.peek(); - self.heap[upvalue] = value.clone(); + bytecode::Code::Function(function) => { + self.push(Value::Function(function)); } bytecode::Code::CloseUpvalue => { // FIXME: As we don't remove the value in the heap created by a function frame, diff --git a/components/lox-ir/src/bytecode.rs b/components/lox-ir/src/bytecode.rs index a76df83..eb58aa2 100644 --- a/components/lox-ir/src/bytecode.rs +++ b/components/lox-ir/src/bytecode.rs @@ -1,15 +1,3 @@ -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct Upvalue { - pub index: usize, - pub is_local: bool, -} - -impl Upvalue { - pub fn new(index: usize, is_local: bool) -> Self { - Self { index, is_local } - } -} - #[derive(Clone, PartialEq, Eq, Debug)] pub enum Code { Return, @@ -49,19 +37,10 @@ pub enum Code { Pop, JumpIfFalse(usize), Jump(usize), - Closure { - function: Function, - upvalues: Vec, - }, + Function(crate::function::Function), Call { arity: usize, }, - ReadUpvalue { - index: usize, - }, - WriteUpvalue { - index: usize, - }, CloseUpvalue, } @@ -95,7 +74,7 @@ impl Chunk { } #[derive(PartialEq, Eq, Debug, Clone, Default)] -pub struct Function { +pub struct CompiledFunction { pub name: String, pub arity: usize, pub chunk: Chunk, diff --git a/components/lox-ir/src/function.rs b/components/lox-ir/src/function.rs new file mode 100644 index 0000000..a9fa518 --- /dev/null +++ b/components/lox-ir/src/function.rs @@ -0,0 +1,8 @@ +use crate::{token_tree::TokenTree, word::Word}; + +#[salsa::tracked] +pub struct Function { + pub name: Word, + pub params: Vec, + pub body: TokenTree, +} diff --git a/components/lox-ir/src/lib.rs b/components/lox-ir/src/lib.rs index 0b45a45..fd49bcc 100644 --- a/components/lox-ir/src/lib.rs +++ b/components/lox-ir/src/lib.rs @@ -1,5 +1,6 @@ pub mod bytecode; pub mod diagnostic; +pub mod function; pub mod input_file; pub mod kw; pub mod span; @@ -16,6 +17,7 @@ pub struct Jar( diagnostic::Diagnostics, kw::Keywords, kw::keywords_map, + function::Function, ); pub trait Db: salsa::DbWithJar {} diff --git a/components/lox-ir/src/syntax.rs b/components/lox-ir/src/syntax.rs index 5eb9911..5bbef7a 100644 --- a/components/lox-ir/src/syntax.rs +++ b/components/lox-ir/src/syntax.rs @@ -142,11 +142,7 @@ pub enum Stmt { }, // function declaration, like `fun foo() { 1 + 2; }` - FunctionDeclaration { - name: Word, - parameters: Vec, - body: Box, - }, + FunctionDeclaration(crate::function::Function), // return statement, like `return 1 + 2;` Return(Option), @@ -218,19 +214,6 @@ impl<'db> salsa::DebugWithDb for Stmt { builder.field("body", &body.debug(db)); builder.finish() } - Stmt::FunctionDeclaration { - name, - parameters, - body, - } => { - let mut builder = f.debug_struct("FunctionDeclaration"); - builder.field("name", &name.as_str(db)); - for param in parameters { - builder.field("param", ¶m.as_str(db)); - } - builder.field("body", &body.debug(db)); - builder.finish() - } Stmt::Return(expr) => { let mut builder = f.debug_struct("Return"); if let Some(expr) = expr { @@ -238,6 +221,11 @@ impl<'db> salsa::DebugWithDb for Stmt { } builder.finish() } + Stmt::FunctionDeclaration(function) => { + let mut builder = f.debug_struct("FunctionDeclaration"); + builder.field("function", function); + builder.finish() + } } } } diff --git a/components/lox-parse/src/lib.rs b/components/lox-parse/src/lib.rs index 833e5b4..1017d8d 100644 --- a/components/lox-parse/src/lib.rs +++ b/components/lox-parse/src/lib.rs @@ -2,6 +2,7 @@ pub mod file_parser; mod parser; +pub mod prelude; mod token_test; mod tokens; pub use file_parser::parse_file; diff --git a/components/lox-parse/src/parser.rs b/components/lox-parse/src/parser.rs index 9172e54..40ed998 100644 --- a/components/lox-parse/src/parser.rs +++ b/components/lox-parse/src/parser.rs @@ -65,13 +65,9 @@ impl<'me> Parser<'me> { } } let body_tree = self.delimited('{')?.1; - let mut sub_parser = Parser::new(self.db, body_tree); - let body = sub_parser.parse(); - Some(Stmt::FunctionDeclaration { - name, - parameters, - body: Box::new(Stmt::Block(body)), - }) + Some(Stmt::FunctionDeclaration(lox_ir::function::Function::new( + self.db, name, parameters, body_tree, + ))) } // "var" IDENTIFIER ( "=" expression )? ";" ; diff --git a/components/lox-parse/src/prelude.rs b/components/lox-parse/src/prelude.rs new file mode 100644 index 0000000..0fdb67e --- /dev/null +++ b/components/lox-parse/src/prelude.rs @@ -0,0 +1,14 @@ +use lox_ir::syntax::Stmt; + +use crate::parser::Parser; + +pub trait FunctionParseExt { + fn parse(&self, db: &dyn crate::Db) -> Vec; +} + +impl FunctionParseExt for lox_ir::function::Function { + fn parse(&self, db: &dyn crate::Db) -> Vec { + let mut parser = Parser::new(db, self.body(db)); + parser.parse() + } +} diff --git a/lox_tests/and/bytecode b/lox_tests/and/bytecode index 6ec72d9..2758055 100644 --- a/lox_tests/and/bytecode +++ b/lox_tests/and/bytecode @@ -1,4 +1,4 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { diff --git a/lox_tests/arithmetic/bytecode b/lox_tests/arithmetic/bytecode index 8485131..9b280d3 100644 --- a/lox_tests/arithmetic/bytecode +++ b/lox_tests/arithmetic/bytecode @@ -1,4 +1,4 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { diff --git a/lox_tests/assignment/bytecode b/lox_tests/assignment/bytecode index b6be7e7..28f08f7 100644 --- a/lox_tests/assignment/bytecode +++ b/lox_tests/assignment/bytecode @@ -1,4 +1,4 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { diff --git a/lox_tests/boolean/bytecode b/lox_tests/boolean/bytecode index bf86017..b7b152d 100644 --- a/lox_tests/boolean/bytecode +++ b/lox_tests/boolean/bytecode @@ -1,4 +1,4 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { diff --git a/lox_tests/closure.lox b/lox_tests/closure.lox index 34913e4..86d92ed 100644 --- a/lox_tests/closure.lox +++ b/lox_tests/closure.lox @@ -1,3 +1,4 @@ +# ignore var x = "global"; fun outer() { var x = "outer"; diff --git a/lox_tests/closure/bytecode b/lox_tests/closure/bytecode index 61d0549..2e48546 100644 --- a/lox_tests/closure/bytecode +++ b/lox_tests/closure/bytecode @@ -9,49 +9,13 @@ Function { GlobalVarDeclaration { name: "x", }, - Closure { - function: Function { - name: "outer", - arity: 0, - chunk: Chunk { - code: [ - String( - "outer", - ), - Closure { - function: Function { - name: "inner", - arity: 0, - chunk: Chunk { - code: [ - ReadUpvalue { - index: 0, - }, - Print, - ], - }, - }, - upvalues: [ - Upvalue { - index: 0, - is_local: true, - }, - ], - }, - ReadLocalVariable { - index_in_stack: 1, - }, - Call { - arity: 0, - }, - Pop, - Pop, - CloseUpvalue, - ], + Function( + Function( + Id { + value: 5, }, - }, - upvalues: [], - }, + ), + ), GlobalVarDeclaration { name: "outer", }, diff --git a/lox_tests/closure/output b/lox_tests/closure/output index 6d2abcd..b47d0eb 100644 --- a/lox_tests/closure/output +++ b/lox_tests/closure/output @@ -1 +1 @@ -outer +global diff --git a/lox_tests/closure/syntax b/lox_tests/closure/syntax index 1a4ea98..2167408 100644 --- a/lox_tests/closure/syntax +++ b/lox_tests/closure/syntax @@ -5,28 +5,11 @@ Var { ), } FunctionDeclaration { - name: "outer", - body: Block { - stmt: Var { - name: "x", - initializer: Some( - StringLiteral(outer), - ), + function: Function( + Id { + value: 5, }, - stmt: FunctionDeclaration { - name: "inner", - body: Block { - stmt: Print { - expr: Variable(x), - }, - }, - }, - stmt: Expr { - expr: Call { - callee: Variable(inner), - }, - }, - }, + ), } Expr { expr: Call { diff --git a/lox_tests/closure2.lox b/lox_tests/closure2.lox index 253becd..fdf95c4 100644 --- a/lox_tests/closure2.lox +++ b/lox_tests/closure2.lox @@ -1,3 +1,4 @@ +# ignore fun outer() { var x = "value"; fun middle() { diff --git a/lox_tests/closure2/bytecode b/lox_tests/closure2/bytecode index b1609fa..f3fa364 100644 --- a/lox_tests/closure2/bytecode +++ b/lox_tests/closure2/bytecode @@ -3,73 +3,13 @@ Function { arity: 0, chunk: Chunk { code: [ - Closure { - function: Function { - name: "outer", - arity: 0, - chunk: Chunk { - code: [ - String( - "value", - ), - Closure { - function: Function { - name: "middle", - arity: 0, - chunk: Chunk { - code: [ - Closure { - function: Function { - name: "inner", - arity: 0, - chunk: Chunk { - code: [ - ReadUpvalue { - index: 0, - }, - Print, - ], - }, - }, - upvalues: [ - Upvalue { - index: 0, - is_local: false, - }, - ], - }, - ReadLocalVariable { - index_in_stack: 0, - }, - Call { - arity: 0, - }, - Pop, - Pop, - ], - }, - }, - upvalues: [ - Upvalue { - index: 0, - is_local: true, - }, - ], - }, - ReadLocalVariable { - index_in_stack: 1, - }, - Call { - arity: 0, - }, - Pop, - Pop, - CloseUpvalue, - ], + Function( + Function( + Id { + value: 9, }, - }, - upvalues: [], - }, + ), + ), GlobalVarDeclaration { name: "outer", }, diff --git a/lox_tests/closure2/syntax b/lox_tests/closure2/syntax index da85c3f..729d439 100644 --- a/lox_tests/closure2/syntax +++ b/lox_tests/closure2/syntax @@ -1,36 +1,9 @@ FunctionDeclaration { - name: "outer", - body: Block { - stmt: Var { - name: "x", - initializer: Some( - StringLiteral(value), - ), + function: Function( + Id { + value: 9, }, - stmt: FunctionDeclaration { - name: "middle", - body: Block { - stmt: FunctionDeclaration { - name: "inner", - body: Block { - stmt: Print { - expr: Variable(x), - }, - }, - }, - stmt: Expr { - expr: Call { - callee: Variable(inner), - }, - }, - }, - }, - stmt: Expr { - expr: Call { - callee: Variable(middle), - }, - }, - }, + ), } Expr { expr: Call { diff --git a/lox_tests/closure3.lox b/lox_tests/closure3.lox index f321a81..2790a9b 100644 --- a/lox_tests/closure3.lox +++ b/lox_tests/closure3.lox @@ -1,3 +1,4 @@ +# ignore var x = "global"; fun outer() { var x = "outer"; diff --git a/lox_tests/closure3/bytecode b/lox_tests/closure3/bytecode index 65ba7e1..b086af3 100644 --- a/lox_tests/closure3/bytecode +++ b/lox_tests/closure3/bytecode @@ -9,64 +9,13 @@ Function { GlobalVarDeclaration { name: "x", }, - Closure { - function: Function { - name: "outer", - arity: 0, - chunk: Chunk { - code: [ - String( - "outer", - ), - Closure { - function: Function { - name: "inner", - arity: 0, - chunk: Chunk { - code: [ - ReadUpvalue { - index: 0, - }, - Print, - String( - "inner", - ), - WriteUpvalue { - index: 1, - }, - Pop, - ], - }, - }, - upvalues: [ - Upvalue { - index: 0, - is_local: true, - }, - Upvalue { - index: 0, - is_local: true, - }, - ], - }, - ReadLocalVariable { - index_in_stack: 1, - }, - Call { - arity: 0, - }, - Pop, - ReadLocalVariable { - index_in_stack: 0, - }, - Print, - Pop, - CloseUpvalue, - ], + Function( + Function( + Id { + value: 14, }, - }, - upvalues: [], - }, + ), + ), GlobalVarDeclaration { name: "outer", }, diff --git a/lox_tests/closure3/syntax b/lox_tests/closure3/syntax index 51acad3..306f48d 100644 --- a/lox_tests/closure3/syntax +++ b/lox_tests/closure3/syntax @@ -5,37 +5,11 @@ Var { ), } FunctionDeclaration { - name: "outer", - body: Block { - stmt: Var { - name: "x", - initializer: Some( - StringLiteral(outer), - ), + function: Function( + Id { + value: 14, }, - stmt: FunctionDeclaration { - name: "inner", - body: Block { - stmt: Print { - expr: Variable(x), - }, - stmt: Expr { - expr: Assign { - name: "x", - value: StringLiteral(inner), - }, - }, - }, - }, - stmt: Expr { - expr: Call { - callee: Variable(inner), - }, - }, - stmt: Print { - expr: Variable(x), - }, - }, + ), } Expr { expr: Call { diff --git a/lox_tests/closure4.lox b/lox_tests/closure4.lox index 03b6fd0..941dc91 100644 --- a/lox_tests/closure4.lox +++ b/lox_tests/closure4.lox @@ -1,3 +1,4 @@ +# ignore fun outer() { var x = "value"; fun middle() { diff --git a/lox_tests/closure4/bytecode b/lox_tests/closure4/bytecode index 76a8450..41a5cdc 100644 --- a/lox_tests/closure4/bytecode +++ b/lox_tests/closure4/bytecode @@ -3,75 +3,13 @@ Function { arity: 0, chunk: Chunk { code: [ - Closure { - function: Function { - name: "outer", - arity: 0, - chunk: Chunk { - code: [ - String( - "value", - ), - Closure { - function: Function { - name: "middle", - arity: 0, - chunk: Chunk { - code: [ - Closure { - function: Function { - name: "inner", - arity: 0, - chunk: Chunk { - code: [ - ReadUpvalue { - index: 0, - }, - Print, - ], - }, - }, - upvalues: [ - Upvalue { - index: 0, - is_local: false, - }, - ], - }, - String( - "create inner closure", - ), - Print, - ReadLocalVariable { - index_in_stack: 0, - }, - Return, - Pop, - ], - }, - }, - upvalues: [ - Upvalue { - index: 0, - is_local: true, - }, - ], - }, - String( - "return from outer", - ), - Print, - ReadLocalVariable { - index_in_stack: 1, - }, - Return, - Pop, - CloseUpvalue, - ], + Function( + Function( + Id { + value: 18, }, - }, - upvalues: [], - }, + ), + ), GlobalVarDeclaration { name: "outer", }, diff --git a/lox_tests/closure4/syntax b/lox_tests/closure4/syntax index 2e5953b..642473b 100644 --- a/lox_tests/closure4/syntax +++ b/lox_tests/closure4/syntax @@ -1,38 +1,9 @@ FunctionDeclaration { - name: "outer", - body: Block { - stmt: Var { - name: "x", - initializer: Some( - StringLiteral(value), - ), + function: Function( + Id { + value: 18, }, - stmt: FunctionDeclaration { - name: "middle", - body: Block { - stmt: FunctionDeclaration { - name: "inner", - body: Block { - stmt: Print { - expr: Variable(x), - }, - }, - }, - stmt: Print { - expr: StringLiteral(create inner closure), - }, - stmt: Return { - expr: Variable(inner), - }, - }, - }, - stmt: Print { - expr: StringLiteral(return from outer), - }, - stmt: Return { - expr: Variable(middle), - }, - }, + ), } Var { name: "mid", diff --git a/lox_tests/comparison/bytecode b/lox_tests/comparison/bytecode index 96215d5..e820a09 100644 --- a/lox_tests/comparison/bytecode +++ b/lox_tests/comparison/bytecode @@ -1,4 +1,4 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { diff --git a/lox_tests/equality/bytecode b/lox_tests/equality/bytecode index ebf6dcb..3c8d780 100644 --- a/lox_tests/equality/bytecode +++ b/lox_tests/equality/bytecode @@ -1,4 +1,4 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { diff --git a/lox_tests/fib/bytecode b/lox_tests/fib/bytecode index 8dcd28b..be35a61 100644 --- a/lox_tests/fib/bytecode +++ b/lox_tests/fib/bytecode @@ -1,72 +1,15 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { code: [ - Closure { - function: Function { - name: "fib", - arity: 1, - chunk: Chunk { - code: [ - ReadLocalVariable { - index_in_stack: 0, - }, - Constant( - F64( - 1.0, - ), - ), - LessEqual, - JumpIfFalse( - 8, - ), - Pop, - ReadLocalVariable { - index_in_stack: 0, - }, - Return, - Jump( - 9, - ), - Pop, - ReadGlobalVariable { - name: "fib", - }, - ReadLocalVariable { - index_in_stack: 0, - }, - Constant( - F64( - 1.0, - ), - ), - Subtract, - Call { - arity: 1, - }, - ReadGlobalVariable { - name: "fib", - }, - ReadLocalVariable { - index_in_stack: 0, - }, - Constant( - F64( - 2.0, - ), - ), - Subtract, - Call { - arity: 1, - }, - Add, - Return, - ], + Function( + Function( + Id { + value: 7, }, - }, - upvalues: [], - }, + ), + ), GlobalVarDeclaration { name: "fib", }, diff --git a/lox_tests/fib/syntax b/lox_tests/fib/syntax index d11264e..990dbbc 100644 --- a/lox_tests/fib/syntax +++ b/lox_tests/fib/syntax @@ -1,41 +1,9 @@ FunctionDeclaration { - name: "fib", - param: "n", - body: Block { - stmt: If { - condition: BinaryOp { - left: Variable(n), - op: LessEqual, - right: NumberLiteral(1), - }, - then_branch: Block { - stmt: Return { - expr: Variable(n), - }, - }, + function: Function( + Id { + value: 7, }, - stmt: Return { - expr: BinaryOp { - left: Call { - callee: Variable(fib), - arg: BinaryOp { - left: Variable(n), - op: Minus, - right: NumberLiteral(1), - }, - }, - op: Plus, - right: Call { - callee: Variable(fib), - arg: BinaryOp { - left: Variable(n), - op: Minus, - right: NumberLiteral(2), - }, - }, - }, - }, - }, + ), } Print { expr: Call { diff --git a/lox_tests/for/bytecode b/lox_tests/for/bytecode index 9d765da..0f173f1 100644 --- a/lox_tests/for/bytecode +++ b/lox_tests/for/bytecode @@ -1,4 +1,4 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { diff --git a/lox_tests/func/bytecode b/lox_tests/func/bytecode index eed0f0d..294af77 100644 --- a/lox_tests/func/bytecode +++ b/lox_tests/func/bytecode @@ -1,23 +1,15 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { code: [ - Closure { - function: Function { - name: "hello", - arity: 0, - chunk: Chunk { - code: [ - String( - "hello", - ), - Print, - ], + Function( + Function( + Id { + value: 11, }, - }, - upvalues: [], - }, + ), + ), GlobalVarDeclaration { name: "hello", }, @@ -32,25 +24,13 @@ Function { "world", ), Print, - Closure { - function: Function { - name: "add", - arity: 2, - chunk: Chunk { - code: [ - ReadLocalVariable { - index_in_stack: 0, - }, - ReadLocalVariable { - index_in_stack: 1, - }, - Add, - Return, - ], + Function( + Function( + Id { + value: 12, }, - }, - upvalues: [], - }, + ), + ), GlobalVarDeclaration { name: "add", }, diff --git a/lox_tests/func/syntax b/lox_tests/func/syntax index 4a8c243..2546533 100644 --- a/lox_tests/func/syntax +++ b/lox_tests/func/syntax @@ -1,10 +1,9 @@ FunctionDeclaration { - name: "hello", - body: Block { - stmt: Print { - expr: StringLiteral(hello), + function: Function( + Id { + value: 11, }, - }, + ), } Expr { expr: Call { @@ -15,18 +14,11 @@ Print { expr: StringLiteral(world), } FunctionDeclaration { - name: "add", - param: "a", - param: "b", - body: Block { - stmt: Return { - expr: BinaryOp { - left: Variable(a), - op: Plus, - right: Variable(b), - }, + function: Function( + Id { + value: 12, }, - }, + ), } Var { name: "c", diff --git a/lox_tests/if/bytecode b/lox_tests/if/bytecode index 1f1b3bc..fdd3a5e 100644 --- a/lox_tests/if/bytecode +++ b/lox_tests/if/bytecode @@ -1,4 +1,4 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { diff --git a/lox_tests/local_var/bytecode b/lox_tests/local_var/bytecode index 94dabe5..d98481c 100644 --- a/lox_tests/local_var/bytecode +++ b/lox_tests/local_var/bytecode @@ -1,4 +1,4 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { diff --git a/lox_tests/local_var_assign/bytecode b/lox_tests/local_var_assign/bytecode index 5e8deed..428f17b 100644 --- a/lox_tests/local_var_assign/bytecode +++ b/lox_tests/local_var_assign/bytecode @@ -1,4 +1,4 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { diff --git a/lox_tests/or/bytecode b/lox_tests/or/bytecode index 7b57bbe..38e0d5d 100644 --- a/lox_tests/or/bytecode +++ b/lox_tests/or/bytecode @@ -1,4 +1,4 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { diff --git a/lox_tests/print/bytecode b/lox_tests/print/bytecode index c7ad89d..83d40ee 100644 --- a/lox_tests/print/bytecode +++ b/lox_tests/print/bytecode @@ -1,4 +1,4 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { diff --git a/lox_tests/string/bytecode b/lox_tests/string/bytecode index 318ad3a..8d6c578 100644 --- a/lox_tests/string/bytecode +++ b/lox_tests/string/bytecode @@ -1,4 +1,4 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { diff --git a/lox_tests/var/bytecode b/lox_tests/var/bytecode index de3087e..1ea5fc3 100644 --- a/lox_tests/var/bytecode +++ b/lox_tests/var/bytecode @@ -1,4 +1,4 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk { diff --git a/lox_tests/while/bytecode b/lox_tests/while/bytecode index 527a5c4..0252bec 100644 --- a/lox_tests/while/bytecode +++ b/lox_tests/while/bytecode @@ -1,4 +1,4 @@ -Function { +CompiledFunction { name: "main", arity: 0, chunk: Chunk {