From af34b3030a46805f42f04341f1ffb20d92fbb7ce Mon Sep 17 00:00:00 2001 From: Mel Date: Sun, 24 Oct 2021 18:26:01 +0200 Subject: Array literals and array access --- src/interpret/value.rs | 40 ++++++++++++++++++++++++++++++++++++++++ src/interpret/walker.rs | 39 +++++++++++++++++++++++---------------- src/parse/ast/expression.rs | 20 ++++++++++++++------ src/parse/ast/nodes.rs | 9 +++++++-- src/parse/parser.rs | 27 +++++++++++++++++++++++---- 5 files changed, 107 insertions(+), 28 deletions(-) (limited to 'src') 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), Fn(Ref), Void, } @@ -163,6 +164,28 @@ impl Value { _ => Err(OperationError::NotType(self)), } } + + pub fn subscript(self, index: Value) -> Result { + 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::>() + .join(", ") + ) + } Value::Fn(v) => write!(f, "", v.as_ptr()), Value::Void => write!(f, ""), } @@ -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), Group(Box), Block(Box), - Fn(Box), If(Box), Loop(Box), - Literal(Literal), + FnLiteral(Box), + 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), @@ -111,6 +111,11 @@ pub struct FnNode { pub body: BlockNode, } +#[derive(Debug, Clone)] +pub struct ArrayNode { + pub elements: Vec, +} + #[derive(Debug, Clone)] pub struct FnHeader { pub has_self_receiver: bool, 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> Parser { 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> Parser { ))), 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> Parser { Ok(expression) } + fn array(&mut self) -> Result { + 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 { consume!(self, KeywordFn)?; let token = self.tokens.next().expect("Expected function header."); -- cgit 1.4.1