Skip to content

Commit

Permalink
feat: implement closure (todo add tests)
Browse files Browse the repository at this point in the history
  • Loading branch information
gengjiawen committed Jul 17, 2023
1 parent 272836e commit 1e2b3af
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 80 deletions.
18 changes: 14 additions & 4 deletions compiler/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,16 +246,20 @@ impl Compiler {
self.emit(OpReturn, &vec![]);
}
let num_locals = self.symbol_table.num_definitions;
let free_symbols = self.symbol_table.free_symbols.clone();
let instructions = self.leave_scope();
for x in free_symbols.clone() {
self.load_symbol(&x);
}

let compiled_function = object::CompiledFunction {
let compiled_function = Rc::from(object::CompiledFunction {
instructions: instructions.data,
num_locals,
num_parameters: f.params.len(),
};
});

let operands = vec![self.add_constant(Object::CompiledFunction(compiled_function))];
self.emit(OpConst, &operands);
let operands = vec![self.add_constant(Object::CompiledFunction(compiled_function)), free_symbols.len()];
self.emit(OpClosure, &operands);
}
Expression::FunctionCall(fc) => {
self.compile_expr(&fc.callee)?;
Expand All @@ -280,6 +284,12 @@ impl Compiler {
SymbolScope::Builtin => {
self.emit(OpGetBuiltin, &vec![symbol.index]);
}
SymbolScope::Free => {
self.emit(OpGetFree, &vec![symbol.index]);
}
SymbolScope::Function => {
self.emit(OpCurrentClosure, &vec![]);
}
}
}

