From cf2e5348bb32f631cc0cbf3bf51351a0a4e84694 Mon Sep 17 00:00:00 2001 From: Daniel M Date: Fri, 4 Feb 2022 18:48:45 +0100 Subject: [PATCH] Implement arrays --- src/ast.rs | 7 +++++++ src/astoptimizer.rs | 2 +- src/interpreter.rs | 50 +++++++++++++++++++++++++++++++++++++++++++++ src/lexer.rs | 2 ++ src/parser.rs | 31 ++++++++++++++++++++++++++++ src/token.rs | 6 ++++++ 6 files changed, 97 insertions(+), 1 deletion(-) diff --git a/src/ast.rs b/src/ast.rs index cccdf1d..a4f12ab 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -82,6 +82,13 @@ pub enum Expression { I64(i64), /// String literal String(Sid), + + /// Array with size + ArrayLiteral(Box), + + /// Array access with name, stackpos and position + ArrayAccess(Sid, usize, Box), + /// Variable Var(Sid, usize), /// Binary operation. Consists of type, left hand side and right hand side diff --git a/src/astoptimizer.rs b/src/astoptimizer.rs index 84bf5e5..7d90d89 100644 --- a/src/astoptimizer.rs +++ b/src/astoptimizer.rs @@ -46,7 +46,6 @@ impl SimpleAstOptimizer { fn optimize_expr(expr: &mut Expression) { match expr { - Expression::I64(_) | Expression::String(_) | Expression::Var(_, _) => (), Expression::BinOp(bo, lhs, rhs) => { Self::optimize_expr(lhs); Self::optimize_expr(rhs); @@ -99,6 +98,7 @@ impl SimpleAstOptimizer { _ => (), } } + _ => (), } } diff --git a/src/interpreter.rs b/src/interpreter.rs index 88327ca..6eb87e0 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -1,3 +1,5 @@ +use std::cell::RefCell; + use crate::{ ast::{BlockScope, BinOpType, Expression, If, Statement, UnOpType, Ast}, lexer::lex, @@ -8,6 +10,7 @@ use crate::{ pub enum Value { I64(i64), String(Sid), + Array(RefCell>), } #[derive(Default)] @@ -127,13 +130,41 @@ impl Interpreter { fn resolve_expr(&mut self, expr: &Expression) -> Value { match expr { Expression::I64(val) => Value::I64(*val), + Expression::ArrayLiteral(size) => { + let size = match self.resolve_expr(size) { + Value::I64(size) => size, + _ => panic!("Array size needs to be I64"), + }; + Value::Array(RefCell::new(vec![Value::I64(0); size as usize])) + } 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, idx) => self.resolve_var(*name, *idx), + Expression::ArrayAccess(name, idx, arr_idx) => self.resolve_array_access(*name, *idx, arr_idx), } } + fn resolve_array_access(&mut self, name: Sid, idx: usize, arr_idx: &Expression) -> Value { + let arr_idx = match self.resolve_expr(arr_idx) { + Value::I64(size) => size, + _ => panic!("Array index needs to be I64"), + }; + + let val = match self.get_var(idx) { + Some(val) => val, + None => panic!("Variable '{}' used but not declared", self.stringstore.lookup(name).unwrap()), + }; + + let arr = match val { + Value::Array(arr) => arr, + _ => panic!("Variable '{}' used but not declared", self.stringstore.lookup(name).unwrap()), + }; + + let arr = arr.borrow_mut(); + arr.get(arr_idx as usize).cloned().expect("Runtime error: Invalid array index") + } + fn resolve_var(&mut self, name: Sid, idx: usize) -> Value { match self.get_var(idx) { Some(val) => val, @@ -167,6 +198,24 @@ impl Interpreter { } return rhs; } + (BinOpType::Assign, Expression::ArrayAccess(name, idx, arr_idx)) => { + let arr_idx = match self.resolve_expr(arr_idx) { + Value::I64(size) => size, + _ => panic!("Array index needs to be I64"), + }; + + let val = match self.get_var_mut(*idx) { + Some(val) => val, + None => panic!("Runtime Error: Trying to assign value to undeclared variable: {:?}", self.stringstore.lookup(*name)), + }; + + match val { + Value::Array(arr) => arr.borrow_mut()[arr_idx as usize] = rhs.clone(), + _ => panic!("Variable '{}' used but not declared", self.stringstore.lookup(*name).unwrap()), + } + + return rhs; + } _ => (), } @@ -202,6 +251,7 @@ impl Interpreter { fn print_value(&self, val: &Value) { match val { Value::I64(val) => print!("{}", val), + Value::Array(val) => print!("{:?}", val.borrow()), Value::String(text) => print!("{}", self.stringstore.lookup(*text).unwrap()), } } diff --git a/src/lexer.rs b/src/lexer.rs index d145c04..cc2bf41 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -106,6 +106,8 @@ impl<'a> Lexer<'a> { '{' => tokens.push(Token::LBraces), '}' => tokens.push(Token::RBraces), '!' => tokens.push(Token::LNot), + '[' => tokens.push(Token::LBracket), + ']' => tokens.push(Token::RBracket), // Special tokens with variable length diff --git a/src/parser.rs b/src/parser.rs index 7ab2892..9d55c36 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -239,6 +239,37 @@ impl> Parser { // Literal String Token::String(text) => Expression::String(self.stringstore.intern_or_lookup(&text)), + Token::LBracket => { + let size = self.parse_expr(); + + if !matches!(self.next(), Token::RBracket) { + panic!("Error parsing array literal: Expected closing bracket") + } + + Expression::ArrayLiteral(size.into()) + } + + Token::Ident(name) if matches!(self.peek(), Token::LBracket) => { + 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); + + self.next(); + + let size = self.parse_expr(); + + if !matches!(self.next(), Token::RBracket) { + panic!("Error parsing array access: Expected closing bracket") + } + + Expression::ArrayAccess(sid, stackpos, size.into()) + } + Token::Ident(name) => { let sid = self.stringstore.intern_or_lookup(&name); let stackpos = self diff --git a/src/token.rs b/src/token.rs index 19f3d3e..5ca659b 100644 --- a/src/token.rs +++ b/src/token.rs @@ -23,6 +23,12 @@ pub enum Token { /// Else keyword (else) Else, + /// Left Bracket ('[') + LBracket, + + /// Right Bracket (']') + RBracket, + /// Left Parenthesis ('(') LParen,