Skip to content

Commit 89ef20f

Browse files
committed
Feat: Implement Environment struct for variable management and update runtime to use it
1 parent 3d086e9 commit 89ef20f

4 files changed

Lines changed: 81 additions & 49 deletions

File tree

example/test.rts

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,9 @@
1-
let x = (2 + 3) * 4;
2-
print "x = " + x;
1+
let x = 10;
32

4-
function max(a, b) {
5-
if (a > b) {
6-
return a;
7-
} else {
8-
return b;
9-
}
3+
function f() {
4+
x = 20;
105
}
116

12-
print "max is " + max(x, 15);
7+
f();
138

14-
function factorial(n) {
15-
if (n < 2) { return 1; }
16-
return n * factorial(n - 1);
17-
}
18-
print "5! = " + factorial(5);
19-
20-
for (let i = 0; i < 5; i++) {
21-
if (i == 2) { continue; }
22-
if (i == 4) { break; }
23-
print i;
24-
}
25-
26-
let name = "Rusty";
27-
if (name && x > 10) {
28-
print name + " works!";
29-
}
9+
print x;

src/environment/mod.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
use std::{cell::RefCell, collections::HashMap, rc::Rc};
2+
3+
use crate::ast::Value;
4+
5+
#[derive(Debug, Clone)]
6+
pub struct Environment {
7+
pub variables: HashMap<String, Value>,
8+
pub parent: Option<Rc<RefCell<Environment>>>,
9+
}
10+
11+
impl Environment {
12+
pub fn new(
13+
parent: Option<Rc<RefCell<Environment>>>
14+
) -> Self {
15+
Environment {
16+
variables: HashMap::new(),
17+
parent,
18+
}
19+
}
20+
21+
pub fn get(&self, name: &str) -> Option<Value> {
22+
if let Some(value) = self.variables.get(name) {
23+
Some(value.clone())
24+
} else if let Some(parent) = self.parent.as_ref() {
25+
parent.borrow().get(name)
26+
} else {
27+
None
28+
}
29+
}
30+
31+
pub fn assign(
32+
&mut self,
33+
name: &str,
34+
value: Value
35+
) -> bool {
36+
if self.variables.contains_key(name) {
37+
self.variables.insert(name.to_string(), value);
38+
true
39+
} else if let Some(parent) = self.parent.as_mut() {
40+
parent.borrow_mut().assign(name, value)
41+
}else{
42+
false
43+
}
44+
}
45+
}

src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod compiler;
66
mod lexer;
77
mod parser;
88
mod vm;
9+
mod environment;
910
use compiler::compile_program;
1011
use lexer::tokenize;
1112
use parser::Parser;

src/vm/mod.rs

Lines changed: 30 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ use std::{cell::RefCell, collections::HashMap, fmt, rc::Rc};
33
use crate::{
44
ast::{BinaryOperation, Value},
55
compiler::{FunctionBytecode, Instruction, Program},
6+
environment::{Environment},
67
};
78

9+
810
impl fmt::Display for Value {
911
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1012
match self {
@@ -34,7 +36,7 @@ impl fmt::Display for Value {
3436

3537
#[derive(Debug, Clone)]
3638
pub struct Frame {
37-
variables: HashMap<String, Value>,
39+
env: Rc<RefCell<Environment>>,
3840
instructions: Vec<Instruction>,
3941
ip: usize,
4042
}
@@ -55,40 +57,35 @@ impl Runtime {
5557
}
5658

5759
fn load_variable(&mut self, var: &str) {
58-
if let Some(value) = self
59-
.frames
60-
.iter()
61-
.rev()
62-
.find_map(|frame| frame.variables.get(var))
60+
let current_frame =
61+
self.frames.last().unwrap();
62+
63+
if let Some(value) =
64+
current_frame
65+
.env
66+
.borrow()
67+
.get(var)
6368
{
64-
self.stack.push((*value).clone());
69+
self.stack.push(value.clone());
6570
} else {
6671
panic!("{} is not defined", var);
6772
}
6873
}
6974

7075
fn store_variable(&mut self, var: String) {
7176
if let Some(value) = self.stack.pop() {
72-
self.frames.last_mut().unwrap().variables.insert(var, value);
77+
self.frames.last_mut().unwrap().env.borrow_mut().variables.insert(var, value);
7378
} else {
7479
panic!("No defined value to store in {}", var);
7580
}
7681
}
7782

7883
fn assign_variable(&mut self, var: String) {
79-
if let Some(value) = self
80-
.frames
81-
.iter_mut()
82-
.rev()
83-
.find_map(|frame| frame.variables.get_mut(&var))
84-
{
85-
if let Some(val) = self.stack.pop() {
86-
*value = val;
87-
} else {
88-
panic!("No defined value to store in {}", var);
89-
}
84+
let current_frame = self.frames.last().unwrap();
85+
if let Some(val) = self.stack.pop() {
86+
current_frame.env.borrow_mut().assign(&var, val);
9087
} else {
91-
panic!("{} is not defined", var);
88+
panic!("No defined value to store in {}", var);
9289
}
9390
}
9491

@@ -214,8 +211,12 @@ impl Runtime {
214211

215212
pub fn execute(program: Program, runtime: &mut Runtime) {
216213
runtime.functions = program.functions;
214+
let global_env =
215+
Rc::new(RefCell::new(
216+
Environment::new(None)
217+
));
217218
runtime.frames.push(Frame {
218-
variables: HashMap::new(),
219+
env: global_env,
219220
instructions: program.main,
220221
ip: 0,
221222
});
@@ -315,7 +316,7 @@ pub fn execute(program: Program, runtime: &mut Runtime) {
315316
}
316317
Instruction::CallFunction(name, arg_count) => {
317318
let func = runtime.functions.get(&name).expect("undefined function");
318-
let mut locals = HashMap::new();
319+
// let mut locals = HashMap::new();
319320
// Pop args in reverse (last arg was pushed last)
320321
if arg_count != func.params.len() {
321322
panic!(
@@ -324,16 +325,21 @@ pub fn execute(program: Program, runtime: &mut Runtime) {
324325
arg_count
325326
);
326327
}
328+
let parnt_env = runtime.frames.last().unwrap().env.clone();
329+
let local_env =
330+
Rc::new(RefCell::new(
331+
Environment::new(Some(parnt_env))
332+
));
327333
for param in func.params.iter().rev() {
328-
locals.insert(param.clone(), runtime.stack.pop().unwrap());
334+
local_env.borrow_mut().variables.insert(param.clone(), runtime.stack.pop().unwrap());
329335
}
330336
// Save caller's position (move past the CallFunction instruction)
331337
runtime.frames.last_mut().unwrap().ip += 1;
332338
// Push new frame
333339
runtime.frames.push(Frame {
334340
instructions: func.instructions.clone(),
335341
ip: 0,
336-
variables: locals,
342+
env: local_env
337343
});
338344
continue; // don't increment ip again
339345
}

0 commit comments

Comments
 (0)