Implement arrays
This commit is contained in:
parent
8b67c4d59c
commit
cf2e5348bb
@ -82,6 +82,13 @@ pub enum Expression {
|
||||
I64(i64),
|
||||
/// String literal
|
||||
String(Sid),
|
||||
|
||||
/// Array with size
|
||||
ArrayLiteral(Box<Expression>),
|
||||
|
||||
/// Array access with name, stackpos and position
|
||||
ArrayAccess(Sid, usize, Box<Expression>),
|
||||
|
||||
/// Variable
|
||||
Var(Sid, usize),
|
||||
/// Binary operation. Consists of type, left hand side and right hand side
|
||||
|
||||
@ -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 {
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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<Vec<Value>>),
|
||||
}
|
||||
|
||||
#[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()),
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -239,6 +239,37 @@ impl<T: Iterator<Item = Token>> Parser<T> {
|
||||
// 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
|
||||
|
||||
@ -23,6 +23,12 @@ pub enum Token {
|
||||
/// Else keyword (else)
|
||||
Else,
|
||||
|
||||
/// Left Bracket ('[')
|
||||
LBracket,
|
||||
|
||||
/// Right Bracket (']')
|
||||
RBracket,
|
||||
|
||||
/// Left Parenthesis ('(')
|
||||
LParen,
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user