Merge pull request #490 from schungx/master

Update codegen version.
This commit is contained in:
Stephen Chung 2021-11-19 14:18:44 +08:00 committed by GitHub
commit df07eaacdb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 111 additions and 139 deletions

View File

@ -20,7 +20,7 @@ smallvec = { version = "1.6", default-features = false, features = ["union"] }
ahash = { version = "0.7", default-features = false } ahash = { version = "0.7", default-features = false }
num-traits = { version = "0.2", default-features = false } num-traits = { version = "0.2", default-features = false }
smartstring = { version = "0.2.7", default-features = false } smartstring = { version = "0.2.7", default-features = false }
rhai_codegen = { version = "1.1", path = "codegen", default-features = false } rhai_codegen = { version = "1.2", path = "codegen", default-features = false }
[features] [features]
default = ["ahash/std", "num-traits/std"] default = ["ahash/std", "num-traits/std"]

View File

@ -1667,11 +1667,11 @@ impl Stmt {
pub struct CustomExpr { pub struct CustomExpr {
/// List of keywords. /// List of keywords.
pub inputs: StaticVec<Expr>, pub inputs: StaticVec<Expr>,
/// List of tokens actually parsed.
pub tokens: StaticVec<Identifier>,
/// Is the current [`Scope`][crate::Scope] possibly modified by this custom statement /// Is the current [`Scope`][crate::Scope] possibly modified by this custom statement
/// (e.g. introducing a new variable)? /// (e.g. introducing a new variable)?
pub scope_may_be_changed: bool, pub scope_may_be_changed: bool,
/// List of tokens actually parsed.
pub tokens: StaticVec<Identifier>,
/// Is this custom syntax self-terminated? /// Is this custom syntax self-terminated?
pub self_terminated: bool, pub self_terminated: bool,
} }
@ -1693,7 +1693,7 @@ impl CustomExpr {
/// # Volatile Data Structure /// # Volatile Data Structure
/// ///
/// This type is volatile and may change. /// This type is volatile and may change.
#[derive(Clone, Hash)] #[derive(Debug, Clone, Hash)]
pub struct BinaryExpr { pub struct BinaryExpr {
/// LHS expression. /// LHS expression.
pub lhs: Expr, pub lhs: Expr,
@ -1711,7 +1711,7 @@ pub struct BinaryExpr {
pub struct OpAssignment<'a> { pub struct OpAssignment<'a> {
/// Hash of the op-assignment call. /// Hash of the op-assignment call.
pub hash_op_assign: u64, pub hash_op_assign: u64,
/// Hash of the underlying operator call. /// Hash of the underlying operator call (for fallback).
pub hash_op: u64, pub hash_op: u64,
/// Op-assignment operator. /// Op-assignment operator.
pub op: &'a str, pub op: &'a str,
@ -1739,10 +1739,9 @@ impl OpAssignment<'_> {
} }
} }
/// _(internals)_ An set of function call hashes. /// _(internals)_ A set of function call hashes. Exported under the `internals` feature only.
/// Exported under the `internals` feature only.
/// ///
/// Two separate hashes are pre-calculated because of the following pattern: /// Two separate hashes are pre-calculated because of the following patterns:
/// ///
/// ```ignore /// ```ignore
/// func(a, b, c); // Native: func(a, b, c) - 3 parameters /// func(a, b, c); // Native: func(a, b, c) - 3 parameters
@ -1753,17 +1752,18 @@ impl OpAssignment<'_> {
/// ``` /// ```
/// ///
/// For normal function calls, the native hash equals the script hash. /// For normal function calls, the native hash equals the script hash.
///
/// For method-style calls, the script hash contains one fewer parameter. /// For method-style calls, the script hash contains one fewer parameter.
/// ///
/// Function call hashes are used in the following manner: /// Function call hashes are used in the following manner:
/// ///
/// * First, the script hash is tried, which contains only the called function's name plus the /// * First, the script hash is tried, which contains only the called function's name plus the
/// of parameters. /// number of parameters.
/// ///
/// * Next, the actual types of arguments are hashed and _combined_ with the native hash, which is /// * Next, the actual types of arguments are hashed and _combined_ with the native hash, which is
/// then used to search for a native function. /// then used to search for a native function. In other words, a complete native function call
/// In other words, a native function call hash always contains the called function's name plus /// hash always contains the called function's name plus the types of the arguments. This is due
/// the types of the arguments. This is to due to possible function overloading for different parameter types. /// to possible function overloading for different parameter types.
/// ///
/// # Volatile Data Structure /// # Volatile Data Structure
/// ///

View File

@ -422,12 +422,11 @@ fn parse_paren_expr(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
let mut settings = settings;
#[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)?;
// ( ... // ( ...
let mut settings = settings;
settings.pos = eat_token(input, Token::LeftParen); settings.pos = eat_token(input, Token::LeftParen);
if match_token(input, Token::RightParen).0 { if match_token(input, Token::RightParen).0 {
@ -597,11 +596,11 @@ fn parse_index_chain(
lhs: Expr, lhs: Expr,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
let mut settings = settings;
#[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)?;
let mut settings = settings;
let idx_expr = parse_expr(input, state, lib, settings.level_up())?; let idx_expr = parse_expr(input, state, lib, settings.level_up())?;
// Check type of indexing - must be integer or string // Check type of indexing - must be integer or string
@ -760,12 +759,11 @@ fn parse_array_literal(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
let mut settings = settings;
#[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)?;
// [ ... // [ ...
let mut settings = settings;
settings.pos = eat_token(input, Token::LeftBracket); settings.pos = eat_token(input, Token::LeftBracket);
let mut arr = StaticVec::new(); let mut arr = StaticVec::new();
@ -834,12 +832,11 @@ fn parse_map_literal(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
let mut settings = settings;
#[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)?;
// #{ ... // #{ ...
let mut settings = settings;
settings.pos = eat_token(input, Token::MapStart); settings.pos = eat_token(input, Token::MapStart);
let mut map = StaticVec::<(Ident, Expr)>::new(); let mut map = StaticVec::<(Ident, Expr)>::new();
@ -952,12 +949,11 @@ fn parse_switch(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
let mut settings = settings;
#[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)?;
// switch ... // switch ...
let mut settings = settings;
settings.pos = eat_token(input, Token::Switch); settings.pos = eat_token(input, Token::Switch);
let item = parse_expr(input, state, lib, settings.level_up())?; let item = parse_expr(input, state, lib, settings.level_up())?;
@ -1099,12 +1095,12 @@ fn parse_primary(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
let mut settings = settings;
#[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)?;
let (token, token_pos) = input.peek().expect(NEVER_ENDS); let (token, token_pos) = input.peek().expect(NEVER_ENDS);
let mut settings = settings;
settings.pos = *token_pos; settings.pos = *token_pos;
let mut root_expr = match token { let mut root_expr = match token {
@ -1358,48 +1354,48 @@ fn parse_primary(
root_expr = match (root_expr, tail_token) { root_expr = match (root_expr, tail_token) {
// Qualified function call with ! // Qualified function call with !
(Expr::Variable(_, _, x), Token::Bang) if x.1.is_some() => { (Expr::Variable(_, _, x), Token::Bang) if x.1.is_some() => {
return Err(if !match_token(input, Token::LeftParen).0 { return if !match_token(input, Token::LeftParen).0 {
LexError::UnexpectedInput(Token::Bang.syntax().to_string()).into_err(tail_pos) Err(LexError::UnexpectedInput(Token::Bang.syntax().to_string())
.into_err(tail_pos))
} else { } else {
LexError::ImproperSymbol( Err(LexError::ImproperSymbol(
"!".to_string(), "!".to_string(),
"'!' cannot be used to call module functions".to_string(), "'!' cannot be used to call module functions".to_string(),
) )
.into_err(tail_pos) .into_err(tail_pos))
}); };
} }
// Function call with ! // Function call with !
(Expr::Variable(_, var_pos, x), Token::Bang) => { (Expr::Variable(_, pos, x), Token::Bang) => {
let (matched, pos) = match_token(input, Token::LeftParen); match match_token(input, Token::LeftParen) {
if !matched { (false, pos) => {
return Err(PERR::MissingToken( return Err(PERR::MissingToken(
Token::LeftParen.syntax().into(), Token::LeftParen.syntax().into(),
"to start arguments list of function call".into(), "to start arguments list of function call".into(),
) )
.into_err(pos)); .into_err(pos))
}
_ => (),
} }
let (_, namespace, name) = *x; let (_, namespace, name) = *x;
settings.pos = var_pos; settings.pos = pos;
let ns = namespace.map(|(ns, _)| ns); let ns = namespace.map(|(ns, _)| ns);
parse_fn_call(input, state, lib, name, true, ns, settings.level_up())? parse_fn_call(input, state, lib, name, true, ns, settings.level_up())?
} }
// Function call // Function call
(Expr::Variable(_, var_pos, x), Token::LeftParen) => { (Expr::Variable(_, pos, x), Token::LeftParen) => {
let (_, namespace, name) = *x; let (_, namespace, name) = *x;
settings.pos = var_pos;
let ns = namespace.map(|(ns, _)| ns); let ns = namespace.map(|(ns, _)| ns);
settings.pos = pos;
parse_fn_call(input, state, lib, name, false, ns, settings.level_up())? parse_fn_call(input, state, lib, name, false, ns, settings.level_up())?
} }
// module access // module access
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
(Expr::Variable(_, var_pos, x), Token::DoubleColon) => { (Expr::Variable(_, pos, x), Token::DoubleColon) => {
let (id2, pos2) = parse_var_name(input)?; let (id2, pos2) = parse_var_name(input)?;
let (_, mut namespace, var_name) = *x; let (_, mut namespace, name) = *x;
let var_name_def = Ident { let var_name_def = Ident { name, pos };
name: var_name,
pos: var_pos,
};
if let Some((ref mut namespace, _)) = namespace { if let Some((ref mut namespace, _)) = namespace {
namespace.push(var_name_def); namespace.push(var_name_def);
@ -1437,7 +1433,6 @@ fn parse_primary(
} }
let rhs = parse_primary(input, state, lib, settings.level_up())?; let rhs = parse_primary(input, state, lib, settings.level_up())?;
make_dot_expr(state, expr, false, rhs, tail_pos)? make_dot_expr(state, expr, false, rhs, tail_pos)?
} }
// Unknown postfix operator // Unknown postfix operator
@ -1482,14 +1477,14 @@ fn parse_unary(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
let mut settings = settings;
let (token, token_pos) = input.peek().expect(NEVER_ENDS);
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)?;
let (token, token_pos) = input.peek().expect(NEVER_ENDS);
let mut settings = settings;
settings.pos = *token_pos;
match token { match token {
// -expr // -expr
Token::Minus | Token::UnaryMinus => { Token::Minus | Token::UnaryMinus => {
@ -1676,7 +1671,7 @@ fn make_assignment_stmt(
} }
} }
/// Parse an operator-assignment expression. /// Parse an operator-assignment expression (if any).
fn parse_op_assignment_stmt( fn parse_op_assignment_stmt(
input: &mut TokenStream, input: &mut TokenStream,
state: &mut ParseState, state: &mut ParseState,
@ -1684,23 +1679,24 @@ fn parse_op_assignment_stmt(
lhs: Expr, lhs: Expr,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
let mut settings = settings;
#[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)?;
let (token, token_pos) = input.peek().expect(NEVER_ENDS); let (op, pos) = match input.peek().expect(NEVER_ENDS) {
settings.pos = *token_pos; // var = ...
(Token::Equals, _) => (None, eat_token(input, Token::Equals)),
let (op, pos) = match token { // var op= ...
Token::Equals => (None, input.next().expect(NEVER_ENDS).1), (token, _) if token.is_op_assignment() => input
_ if token.is_op_assignment() => input
.next() .next()
.map(|(op, pos)| (Some(op), pos)) .map(|(op, pos)| (Some(op), pos))
.expect(NEVER_ENDS), .expect(NEVER_ENDS),
// Not op-assignment
_ => return Ok(Stmt::Expr(lhs)), _ => return Ok(Stmt::Expr(lhs)),
}; };
let mut settings = settings;
settings.pos = pos;
let rhs = parse_expr(input, state, lib, settings.level_up())?; let rhs = parse_expr(input, state, lib, settings.level_up())?;
make_assignment_stmt(op, state, lhs, rhs, pos) make_assignment_stmt(op, state, lhs, rhs, pos)
} }
@ -1714,25 +1710,27 @@ fn make_dot_expr(
rhs: Expr, rhs: Expr,
op_pos: Position, op_pos: Position,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
Ok(match (lhs, rhs) { match (lhs, rhs) {
// lhs[idx_expr].rhs // lhs[idx_expr].rhs
(Expr::Index(mut x, term, pos), rhs) => { (Expr::Index(mut x, term, pos), rhs) => {
x.rhs = make_dot_expr(state, x.rhs, term || terminate_chaining, rhs, op_pos)?; x.rhs = make_dot_expr(state, x.rhs, term || terminate_chaining, rhs, op_pos)?;
Expr::Index(x, false, pos) Ok(Expr::Index(x, false, pos))
} }
// lhs.id // lhs.id
(lhs, var_expr @ Expr::Variable(_, _, _)) if var_expr.is_variable_access(true) => { (lhs, var_expr @ Expr::Variable(_, _, _)) if var_expr.is_variable_access(true) => {
let rhs = var_expr.into_property(state); let rhs = var_expr.into_property(state);
Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos) Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos))
} }
// lhs.module::id - syntax error // lhs.module::id - syntax error
(_, Expr::Variable(_, _, x)) => { (_, Expr::Variable(_, _, x)) => {
return Err(PERR::PropertyExpected.into_err(x.1.expect("`Some`").0[0].pos)) Err(PERR::PropertyExpected.into_err(x.1.expect("`Some`").0[0].pos))
} }
// lhs.prop // lhs.prop
(lhs, prop @ Expr::Property(_)) => { (lhs, prop @ Expr::Property(_)) => Ok(Expr::Dot(
Expr::Dot(BinaryExpr { lhs, rhs: prop }.into(), false, op_pos) BinaryExpr { lhs, rhs: prop }.into(),
} false,
op_pos,
)),
// lhs.dot_lhs.dot_rhs or lhs.dot_lhs[idx_rhs] // lhs.dot_lhs.dot_rhs or lhs.dot_lhs[idx_rhs]
(lhs, rhs @ Expr::Dot(_, _, _)) | (lhs, rhs @ Expr::Index(_, _, _)) => { (lhs, rhs @ Expr::Dot(_, _, _)) | (lhs, rhs @ Expr::Index(_, _, _)) => {
let (x, term, pos, is_dot) = match rhs { let (x, term, pos, is_dot) = match rhs {
@ -1754,7 +1752,7 @@ fn make_dot_expr(
} else { } else {
Expr::Index(new_lhs, term, pos) Expr::Index(new_lhs, term, pos)
}; };
Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos) Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos))
} }
Expr::FnCall(mut func, func_pos) => { Expr::FnCall(mut func, func_pos) => {
// Recalculate hash // Recalculate hash
@ -1775,7 +1773,7 @@ fn make_dot_expr(
} else { } else {
Expr::Index(new_lhs, term, pos) Expr::Index(new_lhs, term, pos)
}; };
Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos) Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos))
} }
_ => unreachable!("invalid dot expression: {:?}", x.lhs), _ => unreachable!("invalid dot expression: {:?}", x.lhs),
} }
@ -1790,7 +1788,7 @@ fn make_dot_expr(
&& [crate::engine::KEYWORD_FN_PTR, crate::engine::KEYWORD_EVAL] && [crate::engine::KEYWORD_FN_PTR, crate::engine::KEYWORD_EVAL]
.contains(&x.name.as_ref()) => .contains(&x.name.as_ref()) =>
{ {
return Err(LexError::ImproperSymbol( Err(LexError::ImproperSymbol(
x.name.to_string(), x.name.to_string(),
format!( format!(
"'{}' should not be called in method style. Try {}(...);", "'{}' should not be called in method style. Try {}(...);",
@ -1800,12 +1798,10 @@ fn make_dot_expr(
.into_err(pos)) .into_err(pos))
} }
// lhs.func!(...) // lhs.func!(...)
(_, Expr::FnCall(x, pos)) if x.capture_parent_scope => { (_, Expr::FnCall(x, pos)) if x.capture_parent_scope => Err(PERR::MalformedCapture(
return Err(PERR::MalformedCapture(
"method-call style does not support running within the caller's scope".into(), "method-call style does not support running within the caller's scope".into(),
) )
.into_err(pos)) .into_err(pos)),
}
// lhs.func(...) // lhs.func(...)
(lhs, Expr::FnCall(mut func, func_pos)) => { (lhs, Expr::FnCall(mut func, func_pos)) => {
// Recalculate hash // Recalculate hash
@ -1816,14 +1812,14 @@ fn make_dot_expr(
); );
let rhs = Expr::FnCall(func, func_pos); let rhs = Expr::FnCall(func, func_pos);
Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos) Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos))
} }
// lhs.rhs // lhs.rhs
(_, rhs) => return Err(PERR::PropertyExpected.into_err(rhs.position())), (_, rhs) => Err(PERR::PropertyExpected.into_err(rhs.position())),
}) }
} }
/// Parse a binary expression. /// Parse a binary expression (if any).
fn parse_binary_op( fn parse_binary_op(
input: &mut TokenStream, input: &mut TokenStream,
state: &mut ParseState, state: &mut ParseState,
@ -1832,11 +1828,10 @@ fn parse_binary_op(
lhs: Expr, lhs: Expr,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
let mut settings = settings;
#[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)?;
let mut settings = settings;
settings.pos = lhs.position(); settings.pos = lhs.position();
let mut root = lhs; let mut root = lhs;
@ -2177,11 +2172,10 @@ fn parse_expr(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Expr, ParseError> { ) -> Result<Expr, ParseError> {
let mut settings = settings;
#[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)?;
let mut settings = settings;
settings.pos = input.peek().expect(NEVER_ENDS).1; settings.pos = input.peek().expect(NEVER_ENDS).1;
// Check if it is a custom syntax. // Check if it is a custom syntax.
@ -2222,12 +2216,11 @@ fn parse_if(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
let mut settings = settings;
#[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)?;
// if ... // if ...
let mut settings = settings;
settings.pos = eat_token(input, Token::If); settings.pos = eat_token(input, Token::If);
// if guard { if_body } // if guard { if_body }
@ -2263,11 +2256,11 @@ fn parse_while_loop(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
let mut settings = settings;
#[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)?;
let mut settings = settings;
// 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) => {
@ -2294,12 +2287,11 @@ fn parse_do(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
let mut settings = settings;
#[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)?;
// do ... // do ...
let mut settings = settings;
settings.pos = eat_token(input, Token::Do); settings.pos = eat_token(input, Token::Do);
// do { body } [while|until] guard // do { body } [while|until] guard
@ -2338,12 +2330,11 @@ fn parse_for(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
let mut settings = settings;
#[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)?;
// for ... // for ...
let mut settings = settings;
settings.pos = eat_token(input, Token::For); settings.pos = eat_token(input, Token::For);
// for name ... // for name ...
@ -2398,16 +2389,20 @@ fn parse_for(
let prev_stack_len = state.stack.len(); let prev_stack_len = state.stack.len();
let counter_var = if let Some(name) = counter_name { let counter_var = if let Some(name) = counter_name {
let counter_var = state.get_identifier(name); let name = state.get_identifier(name);
state let pos = counter_pos.expect("`Some`");
.stack state.stack.push((name.clone(), AccessMode::ReadWrite));
.push((counter_var.clone(), AccessMode::ReadWrite)); Some(Ident { name, pos })
Some(counter_var)
} else { } else {
None None
}; };
let loop_var = state.get_identifier(name); let loop_var = state.get_identifier(name);
state.stack.push((loop_var.clone(), AccessMode::ReadWrite)); state.stack.push((loop_var.clone(), AccessMode::ReadWrite));
let loop_var = Ident {
name: loop_var,
pos: name_pos,
};
settings.is_breakable = true; settings.is_breakable = true;
let body = parse_block(input, state, lib, settings.level_up())?; let body = parse_block(input, state, lib, settings.level_up())?;
@ -2416,17 +2411,7 @@ fn parse_for(
Ok(Stmt::For( Ok(Stmt::For(
expr, expr,
Box::new(( Box::new((loop_var, counter_var, body.into())),
Ident {
name: loop_var,
pos: name_pos,
},
counter_var.map(|name| Ident {
name,
pos: counter_pos.expect("`Some`"),
}),
body.into(),
)),
settings.pos, settings.pos,
)) ))
} }
@ -2440,12 +2425,11 @@ fn parse_let(
is_export: bool, is_export: bool,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
let mut settings = settings;
#[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)?;
// let/const... (specified in `var_type`) // let/const... (specified in `var_type`)
let mut settings = settings;
settings.pos = input.next().expect(NEVER_ENDS).1; settings.pos = input.next().expect(NEVER_ENDS).1;
// let name ... // let name ...
@ -2494,12 +2478,11 @@ fn parse_import(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
let mut settings = settings;
#[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)?;
// import ... // import ...
let mut settings = settings;
settings.pos = eat_token(input, Token::Import); settings.pos = eat_token(input, Token::Import);
// import expr ... // import expr ...
@ -2511,19 +2494,13 @@ fn parse_import(
} }
// import expr as name ... // import expr as name ...
let (name, name_pos) = parse_var_name(input)?; let (name, pos) = parse_var_name(input)?;
let name = state.get_identifier(name); let name = state.get_identifier(name);
state.modules.push(name.clone()); state.modules.push(name.clone());
Ok(Stmt::Import( Ok(Stmt::Import(
expr, expr,
Some( Some(Ident { name, pos }.into()),
Ident {
name,
pos: name_pos,
}
.into(),
),
settings.pos, settings.pos,
)) ))
} }
@ -2536,11 +2513,10 @@ fn parse_export(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
let mut settings = settings;
#[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)?;
let mut settings = settings;
settings.pos = eat_token(input, Token::Export); settings.pos = eat_token(input, Token::Export);
match input.peek().expect(NEVER_ENDS) { match input.peek().expect(NEVER_ENDS) {
@ -2610,9 +2586,11 @@ fn parse_block(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
let mut settings = settings; #[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
// Must start with { // Must start with {
let mut settings = settings;
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)),
@ -2625,9 +2603,6 @@ fn parse_block(
} }
}; };
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let mut statements = Vec::with_capacity(8); let mut statements = Vec::with_capacity(8);
let prev_entry_stack_len = state.entry_stack_len; let prev_entry_stack_len = state.entry_stack_len;
@ -2713,11 +2688,10 @@ fn parse_expr_stmt(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
let mut settings = settings;
#[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)?;
let mut settings = settings;
settings.pos = input.peek().expect(NEVER_ENDS).1; settings.pos = input.peek().expect(NEVER_ENDS).1;
let expr = parse_expr(input, state, lib, settings.level_up())?; let expr = parse_expr(input, state, lib, settings.level_up())?;
@ -2934,12 +2908,11 @@ fn parse_try_catch(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<Stmt, ParseError> { ) -> Result<Stmt, ParseError> {
let mut settings = settings;
#[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)?;
// try ... // try ...
let mut settings = settings;
settings.pos = eat_token(input, Token::Try); settings.pos = eat_token(input, Token::Try);
// try { body } // try { body }
@ -3001,11 +2974,11 @@ fn parse_fn(
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
comments: Vec<Box<str>>, comments: Vec<Box<str>>,
) -> Result<ScriptFnDef, ParseError> { ) -> Result<ScriptFnDef, ParseError> {
let mut settings = settings;
#[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)?;
let mut settings = settings;
let (token, pos) = input.next().expect(NEVER_ENDS); let (token, pos) = input.next().expect(NEVER_ENDS);
let name = match token.into_function_name_for_override() { let name = match token.into_function_name_for_override() {
@ -3142,11 +3115,10 @@ fn parse_anon_fn(
lib: &mut FunctionsLib, lib: &mut FunctionsLib,
settings: ParseSettings, settings: ParseSettings,
) -> Result<(Expr, ScriptFnDef), ParseError> { ) -> Result<(Expr, ScriptFnDef), ParseError> {
let mut settings = settings;
#[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)?;
let mut settings = settings;
let mut params_list = StaticVec::new(); let mut params_list = StaticVec::new();
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 {