diff --git a/src/schala_lang/eval.rs b/src/schala_lang/eval.rs index 0f58a64..91d04b2 100644 --- a/src/schala_lang/eval.rs +++ b/src/schala_lang/eval.rs @@ -16,6 +16,7 @@ type Reduction = (T, Option); enum ReducedValue { StringLiteral(Rc), ListLiteral(VecDeque), + StructLiteral(VecDeque<(Rc, Expression)>), Number(f64), Lambda(Function), } @@ -27,6 +28,7 @@ impl From for Expression { ReducedValue::StringLiteral(n) => Expression::StringLiteral(n), ReducedValue::Lambda(f) => Expression::Lambda(f), ReducedValue::ListLiteral(items) => Expression::ListLiteral(items), + ReducedValue::StructLiteral(items) => Expression::StructLiteral(items), } } } @@ -38,6 +40,7 @@ impl From for ReducedValue { Expression::StringLiteral(n) => ReducedValue::StringLiteral(n), Expression::Lambda(f) => ReducedValue::Lambda(f), Expression::ListLiteral(items) => ReducedValue::ListLiteral(items), + Expression::StructLiteral(items) => ReducedValue::StructLiteral(items), _ => panic!("trying to store a non-fully-reduced variable"), } } @@ -120,6 +123,9 @@ impl Evaluable for Expression { ListLiteral(ref items) => { items.iter().any(|x| x.is_reducible()) } + StructLiteral(ref items) => { + items.iter().any(|pair| pair.1.is_reducible()) + } _ => true, } } @@ -214,6 +220,7 @@ impl<'a> Evaluator<'a> { } } + //TODO I probably want another Expression variant that holds a ReducedValue fn reduce_expr(&mut self, expression: Expression) -> Reduction { match expression { Null => (Null, None), @@ -348,6 +355,14 @@ impl<'a> Evaluator<'a> { (Null, None) } } + (StructLiteral(items), StringLiteral(s)) => { + for item in items { + if s == item.0 { + return (item.1.clone(), None); //TODO this is hella inefficient + } + } + (Null, None) + }, _ => (Null, None) } } @@ -365,6 +380,23 @@ impl<'a> Evaluator<'a> { } (ListLiteral(exprs), side_effect) }, + + StructLiteral(mut items) => { + let mut side_effect = None; + for pair in items.iter_mut() { + if pair.1.is_reducible() { + take_mut::take(pair, |pair| { + let (name, expr) = pair; + let (a, b) = self.reduce_expr(expr); + side_effect = b; + (name, a) + }); + break; + } + } + + (StructLiteral(items), side_effect) + } } } diff --git a/src/schala_lang/parser.rs b/src/schala_lang/parser.rs index a7138ff..ec19972 100644 --- a/src/schala_lang/parser.rs +++ b/src/schala_lang/parser.rs @@ -12,15 +12,17 @@ use std::convert::From; // statement := declaration | expression // declaration := FN prototype LCurlyBrace (statement)* RCurlyBrace // prototype := identifier LParen identlist RParen -// identlist := Ident (Comma Ident)* | e -// exprlist := Expression (Comma Expression)* | e +// identlist := Ident (Comma Ident)* | ε +// exprlist := Expression (Comma Expression)* | ε +// itemlist := Ident COLON Expression (Comma Ident COLON Expression)* | ε // // expression := postop_expression (op postop_expression)* // postop_expression := primary_expression postop -// primary_expression := number_expr | String | identifier_expr | paren_expr | conditional_expr | while_expr | lambda_expr | list_expr +// primary_expression := number_expr | String | identifier_expr | paren_expr | conditional_expr | while_expr | lambda_expr | list_expr | struct_expr // number_expr := (PLUS | MINUS ) number_expr | Number // identifier_expr := call_expression | Variable // list_expr := LSquareBracket exprlist RSquareBracket +// struct_expr := LCurlyBrace itemlist RCurlyBrace // call_expression := Identifier LParen exprlist RParen // while_expr := WHILE primary_expression LCurlyBrace (expression delimiter)* RCurlyBrace // paren_expr := LParen expression RParen @@ -75,6 +77,7 @@ pub enum Expression { While(Box, Vec), Index(Box, Box), ListLiteral(VecDeque), + StructLiteral(VecDeque<(Rc, Expression)>), } #[derive(Clone, Debug)] @@ -83,6 +86,7 @@ pub enum Callable { Lambda(Function), } +//TODO this ought to be ReducedExpression impl fmt::Display for Expression { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { use self::Expression::*; @@ -104,6 +108,17 @@ impl fmt::Display for Expression { } write!(f, " ]") } + StructLiteral(ref items) => { + write!(f, "{} ", "{")?; + let mut iter = items.iter().peekable(); + while let Some(pair) = iter.next() { + write!(f, "{}: {}", pair.0, pair.1)?; + if let Some(_) = iter.peek() { + write!(f, ", ")?; + } + } + write!(f, "{} ", "}") + } _ => write!(f, "UNIMPLEMENTED"), } } @@ -361,6 +376,24 @@ impl Parser { Ok(exprs) } + fn itemlist(&mut self) -> ParseResult, Expression)>> { + let mut items = VecDeque::new(); + loop { + if let Some(RCurlyBrace) = self.peek() { + break; + } + let name = expect_identifier!(self); + expect!(self, Colon); + let expr = self.expression()?; + items.push_back((name, expr)); + match self.peek() { + Some(Comma) => {self.next();}, + _ => break, + }; + } + Ok(items) + } + fn body(&mut self) -> ParseResult> { let statements = delimiter_block!( self, @@ -446,6 +479,7 @@ impl Parser { Some(Token::LParen) => self.paren_expr()?, Some(Keyword(Kw::Fn)) => self.lambda_expr()?, Some(Token::LSquareBracket) => self.list_expr()?, + Some(Token::LCurlyBrace) => self.struct_expr()?, Some(e) => { return ParseError::result_from_str(&format!("Expected primary expression, got \ {:?}", @@ -463,6 +497,13 @@ impl Parser { Ok(Expression::ListLiteral(VecDeque::from(exprlist))) } + fn struct_expr(&mut self) -> ParseResult { + expect!(self, LCurlyBrace); + let struct_items = self.itemlist()?; + expect!(self, RCurlyBrace); + Ok(Expression::StructLiteral(struct_items)) + } + fn number_expression(&mut self) -> ParseResult { let mut multiplier = 1; loop {