Implement vec based scopes

- Replaced vartable hashmap with vec
- Use linear search in reverse to find the variables by name
- This is really fast with a small number of variables but tanks fast
  with more vars due to O(n) lookup times
- Implemented scopes by dropping all elements from the vartable at the
  end of a scope
This commit is contained in:
Daniel M 2022-02-03 22:09:58 +01:00
parent e4977da546
commit cbea567d65

View File

@ -1,4 +1,4 @@
use std::{collections::HashMap, fmt::Display, rc::Rc}; use std::{fmt::Display, rc::Rc};
use crate::{ use crate::{
ast::{Ast, BinOpType, Expression, If, Statement, UnOpType}, ast::{Ast, BinOpType, Expression, If, Statement, UnOpType},
@ -17,7 +17,7 @@ pub struct Interpreter {
capture_output: bool, capture_output: bool,
output: Vec<Value>, output: Vec<Value>,
// Variable table stores the runtime values of variables // Variable table stores the runtime values of variables
vartable: HashMap<String, Value>, vartable: Vec<(String, Value)>,
} }
impl Interpreter { impl Interpreter {
@ -33,6 +33,22 @@ impl Interpreter {
&self.output &self.output
} }
fn get_var(&self, name: &str) -> Option<Value> {
self.vartable
.iter()
.rev()
.find(|it| it.0 == name)
.map(|it| it.1.clone())
}
fn get_var_mut(&mut self, name: &str) -> Option<&mut Value> {
self.vartable
.iter_mut()
.rev()
.find(|it| it.0 == name)
.map(|it| &mut it.1)
}
pub fn run_str(&mut self, code: &str, print_tokens: bool, print_ast: bool) { pub fn run_str(&mut self, code: &str, print_tokens: bool, print_ast: bool) {
let tokens = lex(code).unwrap(); let tokens = lex(code).unwrap();
if print_tokens { if print_tokens {
@ -48,6 +64,7 @@ impl Interpreter {
} }
pub fn run(&mut self, prog: &Ast) { pub fn run(&mut self, prog: &Ast) {
let vartable_len = self.vartable.len();
for stmt in &prog.prog { for stmt in &prog.prog {
match stmt { match stmt {
Statement::Expr(expr) => { Statement::Expr(expr) => {
@ -92,6 +109,8 @@ impl Interpreter {
} }
} }
} }
self.vartable.truncate(vartable_len);
} }
fn resolve_expr(&mut self, expr: &Expression) -> Value { fn resolve_expr(&mut self, expr: &Expression) -> Value {
@ -105,7 +124,7 @@ impl Interpreter {
} }
fn resolve_var(&mut self, name: &str) -> Value { fn resolve_var(&mut self, name: &str) -> Value {
match self.vartable.get(name) { match self.get_var(name) {
Some(val) => val.clone(), Some(val) => val.clone(),
None => panic!("Variable '{}' used but not declared", name), None => panic!("Variable '{}' used but not declared", name),
} }
@ -127,11 +146,11 @@ impl Interpreter {
match (&bo, &lhs) { match (&bo, &lhs) {
(BinOpType::Declare, Expression::Var(name)) => { (BinOpType::Declare, Expression::Var(name)) => {
self.vartable.insert(name.clone(), rhs.clone()); self.vartable.push((name.clone(), rhs.clone()));
return rhs; return rhs;
} }
(BinOpType::Assign, Expression::Var(name)) => { (BinOpType::Assign, Expression::Var(name)) => {
match self.vartable.get_mut(name) { match self.get_var_mut(name) {
Some(val) => *val = rhs.clone(), Some(val) => *val = rhs.clone(),
None => panic!("Runtime Error: Trying to assign value to undeclared variable"), None => panic!("Runtime Error: Trying to assign value to undeclared variable"),
} }