Fix unary parsing.

This commit is contained in:
Stephen Chung 2021-11-13 09:50:49 +08:00
parent 42bef4c28c
commit a227963f7a
4 changed files with 24 additions and 16 deletions

View File

@ -9,6 +9,7 @@ Bug fixes
* Printing of integral floating-point numbers is fixed (used to only prints `0.0`). * Printing of integral floating-point numbers is fixed (used to only prints `0.0`).
* `func!()` calls now work properly under `no_closure`. * `func!()` calls now work properly under `no_closure`.
* Fixed parsing of unary negation such that expressions like `if foo { ... } -x` parses correctly.
Version 1.1.2 Version 1.1.2

View File

@ -28,7 +28,7 @@ impl Engine {
pub(crate) fn global_namespace(&self) -> &Module { pub(crate) fn global_namespace(&self) -> &Module {
self.global_modules self.global_modules
.first() .first()
.expect("global_modules contains at least one module") .expect("global_modules not empty")
} }
/// Get a mutable reference to the global namespace module /// Get a mutable reference to the global namespace module
/// (which is the first module in `global_modules`). /// (which is the first module in `global_modules`).
@ -37,9 +37,9 @@ impl Engine {
Shared::get_mut( Shared::get_mut(
self.global_modules self.global_modules
.first_mut() .first_mut()
.expect("global_modules contains at least one module"), .expect("global_modules not empty"),
) )
.expect("global namespace module is never shared") .expect("global namespace never shared")
} }
/// Register a custom function with the [`Engine`]. /// Register a custom function with the [`Engine`].
/// ///

View File

@ -347,14 +347,18 @@ fn ensure_not_assignment(input: &mut TokenStream) -> Result<(), ParseError> {
} }
/// Consume a particular [token][Token], checking that it is the expected one. /// Consume a particular [token][Token], checking that it is the expected one.
///
/// # Panics
///
/// Panics if the next token is not the expected one.
#[inline] #[inline]
fn eat_token(input: &mut TokenStream, token: Token) -> Position { fn eat_token(input: &mut TokenStream, expected_token: Token) -> Position {
let (t, pos) = input.next().expect(NEVER_ENDS); let (t, pos) = input.next().expect(NEVER_ENDS);
if t != token { if t != expected_token {
unreachable!( unreachable!(
"expecting {} (found {}) at {}", "expecting {} (found {}) at {}",
token.syntax(), expected_token.syntax(),
t.syntax(), t.syntax(),
pos pos
); );
@ -1479,8 +1483,9 @@ fn parse_unary(
match token { match token {
// -expr // -expr
Token::UnaryMinus => { Token::Minus | Token::UnaryMinus => {
let pos = eat_token(input, Token::UnaryMinus); let token = token.clone();
let pos = eat_token(input, token);
match parse_unary(input, state, lib, settings.level_up())? { match parse_unary(input, state, lib, settings.level_up())? {
// Negative integer // Negative integer
@ -1516,8 +1521,9 @@ fn parse_unary(
} }
} }
// +expr // +expr
Token::UnaryPlus => { Token::Plus | Token::UnaryPlus => {
let pos = eat_token(input, Token::UnaryPlus); let token = token.clone();
let pos = eat_token(input, token);
match parse_unary(input, state, lib, settings.level_up())? { match parse_unary(input, state, lib, settings.level_up())? {
expr @ Expr::IntegerConstant(_, _) => Ok(expr), expr @ Expr::IntegerConstant(_, _) => Ok(expr),
@ -2753,9 +2759,9 @@ fn parse_stmt(
let (token, token_pos) = match input.peek().expect(NEVER_ENDS) { let (token, token_pos) = match input.peek().expect(NEVER_ENDS) {
(Token::EOF, pos) => return Ok(Stmt::Noop(*pos)), (Token::EOF, pos) => return Ok(Stmt::Noop(*pos)),
x => x, (x, pos) => (x, *pos),
}; };
settings.pos = *token_pos; settings.pos = token_pos;
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?; settings.ensure_level_within_max_limit(state.max_expr_depth)?;
@ -2764,7 +2770,7 @@ fn parse_stmt(
// ; - empty statement // ; - empty statement
Token::SemiColon => { Token::SemiColon => {
eat_token(input, Token::SemiColon); eat_token(input, Token::SemiColon);
Ok(Stmt::Noop(settings.pos)) Ok(Stmt::Noop(token_pos))
} }
// { - statements block // { - statements block
@ -2772,7 +2778,7 @@ fn parse_stmt(
// fn ... // fn ...
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Token::Fn if !settings.is_global => Err(PERR::WrongFnDefinition.into_err(settings.pos)), Token::Fn if !settings.is_global => Err(PERR::WrongFnDefinition.into_err(token_pos)),
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Token::Fn | Token::Private => { Token::Fn | Token::Private => {
@ -2853,7 +2859,7 @@ fn parse_stmt(
let pos = eat_token(input, Token::Break); let pos = eat_token(input, Token::Break);
Ok(Stmt::BreakLoop(AST_OPTION_BREAK_OUT, pos)) Ok(Stmt::BreakLoop(AST_OPTION_BREAK_OUT, pos))
} }
Token::Continue | Token::Break => Err(PERR::LoopBreak.into_err(settings.pos)), Token::Continue | Token::Break => Err(PERR::LoopBreak.into_err(token_pos)),
Token::Return | Token::Throw => { Token::Return | Token::Throw => {
let (return_type, token_pos) = input let (return_type, token_pos) = input
@ -2896,7 +2902,7 @@ fn parse_stmt(
Token::Import => parse_import(input, state, lib, settings.level_up()), Token::Import => parse_import(input, state, lib, settings.level_up()),
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
Token::Export if !settings.is_global => Err(PERR::WrongExport.into_err(settings.pos)), Token::Export if !settings.is_global => Err(PERR::WrongExport.into_err(token_pos)),
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
Token::Export => parse_export(input, state, lib, settings.level_up()), Token::Export => parse_export(input, state, lib, settings.level_up()),

View File

@ -806,6 +806,7 @@ impl Token {
match self { match self {
LexError(_) | LexError(_) |
SemiColon | // ; - is unary SemiColon | // ; - is unary
Colon | // #{ foo: - is unary
Comma | // ( ... , -expr ) - is unary Comma | // ( ... , -expr ) - is unary
//Period | //Period |
LeftBrace | // { -expr } - is unary LeftBrace | // { -expr } - is unary