Skip to content

Commit 27078a2

Browse files
added opcode, compiler, vm ,repl support for let statements with global assignments
1 parent d7e4e8f commit 27078a2

File tree

6 files changed

+198
-16
lines changed

6 files changed

+198
-16
lines changed

src/compiler/compiler.rs

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
use crate::{
2-
interpreter::evaluate::object_system::*,
3-
virtual_machine::bytecode::{
4-
OpCode,
5-
make_bytecode,
6-
get_raw_instruction,
7-
Instruction,
8-
opcode_lookup,
2+
interpreter::{evaluate::object_system::*},
3+
virtual_machine::{
4+
bytecode::{
5+
OpCode,
6+
make_bytecode,
7+
get_raw_instruction,
8+
Instruction,
9+
opcode_lookup,
10+
},
11+
symbol_table::SymbolTable,
912
},
1013
interpreter::ast,
1114
};
@@ -28,6 +31,7 @@ pub struct Compiler {
2831
pub raw_assembly: RawAssembly,
2932
pub last_instruction: EmittedInstruction,
3033
pub previous_instruction: EmittedInstruction,
34+
pub symbol_table: SymbolTable,
3135
}
3236

3337
impl Compiler {
@@ -42,6 +46,7 @@ impl Compiler {
4246
opcode: None,
4347
position: 0,
4448
},
49+
symbol_table: SymbolTable::new(),
4550
}
4651
}
4752

