about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/interpret/value.rs40
-rw-r--r--src/interpret/walker.rs39
-rw-r--r--src/parse/ast/expression.rs20
-rw-r--r--src/parse/ast/nodes.rs9
-rw-r--r--src/parse/parser.rs27
5 files changed, 107 insertions, 28 deletions
diff --git a/src/interpret/value.rs b/src/interpret/value.rs
index 86fe094..1a7422b 100644
--- a/src/interpret/value.rs
+++ b/src/interpret/value.rs
@@ -10,6 +10,7 @@ pub enum Value {
     Float(f64),
     Int(i64),
     Bool(bool),
+    Array(Vec<Value>),
     Fn(Ref<FnNode>),
     Void,
 }
@@ -163,6 +164,28 @@ impl Value {
             _ => Err(OperationError::NotType(self)),
         }
     }
+
+    pub fn subscript(self, index: Value) -> Result<Value, OperationError> {
+        let index = match index {
+            Value::Int(i) => i,
+            i => return Err(OperationError::ArrayIndexType(i)),
+        };
+
+        match self {
+            Value::Array(a) => {
+                if index < 0 || index as usize >= a.len() {
+                    Err(OperationError::ArrayIndexOutOfRange {
+                        index,
+                        length: a.len(),
+                    })
+                } else {
+                    Ok(a[index as usize].clone())
+                }
+            }
+            // Maybe allow string subscripts?
+            x => Err(OperationError::ArrayType(x)),
+        }
+    }
 }
 
 impl Value {
@@ -172,6 +195,7 @@ impl Value {
             Value::Float(_) => "Float",
             Value::Int(_) => "Int",
             Value::Bool(_) => "Bool",
+            Value::Array(_) => "Array",
             Value::Fn(_) => "Fn",
             Value::Void => "Void",
         }
@@ -185,6 +209,16 @@ impl Display for Value {
             Value::Float(v) => write!(f, "{}", v),
             Value::Int(v) => write!(f, "{}", v),
             Value::Bool(v) => write!(f, "{}", v),
+            Value::Array(a) => {
+                write!(
+                    f,
+                    "[{}]",
+                    a.iter()
+                        .map(|v| format!("{}", v))
+                        .collect::<Vec<_>>()
+                        .join(", ")
+                )
+            }
             Value::Fn(v) => write!(f, "<fn {:?}>", v.as_ptr()),
             Value::Void => write!(f, "<void>"),
         }
@@ -207,4 +241,10 @@ pub enum OperationError {
     NegType(Value),
     #[error("Can't flip value '{0}' of type '{}'.", .0.type_name())]
     NotType(Value),
+    #[error("Can't use value '{0}' of type '{}' as a subsript index.", .0.type_name())]
+    ArrayIndexType(Value),
+    #[error("Can't subscript value '{0}' of type '{}'.", .0.type_name())]
+    ArrayType(Value),
+    #[error("Array index '{index}' out of range for array of length '{length}'.")]
+    ArrayIndexOutOfRange { index: i64, length: usize },
 }
diff --git a/src/interpret/walker.rs b/src/interpret/walker.rs
index ac3a092..0177777 100644
--- a/src/interpret/walker.rs
+++ b/src/interpret/walker.rs
@@ -2,7 +2,7 @@ use std::{cell::RefCell, rc::Rc};
 
 use crate::parse::ast::{
     expression::Expression,
-    nodes::{BinaryOperator as BinOp, BlockNode, Identifier, Literal, UnaryOperator as UnOp},
+    nodes::{BinaryOperator as BinOp, BlockNode, Identifier, SimpleLiteral, UnaryOperator as UnOp},
     statement::Statement,
     Program,
 };
@@ -79,7 +79,7 @@ impl Walker {
                 let right = self.walk_expression(right)?;
 
                 // Other operators
-                let new_value = match op {
+                match op {
                     BinOp::Plus => left.add(right),
                     BinOp::Minus => left.sub(right),
                     BinOp::Star => left.mul(right),
@@ -94,37 +94,44 @@ impl Walker {
                     BinOp::Dot => todo!(),
                     _ => unreachable!(),
                 }
-                .map_err(WalkerError::OperationError)?;
-
-                Ok(new_value)
+                .map_err(WalkerError::OperationError)
             }
             Expression::Unary { op, right } => {
                 let value = self.walk_expression(right)?;
 
-                let new_value = match op {
+                match op {
                     UnOp::Minus => value.neg(),
                     UnOp::Not => value.not(),
                 }
-                .map_err(WalkerError::OperationError)?;
-
-                Ok(new_value)
+                .map_err(WalkerError::OperationError)
             }
             Expression::Call(_) => todo!("Calls not implemented yet."),
-            Expression::ArrayAccess(_) => todo!("Arrays not implemented yet."),
+            Expression::ArrayAccess(node) => {
+                let array = self.walk_expression(&node.array)?;
+                let index = self.walk_expression(&node.index)?;
+                array.subscript(index).map_err(WalkerError::OperationError)
+            }
             Expression::MemberAccess(_) => todo!("Structures not implemented yet."),
             Expression::Group(node) => self.walk_expression(node),
-            Expression::Literal(token) => {
+            Expression::ArrayLiteral(node) => {
+                let mut elements = Vec::new();
+                for expression in &node.elements {
+                    elements.push(self.walk_expression(expression)?);
+                }
+                Ok(Value::Array(elements))
+            }
+            Expression::SimpleLiteral(token) => {
                 let value = match token {
-                    Literal::Int(int) => Value::Int(*int as i64),
-                    Literal::Float(float) => Value::Float(*float as f64),
-                    Literal::Str(string) => Value::Str(string.clone()),
-                    Literal::Bool(bool) => Value::Bool(*bool),
+                    SimpleLiteral::Int(int) => Value::Int(*int as i64),
+                    SimpleLiteral::Float(float) => Value::Float(*float as f64),
+                    SimpleLiteral::Str(string) => Value::Str(string.clone()),
+                    SimpleLiteral::Bool(bool) => Value::Bool(*bool),
                 };
 
                 Ok(value)
             }
             Expression::Block(block) => self.walk_block(block.as_ref()),
-            Expression::Fn(fn_node) => {
+            Expression::FnLiteral(fn_node) => {
                 let node = fn_node.as_ref().clone();
                 Ok(Value::Fn(RefCell::new(Rc::new(node))))
             }
diff --git a/src/parse/ast/expression.rs b/src/parse/ast/expression.rs
index 1eec69d..b2b9678 100644
--- a/src/parse/ast/expression.rs
+++ b/src/parse/ast/expression.rs
@@ -1,8 +1,8 @@
 use std::fmt::{self, Display, Formatter};
 
 use super::nodes::{
-    ArrayAccessNode, BinaryOperator, BlockNode, CallNode, FnNode, Identifier, IfNode, Literal,
-    LoopNode, MemberAccessNode, UnaryOperator,
+    ArrayAccessNode, ArrayNode, BinaryOperator, BlockNode, CallNode, FnNode, Identifier, IfNode,
+    LoopNode, MemberAccessNode, SimpleLiteral, UnaryOperator,
 };
 
 #[derive(Debug, Clone)]
@@ -21,10 +21,11 @@ pub enum Expression {
     MemberAccess(Box<MemberAccessNode>),
     Group(Box<Expression>),
     Block(Box<BlockNode>),
-    Fn(Box<FnNode>),
     If(Box<IfNode>),
     Loop(Box<LoopNode>),
-    Literal(Literal),
+    FnLiteral(Box<FnNode>),
+    ArrayLiteral(ArrayNode),
+    SimpleLiteral(SimpleLiteral),
     Identifier(Identifier),
 }
 
@@ -81,7 +82,7 @@ impl Expression {
             Expression::Block(block) => {
                 Self::block_fmt(f, block, depth + 1)?;
             }
-            Expression::Fn(node) => {
+            Expression::FnLiteral(node) => {
                 write!(f, "{}Fn (", pad)?;
 
                 // Write self receiver
@@ -107,7 +108,14 @@ impl Expression {
                 )?;
                 Self::block_fmt(f, &node.body, depth + 1)?;
             }
-            Expression::Literal(literal) => {
+            Expression::ArrayLiteral(node) => {
+                writeln!(f, "{}Array Literal:", pad)?;
+                for (i, c) in node.elements.iter().enumerate() {
+                    writeln!(f, "{}- Element {}:", pad, i)?;
+                    c.nested_fmt(f, depth + 1)?;
+                }
+            }
+            Expression::SimpleLiteral(literal) => {
                 writeln!(f, "{}Literal: {:?}", pad, literal)?;
             }
             Expression::Identifier(identifier) => {
diff --git a/src/parse/ast/nodes.rs b/src/parse/ast/nodes.rs
index 617a01c..bffaea3 100644
--- a/src/parse/ast/nodes.rs
+++ b/src/parse/ast/nodes.rs
@@ -57,14 +57,14 @@ impl UnaryOperator {
 }
 
 #[derive(Debug, Clone)]
-pub enum Literal {
+pub enum SimpleLiteral {
     Int(u32),
     Float(f32),
     Str(String),
     Bool(bool),
 }
 
-impl Literal {
+impl SimpleLiteral {
     pub fn from_token(token: Token) -> Self {
         match token.variant {
             Int(int) => Self::Int(int),
@@ -112,6 +112,11 @@ pub struct FnNode {
 }
 
 #[derive(Debug, Clone)]
+pub struct ArrayNode {
+    pub elements: Vec<Expression>,
+}
+
+#[derive(Debug, Clone)]
 pub struct FnHeader {
     pub has_self_receiver: bool,
     pub parameters: Vec<TypedIdentifier>,
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 2083f75..a882f35 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -1,11 +1,11 @@
 use super::ast::expression::Expression;
-use super::ast::nodes::{LoopNode, UnaryOperator};
+use super::ast::nodes::{ArrayNode, LoopNode, UnaryOperator};
 use super::ast::statement::Statement;
 use super::ast::Program;
 use crate::lex::token::TokenVariant::*;
 use crate::parse::ast::nodes::{
     ArrayAccessNode, BinaryOperator, BlockNode, CallNode, ConditionalBlock, FnHeader, FnNode,
-    IfNode, Literal, MemberAccessNode, TypedIdentifier,
+    IfNode, MemberAccessNode, SimpleLiteral, TypedIdentifier,
 };
 use crate::{check, consume, consume_if, inner, lex::token::Token};
 use anyhow::{anyhow, Result};
@@ -227,7 +227,9 @@ impl<T: Iterator<Item = Token>> Parser<T> {
             match token.variant {
                 Int(_) | Float(_) | Str(_) | KeywordTrue | KeywordFalse => {
                     let literal = self.tokens.next().unwrap();
-                    Ok(Expression::Literal(Literal::from_token(literal)))
+                    Ok(Expression::SimpleLiteral(SimpleLiteral::from_token(
+                        literal,
+                    )))
                 }
                 Ident(_) => Ok(Expression::Identifier(inner!(
                     self.tokens.next().unwrap(),
@@ -235,7 +237,8 @@ impl<T: Iterator<Item = Token>> Parser<T> {
                 ))),
                 GroupOpen => Ok(Expression::Group(Box::new(self.group()?))),
                 BlockOpen => Ok(Expression::Block(Box::new(self.generic_block()?))),
-                KeywordFn => Ok(Expression::Fn(Box::new(self.function()?))),
+                ArrayOpen => Ok(Expression::ArrayLiteral(self.array()?)),
+                KeywordFn => Ok(Expression::FnLiteral(Box::new(self.function()?))),
                 KeywordIf => Ok(Expression::If(Box::new(self.conditional()?))),
                 KeywordLoop => Ok(Expression::Loop(Box::new(self.repeating()?))),
                 _ => Err(anyhow!("Unexpected token: {:?}", token.variant)),
@@ -252,6 +255,22 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(expression)
     }
 
+    fn array(&mut self) -> Result<ArrayNode> {
+        consume!(self, ArrayOpen)?;
+        let mut elements = Vec::new();
+
+        loop {
+            elements.push(self.expression()?);
+
+            if consume_if!(self, Comma).is_none() {
+                break;
+            }
+        }
+
+        consume!(self, ArrayClose)?;
+        Ok(ArrayNode { elements })
+    }
+
     fn function(&mut self) -> Result<FnNode> {
         consume!(self, KeywordFn)?;
         let token = self.tokens.next().expect("Expected function header.");