Skip to content

Commit

Permalink
Feta: Start migration t full closure function handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Yag000 committed Jul 30, 2023
1 parent d0f2506 commit 78293c4
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 27 deletions.
15 changes: 13 additions & 2 deletions crates/compiler/src/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ impl Instructions {
}

match operand_count {
1 => format!("{} {}", operand, operands[0]),
2 => format!("{operand} {} {}", operands[0], operands[1]),
1 => format!("{operand} {}", operands[0]),
0 => format!("{operand}"),
_ => format!("Unhandeled operand_count for {operand}"),
}
Expand Down Expand Up @@ -115,6 +116,7 @@ pub enum Opcode {
ReturnValue,
Return,
GetBuiltin,
Closure,

// Stack
Pop,
Expand Down Expand Up @@ -152,6 +154,7 @@ impl Display for Opcode {
Opcode::ReturnValue => "OpReturnValue",
Opcode::Return => "OpReturn",
Opcode::GetBuiltin => "OpBuiltIn",
Opcode::Closure => "OpClosure",
Opcode::Pop => "OpPop",
};
write!(f, "{op}")
Expand All @@ -169,6 +172,7 @@ impl Opcode {
| Opcode::Array
| Opcode::HashMap => vec![2],
Opcode::Call | Opcode::SetLocal | Opcode::GetLocal | Opcode::GetBuiltin => vec![1],
Opcode::Closure => vec![2, 1],
_ => vec![],
}
}
Expand Down Expand Up @@ -259,6 +263,11 @@ mod tests {
vec![255],
vec![Opcode::GetLocal as u8, 255],
),
(
Opcode::Closure,
vec![65534, 255],
vec![Opcode::Closure as u8, 255, 254, 255],
),
];

