Function bodies can contain statements now

This commit is contained in:
greg 2017-01-03 02:11:59 -08:00
parent f158b6c712
commit 06771979df
3 changed files with 31 additions and 20 deletions

11
closure.schala Normal file
View File

@ -0,0 +1,11 @@
fn outer()
fn inner(a)
a + 10
end
inner(20) + 8.3
end
outer()

View File

@ -29,7 +29,7 @@ impl<'a> Evaluator<'a> {
pub fn run(&mut self, ast: AST) -> Vec<String> { pub fn run(&mut self, ast: AST) -> Vec<String> {
ast.into_iter() ast.into_iter()
.map(|astnode| format!("{}", self.reduce(astnode))) .map(|astnode| format!("{}", self.reduction_loop(astnode)))
.collect() .collect()
} }
@ -102,7 +102,7 @@ impl Expression {
} }
impl<'a> Evaluator<'a> { impl<'a> Evaluator<'a> {
fn reduce(&mut self, mut node: ASTNode) -> ASTNode { fn reduction_loop(&mut self, mut node: ASTNode) -> ASTNode {
loop { loop {
node = self.step(node); node = self.step(node);
if !node.is_reducible() { if !node.is_reducible() {
@ -290,16 +290,16 @@ impl<'a> Evaluator<'a> {
evaluator.add_binding(binding.clone(), expr.clone()); evaluator.add_binding(binding.clone(), expr.clone());
} }
let nodes = function.body.iter().map(|expr| ASTNode::ExprNode(expr.clone())); let nodes = function.body.iter().map(|node| node.clone());
let mut retval = Null; let mut retval = ExprNode(Null);
for n in nodes { for n in nodes {
retval = match evaluator.reduce(n) { retval = evaluator.reduction_loop(n);
ExprNode(expr) => expr,
FuncDefNode(_) => panic!("This should never happen! A maximally-reduced node\
should never be a function definition!")
};
} }
(retval, None) match retval {
ExprNode(expr) => (expr, None),
FuncDefNode(_) => panic!("This should never happen! A maximally-reduced node\
should never be a function definition!")
}
} }
} }

View File

@ -6,7 +6,7 @@ use std::collections::VecDeque;
// program := (statement delimiter ?)* // program := (statement delimiter ?)*
// delimiter := Newline | Semicolon // delimiter := Newline | Semicolon
// statement := declaration | expression // statement := declaration | expression
// declaraion := Fn prototype (statement)* End // declaration := Fn prototype (statement)* End
// prototype := identifier LParen identlist RParen // prototype := identifier LParen identlist RParen
// identlist := Ident (Comma Ident)* | e // identlist := Ident (Comma Ident)* | e
// exprlist := Expression (Comma Expression)* | e // exprlist := Expression (Comma Expression)* | e
@ -29,7 +29,7 @@ pub enum ASTNode {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Function { pub struct Function {
pub prototype: Prototype, pub prototype: Prototype,
pub body: Vec<Expression>, pub body: Vec<ASTNode>,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -205,7 +205,7 @@ impl Parser {
use tokenizer::Token::*; use tokenizer::Token::*;
expect!(self, Keyword(Kw::Fn)); expect!(self, Keyword(Kw::Fn));
let prototype = try!(self.prototype()); let prototype = try!(self.prototype());
let body: Vec<Expression> = try!(self.body()); let body: Vec<ASTNode> = try!(self.body());
expect!(self, Keyword(Kw::End)); expect!(self, Keyword(Kw::End));
Ok(ASTNode::FuncDefNode(Function { Ok(ASTNode::FuncDefNode(Function {
prototype: prototype, prototype: prototype,
@ -258,9 +258,9 @@ impl Parser {
Ok(args) Ok(args)
} }
fn body(&mut self) -> ParseResult<Vec<Expression>> { fn body(&mut self) -> ParseResult<Vec<ASTNode>> {
use tokenizer::Token::*; use tokenizer::Token::*;
let mut exprs = Vec::new(); let mut statements = Vec::new();
loop { loop {
match self.peek() { match self.peek() {
Some(ref t) if is_delimiter(t) => { Some(ref t) if is_delimiter(t) => {
@ -269,12 +269,12 @@ impl Parser {
} }
Some(Keyword(Kw::End)) => break, Some(Keyword(Kw::End)) => break,
_ => { _ => {
let expr = try!(self.expression()); let ast_node = try!(self.statement());
exprs.push(expr); statements.push(ast_node);
} }
} }
} }
Ok(exprs) Ok(statements)
} }
fn expression(&mut self) -> ParseResult<Expression> { fn expression(&mut self) -> ParseResult<Expression> {
@ -460,14 +460,14 @@ mod tests {
parsetest!( parsetest!(
"fn a() 1 + 2 end", "fn a() 1 + 2 end",
&[FuncDefNode(Function {prototype: Prototype { ref name, ref parameters }, ref body})], &[FuncDefNode(Function {prototype: Prototype { ref name, ref parameters }, ref body})],
match &body[..] { &[BinExp(_, box Number(1.0), box Number(2.0))] => true, _ => false } match &body[..] { &[ExprNode(BinExp(_, box Number(1.0), box Number(2.0)))] => true, _ => false }
&& name == "a" && match &parameters[..] { &[] => true, _ => false } && name == "a" && match &parameters[..] { &[] => true, _ => false }
); );
parsetest!( parsetest!(
"fn a(x,y) 1 + 2 end", "fn a(x,y) 1 + 2 end",
&[FuncDefNode(Function {prototype: Prototype { ref name, ref parameters }, ref body})], &[FuncDefNode(Function {prototype: Prototype { ref name, ref parameters }, ref body})],
match &body[..] { &[BinExp(_, box Number(1.0), box Number(2.0))] => true, _ => false } match &body[..] { &[ExprNode(BinExp(_, box Number(1.0), box Number(2.0)))] => true, _ => false }
&& name == "a" && *parameters == ["x","y"] && name == "a" && *parameters == ["x","y"]
); );
} }