commit
df07eaacdb
@ -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"]
|
||||||
|
22
src/ast.rs
22
src/ast.rs
@ -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
|
||||||
///
|
///
|
||||||
|
206
src/parser.rs
206
src/parser.rs
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user