Finish evaluating conditionals
This commit is contained in:
parent
7f52b20d97
commit
82c52ede48
40
src/eval.rs
40
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 {
|
impl Evaluator {
|
||||||
fn reduce(&mut self, mut node: ASTNode) -> String {
|
fn reduce(&mut self, mut node: ASTNode) -> String {
|
||||||
loop {
|
loop {
|
||||||
@ -208,10 +220,32 @@ impl Evaluator {
|
|||||||
let (new_test, new_effect) = self.reduce_expr(test);
|
let (new_test, new_effect) = self.reduce_expr(test);
|
||||||
(Conditional(Box::new(new_test), then_block, else_block), new_effect)
|
(Conditional(Box::new(new_test), then_block, else_block), new_effect)
|
||||||
} else {
|
} else {
|
||||||
if let Number(0.0) = test {
|
if test.is_truthy() {
|
||||||
unimplemented!()
|
(*then_block, None)
|
||||||
} else {
|
} 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use tokenizer::{Token, Kw, Op};
|
use tokenizer::{Token, Kw, Op};
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
// Grammar
|
// Grammar
|
||||||
// program := (statement delimiter ?)*
|
// program := (statement delimiter ?)*
|
||||||
@ -45,7 +46,8 @@ pub enum Expression {
|
|||||||
Variable(String),
|
Variable(String),
|
||||||
BinExp(String, Box<Expression>, Box<Expression>),
|
BinExp(String, Box<Expression>, Box<Expression>),
|
||||||
Call(String, Vec<Expression>),
|
Call(String, Vec<Expression>),
|
||||||
Conditional(Box<Expression>, Vec<Expression>, Option<Vec<Expression>>),
|
Conditional(Box<Expression>, Box<Expression>, Option<Box<Expression>>),
|
||||||
|
Block(VecDeque<Expression>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ASTNode {
|
impl fmt::Display for ASTNode {
|
||||||
@ -315,7 +317,6 @@ impl Parser {
|
|||||||
Some(Identifier(_)) => try!(self.identifier_expr()),
|
Some(Identifier(_)) => try!(self.identifier_expr()),
|
||||||
Some(Token::LParen) => try!(self.paren_expr()),
|
Some(Token::LParen) => try!(self.paren_expr()),
|
||||||
Some(e) => {
|
Some(e) => {
|
||||||
panic!();
|
|
||||||
return ParseError::result_from_str("Expected primary expression");
|
return ParseError::result_from_str("Expected primary expression");
|
||||||
}
|
}
|
||||||
None => return ParseError::result_from_str("Expected primary expression received EoI"),
|
None => return ParseError::result_from_str("Expected primary expression received EoI"),
|
||||||
@ -324,28 +325,29 @@ impl Parser {
|
|||||||
|
|
||||||
fn conditional_expr(&mut self) -> ParseResult<Expression> {
|
fn conditional_expr(&mut self) -> ParseResult<Expression> {
|
||||||
use tokenizer::Token::*;
|
use tokenizer::Token::*;
|
||||||
|
use self::Expression::*;
|
||||||
expect!(self, Keyword(Kw::If));
|
expect!(self, Keyword(Kw::If));
|
||||||
let test = try!(self.expression());
|
let test = try!(self.expression());
|
||||||
expect!(self, Keyword(Kw::Then));
|
expect!(self, Keyword(Kw::Then));
|
||||||
let mut then_block = Vec::new();
|
let mut then_block = VecDeque::new();
|
||||||
loop {
|
loop {
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
None | Some(Keyword(Kw::Else)) | Some(Keyword(Kw::End)) => break,
|
None | Some(Keyword(Kw::Else)) | Some(Keyword(Kw::End)) => break,
|
||||||
_ => {
|
_ => {
|
||||||
let exp = try!(self.expression());
|
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() {
|
let else_block = if let Some(Keyword(Kw::Else)) = self.peek() {
|
||||||
self.next();
|
self.next();
|
||||||
let mut else_exprs = Vec::new();
|
let mut else_exprs = VecDeque::new();
|
||||||
loop {
|
loop {
|
||||||
match self.peek() {
|
match self.peek() {
|
||||||
None | Some(Keyword(Kw::End)) => break,
|
None | Some(Keyword(Kw::End)) => break,
|
||||||
_ => {
|
_ => {
|
||||||
let exp = try!(self.expression());
|
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));
|
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<Expression> {
|
fn identifier_expr(&mut self) -> ParseResult<Expression> {
|
||||||
|
Loading…
Reference in New Issue
Block a user