diff --git a/src/eval.rs b/src/eval.rs index 1b5cdd1..e3c2d82 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -103,6 +103,18 @@ impl Evaluable for Expression { } } +impl Expression { + fn is_truthy(&self) -> bool { + use parser::Expression::*; + match *self { + Null => false, + StringLiteral(ref s) if s == "" => false, + Number(0.0) => false, + _ => true, + } + } +} + impl Evaluator { fn reduce(&mut self, mut node: ASTNode) -> String { loop { @@ -208,10 +220,32 @@ impl Evaluator { let (new_test, new_effect) = self.reduce_expr(test); (Conditional(Box::new(new_test), then_block, else_block), new_effect) } else { - if let Number(0.0) = test { - unimplemented!() + if test.is_truthy() { + (*then_block, None) } else { - unimplemented!() + match else_block { + Some(box expr) => (expr, None), + None => (Null, None) + } + } + } + } + Block(mut exprs) => { + let first = exprs.pop_front(); + match first { + None => (Null, None), + Some(expr) => { + if exprs.len() == 0 { + (expr, None) + } else { + if expr.is_reducible() { + let (new, side_effect) = self.reduce_expr(expr); + exprs.push_front(new); + (Block(exprs), side_effect) + } else { + (Block(exprs), None) + } + } } } } diff --git a/src/parser.rs b/src/parser.rs index a39b5a0..b2fd9b3 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,5 +1,6 @@ use std::fmt; use tokenizer::{Token, Kw, Op}; +use std::collections::VecDeque; // Grammar // program := (statement delimiter ?)* @@ -45,7 +46,8 @@ pub enum Expression { Variable(String), BinExp(String, Box, Box), Call(String, Vec), - Conditional(Box, Vec, Option>), + Conditional(Box, Box, Option>), + Block(VecDeque), } impl fmt::Display for ASTNode { @@ -315,7 +317,6 @@ impl Parser { Some(Identifier(_)) => try!(self.identifier_expr()), Some(Token::LParen) => try!(self.paren_expr()), Some(e) => { - panic!(); return ParseError::result_from_str("Expected primary expression"); } None => return ParseError::result_from_str("Expected primary expression received EoI"), @@ -324,28 +325,29 @@ impl Parser { fn conditional_expr(&mut self) -> ParseResult { use tokenizer::Token::*; + use self::Expression::*; expect!(self, Keyword(Kw::If)); let test = try!(self.expression()); expect!(self, Keyword(Kw::Then)); - let mut then_block = Vec::new(); + let mut then_block = VecDeque::new(); loop { match self.peek() { None | Some(Keyword(Kw::Else)) | Some(Keyword(Kw::End)) => break, _ => { let exp = try!(self.expression()); - then_block.push(exp); + then_block.push_back(exp); } } } let else_block = if let Some(Keyword(Kw::Else)) = self.peek() { self.next(); - let mut else_exprs = Vec::new(); + let mut else_exprs = VecDeque::new(); loop { match self.peek() { None | Some(Keyword(Kw::End)) => break, _ => { let exp = try!(self.expression()); - else_exprs.push(exp); + else_exprs.push_back(exp); } } } @@ -355,7 +357,7 @@ impl Parser { }; expect!(self, Keyword(Kw::End)); - Ok(Expression::Conditional(Box::new(test), then_block, else_block)) + Ok(Conditional(Box::new(test), Box::new(Block(then_block)), else_block.map(|list| Box::new(Block(list))))) } fn identifier_expr(&mut self) -> ParseResult {