diff --git a/src/ast.rs b/src/ast.rs index 30161a9..da3adc4 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -83,7 +83,7 @@ pub enum Expression { /// String literal String(Sid), /// Variable - Var(Sid), + Var(Sid, usize), /// Binary operation. Consists of type, left hand side and right hand side BinOp(BinOpType, Box, Box), /// Unary operation. Consists of type and operand diff --git a/src/interpreter.rs b/src/interpreter.rs index 10c7e76..d4b6886 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -15,7 +15,7 @@ pub struct Interpreter { capture_output: bool, output: Vec, // Variable table stores the runtime values of variables - vartable: Vec<(Sid, Value)>, + vartable: Vec, stringstore: StringStore, } @@ -33,20 +33,12 @@ impl Interpreter { &self.output } - fn get_var(&self, name: Sid) -> Option { - self.vartable - .iter() - .rev() - .find(|it| it.0 == name) - .map(|it| it.1.clone()) + fn get_var(&self, idx: usize) -> Option { + self.vartable.get(idx).cloned() } - fn get_var_mut(&mut self, name: Sid) -> Option<&mut Value> { - self.vartable - .iter_mut() - .rev() - .find(|it| it.0 == name) - .map(|it| &mut it.1) + fn get_var_mut(&mut self, idx: usize) -> Option<&mut Value> { + self.vartable.get_mut(idx) } pub fn run_str(&mut self, code: &str, print_tokens: bool, print_ast: bool) { @@ -66,7 +58,8 @@ impl Interpreter { } pub fn run_block(&mut self, prog: &BlockScope) { - let vartable_len = self.vartable.len(); + let framepointer = self.vartable.len(); + for stmt in prog { match stmt { Statement::Expr(expr) => { @@ -112,7 +105,7 @@ impl Interpreter { } } - self.vartable.truncate(vartable_len); + self.vartable.truncate(framepointer); } fn resolve_expr(&mut self, expr: &Expression) -> Value { @@ -121,13 +114,13 @@ impl Interpreter { Expression::String(text) => Value::String(text.clone()), Expression::BinOp(bo, lhs, rhs) => self.resolve_binop(bo, lhs, rhs), Expression::UnOp(uo, operand) => self.resolve_unop(uo, operand), - Expression::Var(name) => self.resolve_var(*name), + Expression::Var(name, idx) => self.resolve_var(*name, *idx), } } - fn resolve_var(&mut self, name: Sid) -> Value { - match self.get_var(name) { - Some(val) => val.clone(), + fn resolve_var(&mut self, name: Sid, idx: usize) -> Value { + match self.get_var(idx) { + Some(val) => val, None => panic!("Variable '{}' used but not declared", self.stringstore.lookup(name).unwrap()), } } @@ -147,14 +140,14 @@ impl Interpreter { let rhs = self.resolve_expr(rhs); match (&bo, &lhs) { - (BinOpType::Declare, Expression::Var(name)) => { - self.vartable.push((name.clone(), rhs.clone())); + (BinOpType::Declare, Expression::Var(_name, _idx)) => { + self.vartable.push(rhs.clone()); return rhs; } - (BinOpType::Assign, Expression::Var(name)) => { - match self.get_var_mut(*name) { + (BinOpType::Assign, Expression::Var(name, idx)) => { + match self.get_var_mut(*idx) { 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: {:?}", self.stringstore.lookup(*name)), } return rhs; } diff --git a/src/parser.rs b/src/parser.rs index 72e8038..3391209 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,7 +1,7 @@ use std::iter::Peekable; use crate::ast::*; -use crate::stringstore::StringStore; +use crate::stringstore::{Sid, StringStore}; use crate::token::Token; /// Parse the given tokens into an abstract syntax tree @@ -13,6 +13,7 @@ pub fn parse, A: IntoIterator>(tokens: A struct Parser> { tokens: Peekable, stringstore: StringStore, + varstack: Vec, } impl> Parser { @@ -20,9 +21,11 @@ impl> Parser { pub fn new>(tokens: A) -> Self { let tokens = tokens.into_iter().peekable(); let stringstore = StringStore::new(); + let varstack = Vec::new(); Self { tokens, stringstore, + varstack, } } @@ -37,6 +40,7 @@ impl> Parser { /// Parse tokens into an abstract syntax tree. This will continuously parse statements until /// encountering end-of-file or a block end '}' . fn parse_scoped_block(&mut self) -> BlockScope { + let framepointer = self.varstack.len(); let mut prog = Vec::new(); loop { @@ -51,6 +55,8 @@ impl> Parser { } } + self.varstack.truncate(framepointer); + prog } @@ -76,7 +82,20 @@ impl> Parser { // If it is not a loop, try to lex as an expression _ => { - let stmt = Statement::Expr(self.parse_expr()); + let mut expr = self.parse_expr(); + + match &mut expr { + Expression::BinOp(BinOpType::Declare, lhs, _) => match lhs.as_mut() { + Expression::Var(sid, sp) => { + *sp = self.varstack.len(); + self.varstack.push(*sid); + } + _ => panic!("Left hand side of declaration must be variable"), + }, + _ => (), + } + + let stmt = Statement::Expr(expr); // After a statement, there must be a semicolon if !matches!(self.next(), Token::Semicolon) { @@ -212,7 +231,17 @@ impl> Parser { // Literal String Token::String(text) => Expression::String(self.stringstore.intern_or_lookup(&text)), - Token::Ident(name) => Expression::Var(self.stringstore.intern_or_lookup(&name)), + Token::Ident(name) => { + let sid = self.stringstore.intern_or_lookup(&name); + let stackpos = self + .varstack + .iter() + .rev() + .position(|it| *it == sid) + .map(|it| self.varstack.len() - it - 1) + .unwrap_or(usize::MAX); + Expression::Var(sid, stackpos) + } // Parentheses grouping Token::LParen => {