Expand Down
95 changes: 48 additions & 47 deletions compiler/compiler_function_test.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#[cfg(test)]
mod tests {
use std::rc::Rc;
use crate::compiler_test::{run_compiler_test, CompilerTestCase};
use crate::op_code::Opcode::*;
use crate::op_code::{concat_instructions, make_instructions};
Expand All @@ -13,20 +14,20 @@ mod tests {
expected_constants: vec![
Object::Integer(5),
Object::Integer(10),
Object::CompiledFunction(object::CompiledFunction {
Object::CompiledFunction(Rc::from(object::CompiledFunction {
instructions: concat_instructions(&vec![
make_instructions(OpConst, &vec![0]),
make_instructions(OpConst, &vec![1]),
make_instructions(OpAdd, &vec![0]),
make_instructions(OpReturnValue, &vec![0]),
])
.data,
.data,
num_locals: 0,
num_parameters: 0,
}),
})),
],
expected_instructions: vec![
make_instructions(OpConst, &vec![2]),
make_instructions(OpClosure, &vec![2, 0]),
make_instructions(OpPop, &vec![0]),
],
},
Expand All @@ -35,20 +36,20 @@ mod tests {
expected_constants: vec![
Object::Integer(5),
Object::Integer(10),
Object::CompiledFunction(object::CompiledFunction {
Object::CompiledFunction(Rc::from(object::CompiledFunction {
instructions: concat_instructions(&vec![
make_instructions(OpConst, &vec![0]),
make_instructions(OpConst, &vec![1]),
make_instructions(OpAdd, &vec![0]),
make_instructions(OpReturnValue, &vec![0]),
])
.data,
.data,
num_locals: 0,
num_parameters: 0,
}),
})),
],
expected_instructions: vec![
make_instructions(OpConst, &vec![2]),
make_instructions(OpClosure, &vec![2, 0]),
make_instructions(OpPop, &vec![0]),
],
},
Expand All @@ -57,20 +58,20 @@ mod tests {
expected_constants: vec![
Object::Integer(1),
Object::Integer(2),
Object::CompiledFunction(object::CompiledFunction {
Object::CompiledFunction(Rc::from(object::CompiledFunction {
instructions: concat_instructions(&vec![
make_instructions(OpConst, &vec![0]),
make_instructions(OpPop, &vec![0]),
make_instructions(OpConst, &vec![1]),
make_instructions(OpReturnValue, &vec![0]),
])
.data,
.data,
num_locals: 0,
num_parameters: 0,
}),
})),
],
expected_instructions: vec![
make_instructions(OpConst, &vec![2]),
make_instructions(OpClosure, &vec![2, 0]),
make_instructions(OpPop, &vec![0]),
],
},
Expand All @@ -82,14 +83,14 @@ mod tests {
fn test_function_without_return_value() {
let tests = vec![CompilerTestCase {
input: "fn() { }",
expected_constants: vec![Object::CompiledFunction(object::CompiledFunction {
expected_constants: vec![Object::CompiledFunction(Rc::from(object::CompiledFunction {
instructions: concat_instructions(&vec![make_instructions(OpReturn, &vec![0])])
.data,
num_locals: 0,
num_parameters: 0,
})],
}))],
expected_instructions: vec![
make_instructions(OpConst, &vec![0]),
make_instructions(OpClosure, &vec![0, 0]),
make_instructions(OpPop, &vec![0]),
],
}];
Expand All @@ -103,18 +104,18 @@ mod tests {
input: "fn() { 24 }();",
expected_constants: vec![
Object::Integer(24),
Object::CompiledFunction(object::CompiledFunction {
Object::CompiledFunction(Rc::from(object::CompiledFunction {
instructions: concat_instructions(&vec![
make_instructions(OpConst, &vec![0]),
make_instructions(OpReturnValue, &vec![0]),
])
.data,
.data,
num_locals: 0,
num_parameters: 0,
}),
})),
],
expected_instructions: vec![
make_instructions(OpConst, &vec![1, 0]),
make_instructions(OpClosure, &vec![1, 0]),
make_instructions(OpCall, &vec![0]),
make_instructions(OpPop, &vec![0]),
],
Expand All @@ -123,18 +124,18 @@ mod tests {
input: "let noArg = fn() { 24; }; noArg();",
expected_constants: vec![
Object::Integer(24),
Object::CompiledFunction(object::CompiledFunction {
Object::CompiledFunction(Rc::from(object::CompiledFunction {
instructions: concat_instructions(&vec![
make_instructions(OpConst, &vec![0]),
make_instructions(OpReturnValue, &vec![0]),
])
.data,
.data,
num_locals: 0,
num_parameters: 0,
}),
})),
],
expected_instructions: vec![
make_instructions(OpConst, &vec![1]),
make_instructions(OpClosure, &vec![1, 0]),
make_instructions(OpSetGlobal, &vec![0]),
make_instructions(OpGetGlobal, &vec![0]),
make_instructions(OpCall, &vec![0]),
Expand All @@ -144,19 +145,19 @@ mod tests {
CompilerTestCase {
input: "let oneArg = fn(a) { a; }; oneArg(24);",
expected_constants: vec![
Object::CompiledFunction(object::CompiledFunction {
Object::CompiledFunction(Rc::from(object::CompiledFunction {
instructions: concat_instructions(&vec![
make_instructions(OpGetLocal, &vec![0]),
make_instructions(OpReturnValue, &vec![0]),
])
.data,
.data,
num_locals: 1,
num_parameters: 1,
}),
})),
Object::Integer(24),
],
expected_instructions: vec![
make_instructions(OpConst, &vec![0]),
make_instructions(OpClosure, &vec![0, 0]),
make_instructions(OpSetGlobal, &vec![0]),
make_instructions(OpGetGlobal, &vec![0]),
make_instructions(OpConst, &vec![1]),
Expand All @@ -167,7 +168,7 @@ mod tests {
CompilerTestCase {
input: "let manyArg = fn(a, b, c) { a; b; c; }; manyArg(24, 25, 26);",
expected_constants: vec![
Object::CompiledFunction(object::CompiledFunction {
Object::CompiledFunction(Rc::from(object::CompiledFunction {
instructions: concat_instructions(&vec![
make_instructions(OpGetLocal, &vec![0]),
make_instructions(OpPop, &vec![0]),
Expand All @@ -176,16 +177,16 @@ mod tests {
make_instructions(OpGetLocal, &vec![2]),
make_instructions(OpReturnValue, &vec![0]),
])
.data,
.data,
num_locals: 3,
num_parameters: 3,
}),
})),
Object::Integer(24),
Object::Integer(25),
Object::Integer(26),
],
expected_instructions: vec![
make_instructions(OpConst, &vec![0]),
make_instructions(OpClosure, &vec![0, 0]),
make_instructions(OpSetGlobal, &vec![0]),
make_instructions(OpGetGlobal, &vec![0]),
make_instructions(OpConst, &vec![1]),
Expand All @@ -207,41 +208,41 @@ mod tests {
input: "let num = 55; fn() { num; }",
expected_constants: vec![
Object::Integer(55),
Object::CompiledFunction(object::CompiledFunction {
Object::CompiledFunction(Rc::from(object::CompiledFunction {
instructions: concat_instructions(&vec![
make_instructions(OpGetGlobal, &vec![0]),
make_instructions(OpReturnValue, &vec![0]),
])
.data,
.data,
num_locals: 0,
num_parameters: 0,
}),
})),
],
expected_instructions: vec![
make_instructions(OpConst, &vec![0]),
make_instructions(OpSetGlobal, &vec![0]),
make_instructions(OpConst, &vec![1]),
make_instructions(OpClosure, &vec![1, 0]),
make_instructions(OpPop, &vec![0]),
],
},
CompilerTestCase {
input: "fn() { let num = 55; num; }",
expected_constants: vec![
Object::Integer(55),
Object::CompiledFunction(object::CompiledFunction {
Object::CompiledFunction(Rc::from(object::CompiledFunction {
instructions: concat_instructions(&vec![
make_instructions(OpConst, &vec![0]),
make_instructions(OpSetLocal, &vec![0]),
make_instructions(OpGetLocal, &vec![0]),
make_instructions(OpReturnValue, &vec![0]),
])
.data,
.data,
num_locals: 1,
num_parameters: 0,
}),
})),
],
expected_instructions: vec![
make_instructions(OpConst, &vec![1]),
make_instructions(OpClosure, &vec![1, 0]),
make_instructions(OpPop, &vec![0]),
],
},
Expand All @@ -250,7 +251,7 @@ mod tests {
expected_constants: vec![
Object::Integer(55),
Object::Integer(77),
Object::CompiledFunction(object::CompiledFunction {
Object::CompiledFunction(Rc::from(object::CompiledFunction {
instructions: concat_instructions(&vec![
make_instructions(OpConst, &vec![0]),
make_instructions(OpSetLocal, &vec![0]),
Expand All @@ -261,13 +262,13 @@ mod tests {
make_instructions(OpAdd, &vec![0]),
make_instructions(OpReturnValue, &vec![0]),
])
.data,
.data,
num_locals: 2,
num_parameters: 0,
}),
})),
],
expected_instructions: vec![
make_instructions(OpConst, &vec![2]),
make_instructions(OpClosure, &vec![2, 0]),
make_instructions(OpPop, &vec![0]),
],
},
Expand Down Expand Up @@ -295,19 +296,19 @@ mod tests {
},
CompilerTestCase {
input: "fn() { len([]) }",
expected_constants: vec![Object::CompiledFunction(object::CompiledFunction {
expected_constants: vec![Object::CompiledFunction(Rc::from(object::CompiledFunction {
instructions: concat_instructions(&vec![
make_instructions(OpGetBuiltin, &vec![0]),
make_instructions(OpArray, &vec![0]),
make_instructions(OpCall, &vec![1]),
make_instructions(OpReturnValue, &vec![0]),
])
.data,
.data,
num_locals: 0,
num_parameters: 0,
})],
}))],
expected_instructions: vec![
make_instructions(OpConst, &vec![0]),
make_instructions(OpClosure, &vec![0, 0]),
make_instructions(OpPop, &vec![0]),
],
},
Expand Down
10 changes: 5 additions & 5 deletions compiler/frame.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
use crate::op_code::Instructions;
use object::CompiledFunction;
use object::{Closure};

#[derive(Debug, Clone)]
pub struct Frame {
func: CompiledFunction,
pub cl: Closure,
pub ip: i32,
pub base_pointer: usize,
}

impl Frame {
pub fn new(func: CompiledFunction, base_pointer: usize) -> Self {
Frame { func, ip: -1, base_pointer }
pub fn new(func: Closure, base_pointer: usize) -> Self {
Frame { cl: func, ip: -1, base_pointer }
}

pub fn instructions(&self) -> Instructions {
return Instructions { data: self.func.instructions.clone() };
return Instructions { data: self.cl.func.instructions.clone() };
}
}
2 changes: 1 addition & 1 deletion compiler/symbol_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub struct Symbol {
pub struct SymbolTable {
pub outer: Option<Rc<SymbolTable>>,
symbols: HashMap<String, Rc<Symbol>>,
free_symbols: Vec<Rc<Symbol>>,
pub free_symbols: Vec<Rc<Symbol>>,
pub num_definitions: usize,
}

Expand Down
Loading

0 comments on commit 1e2b3af

Please sign in to comment.