rhai/src/parser.rs

3475 lines
120 KiB
Rust
Raw Normal View History

2020-03-08 12:54:02 +01:00
//! Main module defining the lexer and parser.
2021-12-03 04:16:35 +01:00
use crate::api::options::LanguageOptions;
2021-03-08 08:30:32 +01:00
use crate::ast::{
BinaryExpr, CustomExpr, Expr, FnCallExpr, FnCallHashes, Ident, OpAssignment, ScriptFnDef, Stmt,
StmtBlock, AST_OPTION_FLAGS::*,
2021-03-08 08:30:32 +01:00
};
2021-07-10 09:50:31 +02:00
use crate::custom_syntax::{markers::*, CustomSyntax};
2021-03-14 03:47:29 +01:00
use crate::engine::{Precedence, KEYWORD_THIS, OP_CONTAINS};
2021-11-13 15:36:23 +01:00
use crate::func::hashing::get_hasher;
2021-12-25 16:49:14 +01:00
use crate::module::Namespace;
2021-11-13 15:36:23 +01:00
use crate::tokenizer::{
2021-08-30 09:42:47 +02:00
is_keyword_function, is_valid_function_name, is_valid_identifier, Token, TokenStream,
TokenizerControl,
};
2021-11-13 15:36:23 +01:00
use crate::types::dynamic::AccessMode;
2021-12-27 14:56:50 +01:00
use crate::types::StringsInterner;
2020-11-16 16:10:14 +01:00
use crate::{
calc_fn_hash, calc_qualified_fn_hash, calc_qualified_var_hash, Dynamic, Engine, ExclusiveRange,
2021-12-27 05:27:31 +01:00
Identifier, ImmutableString, InclusiveRange, LexError, ParseError, Position, Scope, Shared,
StaticVec, AST, INT, PERR,
2020-11-16 16:10:14 +01:00
};
2021-04-17 09:15:54 +02:00
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
use std::{
collections::BTreeMap,
hash::{Hash, Hasher},
num::{NonZeroU8, NonZeroUsize},
};
2020-11-16 16:10:14 +01:00
2021-12-25 16:49:14 +01:00
pub type ParseResult<T> = Result<T, ParseError>;
type FnLib = BTreeMap<u64, Shared<ScriptFnDef>>;
2021-06-28 12:06:05 +02:00
/// Invalid variable name that acts as a search barrier in a [`Scope`].
const SCOPE_SEARCH_BARRIER_MARKER: &str = "$BARRIER$";
2021-08-26 17:58:41 +02:00
/// The message: `TokenStream` never ends
const NEVER_ENDS: &str = "`TokenStream` never ends";
2021-05-22 13:14:24 +02:00
2021-09-24 03:26:35 +02:00
/// _(internals)_ A type that encapsulates the current state of the parser.
/// Exported under the `internals` feature only.
2020-11-13 11:32:18 +01:00
#[derive(Debug)]
2021-04-04 07:13:07 +02:00
pub struct ParseState<'e> {
2020-11-25 02:36:06 +01:00
/// Reference to the scripting [`Engine`].
2021-09-24 03:26:35 +02:00
pub engine: &'e Engine,
2021-04-04 07:13:07 +02:00
/// Input stream buffer containing the next character to read.
2021-09-24 03:26:35 +02:00
pub tokenizer_control: TokenizerControl,
/// Interned strings.
2021-12-27 14:56:50 +01:00
pub interned_strings: StringsInterner,
/// Encapsulates a local stack with variable names to simulate an actual runtime scope.
2021-09-24 03:27:45 +02:00
pub stack: StaticVec<(Identifier, AccessMode)>,
/// Size of the local variables stack upon entry of the current block scope.
2021-09-24 03:26:35 +02:00
pub entry_stack_len: usize,
2020-07-29 16:43:50 +02:00
/// Tracks a list of external variables (variables that are not explicitly declared in the scope).
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
2021-09-24 03:26:35 +02:00
pub external_vars: BTreeMap<Identifier, Position>,
/// An indicator that disables variable capturing into externals one single time
/// up until the nearest consumed Identifier token.
2021-06-12 16:47:43 +02:00
/// If set to false the next call to [`access_var`][ParseState::access_var] will not capture the variable.
/// All consequent calls to [`access_var`][ParseState::access_var] will not be affected
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
2021-09-24 03:26:35 +02:00
pub allow_capture: bool,
2020-11-25 02:36:06 +01:00
/// Encapsulates a local stack with imported [module][crate::Module] names.
#[cfg(not(feature = "no_module"))]
2021-09-24 03:26:35 +02:00
pub modules: StaticVec<Identifier>,
/// Maximum levels of expression nesting.
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
2021-09-24 03:26:35 +02:00
pub max_expr_depth: Option<NonZeroUsize>,
/// Maximum levels of expression nesting in functions.
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_function"))]
2021-09-24 03:26:35 +02:00
pub max_function_expr_depth: Option<NonZeroUsize>,
}
2020-04-28 17:05:03 +02:00
2020-07-05 11:41:45 +02:00
impl<'e> ParseState<'e> {
2020-11-25 02:36:06 +01:00
/// Create a new [`ParseState`].
2020-10-08 16:25:50 +02:00
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
pub fn new(engine: &'e Engine, tokenizer_control: TokenizerControl) -> Self {
Self {
2020-07-05 11:41:45 +02:00
engine,
tokenizer_control,
2020-07-29 16:43:50 +02:00
#[cfg(not(feature = "unchecked"))]
max_expr_depth: NonZeroUsize::new(engine.max_expr_depth()),
2020-07-29 16:43:50 +02:00
#[cfg(not(feature = "unchecked"))]
#[cfg(not(feature = "no_function"))]
max_function_expr_depth: NonZeroUsize::new(engine.max_function_expr_depth()),
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
external_vars: BTreeMap::new(),
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
allow_capture: true,
2021-12-27 14:56:50 +01:00
interned_strings: StringsInterner::new(),
2021-11-25 10:09:00 +01:00
stack: StaticVec::new_const(),
entry_stack_len: 0,
#[cfg(not(feature = "no_module"))]
2021-11-25 10:09:00 +01:00
modules: StaticVec::new_const(),
}
2020-04-28 17:05:03 +02:00
}
2020-11-25 02:36:06 +01:00
/// Find explicitly declared variable by name in the [`ParseState`], searching in reverse order.
///
2020-07-29 16:43:50 +02:00
/// If the variable is not present in the scope adds it to the list of external variables
///
2021-07-04 10:40:15 +02:00
/// The return value is the offset to be deducted from `ParseState::stack::len()`,
2021-06-12 16:47:43 +02:00
/// i.e. the top element of [`ParseState`]'s variables stack is offset 1.
///
/// Return `None` when the variable name is not found in the `stack`.
#[inline]
2021-12-04 10:57:28 +01:00
#[must_use]
2021-11-27 16:04:45 +01:00
pub fn access_var(&mut self, name: impl AsRef<str>, pos: Position) -> Option<NonZeroUsize> {
let name = name.as_ref();
let mut barrier = false;
2021-08-13 07:42:39 +02:00
let _pos = pos;
2020-07-29 16:43:50 +02:00
let index = self
.stack
2020-04-28 17:05:03 +02:00
.iter()
.rev()
.enumerate()
.find(|(_, (n, _))| {
2021-06-28 12:06:05 +02:00
if n == SCOPE_SEARCH_BARRIER_MARKER {
// Do not go beyond the barrier
barrier = true;
false
} else {
2021-07-04 10:40:15 +02:00
n == name
}
})
.and_then(|(i, _)| NonZeroUsize::new(i + 1));
2020-08-03 06:10:20 +02:00
#[cfg(not(feature = "no_closure"))]
if self.allow_capture {
2021-03-23 05:13:53 +01:00
if index.is_none() && !self.external_vars.contains_key(name) {
self.external_vars.insert(name.into(), _pos);
}
} else {
2020-08-03 06:10:20 +02:00
self.allow_capture = true
}
if barrier {
None
} else {
index
}
2020-05-04 13:36:58 +02:00
}
2020-11-25 02:36:06 +01:00
/// Find a module by name in the [`ParseState`], searching in reverse.
2020-10-18 11:29:11 +02:00
///
/// Returns the offset to be deducted from `Stack::len`,
2020-11-25 02:36:06 +01:00
/// i.e. the top element of the [`ParseState`] is offset 1.
2020-10-18 11:29:11 +02:00
///
2020-11-25 02:36:06 +01:00
/// Returns `None` when the variable name is not found in the [`ParseState`].
2020-10-18 11:29:11 +02:00
///
/// # Panics
///
/// Panics when called under `no_module`.
2020-10-18 16:10:08 +02:00
#[cfg(not(feature = "no_module"))]
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-11-27 16:04:45 +01:00
pub fn find_module(&self, name: impl AsRef<str>) -> Option<NonZeroUsize> {
let name = name.as_ref();
2020-10-18 16:10:08 +02:00
self.modules
2020-05-04 13:36:58 +02:00
.iter()
.rev()
.enumerate()
2021-06-21 13:12:28 +02:00
.find(|&(_, n)| n == name)
2020-10-18 16:10:08 +02:00
.and_then(|(i, _)| NonZeroUsize::new(i + 1))
2020-04-28 17:05:03 +02:00
}
2021-12-27 14:56:50 +01:00
/// Get an interned identifier, creating one if it is not yet interned.
#[inline(always)]
#[must_use]
pub fn get_identifier(
&mut self,
prefix: &'static str,
text: impl AsRef<str> + Into<Identifier> + Into<ImmutableString>,
) -> Identifier {
self.interned_strings.get(prefix, text).into()
}
/// Get an interned string, creating one if it is not yet interned.
2021-03-24 06:17:52 +01:00
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-12-27 14:56:50 +01:00
pub fn get_interned_string(
&mut self,
prefix: &'static str,
text: impl AsRef<str> + Into<Identifier> + Into<ImmutableString>,
) -> ImmutableString {
self.interned_strings.get(prefix, text)
}
2020-04-28 17:05:03 +02:00
}
/// A type that encapsulates all the settings for a particular parsing function.
2020-11-25 02:36:06 +01:00
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
struct ParseSettings {
/// Current position.
pos: Position,
/// Is the construct being parsed located at global level?
is_global: bool,
2020-07-16 06:09:31 +02:00
/// Is the construct being parsed located at function definition level?
2021-11-28 03:49:48 +01:00
#[cfg(not(feature = "no_function"))]
2020-07-16 06:09:31 +02:00
is_function_scope: bool,
2021-12-04 10:57:28 +01:00
/// Is the construct being parsed located inside a closure?
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_closure"))]
is_closure: bool,
/// Is the current position inside a loop?
is_breakable: bool,
2021-12-03 04:16:35 +01:00
/// Default language options.
default_options: LanguageOptions,
2021-12-04 10:57:28 +01:00
/// Is strict variables mode enabled?
strict_var: bool,
/// Is anonymous function allowed?
2021-11-28 03:49:48 +01:00
#[cfg(not(feature = "no_function"))]
allow_anonymous_fn: bool,
2021-12-03 04:16:35 +01:00
/// Is `if`-expression allowed?
allow_if_expr: bool,
2021-12-03 04:16:35 +01:00
/// Is `switch` expression allowed?
2020-11-14 16:43:36 +01:00
allow_switch_expr: bool,
/// Is statement-expression allowed?
allow_stmt_expr: bool,
/// Current expression nesting level.
level: usize,
}
impl ParseSettings {
/// Create a new `ParseSettings` with one higher expression level.
2020-10-08 16:25:50 +02:00
#[inline(always)]
2021-06-12 16:47:43 +02:00
#[must_use]
2021-06-28 12:06:05 +02:00
pub const fn level_up(&self) -> Self {
Self {
level: self.level + 1,
..*self
}
}
/// Make sure that the current level of expression nesting is within the maximum limit.
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
#[inline]
2021-12-25 16:49:14 +01:00
pub fn ensure_level_within_max_limit(&self, limit: Option<NonZeroUsize>) -> ParseResult<()> {
2021-06-28 12:06:05 +02:00
if let Some(limit) = limit {
if self.level > limit.get() {
return Err(PERR::ExprTooDeep.into_err(self.pos));
}
}
2021-01-06 06:46:53 +01:00
Ok(())
}
}
impl Expr {
2020-11-25 02:36:06 +01:00
/// Convert a [`Variable`][Expr::Variable] into a [`Property`][Expr::Property].
/// All other variants are untouched.
#[cfg(not(feature = "no_object"))]
#[inline]
2021-06-12 16:47:43 +02:00
#[must_use]
fn into_property(self, state: &mut ParseState) -> Self {
match self {
2021-04-05 17:59:15 +02:00
Self::Variable(_, pos, x) if x.1.is_none() => {
2020-12-24 16:22:50 +01:00
let ident = x.2;
2021-12-27 14:56:50 +01:00
let getter = state.get_identifier(crate::engine::FN_GET, ident.as_str());
2021-05-19 14:26:11 +02:00
let hash_get = calc_fn_hash(&getter, 1);
2021-12-27 14:56:50 +01:00
let setter = state.get_identifier(crate::engine::FN_SET, ident.as_str());
2021-05-19 14:26:11 +02:00
let hash_set = calc_fn_hash(&setter, 2);
2021-03-08 08:30:32 +01:00
2021-03-10 15:12:48 +01:00
Self::Property(Box::new((
(getter, hash_get),
(setter, hash_set),
2021-12-27 14:56:50 +01:00
(state.get_interned_string("", ident.as_str()), pos),
2021-03-10 15:12:48 +01:00
)))
}
_ => self,
}
}
2021-07-03 18:15:27 +02:00
/// Raise an error if the expression can never yield a boolean value.
2021-12-25 16:49:14 +01:00
fn ensure_bool_expr(self) -> ParseResult<Expr> {
2021-07-03 18:15:27 +02:00
let type_name = match self {
Expr::Unit(_) => "()",
Expr::DynamicConstant(ref v, _) if !v.is::<bool>() => v.type_name(),
Expr::IntegerConstant(_, _) => "a number",
#[cfg(not(feature = "no_float"))]
Expr::FloatConstant(_, _) => "a floating-point number",
Expr::CharConstant(_, _) => "a character",
Expr::StringConstant(_, _) => "a string",
Expr::InterpolatedString(_, _) => "a string",
Expr::Array(_, _) => "an array",
Expr::Map(_, _) => "an object map",
_ => return Ok(self),
};
Err(
PERR::MismatchedType("a boolean expression".to_string(), type_name.to_string())
.into_err(self.position()),
)
}
/// Raise an error if the expression can never yield an iterable value.
2021-12-25 16:49:14 +01:00
fn ensure_iterable(self) -> ParseResult<Expr> {
2021-07-03 18:15:27 +02:00
let type_name = match self {
Expr::Unit(_) => "()",
Expr::BoolConstant(_, _) => "a boolean",
Expr::IntegerConstant(_, _) => "a number",
#[cfg(not(feature = "no_float"))]
Expr::FloatConstant(_, _) => "a floating-point number",
Expr::CharConstant(_, _) => "a character",
Expr::StringConstant(_, _) => "a string",
Expr::InterpolatedString(_, _) => "a string",
Expr::Map(_, _) => "an object map",
_ => return Ok(self),
};
Err(
PERR::MismatchedType("an iterable value".to_string(), type_name.to_string())
.into_err(self.position()),
)
}
}
2021-07-04 10:40:15 +02:00
/// Make sure that the next expression is not a statement expression (i.e. wrapped in `{}`).
#[inline]
2021-12-25 16:49:14 +01:00
fn ensure_not_statement_expr(input: &mut TokenStream, type_name: impl ToString) -> ParseResult<()> {
2021-07-04 10:40:15 +02:00
match input.peek().expect(NEVER_ENDS) {
(Token::LeftBrace, pos) => Err(PERR::ExprExpected(type_name.to_string()).into_err(*pos)),
_ => Ok(()),
}
}
/// Make sure that the next expression is not a mis-typed assignment (i.e. `a = b` instead of `a == b`).
#[inline]
2021-12-25 16:49:14 +01:00
fn ensure_not_assignment(input: &mut TokenStream) -> ParseResult<()> {
2021-07-04 10:40:15 +02:00
match input.peek().expect(NEVER_ENDS) {
(Token::Equals, pos) => Err(LexError::ImproperSymbol(
"=".to_string(),
"Possibly a typo of '=='?".to_string(),
)
.into_err(*pos)),
_ => Ok(()),
}
}
2020-11-25 02:36:06 +01:00
/// Consume a particular [token][Token], checking that it is the expected one.
2021-11-13 02:50:49 +01:00
///
/// # Panics
///
/// Panics if the next token is not the expected one.
2021-07-04 10:40:15 +02:00
#[inline]
2021-11-13 02:50:49 +01:00
fn eat_token(input: &mut TokenStream, expected_token: Token) -> Position {
2021-05-22 13:14:24 +02:00
let (t, pos) = input.next().expect(NEVER_ENDS);
2021-11-13 02:50:49 +01:00
if t != expected_token {
2020-06-16 16:14:46 +02:00
unreachable!(
"expecting {} (found {}) at {}",
2021-11-13 02:50:49 +01:00
expected_token.syntax(),
t.syntax(),
pos
);
}
pos
}
2020-11-25 02:36:06 +01:00
/// Match a particular [token][Token], consuming it if matched.
2021-07-04 10:40:15 +02:00
#[inline]
2020-10-20 17:16:03 +02:00
fn match_token(input: &mut TokenStream, token: Token) -> (bool, Position) {
2021-05-22 13:14:24 +02:00
let (t, pos) = input.peek().expect(NEVER_ENDS);
if *t == token {
2020-10-20 17:16:03 +02:00
(true, eat_token(input, token))
} else {
2020-10-20 17:16:03 +02:00
(false, *pos)
}
}
2021-06-07 05:43:00 +02:00
/// Parse a variable name.
2021-12-25 16:49:14 +01:00
fn parse_var_name(input: &mut TokenStream) -> ParseResult<(Box<str>, Position)> {
2021-06-07 05:43:00 +02:00
match input.next().expect(NEVER_ENDS) {
// Variable name
(Token::Identifier(s), pos) => Ok((s, pos)),
// Reserved keyword
(Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => {
2021-11-11 06:55:52 +01:00
Err(PERR::Reserved(s.to_string()).into_err(pos))
2021-06-07 05:43:00 +02:00
}
// Bad identifier
(Token::LexError(err), pos) => Err(err.into_err(pos)),
// Not a variable name
(_, pos) => Err(PERR::VariableExpected.into_err(pos)),
}
}
2021-07-10 09:50:31 +02:00
/// Parse a symbol.
2021-12-25 16:49:14 +01:00
fn parse_symbol(input: &mut TokenStream) -> ParseResult<(Box<str>, Position)> {
2021-07-10 09:50:31 +02:00
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.chars()) => Ok((s, pos)),
// Bad identifier
(Token::LexError(err), pos) => Err(err.into_err(pos)),
// Not a symbol
(_, pos) => Err(PERR::MissingSymbol(String::new()).into_err(pos)),
2021-07-10 09:50:31 +02:00
}
}
2021-06-17 03:50:32 +02:00
/// Parse `(` expr `)`
2020-06-11 12:13:33 +02:00
fn parse_paren_expr(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Expr> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2020-12-28 02:49:54 +01:00
// ( ...
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2020-12-28 02:49:54 +01:00
settings.pos = eat_token(input, Token::LeftParen);
2020-10-20 17:16:03 +02:00
if match_token(input, Token::RightParen).0 {
return Ok(Expr::Unit(settings.pos));
}
let expr = parse_expr(input, state, lib, settings.level_up())?;
2016-02-29 22:43:45 +01:00
2021-05-22 13:14:24 +02:00
match input.next().expect(NEVER_ENDS) {
2020-03-18 03:36:50 +01:00
// ( xxx )
(Token::RightParen, _) => Ok(expr),
// ( <error>
2021-07-24 08:11:16 +02:00
(Token::LexError(err), pos) => Err(err.into_err(pos)),
2020-03-18 03:36:50 +01:00
// ( xxx ???
(_, pos) => Err(PERR::MissingToken(
2020-05-04 13:36:58 +02:00
Token::RightParen.into(),
"for a matching ( in this expression".into(),
)
2020-06-11 17:08:00 +02:00
.into_err(pos)),
2016-02-29 22:43:45 +01:00
}
}
2020-03-18 03:36:50 +01:00
/// Parse a function call.
2020-07-26 16:25:30 +02:00
fn parse_fn_call(
2020-06-11 12:13:33 +02:00
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-03-29 05:36:02 +02:00
id: Identifier,
2021-11-13 05:23:35 +01:00
capture_parent_scope: bool,
2021-12-25 16:49:14 +01:00
namespace: Option<Namespace>,
2020-06-11 17:08:00 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Expr> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2021-05-22 13:14:24 +02:00
let (token, token_pos) = input.peek().expect(NEVER_ENDS);
2020-12-28 02:49:54 +01:00
2021-08-13 07:42:39 +02:00
let mut namespace = namespace;
2021-11-25 10:09:00 +01:00
let mut args = StaticVec::new_const();
2017-10-28 05:30:12 +02:00
match token {
2020-06-29 17:55:28 +02:00
// id( <EOF>
Token::EOF => {
2020-04-06 06:29:01 +02:00
return Err(PERR::MissingToken(
2020-05-04 13:36:58 +02:00
Token::RightParen.into(),
2020-04-06 06:29:01 +02:00
format!("to close the arguments list of this function call '{}'", id),
)
2020-06-29 17:55:28 +02:00
.into_err(*token_pos))
2020-04-06 06:29:01 +02:00
}
2020-06-29 17:55:28 +02:00
// id( <error>
2020-11-25 02:36:06 +01:00
Token::LexError(err) => return Err(err.clone().into_err(*token_pos)),
2020-04-06 06:29:01 +02:00
// id()
Token::RightParen => {
eat_token(input, Token::RightParen);
2021-12-04 10:57:28 +01:00
let hash = if let Some(modules) = namespace.as_mut() {
#[cfg(not(feature = "no_module"))]
{
let index = state.find_module(&modules[0].name);
2021-12-04 11:07:27 +01:00
#[cfg(not(feature = "no_function"))]
let relax = settings.is_function_scope;
#[cfg(feature = "no_function")]
let relax = false;
if !relax && settings.strict_var && index.is_none() {
2021-12-27 05:27:31 +01:00
return Err(PERR::ModuleUndefined(modules[0].name.to_string())
2021-12-04 10:57:28 +01:00
.into_err(modules[0].pos));
}
modules.set_index(index);
}
calc_qualified_fn_hash(modules.iter().map(|m| m.name.as_str()), &id, 0)
} else {
calc_fn_hash(&id, 0)
};
2020-05-09 10:15:50 +02:00
2021-08-30 09:42:47 +02:00
let hashes = if is_valid_function_name(&id) {
hash.into()
} else {
2021-04-20 16:26:08 +02:00
FnCallHashes::from_native(hash)
};
2021-05-05 12:38:52 +02:00
args.shrink_to_fit();
2021-06-16 12:36:33 +02:00
return Ok(FnCallExpr {
2021-12-27 14:56:50 +01:00
name: state.get_identifier("", id),
2021-11-13 05:23:35 +01:00
capture_parent_scope,
2021-06-16 12:36:33 +02:00
namespace,
hashes,
args,
..Default::default()
}
.into_fn_call_expr(settings.pos));
2020-04-06 06:29:01 +02:00
}
// id...
_ => (),
2016-02-29 22:43:45 +01:00
}
let settings = settings.level_up();
2016-02-29 22:43:45 +01:00
loop {
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
2020-06-16 16:14:46 +02:00
// id(...args, ) - handle trailing comma
(Token::RightParen, _) => (),
_ => args.push(parse_expr(input, state, lib, settings)?),
2020-06-16 16:14:46 +02:00
}
2016-02-29 22:43:45 +01:00
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
// id(...args)
(Token::RightParen, _) => {
eat_token(input, Token::RightParen);
2020-05-04 11:43:54 +02:00
2021-12-04 10:57:28 +01:00
let hash = if let Some(modules) = namespace.as_mut() {
#[cfg(not(feature = "no_module"))]
{
let index = state.find_module(&modules[0].name);
2021-05-25 04:54:48 +02:00
2021-12-04 11:07:27 +01:00
#[cfg(not(feature = "no_function"))]
let relax = settings.is_function_scope;
#[cfg(feature = "no_function")]
let relax = false;
if !relax && settings.strict_var && index.is_none() {
2021-12-27 05:27:31 +01:00
return Err(PERR::ModuleUndefined(modules[0].name.to_string())
.into_err(modules[0].pos));
2021-12-04 10:57:28 +01:00
}
modules.set_index(index);
}
calc_qualified_fn_hash(modules.iter().map(|m| m.name.as_str()), &id, args.len())
} else {
calc_fn_hash(&id, args.len())
};
2020-05-09 10:15:50 +02:00
2021-08-30 09:42:47 +02:00
let hashes = if is_valid_function_name(&id) {
hash.into()
} else {
2021-04-20 16:26:08 +02:00
FnCallHashes::from_native(hash)
};
2021-05-05 12:38:52 +02:00
args.shrink_to_fit();
2021-06-16 12:36:33 +02:00
return Ok(FnCallExpr {
2021-12-27 14:56:50 +01:00
name: state.get_identifier("", id),
2021-11-13 05:23:35 +01:00
capture_parent_scope,
2021-06-16 12:36:33 +02:00
namespace,
hashes,
args,
..Default::default()
}
.into_fn_call_expr(settings.pos));
}
// id(...args,
(Token::Comma, _) => {
eat_token(input, Token::Comma);
}
// id(...args <EOF>
(Token::EOF, pos) => {
2020-04-06 06:29:01 +02:00
return Err(PERR::MissingToken(
2020-05-04 13:36:58 +02:00
Token::RightParen.into(),
2020-04-06 06:29:01 +02:00
format!("to close the arguments list of this function call '{}'", id),
)
.into_err(*pos))
2020-04-06 06:29:01 +02:00
}
// id(...args <error>
2020-11-25 02:36:06 +01:00
(Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
// id(...args ???
(_, pos) => {
return Err(PERR::MissingToken(
2020-05-04 13:36:58 +02:00
Token::Comma.into(),
format!("to separate the arguments to function call '{}'", id),
)
2020-03-24 09:46:47 +01:00
.into_err(*pos))
}
2016-02-29 22:43:45 +01:00
}
}
}
2020-04-26 13:37:32 +02:00
/// Parse an indexing chain.
/// Indexing binds to the right, so this call parses all possible levels of indexing following in the input.
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "no_index"))]
2020-06-11 12:13:33 +02:00
fn parse_index_chain(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2020-04-28 17:05:03 +02:00
lhs: Expr,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Expr> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2021-11-16 16:13:53 +01:00
let mut settings = settings;
let idx_expr = parse_expr(input, state, lib, settings.level_up())?;
2020-03-09 03:41:17 +01:00
2020-03-29 17:53:35 +02:00
// Check type of indexing - must be integer or string
2021-06-13 11:41:34 +02:00
match idx_expr {
2020-10-31 07:13:45 +01:00
Expr::IntegerConstant(_, pos) => match lhs {
2021-06-02 08:29:18 +02:00
Expr::IntegerConstant(_, _)
| Expr::Array(_, _)
| Expr::StringConstant(_, _)
2021-06-29 12:41:03 +02:00
| Expr::InterpolatedString(_, _) => (),
2020-03-29 17:53:35 +02:00
2020-10-31 16:26:21 +01:00
Expr::Map(_, _) => {
2020-03-29 17:53:35 +02:00
return Err(PERR::MalformedIndexExpr(
"Object map access expects string index, not a number".into(),
)
2021-06-13 11:41:34 +02:00
.into_err(pos))
2020-03-29 17:53:35 +02:00
}
#[cfg(not(feature = "no_float"))]
2020-10-31 07:13:45 +01:00
Expr::FloatConstant(_, _) => {
return Err(PERR::MalformedIndexExpr(
"Only arrays, object maps and strings can be indexed".into(),
)
2020-05-25 14:14:31 +02:00
.into_err(lhs.position()))
}
2020-10-31 07:13:45 +01:00
Expr::CharConstant(_, _)
2020-10-31 16:26:21 +01:00
| Expr::And(_, _)
| Expr::Or(_, _)
| Expr::BoolConstant(_, _)
2020-05-25 14:14:31 +02:00
| Expr::Unit(_) => {
2020-03-29 17:53:35 +02:00
return Err(PERR::MalformedIndexExpr(
"Only arrays, object maps and strings can be indexed".into(),
)
2020-05-25 14:14:31 +02:00
.into_err(lhs.position()))
2020-03-29 17:53:35 +02:00
}
_ => (),
},
// lhs[string]
2021-06-29 12:41:03 +02:00
Expr::StringConstant(_, _) | Expr::InterpolatedString(_, _) => match lhs {
2020-10-31 16:26:21 +01:00
Expr::Map(_, _) => (),
2020-03-29 17:53:35 +02:00
2021-06-29 12:41:03 +02:00
Expr::Array(_, _) | Expr::StringConstant(_, _) | Expr::InterpolatedString(_, _) => {
2020-03-29 17:53:35 +02:00
return Err(PERR::MalformedIndexExpr(
"Array or string expects numeric index, not a string".into(),
)
2021-04-04 07:13:07 +02:00
.into_err(idx_expr.position()))
2020-03-29 17:53:35 +02:00
}
#[cfg(not(feature = "no_float"))]
2020-10-31 07:13:45 +01:00
Expr::FloatConstant(_, _) => {
return Err(PERR::MalformedIndexExpr(
"Only arrays, object maps and strings can be indexed".into(),
)
2020-05-25 14:14:31 +02:00
.into_err(lhs.position()))
}
2020-10-31 07:13:45 +01:00
Expr::CharConstant(_, _)
2020-10-31 16:26:21 +01:00
| Expr::And(_, _)
| Expr::Or(_, _)
| Expr::BoolConstant(_, _)
2020-05-25 14:14:31 +02:00
| Expr::Unit(_) => {
2020-03-29 17:53:35 +02:00
return Err(PERR::MalformedIndexExpr(
"Only arrays, object maps and strings can be indexed".into(),
)
2020-05-25 14:14:31 +02:00
.into_err(lhs.position()))
2020-03-29 17:53:35 +02:00
}
_ => (),
},
2020-03-18 03:36:50 +01:00
// lhs[float]
#[cfg(not(feature = "no_float"))]
2020-10-31 07:13:45 +01:00
x @ Expr::FloatConstant(_, _) => {
2020-03-24 09:46:47 +01:00
return Err(PERR::MalformedIndexExpr(
"Array access expects integer index, not a float".into(),
)
2020-05-25 14:14:31 +02:00
.into_err(x.position()))
2020-03-09 03:41:17 +01:00
}
2020-03-18 03:36:50 +01:00
// lhs[char]
2020-10-31 07:13:45 +01:00
x @ Expr::CharConstant(_, _) => {
2020-03-24 09:46:47 +01:00
return Err(PERR::MalformedIndexExpr(
"Array access expects integer index, not a character".into(),
)
2020-05-25 14:14:31 +02:00
.into_err(x.position()))
}
// lhs[()]
2020-05-25 14:14:31 +02:00
x @ Expr::Unit(_) => {
2020-03-24 09:46:47 +01:00
return Err(PERR::MalformedIndexExpr(
"Array access expects integer index, not ()".into(),
)
2020-05-25 14:14:31 +02:00
.into_err(x.position()))
2020-03-09 03:41:17 +01:00
}
// lhs[??? && ???], lhs[??? || ???]
x @ Expr::And(_, _) | x @ Expr::Or(_, _) => {
return Err(PERR::MalformedIndexExpr(
"Array access expects integer index, not a boolean".into(),
)
2020-05-25 14:14:31 +02:00
.into_err(x.position()))
}
// lhs[true], lhs[false]
x @ Expr::BoolConstant(_, _) => {
2020-03-24 09:46:47 +01:00
return Err(PERR::MalformedIndexExpr(
"Array access expects integer index, not a boolean".into(),
)
2020-05-25 14:14:31 +02:00
.into_err(x.position()))
2020-03-09 03:41:17 +01:00
}
2020-03-18 03:36:50 +01:00
// All other expressions
2020-03-09 03:41:17 +01:00
_ => (),
}
// Check if there is a closing bracket
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
(Token::RightBracket, _) => {
eat_token(input, Token::RightBracket);
2020-04-26 12:04:07 +02:00
2020-04-26 13:37:32 +02:00
// Any more indexing following?
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
2020-04-26 13:37:32 +02:00
// If another indexing level, right-bind it
2020-04-26 12:04:07 +02:00
(Token::LeftBracket, _) => {
2020-06-11 17:08:00 +02:00
let prev_pos = settings.pos;
settings.pos = eat_token(input, Token::LeftBracket);
2020-04-26 13:37:32 +02:00
// Recursively parse the indexing chain, right-binding each
let idx_expr =
parse_index_chain(input, state, lib, idx_expr, settings.level_up())?;
2020-04-26 13:37:32 +02:00
// Indexing binds to right
2020-10-31 16:26:21 +01:00
Ok(Expr::Index(
2021-06-29 12:25:20 +02:00
BinaryExpr { lhs, rhs: idx_expr }.into(),
2021-07-24 06:27:33 +02:00
false,
2020-10-31 16:26:21 +01:00
prev_pos,
))
2020-04-26 12:04:07 +02:00
}
2020-04-26 13:37:32 +02:00
// Otherwise terminate the indexing chain
_ => Ok(Expr::Index(
2021-06-29 12:25:20 +02:00
BinaryExpr { lhs, rhs: idx_expr }.into(),
2021-07-24 06:27:33 +02:00
true,
settings.pos,
)),
2020-04-26 12:04:07 +02:00
}
}
2021-07-24 08:11:16 +02:00
(Token::LexError(err), pos) => Err(err.clone().into_err(*pos)),
(_, pos) => Err(PERR::MissingToken(
2020-05-04 13:36:58 +02:00
Token::RightBracket.into(),
"for a matching [ in this index expression".into(),
)
.into_err(*pos)),
2020-03-09 03:41:17 +01:00
}
2016-03-26 18:46:28 +01:00
}
2020-03-18 03:36:50 +01:00
/// Parse an array literal.
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "no_index"))]
2020-06-11 12:13:33 +02:00
fn parse_array_literal(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Expr> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2020-12-28 02:49:54 +01:00
// [ ...
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2020-12-28 02:49:54 +01:00
settings.pos = eat_token(input, Token::LeftBracket);
2021-11-25 10:09:00 +01:00
let mut arr = StaticVec::new_const();
2016-03-26 18:46:28 +01:00
2020-11-13 11:32:18 +01:00
loop {
const MISSING_RBRACKET: &str = "to end this array literal";
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
if state.engine.max_array_size() > 0 && arr.len() >= state.engine.max_array_size() {
2020-06-16 16:14:46 +02:00
return Err(PERR::LiteralTooLarge(
"Size of array literal".to_string(),
state.engine.max_array_size(),
2020-06-16 16:14:46 +02:00
)
2021-05-22 13:14:24 +02:00
.into_err(input.peek().expect(NEVER_ENDS).1));
2020-06-16 16:14:46 +02:00
}
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
2020-06-16 16:14:46 +02:00
(Token::RightBracket, _) => {
eat_token(input, Token::RightBracket);
break;
}
2020-11-13 11:32:18 +01:00
(Token::EOF, pos) => {
return Err(
PERR::MissingToken(Token::RightBracket.into(), MISSING_RBRACKET.into())
.into_err(*pos),
)
}
2020-06-16 16:14:46 +02:00
_ => {
let expr = parse_expr(input, state, lib, settings.level_up())?;
2020-06-16 16:14:46 +02:00
arr.push(expr);
}
}
2020-06-16 16:14:46 +02:00
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
2020-06-16 16:14:46 +02:00
(Token::Comma, _) => {
eat_token(input, Token::Comma);
}
(Token::RightBracket, _) => (),
(Token::EOF, pos) => {
2020-11-13 11:32:18 +01:00
return Err(
PERR::MissingToken(Token::RightBracket.into(), MISSING_RBRACKET.into())
.into_err(*pos),
2020-06-16 16:14:46 +02:00
)
}
2020-11-25 02:36:06 +01:00
(Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
2020-06-16 16:14:46 +02:00
(_, pos) => {
return Err(PERR::MissingToken(
Token::Comma.into(),
"to separate the items of this array literal".into(),
)
.into_err(*pos))
}
};
2016-03-26 18:46:28 +01:00
}
2021-03-29 05:36:02 +02:00
arr.shrink_to_fit();
2021-06-16 12:36:33 +02:00
Ok(Expr::Array(arr.into(), settings.pos))
2016-03-26 18:46:28 +01:00
}
2020-03-29 17:53:35 +02:00
/// Parse a map literal.
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "no_object"))]
2020-06-11 12:13:33 +02:00
fn parse_map_literal(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Expr> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2020-12-28 02:49:54 +01:00
// #{ ...
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2020-12-28 02:49:54 +01:00
settings.pos = eat_token(input, Token::MapStart);
2021-09-11 13:40:40 +02:00
let mut map = StaticVec::<(Ident, Expr)>::new();
let mut template = BTreeMap::<Identifier, crate::Dynamic>::new();
2020-03-29 17:53:35 +02:00
2020-11-13 11:32:18 +01:00
loop {
2020-06-16 16:14:46 +02:00
const MISSING_RBRACE: &str = "to end this object map literal";
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
2020-06-16 16:14:46 +02:00
(Token::RightBrace, _) => {
eat_token(input, Token::RightBrace);
break;
}
2020-11-13 11:32:18 +01:00
(Token::EOF, pos) => {
return Err(
PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into())
.into_err(*pos),
)
}
_ => (),
}
2020-06-16 16:14:46 +02:00
2021-05-22 13:14:24 +02:00
let (name, pos) = match input.next().expect(NEVER_ENDS) {
2020-11-13 11:32:18 +01:00
(Token::Identifier(s), pos) | (Token::StringConstant(s), pos) => {
2021-11-11 06:55:52 +01:00
if map.iter().any(|(p, _)| p.name == &*s) {
return Err(PERR::DuplicatedProperty(s.to_string()).into_err(pos));
2020-11-13 11:32:18 +01:00
}
(s, pos)
}
(Token::InterpolatedString(_), pos) => return Err(PERR::PropertyExpected.into_err(pos)),
(Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => {
2021-11-11 06:55:52 +01:00
return Err(PERR::Reserved(s.to_string()).into_err(pos));
}
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(Token::EOF, pos) => {
return Err(
PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into())
.into_err(pos),
);
}
(_, pos) if map.is_empty() => {
return Err(
PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into())
.into_err(pos),
);
}
(_, pos) => return Err(PERR::PropertyExpected.into_err(pos)),
};
2020-03-29 17:53:35 +02:00
2021-05-22 13:14:24 +02:00
match input.next().expect(NEVER_ENDS) {
(Token::Colon, _) => (),
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => {
return Err(PERR::MissingToken(
Token::Colon.into(),
format!(
"to follow the property '{}' in this object map literal",
name
),
)
.into_err(pos))
2020-06-14 08:25:47 +02:00
}
};
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
if state.engine.max_map_size() > 0 && map.len() >= state.engine.max_map_size() {
return Err(PERR::LiteralTooLarge(
"Number of properties in object map literal".to_string(),
state.engine.max_map_size(),
)
2021-05-22 13:14:24 +02:00
.into_err(input.peek().expect(NEVER_ENDS).1));
2020-06-16 16:14:46 +02:00
}
2020-03-29 17:53:35 +02:00
let expr = parse_expr(input, state, lib, settings.level_up())?;
2021-12-27 14:56:50 +01:00
let name = state.get_identifier("", name);
template.insert(name.clone(), crate::Dynamic::UNIT);
2021-03-10 05:27:10 +01:00
map.push((Ident { name, pos }, expr));
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
2020-06-16 16:14:46 +02:00
(Token::Comma, _) => {
eat_token(input, Token::Comma);
}
(Token::RightBrace, _) => (),
(Token::Identifier(_), pos) => {
return Err(PERR::MissingToken(
Token::Comma.into(),
"to separate the items of this object map literal".into(),
)
.into_err(*pos))
}
2020-11-25 02:36:06 +01:00
(Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
2020-06-16 16:14:46 +02:00
(_, pos) => {
return Err(
PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into())
.into_err(*pos),
)
2020-03-29 17:53:35 +02:00
}
}
}
2021-03-29 05:36:02 +02:00
map.shrink_to_fit();
2021-06-29 12:25:20 +02:00
Ok(Expr::Map((map, template).into(), settings.pos))
2020-03-29 17:53:35 +02:00
}
2020-11-13 11:32:18 +01:00
/// Parse a switch expression.
fn parse_switch(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Stmt> {
2020-11-13 11:32:18 +01:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2020-12-28 02:49:54 +01:00
// switch ...
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2020-12-28 02:49:54 +01:00
settings.pos = eat_token(input, Token::Switch);
2020-11-13 11:32:18 +01:00
let item = parse_expr(input, state, lib, settings.level_up())?;
2021-05-22 13:14:24 +02:00
match input.next().expect(NEVER_ENDS) {
2020-11-13 11:32:18 +01:00
(Token::LeftBrace, _) => (),
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => {
return Err(PERR::MissingToken(
Token::LeftBrace.into(),
"to start a switch block".into(),
)
.into_err(pos))
}
}
2021-04-16 06:04:33 +02:00
let mut table = BTreeMap::<u64, Box<(Option<Expr>, StmtBlock)>>::new();
2021-12-15 05:06:17 +01:00
let mut ranges = StaticVec::<(INT, INT, bool, Option<Expr>, StmtBlock)>::new();
2021-04-16 03:41:02 +02:00
let mut def_pos = Position::NONE;
2020-11-13 11:32:18 +01:00
let mut def_stmt = None;
loop {
const MISSING_RBRACE: &str = "to end this switch block";
2021-05-22 13:14:24 +02:00
let (expr, condition) = match input.peek().expect(NEVER_ENDS) {
2020-11-13 11:32:18 +01:00
(Token::RightBrace, _) => {
eat_token(input, Token::RightBrace);
break;
}
(Token::EOF, pos) => {
return Err(
PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into())
.into_err(*pos),
)
}
2021-04-16 03:41:02 +02:00
(Token::Underscore, pos) if def_stmt.is_none() => {
def_pos = *pos;
2020-11-13 11:32:18 +01:00
eat_token(input, Token::Underscore);
2021-04-16 07:28:36 +02:00
let (if_clause, if_pos) = match_token(input, Token::If);
if if_clause {
return Err(PERR::WrongSwitchCaseCondition.into_err(if_pos));
}
2021-04-16 06:04:33 +02:00
(None, None)
2020-11-13 11:32:18 +01:00
}
(Token::Underscore, pos) => return Err(PERR::DuplicatedSwitchCase.into_err(*pos)),
2021-12-15 05:06:17 +01:00
2021-04-16 03:41:02 +02:00
_ if def_stmt.is_some() => return Err(PERR::WrongSwitchDefaultCase.into_err(def_pos)),
2021-04-16 06:04:33 +02:00
_ => {
let case_expr = Some(parse_expr(input, state, lib, settings.level_up())?);
let condition = if match_token(input, Token::If).0 {
Some(parse_expr(input, state, lib, settings.level_up())?)
} else {
None
};
(case_expr, condition)
}
2020-11-13 11:32:18 +01:00
};
2021-12-15 05:06:17 +01:00
let (hash, range) = if let Some(expr) = expr {
2021-12-12 05:33:22 +01:00
let value = expr.get_literal_value().ok_or_else(|| {
PERR::ExprExpected("a literal".to_string()).into_err(expr.position())
})?;
2020-11-13 11:32:18 +01:00
2021-12-15 05:06:17 +01:00
let guard = value.read_lock::<ExclusiveRange>();
if let Some(range) = guard {
(None, Some((range.start, range.end, false)))
} else if let Some(range) = value.read_lock::<InclusiveRange>() {
(None, Some((*range.start(), *range.end(), true)))
} else if value.is::<INT>() && !ranges.is_empty() {
return Err(PERR::WrongSwitchIntegerCase.into_err(expr.position()));
} else {
let hasher = &mut get_hasher();
value.hash(hasher);
let hash = hasher.finish();
2021-12-12 05:33:22 +01:00
2021-12-15 05:06:17 +01:00
if table.contains_key(&hash) {
return Err(PERR::DuplicatedSwitchCase.into_err(expr.position()));
}
(Some(hash), None)
}
2020-11-13 11:32:18 +01:00
} else {
2021-12-15 05:06:17 +01:00
(None, None)
2020-11-13 11:32:18 +01:00
};
2021-05-22 13:14:24 +02:00
match input.next().expect(NEVER_ENDS) {
2020-11-13 11:32:18 +01:00
(Token::DoubleArrow, _) => (),
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => {
return Err(PERR::MissingToken(
Token::DoubleArrow.into(),
"in this switch case".to_string(),
)
.into_err(pos))
}
};
2020-12-29 03:41:20 +01:00
let stmt = parse_stmt(input, state, lib, settings.level_up())?;
2020-11-13 11:32:18 +01:00
let need_comma = !stmt.is_self_terminated();
2021-12-15 05:06:17 +01:00
def_stmt = match (hash, range) {
(None, Some(range)) => {
let is_empty = if range.2 {
(range.0..=range.1).is_empty()
} else {
(range.0..range.1).is_empty()
};
if !is_empty {
match (range.1.checked_sub(range.0), range.2) {
// Unroll single range
(Some(1), false) | (Some(0), true) => {
let value = Dynamic::from_int(range.0);
let hasher = &mut get_hasher();
value.hash(hasher);
let hash = hasher.finish();
2021-12-22 15:22:20 +01:00
table
.entry(hash)
.or_insert_with(|| (condition.clone(), stmt.into()).into());
}
// Other range
_ => ranges.push((range.0, range.1, range.2, condition, stmt.into())),
}
}
2021-12-15 05:06:17 +01:00
None
}
(Some(hash), None) => {
2021-12-12 05:33:22 +01:00
table.insert(hash, (condition, stmt.into()).into());
None
}
2021-12-15 05:06:17 +01:00
(None, None) => Some(stmt.into()),
_ => unreachable!("both hash and range in `switch` statement case"),
2020-11-13 11:32:18 +01:00
};
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
2020-11-13 11:32:18 +01:00
(Token::Comma, _) => {
eat_token(input, Token::Comma);
}
(Token::RightBrace, _) => (),
(Token::EOF, pos) => {
return Err(
PERR::MissingToken(Token::RightParen.into(), MISSING_RBRACE.into())
.into_err(*pos),
)
}
2020-11-25 02:36:06 +01:00
(Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
2020-11-13 11:32:18 +01:00
(_, pos) if need_comma => {
return Err(PERR::MissingToken(
Token::Comma.into(),
"to separate the items in this switch block".into(),
)
.into_err(*pos))
}
(_, _) => (),
}
}
2021-06-29 12:25:20 +02:00
let def_stmt_block = def_stmt.unwrap_or_else(|| Stmt::Noop(Position::NONE).into());
2020-11-14 16:43:36 +01:00
Ok(Stmt::Switch(
item,
2021-12-15 05:06:17 +01:00
(table, def_stmt_block, ranges).into(),
2020-11-13 11:32:18 +01:00
settings.pos,
))
}
2020-03-18 03:36:50 +01:00
/// Parse a primary expression.
2020-06-11 12:13:33 +02:00
fn parse_primary(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Expr> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2021-05-22 13:14:24 +02:00
let (token, token_pos) = input.peek().expect(NEVER_ENDS);
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2020-12-28 02:49:54 +01:00
settings.pos = *token_pos;
2021-12-16 15:40:10 +01:00
let root_expr = match token {
2020-12-27 09:50:48 +01:00
Token::EOF => return Err(PERR::UnexpectedEOF.into_err(settings.pos)),
Token::IntegerConstant(_)
| Token::CharConstant(_)
| Token::StringConstant(_)
| Token::True
2021-05-22 13:14:24 +02:00
| Token::False => match input.next().expect(NEVER_ENDS).0 {
2020-12-27 09:50:48 +01:00
Token::IntegerConstant(x) => Expr::IntegerConstant(x, settings.pos),
Token::CharConstant(c) => Expr::CharConstant(c, settings.pos),
Token::StringConstant(s) => {
2021-12-27 14:56:50 +01:00
Expr::StringConstant(state.get_identifier("", s).into(), settings.pos)
2020-12-27 09:50:48 +01:00
}
Token::True => Expr::BoolConstant(true, settings.pos),
Token::False => Expr::BoolConstant(false, settings.pos),
2021-03-07 15:10:54 +01:00
_ => unreachable!(),
2020-12-27 09:50:48 +01:00
},
#[cfg(not(feature = "no_float"))]
Token::FloatConstant(x) => {
2021-07-24 08:11:16 +02:00
let x = *x;
2021-05-22 13:14:24 +02:00
input.next().expect(NEVER_ENDS);
2020-12-27 09:50:48 +01:00
Expr::FloatConstant(x, settings.pos)
}
2021-02-13 13:57:56 +01:00
#[cfg(feature = "decimal")]
Token::DecimalConstant(x) => {
let x = (*x).into();
2021-05-22 13:14:24 +02:00
input.next().expect(NEVER_ENDS);
2021-02-13 13:57:56 +01:00
Expr::DynamicConstant(Box::new(x), settings.pos)
}
2020-12-27 09:50:48 +01:00
// { - block statement as expression
Token::LeftBrace if settings.allow_stmt_expr => {
2020-12-27 09:50:48 +01:00
match parse_block(input, state, lib, settings.level_up())? {
2021-03-10 15:12:48 +01:00
block @ Stmt::Block(_, _) => Expr::Stmt(Box::new(block.into())),
stmt => unreachable!("expecting Stmt::Block, but gets {:?}", stmt),
2020-12-27 09:50:48 +01:00
}
2020-03-07 03:39:00 +01:00
}
2020-12-27 09:50:48 +01:00
// ( - grouped expression
Token::LeftParen => parse_paren_expr(input, state, lib, settings.level_up())?,
2020-07-30 12:18:28 +02:00
2020-12-27 09:50:48 +01:00
// If statement is allowed to act as expressions
2021-03-10 15:12:48 +01:00
Token::If if settings.allow_if_expr => Expr::Stmt(Box::new(
parse_if(input, state, lib, settings.level_up())?.into(),
)),
2020-12-27 09:50:48 +01:00
// Switch statement is allowed to act as expressions
2021-03-10 15:12:48 +01:00
Token::Switch if settings.allow_switch_expr => Expr::Stmt(Box::new(
parse_switch(input, state, lib, settings.level_up())?.into(),
)),
2020-12-27 09:50:48 +01:00
// | ...
#[cfg(not(feature = "no_function"))]
Token::Pipe | Token::Or if settings.allow_anonymous_fn => {
let mut new_state = ParseState::new(state.engine, state.tokenizer_control.clone());
2021-04-04 18:05:56 +02:00
#[cfg(not(feature = "unchecked"))]
{
new_state.max_expr_depth = new_state.max_function_expr_depth;
}
2020-08-08 16:59:05 +02:00
2021-12-04 10:57:28 +01:00
let new_settings = ParseSettings {
2021-12-03 04:16:35 +01:00
allow_if_expr: settings.default_options.allow_if_expr,
allow_switch_expr: settings.default_options.allow_switch_expr,
allow_stmt_expr: settings.default_options.allow_stmt_expr,
allow_anonymous_fn: settings.default_options.allow_anonymous_fn,
2021-12-04 10:57:28 +01:00
strict_var: if cfg!(feature = "no_closure") {
settings.strict_var
} else {
// A capturing closure can access variables not defined locally
false
},
2020-12-27 09:50:48 +01:00
is_global: false,
is_function_scope: true,
2021-12-04 10:57:28 +01:00
#[cfg(not(feature = "no_closure"))]
is_closure: true,
2020-12-27 09:50:48 +01:00
is_breakable: false,
level: 0,
2021-12-03 04:16:35 +01:00
..settings
2020-12-22 09:45:56 +01:00
};
2020-12-27 09:50:48 +01:00
2021-12-04 10:57:28 +01:00
let (expr, func) = parse_anon_fn(input, &mut new_state, lib, new_settings)?;
2020-12-27 09:50:48 +01:00
2020-08-22 16:44:24 +02:00
#[cfg(not(feature = "no_closure"))]
2021-12-04 10:57:28 +01:00
new_state.external_vars.iter().try_for_each(
2021-12-25 16:49:14 +01:00
|(captured_var, &pos)| -> ParseResult<_> {
2021-12-04 10:57:28 +01:00
let index = state.access_var(captured_var, pos);
if !settings.is_closure && settings.strict_var && index.is_none() {
// If the parent scope is not inside another capturing closure
2021-12-27 05:27:31 +01:00
Err(PERR::VariableUndefined(captured_var.to_string()).into_err(pos))
2021-12-04 10:57:28 +01:00
} else {
Ok(())
}
},
)?;
2020-12-27 09:50:48 +01:00
2021-05-19 14:26:11 +02:00
let hash_script = calc_fn_hash(&func.name, func.params.len());
2021-03-12 07:11:08 +01:00
lib.insert(hash_script, func.into());
2020-12-27 09:50:48 +01:00
expr
2020-08-22 16:44:24 +02:00
}
2020-12-27 09:50:48 +01:00
2021-04-04 07:13:07 +02:00
// Interpolated string
Token::InterpolatedString(_) => {
2021-09-11 13:40:40 +02:00
let mut segments = StaticVec::<Expr>::new();
2021-04-04 07:13:07 +02:00
2021-05-22 13:14:24 +02:00
if let (Token::InterpolatedString(s), pos) = input.next().expect(NEVER_ENDS) {
2021-04-04 07:13:07 +02:00
segments.push(Expr::StringConstant(s.into(), pos));
} else {
unreachable!();
}
loop {
let expr = match parse_block(input, state, lib, settings.level_up())? {
block @ Stmt::Block(_, _) => Expr::Stmt(Box::new(block.into())),
stmt => unreachable!("expecting Stmt::Block, but gets {:?}", stmt),
};
segments.push(expr);
// Make sure to parse the following as text
let mut control = state.tokenizer_control.get();
control.is_within_text = true;
state.tokenizer_control.set(control);
2021-04-04 07:13:07 +02:00
2021-05-22 13:14:24 +02:00
match input.next().expect(NEVER_ENDS) {
2021-04-04 07:13:07 +02:00
(Token::StringConstant(s), pos) => {
if !s.is_empty() {
segments.push(Expr::StringConstant(s.into(), pos));
}
// End the interpolated string if it is terminated by a back-tick.
break;
}
(Token::InterpolatedString(s), pos) => {
if !s.is_empty() {
segments.push(Expr::StringConstant(s.into(), pos));
}
}
(Token::LexError(err @ LexError::UnterminatedString), pos) => {
return Err(err.into_err(pos))
}
2021-04-04 07:13:07 +02:00
(token, _) => unreachable!(
"expected a string within an interpolated string literal, but gets {:?}",
token
),
}
}
2021-05-05 12:38:52 +02:00
segments.shrink_to_fit();
2021-06-29 12:41:03 +02:00
Expr::InterpolatedString(segments.into(), settings.pos)
2021-04-04 07:13:07 +02:00
}
2020-12-27 09:50:48 +01:00
// Array literal
#[cfg(not(feature = "no_index"))]
Token::LeftBracket => parse_array_literal(input, state, lib, settings.level_up())?,
// Map literal
#[cfg(not(feature = "no_object"))]
Token::MapStart => parse_map_literal(input, state, lib, settings.level_up())?,
2021-12-16 15:40:10 +01:00
// Custom syntax.
Token::Custom(key) | Token::Reserved(key) | Token::Identifier(key)
if state.engine.custom_syntax.contains_key(&**key) =>
{
let (key, syntax) = state
.engine
.custom_syntax
.get_key_value(&**key)
.expect("exists");
let (_, pos) = input.next().expect(NEVER_ENDS);
let settings2 = settings.level_up();
parse_custom_syntax(input, state, lib, settings2, key, syntax, pos)?
}
2020-12-27 09:50:48 +01:00
// Identifier
Token::Identifier(_) => {
2021-05-22 13:14:24 +02:00
let s = match input.next().expect(NEVER_ENDS) {
2021-04-04 07:13:07 +02:00
(Token::Identifier(s), _) => s,
2021-03-07 15:10:54 +01:00
_ => unreachable!(),
2020-12-22 09:45:56 +01:00
};
2020-08-22 16:44:24 +02:00
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS).0 {
2020-12-27 09:50:48 +01:00
// Function call
Token::LeftParen | Token::Bang => {
#[cfg(not(feature = "no_closure"))]
{
2021-02-03 12:14:26 +01:00
// Once the identifier consumed we must enable next variables capturing
2020-12-27 09:50:48 +01:00
state.allow_capture = true;
}
2021-04-05 17:59:15 +02:00
Expr::Variable(
None,
settings.pos,
2021-12-27 14:56:50 +01:00
(None, None, state.get_identifier("", s)).into(),
2021-04-05 17:59:15 +02:00
)
2020-12-27 09:50:48 +01:00
}
// Namespace qualification
#[cfg(not(feature = "no_module"))]
Token::DoubleColon => {
#[cfg(not(feature = "no_closure"))]
{
2021-02-03 12:14:26 +01:00
// Once the identifier consumed we must enable next variables capturing
2020-12-27 09:50:48 +01:00
state.allow_capture = true;
}
2021-04-05 17:59:15 +02:00
Expr::Variable(
None,
settings.pos,
2021-12-27 14:56:50 +01:00
(None, None, state.get_identifier("", s)).into(),
2021-04-05 17:59:15 +02:00
)
2020-12-27 09:50:48 +01:00
}
// Normal variable access
_ => {
let index = state.access_var(&s, settings.pos);
2021-12-04 10:57:28 +01:00
if settings.strict_var && index.is_none() {
2021-12-27 05:27:31 +01:00
return Err(PERR::VariableUndefined(s.to_string()).into_err(settings.pos));
2021-12-04 10:57:28 +01:00
}
2021-04-05 17:06:48 +02:00
let short_index = index.and_then(|x| {
if x.get() <= u8::MAX as usize {
NonZeroU8::new(x.get() as u8)
} else {
None
}
});
2021-04-05 17:59:15 +02:00
Expr::Variable(
short_index,
settings.pos,
2021-12-27 14:56:50 +01:00
(index, None, state.get_identifier("", s)).into(),
2021-04-05 17:59:15 +02:00
)
2020-12-27 09:50:48 +01:00
}
2020-07-26 16:25:30 +02:00
}
2020-07-16 06:09:31 +02:00
}
2020-08-22 16:44:24 +02:00
2020-12-27 09:50:48 +01:00
// Reserved keyword or symbol
Token::Reserved(_) => {
2021-05-22 13:14:24 +02:00
let s = match input.next().expect(NEVER_ENDS) {
2021-04-04 07:13:07 +02:00
(Token::Reserved(s), _) => s,
2021-03-07 15:10:54 +01:00
_ => unreachable!(),
2020-12-27 09:50:48 +01:00
};
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS).0 {
2020-12-27 09:50:48 +01:00
// Function call is allowed to have reserved keyword
2021-04-05 17:59:15 +02:00
Token::LeftParen | Token::Bang if is_keyword_function(&s) => Expr::Variable(
None,
settings.pos,
2021-12-27 14:56:50 +01:00
(None, None, state.get_identifier("", s)).into(),
2021-04-05 17:59:15 +02:00
),
2021-02-03 12:14:26 +01:00
// Access to `this` as a variable is OK within a function scope
2021-11-28 03:49:48 +01:00
#[cfg(not(feature = "no_function"))]
2021-11-11 06:55:52 +01:00
_ if &*s == KEYWORD_THIS && settings.is_function_scope => Expr::Variable(
2021-04-05 17:59:15 +02:00
None,
settings.pos,
2021-12-27 14:56:50 +01:00
(None, None, state.get_identifier("", s)).into(),
2021-04-05 17:59:15 +02:00
),
2021-02-03 12:14:26 +01:00
// Cannot access to `this` as a variable not in a function scope
2021-11-11 06:55:52 +01:00
_ if &*s == KEYWORD_THIS => {
2021-02-03 12:14:26 +01:00
let msg = format!("'{}' can only be used in functions", s);
2021-11-11 06:55:52 +01:00
return Err(LexError::ImproperSymbol(s.to_string(), msg).into_err(settings.pos));
2020-12-27 09:50:48 +01:00
}
_ => return Err(PERR::Reserved(s.to_string()).into_err(settings.pos)),
2020-07-16 06:09:31 +02:00
}
}
2020-08-22 16:44:24 +02:00
2021-05-22 13:14:24 +02:00
Token::LexError(_) => match input.next().expect(NEVER_ENDS) {
2021-04-04 07:13:07 +02:00
(Token::LexError(err), _) => return Err(err.into_err(settings.pos)),
_ => unreachable!(),
},
2020-08-22 16:44:24 +02:00
2020-06-14 08:25:47 +02:00
_ => {
2021-02-03 12:14:26 +01:00
return Err(LexError::UnexpectedInput(token.syntax().to_string()).into_err(settings.pos))
2020-04-17 13:00:52 +02:00
}
};
2021-12-16 15:40:10 +01:00
parse_postfix(input, state, lib, root_expr, settings)
}
/// Tail processing of all possible postfix operators of a primary expression.
fn parse_postfix(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-12-16 15:40:10 +01:00
mut lhs: Expr,
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Expr> {
2021-12-16 15:40:10 +01:00
let mut settings = settings;
2020-04-17 13:00:52 +02:00
// Tail processing all possible postfix operators
loop {
2021-05-22 13:14:24 +02:00
let (tail_token, _) = input.peek().expect(NEVER_ENDS);
2021-12-16 15:40:10 +01:00
if !lhs.is_valid_postfix(tail_token) {
2020-04-17 13:00:52 +02:00
break;
2020-03-24 09:46:47 +01:00
}
2020-03-05 13:28:03 +01:00
2021-05-22 13:14:24 +02:00
let (tail_token, tail_pos) = input.next().expect(NEVER_ENDS);
2020-12-27 09:50:48 +01:00
settings.pos = tail_pos;
2020-04-10 06:16:39 +02:00
2021-12-16 15:40:10 +01:00
lhs = match (lhs, tail_token) {
2020-10-12 10:59:59 +02:00
// Qualified function call with !
2021-04-05 17:59:15 +02:00
(Expr::Variable(_, _, x), Token::Bang) if x.1.is_some() => {
2021-11-16 16:13:53 +01:00
return if !match_token(input, Token::LeftParen).0 {
Err(LexError::UnexpectedInput(Token::Bang.syntax().to_string())
.into_err(tail_pos))
2020-10-12 10:59:59 +02:00
} else {
2021-11-16 16:13:53 +01:00
Err(LexError::ImproperSymbol(
"!".to_string(),
2020-11-02 05:50:27 +01:00
"'!' cannot be used to call module functions".to_string(),
2020-12-22 04:55:51 +01:00
)
2021-11-16 16:13:53 +01:00
.into_err(tail_pos))
};
2020-10-12 10:59:59 +02:00
}
// Function call with !
2021-11-16 16:13:53 +01:00
(Expr::Variable(_, pos, x), Token::Bang) => {
match match_token(input, Token::LeftParen) {
(false, pos) => {
return Err(PERR::MissingToken(
Token::LeftParen.syntax().into(),
"to start arguments list of function call".into(),
)
.into_err(pos))
}
_ => (),
2020-07-30 12:18:28 +02:00
}
2021-04-05 17:59:15 +02:00
let (_, namespace, name) = *x;
2021-11-16 16:13:53 +01:00
settings.pos = pos;
2021-06-16 12:36:33 +02:00
let ns = namespace.map(|(ns, _)| ns);
2020-12-24 16:22:50 +01:00
parse_fn_call(input, state, lib, name, true, ns, settings.level_up())?
2020-07-30 12:18:28 +02:00
}
2020-04-17 13:00:52 +02:00
// Function call
2021-11-16 16:13:53 +01:00
(Expr::Variable(_, pos, x), Token::LeftParen) => {
2021-04-05 17:59:15 +02:00
let (_, namespace, name) = *x;
2021-06-16 12:36:33 +02:00
let ns = namespace.map(|(ns, _)| ns);
2021-11-16 16:13:53 +01:00
settings.pos = pos;
2020-12-24 16:22:50 +01:00
parse_fn_call(input, state, lib, name, false, ns, settings.level_up())?
}
2020-05-04 17:07:42 +02:00
// module access
2021-10-29 11:01:29 +02:00
#[cfg(not(feature = "no_module"))]
2021-11-16 16:13:53 +01:00
(Expr::Variable(_, pos, x), Token::DoubleColon) => {
2021-06-07 05:43:00 +02:00
let (id2, pos2) = parse_var_name(input)?;
2021-11-16 16:13:53 +01:00
let (_, mut namespace, name) = *x;
let var_name_def = Ident { name, pos };
2020-06-11 17:08:00 +02:00
2021-06-16 12:36:33 +02:00
if let Some((ref mut namespace, _)) = namespace {
2021-06-07 05:43:00 +02:00
namespace.push(var_name_def);
} else {
2021-12-25 16:49:14 +01:00
let mut ns = Namespace::new();
2021-06-07 05:43:00 +02:00
ns.push(var_name_def);
2021-06-16 12:36:33 +02:00
namespace = Some((ns, 42));
}
2021-06-07 05:43:00 +02:00
Expr::Variable(
None,
pos2,
2021-12-27 14:56:50 +01:00
(None, namespace, state.get_identifier("", id2)).into(),
2021-06-07 05:43:00 +02:00
)
2021-05-22 13:14:24 +02:00
}
2020-04-17 13:00:52 +02:00
// Indexing
#[cfg(not(feature = "no_index"))]
2020-04-28 17:05:03 +02:00
(expr, Token::LeftBracket) => {
parse_index_chain(input, state, lib, expr, settings.level_up())?
2020-04-28 17:05:03 +02:00
}
2020-12-27 09:50:48 +01:00
// Property access
2020-12-21 10:39:37 +01:00
#[cfg(not(feature = "no_object"))]
(expr, Token::Period) => {
// Expression after dot must start with an identifier
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
(Token::Identifier(_), _) => {
#[cfg(not(feature = "no_closure"))]
{
// Prevents capturing of the object properties as vars: xxx.<var>
state.allow_capture = false;
}
}
(Token::Reserved(s), _) if is_keyword_function(s) => (),
(_, pos) => return Err(PERR::PropertyExpected.into_err(*pos)),
2020-12-27 04:50:24 +01:00
}
2020-12-28 02:49:54 +01:00
let rhs = parse_primary(input, state, lib, settings.level_up())?;
2021-07-24 06:27:33 +02:00
make_dot_expr(state, expr, false, rhs, tail_pos)?
2020-12-21 10:39:37 +01:00
}
2020-04-17 13:00:52 +02:00
// Unknown postfix operator
2020-06-16 16:14:46 +02:00
(expr, token) => unreachable!(
"unknown postfix operator '{}' for {:?}",
token.syntax(),
expr
),
}
2016-02-29 22:43:45 +01:00
}
2020-12-21 10:39:37 +01:00
// Cache the hash key for namespace-qualified variables
2021-12-16 15:40:10 +01:00
let namespaced_variable = match lhs {
2021-06-13 11:41:34 +02:00
Expr::Variable(_, _, ref mut x) if x.1.is_some() => Some(x.as_mut()),
2021-07-24 06:27:33 +02:00
Expr::Index(ref mut x, _, _) | Expr::Dot(ref mut x, _, _) => match x.lhs {
2021-06-13 11:41:34 +02:00
Expr::Variable(_, _, ref mut x) if x.1.is_some() => Some(x.as_mut()),
2020-12-21 10:39:37 +01:00
_ => None,
},
_ => None,
2021-07-24 08:11:16 +02:00
};
2021-12-04 10:57:28 +01:00
if let Some((_, Some((namespace, hash)), name)) = namespaced_variable {
*hash = calc_qualified_var_hash(namespace.iter().map(|v| v.name.as_str()), name);
2021-07-24 08:11:16 +02:00
2021-12-04 10:57:28 +01:00
#[cfg(not(feature = "no_module"))]
{
let index = state.find_module(&namespace[0].name);
2021-12-04 11:07:27 +01:00
#[cfg(not(feature = "no_function"))]
let relax = settings.is_function_scope;
#[cfg(feature = "no_function")]
let relax = false;
if !relax && settings.strict_var && index.is_none() {
2021-12-04 10:57:28 +01:00
return Err(
2021-12-27 05:27:31 +01:00
PERR::ModuleUndefined(namespace[0].name.to_string()).into_err(namespace[0].pos)
2021-12-04 10:57:28 +01:00
);
2021-07-24 08:11:16 +02:00
}
2021-12-04 10:57:28 +01:00
namespace.set_index(index);
2020-12-24 16:22:50 +01:00
}
2021-07-24 08:11:16 +02:00
}
2020-07-16 06:09:31 +02:00
// Make sure identifiers are valid
2021-12-16 15:40:10 +01:00
Ok(lhs)
2016-02-29 22:43:45 +01:00
}
2020-03-18 03:36:50 +01:00
/// Parse a potential unary operator.
2020-06-11 12:13:33 +02:00
fn parse_unary(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Expr> {
2021-11-16 16:13:53 +01:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2021-08-13 07:42:39 +02:00
2021-05-22 13:14:24 +02:00
let (token, token_pos) = input.peek().expect(NEVER_ENDS);
2020-07-26 09:53:22 +02:00
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2021-12-16 15:40:10 +01:00
settings.pos = *token_pos;
match token {
2020-03-18 03:36:50 +01:00
// -expr
2021-11-13 02:50:49 +01:00
Token::Minus | Token::UnaryMinus => {
let token = token.clone();
let pos = eat_token(input, token);
match parse_unary(input, state, lib, settings.level_up())? {
// Negative integer
2021-04-16 15:59:05 +02:00
Expr::IntegerConstant(num, _) => num
2020-10-31 07:13:45 +01:00
.checked_neg()
.map(|i| Expr::IntegerConstant(i, pos))
.or_else(|| {
#[cfg(not(feature = "no_float"))]
2021-12-06 13:52:47 +01:00
return Some(Expr::FloatConstant((-(num as crate::FLOAT)).into(), pos));
2020-10-31 07:13:45 +01:00
#[cfg(feature = "no_float")]
return None;
})
.ok_or_else(|| LexError::MalformedNumber(format!("-{}", num)).into_err(pos)),
// Negative float
#[cfg(not(feature = "no_float"))]
2021-04-16 15:59:05 +02:00
Expr::FloatConstant(x, _) => Ok(Expr::FloatConstant((-(*x)).into(), pos)),
// Call negative function
expr => {
2021-11-25 10:09:00 +01:00
let mut args = StaticVec::new_const();
args.push(expr);
2021-05-05 12:38:52 +02:00
args.shrink_to_fit();
2020-05-09 10:15:50 +02:00
2021-06-16 12:36:33 +02:00
Ok(FnCallExpr {
2021-12-27 14:56:50 +01:00
name: state.get_identifier("", "-"),
2021-06-16 12:36:33 +02:00
hashes: FnCallHashes::from_native(calc_fn_hash("-", 1)),
args,
..Default::default()
}
.into_fn_call_expr(pos))
2020-05-09 10:15:50 +02:00
}
}
2019-09-18 12:21:07 +02:00
}
2020-03-18 03:36:50 +01:00
// +expr
2021-11-13 02:50:49 +01:00
Token::Plus | Token::UnaryPlus => {
let token = token.clone();
let pos = eat_token(input, token);
2020-12-21 10:39:37 +01:00
match parse_unary(input, state, lib, settings.level_up())? {
expr @ Expr::IntegerConstant(_, _) => Ok(expr),
#[cfg(not(feature = "no_float"))]
expr @ Expr::FloatConstant(_, _) => Ok(expr),
// Call plus function
expr => {
2021-11-25 10:09:00 +01:00
let mut args = StaticVec::new_const();
2020-12-21 10:39:37 +01:00
args.push(expr);
2021-05-05 12:38:52 +02:00
args.shrink_to_fit();
2020-12-21 10:39:37 +01:00
2021-06-16 12:36:33 +02:00
Ok(FnCallExpr {
2021-12-27 14:56:50 +01:00
name: state.get_identifier("", "+"),
2021-06-16 12:36:33 +02:00
hashes: FnCallHashes::from_native(calc_fn_hash("+", 1)),
args,
..Default::default()
}
.into_fn_call_expr(pos))
2020-12-21 10:39:37 +01:00
}
}
2019-09-18 12:21:07 +02:00
}
2020-03-18 03:36:50 +01:00
// !expr
Token::Bang => {
2020-04-17 13:00:52 +02:00
let pos = eat_token(input, Token::Bang);
2021-11-25 10:09:00 +01:00
let mut args = StaticVec::new_const();
2021-05-05 12:38:52 +02:00
args.push(parse_unary(input, state, lib, settings.level_up())?);
args.shrink_to_fit();
2020-05-09 18:19:13 +02:00
2021-06-16 12:36:33 +02:00
Ok(FnCallExpr {
2021-12-27 14:56:50 +01:00
name: state.get_identifier("", "!"),
2021-06-16 12:36:33 +02:00
hashes: FnCallHashes::from_native(calc_fn_hash("!", 1)),
args,
..Default::default()
}
.into_fn_call_expr(pos))
2019-09-18 12:21:07 +02:00
}
// <EOF>
Token::EOF => Err(PERR::UnexpectedEOF.into_err(settings.pos)),
// All other tokens
_ => parse_primary(input, state, lib, settings.level_up()),
2017-10-30 16:08:44 +01:00
}
}
2020-12-26 06:05:57 +01:00
/// Make an assignment statement.
2021-07-24 08:11:16 +02:00
fn make_assignment_stmt(
2021-04-24 05:55:40 +02:00
op: Option<Token>,
state: &mut ParseState,
2020-04-22 11:37:06 +02:00
lhs: Expr,
rhs: Expr,
2020-12-22 09:45:56 +01:00
op_pos: Position,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Stmt> {
2021-06-12 16:47:43 +02:00
#[must_use]
2021-04-22 17:02:25 +02:00
fn check_lvalue(expr: &Expr, parent_is_dot: bool) -> Option<Position> {
2020-12-29 03:41:20 +01:00
match expr {
2021-11-01 02:55:50 +01:00
Expr::Index(x, term, _) | Expr::Dot(x, term, _) if parent_is_dot => match x.lhs {
Expr::Property(_) if !term => {
check_lvalue(&x.rhs, matches!(expr, Expr::Dot(_, _, _)))
}
Expr::Property(_) => None,
// Anything other than a property after dotting (e.g. a method call) is not an l-value
2021-04-22 17:02:25 +02:00
ref e => Some(e.position()),
2020-12-29 03:41:20 +01:00
},
2021-11-01 02:55:50 +01:00
Expr::Index(x, term, _) | Expr::Dot(x, term, _) => match x.lhs {
Expr::Property(_) => unreachable!("unexpected `Expr::Property` in indexing"),
2021-11-01 02:55:50 +01:00
_ if !term => check_lvalue(&x.rhs, matches!(expr, Expr::Dot(_, _, _))),
_ => None,
2020-12-29 03:41:20 +01:00
},
2021-04-22 17:02:25 +02:00
Expr::Property(_) if parent_is_dot => None,
Expr::Property(_) => unreachable!("unexpected `Expr::Property` in indexing"),
2021-04-22 17:02:25 +02:00
e if parent_is_dot => Some(e.position()),
_ => None,
2020-12-29 03:41:20 +01:00
}
}
2021-12-17 09:55:24 +01:00
let op_info = op.map(OpAssignment::new_from_token);
2021-03-08 08:30:32 +01:00
2021-06-13 11:41:34 +02:00
match lhs {
2020-12-29 03:41:20 +01:00
// const_expr = rhs
2021-06-13 11:41:34 +02:00
ref expr if expr.is_constant() => {
2020-12-29 03:41:20 +01:00
Err(PERR::AssignmentToConstant("".into()).into_err(lhs.position()))
}
2020-06-11 17:21:39 +02:00
// var (non-indexed) = rhs
2021-06-13 11:41:34 +02:00
Expr::Variable(None, _, ref x) if x.0.is_none() => {
2021-06-29 12:25:20 +02:00
Ok(Stmt::Assignment((lhs, op_info, rhs).into(), op_pos))
2021-03-08 08:30:32 +01:00
}
2020-06-11 17:21:39 +02:00
// var (indexed) = rhs
2021-06-13 11:41:34 +02:00
Expr::Variable(i, var_pos, ref x) => {
2021-04-05 17:59:15 +02:00
let (index, _, name) = x.as_ref();
2021-05-22 13:14:24 +02:00
let index = i.map_or_else(
|| {
index
2021-08-26 17:58:41 +02:00
.expect("the long index is `Some` when the short index is `None`")
2021-05-22 13:14:24 +02:00
.get()
},
|n| n.get() as usize,
);
2021-04-05 17:06:48 +02:00
match state.stack[state.stack.len() - index].1 {
2021-06-29 12:25:20 +02:00
AccessMode::ReadWrite => Ok(Stmt::Assignment((lhs, op_info, rhs).into(), op_pos)),
// Constant values cannot be assigned to
AccessMode::ReadOnly => {
2021-06-13 11:41:34 +02:00
Err(PERR::AssignmentToConstant(name.to_string()).into_err(var_pos))
}
}
}
2020-12-29 03:41:20 +01:00
// xxx[???]... = rhs, xxx.prop... = rhs
2021-11-01 02:55:50 +01:00
Expr::Index(ref x, term, _) | Expr::Dot(ref x, term, _) => {
let valid_lvalue = if term {
None
} else {
check_lvalue(&x.rhs, matches!(lhs, Expr::Dot(_, _, _)))
};
match valid_lvalue {
None => {
match x.lhs {
// var[???] = rhs, var.??? = rhs
Expr::Variable(_, _, _) => {
Ok(Stmt::Assignment((lhs, op_info, rhs).into(), op_pos))
}
// expr[???] = rhs, expr.??? = rhs
ref expr => {
Err(PERR::AssignmentToInvalidLHS("".to_string())
.into_err(expr.position()))
}
2020-12-29 03:41:20 +01:00
}
2021-11-01 02:55:50 +01:00
}
Some(err_pos) => {
Err(PERR::AssignmentToInvalidLHS("".to_string()).into_err(err_pos))
}
}
}
2020-06-11 17:21:39 +02:00
// ??? && ??? = rhs, ??? || ??? = rhs
2020-12-22 04:55:51 +01:00
Expr::And(_, _) | Expr::Or(_, _) => Err(LexError::ImproperSymbol(
"=".to_string(),
2020-11-02 05:50:27 +01:00
"Possibly a typo of '=='?".to_string(),
2020-12-22 04:55:51 +01:00
)
2020-12-22 09:45:56 +01:00
.into_err(op_pos)),
2020-06-11 17:21:39 +02:00
// expr = rhs
_ => Err(PERR::AssignmentToInvalidLHS("".to_string()).into_err(lhs.position())),
}
2020-04-22 11:37:06 +02:00
}
2021-11-16 16:13:53 +01:00
/// Parse an operator-assignment expression (if any).
2020-06-11 12:13:33 +02:00
fn parse_op_assignment_stmt(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2020-04-06 06:29:01 +02:00
lhs: Expr,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Stmt> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2021-11-16 16:13:53 +01:00
let (op, pos) = match input.peek().expect(NEVER_ENDS) {
// var = ...
(Token::Equals, _) => (None, eat_token(input, Token::Equals)),
// var op= ...
(token, _) if token.is_op_assignment() => input
2021-05-22 13:14:24 +02:00
.next()
.map(|(op, pos)| (Some(op), pos))
.expect(NEVER_ENDS),
2021-11-16 16:13:53 +01:00
// Not op-assignment
2020-10-27 16:21:20 +01:00
_ => return Ok(Stmt::Expr(lhs)),
2020-04-22 11:37:06 +02:00
};
2021-11-16 16:13:53 +01:00
let mut settings = settings;
settings.pos = pos;
let rhs = parse_expr(input, state, lib, settings.level_up())?;
2020-05-25 14:14:31 +02:00
make_assignment_stmt(op, state, lhs, rhs, pos)
2020-04-26 12:04:07 +02:00
}
/// Make a dot expression.
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "no_object"))]
fn make_dot_expr(
state: &mut ParseState,
lhs: Expr,
2021-07-24 06:27:33 +02:00
terminate_chaining: bool,
rhs: Expr,
op_pos: Position,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Expr> {
2021-11-16 16:13:53 +01:00
match (lhs, rhs) {
2021-07-24 06:27:33 +02:00
// lhs[idx_expr].rhs
2021-08-17 12:14:16 +02:00
(Expr::Index(mut x, term, pos), rhs) => {
x.rhs = make_dot_expr(state, x.rhs, term || terminate_chaining, rhs, op_pos)?;
2021-11-16 16:13:53 +01:00
Ok(Expr::Index(x, false, pos))
}
2020-04-26 12:04:07 +02:00
// lhs.id
2021-07-24 06:27:33 +02:00
(lhs, var_expr @ Expr::Variable(_, _, _)) if var_expr.is_variable_access(true) => {
let rhs = var_expr.into_property(state);
2021-11-16 16:13:53 +01:00
Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos))
}
2020-05-04 13:36:58 +02:00
// lhs.module::id - syntax error
2021-07-24 06:27:33 +02:00
(_, Expr::Variable(_, _, x)) => {
2021-11-16 16:13:53 +01:00
Err(PERR::PropertyExpected.into_err(x.1.expect("`Some`").0[0].pos))
2020-05-04 11:43:54 +02:00
}
// lhs.prop
2021-11-16 16:13:53 +01:00
(lhs, prop @ Expr::Property(_)) => Ok(Expr::Dot(
BinaryExpr { lhs, rhs: prop }.into(),
false,
op_pos,
)),
2021-08-17 09:32:48 +02:00
// lhs.dot_lhs.dot_rhs or lhs.dot_lhs[idx_rhs]
(lhs, rhs @ Expr::Dot(_, _, _)) | (lhs, rhs @ Expr::Index(_, _, _)) => {
let (x, term, pos, is_dot) = match rhs {
Expr::Dot(x, term, pos) => (x, term, pos, true),
Expr::Index(x, term, pos) => (x, term, pos, false),
_ => unreachable!(),
};
match x.lhs {
Expr::Variable(_, _, _) | Expr::Property(_) => {
let new_lhs = BinaryExpr {
lhs: x.lhs.into_property(state),
rhs: x.rhs,
2021-06-29 12:25:20 +02:00
}
2021-08-17 09:32:48 +02:00
.into();
let rhs = if is_dot {
Expr::Dot(new_lhs, term, pos)
} else {
Expr::Index(new_lhs, term, pos)
};
2021-11-16 16:13:53 +01:00
Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos))
2021-08-17 09:32:48 +02:00
}
Expr::FnCall(mut func, func_pos) => {
// Recalculate hash
func.hashes = FnCallHashes::from_all(
#[cfg(not(feature = "no_function"))]
2021-08-17 09:32:48 +02:00
calc_fn_hash(&func.name, func.args.len()),
calc_fn_hash(&func.name, func.args.len() + 1),
);
let new_lhs = BinaryExpr {
2021-03-08 08:30:32 +01:00
lhs: Expr::FnCall(func, func_pos),
rhs: x.rhs,
2021-06-29 12:25:20 +02:00
}
2021-08-17 09:32:48 +02:00
.into();
let rhs = if is_dot {
Expr::Dot(new_lhs, term, pos)
} else {
Expr::Index(new_lhs, term, pos)
};
2021-11-16 16:13:53 +01:00
Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos))
2021-06-29 12:25:20 +02:00
}
2021-08-17 09:32:48 +02:00
_ => unreachable!("invalid dot expression: {:?}", x.lhs),
}
2020-05-09 18:19:13 +02:00
}
2021-03-08 08:30:32 +01:00
// lhs.nnn::func(...)
2021-04-20 17:28:04 +02:00
(_, Expr::FnCall(x, _)) if x.is_qualified() => {
2021-03-08 08:30:32 +01:00
unreachable!("method call should not be namespace-qualified")
}
// lhs.Fn() or lhs.eval()
2020-10-31 16:26:21 +01:00
(_, Expr::FnCall(x, pos))
if x.args.is_empty()
&& [crate::engine::KEYWORD_FN_PTR, crate::engine::KEYWORD_EVAL]
.contains(&x.name.as_ref()) =>
{
2021-11-16 16:13:53 +01:00
Err(LexError::ImproperSymbol(
x.name.to_string(),
format!(
"'{}' should not be called in method style. Try {}(...);",
x.name, x.name
),
2020-12-22 04:55:51 +01:00
)
.into_err(pos))
}
2020-07-30 12:18:28 +02:00
// lhs.func!(...)
2021-11-16 16:13:53 +01:00
(_, Expr::FnCall(x, pos)) if x.capture_parent_scope => Err(PERR::MalformedCapture(
"method-call style does not support running within the caller's scope".into(),
)
.into_err(pos)),
2020-07-30 12:18:28 +02:00
// lhs.func(...)
2021-03-08 08:30:32 +01:00
(lhs, Expr::FnCall(mut func, func_pos)) => {
// Recalculate hash
func.hashes = FnCallHashes::from_all(
#[cfg(not(feature = "no_function"))]
calc_fn_hash(&func.name, func.args.len()),
calc_fn_hash(&func.name, func.args.len() + 1),
2021-03-08 08:30:32 +01:00
);
2021-03-08 08:30:32 +01:00
let rhs = Expr::FnCall(func, func_pos);
2021-11-16 16:13:53 +01:00
Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), false, op_pos))
2020-10-31 16:26:21 +01:00
}
2020-04-26 12:04:07 +02:00
// lhs.rhs
2021-11-16 16:13:53 +01:00
(_, rhs) => Err(PERR::PropertyExpected.into_err(rhs.position())),
}
2020-03-07 06:39:28 +01:00
}
2021-11-16 16:13:53 +01:00
/// Parse a binary expression (if any).
2020-06-11 12:13:33 +02:00
fn parse_binary_op(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-03-14 03:47:29 +01:00
parent_precedence: Option<Precedence>,
2019-09-18 12:21:07 +02:00
lhs: Expr,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Expr> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2020-12-28 02:49:54 +01:00
settings.pos = lhs.position();
let mut root = lhs;
2016-02-29 22:43:45 +01:00
loop {
2021-05-22 13:14:24 +02:00
let (current_op, current_pos) = input.peek().expect(NEVER_ENDS);
2020-12-26 16:21:09 +01:00
let precedence = match current_op {
2021-03-14 03:47:29 +01:00
Token::Custom(c) => state
.engine
.custom_keywords
2021-11-11 06:55:52 +01:00
.get(c.as_ref())
2021-03-14 03:47:29 +01:00
.cloned()
2021-11-11 06:55:52 +01:00
.ok_or_else(|| PERR::Reserved(c.to_string()).into_err(*current_pos))?,
2020-12-26 16:21:09 +01:00
Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
2021-11-11 06:55:52 +01:00
return Err(PERR::UnknownOperator(c.to_string()).into_err(*current_pos))
2020-12-26 16:21:09 +01:00
}
_ => current_op.precedence(),
2020-10-25 14:57:18 +01:00
};
let bind_right = current_op.is_bind_right();
2020-03-14 04:51:45 +01:00
// Bind left to the parent lhs expression if precedence is higher
// If same precedence, then check if the operator binds right
if precedence < parent_precedence || (precedence == parent_precedence && !bind_right) {
return Ok(root);
2016-02-29 22:43:45 +01:00
}
2021-05-22 13:14:24 +02:00
let (op_token, pos) = input.next().expect(NEVER_ENDS);
let rhs = parse_unary(input, state, lib, settings)?;
2016-02-29 22:43:45 +01:00
2021-05-22 13:14:24 +02:00
let (next_op, next_pos) = input.peek().expect(NEVER_ENDS);
2020-12-26 16:21:09 +01:00
let next_precedence = match next_op {
2021-03-14 03:47:29 +01:00
Token::Custom(c) => state
.engine
.custom_keywords
2021-11-11 06:55:52 +01:00
.get(c.as_ref())
2021-03-14 03:47:29 +01:00
.cloned()
2021-11-11 06:55:52 +01:00
.ok_or_else(|| PERR::Reserved(c.to_string()).into_err(*next_pos))?,
2020-12-26 16:21:09 +01:00
Token::Reserved(c) if !is_valid_identifier(c.chars()) => {
2021-11-11 06:55:52 +01:00
return Err(PERR::UnknownOperator(c.to_string()).into_err(*next_pos))
2020-12-26 16:21:09 +01:00
}
_ => next_op.precedence(),
2020-10-25 14:57:18 +01:00
};
// Bind to right if the next operator has higher precedence
// If same precedence, then check if the operator binds right
let rhs = if (precedence == next_precedence && bind_right) || precedence < next_precedence {
parse_binary_op(input, state, lib, precedence, rhs, settings)?
} else {
// Otherwise bind to left (even if next operator has the same precedence)
rhs
};
settings = settings.level_up();
settings.pos = pos;
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
let op = op_token.syntax();
2021-05-19 14:26:11 +02:00
let hash = calc_fn_hash(&op, 2);
2020-10-31 07:13:45 +01:00
2020-11-10 16:26:50 +01:00
let op_base = FnCallExpr {
2021-12-27 14:56:50 +01:00
name: state.get_identifier("", op.as_ref()),
2021-04-20 16:26:08 +02:00
hashes: FnCallHashes::from_native(hash),
2020-10-31 07:13:45 +01:00
..Default::default()
};
2021-11-25 10:09:00 +01:00
let mut args = StaticVec::new_const();
args.push(root);
args.push(rhs);
2021-05-05 12:38:52 +02:00
args.shrink_to_fit();
2020-04-22 11:37:06 +02:00
root = match op_token {
// '!=' defaults to true when passed invalid operands
2021-06-16 12:36:33 +02:00
Token::NotEqualsTo => FnCallExpr { args, ..op_base }.into_fn_call_expr(pos),
2020-04-28 17:05:03 +02:00
// Comparison operators default to false when passed invalid operands
Token::EqualsTo
| Token::LessThan
| Token::LessThanEqualsTo
| Token::GreaterThan
2021-06-16 12:36:33 +02:00
| Token::GreaterThanEqualsTo => FnCallExpr { args, ..op_base }.into_fn_call_expr(pos),
Token::Or => {
2021-11-13 05:23:35 +01:00
let rhs = args.pop().expect("two arguments");
let current_lhs = args.pop().expect("two arguments");
2020-10-31 16:26:21 +01:00
Expr::Or(
2021-06-29 12:25:20 +02:00
BinaryExpr {
2021-07-03 18:15:27 +02:00
lhs: current_lhs.ensure_bool_expr()?,
rhs: rhs.ensure_bool_expr()?,
2021-06-29 12:25:20 +02:00
}
.into(),
2020-10-27 16:00:05 +01:00
pos,
2020-10-31 16:26:21 +01:00
)
}
Token::And => {
2021-11-13 05:23:35 +01:00
let rhs = args.pop().expect("two arguments");
let current_lhs = args.pop().expect("two arguments");
2020-10-31 16:26:21 +01:00
Expr::And(
2021-06-29 12:25:20 +02:00
BinaryExpr {
2021-07-03 18:15:27 +02:00
lhs: current_lhs.ensure_bool_expr()?,
rhs: rhs.ensure_bool_expr()?,
2021-06-29 12:25:20 +02:00
}
.into(),
2020-10-27 16:00:05 +01:00
pos,
2020-10-31 16:26:21 +01:00
)
}
Token::In => {
// Swap the arguments
let current_lhs = args.remove(0);
args.push(current_lhs);
2021-05-05 12:38:52 +02:00
args.shrink_to_fit();
// Convert into a call to `contains`
2021-06-16 12:36:33 +02:00
FnCallExpr {
hashes: calc_fn_hash(OP_CONTAINS, 2).into(),
2021-06-16 12:36:33 +02:00
args,
2021-12-27 14:56:50 +01:00
name: state.get_identifier("", OP_CONTAINS),
2021-06-16 12:36:33 +02:00
..op_base
}
.into_fn_call_expr(pos)
}
2020-12-26 16:21:09 +01:00
Token::Custom(s)
if state
.engine
.custom_keywords
2021-11-11 06:55:52 +01:00
.get(s.as_ref())
.map_or(false, Option::is_some) =>
2020-12-26 16:21:09 +01:00
{
2021-05-19 14:26:11 +02:00
let hash = calc_fn_hash(&s, 2);
2020-12-26 16:21:09 +01:00
2021-06-16 12:36:33 +02:00
FnCallExpr {
2021-08-30 09:42:47 +02:00
hashes: if is_valid_function_name(&s) {
hash.into()
2021-06-16 12:36:33 +02:00
} else {
FnCallHashes::from_native(hash)
},
args,
..op_base
}
.into_fn_call_expr(pos)
2020-07-05 11:41:45 +02:00
}
2021-12-15 05:06:17 +01:00
_ => FnCallExpr { args, ..op_base }.into_fn_call_expr(pos),
};
2016-02-29 22:43:45 +01:00
}
}
/// Parse a custom syntax.
2020-10-25 14:57:18 +01:00
fn parse_custom_syntax(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-11-27 16:04:45 +01:00
key: impl Into<ImmutableString>,
syntax: &CustomSyntax,
pos: Position,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Expr> {
2021-08-13 07:42:39 +02:00
let mut settings = settings;
2021-10-25 16:41:42 +02:00
let mut inputs = StaticVec::<Expr>::new();
2021-11-25 10:09:00 +01:00
let mut segments = StaticVec::new_const();
let mut tokens = StaticVec::new_const();
// Adjust the variables stack
2021-07-03 18:15:27 +02:00
if syntax.scope_may_be_changed {
// Add a barrier variable to the stack so earlier variables will not be matched.
// Variable searches stop at the first barrier.
2021-12-27 14:56:50 +01:00
let marker = state.get_identifier("", SCOPE_SEARCH_BARRIER_MARKER);
2021-11-27 07:24:06 +01:00
state.stack.push((marker, AccessMode::ReadWrite));
}
2021-05-29 12:33:29 +02:00
let parse_func = syntax.parse.as_ref();
2021-08-02 04:24:03 +02:00
let mut required_token: ImmutableString = key.into();
2020-10-26 14:49:49 +01:00
2021-08-02 04:24:03 +02:00
tokens.push(required_token.clone().into());
segments.push(required_token.clone());
2020-10-25 14:57:18 +01:00
loop {
2021-05-22 13:14:24 +02:00
let (fwd_token, fwd_pos) = input.peek().expect(NEVER_ENDS);
settings.pos = *fwd_pos;
let settings = settings.level_up();
2021-11-11 06:55:52 +01:00
required_token = match parse_func(&segments, &*fwd_token.syntax()) {
2021-10-25 16:41:42 +02:00
Ok(Some(seg))
if seg.starts_with(CUSTOM_SYNTAX_MARKER_SYNTAX_VARIANT)
&& seg.len() > CUSTOM_SYNTAX_MARKER_SYNTAX_VARIANT.len() =>
{
2021-12-27 14:56:50 +01:00
inputs.push(Expr::StringConstant(
state.get_identifier("", seg).into(),
pos,
));
2021-10-25 16:41:42 +02:00
break;
}
2021-06-16 10:15:29 +02:00
Ok(Some(seg)) => seg,
Ok(None) => break,
Err(err) => return Err(err.0.into_err(settings.pos)),
};
match required_token.as_str() {
2021-06-28 12:06:05 +02:00
CUSTOM_SYNTAX_MARKER_IDENT => {
2021-06-07 05:43:00 +02:00
let (name, pos) = parse_var_name(input)?;
2021-12-27 14:56:50 +01:00
let name = state.get_identifier("", name);
2021-06-07 05:43:00 +02:00
segments.push(name.clone().into());
2021-12-27 14:56:50 +01:00
tokens.push(state.get_identifier("", CUSTOM_SYNTAX_MARKER_IDENT));
2021-10-25 16:41:42 +02:00
inputs.push(Expr::Variable(None, pos, (None, None, name).into()));
2021-06-07 05:43:00 +02:00
}
2021-07-10 09:50:31 +02:00
CUSTOM_SYNTAX_MARKER_SYMBOL => {
let (symbol, pos) = parse_symbol(input)?;
2021-12-27 14:56:50 +01:00
let symbol: ImmutableString = state.get_identifier("", symbol).into();
2021-07-10 09:50:31 +02:00
segments.push(symbol.clone());
2021-12-27 14:56:50 +01:00
tokens.push(state.get_identifier("", CUSTOM_SYNTAX_MARKER_SYMBOL));
2021-10-25 16:41:42 +02:00
inputs.push(Expr::StringConstant(symbol, pos));
2021-07-10 09:50:31 +02:00
}
2021-06-28 12:06:05 +02:00
CUSTOM_SYNTAX_MARKER_EXPR => {
2021-10-25 16:41:42 +02:00
inputs.push(parse_expr(input, state, lib, settings)?);
2021-12-27 14:56:50 +01:00
let keyword = state.get_identifier("", CUSTOM_SYNTAX_MARKER_EXPR);
2021-03-29 05:36:02 +02:00
segments.push(keyword.clone().into());
tokens.push(keyword);
2020-10-25 14:57:18 +01:00
}
2021-06-28 12:06:05 +02:00
CUSTOM_SYNTAX_MARKER_BLOCK => match parse_block(input, state, lib, settings)? {
2021-03-10 15:12:48 +01:00
block @ Stmt::Block(_, _) => {
2021-10-25 16:41:42 +02:00
inputs.push(Expr::Stmt(Box::new(block.into())));
2021-12-27 14:56:50 +01:00
let keyword = state.get_identifier("", CUSTOM_SYNTAX_MARKER_BLOCK);
2021-03-29 05:36:02 +02:00
segments.push(keyword.clone().into());
tokens.push(keyword);
2020-11-04 04:49:02 +01:00
}
stmt => unreachable!("expecting Stmt::Block, but gets {:?}", stmt),
2020-11-04 04:49:02 +01:00
},
2021-06-28 12:06:05 +02:00
CUSTOM_SYNTAX_MARKER_BOOL => match input.next().expect(NEVER_ENDS) {
2021-06-10 04:16:39 +02:00
(b @ Token::True, pos) | (b @ Token::False, pos) => {
2021-10-25 16:41:42 +02:00
inputs.push(Expr::BoolConstant(b == Token::True, pos));
2021-12-27 14:56:50 +01:00
segments.push(state.get_identifier("", b.literal_syntax()).into());
tokens.push(state.get_identifier("", CUSTOM_SYNTAX_MARKER_BOOL));
2021-06-10 04:16:39 +02:00
}
(_, pos) => {
return Err(
PERR::MissingSymbol("Expecting 'true' or 'false'".to_string())
.into_err(pos),
)
}
},
2021-06-28 12:06:05 +02:00
CUSTOM_SYNTAX_MARKER_INT => match input.next().expect(NEVER_ENDS) {
2021-06-10 04:16:39 +02:00
(Token::IntegerConstant(i), pos) => {
2021-10-25 16:41:42 +02:00
inputs.push(Expr::IntegerConstant(i, pos));
2021-07-10 09:50:31 +02:00
segments.push(i.to_string().into());
2021-12-27 14:56:50 +01:00
tokens.push(state.get_identifier("", CUSTOM_SYNTAX_MARKER_INT));
2021-06-10 04:16:39 +02:00
}
(_, pos) => {
return Err(
PERR::MissingSymbol("Expecting an integer number".to_string())
.into_err(pos),
)
}
},
#[cfg(not(feature = "no_float"))]
2021-12-06 13:52:47 +01:00
crate::custom_syntax::markers::CUSTOM_SYNTAX_MARKER_FLOAT => {
match input.next().expect(NEVER_ENDS) {
(Token::FloatConstant(f), pos) => {
inputs.push(Expr::FloatConstant(f, pos));
segments.push(f.to_string().into());
tokens.push(state.get_identifier(
2021-12-27 14:56:50 +01:00
"",
2021-12-06 13:52:47 +01:00
crate::custom_syntax::markers::CUSTOM_SYNTAX_MARKER_FLOAT,
));
}
(_, pos) => {
return Err(PERR::MissingSymbol(
"Expecting a floating-point number".to_string(),
)
.into_err(pos))
}
2021-06-10 04:16:39 +02:00
}
2021-12-06 13:52:47 +01:00
}
2021-06-28 12:06:05 +02:00
CUSTOM_SYNTAX_MARKER_STRING => match input.next().expect(NEVER_ENDS) {
2021-06-10 04:16:39 +02:00
(Token::StringConstant(s), pos) => {
2021-12-27 14:56:50 +01:00
let s: ImmutableString = state.get_identifier("", s).into();
2021-10-25 16:41:42 +02:00
inputs.push(Expr::StringConstant(s.clone(), pos));
2021-07-10 09:50:31 +02:00
segments.push(s);
2021-12-27 14:56:50 +01:00
tokens.push(state.get_identifier("", CUSTOM_SYNTAX_MARKER_STRING));
2021-06-10 04:16:39 +02:00
}
(_, pos) => {
return Err(PERR::MissingSymbol("Expecting a string".to_string()).into_err(pos))
}
},
2021-05-22 13:14:24 +02:00
s => match input.next().expect(NEVER_ENDS) {
2020-10-26 14:49:49 +01:00
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
2021-11-11 06:55:52 +01:00
(t, _) if &*t.syntax() == s => {
segments.push(required_token.clone());
2021-03-29 05:36:02 +02:00
tokens.push(required_token.clone().into());
}
(_, pos) => {
return Err(PERR::MissingToken(
s.to_string(),
2020-10-25 14:57:18 +01:00
format!("for '{}' expression", segments[0]),
)
2020-10-26 14:49:49 +01:00
.into_err(pos))
}
},
}
}
2021-10-25 16:41:42 +02:00
inputs.shrink_to_fit();
2021-05-05 12:38:52 +02:00
tokens.shrink_to_fit();
2021-08-02 04:24:03 +02:00
const KEYWORD_SEMICOLON: &str = Token::SemiColon.literal_syntax();
const KEYWORD_CLOSE_BRACE: &str = Token::RightBrace.literal_syntax();
let self_terminated = match required_token.as_str() {
// It is self-terminating if the last symbol is a block
CUSTOM_SYNTAX_MARKER_BLOCK => true,
// If the last symbol is `;` or `}`, it is self-terminating
KEYWORD_SEMICOLON | KEYWORD_CLOSE_BRACE => true,
_ => false,
};
2021-07-03 18:15:27 +02:00
Ok(Expr::Custom(
CustomExpr {
2021-10-25 16:41:42 +02:00
inputs,
2021-07-03 18:15:27 +02:00
tokens,
scope_may_be_changed: syntax.scope_may_be_changed,
2021-08-02 04:24:03 +02:00
self_terminated,
2021-07-03 18:15:27 +02:00
}
.into(),
pos,
))
}
2020-03-18 03:36:50 +01:00
/// Parse an expression.
2020-06-11 12:13:33 +02:00
fn parse_expr(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Expr> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2021-05-22 13:14:24 +02:00
settings.pos = input.peek().expect(NEVER_ENDS).1;
2020-12-28 02:49:54 +01:00
2020-07-09 13:54:28 +02:00
// Parse expression normally.
let precedence = Precedence::new(1);
let lhs = parse_unary(input, state, lib, settings.level_up())?;
parse_binary_op(input, state, lib, precedence, lhs, settings.level_up())
2016-02-29 22:43:45 +01:00
}
2020-03-18 03:36:50 +01:00
/// Parse an if statement.
2020-06-11 12:13:33 +02:00
fn parse_if(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Stmt> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2016-02-29 22:43:45 +01:00
2020-12-28 02:49:54 +01:00
// if ...
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2020-12-28 02:49:54 +01:00
settings.pos = eat_token(input, Token::If);
// if guard { if_body }
ensure_not_statement_expr(input, "a boolean")?;
2021-07-03 18:15:27 +02:00
let guard = parse_expr(input, state, lib, settings.level_up())?.ensure_bool_expr()?;
2020-04-22 11:37:06 +02:00
ensure_not_assignment(input)?;
2020-10-27 12:23:43 +01:00
let if_body = parse_block(input, state, lib, settings.level_up())?;
2016-02-29 22:43:45 +01:00
// if guard { if_body } else ...
2020-10-20 17:16:03 +02:00
let else_body = if match_token(input, Token::Else).0 {
2021-05-22 13:14:24 +02:00
if let (Token::If, _) = input.peek().expect(NEVER_ENDS) {
// if guard { if_body } else if ...
parse_if(input, state, lib, settings.level_up())?
2020-03-16 16:51:32 +01:00
} else {
// if guard { if_body } else { else-body }
parse_block(input, state, lib, settings.level_up())?
2021-03-09 16:30:48 +01:00
}
2020-03-16 16:51:32 +01:00
} else {
2021-03-09 16:30:48 +01:00
Stmt::Noop(Position::NONE)
2020-03-16 16:51:32 +01:00
};
2020-03-02 10:04:56 +01:00
2020-12-28 02:49:54 +01:00
Ok(Stmt::If(
guard,
2021-06-29 12:25:20 +02:00
(if_body.into(), else_body.into()).into(),
2020-12-28 02:49:54 +01:00
settings.pos,
))
2016-02-29 22:43:45 +01:00
}
2020-03-18 03:36:50 +01:00
/// Parse a while loop.
2020-11-20 15:23:37 +01:00
fn parse_while_loop(
2020-06-11 12:13:33 +02:00
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Stmt> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2016-02-29 22:43:45 +01:00
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2020-11-20 15:23:37 +01:00
// while|loops ...
2021-05-22 13:14:24 +02:00
let (guard, token_pos) = match input.next().expect(NEVER_ENDS) {
2020-11-20 15:23:37 +01:00
(Token::While, pos) => {
ensure_not_statement_expr(input, "a boolean")?;
2021-07-03 18:15:27 +02:00
let expr = parse_expr(input, state, lib, settings.level_up())?.ensure_bool_expr()?;
2021-07-04 10:40:15 +02:00
ensure_not_assignment(input)?;
2021-03-09 16:30:48 +01:00
(expr, pos)
2020-11-20 15:23:37 +01:00
}
2021-03-09 16:30:48 +01:00
(Token::Loop, pos) => (Expr::Unit(Position::NONE), pos),
2021-03-07 15:10:54 +01:00
_ => unreachable!(),
2020-11-20 15:23:37 +01:00
};
settings.pos = token_pos;
settings.is_breakable = true;
2021-07-04 10:40:15 +02:00
2021-03-10 05:27:10 +01:00
let body = parse_block(input, state, lib, settings.level_up())?;
2016-02-29 22:43:45 +01:00
2021-03-10 05:27:10 +01:00
Ok(Stmt::While(guard, Box::new(body.into()), settings.pos))
2016-02-29 22:43:45 +01:00
}
2020-11-20 15:23:37 +01:00
/// Parse a do loop.
fn parse_do(
2020-06-11 12:13:33 +02:00
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Stmt> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2017-10-30 16:08:44 +01:00
2020-12-28 02:49:54 +01:00
// do ...
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2020-12-28 02:49:54 +01:00
settings.pos = eat_token(input, Token::Do);
2020-11-20 15:23:37 +01:00
// do { body } [while|until] guard
settings.is_breakable = true;
2021-03-10 05:27:10 +01:00
let body = parse_block(input, state, lib, settings.level_up())?;
2017-10-30 16:08:44 +01:00
let negated = match input.next().expect(NEVER_ENDS) {
(Token::While, _) => AST_OPTION_NONE,
(Token::Until, _) => AST_OPTION_NEGATED,
2020-11-20 15:23:37 +01:00
(_, pos) => {
return Err(
PERR::MissingToken(Token::While.into(), "for the do statement".into())
.into_err(pos),
)
}
};
settings.is_breakable = false;
2021-07-04 10:40:15 +02:00
ensure_not_statement_expr(input, "a boolean")?;
2021-07-03 18:15:27 +02:00
let guard = parse_expr(input, state, lib, settings.level_up())?.ensure_bool_expr()?;
2020-11-20 15:23:37 +01:00
ensure_not_assignment(input)?;
2021-03-10 05:27:10 +01:00
Ok(Stmt::Do(
Box::new(body.into()),
guard,
negated,
2021-03-10 05:27:10 +01:00
settings.pos,
))
2017-10-30 16:08:44 +01:00
}
2020-03-18 03:36:50 +01:00
/// Parse a for loop.
2020-06-11 12:13:33 +02:00
fn parse_for(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Stmt> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2020-12-28 02:49:54 +01:00
// for ...
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2020-12-28 02:49:54 +01:00
settings.pos = eat_token(input, Token::For);
2020-03-18 11:41:18 +01:00
// for name ...
2021-06-07 05:01:16 +02:00
let (name, name_pos, counter_name, counter_pos) = if match_token(input, Token::LeftParen).0 {
// ( name, counter )
2021-06-07 05:43:00 +02:00
let (name, name_pos) = parse_var_name(input)?;
2021-06-07 05:01:16 +02:00
let (has_comma, pos) = match_token(input, Token::Comma);
if !has_comma {
return Err(PERR::MissingToken(
Token::Comma.into(),
"after the iteration variable name".into(),
)
.into_err(pos));
}
2021-06-07 05:43:00 +02:00
let (counter_name, counter_pos) = parse_var_name(input)?;
2021-06-07 05:01:16 +02:00
if counter_name == name {
2021-11-11 06:55:52 +01:00
return Err(PERR::DuplicatedVariable(counter_name.to_string()).into_err(counter_pos));
2021-06-07 05:01:16 +02:00
}
let (has_close_paren, pos) = match_token(input, Token::RightParen);
if !has_close_paren {
return Err(PERR::MissingToken(
Token::RightParen.into(),
"to close the iteration variable".into(),
)
.into_err(pos));
}
(name, name_pos, Some(counter_name), Some(counter_pos))
} else {
// name
2021-06-07 05:43:00 +02:00
let (name, name_pos) = parse_var_name(input)?;
2021-06-07 05:01:16 +02:00
(name, name_pos, None, None)
};
2020-03-18 11:41:18 +01:00
// for name in ...
2021-05-22 13:14:24 +02:00
match input.next().expect(NEVER_ENDS) {
(Token::In, _) => (),
2020-06-14 10:56:36 +02:00
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => {
return Err(
2020-05-04 13:36:58 +02:00
PERR::MissingToken(Token::In.into(), "after the iteration variable".into())
.into_err(pos),
)
}
}
2020-03-18 11:41:18 +01:00
// for name in expr { body }
ensure_not_statement_expr(input, "a boolean")?;
2021-07-03 18:15:27 +02:00
let expr = parse_expr(input, state, lib, settings.level_up())?.ensure_iterable()?;
2020-04-28 17:05:03 +02:00
2020-06-28 09:49:24 +02:00
let prev_stack_len = state.stack.len();
2021-06-07 05:01:16 +02:00
2021-12-12 05:33:22 +01:00
let counter_var = counter_name.map(|name| {
2021-12-27 14:56:50 +01:00
let name = state.get_identifier("", name);
2021-11-16 16:13:53 +01:00
let pos = counter_pos.expect("`Some`");
state.stack.push((name.clone(), AccessMode::ReadWrite));
2021-12-12 05:33:22 +01:00
Ident { name, pos }
});
2021-11-16 16:13:53 +01:00
2021-12-27 14:56:50 +01:00
let loop_var = state.get_identifier("", name);
2021-03-29 05:36:02 +02:00
state.stack.push((loop_var.clone(), AccessMode::ReadWrite));
2021-11-16 16:13:53 +01:00
let loop_var = Ident {
name: loop_var,
pos: name_pos,
};
2020-04-28 17:05:03 +02:00
settings.is_breakable = true;
2020-10-27 12:23:43 +01:00
let body = parse_block(input, state, lib, settings.level_up())?;
2020-04-28 17:05:03 +02:00
2020-06-28 09:49:24 +02:00
state.stack.truncate(prev_stack_len);
2021-03-29 05:36:02 +02:00
Ok(Stmt::For(
expr,
2021-11-16 16:13:53 +01:00
Box::new((loop_var, counter_var, body.into())),
2021-03-29 05:36:02 +02:00
settings.pos,
))
}
2020-03-18 03:36:50 +01:00
/// Parse a variable definition statement.
2020-06-11 12:13:33 +02:00
fn parse_let(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
var_type: AccessMode,
2021-08-13 07:42:39 +02:00
is_export: bool,
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Stmt> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2020-03-16 16:51:32 +01:00
2020-12-28 02:49:54 +01:00
// let/const... (specified in `var_type`)
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2021-05-22 13:14:24 +02:00
settings.pos = input.next().expect(NEVER_ENDS).1;
2020-12-28 02:49:54 +01:00
2020-03-18 11:41:18 +01:00
// let name ...
2021-06-07 05:43:00 +02:00
let (name, pos) = parse_var_name(input)?;
2016-02-29 22:43:45 +01:00
2021-12-27 14:56:50 +01:00
let name = state.get_identifier("", name);
2021-02-03 12:14:26 +01:00
let var_def = Ident {
name: name.clone(),
pos,
};
2020-03-18 11:41:18 +01:00
// let name = ...
2020-12-28 02:49:54 +01:00
let expr = if match_token(input, Token::Equals).0 {
2020-03-18 11:41:18 +01:00
// let name = expr
2021-03-09 16:30:48 +01:00
parse_expr(input, state, lib, settings.level_up())?
2020-03-14 16:41:15 +01:00
} else {
2021-03-09 16:30:48 +01:00
Expr::Unit(Position::NONE)
2020-10-09 05:15:25 +02:00
};
2021-02-03 12:14:26 +01:00
state.stack.push((name, var_type));
2021-08-13 07:42:39 +02:00
let export = if is_export {
AST_OPTION_PUBLIC
} else {
AST_OPTION_NONE
};
2020-10-09 05:15:25 +02:00
match var_type {
// let name = expr
AccessMode::ReadWrite => Ok(Stmt::Var(expr, var_def.into(), export, settings.pos)),
2020-10-09 05:15:25 +02:00
// const name = { expr:constant }
AccessMode::ReadOnly => Ok(Stmt::Var(
expr,
var_def.into(),
AST_OPTION_CONSTANT + export,
settings.pos,
)),
2016-02-29 22:43:45 +01:00
}
}
2020-05-04 13:36:58 +02:00
/// Parse an import statement.
2020-07-01 16:21:43 +02:00
#[cfg(not(feature = "no_module"))]
2020-06-11 12:13:33 +02:00
fn parse_import(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Stmt> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2020-12-28 02:49:54 +01:00
// import ...
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2020-12-28 02:49:54 +01:00
settings.pos = eat_token(input, Token::Import);
2020-05-04 13:36:58 +02:00
// import expr ...
let expr = parse_expr(input, state, lib, settings.level_up())?;
2020-05-04 13:36:58 +02:00
// import expr as ...
2020-10-20 17:16:03 +02:00
if !match_token(input, Token::As).0 {
2021-03-10 05:27:10 +01:00
return Ok(Stmt::Import(expr, None, settings.pos));
2020-05-04 13:36:58 +02:00
}
// import expr as name ...
2021-11-16 16:13:53 +01:00
let (name, pos) = parse_var_name(input)?;
2021-12-27 14:56:50 +01:00
let name = state.get_identifier("", name);
state.modules.push(name.clone());
2020-10-27 11:18:19 +01:00
Ok(Stmt::Import(
expr,
2021-11-16 16:13:53 +01:00
Some(Ident { name, pos }.into()),
2020-12-28 02:49:54 +01:00
settings.pos,
2020-10-27 11:18:19 +01:00
))
2020-05-04 13:36:58 +02:00
}
2020-05-08 10:49:24 +02:00
/// Parse an export statement.
#[cfg(not(feature = "no_module"))]
2020-06-11 12:13:33 +02:00
fn parse_export(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Stmt> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2020-12-28 02:49:54 +01:00
settings.pos = eat_token(input, Token::Export);
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
(Token::Let, pos) => {
let pos = *pos;
let mut stmt = parse_let(input, state, lib, AccessMode::ReadWrite, true, settings)?;
stmt.set_position(pos);
return Ok(stmt);
}
(Token::Const, pos) => {
let pos = *pos;
let mut stmt = parse_let(input, state, lib, AccessMode::ReadOnly, true, settings)?;
stmt.set_position(pos);
return Ok(stmt);
}
_ => (),
}
2020-05-08 10:49:24 +02:00
2021-06-16 10:35:56 +02:00
let mut exports = Vec::<(Ident, Ident)>::with_capacity(4);
2020-05-08 10:49:24 +02:00
loop {
2021-06-07 05:43:00 +02:00
let (id, id_pos) = parse_var_name(input)?;
2020-05-08 10:49:24 +02:00
2021-06-16 10:35:56 +02:00
let (rename, rename_pos) = if match_token(input, Token::As).0 {
2021-06-07 05:43:00 +02:00
let (name, pos) = parse_var_name(input)?;
2021-11-11 06:55:52 +01:00
if exports.iter().any(|(_, alias)| alias.name == name.as_ref()) {
return Err(PERR::DuplicatedVariable(name.to_string()).into_err(pos));
2021-06-07 05:43:00 +02:00
}
2021-11-11 06:55:52 +01:00
(Some(name), pos)
2020-05-08 10:49:24 +02:00
} else {
2021-11-11 06:55:52 +01:00
(None, Position::NONE)
2020-05-08 10:49:24 +02:00
};
2020-12-22 09:45:56 +01:00
exports.push((
Ident {
2021-12-27 14:56:50 +01:00
name: state.get_identifier("", id),
2020-12-22 09:45:56 +01:00
pos: id_pos,
},
2021-06-16 10:35:56 +02:00
Ident {
2021-12-27 14:56:50 +01:00
name: state.get_identifier("", rename.as_ref().map_or("", |s| s.as_ref())),
2021-06-16 10:35:56 +02:00
pos: rename_pos,
},
2020-12-22 09:45:56 +01:00
));
2020-05-08 10:49:24 +02:00
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
2020-05-08 10:49:24 +02:00
(Token::Comma, _) => {
eat_token(input, Token::Comma);
}
(Token::Identifier(_), pos) => {
return Err(PERR::MissingToken(
Token::Comma.into(),
"to separate the list of exports".into(),
)
.into_err(*pos))
}
_ => break,
}
}
2021-05-05 12:38:52 +02:00
Ok(Stmt::Export(exports.into_boxed_slice(), settings.pos))
2020-05-08 10:49:24 +02:00
}
2020-03-18 03:36:50 +01:00
/// Parse a statement block.
2020-06-11 12:13:33 +02:00
fn parse_block(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Stmt> {
2021-11-16 16:13:53 +01:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2021-08-13 07:42:39 +02:00
2020-03-18 11:41:18 +01:00
// Must start with {
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2021-05-22 13:14:24 +02:00
settings.pos = match input.next().expect(NEVER_ENDS) {
2020-03-16 16:51:32 +01:00
(Token::LeftBrace, pos) => pos,
2020-06-14 10:56:36 +02:00
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => {
2020-05-04 13:36:58 +02:00
return Err(PERR::MissingToken(
Token::LeftBrace.into(),
"to start a statement block".into(),
)
2020-05-04 13:36:58 +02:00
.into_err(pos))
}
2020-03-12 05:40:28 +01:00
};
2016-02-29 22:43:45 +01:00
2020-11-15 06:49:54 +01:00
let mut statements = Vec::with_capacity(8);
let prev_entry_stack_len = state.entry_stack_len;
state.entry_stack_len = state.stack.len();
2020-10-18 16:10:08 +02:00
#[cfg(not(feature = "no_module"))]
2020-06-28 09:49:24 +02:00
let prev_mods_len = state.modules.len();
loop {
// Terminated?
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
(Token::RightBrace, _) => {
eat_token(input, Token::RightBrace);
break;
}
(Token::EOF, pos) => {
return Err(PERR::MissingToken(
Token::RightBrace.into(),
"to terminate this block".into(),
)
.into_err(*pos));
}
_ => (),
}
2020-03-17 10:33:37 +01:00
// Parse statements inside the block
settings.is_global = false;
2020-12-29 03:41:20 +01:00
let stmt = parse_stmt(input, state, lib, settings.level_up())?;
if stmt.is_noop() {
continue;
}
2020-03-17 10:33:37 +01:00
// See if it needs a terminating semicolon
let need_semicolon = !stmt.is_self_terminated();
2017-10-02 23:44:45 +02:00
2020-03-17 10:33:37 +01:00
statements.push(stmt);
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
2020-03-18 11:41:18 +01:00
// { ... stmt }
(Token::RightBrace, _) => {
eat_token(input, Token::RightBrace);
break;
}
2020-03-18 11:41:18 +01:00
// { ... stmt;
(Token::SemiColon, _) if need_semicolon => {
eat_token(input, Token::SemiColon);
2020-03-17 10:33:37 +01:00
}
2020-03-18 11:41:18 +01:00
// { ... { stmt } ;
(Token::SemiColon, _) if !need_semicolon => {
eat_token(input, Token::SemiColon);
}
2020-03-18 11:41:18 +01:00
// { ... { stmt } ???
(_, _) if !need_semicolon => (),
// { ... stmt <error>
(Token::LexError(err), err_pos) => return Err(err.clone().into_err(*err_pos)),
// { ... stmt ???
(_, pos) => {
2020-03-17 10:33:37 +01:00
// Semicolons are not optional between statements
2020-05-04 13:36:58 +02:00
return Err(PERR::MissingToken(
Token::SemiColon.into(),
"to terminate this statement".into(),
)
.into_err(*pos));
2019-09-18 12:21:07 +02:00
}
}
}
2016-02-29 22:43:45 +01:00
state.stack.truncate(state.entry_stack_len);
state.entry_stack_len = prev_entry_stack_len;
2020-10-18 16:10:08 +02:00
#[cfg(not(feature = "no_module"))]
2020-06-28 09:49:24 +02:00
state.modules.truncate(prev_mods_len);
2020-04-28 17:05:03 +02:00
2021-05-05 12:38:52 +02:00
Ok(Stmt::Block(statements.into_boxed_slice(), settings.pos))
2016-02-29 22:43:45 +01:00
}
2020-03-18 03:36:50 +01:00
/// Parse an expression as a statement.
2020-06-11 12:13:33 +02:00
fn parse_expr_stmt(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Stmt> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2021-05-22 13:14:24 +02:00
settings.pos = input.peek().expect(NEVER_ENDS).1;
2020-12-28 02:49:54 +01:00
let expr = parse_expr(input, state, lib, settings.level_up())?;
2020-10-27 16:21:20 +01:00
let stmt = parse_op_assignment_stmt(input, state, lib, expr, settings.level_up())?;
Ok(stmt)
2016-02-29 22:43:45 +01:00
}
2020-03-18 03:36:50 +01:00
/// Parse a single statement.
2020-06-11 12:13:33 +02:00
fn parse_stmt(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Stmt> {
use AccessMode::{ReadOnly, ReadWrite};
2021-08-13 07:42:39 +02:00
let mut settings = settings;
2020-12-12 13:09:29 +01:00
#[cfg(not(feature = "no_function"))]
2021-04-09 16:49:47 +02:00
#[cfg(feature = "metadata")]
let comments = {
2021-11-12 06:25:57 +01:00
let mut comments = Vec::<Box<str>>::new();
2020-12-29 05:29:45 +01:00
let mut comments_pos = Position::NONE;
2020-12-12 13:09:29 +01:00
2020-12-29 05:29:45 +01:00
// Handle doc-comments.
2021-05-22 13:34:10 +02:00
while let (Token::Comment(ref comment), pos) = input.peek().expect(NEVER_ENDS) {
2020-12-29 05:29:45 +01:00
if comments_pos.is_none() {
comments_pos = *pos;
}
2020-12-12 13:09:29 +01:00
2021-11-13 15:36:23 +01:00
if !crate::tokenizer::is_doc_comment(comment) {
2020-12-29 05:29:45 +01:00
unreachable!("expecting doc-comment, but gets {:?}", comment);
}
if !settings.is_global {
return Err(PERR::WrongDocComment.into_err(comments_pos));
}
2020-12-12 13:09:29 +01:00
2021-05-22 13:14:24 +02:00
match input.next().expect(NEVER_ENDS).0 {
2020-12-29 05:29:45 +01:00
Token::Comment(comment) => {
2021-04-09 16:49:47 +02:00
comments.push(comment);
2020-12-12 13:09:29 +01:00
2021-05-22 13:34:10 +02:00
match input.peek().expect(NEVER_ENDS) {
2020-12-29 05:29:45 +01:00
(Token::Fn, _) | (Token::Private, _) => break,
(Token::Comment(_), _) => (),
_ => return Err(PERR::WrongDocComment.into_err(comments_pos)),
}
}
2021-03-07 15:10:54 +01:00
_ => unreachable!(),
2020-12-12 13:09:29 +01:00
}
}
2021-04-09 16:49:47 +02:00
comments
};
2020-12-12 13:09:29 +01:00
2021-05-22 13:14:24 +02:00
let (token, token_pos) = match input.peek().expect(NEVER_ENDS) {
2020-12-29 03:41:20 +01:00
(Token::EOF, pos) => return Ok(Stmt::Noop(*pos)),
2021-11-13 02:50:49 +01:00
(x, pos) => (x, *pos),
};
2021-11-13 02:50:49 +01:00
settings.pos = token_pos;
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
match token {
// ; - empty statement
2021-02-09 07:08:17 +01:00
Token::SemiColon => {
eat_token(input, Token::SemiColon);
2021-11-13 02:50:49 +01:00
Ok(Stmt::Noop(token_pos))
2021-02-09 07:08:17 +01:00
}
2020-03-18 11:41:18 +01:00
// { - statements block
2020-12-29 03:41:20 +01:00
Token::LeftBrace => Ok(parse_block(input, state, lib, settings.level_up())?),
2020-04-01 10:22:18 +02:00
2020-03-18 11:41:18 +01:00
// fn ...
#[cfg(not(feature = "no_function"))]
2021-11-13 02:50:49 +01:00
Token::Fn if !settings.is_global => Err(PERR::WrongFnDefinition.into_err(token_pos)),
#[cfg(not(feature = "no_function"))]
Token::Fn | Token::Private => {
let access = if matches!(token, Token::Private) {
eat_token(input, Token::Private);
2021-12-06 13:52:47 +01:00
crate::FnAccess::Private
} else {
2021-12-06 13:52:47 +01:00
crate::FnAccess::Public
};
2021-05-22 13:14:24 +02:00
match input.next().expect(NEVER_ENDS) {
(Token::Fn, pos) => {
let mut new_state =
ParseState::new(state.engine, state.tokenizer_control.clone());
2021-04-04 18:05:56 +02:00
#[cfg(not(feature = "unchecked"))]
{
new_state.max_expr_depth = new_state.max_function_expr_depth;
}
2021-12-04 10:57:28 +01:00
let new_settings = ParseSettings {
2021-12-03 04:16:35 +01:00
allow_if_expr: settings.default_options.allow_if_expr,
allow_switch_expr: settings.default_options.allow_switch_expr,
allow_stmt_expr: settings.default_options.allow_stmt_expr,
allow_anonymous_fn: settings.default_options.allow_anonymous_fn,
2021-12-04 10:57:28 +01:00
strict_var: settings.strict_var,
is_global: false,
2020-07-16 06:09:31 +02:00
is_function_scope: true,
2021-12-04 11:07:27 +01:00
#[cfg(not(feature = "no_closure"))]
2021-12-04 10:57:28 +01:00
is_closure: false,
is_breakable: false,
level: 0,
2021-07-24 08:11:16 +02:00
pos,
2021-12-03 04:16:35 +01:00
..settings
};
2021-04-09 16:49:47 +02:00
let func = parse_fn(
input,
&mut new_state,
lib,
access,
2021-12-04 10:57:28 +01:00
new_settings,
2021-04-09 16:49:47 +02:00
#[cfg(not(feature = "no_function"))]
#[cfg(feature = "metadata")]
comments,
)?;
2021-05-19 14:26:11 +02:00
let hash = calc_fn_hash(&func.name, func.params.len());
if lib.contains_key(&hash) {
return Err(PERR::FnDuplicatedDefinition(
2021-03-29 05:36:02 +02:00
func.name.to_string(),
func.params.len(),
)
.into_err(pos));
}
2021-03-12 07:11:08 +01:00
lib.insert(hash, func.into());
Ok(Stmt::Noop(pos))
}
(_, pos) => Err(PERR::MissingToken(
Token::Fn.into(),
format!("following '{}'", Token::Private.syntax()),
)
.into_err(pos)),
}
}
2020-12-29 03:41:20 +01:00
Token::If => parse_if(input, state, lib, settings.level_up()),
Token::Switch => parse_switch(input, state, lib, settings.level_up()),
2021-12-04 10:57:28 +01:00
Token::While | Token::Loop if settings.default_options.allow_loop => {
2021-12-03 04:24:38 +01:00
parse_while_loop(input, state, lib, settings.level_up())
}
2021-12-04 10:57:28 +01:00
Token::Do if settings.default_options.allow_loop => {
parse_do(input, state, lib, settings.level_up())
}
Token::For if settings.default_options.allow_loop => {
parse_for(input, state, lib, settings.level_up())
}
2020-04-01 10:22:18 +02:00
2021-12-04 10:57:28 +01:00
Token::Continue if settings.default_options.allow_loop && settings.is_breakable => {
2020-04-17 13:00:52 +02:00
let pos = eat_token(input, Token::Continue);
Ok(Stmt::BreakLoop(AST_OPTION_NONE, pos))
2020-04-01 10:22:18 +02:00
}
2021-12-04 10:57:28 +01:00
Token::Break if settings.default_options.allow_loop && settings.is_breakable => {
2020-04-17 13:00:52 +02:00
let pos = eat_token(input, Token::Break);
Ok(Stmt::BreakLoop(AST_OPTION_BREAK_OUT, pos))
}
2021-12-04 10:57:28 +01:00
Token::Continue | Token::Break if settings.default_options.allow_loop => {
2021-12-03 04:24:38 +01:00
Err(PERR::LoopBreak.into_err(token_pos))
}
2020-04-01 10:22:18 +02:00
Token::Return | Token::Throw => {
let (return_type, token_pos) = input
.next()
.map(|(token, pos)| {
(
match token {
Token::Return => AST_OPTION_NONE,
Token::Throw => AST_OPTION_BREAK_OUT,
2021-03-07 15:10:54 +01:00
_ => unreachable!(),
},
pos,
)
})
2021-05-22 13:14:24 +02:00
.expect(NEVER_ENDS);
2020-03-03 11:15:20 +01:00
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
// `return`/`throw` at <EOF>
2021-03-09 16:30:48 +01:00
(Token::EOF, _) => Ok(Stmt::Return(return_type, None, token_pos)),
2021-07-03 18:15:27 +02:00
// `return`/`throw` at end of block
(Token::RightBrace, _) if !settings.is_global => {
Ok(Stmt::Return(return_type, None, token_pos))
}
2020-03-18 03:36:50 +01:00
// `return;` or `throw;`
2021-03-09 16:30:48 +01:00
(Token::SemiColon, _) => Ok(Stmt::Return(return_type, None, token_pos)),
2020-03-18 03:36:50 +01:00
// `return` or `throw` with expression
(_, _) => {
let expr = parse_expr(input, state, lib, settings.level_up())?;
2021-03-09 16:30:48 +01:00
Ok(Stmt::Return(return_type, Some(expr), token_pos))
}
}
}
2020-04-01 10:22:18 +02:00
2020-12-29 03:41:20 +01:00
Token::Try => parse_try_catch(input, state, lib, settings.level_up()),
2020-10-20 17:16:03 +02:00
2020-12-29 03:41:20 +01:00
Token::Let => parse_let(input, state, lib, ReadWrite, false, settings.level_up()),
Token::Const => parse_let(input, state, lib, ReadOnly, false, settings.level_up()),
2020-07-01 16:21:43 +02:00
#[cfg(not(feature = "no_module"))]
2020-12-29 03:41:20 +01:00
Token::Import => parse_import(input, state, lib, settings.level_up()),
2020-05-04 13:36:58 +02:00
2020-05-08 10:49:24 +02:00
#[cfg(not(feature = "no_module"))]
2021-11-13 02:50:49 +01:00
Token::Export if !settings.is_global => Err(PERR::WrongExport.into_err(token_pos)),
2020-05-08 10:49:24 +02:00
#[cfg(not(feature = "no_module"))]
2020-12-29 03:41:20 +01:00
Token::Export => parse_export(input, state, lib, settings.level_up()),
2020-05-08 10:49:24 +02:00
2020-12-29 03:41:20 +01:00
_ => parse_expr_stmt(input, state, lib, settings.level_up()),
2016-02-29 22:43:45 +01:00
}
}
2020-10-20 17:16:03 +02:00
/// Parse a try/catch statement.
fn parse_try_catch(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<Stmt> {
2020-10-20 17:16:03 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2020-12-28 02:49:54 +01:00
// try ...
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2020-12-28 02:49:54 +01:00
settings.pos = eat_token(input, Token::Try);
2020-10-20 17:16:03 +02:00
// try { body }
let body = parse_block(input, state, lib, settings.level_up())?;
// try { body } catch
let (matched, catch_pos) = match_token(input, Token::Catch);
if !matched {
return Err(
PERR::MissingToken(Token::Catch.into(), "for the 'try' statement".into())
.into_err(catch_pos),
);
}
// try { body } catch (
2021-09-03 04:05:58 +02:00
let err_var = if match_token(input, Token::LeftParen).0 {
2021-06-07 05:43:00 +02:00
let (name, pos) = parse_var_name(input)?;
let (matched, err_pos) = match_token(input, Token::RightParen);
2020-10-20 17:16:03 +02:00
if !matched {
return Err(PERR::MissingToken(
Token::RightParen.into(),
"to enclose the catch variable".into(),
)
2021-06-07 05:43:00 +02:00
.into_err(err_pos));
2020-10-20 17:16:03 +02:00
}
2021-12-27 14:56:50 +01:00
let name = state.get_identifier("", name);
state.stack.push((name.clone(), AccessMode::ReadWrite));
2021-06-07 05:43:00 +02:00
Some(Ident { name, pos })
2020-10-20 17:16:03 +02:00
} else {
None
};
// try { body } catch ( var ) { catch_block }
let catch_body = parse_block(input, state, lib, settings.level_up())?;
2021-09-03 04:05:58 +02:00
if err_var.is_some() {
// Remove the error variable from the stack
2021-11-13 05:23:35 +01:00
state.stack.pop().expect("not empty");
2021-09-03 04:05:58 +02:00
}
2020-11-06 09:27:40 +01:00
Ok(Stmt::TryCatch(
2021-09-03 04:05:58 +02:00
(body.into(), err_var, catch_body.into()).into(),
2020-12-28 02:49:54 +01:00
settings.pos,
2020-11-06 09:27:40 +01:00
))
2020-10-20 17:16:03 +02:00
}
2020-03-18 03:36:50 +01:00
/// Parse a function definition.
#[cfg(not(feature = "no_function"))]
2020-06-11 12:13:33 +02:00
fn parse_fn(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-12-06 13:52:47 +01:00
access: crate::FnAccess,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-04-09 16:49:47 +02:00
#[cfg(not(feature = "no_function"))]
#[cfg(feature = "metadata")]
2021-11-12 06:25:57 +01:00
comments: Vec<Box<str>>,
2021-12-25 16:49:14 +01:00
) -> ParseResult<ScriptFnDef> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2021-05-22 13:14:24 +02:00
let (token, pos) = input.next().expect(NEVER_ENDS);
2020-07-26 16:25:30 +02:00
2021-06-16 10:15:29 +02:00
let name = match token.into_function_name_for_override() {
Ok(r) => r,
2021-11-11 06:55:52 +01:00
Err(Token::Reserved(s)) => return Err(PERR::Reserved(s.to_string()).into_err(pos)),
2021-06-16 10:15:29 +02:00
Err(_) => return Err(PERR::FnMissingName.into_err(pos)),
};
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
(Token::LeftParen, _) => eat_token(input, Token::LeftParen),
2021-11-11 06:55:52 +01:00
(_, pos) => return Err(PERR::FnMissingParams(name.to_string()).into_err(*pos)),
2020-04-06 11:47:34 +02:00
};
2021-11-25 10:09:00 +01:00
let mut params = StaticVec::new_const();
2020-10-20 17:16:03 +02:00
if !match_token(input, Token::RightParen).0 {
let sep_err = format!("to separate the parameters of function '{}'", name);
2020-03-24 09:46:47 +01:00
2020-03-14 16:41:15 +01:00
loop {
2021-05-22 13:14:24 +02:00
match input.next().expect(NEVER_ENDS) {
2020-07-19 11:14:55 +02:00
(Token::RightParen, _) => break,
(Token::Identifier(s), pos) => {
2021-11-11 06:55:52 +01:00
if params.iter().any(|(p, _)| p == &*s) {
return Err(
PERR::FnDuplicatedParam(name.to_string(), s.to_string()).into_err(pos)
);
2020-11-13 11:32:18 +01:00
}
2021-12-27 14:56:50 +01:00
let s = state.get_identifier("", s);
state.stack.push((s.clone(), AccessMode::ReadWrite));
2020-07-19 11:14:55 +02:00
params.push((s, pos))
}
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => {
return Err(PERR::MissingToken(
Token::RightParen.into(),
format!("to close the parameters list of function '{}'", name),
)
.into_err(pos))
}
2020-03-16 16:51:32 +01:00
}
2021-05-22 13:14:24 +02:00
match input.next().expect(NEVER_ENDS) {
(Token::RightParen, _) => break,
(Token::Comma, _) => (),
2020-06-14 10:56:36 +02:00
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
2020-05-04 13:36:58 +02:00
(_, pos) => {
return Err(PERR::MissingToken(Token::Comma.into(), sep_err).into_err(pos))
}
}
2020-03-14 16:41:15 +01:00
}
2016-02-29 22:43:45 +01:00
}
// Parse function body
2021-05-22 13:14:24 +02:00
let body = match input.peek().expect(NEVER_ENDS) {
(Token::LeftBrace, _) => {
settings.is_breakable = false;
parse_block(input, state, lib, settings.level_up())?
}
2021-11-11 06:55:52 +01:00
(_, pos) => return Err(PERR::FnMissingBody(name.to_string()).into_err(*pos)),
2021-03-10 15:12:48 +01:00
}
.into();
2021-05-05 12:38:52 +02:00
let mut params: StaticVec<_> = params.into_iter().map(|(p, _)| p).collect();
params.shrink_to_fit();
2020-07-30 07:28:06 +02:00
Ok(ScriptFnDef {
2021-12-27 14:56:50 +01:00
name: state.get_identifier("", name),
access,
2020-04-06 11:47:34 +02:00
params,
2020-03-09 14:57:07 +01:00
body,
lib: None,
2020-11-09 14:52:23 +01:00
#[cfg(not(feature = "no_module"))]
mods: crate::engine::Imports::new(),
2021-04-09 16:49:47 +02:00
#[cfg(not(feature = "no_function"))]
#[cfg(feature = "metadata")]
2021-11-12 06:25:57 +01:00
comments: if comments.is_empty() {
None
} else {
Some(comments.into())
},
})
}
2020-07-29 16:43:50 +02:00
/// Creates a curried expression from a list of external variables
2020-08-05 16:53:01 +02:00
#[cfg(not(feature = "no_function"))]
2021-01-25 04:31:54 +01:00
#[cfg(not(feature = "no_closure"))]
fn make_curry_from_externals(
state: &mut ParseState,
fn_expr: Expr,
2021-03-30 17:55:29 +02:00
externals: StaticVec<Identifier>,
pos: Position,
) -> Expr {
2021-01-25 04:31:54 +01:00
// If there are no captured variables, no need to curry
2020-07-30 07:28:06 +02:00
if externals.is_empty() {
2020-07-29 16:43:50 +02:00
return fn_expr;
}
2020-07-30 07:28:06 +02:00
let num_externals = externals.len();
2021-06-16 12:36:33 +02:00
let mut args = StaticVec::with_capacity(externals.len() + 1);
2020-07-29 16:43:50 +02:00
args.push(fn_expr);
2021-06-16 12:36:33 +02:00
args.extend(
externals
.iter()
.cloned()
2021-06-29 12:25:20 +02:00
.map(|x| Expr::Variable(None, Position::NONE, (None, None, x).into())),
2020-10-31 16:26:21 +01:00
);
2020-07-29 16:43:50 +02:00
2021-06-16 12:36:33 +02:00
let expr = FnCallExpr {
2021-12-27 14:56:50 +01:00
name: state.get_identifier("", crate::engine::KEYWORD_FN_PTR_CURRY),
2021-06-16 12:36:33 +02:00
hashes: FnCallHashes::from_native(calc_fn_hash(
crate::engine::KEYWORD_FN_PTR_CURRY,
num_externals + 1,
)),
args,
..Default::default()
}
.into_fn_call_expr(pos);
2021-01-25 04:31:54 +01:00
// Convert the entire expression into a statement block, then insert the relevant
// [`Share`][Stmt::Share] statements.
2021-06-16 12:36:33 +02:00
let mut statements = StaticVec::with_capacity(externals.len() + 1);
2021-03-30 17:55:29 +02:00
statements.extend(externals.into_iter().map(Stmt::Share));
2021-01-25 04:31:54 +01:00
statements.push(Stmt::Expr(expr));
2021-06-29 12:25:20 +02:00
Expr::Stmt(StmtBlock::new(statements, pos).into())
2020-07-29 16:43:50 +02:00
}
2020-07-19 11:14:55 +02:00
/// Parse an anonymous function definition.
#[cfg(not(feature = "no_function"))]
fn parse_anon_fn(
input: &mut TokenStream,
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
lib: &mut FnLib,
2021-08-13 07:42:39 +02:00
settings: ParseSettings,
2021-12-25 16:49:14 +01:00
) -> ParseResult<(Expr, ScriptFnDef)> {
2020-07-26 09:53:22 +02:00
#[cfg(not(feature = "unchecked"))]
2020-07-19 11:14:55 +02:00
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
2021-11-16 16:13:53 +01:00
let mut settings = settings;
2021-11-25 10:09:00 +01:00
let mut params_list = StaticVec::new_const();
2020-07-19 11:14:55 +02:00
2021-07-24 08:11:16 +02:00
if input.next().expect(NEVER_ENDS).0 != Token::Or && !match_token(input, Token::Pipe).0 {
loop {
match input.next().expect(NEVER_ENDS) {
(Token::Pipe, _) => break,
(Token::Identifier(s), pos) => {
2021-11-11 06:55:52 +01:00
if params_list.iter().any(|p| p == &*s) {
return Err(
PERR::FnDuplicatedParam("".to_string(), s.to_string()).into_err(pos)
);
2020-07-19 11:14:55 +02:00
}
2021-12-27 14:56:50 +01:00
let s = state.get_identifier("", s);
2021-07-24 08:11:16 +02:00
state.stack.push((s.clone(), AccessMode::ReadWrite));
params_list.push(s)
2020-07-19 11:14:55 +02:00
}
2021-07-24 08:11:16 +02:00
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => {
return Err(PERR::MissingToken(
Token::Pipe.into(),
"to close the parameters list of anonymous function".into(),
)
.into_err(pos))
}
}
2020-07-19 11:14:55 +02:00
2021-07-24 08:11:16 +02:00
match input.next().expect(NEVER_ENDS) {
(Token::Pipe, _) => break,
(Token::Comma, _) => (),
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
(_, pos) => {
return Err(PERR::MissingToken(
Token::Comma.into(),
"to separate the parameters of anonymous function".into(),
)
.into_err(pos))
2020-07-19 11:14:55 +02:00
}
}
}
}
// Parse function body
settings.is_breakable = false;
2020-12-29 03:41:20 +01:00
let body = parse_stmt(input, state, lib, settings.level_up())?;
2020-07-19 11:14:55 +02:00
2020-07-30 07:28:06 +02:00
// External variables may need to be processed in a consistent order,
// so extract them into a list.
2021-06-13 11:41:34 +02:00
#[cfg(not(feature = "no_closure"))]
let externals: StaticVec<Identifier> = state
.external_vars
.iter()
.map(|(name, _)| name.clone())
.collect();
2020-07-30 07:28:06 +02:00
2021-06-14 06:09:54 +02:00
#[cfg(not(feature = "no_closure"))]
let mut params = StaticVec::with_capacity(params_list.len() + externals.len());
#[cfg(feature = "no_closure")]
let mut params = StaticVec::with_capacity(params_list.len());
2021-06-13 11:41:34 +02:00
#[cfg(not(feature = "no_closure"))]
params.extend(externals.iter().cloned());
2021-06-14 06:09:54 +02:00
params.append(&mut params_list);
2020-07-19 11:14:55 +02:00
// Create unique function name by hashing the script body plus the parameters.
2020-11-13 11:32:18 +01:00
let hasher = &mut get_hasher();
2021-03-17 06:30:47 +01:00
params.iter().for_each(|p| p.hash(hasher));
body.hash(hasher);
2020-11-13 11:32:18 +01:00
let hash = hasher.finish();
2020-07-19 11:14:55 +02:00
2021-12-27 14:56:50 +01:00
let fn_name = state.get_identifier(
"",
&(format!("{}{:016x}", crate::engine::FN_ANONYMOUS, hash)),
);
2020-07-19 11:14:55 +02:00
2020-07-30 07:28:06 +02:00
// Define the function
2020-07-19 11:14:55 +02:00
let script = ScriptFnDef {
name: fn_name.clone(),
2021-12-06 13:52:47 +01:00
access: crate::FnAccess::Public,
2020-07-29 17:34:48 +02:00
params,
2021-03-10 15:12:48 +01:00
body: body.into(),
lib: None,
2020-11-09 14:52:23 +01:00
#[cfg(not(feature = "no_module"))]
mods: crate::engine::Imports::new(),
2021-04-09 16:49:47 +02:00
#[cfg(not(feature = "no_function"))]
#[cfg(feature = "metadata")]
2021-11-12 06:25:57 +01:00
comments: None,
2020-07-19 11:14:55 +02:00
};
2021-11-25 10:09:00 +01:00
let fn_ptr = crate::FnPtr::new_unchecked(fn_name, StaticVec::new_const());
2021-04-20 17:40:52 +02:00
let expr = Expr::DynamicConstant(Box::new(fn_ptr.into()), settings.pos);
2020-07-19 11:14:55 +02:00
2021-01-25 04:31:54 +01:00
#[cfg(not(feature = "no_closure"))]
let expr = make_curry_from_externals(state, expr, externals, settings.pos);
2020-07-29 16:43:50 +02:00
2020-07-19 11:14:55 +02:00
Ok((expr, script))
}
2020-06-03 04:44:36 +02:00
impl Engine {
2021-06-12 16:47:43 +02:00
/// Parse a global level expression.
2020-06-11 12:13:33 +02:00
pub(crate) fn parse_global_expr(
2020-06-03 04:44:36 +02:00
&self,
2020-06-11 12:13:33 +02:00
input: &mut TokenStream,
2021-04-04 07:13:07 +02:00
state: &mut ParseState,
2020-06-03 04:44:36 +02:00
scope: &Scope,
#[cfg(not(feature = "no_optimize"))] optimization_level: crate::OptimizationLevel,
2021-12-25 16:49:14 +01:00
) -> ParseResult<AST> {
let _scope = scope;
let mut functions = BTreeMap::new();
2020-07-26 09:53:22 +02:00
let settings = ParseSettings {
2021-12-03 04:16:35 +01:00
default_options: self.options,
allow_if_expr: false,
2020-11-14 16:43:36 +01:00
allow_switch_expr: false,
allow_stmt_expr: false,
2021-11-28 03:49:48 +01:00
#[cfg(not(feature = "no_function"))]
allow_anonymous_fn: false,
2021-12-04 10:57:28 +01:00
strict_var: self.options.strict_var,
is_global: true,
2021-11-28 03:49:48 +01:00
#[cfg(not(feature = "no_function"))]
2020-07-16 06:09:31 +02:00
is_function_scope: false,
2021-12-04 10:57:28 +01:00
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_closure"))]
is_closure: false,
is_breakable: false,
level: 0,
2020-11-20 09:52:28 +01:00
pos: Position::NONE,
};
2021-04-04 07:13:07 +02:00
let expr = parse_expr(input, state, &mut functions, settings)?;
2020-06-03 04:44:36 +02:00
assert!(functions.is_empty());
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
2020-06-03 04:44:36 +02:00
(Token::EOF, _) => (),
// Return error if the expression doesn't end
(token, pos) => {
2020-12-22 04:55:51 +01:00
return Err(LexError::UnexpectedInput(token.syntax().to_string()).into_err(*pos))
2020-06-03 04:44:36 +02:00
}
}
2021-11-25 10:09:00 +01:00
let mut statements = StaticVec::new_const();
2021-09-12 08:34:00 +02:00
statements.push(Stmt::Expr(expr));
2020-06-03 04:44:36 +02:00
#[cfg(not(feature = "no_optimize"))]
2021-11-13 15:36:23 +01:00
return Ok(crate::optimizer::optimize_into_ast(
self,
_scope,
statements,
#[cfg(not(feature = "no_function"))]
2021-11-25 10:09:00 +01:00
StaticVec::new_const(),
optimization_level,
));
#[cfg(feature = "no_optimize")]
2021-11-29 03:17:04 +01:00
return Ok(AST::new(
statements,
#[cfg(not(feature = "no_function"))]
crate::Module::new(),
));
2020-06-03 04:44:36 +02:00
}
2020-06-14 08:25:47 +02:00
/// Parse the global level statements.
fn parse_global_level(
&self,
input: &mut TokenStream,
2021-04-04 07:13:07 +02:00
state: &mut ParseState,
2021-12-25 16:49:14 +01:00
) -> ParseResult<(StaticVec<Stmt>, StaticVec<Shared<ScriptFnDef>>)> {
2021-11-25 10:09:00 +01:00
let mut statements = StaticVec::new_const();
2021-03-23 05:13:53 +01:00
let mut functions = BTreeMap::new();
2020-06-14 08:25:47 +02:00
2021-05-22 13:14:24 +02:00
while !input.peek().expect(NEVER_ENDS).0.is_eof() {
2020-06-14 08:25:47 +02:00
let settings = ParseSettings {
2021-12-03 04:16:35 +01:00
default_options: self.options,
allow_if_expr: self.options.allow_if_expr,
allow_switch_expr: self.options.allow_switch_expr,
allow_stmt_expr: self.options.allow_stmt_expr,
2021-11-28 03:49:48 +01:00
#[cfg(not(feature = "no_function"))]
2021-12-03 04:16:35 +01:00
allow_anonymous_fn: self.options.allow_anonymous_fn,
2021-12-04 10:57:28 +01:00
strict_var: self.options.strict_var,
2020-06-14 08:25:47 +02:00
is_global: true,
2021-11-28 03:49:48 +01:00
#[cfg(not(feature = "no_function"))]
2020-07-16 06:09:31 +02:00
is_function_scope: false,
2021-12-04 10:57:28 +01:00
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_closure"))]
is_closure: false,
2020-06-14 08:25:47 +02:00
is_breakable: false,
level: 0,
2020-11-20 09:52:28 +01:00
pos: Position::NONE,
2020-06-14 08:25:47 +02:00
};
2021-04-04 07:13:07 +02:00
let stmt = parse_stmt(input, state, &mut functions, settings)?;
2020-12-29 03:41:20 +01:00
if stmt.is_noop() {
continue;
}
2020-06-14 08:25:47 +02:00
let need_semicolon = !stmt.is_self_terminated();
statements.push(stmt);
2021-05-22 13:14:24 +02:00
match input.peek().expect(NEVER_ENDS) {
2020-06-14 08:25:47 +02:00
// EOF
(Token::EOF, _) => break,
// stmt ;
(Token::SemiColon, _) if need_semicolon => {
eat_token(input, Token::SemiColon);
}
// stmt ;
(Token::SemiColon, _) if !need_semicolon => (),
// { stmt } ???
(_, _) if !need_semicolon => (),
// stmt <error>
2020-11-25 02:36:06 +01:00
(Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
2020-06-14 08:25:47 +02:00
// stmt ???
(_, pos) => {
// Semicolons are not optional between statements
return Err(PERR::MissingToken(
Token::SemiColon.into(),
"to terminate this statement".into(),
)
.into_err(*pos));
}
}
}
Ok((statements, functions.into_iter().map(|(_, v)| v).collect()))
}
2020-06-03 04:44:36 +02:00
/// Run the parser on an input stream, returning an AST.
#[inline]
2020-06-11 12:13:33 +02:00
pub(crate) fn parse(
2020-06-03 04:44:36 +02:00
&self,
2020-06-11 12:13:33 +02:00
input: &mut TokenStream,
2021-04-04 07:13:07 +02:00
state: &mut ParseState,
2020-06-03 04:44:36 +02:00
scope: &Scope,
#[cfg(not(feature = "no_optimize"))] optimization_level: crate::OptimizationLevel,
2021-12-25 16:49:14 +01:00
) -> ParseResult<AST> {
let _scope = scope;
2021-10-21 13:30:58 +02:00
let (statements, _lib) = self.parse_global_level(input, state)?;
2020-06-03 04:44:36 +02:00
#[cfg(not(feature = "no_optimize"))]
2021-11-13 15:36:23 +01:00
return Ok(crate::optimizer::optimize_into_ast(
self,
_scope,
statements,
#[cfg(not(feature = "no_function"))]
2021-10-21 13:30:58 +02:00
_lib,
optimization_level,
));
#[cfg(feature = "no_optimize")]
2021-10-21 13:30:58 +02:00
#[cfg(not(feature = "no_function"))]
{
let mut m = crate::Module::new();
2021-10-21 13:51:35 +02:00
_lib.into_iter().for_each(|fn_def| {
m.set_script_fn(fn_def);
});
return Ok(AST::new(statements, m));
}
2021-10-21 13:30:58 +02:00
#[cfg(feature = "no_optimize")]
#[cfg(feature = "no_function")]
2021-11-29 03:17:04 +01:00
return Ok(AST::new(
statements,
#[cfg(not(feature = "no_function"))]
crate::Module::new(),
));
2020-06-03 04:44:36 +02:00
}
2016-02-29 22:43:45 +01:00
}