Better error messages for function definitions.

This commit is contained in:
Stephen Chung 2020-03-03 16:23:55 +08:00
parent a1591ae45b
commit 95d0b2e620
2 changed files with 250 additions and 134 deletions

View File

@ -11,7 +11,7 @@ Rhai's current feature set:
* Support for overloaded functions * Support for overloaded functions
* No additional dependencies * No additional dependencies
**Note:** Currently, the version is 0.10.0-alpha1, so the language and APIs may change before they stabilize.* **Note:** Currently, the version is 0.10.1, so the language and APIs may change before they stabilize.*
## Installation ## Installation
@ -19,7 +19,7 @@ You can install Rhai using crates by adding this line to your dependencies:
```toml ```toml
[dependencies] [dependencies]
rhai = "0.10.0" rhai = "0.10.1"
``` ```
or simply: or simply:
@ -190,7 +190,7 @@ fn main() {
} }
``` ```
To return a `Dynamic` value, simply `Box` it and return it. To return a [`Dynamic`] value, simply `Box` it and return it.
```rust ```rust
fn decide(yes_no: bool) -> Dynamic { fn decide(yes_no: bool) -> Dynamic {
@ -514,7 +514,7 @@ fn add(x, y) {
return x + y; return x + y;
} }
print(add(2, 3)) print(add(2, 3));
``` ```
Just like in Rust, you can also use an implicit return. Just like in Rust, you can also use an implicit return.
@ -524,9 +524,29 @@ fn add(x, y) {
x + y x + y
} }
print(add(2, 3)) print(add(2, 3));
``` ```
Remember that functions defined in script always take [`Dynamic`] arguments (i.e. the arguments can be of any type).
Furthermore, functions can only be defined at the top level, never inside a block or another function.
```rust
// Top level is OK
fn add(x, y) {
x + y
}
// The following will not compile
fn do_addition(x) {
fn add_y(n) { // functions cannot be defined inside another function
n + y
}
add_y(x)
}
```
## Arrays ## Arrays
You can create arrays of values, and then access them with numeric indices. You can create arrays of values, and then access them with numeric indices.
@ -740,3 +760,6 @@ my_str += 12345;
my_str == "abcABC12345" my_str == "abcABC12345"
``` ```
[`Dynamic`]: #values-and-types

View File

