Refine expression nesting level.

This commit is contained in:
Stephen Chung 2022-12-08 17:18:40 +08:00
parent 544b86adef
commit a391f26920
4 changed files with 106 additions and 128 deletions

View File

@ -54,6 +54,7 @@ Enhancements
* Line-style doc-comments are now merged into a single string to avoid creating many strings. Block-style doc-comments continue to be independent strings. * Line-style doc-comments are now merged into a single string to avoid creating many strings. Block-style doc-comments continue to be independent strings.
* Block-style doc-comments are now "un-indented" for better formatting. * Block-style doc-comments are now "un-indented" for better formatting.
* Doc-comments on plugin modules are now captured in the module's `doc` field. * Doc-comments on plugin modules are now captured in the module's `doc` field.
* Expression nesting levels is refined such that it grows less excessively for common patterns.
Version 1.11.0 Version 1.11.0

View File

@ -6,6 +6,7 @@ use crate::{Dynamic, Engine, EvalContext, Position, RhaiResultOf};
use std::prelude::v1::*; use std::prelude::v1::*;
/// Information on a variable definition. /// Information on a variable definition.
#[derive(Debug, Hash)]
#[non_exhaustive] #[non_exhaustive]
pub struct VarDefInfo<'a> { pub struct VarDefInfo<'a> {
/// Name of the variable to be defined. /// Name of the variable to be defined.

View File

@ -343,14 +343,15 @@ impl ParseSettings {
/// Create a new `ParseSettings` with one higher expression level. /// Create a new `ParseSettings` with one higher expression level.
#[inline] #[inline]
pub fn level_up(&self) -> ParseResult<Self> { pub fn level_up(&self) -> ParseResult<Self> {
let level = self.level + 1;
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if self.max_expr_depth > 0 && level > self.max_expr_depth { if self.max_expr_depth > 0 && self.level >= self.max_expr_depth {
return Err(PERR::ExprTooDeep.into_err(self.pos)); return Err(PERR::ExprTooDeep.into_err(self.pos));
} }
Ok(Self { level, ..*self }) Ok(Self {
level: self.level + 1,
..*self
})
} }
} }
@ -537,50 +538,7 @@ fn parse_var_name(input: &mut TokenStream) -> ParseResult<(SmartString, Position
} }
} }
/// Parse a symbol.
#[cfg(not(feature = "no_custom_syntax"))]
fn parse_symbol(input: &mut TokenStream) -> ParseResult<(SmartString, Position)> {
match input.next().expect(NEVER_ENDS) {
// Symbol
(token, pos) if token.is_standard_symbol() => Ok((token.literal_syntax().into(), pos)),
// Reserved symbol
(Token::Reserved(s), pos) if !is_valid_identifier(s.as_str()) => Ok((*s, pos)),
// Bad symbol
(Token::LexError(err), pos) => Err(err.into_err(pos)),
// Not a symbol
(.., pos) => Err(PERR::MissingSymbol(String::new()).into_err(pos)),
}
}
impl Engine { impl Engine {
/// Parse `(` expr `)`
fn parse_paren_expr(
&self,
input: &mut TokenStream,
state: &mut ParseState,
lib: &mut FnLib,
settings: ParseSettings,
) -> ParseResult<Expr> {
// ( ...
let mut settings = settings;
settings.pos = eat_token(input, Token::LeftParen);
let expr = self.parse_expr(input, state, lib, settings.level_up()?)?;
match input.next().expect(NEVER_ENDS) {
// ( ... )
(Token::RightParen, ..) => Ok(expr),
// ( <error>
(Token::LexError(err), pos) => Err(err.into_err(pos)),
// ( ... ???
(.., pos) => Err(PERR::MissingToken(
Token::RightParen.into(),
"for a matching ( in this expression".into(),
)
.into_err(pos)),
}
}
/// Parse a function call. /// Parse a function call.
fn parse_fn_call( fn parse_fn_call(
&self, &self,
@ -974,10 +932,7 @@ impl Engine {
) )
.into_err(*pos)) .into_err(*pos))
} }
_ => { _ => array.push(self.parse_expr(input, state, lib, settings.level_up()?)?),
let expr = self.parse_expr(input, state, lib, settings.level_up()?)?;
array.push(expr);
}
} }
match input.peek().expect(NEVER_ENDS) { match input.peek().expect(NEVER_ENDS) {
@ -1139,10 +1094,10 @@ impl Engine {
settings: ParseSettings, settings: ParseSettings,
) -> ParseResult<Stmt> { ) -> ParseResult<Stmt> {
// switch ... // switch ...
let mut settings = settings; let mut settings = settings.level_up()?;
settings.pos = eat_token(input, Token::Switch); settings.pos = eat_token(input, Token::Switch);
let item = self.parse_expr(input, state, lib, settings.level_up()?)?; let item = self.parse_expr(input, state, lib, settings)?;
match input.next().expect(NEVER_ENDS) { match input.next().expect(NEVER_ENDS) {
(Token::LeftBrace, ..) => (), (Token::LeftBrace, ..) => (),
@ -1201,7 +1156,7 @@ impl Engine {
loop { loop {
let filter = state.expr_filter; let filter = state.expr_filter;
state.expr_filter = |t| t != &Token::Pipe; state.expr_filter = |t| t != &Token::Pipe;
let expr = self.parse_expr(input, state, lib, settings.level_up()?); let expr = self.parse_expr(input, state, lib, settings);
state.expr_filter = filter; state.expr_filter = filter;
match expr { match expr {
@ -1219,7 +1174,7 @@ impl Engine {
let condition = if match_token(input, Token::If).0 { let condition = if match_token(input, Token::If).0 {
ensure_not_statement_expr(input, "a boolean")?; ensure_not_statement_expr(input, "a boolean")?;
let guard = self let guard = self
.parse_expr(input, state, lib, settings.level_up()?)? .parse_expr(input, state, lib, settings)?
.ensure_bool_expr()?; .ensure_bool_expr()?;
ensure_not_assignment(input)?; ensure_not_assignment(input)?;
guard guard
@ -1244,16 +1199,13 @@ impl Engine {
let (action_expr, need_comma) = let (action_expr, need_comma) =
if !settings.has_flag(ParseSettingFlags::DISALLOW_STATEMENTS_IN_BLOCKS) { if !settings.has_flag(ParseSettingFlags::DISALLOW_STATEMENTS_IN_BLOCKS) {
let stmt = self.parse_stmt(input, state, lib, settings.level_up()?)?; let stmt = self.parse_stmt(input, state, lib, settings)?;
let need_comma = !stmt.is_self_terminated(); let need_comma = !stmt.is_self_terminated();
let stmt_block: StmtBlock = stmt.into(); let stmt_block: StmtBlock = stmt.into();
(Expr::Stmt(stmt_block.into()), need_comma) (Expr::Stmt(stmt_block.into()), need_comma)
} else { } else {
( (self.parse_expr(input, state, lib, settings)?, true)
self.parse_expr(input, state, lib, settings.level_up()?)?,
true,
)
}; };
let has_condition = !matches!(condition, Expr::BoolConstant(true, ..)); let has_condition = !matches!(condition, Expr::BoolConstant(true, ..));
@ -1410,7 +1362,26 @@ impl Engine {
} }
// ( - grouped expression // ( - grouped expression
Token::LeftParen => self.parse_paren_expr(input, state, lib, settings.level_up()?)?, Token::LeftParen => {
settings.pos = eat_token(input, Token::LeftParen);
let expr = self.parse_expr(input, state, lib, settings.level_up()?)?;
match input.next().expect(NEVER_ENDS) {
// ( ... )
(Token::RightParen, ..) => expr,
// ( <error>
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
// ( ... ???
(.., pos) => {
return Err(PERR::MissingToken(
Token::RightParen.into(),
"for a matching ( in this expression".into(),
)
.into_err(pos))
}
}
}
// If statement is allowed to act as expressions // If statement is allowed to act as expressions
Token::If if settings.has_option(LangOptions::IF_EXPR) => Expr::Stmt(Box::new( Token::If if settings.has_option(LangOptions::IF_EXPR) => Expr::Stmt(Box::new(
@ -1528,6 +1499,7 @@ impl Engine {
// Interpolated string // Interpolated string
Token::InterpolatedString(..) => { Token::InterpolatedString(..) => {
let mut segments = StaticVec::<Expr>::new(); let mut segments = StaticVec::<Expr>::new();
let settings = settings.level_up()?;
match input.next().expect(NEVER_ENDS) { match input.next().expect(NEVER_ENDS) {
(Token::InterpolatedString(s), ..) if s.is_empty() => (), (Token::InterpolatedString(s), ..) if s.is_empty() => (),
@ -1540,7 +1512,7 @@ impl Engine {
} }
loop { loop {
let expr = match self.parse_block(input, state, lib, settings.level_up()?)? { let expr = match self.parse_block(input, state, lib, settings)? {
block @ Stmt::Block(..) => Expr::Stmt(Box::new(block.into())), block @ Stmt::Block(..) => Expr::Stmt(Box::new(block.into())),
stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt), stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt),
}; };
@ -1784,7 +1756,6 @@ impl Engine {
let (.., ns, _, name) = *x; let (.., ns, _, name) = *x;
settings.pos = pos; settings.pos = pos;
let settings = settings.level_up()?;
self.parse_fn_call(input, state, lib, name, no_args, true, ns, settings)? self.parse_fn_call(input, state, lib, name, no_args, true, ns, settings)?
} }
// Function call // Function call
@ -1792,7 +1763,6 @@ impl Engine {
let (.., ns, _, name) = *x; let (.., ns, _, name) = *x;
let no_args = t == Token::Unit; let no_args = t == Token::Unit;
settings.pos = pos; settings.pos = pos;
let settings = settings.level_up()?;
self.parse_fn_call(input, state, lib, name, no_args, false, ns, settings)? self.parse_fn_call(input, state, lib, name, no_args, false, ns, settings)?
} }
// module access // module access
@ -2014,7 +1984,7 @@ impl Engine {
// <EOF> // <EOF>
Token::EOF => Err(PERR::UnexpectedEOF.into_err(settings.pos)), Token::EOF => Err(PERR::UnexpectedEOF.into_err(settings.pos)),
// All other tokens // All other tokens
_ => self.parse_primary(input, state, lib, false, settings.level_up()?), _ => self.parse_primary(input, state, lib, false, settings),
} }
} }
@ -2123,33 +2093,6 @@ impl Engine {
} }
} }
/// Parse an operator-assignment expression (if any).
fn parse_op_assignment_stmt(
&self,
input: &mut TokenStream,
state: &mut ParseState,
lib: &mut FnLib,
lhs: Expr,
settings: ParseSettings,
) -> ParseResult<Stmt> {
let (op, pos) = match input.peek().expect(NEVER_ENDS) {
// var = ...
(Token::Equals, ..) => (NO_TOKEN, eat_token(input, Token::Equals)),
// var op= ...
(token, ..) if token.is_op_assignment() => {
input.next().map(|(op, pos)| (op, pos)).expect(NEVER_ENDS)
}
// Not op-assignment
_ => return Ok(Stmt::Expr(lhs.into())),
};
let mut settings = settings;
settings.pos = pos;
let rhs = self.parse_expr(input, state, lib, settings.level_up()?)?;
Self::make_assignment_stmt(op, state, lhs, rhs, pos)
}
/// Make a dot expression. /// Make a dot expression.
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
fn make_dot_expr( fn make_dot_expr(
@ -2545,7 +2488,20 @@ impl Engine {
inputs.push(Expr::Variable((None, ns, 0, name).into(), None, pos)); inputs.push(Expr::Variable((None, ns, 0, name).into(), None, pos));
} }
CUSTOM_SYNTAX_MARKER_SYMBOL => { CUSTOM_SYNTAX_MARKER_SYMBOL => {
let (symbol, pos) = parse_symbol(input)?; let (symbol, pos) = match input.next().expect(NEVER_ENDS) {
// Standard symbol
(token, pos) if token.is_standard_symbol() => {
Ok((token.literal_syntax().into(), pos))
}
// Reserved symbol
(Token::Reserved(s), pos) if !is_valid_identifier(s.as_str()) => {
Ok((*s, pos))
}
// Bad symbol
(Token::LexError(err), pos) => Err(err.into_err(pos)),
// Not a symbol
(.., pos) => Err(PERR::MissingSymbol(String::new()).into_err(pos)),
}?;
let symbol = state.get_interned_string(symbol); let symbol = state.get_interned_string(symbol);
segments.push(symbol.clone()); segments.push(symbol.clone());
tokens.push(state.get_interned_string(CUSTOM_SYNTAX_MARKER_SYMBOL)); tokens.push(state.get_interned_string(CUSTOM_SYNTAX_MARKER_SYMBOL));
@ -2677,8 +2633,9 @@ impl Engine {
// Parse expression normally. // Parse expression normally.
let precedence = Precedence::new(1); let precedence = Precedence::new(1);
let lhs = self.parse_unary(input, state, lib, settings.level_up()?)?; let settings = settings.level_up()?;
self.parse_binary_op(input, state, lib, precedence, lhs, settings.level_up()?) let lhs = self.parse_unary(input, state, lib, settings)?;
self.parse_binary_op(input, state, lib, precedence, lhs, settings)
} }
/// Parse an if statement. /// Parse an if statement.
@ -2690,25 +2647,25 @@ impl Engine {
settings: ParseSettings, settings: ParseSettings,
) -> ParseResult<Stmt> { ) -> ParseResult<Stmt> {
// if ... // if ...
let mut settings = settings; let mut settings = settings.level_up()?;
settings.pos = eat_token(input, Token::If); settings.pos = eat_token(input, Token::If);
// if guard { if_body } // if guard { if_body }
ensure_not_statement_expr(input, "a boolean")?; ensure_not_statement_expr(input, "a boolean")?;
let guard = self let guard = self
.parse_expr(input, state, lib, settings.level_up()?)? .parse_expr(input, state, lib, settings)?
.ensure_bool_expr()?; .ensure_bool_expr()?;
ensure_not_assignment(input)?; ensure_not_assignment(input)?;
let if_body = self.parse_block(input, state, lib, settings.level_up()?)?; let if_body = self.parse_block(input, state, lib, settings)?;
// if guard { if_body } else ... // if guard { if_body } else ...
let else_body = if match_token(input, Token::Else).0 { let else_body = if match_token(input, Token::Else).0 {
if let (Token::If, ..) = input.peek().expect(NEVER_ENDS) { if let (Token::If, ..) = input.peek().expect(NEVER_ENDS) {
// if guard { if_body } else if ... // if guard { if_body } else if ...
self.parse_if(input, state, lib, settings.level_up()?)? self.parse_if(input, state, lib, settings)?
} else { } else {
// if guard { if_body } else { else-body } // if guard { if_body } else { else-body }
self.parse_block(input, state, lib, settings.level_up()?)? self.parse_block(input, state, lib, settings)?
} }
} else { } else {
Stmt::Noop(Position::NONE) Stmt::Noop(Position::NONE)
@ -2728,14 +2685,14 @@ impl Engine {
lib: &mut FnLib, lib: &mut FnLib,
settings: ParseSettings, settings: ParseSettings,
) -> ParseResult<Stmt> { ) -> ParseResult<Stmt> {
let mut settings = settings; let mut settings = settings.level_up()?;
// while|loops ... // while|loops ...
let (guard, token_pos) = match input.next().expect(NEVER_ENDS) { let (guard, token_pos) = match input.next().expect(NEVER_ENDS) {
(Token::While, pos) => { (Token::While, pos) => {
ensure_not_statement_expr(input, "a boolean")?; ensure_not_statement_expr(input, "a boolean")?;
let expr = self let expr = self
.parse_expr(input, state, lib, settings.level_up()?)? .parse_expr(input, state, lib, settings)?
.ensure_bool_expr()?; .ensure_bool_expr()?;
ensure_not_assignment(input)?; ensure_not_assignment(input)?;
(expr, pos) (expr, pos)
@ -2746,7 +2703,7 @@ impl Engine {
settings.pos = token_pos; settings.pos = token_pos;
settings.flags |= ParseSettingFlags::BREAKABLE; settings.flags |= ParseSettingFlags::BREAKABLE;
let body = self.parse_block(input, state, lib, settings.level_up()?)?; let body = self.parse_block(input, state, lib, settings)?;
Ok(Stmt::While((guard, body.into()).into(), settings.pos)) Ok(Stmt::While((guard, body.into()).into(), settings.pos))
} }
@ -2760,7 +2717,7 @@ impl Engine {
settings: ParseSettings, settings: ParseSettings,
) -> ParseResult<Stmt> { ) -> ParseResult<Stmt> {
// do ... // do ...
let mut settings = settings; let mut settings = settings.level_up()?;
let orig_breakable = settings.flags.contains(ParseSettingFlags::BREAKABLE); let orig_breakable = settings.flags.contains(ParseSettingFlags::BREAKABLE);
settings.flags |= ParseSettingFlags::BREAKABLE; settings.flags |= ParseSettingFlags::BREAKABLE;
@ -2768,7 +2725,7 @@ impl Engine {
// do { body } [while|until] guard // do { body } [while|until] guard
let body = self.parse_block(input, state, lib, settings.level_up()?)?; let body = self.parse_block(input, state, lib, settings)?;
let negated = match input.next().expect(NEVER_ENDS) { let negated = match input.next().expect(NEVER_ENDS) {
(Token::While, ..) => ASTFlags::NONE, (Token::While, ..) => ASTFlags::NONE,
@ -2787,7 +2744,7 @@ impl Engine {
ensure_not_statement_expr(input, "a boolean")?; ensure_not_statement_expr(input, "a boolean")?;
let guard = self let guard = self
.parse_expr(input, state, lib, settings.level_up()?)? .parse_expr(input, state, lib, settings)?
.ensure_bool_expr()?; .ensure_bool_expr()?;
ensure_not_assignment(input)?; ensure_not_assignment(input)?;
@ -2803,7 +2760,7 @@ impl Engine {
settings: ParseSettings, settings: ParseSettings,
) -> ParseResult<Stmt> { ) -> ParseResult<Stmt> {
// for ... // for ...
let mut settings = settings; let mut settings = settings.level_up()?;
settings.pos = eat_token(input, Token::For); settings.pos = eat_token(input, Token::For);
// for name ... // for name ...
@ -2856,7 +2813,7 @@ impl Engine {
// for name in expr { body } // for name in expr { body }
ensure_not_statement_expr(input, "a boolean")?; ensure_not_statement_expr(input, "a boolean")?;
let expr = self let expr = self
.parse_expr(input, state, lib, settings.level_up()?)? .parse_expr(input, state, lib, settings)?
.ensure_iterable()?; .ensure_iterable()?;
let counter_var = Ident { let counter_var = Ident {
@ -2883,7 +2840,7 @@ impl Engine {
}; };
settings.flags |= ParseSettingFlags::BREAKABLE; settings.flags |= ParseSettingFlags::BREAKABLE;
let body = self.parse_block(input, state, lib, settings.level_up()?)?; let body = self.parse_block(input, state, lib, settings)?;
state.stack.as_deref_mut().unwrap().rewind(prev_stack_len); state.stack.as_deref_mut().unwrap().rewind(prev_stack_len);
@ -3008,11 +2965,11 @@ impl Engine {
settings: ParseSettings, settings: ParseSettings,
) -> ParseResult<Stmt> { ) -> ParseResult<Stmt> {
// import ... // import ...
let mut settings = settings; let mut settings = settings.level_up()?;
settings.pos = eat_token(input, Token::Import); settings.pos = eat_token(input, Token::Import);
// import expr ... // import expr ...
let expr = self.parse_expr(input, state, lib, settings.level_up()?)?; let expr = self.parse_expr(input, state, lib, settings)?;
let export = if match_token(input, Token::As).0 { let export = if match_token(input, Token::As).0 {
// import expr as name ... // import expr as name ...
@ -3052,6 +3009,7 @@ impl Engine {
match input.peek().expect(NEVER_ENDS) { match input.peek().expect(NEVER_ENDS) {
(Token::Let, pos) => { (Token::Let, pos) => {
let pos = *pos; let pos = *pos;
let settings = settings.level_up()?;
let mut stmt = let mut stmt =
self.parse_let(input, state, lib, AccessMode::ReadWrite, true, settings)?; self.parse_let(input, state, lib, AccessMode::ReadWrite, true, settings)?;
stmt.set_position(pos); stmt.set_position(pos);
@ -3059,6 +3017,7 @@ impl Engine {
} }
(Token::Const, pos) => { (Token::Const, pos) => {
let pos = *pos; let pos = *pos;
let settings = settings.level_up()?;
let mut stmt = let mut stmt =
self.parse_let(input, state, lib, AccessMode::ReadOnly, true, settings)?; self.parse_let(input, state, lib, AccessMode::ReadOnly, true, settings)?;
stmt.set_position(pos); stmt.set_position(pos);
@ -3099,7 +3058,7 @@ impl Engine {
settings: ParseSettings, settings: ParseSettings,
) -> ParseResult<Stmt> { ) -> ParseResult<Stmt> {
// Must start with { // Must start with {
let mut settings = settings; let mut settings = settings.level_up()?;
settings.pos = match input.next().expect(NEVER_ENDS) { settings.pos = match input.next().expect(NEVER_ENDS) {
(Token::LeftBrace, pos) => pos, (Token::LeftBrace, pos) => pos,
(Token::LexError(err), pos) => return Err(err.into_err(pos)), (Token::LexError(err), pos) => return Err(err.into_err(pos)),
@ -3115,7 +3074,7 @@ impl Engine {
let mut statements = StaticVec::new_const(); let mut statements = StaticVec::new_const();
if settings.has_flag(ParseSettingFlags::DISALLOW_STATEMENTS_IN_BLOCKS) { if settings.has_flag(ParseSettingFlags::DISALLOW_STATEMENTS_IN_BLOCKS) {
let stmt = self.parse_expr_stmt(input, state, lib, settings.level_up()?)?; let stmt = self.parse_expr_stmt(input, state, lib, settings)?;
statements.push(stmt); statements.push(stmt);
// Must end with } // Must end with }
@ -3153,7 +3112,7 @@ impl Engine {
// Parse statements inside the block // Parse statements inside the block
settings.flags &= !ParseSettingFlags::GLOBAL_LEVEL; settings.flags &= !ParseSettingFlags::GLOBAL_LEVEL;
let stmt = self.parse_stmt(input, state, lib, settings.level_up()?)?; let stmt = self.parse_stmt(input, state, lib, settings)?;
if stmt.is_noop() { if stmt.is_noop() {
continue; continue;
@ -3215,9 +3174,24 @@ impl Engine {
let mut settings = settings; let mut settings = settings;
settings.pos = input.peek().expect(NEVER_ENDS).1; settings.pos = input.peek().expect(NEVER_ENDS).1;
let expr = self.parse_expr(input, state, lib, settings.level_up()?)?; let expr = self.parse_expr(input, state, lib, settings)?;
let stmt = self.parse_op_assignment_stmt(input, state, lib, expr, settings.level_up()?)?;
Ok(stmt) let (op, pos) = match input.peek().expect(NEVER_ENDS) {
// var = ...
(Token::Equals, ..) => (NO_TOKEN, eat_token(input, Token::Equals)),
// var op= ...
(token, ..) if token.is_op_assignment() => {
input.next().map(|(op, pos)| (op, pos)).expect(NEVER_ENDS)
}
// Not op-assignment
_ => return Ok(Stmt::Expr(expr.into())),
};
settings.pos = pos;
let rhs = self.parse_expr(input, state, lib, settings)?;
Self::make_assignment_stmt(op, state, expr, rhs, pos)
} }
/// Parse a single statement. /// Parse a single statement.
@ -3292,6 +3266,7 @@ impl Engine {
(Token::EOF, pos) => return Ok(Stmt::Noop(*pos)), (Token::EOF, pos) => return Ok(Stmt::Noop(*pos)),
(x, pos) => (x, *pos), (x, pos) => (x, *pos),
}; };
settings.pos = token_pos; settings.pos = token_pos;
match token { match token {
@ -3503,11 +3478,11 @@ impl Engine {
settings: ParseSettings, settings: ParseSettings,
) -> ParseResult<Stmt> { ) -> ParseResult<Stmt> {
// try ... // try ...
let mut settings = settings; let mut settings = settings.level_up()?;
settings.pos = eat_token(input, Token::Try); settings.pos = eat_token(input, Token::Try);
// try { try_block } // try { try_block }
let try_block = self.parse_block(input, state, lib, settings.level_up()?)?; let try_block = self.parse_block(input, state, lib, settings)?;
// try { try_block } catch // try { try_block } catch
let (matched, catch_pos) = match_token(input, Token::Catch); let (matched, catch_pos) = match_token(input, Token::Catch);
@ -3546,7 +3521,7 @@ impl Engine {
}; };
// try { try_block } catch ( var ) { catch_block } // try { try_block } catch ( var ) { catch_block }
let catch_block = self.parse_block(input, state, lib, settings.level_up()?)?; let catch_block = self.parse_block(input, state, lib, settings)?;
if !catch_var.is_empty() { if !catch_var.is_empty() {
// Remove the error variable from the stack // Remove the error variable from the stack
@ -3575,7 +3550,7 @@ impl Engine {
settings: ParseSettings, settings: ParseSettings,
#[cfg(feature = "metadata")] comments: impl IntoIterator<Item = Identifier>, #[cfg(feature = "metadata")] comments: impl IntoIterator<Item = Identifier>,
) -> ParseResult<ScriptFnDef> { ) -> ParseResult<ScriptFnDef> {
let settings = settings; let settings = settings.level_up()?;
let (token, pos) = input.next().expect(NEVER_ENDS); let (token, pos) = input.next().expect(NEVER_ENDS);
@ -3642,7 +3617,7 @@ impl Engine {
// Parse function body // Parse function body
let body = match input.peek().expect(NEVER_ENDS) { let body = match input.peek().expect(NEVER_ENDS) {
(Token::LeftBrace, ..) => self.parse_block(input, state, lib, settings.level_up()?)?, (Token::LeftBrace, ..) => self.parse_block(input, state, lib, settings)?,
(.., pos) => return Err(PERR::FnMissingBody(name.into()).into_err(*pos)), (.., pos) => return Err(PERR::FnMissingBody(name.into()).into_err(*pos)),
} }
.into(); .into();
@ -3734,7 +3709,7 @@ impl Engine {
lib: &mut FnLib, lib: &mut FnLib,
settings: ParseSettings, settings: ParseSettings,
) -> ParseResult<(Expr, ScriptFnDef)> { ) -> ParseResult<(Expr, ScriptFnDef)> {
let settings = settings; let settings = settings.level_up()?;
let mut params_list = StaticVec::<ImmutableString>::new_const(); let mut params_list = StaticVec::<ImmutableString>::new_const();
if input.next().expect(NEVER_ENDS).0 != Token::Or && !match_token(input, Token::Pipe).0 { if input.next().expect(NEVER_ENDS).0 != Token::Or && !match_token(input, Token::Pipe).0 {
@ -3781,7 +3756,7 @@ impl Engine {
} }
// Parse function body // Parse function body
let body = self.parse_stmt(input, state, lib, settings.level_up()?)?; let body = self.parse_stmt(input, state, lib, settings)?;
// External variables may need to be processed in a consistent order, // External variables may need to be processed in a consistent order,
// so extract them into a list. // so extract them into a list.

View File

@ -55,7 +55,8 @@ fn test_stack_overflow_parsing() -> Result<(), Box<EvalAltResult>> {
" "
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 +
1
", ",
)?; )?;
@ -67,7 +68,7 @@ fn test_stack_overflow_parsing() -> Result<(), Box<EvalAltResult>> {
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 +
1 1 + 2
" "
) )
.expect_err("should error") .expect_err("should error")
@ -92,7 +93,7 @@ fn test_stack_overflow_parsing() -> Result<(), Box<EvalAltResult>> {
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9
", ",
)?; )?;
@ -109,7 +110,7 @@ fn test_stack_overflow_parsing() -> Result<(), Box<EvalAltResult>> {
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0 +
1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 0
" "
) )
.expect_err("should error") .expect_err("should error")