for (op, operands, expected) in tests {
Expand All @@ -285,14 +294,15 @@ mod tests {
Opcode::GetLocal.make(vec![1]),
Opcode::Constant.make(vec![2]),
Opcode::Constant.make(vec![65535]),
Opcode::Closure.make(vec![65535, 255]),
];

let mut test_instruction = Instructions::default();
for instruction in instructions {
test_instruction.append(instruction);
}

let expected = "0000 OpAdd\n0001 OpGetLocal 1\n0003 OpConstant 2\n0006 OpConstant 65535\n";
let expected = "0000 OpAdd\n0001 OpGetLocal 1\n0003 OpConstant 2\n0006 OpConstant 65535\n0009 OpClosure 65535 255\n";

assert_eq!(test_instruction.to_string(), expected);
}
Expand All @@ -302,6 +312,7 @@ mod tests {
let tests = vec![
(Opcode::Constant, vec![65535], 2),
(Opcode::GetLocal, vec![255], 1),
(Opcode::Closure, vec![65535, 255], 3),
];

for (op, operands, bytes_read) in tests {
Expand Down
2 changes: 1 addition & 1 deletion crates/compiler/src/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ impl Compiler {
let operands = i32::from_usize(self.add_constant(compiled_function))
.ok_or("Invalid integer type")?;

self.emit(Opcode::Constant, vec![operands]);
self.emit(Opcode::Closure, vec![operands, 0]);
}
Expression::FunctionCall(call) => {
self.compile_expression(*call.function)?;
Expand Down
28 changes: 14 additions & 14 deletions crates/compiler/src/compiler_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ pub mod tests {
}),
],
expected_instructions: flatten_instructions(vec![
Opcode::Constant.make(vec![2]),
Opcode::Closure.make(vec![2, 0]),
Opcode::Pop.make(vec![]),
]),
},
Expand All @@ -597,7 +597,7 @@ pub mod tests {
}),
],
expected_instructions: flatten_instructions(vec![
Opcode::Constant.make(vec![2]),
Opcode::Closure.make(vec![2, 0]),
Opcode::Pop.make(vec![]),
]),
},
Expand All @@ -618,7 +618,7 @@ pub mod tests {
}),
],
expected_instructions: flatten_instructions(vec![
Opcode::Constant.make(vec![2]),
Opcode::Closure.make(vec![2, 0]),
Opcode::Pop.make(vec![]),
]),
},
Expand All @@ -636,7 +636,7 @@ pub mod tests {
}),
],
expected_instructions: flatten_instructions(vec![
Opcode::Constant.make(vec![1]),
Opcode::Closure.make(vec![1, 0]),
Opcode::Call.make(vec![0]),
Opcode::Pop.make(vec![]),
]),
Expand All @@ -655,7 +655,7 @@ pub mod tests {
}),
],
expected_instructions: flatten_instructions(vec![
Opcode::Constant.make(vec![1]),
Opcode::Closure.make(vec![1, 0]),
Opcode::SetGlobal.make(vec![0]),
Opcode::GetGlobal.make(vec![0]),
Opcode::Call.make(vec![0]),
Expand All @@ -673,7 +673,7 @@ pub mod tests {
Object::INTEGER(24),
],
expected_instructions: flatten_instructions(vec![
Opcode::Constant.make(vec![0]),
Opcode::Closure.make(vec![0, 0]),
Opcode::SetGlobal.make(vec![0]),
Opcode::GetGlobal.make(vec![0]),
Opcode::Constant.make(vec![1]),
Expand All @@ -694,7 +694,7 @@ pub mod tests {
Object::INTEGER(26),
],
expected_instructions: flatten_instructions(vec![
Opcode::Constant.make(vec![0]),
Opcode::Closure.make(vec![0, 0]),
Opcode::SetGlobal.make(vec![0]),
Opcode::GetGlobal.make(vec![0]),
Opcode::Constant.make(vec![1]),
Expand All @@ -718,7 +718,7 @@ pub mod tests {
Object::INTEGER(24),
],
expected_instructions: flatten_instructions(vec![
Opcode::Constant.make(vec![0]),
Opcode::Closure.make(vec![0, 0]),
Opcode::SetGlobal.make(vec![0]),
Opcode::GetGlobal.make(vec![0]),
Opcode::Constant.make(vec![1]),
Expand Down Expand Up @@ -746,7 +746,7 @@ pub mod tests {
Object::INTEGER(26),
],
expected_instructions: flatten_instructions(vec![
Opcode::Constant.make(vec![0]),
Opcode::Closure.make(vec![0, 0]),
Opcode::SetGlobal.make(vec![0]),
Opcode::GetGlobal.make(vec![0]),
Opcode::Constant.make(vec![1]),
Expand All @@ -771,7 +771,7 @@ pub mod tests {
num_parameters: 0,
})],
expected_instructions: flatten_instructions(vec![
Opcode::Constant.make(vec![0]),
Opcode::Closure.make(vec![0, 0]),
Opcode::Pop.make(vec![]),
]),
}];
Expand Down Expand Up @@ -801,7 +801,7 @@ pub mod tests {
expected_instructions: flatten_instructions(vec![
Opcode::Constant.make(vec![0]),
Opcode::SetGlobal.make(vec![0]),
Opcode::Constant.make(vec![1]),
Opcode::Closure.make(vec![1, 0]),
Opcode::Pop.make(vec![]),
]),
},
Expand All @@ -826,7 +826,7 @@ pub mod tests {
}),
],
expected_instructions: flatten_instructions(vec![
Opcode::Constant.make(vec![1]),
Opcode::Closure.make(vec![1, 0]),
Opcode::Pop.make(vec![]),
]),
},
Expand Down Expand Up @@ -857,7 +857,7 @@ pub mod tests {
}),
],
expected_instructions: flatten_instructions(vec![
Opcode::Constant.make(vec![2]),
Opcode::Closure.make(vec![2, 0]),
Opcode::Pop.make(vec![]),
]),
},
Expand Down Expand Up @@ -897,7 +897,7 @@ pub mod tests {
num_parameters: 0,
})],
expected_instructions: flatten_instructions(vec![
Opcode::Constant.make(vec![0]),
Opcode::Closure.make(vec![0, 0]),
Opcode::Pop.make(vec![]),
]),
},
Expand Down
36 changes: 36 additions & 0 deletions crates/object/src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ pub enum Object {
ERROR(String),
FUNCTION(Function),
COMPILEDFUNCTION(CompiledFunction),
CLOSURE(Closure),
BUILTIN(BuiltinFunction),
ARRAY(Vec<Object>),
HASHMAP(HashMap<Object, Object>),
Expand All @@ -38,6 +39,7 @@ impl Display for Object {
Object::RETURN(o) => write!(f, "{o}",),
Object::FUNCTION(o) => write!(f, "{o}"),
Object::COMPILEDFUNCTION(o) => write!(f, "{o}"),
Object::CLOSURE(o) => write!(f, "{o}"),
Object::BUILTIN(o) => write!(f, "{o}"),
Object::ERROR(s) => write!(f, "ERROR: {s}"),
Object::ARRAY(a) => Self::format_array(f, a),
Expand Down Expand Up @@ -74,6 +76,7 @@ impl Object {
Object::ERROR(_) => String::from("ERROR"),
Object::FUNCTION(_) => String::from("FUNCTION"),
Object::COMPILEDFUNCTION(_) => String::from("COMPILEDFUNCTION"),
Object::CLOSURE(_) => String::from("CLOSURE"),
Object::BUILTIN(_) => String::from("BUILTIN"),
Object::ARRAY(_) => String::from("ARRAY"),
Object::HASHMAP(_) => String::from("HASHMAP"),
Expand Down Expand Up @@ -129,6 +132,39 @@ impl Display for CompiledFunction {
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct Closure {
pub function: CompiledFunction,
pub free: Vec<Object>,
}

impl Display for Closure {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"Closure(function={}, free={:?}",
self.function, self.free
)
}
}

impl Closure {
pub fn new(function: CompiledFunction) -> Self {
Self {
function,
free: Vec::new(),
}
}

pub fn add_free_variable(&mut self, variable: Object) {
self.free.push(variable);
}

pub fn extend_free_varaibles(&mut self, variables: Vec<Object>) {
self.free.extend(variables);
}
}

#[cfg(test)]
mod tests {

Expand Down
39 changes: 29 additions & 10 deletions crates/vm/src/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use compiler::{
use num_traits::FromPrimitive;
use object::{
builtins::BuiltinFunction,
object::{CompiledFunction, Object, FALSE, NULL, TRUE},
object::{Closure, CompiledFunction, Object, FALSE, NULL, TRUE},
};
use std::{collections::HashMap, rc::Rc};

Expand All @@ -15,13 +15,13 @@ pub const GLOBALS_SIZE: usize = 65536;

#[derive(Debug)]
struct Frame {
function: CompiledFunction,
function: Closure,
ip: i32,
base_pointer: usize,
}

impl Frame {
fn new(function: CompiledFunction, base_pointer: usize) -> Self {
fn new(function: Closure, base_pointer: usize) -> Self {
Self {
function,
ip: -1,
Expand All @@ -30,7 +30,7 @@ impl Frame {
}

fn get_instructions(&self) -> &Vec<u8> {
&self.function.instructions
&self.function.function.instructions
}
}

Expand All @@ -53,7 +53,8 @@ impl VM {
num_locals: 0,
num_parameters: 0,
};
let main_frame = Frame::new(main_function, 0);
let main_closure = Closure::new(main_function);
let main_frame = Frame::new(main_closure, 0);
let mut frames = Vec::with_capacity(MAX_FRAMES);
frames.push(main_frame);
Self {
Expand Down Expand Up @@ -221,6 +222,14 @@ impl VM {

self.push(Rc::new(NULL))?;
}
Opcode::Closure => {
let const_index = read_u16(&ins[ip + 1..]) as usize;
let _free = ins[ip + 3] as usize;

self.current_frame().ip += 3;

self.push_closure(const_index)?;
}
}
}
Ok(())
Expand Down Expand Up @@ -425,21 +434,21 @@ impl VM {
.ok_or("Stack underflow")?;

match callee.as_ref().clone() {
Object::COMPILEDFUNCTION(func) => self.call_function(func, num_args),
Object::CLOSURE(func) => self.call_closure(func, num_args),
Object::BUILTIN(func) => self.call_builtin_function(&func, num_args),
_ => Err("Calling non-function".to_string()),
}
}

fn call_function(&mut self, func: CompiledFunction, num_args: usize) -> Result<(), String> {
if num_args != func.num_parameters {
fn call_closure(&mut self, func: Closure, num_args: usize) -> Result<(), String> {
if num_args != func.function.num_parameters {
return Err(format!(
"Wrong number of arguments: want={}, got={}",
func.num_parameters, num_args
func.function.num_parameters, num_args
));
}

let num_locals = func.num_locals;
let num_locals = func.function.num_locals;
let frame = Frame::new(func, self.sp - num_args);
self.sp = frame.base_pointer + num_locals;
self.push_frame(frame);
Expand All @@ -464,6 +473,16 @@ impl VM {
Ok(())
}

fn push_closure(&mut self, const_index: usize) -> Result<(), String> {
match (*self.constants[const_index]).clone() {
Object::COMPILEDFUNCTION(func) => {
let closure = Closure::new(func);
self.push(Rc::new(Object::CLOSURE(closure)))
}
x => Err(format!["Function expected, got {}", x.get_type()]),
}
}

fn native_boolean_to_boolean_object(&self, input: bool) -> Rc<Object> {
if input {
Rc::new(TRUE)
Expand Down

0 comments on commit 78293c4

Please sign in to comment.