Skip to content

Commit

Permalink
Eval arrays and index expressions (#35)
Browse files Browse the repository at this point in the history
* Lexing

* Parse

* Parse index expressions

* Eval

* Eval index expressions, fix broken lexer

* Fix commented out tests
  • Loading branch information
poteto authored Jul 8, 2021
1 parent 689c76b commit 1a0c6b7
Show file tree
Hide file tree
Showing 5 changed files with 256 additions and 70 deletions.
18 changes: 18 additions & 0 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ pub enum Expression {
Box<Expression>, // Left
Box<Expression>, // Right
),
Index(
Box<Expression>, // Left
Box<Expression>, // Index
),

If(
Box<Expression>, // Condition
Expand All @@ -94,6 +98,8 @@ pub enum Expression {
Box<Expression>, // Function
Vec<Expression>, // Arguments
),

Array(Vec<Expression>),
}

impl fmt::Display for Expression {
Expand All @@ -115,6 +121,9 @@ impl fmt::Display for Expression {
operator = operator,
right = right
),
Expression::Index(left, index) => {
write!(f, "({left}[{index}])", left = left, index = index)
}
Expression::If(condition, consequence, alternative) => {
if let (condition, Some(consequence)) = (condition, consequence) {
write!(
Expand Down Expand Up @@ -151,6 +160,15 @@ impl fmt::Display for Expression {
.collect::<Vec<String>>()
.join(", ")
),
Expression::Array(expressions) => write!(
f,
"[{}]",
expressions
.iter()
.map(|expression| expression.to_string())
.collect::<Vec<String>>()
.join(", ")
),
}
}
}
9 changes: 9 additions & 0 deletions src/eval/ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub enum IR {
Rc<RefCell<Env>>, // Env
),
String(String),
Array(Vec<Rc<IR>>),
StdLib(BuiltIn),
}

Expand All @@ -33,6 +34,14 @@ impl fmt::Display for IR {
IR::Function(_, _, _) => Ok(()),
IR::String(ir) => ir.fmt(f),
IR::StdLib(bi) => bi.fmt(f),
IR::Array(irs) => write!(
f,
"[{}]",
irs.iter()
.map(|ir| ir.to_string())
.collect::<Vec<String>>()
.join(", ")
),
}
}
}
Expand Down
106 changes: 102 additions & 4 deletions src/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,16 @@ impl Interpreter {
Ok(result)
}

fn eval_expressions(
&mut self,
expressions: &Vec<Expression>,
) -> Result<Vec<Rc<IR>>, EvalError> {
expressions
.iter()
.map(|arg| self.eval_expression(arg))
.collect::<Result<Vec<Rc<IR>>, _>>()
}

fn eval_expression(&mut self, expression: &Expression) -> EvalResult {
match expression {
Expression::Identifier(Identifier(identifier_key)) => {
Expand Down Expand Up @@ -109,6 +119,11 @@ impl Interpreter {
let right = self.eval_expression(right)?;
self.eval_infix_expression(operator, left, right)
}
Expression::Index(left, index) => {
let left = self.eval_expression(left)?;
let index = self.eval_expression(index)?;
self.eval_index_expression(left, index)
}
Expression::If(condition, consequence, alternative) => {
self.eval_if_expression(condition, consequence, alternative)
}
Expand All @@ -119,17 +134,15 @@ impl Interpreter {
))),
Expression::Call(function, arguments) => {
let function = self.eval_expression(function)?;
let evaluated_args = arguments
.iter()
.map(|arg| self.eval_expression(arg))
.collect::<Result<Vec<Rc<IR>>, _>>()?;
let evaluated_args = self.eval_expressions(arguments)?;
self.eval_call_expression(function, &evaluated_args)
}
Expression::String(string_key) => {
let interner = self.interner.borrow_mut();
let value = interner.resolve(*string_key).unwrap();
Ok(Rc::new(IR::String(value.to_string())))
}
Expression::Array(values) => Ok(Rc::new(IR::Array(self.eval_expressions(values)?))),
}
}

Expand Down Expand Up @@ -199,6 +212,22 @@ impl Interpreter {
}
}

fn eval_index_expression(&mut self, left: Rc<IR>, index: Rc<IR>) -> EvalResult {
match (&*left, &*index) {
(IR::Array(values), IR::Integer(index)) => {
let index = *index as usize;
match values.get(index) {
Some(ir) => Ok(Rc::clone(ir)),
None => Ok(Rc::new(NULL)),
}
}
(left, _) => Err(EvalError::InvalidExpression(format!(
"Index operator not supported: {}",
left
))),
}
}

fn eval_if_expression(
&mut self,
condition: &Expression,
Expand Down Expand Up @@ -281,6 +310,7 @@ mod tests {
use crate::eval::{ir::IR, Env, Interpreter};
use crate::lexer::Lexer;
use crate::parser::Parser;
use crate::token::IntegerSize;

use super::EvalResult;

Expand Down Expand Up @@ -667,4 +697,72 @@ mod tests {
}
}
}

#[test]
fn it_evaluates_array_literals() {
let tests = vec![("[1, 2 * 2, 3 + 3];", vec![1, 4, 6])];

for (input, expected) in tests {
let result = test_eval(input);
match result {
Ok(ir) => match &*ir {
IR::Array(values) => {
for (i, value) in values.iter().enumerate() {
if let IR::Integer(int) = **value {
assert_eq!(int, expected[i] as IntegerSize);
}
}
}
ir_object => {
panic!("Didn't expect {}", ir_object);
}
},
Err(err) => {
panic!("{}", err);
}
}
}
}

#[test]
fn it_evaluates_array_index_expressions() {
let tests = vec![
("[1, 2, 3][0];", Some(1)),
("[1, 2, 3][1];", Some(2)),
("[1, 2, 3][2];", Some(3)),
("let i = 0; [1][i];", Some(1)),
("[1, 2, 3][1 + 1];", Some(3)),
("let myArray = [1, 2, 3]; myArray[2];", Some(3)),
(
"let myArray = [1, 2, 3]; myArray[0] + myArray[1] + myArray[2];",
Some(6),
),
(
"let myArray = [1, 2, 3]; let i = myArray[0]; myArray[i];",
Some(2),
),
("[1, 2, 3][3]", None),
("[1, 2, 3][-1]", None),
];

for (input, expected) in tests {
let result = test_eval(input);
match result {
Ok(ir) => match &*ir {
IR::Integer(value) => {
assert_eq!(&expected.unwrap(), value);
}
IR::Null => {
assert!(expected.is_none());
}
ir_object => {
panic!("Didn't expect {}", ir_object);
}
},
Err(err) => {
panic!("{}", err);
}
}
}
}
}
Loading

0 comments on commit 1a0c6b7

Please sign in to comment.