@@ -89,6 +94,12 @@ impl Compiler {
8994
Ok(_) => (),
9095
Err(e) => return Err(e)
9196
};
97+
98+
let symbol = match self.symbol_table.define(let_statement.name.value.clone()) {
99+
Ok(symbol) => symbol,
100+
Err(e) => return Err(e),
101+
};
102+
let _ = self.emit(OpCode::OpSetGlobal, vec![symbol.index as usize]);
92103
}
93104
_ => return Err(format!("Statement type not supported: {:?}", statement)),
94105
}
@@ -98,6 +109,17 @@ impl Compiler {
98109

99110
fn compile_expression(&mut self, expression: &ast::Expression) -> Result<(), String> {
100111
match expression {
112+
ast::Expression::Identifier(identifier) => {
113+
let symbol = match self.symbol_table.resolve(identifier.value.clone()) {
114+
Ok(symbol) => symbol,
115+
Err(e) => return Err(e),
116+
};
117+
118+
let _ = match self.emit(OpCode::OpGetGlobal, vec![symbol.index as usize]) {
119+
Ok(_) => (),
120+
Err(e) => return Err(e),
121+
};
122+
}
101123
ast::Expression::IfExpression(if_expr) => {
102124
let _ = match self.compile_expression(&if_expr.condition) {
103125
Ok(_) => (),

src/lib.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use interpreter::{
1313
lexer,
1414
};
1515

16-
use compiler::compiler::Compiler;
16+
use compiler::compiler::{Compiler};
1717
use virtual_machine::virtual_machine::VirtualMachine;
1818

1919
use std::fs;
@@ -45,7 +45,9 @@ fn run_code(input: &str, env: Option<&mut environment::Environment>) -> object_s
4545
result
4646
}
4747

48-
pub fn compile_and_run(input: &str) -> object_system::Object {
48+
pub fn compile_and_run(
49+
input: &str,
50+
) -> object_system::Object {
4951
let lexer = lexer::Lexer::new(input.to_string());
5052
let mut parser = parser::Parser::new(lexer);
5153

@@ -109,21 +111,23 @@ pub fn compile_and_run(input: &str) -> object_system::Object {
109111
}
110112

111113
pub fn start_compiler_repl() {
114+
let mut input = String::new();
112115
loop {
113116
// read input
114117
println!(">>");
115-
let mut input = String::new();
116-
match std::io::stdin().read_line(&mut input) {
118+
let mut command = String::new();
119+
match std::io::stdin().read_line(&mut command) {
117120
Ok(_) => {},
118-
Err(e) => println!("Error reading input: {}", e),
121+
Err(e) => println!("Error reading command: {}", e),
119122
}
120123

121-
// if input is "quit", break
122-
if input.trim() == "quit" {
124+
// if command is "quit", break
125+
if command.trim() == "quit" {
123126
break;
124127
}
125128

126-
// run code
129+
input = input + &command;
130+
127131
let result = compile_and_run(&input);
128132

129133
// print result

src/virtual_machine.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
pub mod bytecode;
22
pub mod virtual_machine;
3+
pub mod symbol_table;

src/virtual_machine/bytecode.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ pub fn opcode_lookup(opcode: usize) -> Result<OpCode, String> {
193193
14 => Ok(OpCode::OpJumpNotTruthy),
194194
15 => Ok(OpCode::OpJump),
195195
16 => Ok(OpCode::OpNull),
196+
17 => Ok(OpCode::OpSetGlobal),
197+
18 => Ok(OpCode::OpGetGlobal),
196198
_ => Err(format!("Opcode {} not found", opcode)),
197199
}
198200
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
use lazy_static::lazy_static;
2+
use std::collections::HashMap;
3+
4+
pub type SymbolScope = String;
5+
6+
lazy_static! {
7+
static ref GLOBAL_SCOPE: SymbolScope = String::from("GLOBAL");
8+
}
9+
10+
#[derive(Debug, Clone, PartialEq)]
11+
pub struct Symbol {
12+
pub name: String,
13+
pub scope: SymbolScope,
14+
pub index: i32
15+
}
16+
17+
#[derive(Debug, Clone)]
18+
pub struct SymbolTable {
19+
pub store: HashMap<String, Symbol>,
20+
pub number_of_definitions: i32
21+
}
22+
23+
impl SymbolTable {
24+
pub fn new() -> Self {
25+
SymbolTable {
26+
store: HashMap::new(),
27+
number_of_definitions: 0
28+
}
29+
}
30+
31+
pub fn define(&mut self, symbol_name: String) -> Result<Symbol, String> {
32+
let symbol = Symbol {
33+
name: symbol_name.clone(),
34+
scope: GLOBAL_SCOPE.clone(),
35+
index: self.number_of_definitions
36+
};
37+
38+
self.store.insert(symbol_name, symbol.clone());
39+
self.number_of_definitions += 1;
40+
41+
return Ok(symbol)
42+
}
43+
44+
pub fn resolve(&mut self, symbol_name: String) -> Result<Symbol, String> {
45+
match self.store.get(&symbol_name) {
46+
Some(symbol) => Ok(symbol.clone()),
47+
None => Err(format!("Symbol {} not found", symbol_name))
48+
}
49+
}
50+
}
51+
52+
mod test {
53+
use super::*;
54+
55+
#[test]
56+
fn test_define_symbols() {
57+
let expected = HashMap::from(
58+
[
59+
("a" , Symbol{name: "a".to_string(), scope: GLOBAL_SCOPE.clone(), index: 0}),
60+
("b" , Symbol{name: "b".to_string(), scope: GLOBAL_SCOPE.clone(), index: 1}),
61+
]
62+
);
63+
64+
let mut global = SymbolTable::new();
65+
66+
let a = global.define("a".to_string()).unwrap();
67+
68+
assert!(a == expected["a"]);
69+
70+
let b = global.define("b".to_string()).unwrap();
71+
72+
assert!(b == expected["b"]);
73+
}
74+
75+
#[test]
76+
fn test_resolve_symbol() {
77+
let mut global = SymbolTable::new();
78+
global.define("a".to_string()).unwrap();
79+
global.define("b".to_string()).unwrap();
80+
81+
let expected = vec![
82+
Symbol{name: "a".to_string(), scope: GLOBAL_SCOPE.clone(), index: 0},
83+
Symbol{name: "b".to_string(), scope: GLOBAL_SCOPE.clone(), index: 1},
84+
];
85+
86+
for sym in expected {
87+
let result = global.resolve(sym.name.clone()).unwrap();
88+
assert!(result == sym);
89+
}
90+
}
91+
}

src/virtual_machine/virtual_machine.rs

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use crate::virtual_machine::bytecode::{
77
};
88

99
pub const STACK_SIZE: usize = 2048;
10+
pub const GLOBALS_SIZE: usize = 65536;
1011

1112
pub struct VmStack {
1213
pub stack: Vec<Object>,
@@ -59,15 +60,31 @@ impl VmStack {
5960
}
6061
}
6162

63+
pub struct VmGlobals {
64+
pub store: Vec<Object>,
65+
pub number_of_definitions: usize,
66+
}
67+
68+
impl VmGlobals {
69+
pub fn new() -> Self {
70+
VmGlobals {
71+
store: vec![object_system::Object::Null; GLOBALS_SIZE],
72+
number_of_definitions: 0,
73+
}
74+
}
75+
}
76+
6277
pub struct VirtualMachine {
6378
pub stack: VmStack,
79+
pub globals: VmGlobals,
6480
pub assembly: RawAssembly,
6581
}
6682

6783
impl VirtualMachine {
6884
pub fn new(assembly: RawAssembly) -> Self {
6985
VirtualMachine {
7086
stack: VmStack::new(),
87+
globals: VmGlobals::new(),
7188
assembly,
7289
}
7390
}
@@ -89,6 +106,27 @@ impl VirtualMachine {
89106
instruction_pointer += 2;
90107

91108
match opcode {
109+
OpCode::OpSetGlobal => {
110+
let global_index = self.assembly.instructions[instruction_pointer..instruction_pointer+4].parse::<usize>().unwrap();
111+
instruction_pointer += 4;
112+
113+
self.globals.store[global_index] = match self.stack.stack_pop() {
114+
Ok(object) => object,
115+
Err(e) => return Err(e),
116+
};
117+
self.globals.number_of_definitions += 1;
118+
}
119+
OpCode::OpGetGlobal => {
120+
let global_index = self.assembly.instructions[instruction_pointer..instruction_pointer+4].parse::<usize>().unwrap();
121+
instruction_pointer += 4;
122+
123+
match self.stack.push_constant(
124+
self.globals.store[global_index].clone()
125+
) {
126+
Ok(_) => (),
127+
Err(e) => return Err(e),
128+
}
129+
}
92130
OpCode::OpConstant => {
93131
let const_index = self.assembly.instructions[instruction_pointer..instruction_pointer+4].parse::<usize>().unwrap();
94132
instruction_pointer += 4;
@@ -182,7 +220,6 @@ impl VirtualMachine {
182220
Err(e) => return Err(e),
183221
}
184222
},
185-
_ => return Err(format!("Opcode not supported: {:?}", opcode)),
186223
}
187224
}
188225

@@ -842,4 +879,29 @@ mod tests {
842879
];
843880
run_vm_tests(inputs);
844881
}
882+
883+
#[test]
884+
fn test_global_let_statements() {
885+
let inputs = vec![
886+
VirtualMachineTest {
887+
input: String::from("let one = 1; one;"),
888+
expected_stack: vec![
889+
Object::Integer(Integer { value: 1 }),
890+
],
891+
},
892+
VirtualMachineTest {
893+
input: String::from("let one = 1; let two = 2; one + two;"),
894+
expected_stack: vec![
895+
Object::Integer(Integer { value: 3 }),
896+
],
897+
},
898+
VirtualMachineTest {
899+
input: String::from("let one = 1; let two = one + one; one + two;"),
900+
expected_stack: vec![
901+
Object::Integer(Integer { value: 3 }),
902+
],
903+
}
904+
];
905+
run_vm_tests(inputs);
906+
}
845907
}

0 commit comments

Comments
 (0)