Support for methods. Started support for functions defined in script but not yet ready

This commit is contained in:
jonathandturner 2016-03-01 15:16:10 -05:00
parent 419781cfb6
commit a8fa76c2fc
4 changed files with 297 additions and 128 deletions

View File

@ -6,7 +6,6 @@ use std::fmt;
use parser::{lex, parse, Expr, Stmt };
use fn_register::FnRegister;
//use ops::{add_boxes, sub_boxes, mult_boxes, div_boxes};
use std::ops::{Add, Sub, Mul, Div};
use std::cmp::{Ord, Eq};
@ -91,6 +90,7 @@ fn or(x: bool, y: bool) -> bool {
}
pub struct Engine {
pub fns_arity_3: HashMap<String, Vec<Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>>>>,
pub fns_arity_2: HashMap<String, Vec<Box<Fn(&mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>>>>,
pub fns_arity_1: HashMap<String, Vec<Box<Fn(&mut Box<Any>)->Result<Box<Any>, EvalError>>>>,
pub fns_arity_0: HashMap<String, Vec<Box<Fn()->Result<Box<Any>, EvalError>>>>,
@ -98,8 +98,8 @@ pub struct Engine {
}
impl Engine {
pub fn call_fn_0_arg(&self, name: &str) -> Result<Box<Any>, EvalError> {
match self.fns_arity_0.get(name) {
pub fn call_fn_0_arg(fns_arity_0: &HashMap<String, Vec<Box<Fn()->Result<Box<Any>, EvalError>>>>, name: &str) -> Result<Box<Any>, EvalError> {
match fns_arity_0.get(name) {
Some(vf) => {
for f in vf {
let invoke = f();
@ -114,8 +114,10 @@ impl Engine {
}
}
pub fn call_fn_1_arg(&self, name: &str, arg1: &mut Box<Any>) -> Result<Box<Any>, EvalError> {
match self.fns_arity_1.get(name) {
pub fn call_fn_1_arg(fns_arity_1: &HashMap<String, Vec<Box<Fn(&mut Box<Any>)->Result<Box<Any>, EvalError>>>>,
name: &str, arg1: &mut Box<Any>) -> Result<Box<Any>, EvalError> {
match fns_arity_1.get(name) {
Some(vf) => {
for f in vf {
let invoke = f(arg1);
@ -130,8 +132,10 @@ impl Engine {
}
}
pub fn call_fn_2_arg(&self, name: &str, arg1: &mut Box<Any>, arg2: &mut Box<Any>) -> Result<Box<Any>, EvalError> {
match self.fns_arity_2.get(name) {
pub fn call_fn_2_arg(fns_arity_2: &HashMap<String, Vec<Box<Fn(&mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>>>>,
name: &str, arg1: &mut Box<Any>, arg2: &mut Box<Any>) -> Result<Box<Any>, EvalError> {
match fns_arity_2.get(name) {
Some(vf) => {
for f in vf {
let invoke = f(arg1, arg2);
@ -146,6 +150,24 @@ impl Engine {
}
}
pub fn call_fn_3_arg(fns_arity_3: &HashMap<String, Vec<Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>>>>,
name: &str, arg1: &mut Box<Any>, arg2: &mut Box<Any>, arg3: &mut Box<Any>) -> Result<Box<Any>, EvalError> {
match fns_arity_3.get(name) {
Some(vf) => {
for f in vf {
let invoke = f(arg1, arg2, arg3);
match invoke {
Ok(v) => return Ok(v),
_ => ()
}
};
Err(EvalError::FunctionArgMismatch)
}
None => Err(EvalError::FunctionNotFound)
}
}
fn register_type<T: Clone+Any>(&mut self) {
fn clone_helper<T: Clone>(t:T)->T { t.clone() };
@ -196,20 +218,61 @@ impl Engine {
_ => Err(EvalError::VariableNotFound)
}
}
Expr::Call(ref fn_name, ref args) => {
Expr::FnCall(ref fn_name, ref args) => {
if args.len() == 0 {
self.call_fn_0_arg(&fn_name)
Engine::call_fn_0_arg(&self.fns_arity_0, &fn_name)
}
else if args.len() == 1 {
let mut arg = try!(self.eval_expr(&args[0]));
self.call_fn_1_arg(&fn_name, &mut arg)
Engine::call_fn_1_arg(&self.fns_arity_1, &fn_name, &mut arg)
}
else if args.len() == 2 {
let mut arg1 = try!(self.eval_expr(&args[0]));
let mut arg2 = try!(self.eval_expr(&args[1]));
self.call_fn_2_arg(&fn_name, &mut arg1, &mut arg2)
Engine::call_fn_2_arg(&self.fns_arity_2, &fn_name, &mut arg1, &mut arg2)
}
else if args.len() == 3 {
let mut arg1 = try!(self.eval_expr(&args[0]));
let mut arg2 = try!(self.eval_expr(&args[1]));
let mut arg3 = try!(self.eval_expr(&args[1]));
Engine::call_fn_3_arg(&self.fns_arity_3, &fn_name, &mut arg1, &mut arg2, &mut arg3)
}
else {
Err(EvalError::FunctionCallNotSupported)
}
}
Expr::MethodCall(ref target, ref fn_name, ref args) => {
if args.len() == 0 {
for &mut (ref name, ref mut val) in &mut self.scope.iter_mut().rev() {
if *target == *name {
return Engine::call_fn_1_arg(&self.fns_arity_1, &fn_name, val);
}
}
Err(EvalError::VariableNotFound)
}
else if args.len() == 1 {
let mut arg = try!(self.eval_expr(&args[0]));
for &mut (ref name, ref mut val) in &mut self.scope.iter_mut().rev() {
if *target == *name {
return Engine::call_fn_2_arg(&self.fns_arity_2, &fn_name, val, &mut arg);
}
}
Err(EvalError::VariableNotFound)
}
else if args.len() == 2 {
let mut arg1 = try!(self.eval_expr(&args[0]));
let mut arg2 = try!(self.eval_expr(&args[1]));
for &mut (ref name, ref mut val) in &mut self.scope.iter_mut().rev() {
if *target == *name {
return Engine::call_fn_3_arg(&self.fns_arity_3, &fn_name, val, &mut arg1, &mut arg2);
}
}
Err(EvalError::VariableNotFound)
}
else {
Err(EvalError::FunctionCallNotSupported)
@ -295,8 +358,19 @@ impl Engine {
let tree = parse(&mut peekables);
match tree {
Ok(os) => {
Ok((ref os, ref fns)) => {
let mut x: Result<Box<Any>, EvalError> = Ok(Box::new(()));
for f in fns {
if f.params.len() == 0 {
let local_f = f.clone();
let ent = self.fns_arity_0.entry(local_f.name).or_insert(Vec::new());
let wrapped : Box<Fn()->Result<Box<Any>, EvalError>> =
Box::new(move || { Ok(Box::new(0)) } );
//move || { self.eval_stmt(&local_f.body) }
(*ent).push(wrapped);
}
}
for o in os {
x = self.eval_stmt(&o)
}
@ -342,8 +416,8 @@ impl Engine {
reg_cmp!(engine, "<=", lte, i32, i64, u32, u64);
reg_cmp!(engine, ">", gt, i32, i64, u32, u64);
reg_cmp!(engine, ">=", gte, i32, i64, u32, u64);
reg_cmp!(engine, "==", eq, i32, i64, u32, u64);
reg_cmp!(engine, "!=", ne, i32, i64, u32, u64);
reg_cmp!(engine, "==", eq, i32, i64, u32, u64, bool);
reg_cmp!(engine, "!=", ne, i32, i64, u32, u64, bool);
reg_op!(engine, "||", or, bool);
reg_op!(engine, "&&", and, bool);
@ -354,6 +428,7 @@ impl Engine {
fns_arity_0: HashMap::new(),
fns_arity_1: HashMap::new(),
fns_arity_2: HashMap::new(),
fns_arity_3: HashMap::new(),
scope: Vec::new()
};
@ -463,4 +538,35 @@ fn test_var_scope() {
}
}
#[test]
fn test_method_call() {
#[derive(Debug, Clone)]
struct TestStruct {
x: i32
}
impl TestStruct {
fn update(&mut self) {
self.x += 1000;
}
fn new() -> TestStruct {
TestStruct { x: 1 }
}
}
let mut engine = Engine::new();
engine.register_type::<TestStruct>();
&(TestStruct::update as fn(&mut TestStruct)->()).register(&mut engine, "update");
&(TestStruct::new as fn()->TestStruct).register(&mut engine, "new_ts");
if let Ok(result) = engine.eval("var x = new_ts(); x.update(); x".to_string()).unwrap().downcast::<TestStruct>() {
assert_eq!(result.x, 1001);
}
else {
assert!(false);
}
}

View File

@ -7,6 +7,48 @@ pub trait FnRegister {
fn register(self, engine: &mut Engine, name: &str);
}
impl<T: Any+Clone, U: Any+Clone, V: Any+Clone, W: Any+Clone> FnRegister for fn(&mut T, U, V)->W {
fn register(self, engine: &mut Engine, name: &str) {
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>> =
Box::new(
move |x: &mut Box<Any>, y: &mut Box<Any>, z: &mut Box<Any>| {
let inside1 = (*x).downcast_mut() as Option<&mut T>;
let inside2 = (*y).downcast_mut() as Option<&mut U>;
let inside3 = (*z).downcast_mut() as Option<&mut V>;
match (inside1, inside2, inside3) {
(Some(b), Some(c), Some(d)) => Ok(Box::new(self(b, c.clone(), d.clone())) as Box<Any>),
_ => Err(EvalError::FunctionArgMismatch)
}
}
);
let ent = engine.fns_arity_3.entry(name.to_string()).or_insert(Vec::new());
(*ent).push(wrapped);
}
}
impl<T: Any+Clone, U: Any+Clone, V: Any+Clone, W: Any+Clone> FnRegister for fn(T, U, V)->W {
fn register(self, engine: &mut Engine, name: &str) {
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>> =
Box::new(
move |x: &mut Box<Any>, y: &mut Box<Any>, z: &mut Box<Any>| {
let inside1 = (*x).downcast_mut() as Option<&mut T>;
let inside2 = (*y).downcast_mut() as Option<&mut U>;
let inside3 = (*z).downcast_mut() as Option<&mut V>;
match (inside1, inside2, inside3) {
(Some(b), Some(c), Some(d)) => Ok(Box::new(self(b.clone(), c.clone(), d.clone())) as Box<Any>),
_ => Err(EvalError::FunctionArgMismatch)
}
}
);
let ent = engine.fns_arity_3.entry(name.to_string()).or_insert(Vec::new());
(*ent).push(wrapped);
}
}
impl<T: Any+Clone, U: Any+Clone, V: Any+Clone> FnRegister for fn(&mut T, U)->V {
fn register(self, engine: &mut Engine, name: &str) {
let wrapped : Box<Fn(&mut Box<Any>, &mut Box<Any>)->Result<Box<Any>, EvalError>> =

View File

@ -14,78 +14,9 @@ mod parser;
// Todo (in no particular order):
// * Function in script
// * Doc some examples
// * Refactor identifer to not require inlining of clone lookup in engine
// * String constants
// * Remove empty box values?
// * Methods
/*
fn simple_fn(x: i32) -> bool { x == 1 }
fn simple_fn2(x: &mut i32) -> bool { x.clone() == 2 }
#[derive(Debug)]
struct TestStruct {
x: i32
}
impl TestStruct {
fn update(&mut self) {
self.x += 1000;
}
fn new() -> TestStruct {
TestStruct { x: 1 }
}
}
#[derive(Debug)]
struct TestStruct2 {
x: bool
}
impl TestStruct2 {
fn update(&mut self) {
self.x = true;
}
}
fn engine_test() {
let mut engine = Engine::new();
&(simple_fn as fn(i32)->bool).register(&mut engine, "simple_fn");
&(simple_fn2 as fn(&mut i32)->bool).register(&mut engine, "simple_fn2");
&(TestStruct::update as fn(&mut TestStruct)->()).register(&mut engine, "update");
&(TestStruct::new as fn()->TestStruct).register(&mut engine, "newteststruct");
&(showit as fn(x: &mut Box<Debug>)->()).register(&mut engine, "showit");
&(TestStruct2::update as fn(&mut TestStruct2)->()).register(&mut engine, "update");
let mut arg : Box<Any> = Box::new(2);
println!("Result: {:?}", engine.call_fn_1_arg("simple_fn" , &mut arg).unwrap().downcast::<bool>());
println!("Result: {:?}", engine.call_fn_1_arg("simple_fn2", &mut arg).unwrap().downcast::<bool>());
println!("Intentional errors: ");
println!(" Result: {:?}", engine.call_fn_1_arg("simple_fn3", &mut arg));
arg = Box::new("foo");
println!(" Result: {:?}", engine.call_fn_1_arg("simple_fn", &mut arg));
let mut ts : Box<Any> = Box::new(TestStruct { x: 6 });
engine.call_fn_1_arg("update" , &mut ts);
let result : Result<Box<TestStruct>, Box<Any>> = ts.downcast();
println!("TS: {:?}", result);
let myts = engine.call_fn_0_arg("newteststruct").unwrap().downcast::<TestStruct>();
println!("MyTS: {:?}", myts);
let mut mybox = Box::new(Box::new(56) as Box<Debug>) as Box<Any>;
engine.call_fn_1_arg("showit", &mut mybox);
let mut ts2 : Box<Any> = Box::new(TestStruct2 { x: false });
engine.call_fn_1_arg("update" , &mut ts2);
let result2 : Result<Box<TestStruct2>, Box<Any>> = ts2.downcast();
println!("TS2: {:?}", result2);
}
*/
// * Refactor identifer to not require inlining of clone lookup in engine?
fn showit<T: Display>(x: &mut T) -> () {
println!("{}", x)

View File

@ -13,7 +13,10 @@ pub enum ParseError {
MissingLCurly,
MissingRCurly,
MalformedCallExpr,
VarExpectsIdentifier
VarExpectsIdentifier,
ExpectedMethodInvocation,
FnMissingName,
FnMissingParams
}
impl Error for ParseError {
@ -26,7 +29,10 @@ impl Error for ParseError {
ParseError::MissingLCurly => "Expected '{'",
ParseError::MissingRCurly => "Expected '}'",
ParseError::MalformedCallExpr => "Call contains bad expression",
ParseError::VarExpectsIdentifier => "'var' expects the name of a variable"
ParseError::VarExpectsIdentifier => "'var' expects the name of a variable",
ParseError::ExpectedMethodInvocation => "Expected method call after '.'",
ParseError::FnMissingName => "Function declaration is missing name",
ParseError::FnMissingParams => "Function declaration is missing parameters"
}
}
@ -41,17 +47,25 @@ impl fmt::Display for ParseError {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct FnDef {
pub name: String,
pub params: Vec<String>,
pub body: Box<Stmt>
}
#[derive(Debug, Clone)]
pub enum Stmt { If(Box<Expr>, Box<Stmt>), While(Box<Expr>, Box<Stmt>), Var(String, Option<Box<Expr>>),
Block(Box<Vec<Stmt>>), Expr(Box<Expr>) }
#[derive(Debug)]
pub enum Expr { IntConst(i32), Identifier(String), Call(String, Box<Vec<Expr>>), Assignment(Box<Expr>, Box<Expr>), True, False }
#[derive(Debug, Clone)]
pub enum Expr { IntConst(i32), Identifier(String), FnCall(String, Box<Vec<Expr>>), MethodCall(String, String, Box<Vec<Expr>>),
Assignment(Box<Expr>, Box<Expr>), True, False }
#[derive(Debug)]
pub enum Token { Int(i32), Id(String), LCurly, RCurly, LParen, RParen, LSquare, RSquare,
Plus, Minus, Multiply, Divide, Semicolon, Colon, Comma, Equals, True, False, Var, If, While,
LessThan, GreaterThan, Bang, LessThanEqual, GreaterThanEqual, EqualTo, NotEqualTo, Pipe, Or, Ampersand, And }
Plus, Minus, Multiply, Divide, Semicolon, Colon, Comma, Period, Equals, True, False, Var, If, While,
LessThan, GreaterThan, Bang, LessThanEqual, GreaterThanEqual, EqualTo, NotEqualTo, Pipe, Or, Ampersand, And, Fn }
pub struct TokenIterator<'a> {
char_stream: Peekable<Chars<'a>>
@ -110,6 +124,9 @@ impl<'a> Iterator for TokenIterator<'a> {
else if out == "while" {
return Some(Token::While);
}
else if out == "fn" {
return Some(Token::Fn);
}
else {
return Some(Token::Id(out));
}
@ -127,6 +144,7 @@ impl<'a> Iterator for TokenIterator<'a> {
';' => { return Some(Token::Semicolon); },
':' => { return Some(Token::Colon); },
',' => { return Some(Token::Comma); },
'.' => { return Some(Token::Period); },
'=' => {
match self.char_stream.peek() {
Some(&'=') => {self.char_stream.next(); return Some(Token::EqualTo); },
@ -204,17 +222,35 @@ fn parse_paren_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr,
}
fn parse_ident_expr<'a>(id: String, input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
let id2 = match input.peek() {
Some(&Token::Period) => {
input.next();
match input.next() {
Some(Token::Id(ref s)) => {
s.clone()
}
_ => return Err(ParseError::ExpectedMethodInvocation)
}
},
_ => String::new()
};
match input.peek() {
Some(&Token::LParen) => (),
Some(&Token::LParen) => {input.next();},
_ => return Ok(Expr::Identifier(id))
}
input.next();
let mut args = Vec::new();
match input.peek() {
Some(&Token::RParen) => {input.next(); return Ok(Expr::Call(id, Box::new(args)))},
Some(&Token::RParen) => {
input.next();
if id2 == "" {
return Ok(Expr::FnCall(id, Box::new(args)))
}
else {
return Ok(Expr::MethodCall(id, id2, Box::new(args)))
}
},
_ => ()
}
@ -227,7 +263,15 @@ fn parse_ident_expr<'a>(id: String, input: &mut Peekable<TokenIterator<'a>>) ->
}
match input.peek() {
Some(&Token::RParen) => {input.next(); return Ok(Expr::Call(id, Box::new(args)))},
Some(&Token::RParen) => {
input.next();
if id2 == "" {
return Ok(Expr::FnCall(id, Box::new(args)))
}
else {
return Ok(Expr::MethodCall(id, id2, Box::new(args)))
}
},
Some(&Token::Comma) => (),
_ => return Err(ParseError::MalformedCallExpr)
}
@ -280,19 +324,19 @@ fn parse_binop<'a>(input: &mut Peekable<TokenIterator<'a>>, prec: i32, lhs: Expr
}
lhs_curr = match op_token {
Token::Plus => Expr::Call("+".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::Minus => Expr::Call("-".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::Multiply => Expr::Call("*".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::Divide => Expr::Call("/".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::Plus => Expr::FnCall("+".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::Minus => Expr::FnCall("-".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::Multiply => Expr::FnCall("*".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::Divide => Expr::FnCall("/".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::Equals => Expr::Assignment(Box::new(lhs_curr), Box::new(rhs)),
Token::EqualTo => Expr::Call("==".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::NotEqualTo => Expr::Call("!=".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::LessThan => Expr::Call("<".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::LessThanEqual => Expr::Call("<=".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::GreaterThan => Expr::Call(">".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::GreaterThanEqual => Expr::Call(">=".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::Or => Expr::Call("||".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::And => Expr::Call("&&".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::EqualTo => Expr::FnCall("==".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::NotEqualTo => Expr::FnCall("!=".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::LessThan => Expr::FnCall("<".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::LessThanEqual => Expr::FnCall("<=".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::GreaterThan => Expr::FnCall(">".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::GreaterThanEqual => Expr::FnCall(">=".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::Or => Expr::FnCall("||".to_string(), Box::new(vec![lhs_curr, rhs])),
Token::And => Expr::FnCall("&&".to_string(), Box::new(vec![lhs_curr, rhs])),
_ => return Err(ParseError::UnknownOperator)
};
}
@ -349,7 +393,27 @@ fn parse_block<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, Pars
input.next();
let stmts = try!(parse_stmts(input, true));
let mut stmts = Vec::new();
let skip_body = match input.peek() {
Some(& Token::RCurly) => true,
_ => false
};
if !skip_body {
while let Some(_) = input.peek() {
stmts.push(try!(parse_stmt(input)));
match input.peek() {
Some(& Token::Semicolon) => {input.next();},
_ => ()
}
match input.peek() {
Some(& Token::RCurly) => break,
_ => ()
}
}
}
match input.peek() {
Some(& Token::RCurly) => {input.next(); Ok(Stmt::Block(Box::new(stmts)))},
@ -372,35 +436,61 @@ fn parse_stmt<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, Parse
}
}
fn parse_stmts<'a>(input: &mut Peekable<TokenIterator<'a>>, check_for_rcurly: bool) -> Result<Vec<Stmt>, ParseError> {
let mut result = Vec::new();
fn parse_fn<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<FnDef, ParseError> {
input.next();
if check_for_rcurly {
match input.peek() {
Some(& Token::RCurly) => return Ok(result),
_ => ()
let name = match input.next() {
Some(Token::Id(ref s)) => s.clone(),
_ => return Err(ParseError::FnMissingName)
};
match input.peek() {
Some(&Token::LParen) => {input.next();},
_ => return Err(ParseError::FnMissingParams)
}
let mut params = Vec::new();
let skip_params = match input.peek() {
Some(&Token::RParen) => { input.next(); true }
_ => false
};
if !skip_params {
loop {
match input.next() {
Some(Token::RParen) => { break },
Some(Token::Comma) => (),
Some(Token::Id(ref s)) => { params.push(s.clone()); },
_ => return Err(ParseError::MalformedCallExpr)
}
}
}
let body = try!(parse_block(input));
Ok(FnDef{name: name, params: params, body: Box::new(body)})
}
fn parse_top_level<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<(Vec<Stmt>, Vec<FnDef>), ParseError> {
let mut stmts = Vec::new();
let mut fndefs = Vec::new();
while let Some(_) = input.peek() {
result.push(try!(parse_stmt(input)));
match input.peek() {
Some(& Token::Fn) => fndefs.push(try!(parse_fn(input))),
_ => stmts.push(try!(parse_stmt(input)))
}
match input.peek() {
Some(& Token::Semicolon) => {input.next();},
_ => ()
}
if check_for_rcurly {
match input.peek() {
Some(& Token::RCurly) => return Ok(result),
_ => ()
}
}
}
Ok(result)
Ok((stmts, fndefs))
}
pub fn parse<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Vec<Stmt>, ParseError> {
let result = parse_stmts(input, false);
result
pub fn parse<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<(Vec<Stmt>, Vec<FnDef>), ParseError> {
parse_top_level(input)
}