Skip to content

Commit

Permalink
feat: array compilation and execution
Browse files Browse the repository at this point in the history
  • Loading branch information
ZakFarmer committed Oct 26, 2023
1 parent b4c5e4c commit 28a8bdc
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 0 deletions.
9 changes: 9 additions & 0 deletions compiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,15 @@ impl Compiler {
Ok(())
}
Expression::Literal(literal_expression) => match literal_expression {
Literal::Array(array) => {
for element in array.elements.iter() {
self.compile_expression(element)?;
}

self.emit(opcode::Opcode::OpArray, vec![array.elements.len()]);

Ok(())
}
Literal::Boolean(boolean) => match boolean {
BooleanLiteral { value: true, .. } => {
self.emit(opcode::Opcode::OpTrue, vec![]);
Expand Down
57 changes: 57 additions & 0 deletions compiler/tests/compiler_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,63 @@ struct CompilerTestCase {
expected_instructions: Vec<opcode::Instructions>,
}

#[test]
fn test_array_expressions() -> Result<(), Error> {
let tests = vec![
CompilerTestCase {
input: "[]".to_string(),
expected_constants: vec![],
expected_instructions: vec![
opcode::make(opcode::Opcode::OpArray, &vec![0]),
opcode::make(opcode::Opcode::OpPop, &vec![]),
],
},
CompilerTestCase {
input: "[1, 2, 3]".to_string(),
expected_constants: vec![
Object::Integer(1),
Object::Integer(2),
Object::Integer(3),
],
expected_instructions: vec![
opcode::make(opcode::Opcode::OpConst, &vec![0]),
opcode::make(opcode::Opcode::OpConst, &vec![1]),
opcode::make(opcode::Opcode::OpConst, &vec![2]),
opcode::make(opcode::Opcode::OpArray, &vec![3]),
opcode::make(opcode::Opcode::OpPop, &vec![]),
],
},
CompilerTestCase {
input: "[1 + 2, 3 - 4, 5 * 6]".to_string(),
expected_constants: vec![
Object::Integer(1),
Object::Integer(2),
Object::Integer(3),
Object::Integer(4),
Object::Integer(5),
Object::Integer(6),
],
expected_instructions: vec![
opcode::make(opcode::Opcode::OpConst, &vec![0]),
opcode::make(opcode::Opcode::OpConst, &vec![1]),
opcode::make(opcode::Opcode::OpAdd, &vec![1]),
opcode::make(opcode::Opcode::OpConst, &vec![2]),
opcode::make(opcode::Opcode::OpConst, &vec![3]),
opcode::make(opcode::Opcode::OpSub, &vec![1]),
opcode::make(opcode::Opcode::OpConst, &vec![4]),
opcode::make(opcode::Opcode::OpConst, &vec![5]),
opcode::make(opcode::Opcode::OpMul, &vec![1]),
opcode::make(opcode::Opcode::OpArray, &vec![3]),
opcode::make(opcode::Opcode::OpPop, &vec![]),
],
},
];

run_compiler_tests(tests)?;

Ok(())
}

#[test]
fn test_boolean_expressions() -> Result<(), Error> {
let tests = vec![
Expand Down
16 changes: 16 additions & 0 deletions vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,22 @@ impl Vm {

self.push(Rc::new(result));
}
Opcode::OpArray => {
let num_elements =
BigEndian::read_u16(&self.instructions.0[ip..ip + 2]) as usize;

ip += 2;

let mut elements = Vec::with_capacity(num_elements);

for _ in 0..num_elements {
elements.push(self.pop());
}

elements.reverse();

self.push(Rc::new(Object::Array(elements)));
}
_ => {
return Err(Error::msg(format!("unknown opcode: {}", op)));
}
Expand Down
22 changes: 22 additions & 0 deletions vm/tests/vm_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,28 @@ fn run_vm_tests(tests: Vec<VmTestCase>) -> Result<(), Error> {
Ok(())
}

#[test]
fn test_array_expressions() -> Result<(), Error> {
let tests = vec![
VmTestCase {
input: "[]".to_string(),
expected: "[]".to_string(),
},
VmTestCase {
input: "[1, 2, 3]".to_string(),
expected: "[1, 2, 3]".to_string(),
},
VmTestCase {
input: "[1 + 2, 3 * 4, 5 + 6]".to_string(),
expected: "[3, 12, 11]".to_string(),
},
];

run_vm_tests(tests)?;

Ok(())
}

#[test]
fn test_boolean_expressions() -> Result<(), Error> {
let tests = vec![
Expand Down

0 comments on commit 28a8bdc

Please sign in to comment.