Skip to content

Commit

Permalink
feat: strings in compiler and VM
Browse files Browse the repository at this point in the history
  • Loading branch information
ZakFarmer committed Oct 25, 2023
1 parent 770a666 commit 1b05599
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 1 deletion.
11 changes: 10 additions & 1 deletion compiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::rc::Rc;
use anyhow::Error;
use opcode::Opcode;
use parser::ast::{
BlockStatement, BooleanLiteral, Expression, IntegerLiteral, Literal, Node, Statement,
BlockStatement, BooleanLiteral, Expression, IntegerLiteral, Literal, Node, Statement, StringLiteral,
};
use symbol_table::SymbolTable;

Expand Down Expand Up @@ -303,6 +303,15 @@ impl Compiler {

Ok(())
}
Literal::String(StringLiteral { value, .. }) => {
let string = object::Object::String(value.clone());

let constant = self.add_constant(string);

self.emit(opcode::Opcode::OpConst, vec![constant]);

Ok(())
}
_ => {
return Err(Error::msg("compile_expression: unimplemented"));
}
Expand Down
31 changes: 31 additions & 0 deletions compiler/tests/compiler_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,37 @@ fn test_integer_arithmetic() -> Result<(), Error> {
Ok(())
}

#[test]
fn test_string_expressions() -> Result<(), Error> {
let tests = vec![
CompilerTestCase {
input: "\"hello\"".to_string(),
expected_constants: vec![Object::String("hello".to_string())],
expected_instructions: vec![
opcode::make(opcode::Opcode::OpConst, &vec![0]),
opcode::make(opcode::Opcode::OpPop, &vec![]),
],
},
CompilerTestCase {
input: "\"hello\" + \"world\"".to_string(),
expected_constants: vec![
Object::String("hello".to_string()),
Object::String("world".to_string()),
],
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::OpPop, &vec![0]),
]
}
];

run_compiler_tests(tests)?;

Ok(())
}

fn run_compiler_tests(tests: Vec<CompilerTestCase>) -> Result<(), Error> {
for test in tests {
let mut parser = parser::Parser::new(Lexer::new(&test.input));
Expand Down
1 change: 1 addition & 0 deletions vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ impl Vm {

let result = match (&*left, &*right) {
(Object::Integer(l), Object::Integer(r)) => Object::Integer(l + r),
(Object::String(l), Object::String(r)) => Object::String(format!("{}{}", l, r)),
_ => {
return Err(Error::msg(format!(
"unsupported types for addition: {} + {}",
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 @@ -249,3 +249,25 @@ fn test_global_dollar_statements() -> Result<(), Error> {

Ok(())
}

#[test]
fn test_string_expressions() -> Result<(), Error> {
let tests = vec![
VmTestCase {
input: r#""hello""#.to_string(),
expected: "hello".to_string(),
},
VmTestCase {
input: r#""hello" + "world""#.to_string(),
expected: "helloworld".to_string(),
},
VmTestCase {
input: r#""hello" + "world" + "!""#.to_string(),
expected: "helloworld!".to_string(),
},
];

run_vm_tests(tests)?;

Ok(())
}

0 comments on commit 1b05599

Please sign in to comment.