@ -25,7 +25,7 @@ impl Error for LexError {
LERR::MalformedEscapeSequence => "Unexpected values in escape sequence", LERR::MalformedEscapeSequence => "Unexpected values in escape sequence",
LERR::MalformedNumber => "Unexpected characters in number", LERR::MalformedNumber => "Unexpected characters in number",
LERR::MalformedChar => "Char constant not a single character", LERR::MalformedChar => "Char constant not a single character",
LERR::InputError(_) => "Imput error", LERR::InputError(_) => "Input error",
} }
} }
} }
@ -52,6 +52,7 @@ pub enum ParseErrorType {
MalformedCallExpr, MalformedCallExpr,
MalformedIndexExpr, MalformedIndexExpr,
VarExpectsIdentifier, VarExpectsIdentifier,
WrongFnDefinition,
FnMissingName, FnMissingName,
FnMissingParams, FnMissingParams,
} }
@ -177,6 +178,7 @@ impl Error for ParseError {
PERR::VarExpectsIdentifier => "Expecting name of a variable", PERR::VarExpectsIdentifier => "Expecting name of a variable",
PERR::FnMissingName => "Expecting name in function declaration", PERR::FnMissingName => "Expecting name in function declaration",
PERR::FnMissingParams => "Expecting parameters in function declaration", PERR::FnMissingParams => "Expecting parameters in function declaration",
PERR::WrongFnDefinition => "Function definitions must be at top level and cannot be inside a block or another function",
} }
} }
@ -330,6 +332,80 @@ pub enum Token {
} }
impl Token { impl Token {
pub fn syntax(&self) -> std::borrow::Cow<'static, str> {
use self::Token::*;
match *self {
IntegerConstant(ref s) => s.to_string().into(),
FloatConstant(ref s) => s.to_string().into(),
Identifier(ref s) => s.to_string().into(),
CharConstant(ref s) => s.to_string().into(),
LexErr(ref err) => err.to_string().into(),
ref token => (match token {
StringConst(_) => "string",
LeftBrace => "{",
RightBrace => "}",
LeftParen => "(",
RightParen => ")",
LeftBracket => "[",
RightBracket => "]",
Plus => "+",
UnaryPlus => "+",
Minus => "-",
UnaryMinus => "-",
Multiply => "*",
Divide => "/",
SemiColon => ";",
Colon => ":",
Comma => ",",
Period => ".",
Equals => "=",
True => "true",
False => "false",
Let => "let",
If => "if",
Else => "else",
While => "while",
Loop => "loop",
LessThan => "<",
GreaterThan => ">",
Bang => "!",
LessThanEqualsTo => "<=",
GreaterThanEqualsTo => ">=",
EqualsTo => "==",
NotEqualsTo => "!=",
Pipe => "|",
Or => "||",
Ampersand => "&",
And => "&&",
Fn => "fn",
Break => "break",
Return => "return",
PlusAssign => "+=",
MinusAssign => "-=",
MultiplyAssign => "*=",
DivideAssign => "/=",
LeftShiftAssign => "<<=",
RightShiftAssign => ">>=",
AndAssign => "&=",
OrAssign => "|=",
XOrAssign => "^=",
LeftShift => "<<",
RightShift => ">>",
XOr => "^",
Modulo => "%",
ModuloAssign => "%=",
PowerOf => "~",
PowerOfAssign => "~=",
For => "for",
In => "in",
_ => panic!(),
})
.into(),
}
}
// if another operator is after these, it's probably an unary operator // if another operator is after these, it's probably an unary operator
// not sure about fn's name // not sure about fn's name
pub fn is_next_unary(&self) -> bool { pub fn is_next_unary(&self) -> bool {
@ -1240,21 +1316,20 @@ fn parse_array_expr<'a>(
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
let mut arr = Vec::new(); let mut arr = Vec::new();
let skip_contents = match input.peek() { match input.peek() {
Some(&(Token::RightBracket, _)) => true, Some(&(Token::RightBracket, _)) => (),
_ => false,
};
if !skip_contents { _ => {
while let Some(_) = input.peek() { while input.peek().is_some() {
arr.push(parse_expr(input)?); arr.push(parse_expr(input)?);
if let Some(&(Token::Comma, _)) = input.peek() { if let Some(&(Token::Comma, _)) = input.peek() {
input.next(); input.next();
} }
if let Some(&(Token::RightBracket, _)) = input.peek() { if let Some(&(Token::RightBracket, _)) = input.peek() {
break; break;
}
} }
} }
} }
@ -1271,34 +1346,27 @@ fn parse_array_expr<'a>(
fn parse_primary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> { fn parse_primary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
match input.next() { match input.next() {
Some((token, pos)) => match token { Some((Token::IntegerConstant(x), pos)) => Ok(Expr::IntegerConstant(x, pos)),
Token::IntegerConstant(x) => Ok(Expr::IntegerConstant(x, pos)), Some((Token::FloatConstant(x), pos)) => Ok(Expr::FloatConstant(x, pos)),
Token::FloatConstant(x) => Ok(Expr::FloatConstant(x, pos)), Some((Token::StringConst(s), pos)) => Ok(Expr::StringConstant(s, pos)),
Token::StringConst(s) => Ok(Expr::StringConstant(s, pos)), Some((Token::CharConstant(c), pos)) => Ok(Expr::CharConstant(c, pos)),
Token::CharConstant(c) => Ok(Expr::CharConstant(c, pos)), Some((Token::Identifier(s), pos)) => parse_ident_expr(s, input, pos),
Token::Identifier(s) => parse_ident_expr(s, input, pos), Some((Token::LeftParen, pos)) => parse_paren_expr(input, pos),
Token::LeftParen => parse_paren_expr(input, pos), Some((Token::LeftBracket, pos)) => parse_array_expr(input, pos),
Token::LeftBracket => parse_array_expr(input, pos), Some((Token::True, pos)) => Ok(Expr::True(pos)),
Token::True => Ok(Expr::True(pos)), Some((Token::False, pos)) => Ok(Expr::False(pos)),
Token::False => Ok(Expr::False(pos)), Some((Token::LexErr(le), pos)) => Err(ParseError(PERR::BadInput(le.to_string()), pos)),
Token::LexErr(le) => Err(ParseError(PERR::BadInput(le.to_string()), pos)), Some((token, pos)) => Err(ParseError(
_ => Err(ParseError( PERR::BadInput(format!("Unexpected '{}'", token.syntax())),
PERR::BadInput(format!("Unexpected {:?} token", token)), pos,
pos, )),
)),
},
None => Err(ParseError(PERR::InputPastEndOfFile, Position::eof())), None => Err(ParseError(PERR::InputPastEndOfFile, Position::eof())),
} }
} }
fn parse_unary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> { fn parse_unary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
let (token, pos) = match input.peek() { match input.peek() {
Some((tok, tok_pos)) => (tok.clone(), *tok_pos), Some(&(Token::UnaryMinus, pos)) => {
None => return Err(ParseError(PERR::InputPastEndOfFile, Position::eof())),
};
match token {
Token::UnaryMinus => {
input.next(); input.next();
Ok(Expr::FunctionCall( Ok(Expr::FunctionCall(
@ -1308,11 +1376,11 @@ fn parse_unary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, Pars
pos, pos,
)) ))
} }
Token::UnaryPlus => { Some(&(Token::UnaryPlus, _)) => {
input.next(); input.next();
parse_primary(input) parse_primary(input)
} }
Token::Bang => { Some(&(Token::Bang, pos)) => {
input.next(); input.next();
Ok(Expr::FunctionCall( Ok(Expr::FunctionCall(
@ -1326,22 +1394,22 @@ fn parse_unary<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, Pars
} }
} }
fn parse_binop<'a>( fn parse_binary_op<'a>(
input: &mut Peekable<TokenIterator<'a>>, input: &mut Peekable<TokenIterator<'a>>,
prec: i8, precedence: i8,
lhs: Expr, lhs: Expr,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
let mut lhs_curr = lhs; let mut current_lhs = lhs;
loop { loop {
let mut curr_prec = -1; let mut current_precedence = -1;
if let Some(&(ref curr_op, _)) = input.peek() { if let Some(&(ref current_op, _)) = input.peek() {
curr_prec = get_precedence(curr_op); current_precedence = get_precedence(current_op);
} }
if curr_prec < prec { if current_precedence < precedence {
return Ok(lhs_curr); return Ok(current_lhs);
} }
if let Some((op_token, pos)) = input.next() { if let Some((op_token, pos)) = input.next() {
@ -1349,30 +1417,32 @@ fn parse_binop<'a>(
let mut rhs = parse_unary(input)?; let mut rhs = parse_unary(input)?;
let mut next_prec = -1; let mut next_precedence = -1;
if let Some(&(ref next_op, _)) = input.peek() { if let Some(&(ref next_op, _)) = input.peek() {
next_prec = get_precedence(next_op); next_precedence = get_precedence(next_op);
} }
if curr_prec < next_prec { if current_precedence < next_precedence {
rhs = parse_binop(input, curr_prec + 1, rhs)?; rhs = parse_binary_op(input, current_precedence + 1, rhs)?;
} else if curr_prec >= 100 { } else if current_precedence >= 100 {
// Always bind right to left for precedence over 100 // Always bind right to left for precedence over 100
rhs = parse_binop(input, curr_prec, rhs)?; rhs = parse_binary_op(input, current_precedence, rhs)?;
} }
lhs_curr = match op_token { current_lhs = match op_token {
Token::Plus => Expr::FunctionCall("+".into(), vec![lhs_curr, rhs], None, pos), Token::Plus => Expr::FunctionCall("+".into(), vec![current_lhs, rhs], None, pos),
Token::Minus => Expr::FunctionCall("-".into(), vec![lhs_curr, rhs], None, pos), Token::Minus => Expr::FunctionCall("-".into(), vec![current_lhs, rhs], None, pos),
Token::Multiply => Expr::FunctionCall("*".into(), vec![lhs_curr, rhs], None, pos), Token::Multiply => {
Token::Divide => Expr::FunctionCall("/".into(), vec![lhs_curr, rhs], None, pos), Expr::FunctionCall("*".into(), vec![current_lhs, rhs], None, pos)
}
Token::Divide => Expr::FunctionCall("/".into(), vec![current_lhs, rhs], None, pos),
Token::Equals => Expr::Assignment(Box::new(lhs_curr), Box::new(rhs)), Token::Equals => Expr::Assignment(Box::new(current_lhs), Box::new(rhs)),
Token::PlusAssign => { Token::PlusAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = current_lhs.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(current_lhs),
Box::new(Expr::FunctionCall( Box::new(Expr::FunctionCall(
"+".into(), "+".into(),
vec![lhs_copy, rhs], vec![lhs_copy, rhs],
@ -1382,9 +1452,9 @@ fn parse_binop<'a>(
) )
} }
Token::MinusAssign => { Token::MinusAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = current_lhs.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(current_lhs),
Box::new(Expr::FunctionCall( Box::new(Expr::FunctionCall(
"-".into(), "-".into(),
vec![lhs_copy, rhs], vec![lhs_copy, rhs],
@ -1393,35 +1463,53 @@ fn parse_binop<'a>(
)), )),
) )
} }
Token::Period => Expr::Dot(Box::new(lhs_curr), Box::new(rhs)), Token::Period => Expr::Dot(Box::new(current_lhs), Box::new(rhs)),
// Comparison operators default to false when passed invalid operands // Comparison operators default to false when passed invalid operands
Token::EqualsTo => { Token::EqualsTo => Expr::FunctionCall(
Expr::FunctionCall("==".into(), vec![lhs_curr, rhs], Some(Box::new(false)), pos) "==".into(),
} vec![current_lhs, rhs],
Token::NotEqualsTo => { Some(Box::new(false)),
Expr::FunctionCall("!=".into(), vec![lhs_curr, rhs], Some(Box::new(false)), pos) pos,
} ),
Token::LessThan => { Token::NotEqualsTo => Expr::FunctionCall(
Expr::FunctionCall("<".into(), vec![lhs_curr, rhs], Some(Box::new(false)), pos) "!=".into(),
} vec![current_lhs, rhs],
Token::LessThanEqualsTo => { Some(Box::new(false)),
Expr::FunctionCall("<=".into(), vec![lhs_curr, rhs], Some(Box::new(false)), pos) pos,
} ),
Token::GreaterThan => { Token::LessThan => Expr::FunctionCall(
Expr::FunctionCall(">".into(), vec![lhs_curr, rhs], Some(Box::new(false)), pos) "<".into(),
} vec![current_lhs, rhs],
Token::GreaterThanEqualsTo => { Some(Box::new(false)),
Expr::FunctionCall(">=".into(), vec![lhs_curr, rhs], Some(Box::new(false)), pos) pos,
} ),
Token::LessThanEqualsTo => Expr::FunctionCall(
"<=".into(),
vec![current_lhs, rhs],
Some(Box::new(false)),
pos,
),
Token::GreaterThan => Expr::FunctionCall(
">".into(),
vec![current_lhs, rhs],
Some(Box::new(false)),
pos,
),
Token::GreaterThanEqualsTo => Expr::FunctionCall(
">=".into(),
vec![current_lhs, rhs],
Some(Box::new(false)),
pos,
),
Token::Or => Expr::Or(Box::new(lhs_curr), Box::new(rhs)), Token::Or => Expr::Or(Box::new(current_lhs), Box::new(rhs)),
Token::And => Expr::And(Box::new(lhs_curr), Box::new(rhs)), Token::And => Expr::And(Box::new(current_lhs), Box::new(rhs)),
Token::XOr => Expr::FunctionCall("^".into(), vec![lhs_curr, rhs], None, pos), Token::XOr => Expr::FunctionCall("^".into(), vec![current_lhs, rhs], None, pos),
Token::OrAssign => { Token::OrAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = current_lhs.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(current_lhs),
Box::new(Expr::FunctionCall( Box::new(Expr::FunctionCall(
"|".into(), "|".into(),
vec![lhs_copy, rhs], vec![lhs_copy, rhs],
@ -1431,9 +1519,9 @@ fn parse_binop<'a>(
) )
} }
Token::AndAssign => { Token::AndAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = current_lhs.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(current_lhs),
Box::new(Expr::FunctionCall( Box::new(Expr::FunctionCall(
"&".into(), "&".into(),
vec![lhs_copy, rhs], vec![lhs_copy, rhs],
@ -1443,9 +1531,9 @@ fn parse_binop<'a>(
) )
} }
Token::XOrAssign => { Token::XOrAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = current_lhs.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(current_lhs),
Box::new(Expr::FunctionCall( Box::new(Expr::FunctionCall(
"^".into(), "^".into(),
vec![lhs_copy, rhs], vec![lhs_copy, rhs],
@ -1455,9 +1543,9 @@ fn parse_binop<'a>(
) )
} }
Token::MultiplyAssign => { Token::MultiplyAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = current_lhs.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(current_lhs),
Box::new(Expr::FunctionCall( Box::new(Expr::FunctionCall(
"*".into(), "*".into(),
vec![lhs_copy, rhs], vec![lhs_copy, rhs],
@ -1467,9 +1555,9 @@ fn parse_binop<'a>(
) )
} }
Token::DivideAssign => { Token::DivideAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = current_lhs.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(current_lhs),
Box::new(Expr::FunctionCall( Box::new(Expr::FunctionCall(
"/".into(), "/".into(),
vec![lhs_copy, rhs], vec![lhs_copy, rhs],
@ -1478,15 +1566,17 @@ fn parse_binop<'a>(
)), )),
) )
} }
Token::Pipe => Expr::FunctionCall("|".into(), vec![lhs_curr, rhs], None, pos), Token::Pipe => Expr::FunctionCall("|".into(), vec![current_lhs, rhs], None, pos),
Token::LeftShift => Expr::FunctionCall("<<".into(), vec![lhs_curr, rhs], None, pos), Token::LeftShift => {
Expr::FunctionCall("<<".into(), vec![current_lhs, rhs], None, pos)
}
Token::RightShift => { Token::RightShift => {
Expr::FunctionCall(">>".into(), vec![lhs_curr, rhs], None, pos) Expr::FunctionCall(">>".into(), vec![current_lhs, rhs], None, pos)
} }
Token::LeftShiftAssign => { Token::LeftShiftAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = current_lhs.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(current_lhs),
Box::new(Expr::FunctionCall( Box::new(Expr::FunctionCall(
"<<".into(), "<<".into(),
vec![lhs_copy, rhs], vec![lhs_copy, rhs],
@ -1496,9 +1586,9 @@ fn parse_binop<'a>(
) )
} }
Token::RightShiftAssign => { Token::RightShiftAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = current_lhs.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(current_lhs),
Box::new(Expr::FunctionCall( Box::new(Expr::FunctionCall(
">>".into(), ">>".into(),
vec![lhs_copy, rhs], vec![lhs_copy, rhs],
@ -1507,12 +1597,14 @@ fn parse_binop<'a>(
)), )),
) )
} }
Token::Ampersand => Expr::FunctionCall("&".into(), vec![lhs_curr, rhs], None, pos), Token::Ampersand => {
Token::Modulo => Expr::FunctionCall("%".into(), vec![lhs_curr, rhs], None, pos), Expr::FunctionCall("&".into(), vec![current_lhs, rhs], None, pos)
}
Token::Modulo => Expr::FunctionCall("%".into(), vec![current_lhs, rhs], None, pos),
Token::ModuloAssign => { Token::ModuloAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = current_lhs.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(current_lhs),
Box::new(Expr::FunctionCall( Box::new(Expr::FunctionCall(
"%".into(), "%".into(),
vec![lhs_copy, rhs], vec![lhs_copy, rhs],
@ -1521,11 +1613,11 @@ fn parse_binop<'a>(
)), )),
) )
} }
Token::PowerOf => Expr::FunctionCall("~".into(), vec![lhs_curr, rhs], None, pos), Token::PowerOf => Expr::FunctionCall("~".into(), vec![current_lhs, rhs], None, pos),
Token::PowerOfAssign => { Token::PowerOfAssign => {
let lhs_copy = lhs_curr.clone(); let lhs_copy = current_lhs.clone();
Expr::Assignment( Expr::Assignment(
Box::new(lhs_curr), Box::new(current_lhs),
Box::new(Expr::FunctionCall( Box::new(Expr::FunctionCall(
"~".into(), "~".into(),
vec![lhs_copy, rhs], vec![lhs_copy, rhs],
@ -1542,7 +1634,7 @@ fn parse_binop<'a>(
fn parse_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> { fn parse_expr<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Expr, ParseError> {
let lhs = parse_unary(input)?; let lhs = parse_unary(input)?;
parse_binop(input, 0, lhs) parse_binary_op(input, 0, lhs)
} }
fn parse_if<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> { fn parse_if<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, ParseError> {
@ -1640,23 +1732,24 @@ fn parse_block<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, Pars
input.next(); input.next();
let mut stmts = Vec::new(); let mut statements = Vec::new();
let skip_body = match input.peek() { match input.peek() {
Some(&(Token::RightBrace, _)) => true, Some(&(Token::RightBrace, _)) => (), // empty block
_ => false, Some(&(Token::Fn, pos)) => return Err(ParseError(PERR::WrongFnDefinition, pos)),
};
if !skip_body { _ => {
while let Some(_) = input.peek() { while input.peek().is_some() {
stmts.push(parse_stmt(input)?); // Parse statements inside the block
statements.push(parse_stmt(input)?);
if let Some(&(Token::SemiColon, _)) = input.peek() { if let Some(&(Token::SemiColon, _)) = input.peek() {
input.next(); input.next();
} }
if let Some(&(Token::RightBrace, _)) = input.peek() { if let Some(&(Token::RightBrace, _)) = input.peek() {
break; break;
}
} }
} }
} }
@ -1664,7 +1757,7 @@ fn parse_block<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<Stmt, Pars
match input.peek() { match input.peek() {
Some(&(Token::RightBrace, _)) => { Some(&(Token::RightBrace, _)) => {
input.next(); input.next();
Ok(Stmt::Block(stmts)) Ok(Stmt::Block(statements))
} }
Some(&(_, pos)) => Err(ParseError(PERR::MissingRightBrace, pos)), Some(&(_, pos)) => Err(ParseError(PERR::MissingRightBrace, pos)),
None => Err(ParseError(PERR::MissingRightBrace, Position::eof())), None => Err(ParseError(PERR::MissingRightBrace, Position::eof())),
@ -1757,13 +1850,13 @@ fn parse_fn<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<FnDef, ParseE
} }
fn parse_top_level<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<AST, ParseError> { fn parse_top_level<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<AST, ParseError> {
let mut stmts = Vec::new(); let mut statements = Vec::new();
let mut fndefs = Vec::new(); let mut functions = Vec::new();
while let Some(_) = input.peek() { while input.peek().is_some() {
match input.peek() { match input.peek() {
Some(&(Token::Fn, _)) => fndefs.push(parse_fn(input)?), Some(&(Token::Fn, _)) => functions.push(parse_fn(input)?),
_ => stmts.push(parse_stmt(input)?), _ => statements.push(parse_stmt(input)?),
} }
if let Some(&(Token::SemiColon, _)) = input.peek() { if let Some(&(Token::SemiColon, _)) = input.peek() {
@ -1771,7 +1864,7 @@ fn parse_top_level<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<AST, P
} }
} }
Ok(AST(stmts, fndefs)) Ok(AST(statements, functions))
} }
pub fn parse<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<AST, ParseError> { pub fn parse<'a>(input: &mut Peekable<TokenIterator<'a>>) -> Result<AST, ParseError> {