Better error messages for function definitions.
This commit is contained in:
parent
a1591ae45b
commit
95d0b2e620
33
README.md
33
README.md
@ -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
|
||||||
|
351
src/parser.rs
351
src/parser.rs
@ -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> {
|
||||||
|
Loading…
Reference in New Issue
Block a user