Skip to content

Commit

Permalink
feat: symbol table
Browse files Browse the repository at this point in the history
  • Loading branch information
ZakFarmer committed Oct 24, 2023
1 parent 6edd912 commit ec9c1a7
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 0 deletions.
7 changes: 7 additions & 0 deletions compiler/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use anyhow::Error;
use opcode::Opcode;
use parser::ast::{BooleanLiteral, Expression, IntegerLiteral, Literal, Node, Statement, BlockStatement};

pub mod symbol_table;

#[derive(Clone, PartialEq)]
pub struct Bytecode {
pub instructions: opcode::Instructions,
Expand Down Expand Up @@ -136,6 +138,11 @@ impl Compiler {

fn compile_statement(&mut self, s: &Statement) -> Result<(), Error> {
match s {
Statement::Assign(a) => {
self.compile_expression(&a.value)?;

return Ok(());
}
Statement::Return(r) => {
self.compile_expression(&r.return_value)?;

Expand Down
55 changes: 55 additions & 0 deletions compiler/src/symbol_table.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use std::{collections::HashMap, rc::Rc};

#[derive(Clone, Debug)]
pub enum SymbolScope {
Global,
Local,
Builtin,
Free,
Function,
}

#[derive(Clone, Debug)]
pub struct Symbol {
pub name: String,
pub scope: SymbolScope,
pub index: usize,
}

#[derive(Clone, Debug)]
pub struct SymbolTable {
pub store: HashMap<String, Rc<Symbol>>,
pub num_definitions: usize,
}

impl SymbolTable {
pub fn define(&mut self, name: &str) -> Rc<Symbol> {
let symbol = Rc::new(
Symbol {
name: name.to_string(),
scope: SymbolScope::Global,
index: self.num_definitions,
}
);

self.store.insert(name.to_string(), Rc::clone(&symbol));

self.num_definitions += 1;

symbol
}

pub fn new() -> Self {
Self {
store: HashMap::new(),
num_definitions: 0,
}
}

pub fn resolve(&self, name: &str) -> Option<Rc<Symbol>> {
match self.store.get(name) {
Some(symbol) => Some(Rc::clone(symbol)),
None => None,
}
}
}
59 changes: 59 additions & 0 deletions compiler/tests/symbol_table_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use std::collections::HashMap;

use anyhow::Error;
use compiler::symbol_table::{Symbol, SymbolScope, SymbolTable};

#[test]
fn test_define() -> Result<(), Error> {
let expected = HashMap::from([
("a".to_string(), Symbol {name: "a".to_string(), scope: SymbolScope::Global, index: 0}),
("b".to_string(), Symbol {name: "b".to_string(), scope: SymbolScope::Global, index: 1}),
("c".to_string(), Symbol {name: "c".to_string(), scope: SymbolScope::Global, index: 2}),
("d".to_string(), Symbol {name: "d".to_string(), scope: SymbolScope::Global, index: 3}),
]);

let mut global = SymbolTable::new();

let a = global.define("a");

if a.name != "a" {
panic!("a.name not 'a'. got={}", a.name);
}

let b = global.define("b");

if b.name != "b" {
panic!("b.name not 'b'. got={}", b.name);
}

Ok(())
}

#[test]
fn test_resolve_global() -> Result<(), Error> {
let mut global = SymbolTable::new();

global.define("a");
global.define("b");

let expected = vec![
("a".to_string(), Symbol {name: "a".to_string(), scope: SymbolScope::Global, index: 0}),
("b".to_string(), Symbol {name: "b".to_string(), scope: SymbolScope::Global, index: 1}),
];

for (name, expected_symbol) in expected {
let symbol = global.resolve(&name);

if symbol.is_none() {
panic!("symbol for {} is None", name);
}

let symbol = symbol.unwrap();

if symbol.name != expected_symbol.name {
panic!("symbol.name not {}. got={}", expected_symbol.name, symbol.name);
}
}

Ok(())
}
22 changes: 22 additions & 0 deletions vm/tests/vm_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,3 +227,25 @@ fn test_integer_arithmetic() -> Result<(), Error> {

Ok(())
}

#[test]
fn test_global_dollar_statements() -> Result<(), Error> {
let tests = vec![
VmTestCase {
input: "$one = 1; $one".to_string(),
expected: "1".to_string(),
},
VmTestCase {
input: "$one = 1; $two = 2; $one + $two".to_string(),
expected: "3".to_string(),
},
VmTestCase {
input: "$one = 1; $two = $one + $one; $one + $two".to_string(),
expected: "3".to_string(),
},
];

run_vm_tests(tests)?;

Ok(())
}

0 comments on commit ec9c1a7

Please sign in to comment.