1use crate::api::options::LangOptions;
4use crate::ast::{
5    ASTFlags, BinaryExpr, CaseBlocksList, Expr, FlowControl, FnCallExpr, FnCallHashes, Ident,
6    OpAssignment, RangeCase, ScriptFuncDef, Stmt, StmtBlock, StmtBlockContainer,
7    SwitchCasesCollection,
8};
9use crate::engine::{Precedence, OP_CONTAINS, OP_NOT};
10use crate::eval::{Caches, GlobalRuntimeState};
11use crate::func::{hashing::get_hasher, StraightHashMap};
12use crate::tokenizer::{
13    is_reserved_keyword_or_symbol, is_valid_function_name, is_valid_identifier, Token, TokenStream,
14    TokenizerControl,
15};
16use crate::types::dynamic::{AccessMode, Union};
17use crate::{
18    calc_fn_hash, Dynamic, Engine, EvalAltResult, EvalContext, ExclusiveRange, FnArgsVec,
19    ImmutableString, InclusiveRange, LexError, ParseError, Position, Scope, Shared, SmartString,
20    StaticVec, ThinVec, VarDefInfo, AST, PERR,
21};
22use bitflags::bitflags;
23#[cfg(feature = "no_std")]
24use std::prelude::v1::*;
25use std::{
26    convert::TryFrom,
27    fmt,
28    hash::{Hash, Hasher},
29    num::{NonZeroU8, NonZeroUsize},
30};
31
32pub type ParseResult<T> = Result<T, ParseError>;
33
34#[cfg(not(feature = "no_function"))]
35type FnLib = StraightHashMap<Shared<ScriptFuncDef>>;
36
37const SCOPE_SEARCH_BARRIER_MARKER: &str = "$ BARRIER $";
39
40impl PERR {
41    #[cold]
43    #[inline(never)]
44    fn into_err(self, pos: Position) -> ParseError {
45        ParseError(self.into(), pos)
46    }
47}
48
49pub struct ParseState<'a, 't, 'f> {
52    pub input: &'t mut TokenStream<'a>,
54    pub tokenizer_control: TokenizerControl,
56    #[cfg(not(feature = "no_function"))]
58    pub lib: &'f mut FnLib,
59    pub expr_filter: fn(&Token) -> bool,
61    pub external_constants: Option<&'a Scope<'a>>,
63    pub global: Option<Box<GlobalRuntimeState>>,
65    pub stack: Scope<'a>,
67    pub frame_pointer: usize,
69    #[cfg(not(feature = "no_closure"))]
71    pub external_vars: ThinVec<Ident>,
72    pub allow_capture: bool,
80    #[cfg(not(feature = "no_module"))]
82    pub imports: ThinVec<ImmutableString>,
83    #[cfg(not(feature = "no_module"))]
85    pub global_imports: ThinVec<ImmutableString>,
86    #[cfg(feature = "no_function")]
88    pub _dummy: &'f (),
89}
90
91impl fmt::Debug for ParseState<'_, '_, '_> {
92    #[cold]
93    #[inline(never)]
94    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95        let mut f = f.debug_struct("ParseState");
96
97        f.field("tokenizer_control", &self.tokenizer_control)
98            .field("external_constants_scope", &self.external_constants)
99            .field("global", &self.global)
100            .field("stack", &self.stack)
101            .field("frame_pointer", &self.frame_pointer);
102
103        #[cfg(not(feature = "no_closure"))]
104        f.field("external_vars", &self.external_vars)
105            .field("allow_capture", &self.allow_capture);
106
107        #[cfg(not(feature = "no_module"))]
108        f.field("imports", &self.imports)
109            .field("global_imports", &self.global_imports);
110
111        f.finish()
112    }
113}
114
115impl<'a, 't, 'f> ParseState<'a, 't, 'f> {
116    #[inline]
118    #[must_use]
119    pub fn new(
120        external_constants: Option<&'a Scope>,
121        input: &'t mut TokenStream<'a>,
122        tokenizer_control: TokenizerControl,
123        #[cfg(not(feature = "no_function"))] lib: &'f mut FnLib,
124        #[cfg(feature = "no_function")] dummy: &'f (),
125    ) -> Self {
126        Self {
127            input,
128            tokenizer_control,
129            #[cfg(not(feature = "no_function"))]
130            lib,
131            #[cfg(feature = "no_function")]
132            _dummy: dummy,
133            expr_filter: |_| true,
134            #[cfg(not(feature = "no_closure"))]
135            external_vars: ThinVec::new(),
136            allow_capture: true,
137            external_constants,
138            global: None,
139            stack: Scope::new(),
140            frame_pointer: 0,
141            #[cfg(not(feature = "no_module"))]
142            imports: ThinVec::new(),
143            #[cfg(not(feature = "no_module"))]
144            global_imports: ThinVec::new(),
145        }
146    }
147
148    #[must_use]
157    pub fn find_var(&self, name: &str) -> (usize, bool) {
158        let mut hit_barrier = false;
159
160        let index = self
161            .stack
162            .iter_rev_inner()
163            .position(|(n, ..)| {
164                if n == SCOPE_SEARCH_BARRIER_MARKER {
165                    hit_barrier = true;
167                    false
168                } else {
169                    n == name
170                }
171            })
172            .map_or(0, |i| i + 1);
173
174        (index, hit_barrier)
175    }
176
177    #[cfg(not(feature = "no_module"))]
188    #[must_use]
189    pub fn find_module(&self, name: &str) -> Option<NonZeroUsize> {
190        self.imports
191            .iter()
192            .rev()
193            .rposition(|n| n == name)
194            .and_then(|i| NonZeroUsize::new(i + 1))
195    }
196}
197
198bitflags! {
199    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
201    pub struct ParseSettingFlags: u8 {
202        const GLOBAL_LEVEL = 0b0000_0001;
204        const FN_SCOPE = 0b0000_0010;
206        const CLOSURE_SCOPE = 0b0000_0100;
208        const BREAKABLE = 0b0000_1000;
210
211        const DISALLOW_STATEMENTS_IN_BLOCKS = 0b0001_0000;
213        const DISALLOW_UNQUOTED_MAP_PROPERTIES = 0b0010_0000;
215    }
216}
217
218bitflags! {
219    #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Copy)]
221    struct ChainingFlags: u8 {
222        const PROPERTY = 0b0000_0001;
224        const DISALLOW_NAMESPACES = 0b0000_0010;
226    }
227}
228
229#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
231pub struct ParseSettings {
232    pub flags: ParseSettingFlags,
234    pub options: LangOptions,
236    pub level: usize,
238    pub pos: Position,
240    #[cfg(not(feature = "unchecked"))]
242    pub max_expr_depth: usize,
243}
244
245impl ParseSettings {
246    #[inline(always)]
248    #[must_use]
249    pub const fn has_flag(&self, flag: ParseSettingFlags) -> bool {
250        self.flags.intersects(flag)
251    }
252    #[inline(always)]
254    #[must_use]
255    pub const fn has_option(&self, option: LangOptions) -> bool {
256        self.options.intersects(option)
257    }
258    #[inline]
260    pub fn level_up(&self) -> ParseResult<Self> {
261        #[cfg(not(feature = "unchecked"))]
262        if self.max_expr_depth > 0 && self.level >= self.max_expr_depth {
263            return Err(PERR::ExprTooDeep.into_err(self.pos));
264        }
265
266        Ok(Self {
267            level: self.level + 1,
268            ..*self
269        })
270    }
271    #[inline]
273    pub fn level_up_with_position(&self, pos: Position) -> ParseResult<Self> {
274        let mut x = self.level_up()?;
275        x.pos = pos;
276        Ok(x)
277    }
278}
279
280#[cfg(not(feature = "no_function"))]
282#[inline]
283#[must_use]
284pub fn make_anonymous_fn(hash: u64) -> crate::Identifier {
285    use std::fmt::Write;
286
287    let mut buf = crate::Identifier::new_const();
288    write!(&mut buf, "{}{hash:016x}", crate::engine::FN_ANONYMOUS).unwrap();
289    buf
290}
291
292#[cfg(not(feature = "no_function"))]
294#[inline(always)]
295#[must_use]
296pub fn is_anonymous_fn(fn_name: &str) -> bool {
297    fn_name.starts_with(crate::engine::FN_ANONYMOUS)
298}
299
300impl Expr {
301    fn ensure_bool_expr(self) -> ParseResult<Self> {
303        let type_name = match self {
304            Self::Unit(..) => "()",
305            Self::DynamicConstant(ref v, ..) if !v.is_bool() => v.type_name(),
306            Self::IntegerConstant(..) => "a number",
307            #[cfg(not(feature = "no_float"))]
308            Self::FloatConstant(..) => "a floating-point number",
309            Self::CharConstant(..) => "a character",
310            Self::StringConstant(..) => "a string",
311            Self::InterpolatedString(..) => "a string",
312            Self::Array(..) => "an array",
313            Self::Map(..) => "an object map",
314            _ => return Ok(self),
315        };
316
317        Err(
318            PERR::MismatchedType("a boolean expression".into(), type_name.into())
319                .into_err(self.start_position()),
320        )
321    }
322    fn ensure_iterable(self) -> ParseResult<Self> {
324        let type_name = match self {
325            Self::Unit(..) => "()",
326            Self::BoolConstant(..) => "a boolean",
327            Self::IntegerConstant(..) => "a number",
328            #[cfg(not(feature = "no_float"))]
329            Self::FloatConstant(..) => "a floating-point number",
330            Self::CharConstant(..) => "a character",
331            Self::Map(..) => "an object map",
332            _ => return Ok(self),
333        };
334
335        Err(
336            PERR::MismatchedType("an iterable value".into(), type_name.into())
337                .into_err(self.start_position()),
338        )
339    }
340}
341
342fn ensure_not_statement_expr(
344    input: &mut TokenStream,
345    type_name: &(impl ToString + ?Sized),
346) -> ParseResult<()> {
347    match input.peek().unwrap() {
348        (Token::LeftBrace, pos) => Err(PERR::ExprExpected(type_name.to_string()).into_err(*pos)),
349        _ => Ok(()),
350    }
351}
352
353fn ensure_not_assignment(input: &mut TokenStream) -> ParseResult<()> {
355    match input.peek().unwrap() {
356        (token @ Token::Equals, pos) => Err(LexError::ImproperSymbol(
357            token.literal_syntax().into(),
358            "Possibly a typo of '=='?".into(),
359        )
360        .into_err(*pos)),
361        _ => Ok(()),
362    }
363}
364
365#[inline(always)]
371fn eat_token(input: &mut TokenStream, expected_token: &Token) -> Position {
372    let (t, pos) = input.next().unwrap();
373
374    debug_assert_eq!(
375        &t,
376        expected_token,
377        "{} expected but gets {} at {}",
378        expected_token.literal_syntax(),
379        t.literal_syntax(),
380        pos,
381    );
382
383    pos
384}
385
386#[inline]
388fn match_token(input: &mut TokenStream, token: &Token) -> (bool, Position) {
389    let (t, pos) = input.peek().unwrap();
390    if t == token {
391        (true, eat_token(input, token))
392    } else {
393        (false, *pos)
394    }
395}
396
397#[cfg(not(feature = "no_function"))]
399#[cfg(feature = "metadata")]
400#[inline]
401fn unindent_block_comment(comment: String, pos: usize) -> String {
402    if pos == 0 || !comment.contains('\n') {
403        return comment;
404    }
405
406    let offset = comment
410        .lines()
411        .skip(1)
412        .map(|s| s.len() - s.trim_start_matches(' ').len())
413        .min()
414        .unwrap_or(pos)
415        .min(pos);
416
417    if offset == 0 {
418        return comment;
419    }
420
421    comment
422        .lines()
423        .enumerate()
424        .map(|(i, s)| if i > 0 { &s[offset..] } else { s })
425        .collect::<Vec<_>>()
426        .join("\n")
427}
428
429fn parse_var_name(input: &mut TokenStream) -> ParseResult<(SmartString, Position)> {
431    match input.next().unwrap() {
432        (Token::Identifier(s), pos) => Ok((*s, pos)),
434        (Token::Reserved(s), pos) if is_valid_identifier(&s) => {
436            Err(PERR::Reserved(s.to_string()).into_err(pos))
437        }
438        (Token::LexError(err), pos) => Err(err.into_err(pos)),
440        (.., pos) => Err(PERR::VariableExpected.into_err(pos)),
442    }
443}
444
445#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
451fn optimize_combo_chain(expr: &mut Expr) {
452    #[allow(clippy::type_complexity)]
453    let (mut x, x_options, x_pos, mut root, mut root_options, root_pos, make_sub, make_root): (
454        _,
455        _,
456        _,
457        _,
458        _,
459        _,
460        fn(_, _, _) -> Expr,
461        fn(_, _, _) -> Expr,
462    ) = match expr.take() {
463        #[cfg(not(feature = "no_index"))]
464        Expr::Index(mut x, opt, pos) => match x.lhs.take() {
465            Expr::Index(x2, opt2, pos2) => (x, opt, pos, x2, opt2, pos2, Expr::Index, Expr::Index),
466            #[cfg(not(feature = "no_object"))]
467            Expr::Dot(x2, opt2, pos2) => (x, opt, pos, x2, opt2, pos2, Expr::Index, Expr::Dot),
468            _ => unreachable!("combo chain expected"),
469        },
470        #[cfg(not(feature = "no_object"))]
471        Expr::Dot(mut x, opt, pos) => match x.lhs.take() {
472            #[cfg(not(feature = "no_index"))]
473            Expr::Index(x2, opt2, pos2) => (x, opt, pos, x2, opt2, pos2, Expr::Dot, Expr::Index),
474            Expr::Dot(x2, opt2, pos2) => (x, opt, pos, x2, opt2, pos2, Expr::Dot, Expr::Dot),
475            _ => unreachable!("combo chain expected"),
476        },
477        _ => unreachable!("combo chain expected"),
478    };
479
480    let mut tail = root.as_mut();
496    let mut tail_options = &mut root_options;
497
498    while !tail_options.intersects(ASTFlags::BREAK) {
499        match tail.rhs {
500            Expr::Index(ref mut x, ref mut options2, ..) => {
501                tail = x.as_mut();
502                tail_options = options2;
503            }
504            #[cfg(not(feature = "no_object"))]
505            Expr::Dot(ref mut x, ref mut options2, ..) => {
506                tail = x.as_mut();
507                tail_options = options2;
508            }
509            _ => break,
510        }
511    }
512
513    tail_options.remove(ASTFlags::BREAK);
516
517    x.lhs = tail.rhs.take(); tail.rhs = make_sub(x, x_options, x_pos); *expr = make_root(root, root_options, root_pos);
520}
521
522impl Engine {
523    #[must_use]
538    fn access_var(
539        &self,
540        state: &mut ParseState,
541        name: &str,
542        _pos: Position,
543    ) -> (Option<NonZeroUsize>, bool) {
544        let (index, hit_barrier) = state.find_var(name);
545
546        #[cfg(not(feature = "no_function"))]
547        let is_func_name = state.lib.values().any(|f| f.name == name);
548        #[cfg(feature = "no_function")]
549        let is_func_name = false;
550
551        #[cfg(not(feature = "no_closure"))]
552        if state.allow_capture {
553            if !is_func_name && index == 0 && !state.external_vars.iter().any(|v| v.name == name) {
554                let name = self.get_interned_string(name);
555                state.external_vars.push(Ident { name, pos: _pos });
556            }
557        } else {
558            state.allow_capture = true;
559        }
560
561        let index = (!hit_barrier).then(|| NonZeroUsize::new(index)).flatten();
562
563        (index, is_func_name)
564    }
565
566    #[cfg(not(feature = "no_object"))]
569    #[inline]
570    #[must_use]
571    fn convert_expr_into_property(&self, expr: Expr) -> Expr {
572        match expr {
573            #[cfg(not(feature = "no_module"))]
574            Expr::Variable(x, ..) if !x.2.is_empty() => unreachable!("qualified property"),
575            Expr::Variable(x, .., pos) => {
576                let ident = x.1.clone();
577                let getter = self.get_interned_getter(&ident);
578                let hash_get = calc_fn_hash(None, &getter, 1);
579                let setter = self.get_interned_setter(&ident);
580                let hash_set = calc_fn_hash(None, &setter, 2);
581
582                Expr::Property(
583                    Box::new(((getter, hash_get), (setter, hash_set), ident)),
584                    pos,
585                )
586            }
587            _ => expr,
588        }
589    }
590
591    fn parse_fn_call(
593        &self,
594        state: &mut ParseState,
595        settings: ParseSettings,
596        id: ImmutableString,
597        no_args: bool,
598        capture_parent_scope: bool,
599        #[cfg(not(feature = "no_module"))] mut namespace: crate::ast::Namespace,
600    ) -> ParseResult<Expr> {
601        let (token, token_pos) = if no_args {
602            &(Token::RightParen, Position::NONE)
603        } else {
604            state.input.peek().unwrap()
605        };
606
607        let mut args = FnArgsVec::new();
608
609        match token {
610            Token::EOF => {
612                return Err(PERR::MissingToken(
613                    Token::RightParen.into(),
614                    format!("to close the arguments list of this function call '{id}'"),
615                )
616                .into_err(*token_pos))
617            }
618            Token::LexError(err) => return Err(err.clone().into_err(*token_pos)),
620            Token::RightParen => {
622                if !no_args {
623                    eat_token(state.input, &Token::RightParen);
624                }
625
626                #[cfg(not(feature = "no_module"))]
627                let hash = if namespace.is_empty() {
628                    calc_fn_hash(None, &id, 0)
629                } else {
630                    let root = namespace.root();
631                    let index = state.find_module(root);
632                    let is_global = false;
633
634                    #[cfg(not(feature = "no_function"))]
635                    #[cfg(not(feature = "no_module"))]
636                    let is_global = is_global || root == crate::engine::KEYWORD_GLOBAL;
637
638                    if settings.has_option(LangOptions::STRICT_VAR)
639                        && index.is_none()
640                        && !is_global
641                        && !state.global_imports.iter().any(|m| m == root)
642                        && !self.global_sub_modules.contains_key(root)
643                    {
644                        return Err(
645                            PERR::ModuleUndefined(root.into()).into_err(namespace.position())
646                        );
647                    }
648
649                    namespace.index = index;
650
651                    calc_fn_hash(namespace.path.iter().map(Ident::as_str), &id, 0)
652                };
653                #[cfg(feature = "no_module")]
654                let hash = calc_fn_hash(None, &id, 0);
655
656                let hashes = if is_valid_function_name(&id) {
657                    FnCallHashes::from_hash(hash)
658                } else {
659                    FnCallHashes::from_native_only(hash)
660                };
661
662                args.shrink_to_fit();
663
664                return Ok(FnCallExpr {
665                    name: self.get_interned_string(id),
666                    capture_parent_scope,
667                    op_token: None,
668                    #[cfg(not(feature = "no_module"))]
669                    namespace,
670                    hashes,
671                    args,
672                }
673                .into_fn_call_expr(settings.pos));
674            }
675            _ => (),
677        }
678
679        let settings = settings.level_up()?;
680
681        loop {
682            match state.input.peek().unwrap() {
683                (Token::RightParen, ..) => (),
685                _ => args.push(self.parse_expr(state, settings)?),
686            }
687
688            match state.input.peek().unwrap() {
689                (Token::RightParen, ..) => {
691                    eat_token(state.input, &Token::RightParen);
692
693                    #[cfg(not(feature = "no_module"))]
694                    let hash = if namespace.is_empty() {
695                        calc_fn_hash(None, &id, args.len())
696                    } else {
697                        let root = namespace.root();
698                        let index = state.find_module(root);
699
700                        #[cfg(not(feature = "no_function"))]
701                        #[cfg(not(feature = "no_module"))]
702                        let is_global = root == crate::engine::KEYWORD_GLOBAL;
703                        #[cfg(any(feature = "no_function", feature = "no_module"))]
704                        let is_global = false;
705
706                        if settings.has_option(LangOptions::STRICT_VAR)
707                            && index.is_none()
708                            && !is_global
709                            && !state.global_imports.iter().any(|m| m == root)
710                            && !self.global_sub_modules.contains_key(root)
711                        {
712                            return Err(
713                                PERR::ModuleUndefined(root.into()).into_err(namespace.position())
714                            );
715                        }
716
717                        namespace.index = index;
718
719                        calc_fn_hash(namespace.path.iter().map(Ident::as_str), &id, args.len())
720                    };
721                    #[cfg(feature = "no_module")]
722                    let hash = calc_fn_hash(None, &id, args.len());
723
724                    let hashes = if is_valid_function_name(&id) {
725                        FnCallHashes::from_hash(hash)
726                    } else {
727                        FnCallHashes::from_native_only(hash)
728                    };
729
730                    args.shrink_to_fit();
731
732                    return Ok(FnCallExpr {
733                        name: self.get_interned_string(id),
734                        capture_parent_scope,
735                        op_token: None,
736                        #[cfg(not(feature = "no_module"))]
737                        namespace,
738                        hashes,
739                        args,
740                    }
741                    .into_fn_call_expr(settings.pos));
742                }
743                (Token::Comma, ..) => {
745                    eat_token(state.input, &Token::Comma);
746                }
747                (Token::EOF, pos) => {
749                    return Err(PERR::MissingToken(
750                        Token::RightParen.into(),
751                        format!("to close the arguments list of this function call '{id}'"),
752                    )
753                    .into_err(*pos))
754                }
755                (Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
757                (.., pos) => {
759                    return Err(PERR::MissingToken(
760                        Token::Comma.into(),
761                        format!("to separate the arguments to function call '{id}'"),
762                    )
763                    .into_err(*pos))
764                }
765            }
766        }
767    }
768
769    #[cfg(not(feature = "no_index"))]
772    fn parse_index_chain(
773        &self,
774        state: &mut ParseState,
775        mut settings: ParseSettings,
776        lhs: Expr,
777        options: ASTFlags,
778        check_types: bool,
779    ) -> ParseResult<Expr> {
780        fn check_argument_types(lhs: &Expr, idx_expr: &Expr) -> Result<(), ParseError> {
781            match *lhs {
784                Expr::Map(..) => match *idx_expr {
785                    Expr::IntegerConstant(..) => Err(PERR::MalformedIndexExpr(
787                        "Object map expects string index, not a number".into(),
788                    )
789                    .into_err(idx_expr.start_position())),
790
791                    Expr::StringConstant(..) | Expr::InterpolatedString(..) => Ok(()),
793
794                    #[cfg(not(feature = "no_float"))]
796                    Expr::FloatConstant(..) => Err(PERR::MalformedIndexExpr(
797                        "Object map expects string index, not a float".into(),
798                    )
799                    .into_err(idx_expr.start_position())),
800                    Expr::CharConstant(..) => Err(PERR::MalformedIndexExpr(
802                        "Object map expects string index, not a character".into(),
803                    )
804                    .into_err(idx_expr.start_position())),
805                    Expr::Unit(..) => Err(PERR::MalformedIndexExpr(
807                        "Object map expects string index, not ()".into(),
808                    )
809                    .into_err(idx_expr.start_position())),
810                    Expr::And(..) | Expr::Or(..) | Expr::BoolConstant(..) => {
812                        Err(PERR::MalformedIndexExpr(
813                            "Object map expects string index, not a boolean".into(),
814                        )
815                        .into_err(idx_expr.start_position()))
816                    }
817                    _ => Ok(()),
818                },
819
820                Expr::IntegerConstant(..)
821                | Expr::Array(..)
822                | Expr::StringConstant(..)
823                | Expr::InterpolatedString(..) => match *idx_expr {
824                    Expr::IntegerConstant(..) => Ok(()),
826
827                    Expr::StringConstant(..) | Expr::InterpolatedString(..) => {
829                        Err(PERR::MalformedIndexExpr(
830                            "Array, string or bit-field expects numeric index, not a string".into(),
831                        )
832                        .into_err(idx_expr.start_position()))
833                    }
834                    #[cfg(not(feature = "no_float"))]
836                    Expr::FloatConstant(..) => Err(PERR::MalformedIndexExpr(
837                        "Array, string or bit-field expects integer index, not a float".into(),
838                    )
839                    .into_err(idx_expr.start_position())),
840                    Expr::CharConstant(..) => Err(PERR::MalformedIndexExpr(
842                        "Array, string or bit-field expects integer index, not a character".into(),
843                    )
844                    .into_err(idx_expr.start_position())),
845                    Expr::Unit(..) => Err(PERR::MalformedIndexExpr(
847                        "Array, string or bit-field expects integer index, not ()".into(),
848                    )
849                    .into_err(idx_expr.start_position())),
850                    Expr::And(..) | Expr::Or(..) | Expr::BoolConstant(..) => {
852                        Err(PERR::MalformedIndexExpr(
853                            "Array, string or bit-field expects integer index, not a boolean"
854                                .into(),
855                        )
856                        .into_err(idx_expr.start_position()))
857                    }
858                    _ => Ok(()),
859                },
860                _ => Ok(()),
861            }
862        }
863
864        let idx_expr = self.parse_expr(state, settings.level_up()?)?;
865
866        if check_types {
867            check_argument_types(&lhs, &idx_expr)?;
868        }
869
870        match state.input.peek().unwrap() {
872            (Token::RightBracket, ..) => {
873                eat_token(state.input, &Token::RightBracket);
874
875                match state.input.peek().unwrap() {
877                    (Token::LeftBracket | Token::QuestionBracket, ..) => {
879                        let (token, pos) = state.input.next().unwrap();
880                        let prev_pos = settings.pos;
881                        settings.pos = pos;
882                        let settings = settings.level_up()?;
883                        let options = match token {
885                            Token::LeftBracket => ASTFlags::empty(),
886                            Token::QuestionBracket => ASTFlags::NEGATED,
887                            _ => unreachable!("`[` or `?[`"),
888                        };
889                        let idx_expr =
890                            self.parse_index_chain(state, settings, idx_expr, options, false)?;
891                        Ok(Expr::Index(
893                            BinaryExpr { lhs, rhs: idx_expr }.into(),
894                            options,
895                            prev_pos,
896                        ))
897                    }
898                    _ => Ok(Expr::Index(
900                        BinaryExpr { lhs, rhs: idx_expr }.into(),
901                        options | ASTFlags::BREAK,
902                        settings.pos,
903                    )),
904                }
905            }
906            (Token::LexError(err), pos) => Err(err.clone().into_err(*pos)),
907            (.., pos) => Err(PERR::MissingToken(
908                Token::RightBracket.into(),
909                "for a matching [ in this index expression".into(),
910            )
911            .into_err(*pos)),
912        }
913    }
914
915    #[cfg(not(feature = "no_index"))]
917    fn parse_array_literal(
918        &self,
919        state: &mut ParseState,
920        mut settings: ParseSettings,
921    ) -> ParseResult<Expr> {
922        settings.pos = eat_token(state.input, &Token::LeftBracket);
924
925        let mut array = ThinVec::new();
926
927        loop {
928            const MISSING_RBRACKET: &str = "to end this array literal";
929
930            #[cfg(not(feature = "unchecked"))]
931            if self.max_array_size() > 0 && array.len() >= self.max_array_size() {
932                return Err(PERR::LiteralTooLarge(
933                    "Size of array literal".into(),
934                    self.max_array_size(),
935                )
936                .into_err(state.input.peek().unwrap().1));
937            }
938
939            match state.input.peek().unwrap() {
940                (Token::RightBracket, ..) => {
941                    eat_token(state.input, &Token::RightBracket);
942                    break;
943                }
944                (Token::EOF, pos) => {
945                    return Err(PERR::MissingToken(
946                        Token::RightBracket.into(),
947                        MISSING_RBRACKET.into(),
948                    )
949                    .into_err(*pos))
950                }
951                _ => array.push(self.parse_expr(state, settings.level_up()?)?),
952            }
953
954            match state.input.peek().unwrap() {
955                (Token::Comma, ..) => {
956                    eat_token(state.input, &Token::Comma);
957                }
958                (Token::RightBracket, ..) => (),
959                (Token::EOF, pos) => {
960                    return Err(PERR::MissingToken(
961                        Token::RightBracket.into(),
962                        MISSING_RBRACKET.into(),
963                    )
964                    .into_err(*pos))
965                }
966                (Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
967                (.., pos) => {
968                    return Err(PERR::MissingToken(
969                        Token::Comma.into(),
970                        "to separate the items of this array literal".into(),
971                    )
972                    .into_err(*pos))
973                }
974            };
975        }
976
977        array.shrink_to_fit();
978
979        Ok(Expr::Array(array, settings.pos))
980    }
981
982    #[cfg(not(feature = "no_object"))]
984    fn parse_map_literal(
985        &self,
986        state: &mut ParseState,
987        mut settings: ParseSettings,
988    ) -> ParseResult<Expr> {
989        settings.pos = eat_token(state.input, &Token::MapStart);
991
992        let mut map = StaticVec::<(Ident, Expr)>::new();
993        let mut template = std::collections::BTreeMap::<crate::Identifier, crate::Dynamic>::new();
994
995        loop {
996            const MISSING_RBRACE: &str = "to end this object map literal";
997
998            match state.input.peek().unwrap() {
999                (Token::RightBrace, ..) => {
1000                    eat_token(state.input, &Token::RightBrace);
1001                    break;
1002                }
1003                (Token::EOF, pos) => {
1004                    return Err(
1005                        PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into())
1006                            .into_err(*pos),
1007                    )
1008                }
1009                _ => (),
1010            }
1011
1012            let (name, pos) = match state.input.next().unwrap() {
1013                (Token::Identifier(..), pos)
1014                    if settings.has_flag(ParseSettingFlags::DISALLOW_UNQUOTED_MAP_PROPERTIES) =>
1015                {
1016                    return Err(PERR::PropertyExpected.into_err(pos))
1017                }
1018                (Token::Identifier(s) | Token::StringConstant(s), pos) => {
1019                    if map.iter().any(|(p, ..)| p.as_str() == s.as_str()) {
1020                        return Err(PERR::DuplicatedProperty(s.to_string()).into_err(pos));
1021                    }
1022                    (*s, pos)
1023                }
1024                (Token::InterpolatedString(..), pos) => {
1025                    return Err(PERR::PropertyExpected.into_err(pos))
1026                }
1027                (Token::Reserved(s), pos) if is_valid_identifier(&s) => {
1028                    return Err(PERR::Reserved(s.to_string()).into_err(pos));
1029                }
1030                (Token::LexError(err), pos) => return Err(err.into_err(pos)),
1031                (Token::EOF, pos) => {
1032                    return Err(PERR::MissingToken(
1033                        Token::RightBrace.into(),
1034                        MISSING_RBRACE.into(),
1035                    )
1036                    .into_err(pos));
1037                }
1038                (.., pos) if map.is_empty() => {
1039                    return Err(PERR::MissingToken(
1040                        Token::RightBrace.into(),
1041                        MISSING_RBRACE.into(),
1042                    )
1043                    .into_err(pos));
1044                }
1045                (.., pos) => return Err(PERR::PropertyExpected.into_err(pos)),
1046            };
1047
1048            match state.input.next().unwrap() {
1049                (Token::Colon, ..) => (),
1050                (Token::LexError(err), pos) => return Err(err.into_err(pos)),
1051                (.., pos) => {
1052                    return Err(PERR::MissingToken(
1053                        Token::Colon.into(),
1054                        format!("to follow the property '{name}' in this object map literal"),
1055                    )
1056                    .into_err(pos))
1057                }
1058            };
1059
1060            #[cfg(not(feature = "unchecked"))]
1061            if self.max_map_size() > 0 && map.len() >= self.max_map_size() {
1062                return Err(PERR::LiteralTooLarge(
1063                    "Number of properties in object map literal".into(),
1064                    self.max_map_size(),
1065                )
1066                .into_err(state.input.peek().unwrap().1));
1067            }
1068
1069            let expr = self.parse_expr(state, settings.level_up()?)?;
1070            template.insert(name.clone(), crate::Dynamic::UNIT);
1071
1072            let name = self.get_interned_string(name);
1073            map.push((Ident { name, pos }, expr));
1074
1075            match state.input.peek().unwrap() {
1076                (Token::Comma, ..) => {
1077                    eat_token(state.input, &Token::Comma);
1078                }
1079                (Token::RightBrace, ..) => (),
1080                (Token::Identifier(..), pos) => {
1081                    return Err(PERR::MissingToken(
1082                        Token::Comma.into(),
1083                        "to separate the items of this object map literal".into(),
1084                    )
1085                    .into_err(*pos))
1086                }
1087                (Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
1088                (.., pos) => {
1089                    return Err(
1090                        PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into())
1091                            .into_err(*pos),
1092                    )
1093                }
1094            }
1095        }
1096
1097        map.shrink_to_fit();
1098
1099        Ok(Expr::Map((map, template).into(), settings.pos))
1100    }
1101
1102    fn parse_switch(&self, state: &mut ParseState, settings: ParseSettings) -> ParseResult<Stmt> {
1104        let settings = settings.level_up_with_position(eat_token(state.input, &Token::Switch))?;
1106
1107        let item = self.parse_expr(state, settings)?;
1108
1109        match state.input.next().unwrap() {
1110            (Token::LeftBrace, ..) => (),
1111            (Token::LexError(err), pos) => return Err(err.into_err(pos)),
1112            (.., pos) => {
1113                return Err(PERR::MissingToken(
1114                    Token::LeftBrace.into(),
1115                    "to start a switch block".into(),
1116                )
1117                .into_err(pos))
1118            }
1119        }
1120
1121        let mut expressions = FnArgsVec::<BinaryExpr>::new();
1122        let mut cases = StraightHashMap::<CaseBlocksList>::default();
1123        let mut ranges = StaticVec::<RangeCase>::new();
1124        let mut def_case = None;
1125        let mut def_case_pos = Position::NONE;
1126
1127        loop {
1128            const MISSING_RBRACE: &str = "to end this switch block";
1129
1130            let (case_expr_list, condition) = match state.input.peek().unwrap() {
1131                (Token::RightBrace, ..) => {
1132                    eat_token(state.input, &Token::RightBrace);
1133                    break;
1134                }
1135                (Token::EOF, pos) => {
1136                    return Err(
1137                        PERR::MissingToken(Token::RightBrace.into(), MISSING_RBRACE.into())
1138                            .into_err(*pos),
1139                    )
1140                }
1141                (Token::Underscore, pos) if def_case.is_none() => {
1142                    def_case_pos = *pos;
1143                    eat_token(state.input, &Token::Underscore);
1144
1145                    let (if_clause, if_pos) = match_token(state.input, &Token::If);
1146
1147                    if if_clause {
1148                        return Err(PERR::WrongSwitchCaseCondition.into_err(if_pos));
1149                    }
1150
1151                    (
1152                        StaticVec::new_const(),
1153                        Expr::BoolConstant(true, Position::NONE),
1154                    )
1155                }
1156                _ if def_case.is_some() => {
1157                    return Err(PERR::WrongSwitchDefaultCase.into_err(def_case_pos))
1158                }
1159
1160                _ => {
1161                    let mut case_expr_list = StaticVec::new_const();
1162
1163                    loop {
1164                        let filter = state.expr_filter;
1165                        state.expr_filter = |t| t != &Token::Pipe;
1166                        let expr = self.parse_expr(state, settings);
1167                        state.expr_filter = filter;
1168
1169                        match expr {
1170                            Ok(expr) => case_expr_list.push(expr),
1171                            Err(err) => {
1172                                return Err(PERR::ExprExpected("literal".into()).into_err(err.1))
1173                            }
1174                        }
1175
1176                        if !match_token(state.input, &Token::Pipe).0 {
1177                            break;
1178                        }
1179                    }
1180
1181                    let condition = if match_token(state.input, &Token::If).0 {
1182                        ensure_not_statement_expr(state.input, "a boolean")?;
1183                        let guard = self.parse_expr(state, settings)?.ensure_bool_expr()?;
1184                        ensure_not_assignment(state.input)?;
1185                        guard
1186                    } else {
1187                        Expr::BoolConstant(true, Position::NONE)
1188                    };
1189                    (case_expr_list, condition)
1190                }
1191            };
1192
1193            match state.input.next().unwrap() {
1194                (Token::DoubleArrow, ..) => (),
1195                (Token::LexError(err), pos) => return Err(err.into_err(pos)),
1196                (.., pos) => {
1197                    return Err(PERR::MissingToken(
1198                        Token::DoubleArrow.into(),
1199                        "in this switch case".into(),
1200                    )
1201                    .into_err(pos))
1202                }
1203            };
1204
1205            let (action_expr, need_comma) =
1206                if settings.has_flag(ParseSettingFlags::DISALLOW_STATEMENTS_IN_BLOCKS) {
1207                    (self.parse_expr(state, settings)?, true)
1208                } else {
1209                    let stmt = self.parse_stmt(state, settings)?;
1210                    let need_comma = !stmt.is_self_terminated();
1211
1212                    let stmt_block: StmtBlock = stmt.into();
1213                    (Expr::Stmt(stmt_block.into()), need_comma)
1214                };
1215
1216            expressions.push(BinaryExpr {
1217                lhs: condition,
1218                rhs: action_expr,
1219            });
1220
1221            let index = expressions.len() - 1;
1222
1223            if case_expr_list.is_empty() {
1224                def_case = Some(index);
1225            } else {
1226                for expr in case_expr_list {
1227                    let value = expr.get_literal_value(None).ok_or_else(|| {
1228                        PERR::ExprExpected("a literal".into()).into_err(expr.start_position())
1229                    })?;
1230
1231                    let mut range_value: Option<RangeCase> = None;
1232
1233                    if let Some(range) = value.read_lock::<ExclusiveRange>() {
1234                        range_value = Some(range.clone().into());
1235                    } else if let Some(range) = value.read_lock::<InclusiveRange>() {
1236                        range_value = Some(range.clone().into());
1237                    }
1238
1239                    if let Some(mut r) = range_value {
1240                        if !r.is_empty() {
1241                            r.set_index(index);
1242                            ranges.push(r);
1243                        }
1244                    } else if !ranges.is_empty() {
1245                        let forbidden = match value {
1247                            Dynamic(Union::Int(..)) => true,
1248                            #[cfg(not(feature = "no_float"))]
1249                            Dynamic(Union::Float(..)) => true,
1250                            #[cfg(feature = "decimal")]
1251                            Dynamic(Union::Decimal(..)) => true,
1252                            _ => false,
1253                        };
1254
1255                        if forbidden {
1256                            return Err(
1257                                PERR::WrongSwitchIntegerCase.into_err(expr.start_position())
1258                            );
1259                        }
1260                    }
1261
1262                    let hasher = &mut get_hasher();
1263                    value.hash(hasher);
1264                    let hash = hasher.finish();
1265
1266                    cases
1267                        .entry(hash)
1268                        .or_insert(CaseBlocksList::new_const())
1269                        .push(index);
1270                }
1271            }
1272
1273            match state.input.peek().unwrap() {
1274                (Token::Comma, ..) => {
1275                    eat_token(state.input, &Token::Comma);
1276                }
1277                (Token::RightBrace, ..) => (),
1278                (Token::EOF, pos) => {
1279                    return Err(
1280                        PERR::MissingToken(Token::RightParen.into(), MISSING_RBRACE.into())
1281                            .into_err(*pos),
1282                    )
1283                }
1284                (Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
1285                (.., pos) if need_comma => {
1286                    return Err(PERR::MissingToken(
1287                        Token::Comma.into(),
1288                        "to separate the items in this switch block".into(),
1289                    )
1290                    .into_err(*pos))
1291                }
1292                _ => (),
1293            }
1294        }
1295
1296        expressions.shrink_to_fit();
1297        cases.shrink_to_fit();
1298        ranges.shrink_to_fit();
1299
1300        let cases = SwitchCasesCollection {
1301            expressions,
1302            cases,
1303            ranges,
1304            def_case,
1305        };
1306
1307        Ok(Stmt::Switch((item, cases).into(), settings.pos))
1308    }
1309
1310    fn parse_primary(
1312        &self,
1313        state: &mut ParseState,
1314        mut settings: ParseSettings,
1315        options: ChainingFlags,
1316    ) -> ParseResult<Expr> {
1317        let (next_token, next_token_pos) = state.input.peek().unwrap();
1318
1319        settings.pos = *next_token_pos;
1320
1321        let root_expr = match next_token {
1322            _ if !(state.expr_filter)(next_token) => {
1323                return Err(LexError::UnexpectedInput(next_token.to_string()).into_err(settings.pos))
1324            }
1325
1326            Token::EOF => return Err(PERR::UnexpectedEOF.into_err(settings.pos)),
1327
1328            Token::Unit => {
1329                state.input.next();
1330                Expr::Unit(settings.pos)
1331            }
1332
1333            Token::IntegerConstant(..)
1334            | Token::CharConstant(..)
1335            | Token::StringConstant(..)
1336            | Token::True
1337            | Token::False => match state.input.next().unwrap().0 {
1338                Token::IntegerConstant(x) => Expr::IntegerConstant(x, settings.pos),
1339                Token::CharConstant(c) => Expr::CharConstant(c, settings.pos),
1340                Token::StringConstant(s) => {
1341                    Expr::StringConstant(self.get_interned_string(*s), settings.pos)
1342                }
1343                Token::True => Expr::BoolConstant(true, settings.pos),
1344                Token::False => Expr::BoolConstant(false, settings.pos),
1345                token => unreachable!("token is {:?}", token),
1346            },
1347            Token::ExclusiveRange | Token::InclusiveRange => Expr::IntegerConstant(0, settings.pos),
1348            #[cfg(not(feature = "no_float"))]
1349            Token::FloatConstant(x) => {
1350                let x = x.0;
1351                state.input.next();
1352                Expr::FloatConstant(x, settings.pos)
1353            }
1354            #[cfg(feature = "decimal")]
1355            Token::DecimalConstant(x) => {
1356                let x = x.0;
1357                state.input.next();
1358                Expr::DynamicConstant(Box::new(x.into()), settings.pos)
1359            }
1360
1361            Token::LeftBrace if settings.has_option(LangOptions::STMT_EXPR) => {
1363                match self.parse_block(state, settings.level_up()?, false)? {
1364                    block @ Stmt::Block(..) => Expr::Stmt(Box::new(block.into())),
1365                    stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt),
1366                }
1367            }
1368
1369            Token::LeftParen => {
1371                settings.pos = eat_token(state.input, &Token::LeftParen);
1372
1373                let expr = self.parse_expr(state, settings.level_up()?)?;
1374
1375                match state.input.next().unwrap() {
1376                    (Token::RightParen, ..) => expr,
1378                    (Token::LexError(err), pos) => return Err(err.into_err(pos)),
1380                    (.., pos) => {
1382                        return Err(PERR::MissingToken(
1383                            Token::RightParen.into(),
1384                            "for a matching ( in this expression".into(),
1385                        )
1386                        .into_err(pos))
1387                    }
1388                }
1389            }
1390
1391            Token::If if settings.has_option(LangOptions::IF_EXPR) => {
1393                Expr::Stmt(Box::new(self.parse_if(state, settings.level_up()?)?.into()))
1394            }
1395            Token::While | Token::Loop
1397                if self.allow_looping() && settings.has_option(LangOptions::LOOP_EXPR) =>
1398            {
1399                Expr::Stmt(Box::new(
1400                    self.parse_while_loop(state, settings.level_up()?)?.into(),
1401                ))
1402            }
1403            Token::Do if self.allow_looping() && settings.has_option(LangOptions::LOOP_EXPR) => {
1404                Expr::Stmt(Box::new(self.parse_do(state, settings.level_up()?)?.into()))
1405            }
1406            Token::For if self.allow_looping() && settings.has_option(LangOptions::LOOP_EXPR) => {
1407                Expr::Stmt(Box::new(
1408                    self.parse_for(state, settings.level_up()?)?.into(),
1409                ))
1410            }
1411            Token::Switch if settings.has_option(LangOptions::SWITCH_EXPR) => Expr::Stmt(Box::new(
1413                self.parse_switch(state, settings.level_up()?)?.into(),
1414            )),
1415
1416            #[cfg(not(feature = "no_function"))]
1418            #[cfg(not(feature = "unchecked"))]
1419            Token::Pipe | Token::Or
1420                if settings.has_option(LangOptions::ANON_FN)
1421                    && state.lib.len() >= self.max_functions() =>
1422            {
1423                return Err(PERR::TooManyFunctions.into_err(settings.pos));
1424            }
1425            #[cfg(not(feature = "no_function"))]
1426            Token::Pipe | Token::Or if settings.has_option(LangOptions::ANON_FN) => {
1427                self.parse_anon_fn(state, settings, false)?
1428            }
1429
1430            Token::InterpolatedString(..) => {
1432                let mut segments = ThinVec::new();
1433                let settings = settings.level_up()?;
1434
1435                match state.input.next().unwrap() {
1436                    (Token::InterpolatedString(s), ..) if s.is_empty() => (),
1437                    (Token::InterpolatedString(s), pos) => {
1438                        segments.push(Expr::StringConstant(self.get_interned_string(*s), pos))
1439                    }
1440                    token => {
1441                        unreachable!("Token::InterpolatedString expected but gets {:?}", token)
1442                    }
1443                }
1444
1445                loop {
1446                    let expr = match self.parse_block(state, settings, false)? {
1447                        block @ Stmt::Block(..) => Expr::Stmt(Box::new(block.into())),
1448                        stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt),
1449                    };
1450                    match expr {
1451                        Expr::StringConstant(s, ..) if s.is_empty() => (),
1452                        _ => segments.push(expr),
1453                    }
1454
1455                    state.tokenizer_control.borrow_mut().is_within_text = true;
1457
1458                    match state.input.next().unwrap() {
1459                        (Token::StringConstant(s), pos) => {
1460                            if !s.is_empty() {
1461                                segments
1462                                    .push(Expr::StringConstant(self.get_interned_string(*s), pos));
1463                            }
1464                            break;
1466                        }
1467                        (Token::InterpolatedString(s), pos) => {
1468                            if !s.is_empty() {
1469                                segments
1470                                    .push(Expr::StringConstant(self.get_interned_string(*s), pos));
1471                            }
1472                        }
1473                        (Token::LexError(err), pos) => match *err {
1474                            LexError::UnterminatedString | LexError::StringTooLong(_) => {
1475                                return Err(err.into_err(pos))
1476                            }
1477                            _ => unreachable!("improper lex error: {:?}", err),
1478                        },
1479                        (token, ..) => unreachable!(
1480                            "string within an interpolated string literal expected but gets {:?}",
1481                            token
1482                        ),
1483                    }
1484                }
1485
1486                if segments.is_empty() {
1487                    Expr::StringConstant(self.get_interned_string(""), settings.pos)
1488                } else {
1489                    segments.shrink_to_fit();
1490                    Expr::InterpolatedString(segments, settings.pos)
1491                }
1492            }
1493
1494            #[cfg(not(feature = "no_index"))]
1496            Token::LeftBracket => self.parse_array_literal(state, settings.level_up()?)?,
1497
1498            #[cfg(not(feature = "no_object"))]
1500            Token::MapStart => self.parse_map_literal(state, settings.level_up()?)?,
1501
1502            #[cfg(not(feature = "no_custom_syntax"))]
1504            Token::Custom(key) | Token::Reserved(key) | Token::Identifier(key)
1505                if self.custom_syntax.contains_key(&**key) =>
1506            {
1507                let (key, syntax) = self.custom_syntax.get_key_value(&**key).unwrap();
1508                let _ = state.input.next().unwrap();
1509                self.parse_custom_syntax(state, settings.level_up()?, key, syntax)?
1510            }
1511
1512            Token::Identifier(..) => {
1514                #[cfg(not(feature = "no_module"))]
1515                let ns = crate::ast::Namespace::NONE;
1516
1517                let s = match state.input.next().unwrap() {
1518                    (Token::Identifier(s), ..) => s,
1519                    token => unreachable!("Token::Identifier expected but gets {:?}", token),
1520                };
1521
1522                match state.input.peek().unwrap() {
1523                    (Token::LeftParen | Token::Bang | Token::Unit, _) => {
1525                        state.allow_capture = true;
1527
1528                        Expr::Variable(
1529                            #[cfg(not(feature = "no_module"))]
1530                            (None, self.get_interned_string(*s), ns, 0).into(),
1531                            #[cfg(feature = "no_module")]
1532                            (None, self.get_interned_string(*s)).into(),
1533                            None,
1534                            settings.pos,
1535                        )
1536                    }
1537                    #[cfg(not(feature = "no_module"))]
1539                    (token @ Token::DoubleColon, pos) => {
1540                        if options.intersects(ChainingFlags::DISALLOW_NAMESPACES) {
1541                            return Err(LexError::ImproperSymbol(
1542                                token.literal_syntax().into(),
1543                                String::new(),
1544                            )
1545                            .into_err(*pos));
1546                        }
1547
1548                        state.allow_capture = true;
1550
1551                        let name = self.get_interned_string(*s);
1552                        Expr::Variable((None, name, ns, 0).into(), None, settings.pos)
1553                    }
1554                    _ => {
1556                        let (index, is_func) = self.access_var(state, &s, settings.pos);
1557
1558                        if !options.intersects(ChainingFlags::PROPERTY)
1559                            && !is_func
1560                            && index.is_none()
1561                            && settings.has_option(LangOptions::STRICT_VAR)
1562                            && !state
1563                                .external_constants
1564                                .map_or(false, |scope| scope.contains(&s))
1565                        {
1566                            return Err(
1567                                PERR::VariableUndefined(s.to_string()).into_err(settings.pos)
1568                            );
1569                        }
1570
1571                        let short_index = index
1572                            .and_then(|x| u8::try_from(x.get()).ok())
1573                            .and_then(NonZeroU8::new);
1574                        let name = self.get_interned_string(*s);
1575
1576                        Expr::Variable(
1577                            #[cfg(not(feature = "no_module"))]
1578                            (index, name, ns, 0).into(),
1579                            #[cfg(feature = "no_module")]
1580                            (index, name).into(),
1581                            short_index,
1582                            settings.pos,
1583                        )
1584                    }
1585                }
1586            }
1587
1588            Token::Reserved(..) => {
1590                #[cfg(not(feature = "no_module"))]
1591                let ns = crate::ast::Namespace::NONE;
1592
1593                let s = match state.input.next().unwrap() {
1594                    (Token::Reserved(s), ..) => s,
1595                    token => unreachable!("Token::Reserved expected but gets {:?}", token),
1596                };
1597
1598                match state.input.peek().unwrap().0 {
1599                    Token::LeftParen | Token::Bang | Token::Unit
1601                        if is_reserved_keyword_or_symbol(&s).1 =>
1602                    {
1603                        Expr::Variable(
1604                            #[cfg(not(feature = "no_module"))]
1605                            (None, self.get_interned_string(*s), ns, 0).into(),
1606                            #[cfg(feature = "no_module")]
1607                            (None, self.get_interned_string(*s)).into(),
1608                            None,
1609                            settings.pos,
1610                        )
1611                    }
1612                    #[cfg(not(feature = "no_function"))]
1614                    _ if *s == crate::engine::KEYWORD_THIS => {
1615                        if settings.has_flag(ParseSettingFlags::FN_SCOPE) {
1617                            Expr::ThisPtr(settings.pos)
1618                        } else {
1619                            let msg = format!("'{s}' can only be used in functions");
1621                            return Err(
1622                                LexError::ImproperSymbol(s.to_string(), msg).into_err(settings.pos)
1623                            );
1624                        }
1625                    }
1626                    _ => return Err(PERR::Reserved(s.to_string()).into_err(settings.pos)),
1627                }
1628            }
1629
1630            Token::LexError(..) => match state.input.next().unwrap() {
1631                (Token::LexError(err), ..) => return Err(err.into_err(settings.pos)),
1632                token => unreachable!("Token::LexError expected but gets {:?}", token),
1633            },
1634
1635            _ => {
1636                return Err(LexError::UnexpectedInput(next_token.to_string()).into_err(settings.pos))
1637            }
1638        };
1639
1640        if !(state.expr_filter)(&state.input.peek().unwrap().0) {
1641            return Ok(root_expr);
1642        }
1643
1644        self.parse_postfix(state, settings, root_expr, ChainingFlags::empty())
1645    }
1646
1647    fn parse_postfix(
1649        &self,
1650        state: &mut ParseState,
1651        mut settings: ParseSettings,
1652        mut lhs: Expr,
1653        _options: ChainingFlags,
1654    ) -> ParseResult<Expr> {
1655        let mut _parent_options = ASTFlags::BREAK;
1657
1658        loop {
1660            let (tail_token, ..) = state.input.peek().unwrap();
1661
1662            if !lhs.is_valid_postfix(tail_token) {
1663                break;
1664            }
1665
1666            let (tail_token, tail_pos) = state.input.next().unwrap();
1667            settings.pos = tail_pos;
1668
1669            lhs = match (lhs, tail_token) {
1670                #[cfg(not(feature = "no_module"))]
1672                (Expr::Variable(x, ..), Token::Bang) if !x.2.is_empty() => {
1673                    return match state.input.peek().unwrap() {
1674                        (Token::LeftParen | Token::Unit, ..) => {
1675                            Err(LexError::UnexpectedInput(Token::Bang.into()).into_err(tail_pos))
1676                        }
1677                        _ => Err(LexError::ImproperSymbol(
1678                            "!".into(),
1679                            "'!' cannot be used to call module functions".into(),
1680                        )
1681                        .into_err(tail_pos)),
1682                    };
1683                }
1684                (Expr::Variable(x, .., pos), Token::Bang) => {
1686                    match state.input.peek().unwrap() {
1687                        (Token::LeftParen | Token::Unit, ..) => (),
1688                        (_, pos) => {
1689                            return Err(PERR::MissingToken(
1690                                Token::LeftParen.into(),
1691                                "to start arguments list of function call".into(),
1692                            )
1693                            .into_err(*pos))
1694                        }
1695                    }
1696
1697                    let no_args = state.input.next().unwrap().0 == Token::Unit;
1698
1699                    #[cfg(not(feature = "no_module"))]
1700                    let (_, name, ns, ..) = *x;
1701                    #[cfg(feature = "no_module")]
1702                    let (_, name) = *x;
1703
1704                    settings.pos = pos;
1705
1706                    self.parse_fn_call(
1707                        state,
1708                        settings,
1709                        name,
1710                        no_args,
1711                        true,
1712                        #[cfg(not(feature = "no_module"))]
1713                        ns,
1714                    )?
1715                }
1716                (Expr::Variable(x, .., pos), t @ (Token::LeftParen | Token::Unit)) => {
1718                    #[cfg(not(feature = "no_module"))]
1719                    let (_, name, ns, ..) = *x;
1720                    #[cfg(feature = "no_module")]
1721                    let (_, name) = *x;
1722
1723                    let no_args = t == Token::Unit;
1724                    settings.pos = pos;
1725
1726                    self.parse_fn_call(
1727                        state,
1728                        settings,
1729                        name,
1730                        no_args,
1731                        false,
1732                        #[cfg(not(feature = "no_module"))]
1733                        ns,
1734                    )?
1735                }
1736                #[cfg(not(feature = "no_module"))]
1738                (_, token @ Token::DoubleColon)
1739                    if _options.intersects(ChainingFlags::DISALLOW_NAMESPACES) =>
1740                {
1741                    return Err(LexError::ImproperSymbol(
1742                        token.literal_syntax().into(),
1743                        String::new(),
1744                    )
1745                    .into_err(tail_pos))
1746                }
1747                #[cfg(not(feature = "no_module"))]
1749                (Expr::Variable(x, .., pos), Token::DoubleColon) => {
1750                    let (id2, pos2) = parse_var_name(state.input)?;
1751                    let (_, name, mut namespace, ..) = *x;
1752                    let var_name_def = Ident { name, pos };
1753
1754                    namespace.path.push(var_name_def);
1755
1756                    let var_name = self.get_interned_string(id2);
1757
1758                    Expr::Variable((None, var_name, namespace, 0).into(), None, pos2)
1759                }
1760                #[cfg(not(feature = "no_index"))]
1762                (expr, token @ (Token::LeftBracket | Token::QuestionBracket)) => {
1763                    let opt = match token {
1764                        Token::LeftBracket => ASTFlags::empty(),
1765                        Token::QuestionBracket => ASTFlags::NEGATED,
1766                        _ => unreachable!("`[` or `?[`"),
1767                    };
1768                    let settings = settings.level_up()?;
1769                    self.parse_index_chain(state, settings, expr, opt, true)?
1770                }
1771                #[cfg(not(feature = "no_object"))]
1773                (expr, op @ (Token::Period | Token::Elvis)) => {
1774                    match state.input.peek().unwrap() {
1776                        (Token::Identifier(..), ..) => {
1777                            state.allow_capture = false;
1779                        }
1780                        (Token::Reserved(s), ..) if is_reserved_keyword_or_symbol(s).2 => (),
1781                        (Token::Reserved(s), pos) => {
1782                            return Err(PERR::Reserved(s.to_string()).into_err(*pos))
1783                        }
1784                        (.., pos) => return Err(PERR::PropertyExpected.into_err(*pos)),
1785                    }
1786
1787                    let op_flags = match op {
1788                        Token::Period => ASTFlags::empty(),
1789                        Token::Elvis => ASTFlags::NEGATED,
1790                        _ => unreachable!("`.` or `?.`"),
1791                    };
1792                    let options = ChainingFlags::PROPERTY | ChainingFlags::DISALLOW_NAMESPACES;
1793                    let rhs = self.parse_primary(state, settings.level_up()?, options)?;
1794
1795                    self.make_dot_expr(expr, rhs, _parent_options, op_flags, tail_pos)?
1796                }
1797                (expr, token) => {
1799                    unreachable!("unknown postfix operator '{}' for {:?}", token, expr)
1800                }
1801            };
1802
1803            _parent_options = ASTFlags::empty();
1805        }
1806
1807        #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
1809        if matches!(lhs, Expr::Index(ref x, ..) | Expr::Dot(ref x, ..) if matches!(x.lhs, Expr::Index(..) | Expr::Dot(..)))
1810        {
1811            optimize_combo_chain(&mut lhs);
1812        }
1813
1814        #[cfg(not(feature = "no_module"))]
1816        let namespaced_variable = match lhs {
1817            Expr::Variable(ref mut x, ..) if !x.2.is_empty() => Some(&mut **x),
1818            Expr::Index(ref mut x, ..) | Expr::Dot(ref mut x, ..) => match x.lhs {
1819                Expr::Variable(ref mut x, ..) if !x.2.is_empty() => Some(&mut **x),
1820                _ => None,
1821            },
1822            _ => None,
1823        };
1824
1825        #[cfg(not(feature = "no_module"))]
1826        if let Some((.., name, namespace, hash)) = namespaced_variable {
1827            if !namespace.is_empty() {
1828                *hash = crate::calc_var_hash(namespace.path.iter().map(Ident::as_str), name);
1829
1830                #[cfg(not(feature = "no_module"))]
1831                {
1832                    let root = namespace.root();
1833                    let index = state.find_module(root);
1834                    let is_global = false;
1835
1836                    #[cfg(not(feature = "no_function"))]
1837                    #[cfg(not(feature = "no_module"))]
1838                    let is_global = is_global || root == crate::engine::KEYWORD_GLOBAL;
1839
1840                    if settings.has_option(LangOptions::STRICT_VAR)
1841                        && index.is_none()
1842                        && !is_global
1843                        && !state.global_imports.iter().any(|m| m == root)
1844                        && !self.global_sub_modules.contains_key(root)
1845                    {
1846                        return Err(
1847                            PERR::ModuleUndefined(root.into()).into_err(namespace.position())
1848                        );
1849                    }
1850
1851                    namespace.index = index;
1852                }
1853            }
1854        }
1855
1856        Ok(lhs)
1858    }
1859
1860    fn parse_unary(
1862        &self,
1863        state: &mut ParseState,
1864        mut settings: ParseSettings,
1865    ) -> ParseResult<Expr> {
1866        let (token, token_pos) = state.input.peek().unwrap();
1867
1868        if !(state.expr_filter)(token) {
1869            return Err(LexError::UnexpectedInput(token.to_string()).into_err(*token_pos));
1870        }
1871
1872        settings.pos = *token_pos;
1873
1874        match token {
1875            Token::Minus | Token::UnaryMinus => {
1877                let token = token.clone();
1878                let pos = eat_token(state.input, &token);
1879
1880                match self.parse_unary(state, settings.level_up()?)? {
1881                    Expr::IntegerConstant(num, ..) => num
1883                        .checked_neg()
1884                        .map(|i| Expr::IntegerConstant(i, pos))
1885                        .or_else(|| {
1886                            #[cfg(not(feature = "no_float"))]
1887                            return Some(Expr::FloatConstant((-(num as crate::FLOAT)).into(), pos));
1888                            #[cfg(feature = "no_float")]
1889                            return None;
1890                        })
1891                        .ok_or_else(|| LexError::MalformedNumber(format!("-{num}")).into_err(pos)),
1892
1893                    #[cfg(not(feature = "no_float"))]
1895                    Expr::FloatConstant(x, ..) => Ok(Expr::FloatConstant((-(*x)).into(), pos)),
1896
1897                    expr => Ok(FnCallExpr {
1899                        #[cfg(not(feature = "no_module"))]
1900                        namespace: crate::ast::Namespace::NONE,
1901                        name: self.get_interned_string("-"),
1902                        hashes: FnCallHashes::from_native_only(calc_fn_hash(None, "-", 1)),
1903                        args: IntoIterator::into_iter([expr]).collect(),
1904                        op_token: Some(token),
1905                        capture_parent_scope: false,
1906                    }
1907                    .into_fn_call_expr(pos)),
1908                }
1909            }
1910            Token::Plus | Token::UnaryPlus => {
1912                let token = token.clone();
1913                let pos = eat_token(state.input, &token);
1914
1915                match self.parse_unary(state, settings.level_up()?)? {
1916                    expr @ Expr::IntegerConstant(..) => Ok(expr),
1917                    #[cfg(not(feature = "no_float"))]
1918                    expr @ Expr::FloatConstant(..) => Ok(expr),
1919
1920                    expr => Ok(FnCallExpr {
1922                        #[cfg(not(feature = "no_module"))]
1923                        namespace: crate::ast::Namespace::NONE,
1924                        name: self.get_interned_string("+"),
1925                        hashes: FnCallHashes::from_native_only(calc_fn_hash(None, "+", 1)),
1926                        args: IntoIterator::into_iter([expr]).collect(),
1927                        op_token: Some(token),
1928                        capture_parent_scope: false,
1929                    }
1930                    .into_fn_call_expr(pos)),
1931                }
1932            }
1933            Token::Bang => {
1935                let token = token.clone();
1936                let pos = eat_token(state.input, &Token::Bang);
1937
1938                Ok(FnCallExpr {
1939                    #[cfg(not(feature = "no_module"))]
1940                    namespace: crate::ast::Namespace::NONE,
1941                    name: self.get_interned_string("!"),
1942                    hashes: FnCallHashes::from_native_only(calc_fn_hash(None, "!", 1)),
1943                    args: {
1944                        let expr = self.parse_unary(state, settings.level_up()?)?;
1945                        IntoIterator::into_iter([expr]).collect()
1946                    },
1947                    op_token: Some(token),
1948                    capture_parent_scope: false,
1949                }
1950                .into_fn_call_expr(pos))
1951            }
1952            Token::EOF => Err(PERR::UnexpectedEOF.into_err(settings.pos)),
1954            _ => self.parse_primary(state, settings, ChainingFlags::empty()),
1956        }
1957    }
1958
1959    fn make_assignment_stmt(
1961        op: Option<Token>,
1962        state: &mut ParseState,
1963        lhs: Expr,
1964        rhs: Expr,
1965        op_pos: Position,
1966    ) -> ParseResult<Stmt> {
1967        #[must_use]
1968        fn check_lvalue(expr: &Expr, parent_is_dot: bool) -> Option<Position> {
1969            match expr {
1970                Expr::Index(x, options, ..) | Expr::Dot(x, options, ..) if parent_is_dot => {
1971                    match x.lhs {
1972                        Expr::Property(..) if !options.intersects(ASTFlags::BREAK) => {
1973                            check_lvalue(&x.rhs, matches!(expr, Expr::Dot(..)))
1974                        }
1975                        Expr::Property(..) => None,
1976                        ref e => Some(e.position()),
1978                    }
1979                }
1980                Expr::Index(x, options, ..) | Expr::Dot(x, options, ..) => match x.lhs {
1981                    Expr::Property(..) => unreachable!("unexpected Expr::Property in indexing"),
1982                    _ if !options.intersects(ASTFlags::BREAK) => {
1983                        check_lvalue(&x.rhs, matches!(expr, Expr::Dot(..)))
1984                    }
1985                    _ => None,
1986                },
1987                Expr::Property(..) if parent_is_dot => None,
1988                Expr::Property(..) => unreachable!("unexpected Expr::Property in indexing"),
1989                e if parent_is_dot => Some(e.position()),
1990                _ => None,
1991            }
1992        }
1993
1994        let op_info = op.map_or_else(
1995            || OpAssignment::new_assignment(op_pos),
1996            |op| OpAssignment::new_op_assignment_from_token(op, op_pos),
1997        );
1998
1999        match lhs {
2000            Expr::ThisPtr(_) => Ok(Stmt::Assignment((op_info, BinaryExpr { lhs, rhs }).into())),
2002            Expr::Variable(ref x, None, _) if x.0.is_none() => {
2004                Ok(Stmt::Assignment((op_info, BinaryExpr { lhs, rhs }).into()))
2005            }
2006            Expr::Variable(ref x, i, var_pos) => {
2008                let (index, name, ..) = &**x;
2009                let index = i.map_or_else(
2010                    || index.expect("long or short index must be `Some`").get(),
2011                    |n| n.get() as usize,
2012                );
2013
2014                match state
2015                    .stack
2016                    .get_mut_by_index(state.stack.len() - index)
2017                    .access_mode()
2018                {
2019                    AccessMode::ReadWrite => {
2020                        Ok(Stmt::Assignment((op_info, BinaryExpr { lhs, rhs }).into()))
2021                    }
2022                    AccessMode::ReadOnly => {
2024                        Err(PERR::AssignmentToConstant(name.to_string()).into_err(var_pos))
2025                    }
2026                }
2027            }
2028            Expr::Index(ref x, options, ..) | Expr::Dot(ref x, options, ..) => {
2030                let valid_lvalue = if options.intersects(ASTFlags::BREAK) {
2031                    None
2032                } else {
2033                    check_lvalue(&x.rhs, matches!(lhs, Expr::Dot(..)))
2034                };
2035
2036                if let Some(err_pos) = valid_lvalue {
2037                    Err(PERR::AssignmentToInvalidLHS(String::new()).into_err(err_pos))
2038                } else {
2039                    match x.lhs {
2040                        Expr::Variable(..) | Expr::ThisPtr(..) => {
2042                            Ok(Stmt::Assignment((op_info, BinaryExpr { lhs, rhs }).into()))
2043                        }
2044                        ref expr => {
2046                            Err(PERR::AssignmentToInvalidLHS(String::new())
2047                                .into_err(expr.position()))
2048                        }
2049                    }
2050                }
2051            }
2052            ref expr if expr.is_constant() => {
2054                Err(PERR::AssignmentToConstant(String::new()).into_err(lhs.start_position()))
2055            }
2056            Expr::And(..) | Expr::Or(..) | Expr::Coalesce(..) if !op_info.is_op_assignment() => {
2058                Err(LexError::ImproperSymbol(
2059                    Token::Equals.literal_syntax().into(),
2060                    "Possibly a typo of '=='?".into(),
2061                )
2062                .into_err(op_pos))
2063            }
2064            _ => Err(PERR::AssignmentToInvalidLHS(String::new()).into_err(lhs.position())),
2066        }
2067    }
2068
2069    #[cfg(not(feature = "no_object"))]
2071    fn make_dot_expr(
2072        &self,
2073        lhs: Expr,
2074        rhs: Expr,
2075        parent_options: ASTFlags,
2076        op_flags: ASTFlags,
2077        op_pos: Position,
2078    ) -> ParseResult<Expr> {
2079        match (lhs, rhs) {
2080            (Expr::Index(mut x, options, pos), rhs)
2082                if !parent_options.intersects(ASTFlags::BREAK) =>
2083            {
2084                let options = options | parent_options;
2085                x.rhs = self.make_dot_expr(x.rhs, rhs, options, op_flags, op_pos)?;
2086                Ok(Expr::Index(x, ASTFlags::empty(), pos))
2087            }
2088            #[cfg(not(feature = "no_module"))]
2090            (.., Expr::Variable(x, ..)) if !x.2.is_empty() => unreachable!("lhs.ns::id"),
2091            (lhs, var_expr @ Expr::Variable(..)) => {
2093                let rhs = self.convert_expr_into_property(var_expr);
2094                Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), op_flags, op_pos))
2095            }
2096            (lhs, prop @ Expr::Property(..)) => Ok(Expr::Dot(
2098                BinaryExpr { lhs, rhs: prop }.into(),
2099                op_flags,
2100                op_pos,
2101            )),
2102            #[cfg(not(feature = "no_module"))]
2104            (.., Expr::FnCall(f, ..)) if f.is_qualified() => unreachable!("lhs.ns::func()"),
2105            (.., Expr::FnCall(f, func_pos))
2107                if f.args.is_empty()
2108                    && matches!(
2109                        &*f.name,
2110                        crate::engine::KEYWORD_FN_PTR | crate::engine::KEYWORD_EVAL
2111                    ) =>
2112            {
2113                let err_msg = format!(
2114                    "'{}' should not be called in method style. Try {}(...);",
2115                    f.name, f.name
2116                );
2117                Err(LexError::ImproperSymbol(f.name.to_string(), err_msg).into_err(func_pos))
2118            }
2119            (.., Expr::FnCall(f, func_pos)) if f.capture_parent_scope => {
2121                Err(PERR::MalformedCapture(
2122                    "method-call style does not support running within the caller's scope".into(),
2123                )
2124                .into_err(func_pos))
2125            }
2126            (lhs, Expr::FnCall(mut f, func_pos)) => {
2128                let args_len = f.args.len() + 1;
2130                f.hashes = if is_valid_function_name(&f.name) {
2131                    #[cfg(not(feature = "no_function"))]
2132                    {
2133                        FnCallHashes::from_script_and_native(
2134                            calc_fn_hash(None, &f.name, args_len - 1),
2135                            calc_fn_hash(None, &f.name, args_len),
2136                        )
2137                    }
2138                    #[cfg(feature = "no_function")]
2139                    {
2140                        FnCallHashes::from_native_only(calc_fn_hash(None, &f.name, args_len))
2141                    }
2142                } else {
2143                    FnCallHashes::from_native_only(calc_fn_hash(None, &f.name, args_len))
2144                };
2145
2146                let rhs = Expr::MethodCall(f, func_pos);
2147                Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), op_flags, op_pos))
2148            }
2149            (lhs, rhs @ (Expr::Dot(..) | Expr::Index(..))) => {
2151                let (x, options, pos, is_dot) = match rhs {
2152                    Expr::Dot(x, options, pos) => (x, options, pos, true),
2153                    Expr::Index(x, options, pos) => (x, options, pos, false),
2154                    expr => unreachable!("Expr::Dot or Expr::Index expected but gets {:?}", expr),
2155                };
2156
2157                match x.lhs {
2158                    #[cfg(not(feature = "no_module"))]
2160                    Expr::Variable(x, ..) if !x.2.is_empty() => unreachable!("lhs.ns::id..."),
2161                    #[cfg(not(feature = "no_module"))]
2163                    Expr::FnCall(f, ..) if f.is_qualified() => {
2164                        unreachable!("lhs.ns::func()...")
2165                    }
2166                    Expr::Variable(..) | Expr::Property(..) => {
2168                        let new_binary = BinaryExpr {
2169                            lhs: self.convert_expr_into_property(x.lhs),
2170                            rhs: x.rhs,
2171                        }
2172                        .into();
2173
2174                        let rhs = if is_dot {
2175                            Expr::Dot(new_binary, options, pos)
2176                        } else {
2177                            Expr::Index(new_binary, options, pos)
2178                        };
2179                        Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), op_flags, op_pos))
2180                    }
2181                    Expr::FnCall(mut f, func_pos) => {
2183                        let args_len = f.args.len() + 1;
2185                        f.hashes = if is_valid_function_name(&f.name) {
2186                            #[cfg(not(feature = "no_function"))]
2187                            {
2188                                FnCallHashes::from_script_and_native(
2189                                    calc_fn_hash(None, &f.name, args_len - 1),
2190                                    calc_fn_hash(None, &f.name, args_len),
2191                                )
2192                            }
2193                            #[cfg(feature = "no_function")]
2194                            {
2195                                FnCallHashes::from_native_only(calc_fn_hash(
2196                                    None, &f.name, args_len,
2197                                ))
2198                            }
2199                        } else {
2200                            FnCallHashes::from_native_only(calc_fn_hash(None, &f.name, args_len))
2201                        };
2202
2203                        let new_lhs = BinaryExpr {
2204                            lhs: Expr::MethodCall(f, func_pos),
2205                            rhs: x.rhs,
2206                        }
2207                        .into();
2208
2209                        let rhs = if is_dot {
2210                            Expr::Dot(new_lhs, options, pos)
2211                        } else {
2212                            Expr::Index(new_lhs, options, pos)
2213                        };
2214                        Ok(Expr::Dot(BinaryExpr { lhs, rhs }.into(), op_flags, op_pos))
2215                    }
2216                    expr => unreachable!("invalid dot expression: {:?}", expr),
2217                }
2218            }
2219            (.., rhs) => Err(PERR::PropertyExpected.into_err(rhs.start_position())),
2221        }
2222    }
2223
2224    fn parse_binary_op(
2226        &self,
2227        state: &mut ParseState,
2228        mut settings: ParseSettings,
2229        parent_precedence: Option<Precedence>,
2230        lhs: Expr,
2231    ) -> ParseResult<Expr> {
2232        settings.pos = lhs.position();
2233
2234        let mut root = lhs;
2235
2236        loop {
2237            let (current_op, current_pos) = state.input.peek().unwrap();
2238
2239            if !(state.expr_filter)(current_op) {
2240                return Ok(root);
2241            }
2242
2243            let precedence = match current_op {
2244                #[cfg(not(feature = "no_custom_syntax"))]
2245                Token::Custom(c) => self
2246                    .custom_keywords
2247                    .get(&**c)
2248                    .copied()
2249                    .ok_or_else(|| PERR::Reserved(c.to_string()).into_err(*current_pos))?,
2250                Token::Reserved(c) if !is_valid_identifier(c) => {
2251                    return Err(PERR::UnknownOperator(c.to_string()).into_err(*current_pos))
2252                }
2253                _ => current_op.precedence(),
2254            };
2255            let bind_right = current_op.is_bind_right();
2256
2257            if precedence < parent_precedence || (precedence == parent_precedence && !bind_right) {
2260                return Ok(root);
2261            }
2262
2263            let (op_token, pos) = state.input.next().unwrap();
2264
2265            let rhs = match op_token {
2267                Token::DoubleQuestion
2268                    if matches!(
2269                        state.input.peek().unwrap().0,
2270                        Token::Break | Token::Continue | Token::Return | Token::Throw
2271                    ) =>
2272                {
2273                    let stmt = self.parse_stmt(state, settings)?;
2274                    let block: StmtBlock = stmt.into();
2275                    Expr::Stmt(block.into())
2276                }
2277                Token::ExclusiveRange | Token::InclusiveRange
2280                    if matches!(
2281                        state.input.peek().unwrap().0,
2282                        Token::RightBracket
2283                            | Token::RightParen
2284                            | Token::RightBrace
2285                            | Token::Comma
2286                            | Token::SemiColon
2287                            | Token::DoubleArrow
2288                    ) =>
2289                {
2290                    let (_, next_pos) = state.input.peek().unwrap();
2291                    Expr::Unit(*next_pos)
2292                }
2293                _ => self.parse_unary(state, settings)?,
2294            };
2295
2296            let (next_op, next_pos) = state.input.peek().unwrap();
2297            let next_precedence = match next_op {
2298                #[cfg(not(feature = "no_custom_syntax"))]
2299                Token::Custom(c) => self
2300                    .custom_keywords
2301                    .get(&**c)
2302                    .copied()
2303                    .ok_or_else(|| PERR::Reserved(c.to_string()).into_err(*next_pos))?,
2304                Token::Reserved(c) if !is_valid_identifier(c) => {
2305                    return Err(PERR::UnknownOperator(c.to_string()).into_err(*next_pos))
2306                }
2307                _ => next_op.precedence(),
2308            };
2309
2310            let rhs =
2313                if (precedence == next_precedence && bind_right) || precedence < next_precedence {
2314                    self.parse_binary_op(state, settings.level_up()?, precedence, rhs)?
2315                } else {
2316                    rhs
2318                };
2319
2320            settings = settings.level_up()?;
2321            settings.pos = pos;
2322
2323            let op: SmartString = (&op_token).into();
2324            let hash = calc_fn_hash(None, &op, 2);
2325            let native_only = !is_valid_function_name(&op);
2326
2327            let mut op_base = FnCallExpr {
2328                #[cfg(not(feature = "no_module"))]
2329                namespace: crate::ast::Namespace::NONE,
2330                name: self.get_interned_string(&op),
2331                hashes: FnCallHashes::from_native_only(hash),
2332                args: IntoIterator::into_iter([root, rhs]).collect(),
2333                op_token: native_only.then(|| op_token.clone()),
2334                capture_parent_scope: false,
2335            };
2336
2337            root = match op_token {
2338                Token::And => {
2339                    let mut lhs = op_base.args[0].take().ensure_bool_expr()?;
2340                    let mut rhs = op_base.args[1].take().ensure_bool_expr()?;
2341
2342                    if let Expr::And(ref mut x, ..) = lhs {
2343                        if let Expr::And(x2, ..) = rhs {
2344                            x.extend(*x2);
2345                        } else {
2346                            x.push(rhs);
2347                        }
2348                        lhs
2349                    } else if let Expr::And(ref mut x, ..) = rhs {
2350                        x.insert(0, lhs);
2351                        rhs.set_position(pos);
2352                        rhs
2353                    } else {
2354                        Expr::And(Box::new(vec![lhs, rhs].into()), pos)
2355                    }
2356                }
2357                Token::Or => {
2358                    let mut lhs = op_base.args[0].take().ensure_bool_expr()?;
2359                    let mut rhs = op_base.args[1].take().ensure_bool_expr()?;
2360
2361                    if let Expr::Or(ref mut x, ..) = lhs {
2362                        if let Expr::Or(x2, ..) = rhs {
2363                            x.extend(*x2);
2364                        } else {
2365                            x.push(rhs);
2366                        }
2367                        lhs
2368                    } else if let Expr::Or(ref mut x, ..) = rhs {
2369                        x.insert(0, lhs);
2370                        rhs.set_position(pos);
2371                        rhs
2372                    } else {
2373                        Expr::Or(Box::new(vec![lhs, rhs].into()), pos)
2374                    }
2375                }
2376                Token::DoubleQuestion => {
2377                    let mut lhs = op_base.args[0].take();
2378                    let mut rhs = op_base.args[1].take();
2379
2380                    if let Expr::Coalesce(ref mut x, ..) = lhs {
2381                        if let Expr::Coalesce(x2, ..) = rhs {
2382                            x.extend(*x2);
2383                        } else {
2384                            x.push(rhs);
2385                        }
2386                        lhs
2387                    } else if let Expr::Coalesce(ref mut x, ..) = rhs {
2388                        x.insert(0, lhs);
2389                        rhs.set_position(pos);
2390                        rhs
2391                    } else {
2392                        Expr::Coalesce(Box::new(vec![lhs, rhs].into()), pos)
2393                    }
2394                }
2395                Token::In | Token::NotIn => {
2396                    let (lhs, rhs) = op_base.args.split_first_mut().unwrap();
2398                    std::mem::swap(lhs, &mut rhs[0]);
2399
2400                    op_base.hashes = FnCallHashes::from_hash(calc_fn_hash(None, OP_CONTAINS, 2));
2402                    op_base.name = self.get_interned_string(OP_CONTAINS);
2403                    let fn_call = op_base.into_fn_call_expr(pos);
2404
2405                    if op_token == Token::In {
2406                        fn_call
2407                    } else {
2408                        let not_base = FnCallExpr {
2410                            #[cfg(not(feature = "no_module"))]
2411                            namespace: crate::ast::Namespace::NONE,
2412                            name: self.get_interned_string(OP_NOT),
2413                            hashes: FnCallHashes::from_native_only(calc_fn_hash(None, OP_NOT, 1)),
2414                            args: IntoIterator::into_iter([fn_call]).collect(),
2415                            op_token: Some(Token::Bang),
2416                            capture_parent_scope: false,
2417                        };
2418                        not_base.into_fn_call_expr(pos)
2419                    }
2420                }
2421                Token::ExclusiveRange | Token::InclusiveRange => op_base.into_fn_call_expr(pos),
2422
2423                #[cfg(not(feature = "no_custom_syntax"))]
2424                Token::Custom(s) if self.custom_keywords.contains_key(&*s) => {
2425                    op_base.hashes = if native_only {
2426                        FnCallHashes::from_native_only(calc_fn_hash(None, &s, 2))
2427                    } else {
2428                        FnCallHashes::from_hash(calc_fn_hash(None, &s, 2))
2429                    };
2430                    op_base.into_fn_call_expr(pos)
2431                }
2432
2433                _ => op_base.into_fn_call_expr(pos),
2434            };
2435        }
2436    }
2437
2438    #[cfg(not(feature = "no_custom_syntax"))]
2440    fn parse_custom_syntax(
2441        &self,
2442        state: &mut ParseState,
2443        settings: ParseSettings,
2444        key: impl Into<ImmutableString>,
2445        syntax: &crate::api::custom_syntax::CustomSyntax,
2446    ) -> ParseResult<Expr> {
2447        #[allow(clippy::wildcard_imports)]
2448        use crate::api::custom_syntax::markers::*;
2449
2450        const KEYWORD_SEMICOLON: &str = Token::SemiColon.literal_syntax();
2451        const KEYWORD_CLOSE_BRACE: &str = Token::RightBrace.literal_syntax();
2452
2453        let key_pos = settings.pos;
2454
2455        let mut inputs = FnArgsVec::new();
2456        let mut segments = FnArgsVec::new();
2457        let mut tokens = FnArgsVec::new();
2458
2459        if syntax.scope_may_be_changed {
2461            state.stack.push_constant_dynamic(
2464                self.get_interned_string(SCOPE_SEARCH_BARRIER_MARKER),
2465                Dynamic::UNIT,
2466            );
2467        }
2468
2469        let mut user_state = Dynamic::UNIT;
2470        let parse_func = &*syntax.parse;
2471        let mut required_token: ImmutableString = key.into();
2472
2473        tokens.push(required_token.clone());
2474        segments.push(required_token.clone());
2475
2476        loop {
2477            let (fwd_token, fwd_pos) = if syntax.use_look_ahead {
2478                let (token, pos) = state.input.peek().unwrap();
2479                (token.into(), *pos)
2480            } else {
2481                (SmartString::new_const(), settings.pos)
2482            };
2483
2484            let settings = settings.level_up()?;
2485
2486            required_token = match parse_func(&segments, &fwd_token, &mut user_state) {
2487                Ok(Some(seg))
2488                    if seg.starts_with(CUSTOM_SYNTAX_MARKER_SYNTAX_VARIANT)
2489                        && seg.len() > CUSTOM_SYNTAX_MARKER_SYNTAX_VARIANT.len() =>
2490                {
2491                    inputs.push(Expr::StringConstant(self.get_interned_string(seg), key_pos));
2492                    break;
2493                }
2494                Ok(Some(seg)) if syntax.use_look_ahead && seg == CUSTOM_SYNTAX_MARKER_RAW => {
2495                    self.get_interned_string(CUSTOM_SYNTAX_MARKER_TOKEN)
2497                }
2498                Ok(Some(seg)) => seg,
2499                Ok(None) => break,
2500                Err(err) => return Err(err.0.into_err(fwd_pos)),
2501            };
2502
2503            match required_token.as_str() {
2504                CUSTOM_SYNTAX_MARKER_RAW => {
2505                    {
2506                        state.tokenizer_control.borrow_mut().in_char_mode = true;
2507                    }
2508
2509                    match state.input.next().unwrap() {
2510                        (Token::EOF, _) => break,
2511                        (Token::UnprocessedRawChar(ch), _) => {
2512                            segments.push(ch.to_string().into());
2513
2514                            if tokens.last().unwrap() != CUSTOM_SYNTAX_MARKER_RAW {
2515                                tokens.push(self.get_interned_string(CUSTOM_SYNTAX_MARKER_RAW));
2516                            }
2517                        }
2518                        _ => unreachable!(),
2519                    }
2520                }
2521                CUSTOM_SYNTAX_MARKER_IDENT => {
2522                    let (name, pos) = parse_var_name(state.input)?;
2523                    let name = self.get_interned_string(name);
2524
2525                    segments.push(name.clone());
2526                    tokens.push(self.get_interned_string(CUSTOM_SYNTAX_MARKER_IDENT));
2527
2528                    inputs.push(Expr::Variable(
2529                        #[cfg(not(feature = "no_module"))]
2530                        (None, name, crate::ast::Namespace::NONE, 0).into(),
2531                        #[cfg(feature = "no_module")]
2532                        (None, name).into(),
2533                        None,
2534                        pos,
2535                    ));
2536                }
2537                CUSTOM_SYNTAX_MARKER_SYMBOL => {
2538                    let (symbol, pos) = match state.input.next().unwrap() {
2539                        (token, pos) if token.is_standard_symbol() => {
2541                            Ok((token.literal_syntax().into(), pos))
2542                        }
2543                        (Token::Reserved(s), pos) if !is_valid_identifier(s.as_str()) => {
2545                            Ok((*s, pos))
2546                        }
2547                        (Token::LexError(err), pos) => Err(err.into_err(pos)),
2549                        (.., pos) => Err(PERR::MissingSymbol(String::new()).into_err(pos)),
2551                    }?;
2552                    let symbol = self.get_interned_string(symbol);
2553                    segments.push(symbol.clone());
2554                    tokens.push(self.get_interned_string(CUSTOM_SYNTAX_MARKER_SYMBOL));
2555                    inputs.push(Expr::StringConstant(symbol, pos));
2556                }
2557                CUSTOM_SYNTAX_MARKER_TOKEN => {
2558                    let (token, pos): (SmartString, _) = match state.input.next().unwrap() {
2559                        (Token::LexError(err), pos) => Err(err.into_err(pos)),
2561                        (token, pos) => Ok((token.into(), pos)),
2563                    }?;
2564                    let token = self.get_interned_string(token);
2565                    segments.push(token.clone());
2566                    tokens.push(self.get_interned_string(CUSTOM_SYNTAX_MARKER_TOKEN));
2567                    inputs.push(Expr::StringConstant(token, pos));
2568                }
2569                CUSTOM_SYNTAX_MARKER_EXPR => {
2570                    inputs.push(self.parse_expr(state, settings)?);
2571                    let keyword = self.get_interned_string(CUSTOM_SYNTAX_MARKER_EXPR);
2572                    segments.push(keyword.clone());
2573                    tokens.push(keyword);
2574                }
2575                CUSTOM_SYNTAX_MARKER_BLOCK => match self.parse_block(state, settings, false)? {
2576                    block @ Stmt::Block(..) => {
2577                        inputs.push(Expr::Stmt(Box::new(block.into())));
2578                        let keyword = self.get_interned_string(CUSTOM_SYNTAX_MARKER_BLOCK);
2579                        segments.push(keyword.clone());
2580                        tokens.push(keyword);
2581                    }
2582                    stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt),
2583                },
2584                CUSTOM_SYNTAX_MARKER_INNER => match self.parse_block(state, settings, true)? {
2585                    block @ Stmt::Block(..) => {
2586                        inputs.push(Expr::Stmt(Box::new(block.into())));
2587                        let keyword = self.get_interned_string(CUSTOM_SYNTAX_MARKER_INNER);
2588                        segments.push(keyword.clone());
2589                        tokens.push(keyword);
2590                    }
2591                    stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt),
2592                },
2593                #[cfg(not(feature = "no_function"))]
2594                CUSTOM_SYNTAX_MARKER_FUNC => {
2595                    let skip = match state.input.peek().unwrap() {
2596                        (Token::Or | Token::Pipe, _) => false,
2597                        (Token::LeftBrace, _) => true,
2598                        (_, pos) => {
2599                            return Err(
2600                                PERR::MissingSymbol("Expecting '{' or '|'".into()).into_err(*pos)
2601                            )
2602                        }
2603                    };
2604                    inputs.push(self.parse_anon_fn(state, settings, skip)?);
2605                    let keyword = self.get_interned_string(CUSTOM_SYNTAX_MARKER_FUNC);
2606                    segments.push(keyword.clone());
2607                    tokens.push(keyword);
2608                }
2609                CUSTOM_SYNTAX_MARKER_BOOL => match state.input.next().unwrap() {
2610                    (b @ (Token::True | Token::False), pos) => {
2611                        inputs.push(Expr::BoolConstant(b == Token::True, pos));
2612                        segments.push(self.get_interned_string(b.literal_syntax()));
2613                        tokens.push(self.get_interned_string(CUSTOM_SYNTAX_MARKER_BOOL));
2614                    }
2615                    (.., pos) => {
2616                        return Err(
2617                            PERR::MissingSymbol("Expecting 'true' or 'false'".into()).into_err(pos)
2618                        )
2619                    }
2620                },
2621                CUSTOM_SYNTAX_MARKER_INT => match state.input.next().unwrap() {
2622                    (Token::IntegerConstant(i), pos) => {
2623                        inputs.push(Expr::IntegerConstant(i, pos));
2624                        segments.push(i.to_string().into());
2625                        tokens.push(self.get_interned_string(CUSTOM_SYNTAX_MARKER_INT));
2626                    }
2627                    (.., pos) => {
2628                        return Err(
2629                            PERR::MissingSymbol("Expecting an integer number".into()).into_err(pos)
2630                        )
2631                    }
2632                },
2633                #[cfg(not(feature = "no_float"))]
2634                CUSTOM_SYNTAX_MARKER_FLOAT => match state.input.next().unwrap() {
2635                    (Token::FloatConstant(f), pos) => {
2636                        inputs.push(Expr::FloatConstant(f.0, pos));
2637                        segments.push(f.1.into());
2638                        tokens.push(self.get_interned_string(CUSTOM_SYNTAX_MARKER_FLOAT));
2639                    }
2640                    (.., pos) => {
2641                        return Err(
2642                            PERR::MissingSymbol("Expecting a floating-point number".into())
2643                                .into_err(pos),
2644                        )
2645                    }
2646                },
2647                CUSTOM_SYNTAX_MARKER_STRING => match state.input.next().unwrap() {
2648                    (Token::StringConstant(s), pos) => {
2649                        let s = self.get_interned_string(*s);
2650                        inputs.push(Expr::StringConstant(s.clone(), pos));
2651                        segments.push(s);
2652                        tokens.push(self.get_interned_string(CUSTOM_SYNTAX_MARKER_STRING));
2653                    }
2654                    (.., pos) => {
2655                        return Err(PERR::MissingSymbol("Expecting a string".into()).into_err(pos))
2656                    }
2657                },
2658                s => match state.input.next().unwrap() {
2659                    (Token::LexError(err), pos) => return Err(err.into_err(pos)),
2660                    (Token::Identifier(t) | Token::Reserved(t) | Token::Custom(t), ..)
2661                        if *t == s =>
2662                    {
2663                        segments.push(required_token.clone());
2664                        tokens.push(required_token.clone());
2665                    }
2666                    (t, ..) if t.is_literal() && t.literal_syntax() == s => {
2667                        segments.push(required_token.clone());
2668                        tokens.push(required_token.clone());
2669                    }
2670                    (.., pos) => {
2671                        return Err(PERR::MissingToken(
2672                            s.into(),
2673                            format!("for '{}' expression", segments[0]),
2674                        )
2675                        .into_err(pos))
2676                    }
2677                },
2678            }
2679        }
2680
2681        inputs.shrink_to_fit();
2682        tokens.shrink_to_fit();
2683
2684        let self_terminated = matches!(
2685            &*required_token,
2686            CUSTOM_SYNTAX_MARKER_BLOCK |
2688            KEYWORD_SEMICOLON | KEYWORD_CLOSE_BRACE
2690        );
2691        #[cfg(not(feature = "no_function"))]
2693        let self_terminated = required_token == CUSTOM_SYNTAX_MARKER_FUNC || self_terminated;
2694
2695        Ok(Expr::Custom(
2696            crate::ast::CustomExpr {
2697                inputs,
2698                tokens,
2699                state: user_state,
2700                scope_may_be_changed: syntax.scope_may_be_changed,
2701                self_terminated,
2702            }
2703            .into(),
2704            key_pos,
2705        ))
2706    }
2707
2708    fn parse_expr(&self, state: &mut ParseState, mut settings: ParseSettings) -> ParseResult<Expr> {
2710        settings.pos = state.input.peek().unwrap().1;
2711
2712        let precedence = Precedence::new(1);
2714        let settings = settings.level_up()?;
2715        let lhs = self.parse_unary(state, settings)?;
2716        self.parse_binary_op(state, settings, precedence, lhs)
2717    }
2718
2719    fn parse_if(&self, state: &mut ParseState, settings: ParseSettings) -> ParseResult<Stmt> {
2721        let settings = settings.level_up_with_position(eat_token(state.input, &Token::If))?;
2723
2724        ensure_not_statement_expr(state.input, "a boolean")?;
2726        let expr = self.parse_expr(state, settings)?.ensure_bool_expr()?;
2727        ensure_not_assignment(state.input)?;
2728        let body = self.parse_block(state, settings, false)?.into();
2729
2730        let branch = if match_token(state.input, &Token::Else).0 {
2732            match state.input.peek().unwrap() {
2733                (Token::If, ..) => self.parse_if(state, settings)?,
2735                _ => self.parse_block(state, settings, false)?,
2737            }
2738        } else {
2739            Stmt::Noop(Position::NONE)
2740        }
2741        .into();
2742
2743        Ok(Stmt::If(
2744            FlowControl { expr, body, branch }.into(),
2745            settings.pos,
2746        ))
2747    }
2748
2749    fn parse_while_loop(
2751        &self,
2752        state: &mut ParseState,
2753        settings: ParseSettings,
2754    ) -> ParseResult<Stmt> {
2755        let mut settings = settings.level_up()?;
2756
2757        let (expr, token_pos) = match state.input.next().unwrap() {
2759            (Token::While, pos) => {
2760                ensure_not_statement_expr(state.input, "a boolean")?;
2761                let expr = self.parse_expr(state, settings)?.ensure_bool_expr()?;
2762                ensure_not_assignment(state.input)?;
2763                (expr, pos)
2764            }
2765            (Token::Loop, pos) => (Expr::Unit(Position::NONE), pos),
2766            token => unreachable!("Token::While or Token::Loop expected but gets {:?}", token),
2767        };
2768        settings.pos = token_pos;
2769        settings.flags |= ParseSettingFlags::BREAKABLE;
2770
2771        let body = self.parse_block(state, settings, false)?.into();
2772        let branch = StmtBlock::NONE;
2773
2774        Ok(Stmt::While(
2775            FlowControl { expr, body, branch }.into(),
2776            settings.pos,
2777        ))
2778    }
2779
2780    fn parse_do(&self, state: &mut ParseState, settings: ParseSettings) -> ParseResult<Stmt> {
2782        let mut settings = settings.level_up_with_position(eat_token(state.input, &Token::Do))?;
2784        let orig_breakable = settings.has_flag(ParseSettingFlags::BREAKABLE);
2785        settings.flags |= ParseSettingFlags::BREAKABLE;
2786
2787        let body = self.parse_block(state, settings, false)?.into();
2790
2791        let negated = match state.input.next().unwrap() {
2792            (Token::While, ..) => ASTFlags::empty(),
2793            (Token::Until, ..) => ASTFlags::NEGATED,
2794            (.., pos) => {
2795                return Err(
2796                    PERR::MissingToken(Token::While.into(), "for the do statement".into())
2797                        .into_err(pos),
2798                )
2799            }
2800        };
2801
2802        if !orig_breakable {
2803            settings.flags.remove(ParseSettingFlags::BREAKABLE);
2804        }
2805
2806        ensure_not_statement_expr(state.input, "a boolean")?;
2807        let expr = self.parse_expr(state, settings)?.ensure_bool_expr()?;
2808        ensure_not_assignment(state.input)?;
2809
2810        let branch = StmtBlock::NONE;
2811
2812        Ok(Stmt::Do(
2813            FlowControl { expr, body, branch }.into(),
2814            negated,
2815            settings.pos,
2816        ))
2817    }
2818
2819    fn parse_for(&self, state: &mut ParseState, settings: ParseSettings) -> ParseResult<Stmt> {
2821        let mut settings = settings.level_up_with_position(eat_token(state.input, &Token::For))?;
2823
2824        let (name, name_pos, counter_name, counter_pos) =
2826            if match_token(state.input, &Token::LeftParen).0 {
2827                let (name, name_pos) = parse_var_name(state.input)?;
2829                let (has_comma, pos) = match_token(state.input, &Token::Comma);
2830                if !has_comma {
2831                    return Err(PERR::MissingToken(
2832                        Token::Comma.into(),
2833                        "after the iteration variable name".into(),
2834                    )
2835                    .into_err(pos));
2836                }
2837                let (counter_name, counter_pos) = parse_var_name(state.input)?;
2838
2839                if counter_name == name {
2840                    return Err(PERR::DuplicatedVariable(counter_name.into()).into_err(counter_pos));
2841                }
2842
2843                let (has_close_paren, pos) = match_token(state.input, &Token::RightParen);
2844                if !has_close_paren {
2845                    return Err(PERR::MissingToken(
2846                        Token::RightParen.into(),
2847                        "to close the iteration variable".into(),
2848                    )
2849                    .into_err(pos));
2850                }
2851                (name, name_pos, Some(counter_name), counter_pos)
2852            } else {
2853                let (name, name_pos) = parse_var_name(state.input)?;
2855                (name, name_pos, None, Position::NONE)
2856            };
2857
2858        match state.input.next().unwrap() {
2860            (Token::In, ..) => (),
2861            (Token::LexError(err), pos) => return Err(err.into_err(pos)),
2862            (.., pos) => {
2863                return Err(PERR::MissingToken(
2864                    Token::In.into(),
2865                    "after the iteration variable".into(),
2866                )
2867                .into_err(pos))
2868            }
2869        }
2870
2871        ensure_not_statement_expr(state.input, "a boolean")?;
2873        let expr = self.parse_expr(state, settings)?.ensure_iterable()?;
2874
2875        let counter_var = counter_name.map(|counter_name| Ident {
2876            name: self.get_interned_string(counter_name),
2877            pos: counter_pos,
2878        });
2879
2880        let loop_var = Ident {
2881            name: self.get_interned_string(name),
2882            pos: name_pos,
2883        };
2884
2885        let prev_stack_len = {
2886            let prev_stack_len = state.stack.len();
2887
2888            if let Some(ref counter_var) = counter_var {
2889                state.stack.push(counter_var.name.clone(), ());
2890            }
2891            state.stack.push(&loop_var.name, ());
2892
2893            prev_stack_len
2894        };
2895
2896        settings.flags |= ParseSettingFlags::BREAKABLE;
2897        let body = self.parse_block(state, settings, false)?.into();
2898
2899        state.stack.rewind(prev_stack_len);
2900
2901        let branch = StmtBlock::NONE;
2902
2903        Ok(Stmt::For(
2904            Box::new((loop_var, counter_var, FlowControl { expr, body, branch })),
2905            settings.pos,
2906        ))
2907    }
2908
2909    fn parse_let(
2911        &self,
2912        state: &mut ParseState,
2913        mut settings: ParseSettings,
2914        access: AccessMode,
2915        is_export: bool,
2916    ) -> ParseResult<Stmt> {
2917        settings.pos = state.input.next().unwrap().1;
2919
2920        let (name, pos) = parse_var_name(state.input)?;
2922
2923        if !self.allow_shadowing() && state.stack.get(&name).is_some() {
2924            return Err(PERR::VariableExists(name.into()).into_err(pos));
2925        }
2926
2927        if let Some(ref filter) = self.def_var_filter {
2928            let will_shadow = state.stack.get(&name).is_some();
2929
2930            let global = state
2931                .global
2932                .get_or_insert_with(|| self.new_global_runtime_state().into());
2933
2934            global.level = settings.level;
2935            let is_const = access == AccessMode::ReadOnly;
2936            let info = VarDefInfo::new(&name, is_const, settings.level, will_shadow);
2937            let caches = &mut Caches::new();
2938            let context = EvalContext::new(self, global, caches, &mut state.stack, None);
2939
2940            match filter(false, info, context) {
2941                Ok(true) => (),
2942                Ok(false) => return Err(PERR::ForbiddenVariable(name.into()).into_err(pos)),
2943                Err(err) => {
2944                    return Err(match *err {
2945                        EvalAltResult::ErrorParsing(e, pos) => e.into_err(pos),
2946                        _ => PERR::ForbiddenVariable(name.into()).into_err(pos),
2947                    })
2948                }
2949            }
2950        }
2951
2952        let name = self.get_interned_string(name);
2953
2954        let expr = if match_token(state.input, &Token::Equals).0 {
2956            self.parse_expr(state, settings.level_up()?)?
2958        } else {
2959            Expr::Unit(Position::NONE)
2960        };
2961
2962        let export = if is_export {
2963            ASTFlags::EXPORTED
2964        } else {
2965            ASTFlags::empty()
2966        };
2967
2968        let (existing, hit_barrier) = state.find_var(&name);
2969
2970        let existing = if !hit_barrier && existing > 0 {
2971            match state.stack.len() - existing {
2972                #[cfg(not(feature = "no_module"))]
2974                offset if !state.stack.get_entry_by_index(offset).2.is_empty() => None,
2975                offset if offset < state.frame_pointer => None,
2977                offset => Some(offset),
2978            }
2979        } else {
2980            None
2981        };
2982
2983        let idx = if let Some(n) = existing {
2984            state.stack.get_mut_by_index(n).set_access_mode(access);
2985            Some(NonZeroUsize::new(state.stack.len() - n).unwrap())
2986        } else {
2987            state.stack.push_entry(name.clone(), access, Dynamic::UNIT);
2988            None
2989        };
2990
2991        #[cfg(not(feature = "no_module"))]
2992        if is_export {
2993            state
2994                .stack
2995                .add_alias_by_index(state.stack.len() - 1, name.clone());
2996        }
2997
2998        let var_def = (Ident { name, pos }, expr, idx).into();
2999
3000        Ok(match access {
3001            AccessMode::ReadWrite => Stmt::Var(var_def, export, settings.pos),
3003            AccessMode::ReadOnly => Stmt::Var(var_def, ASTFlags::CONSTANT | export, settings.pos),
3005        })
3006    }
3007
3008    #[cfg(not(feature = "no_module"))]
3010    fn parse_import(&self, state: &mut ParseState, settings: ParseSettings) -> ParseResult<Stmt> {
3011        let settings = settings.level_up_with_position(eat_token(state.input, &Token::Import))?;
3013
3014        let expr = self.parse_expr(state, settings)?;
3016
3017        let export = if match_token(state.input, &Token::As).0 {
3018            let (name, pos) = parse_var_name(state.input)?;
3020            Ident {
3021                name: self.get_interned_string(name),
3022                pos,
3023            }
3024        } else {
3025            Ident {
3027                name: self.get_interned_string(""),
3028                pos: Position::NONE,
3029            }
3030        };
3031
3032        state.imports.push(export.name.clone());
3033
3034        Ok(Stmt::Import((expr, export).into(), settings.pos))
3035    }
3036
3037    #[cfg(not(feature = "no_module"))]
3039    fn parse_export(
3040        &self,
3041        state: &mut ParseState,
3042        mut settings: ParseSettings,
3043    ) -> ParseResult<Stmt> {
3044        settings.pos = eat_token(state.input, &Token::Export);
3045
3046        match state.input.peek().unwrap() {
3047            (Token::Let, pos) => {
3048                let pos = *pos;
3049                let settings = settings.level_up()?;
3050                let mut stmt = self.parse_let(state, settings, AccessMode::ReadWrite, true)?;
3051                stmt.set_position(pos);
3052                return Ok(stmt);
3053            }
3054            (Token::Const, pos) => {
3055                let pos = *pos;
3056                let settings = settings.level_up()?;
3057                let mut stmt = self.parse_let(state, settings, AccessMode::ReadOnly, true)?;
3058                stmt.set_position(pos);
3059                return Ok(stmt);
3060            }
3061            _ => (),
3062        }
3063
3064        let (id, id_pos) = parse_var_name(state.input)?;
3065
3066        let (alias, alias_pos) = if match_token(state.input, &Token::As).0 {
3067            parse_var_name(state.input).map(|(name, pos)| (self.get_interned_string(name), pos))?
3068        } else {
3069            (self.get_interned_string(""), Position::NONE)
3070        };
3071
3072        let (existing, hit_barrier) = state.find_var(&id);
3073
3074        if !hit_barrier && existing > 0 {
3075            state
3076                .stack
3077                .add_alias_by_index(state.stack.len() - existing, alias.clone());
3078        }
3079
3080        let export = (
3081            Ident {
3082                name: self.get_interned_string(id),
3083                pos: id_pos,
3084            },
3085            Ident {
3086                name: alias,
3087                pos: alias_pos,
3088            },
3089        );
3090
3091        Ok(Stmt::Export(export.into(), settings.pos))
3092    }
3093
3094    fn parse_block(
3096        &self,
3097        state: &mut ParseState,
3098        settings: ParseSettings,
3099        no_brace: bool,
3100    ) -> ParseResult<Stmt> {
3101        let brace_start_pos = if no_brace {
3102            settings.pos
3103        } else {
3104            match state.input.next().unwrap() {
3106                (Token::LeftBrace, pos) => pos,
3107                (Token::LexError(err), pos) => return Err(err.into_err(pos)),
3108                (.., pos) => {
3109                    return Err(PERR::MissingToken(
3110                        Token::LeftBrace.into(),
3111                        "to start a statement block".into(),
3112                    )
3113                    .into_err(pos))
3114                }
3115            }
3116        };
3117        let mut settings = settings.level_up_with_position(brace_start_pos)?;
3118
3119        let mut block = StmtBlock::empty(settings.pos);
3120
3121        if settings.has_flag(ParseSettingFlags::DISALLOW_STATEMENTS_IN_BLOCKS) {
3122            let stmt = self.parse_expr_stmt(state, settings)?;
3123            block.statements_mut().push(stmt);
3124
3125            return match state.input.next().unwrap() {
3127                (Token::RightBrace, pos) => {
3128                    Ok(Stmt::Block(StmtBlock::new(block, settings.pos, pos).into()))
3129                }
3130                (Token::LexError(err), pos) => Err(err.into_err(pos)),
3131                (.., pos) => Err(PERR::MissingToken(
3132                    Token::LeftBrace.into(),
3133                    "to start a statement block".into(),
3134                )
3135                .into_err(pos)),
3136            };
3137        }
3138
3139        let prev_frame_pointer = state.frame_pointer;
3140        state.frame_pointer = state.stack.len();
3141
3142        #[cfg(not(feature = "no_module"))]
3143        let orig_imports_len = state.imports.len();
3144
3145        let end_pos = loop {
3146            match state.input.peek().unwrap() {
3148                (Token::RightBrace, ..) => break eat_token(state.input, &Token::RightBrace),
3149                (Token::EOF, pos) => {
3150                    return Err(PERR::MissingToken(
3151                        Token::RightBrace.into(),
3152                        "to terminate this block".into(),
3153                    )
3154                    .into_err(*pos));
3155                }
3156                _ => (),
3157            }
3158
3159            settings.flags.remove(ParseSettingFlags::GLOBAL_LEVEL);
3161
3162            let stmt = self.parse_stmt(state, settings)?;
3163
3164            if stmt.is_noop() {
3165                continue;
3166            }
3167
3168            let need_semicolon = !stmt.is_self_terminated();
3170
3171            block.statements_mut().push(stmt);
3172
3173            match state.input.peek().unwrap() {
3174                (Token::RightBrace, ..) => break eat_token(state.input, &Token::RightBrace),
3176                (Token::SemiColon, ..) if need_semicolon => {
3178                    eat_token(state.input, &Token::SemiColon);
3179                }
3180                (Token::SemiColon, ..) if !need_semicolon => {
3182                    eat_token(state.input, &Token::SemiColon);
3183                }
3184                _ if !need_semicolon => (),
3186                (Token::LexError(err), err_pos) => return Err(err.clone().into_err(*err_pos)),
3188                (.., pos) => {
3190                    return Err(PERR::MissingToken(
3192                        Token::SemiColon.into(),
3193                        "to terminate this statement".into(),
3194                    )
3195                    .into_err(*pos));
3196                }
3197            }
3198        };
3199
3200        state.stack.rewind(state.frame_pointer);
3201        state.frame_pointer = prev_frame_pointer;
3202
3203        #[cfg(not(feature = "no_module"))]
3204        state.imports.truncate(orig_imports_len);
3205
3206        Ok(Stmt::Block(
3207            StmtBlock::new(block, settings.pos, end_pos).into(),
3208        ))
3209    }
3210
3211    fn parse_expr_stmt(
3213        &self,
3214        state: &mut ParseState,
3215        mut settings: ParseSettings,
3216    ) -> ParseResult<Stmt> {
3217        settings.pos = state.input.peek().unwrap().1;
3218
3219        let expr = self.parse_expr(state, settings)?;
3220
3221        let (op, pos) = match state.input.peek().unwrap() {
3222            (Token::Equals, ..) => (None, eat_token(state.input, &Token::Equals)),
3224            (token, ..) if token.is_op_assignment() => {
3226                state.input.next().map(|(op, pos)| (Some(op), pos)).unwrap()
3227            }
3228            _ => return Ok(Stmt::Expr(expr.into())),
3230        };
3231
3232        settings.pos = pos;
3233
3234        let rhs = self.parse_expr(state, settings)?;
3235
3236        Self::make_assignment_stmt(op, state, expr, rhs, pos)
3237    }
3238
3239    fn parse_stmt(&self, state: &mut ParseState, mut settings: ParseSettings) -> ParseResult<Stmt> {
3241        use AccessMode::{ReadOnly, ReadWrite};
3242
3243        #[cfg(not(feature = "no_function"))]
3244        #[cfg(feature = "metadata")]
3245        let comments = {
3246            let mut comments = StaticVec::<SmartString>::new_const();
3247            let mut comments_pos = Position::NONE;
3248            let mut buf = SmartString::new_const();
3249
3250            while let (Token::Comment(ref comment), pos) = state.input.peek().unwrap() {
3252                if comments_pos.is_none() {
3253                    comments_pos = *pos;
3254                }
3255
3256                debug_assert!(
3257                    crate::tokenizer::is_doc_comment(comment),
3258                    "doc-comment expected but gets {:?}",
3259                    comment
3260                );
3261
3262                if !settings.has_flag(ParseSettingFlags::GLOBAL_LEVEL) {
3263                    return Err(PERR::WrongDocComment.into_err(comments_pos));
3264                }
3265
3266                match state.input.next().unwrap() {
3267                    (Token::Comment(comment), pos) => {
3268                        if comment.contains('\n') {
3269                            if !buf.is_empty() {
3271                                comments.push(buf.clone());
3272                                buf.clear();
3273                            }
3274                            let c =
3275                                unindent_block_comment(*comment, pos.position().unwrap_or(1) - 1);
3276                            comments.push(c.into());
3277                        } else {
3278                            if !buf.is_empty() {
3279                                buf.push_str("\n");
3280                            }
3281                            buf.push_str(&comment);
3282                        }
3283
3284                        match state.input.peek().unwrap() {
3285                            (Token::Fn | Token::Private, ..) => break,
3286                            (Token::Comment(..), ..) => (),
3287                            _ => return Err(PERR::WrongDocComment.into_err(comments_pos)),
3288                        }
3289                    }
3290                    (token, ..) => unreachable!("Token::Comment expected but gets {:?}", token),
3291                }
3292            }
3293
3294            if !buf.is_empty() {
3295                comments.push(buf);
3296            }
3297
3298            comments
3299        };
3300
3301        let (token, token_pos) = match state.input.peek().unwrap() {
3302            (Token::EOF, pos) => return Ok(Stmt::Noop(*pos)),
3303            (x, pos) => (x, *pos),
3304        };
3305
3306        settings.pos = token_pos;
3307
3308        match token {
3309            Token::SemiColon => {
3311                eat_token(state.input, &Token::SemiColon);
3312                Ok(Stmt::Noop(token_pos))
3313            }
3314
3315            Token::LeftBrace => Ok(self.parse_block(state, settings.level_up()?, false)?),
3317
3318            #[cfg(not(feature = "no_function"))]
3320            Token::Fn | Token::Private => {
3321                let access = if matches!(token, Token::Private) {
3322                    eat_token(state.input, &Token::Private);
3323                    crate::FnAccess::Private
3324                } else {
3325                    crate::FnAccess::Public
3326                };
3327
3328                match state.input.next().unwrap() {
3329                    (Token::Fn, _) if !settings.has_flag(ParseSettingFlags::GLOBAL_LEVEL) => {
3330                        Err(PERR::WrongFnDefinition.into_err(token_pos))
3331                    }
3332                    #[cfg(not(feature = "unchecked"))]
3333                    (Token::Fn, pos) if state.lib.len() >= self.max_functions() => {
3334                        Err(PERR::TooManyFunctions.into_err(pos))
3335                    }
3336                    (Token::Fn, pos) => {
3337                        let new_state = &mut ParseState::new(
3339                            state.external_constants,
3340                            state.input,
3341                            state.tokenizer_control.clone(),
3342                            state.lib,
3343                        );
3344
3345                        #[cfg(not(feature = "no_module"))]
3346                        {
3347                            new_state.global_imports.clone_from(&state.global_imports);
3353                            new_state.global_imports.extend(state.imports.clone());
3354                        }
3355
3356                        let options = self.options | (settings.options & LangOptions::STRICT_VAR);
3358
3359                        let flags = ParseSettingFlags::FN_SCOPE
3361                            | (settings.flags
3362                                & ParseSettingFlags::DISALLOW_UNQUOTED_MAP_PROPERTIES);
3363
3364                        let new_settings = ParseSettings {
3365                            flags,
3366                            level: 0,
3367                            options,
3368                            pos,
3369                            #[cfg(not(feature = "unchecked"))]
3370                            max_expr_depth: self.max_function_expr_depth(),
3371                        };
3372
3373                        let f = self.parse_fn(
3374                            new_state,
3375                            new_settings,
3376                            access,
3377                            #[cfg(feature = "metadata")]
3378                            comments,
3379                        )?;
3380
3381                        let hash = calc_fn_hash(None, &f.name, f.params.len());
3382
3383                        #[cfg(not(feature = "no_object"))]
3384                        let hash = f
3385                            .this_type
3386                            .as_ref()
3387                            .map_or(hash, |typ| crate::calc_typed_method_hash(hash, typ));
3388
3389                        if state.lib.contains_key(&hash) {
3390                            return Err(PERR::FnDuplicatedDefinition(
3391                                f.name.to_string(),
3392                                f.params.len(),
3393                            )
3394                            .into_err(pos));
3395                        }
3396
3397                        state.lib.insert(hash, f.into());
3398
3399                        Ok(Stmt::Noop(pos))
3400                    }
3401
3402                    (.., pos) => Err(PERR::MissingToken(
3403                        Token::Fn.into(),
3404                        format!("following '{}'", Token::Private),
3405                    )
3406                    .into_err(pos)),
3407                }
3408            }
3409
3410            Token::If => self.parse_if(state, settings.level_up()?),
3411            Token::Switch => self.parse_switch(state, settings.level_up()?),
3412            Token::While | Token::Loop if self.allow_looping() => {
3413                self.parse_while_loop(state, settings.level_up()?)
3414            }
3415            Token::Do if self.allow_looping() => self.parse_do(state, settings.level_up()?),
3416            Token::For if self.allow_looping() => self.parse_for(state, settings.level_up()?),
3417
3418            Token::Continue
3419                if self.allow_looping() && settings.has_flag(ParseSettingFlags::BREAKABLE) =>
3420            {
3421                let pos = eat_token(state.input, &Token::Continue);
3422                Ok(Stmt::BreakLoop(None, ASTFlags::empty(), pos))
3423            }
3424            Token::Break
3425                if self.allow_looping() && settings.has_flag(ParseSettingFlags::BREAKABLE) =>
3426            {
3427                let pos = eat_token(state.input, &Token::Break);
3428
3429                let current_pos = state.input.peek().unwrap().1;
3430
3431                match self.parse_expr(state, settings.level_up()?) {
3432                    Ok(expr) => Ok(Stmt::BreakLoop(Some(expr.into()), ASTFlags::BREAK, pos)),
3433                    Err(err) => {
3434                        if state.input.peek().unwrap().1 == current_pos {
3435                            Ok(Stmt::BreakLoop(None, ASTFlags::BREAK, pos))
3436                        } else {
3437                            return Err(err);
3438                        }
3439                    }
3440                }
3441            }
3442            Token::Continue | Token::Break if self.allow_looping() => {
3443                Err(PERR::LoopBreak.into_err(token_pos))
3444            }
3445
3446            Token::Return | Token::Throw => {
3447                let (return_type, token_pos) = state
3448                    .input
3449                    .next()
3450                    .map(|(token, pos)| {
3451                        let flags = match token {
3452                            Token::Return => ASTFlags::empty(),
3453                            Token::Throw => ASTFlags::BREAK,
3454                            token => unreachable!(
3455                                "Token::Return or Token::Throw expected but gets {:?}",
3456                                token
3457                            ),
3458                        };
3459                        (flags, pos)
3460                    })
3461                    .unwrap();
3462
3463                let current_pos = state.input.peek().unwrap().1;
3464
3465                match self.parse_expr(state, settings.level_up()?) {
3466                    Ok(expr) => Ok(Stmt::Return(Some(expr.into()), return_type, token_pos)),
3467                    Err(err) => {
3468                        if state.input.peek().unwrap().1 == current_pos {
3469                            Ok(Stmt::Return(None, return_type, token_pos))
3470                        } else {
3471                            Err(err)
3472                        }
3473                    }
3474                }
3475            }
3476
3477            Token::Try => self.parse_try_catch(state, settings.level_up()?),
3478
3479            Token::Let => self.parse_let(state, settings.level_up()?, ReadWrite, false),
3480            Token::Const => self.parse_let(state, settings.level_up()?, ReadOnly, false),
3481
3482            #[cfg(not(feature = "no_module"))]
3483            Token::Import => self.parse_import(state, settings.level_up()?),
3484
3485            #[cfg(not(feature = "no_module"))]
3486            Token::Export if !settings.has_flag(ParseSettingFlags::GLOBAL_LEVEL) => {
3487                Err(PERR::WrongExport.into_err(token_pos))
3488            }
3489
3490            #[cfg(not(feature = "no_module"))]
3491            Token::Export => self.parse_export(state, settings.level_up()?),
3492
3493            _ => self.parse_expr_stmt(state, settings.level_up()?),
3494        }
3495    }
3496
3497    fn parse_try_catch(
3499        &self,
3500        state: &mut ParseState,
3501        settings: ParseSettings,
3502    ) -> ParseResult<Stmt> {
3503        let settings = settings.level_up_with_position(eat_token(state.input, &Token::Try))?;
3505
3506        let body = self.parse_block(state, settings, false)?.into();
3508
3509        let (matched, catch_pos) = match_token(state.input, &Token::Catch);
3511
3512        if !matched {
3513            return Err(
3514                PERR::MissingToken(Token::Catch.into(), "for the 'try' statement".into())
3515                    .into_err(catch_pos),
3516            );
3517        }
3518
3519        let catch_var = if match_token(state.input, &Token::LeftParen).0 {
3521            let (name, pos) = parse_var_name(state.input)?;
3522            let (matched, err_pos) = match_token(state.input, &Token::RightParen);
3523
3524            if !matched {
3525                return Err(PERR::MissingToken(
3526                    Token::RightParen.into(),
3527                    "to enclose the catch variable".into(),
3528                )
3529                .into_err(err_pos));
3530            }
3531
3532            let name = self.get_interned_string(name);
3533            state.stack.push(name.clone(), ());
3534            Ident { name, pos }
3535        } else {
3536            Ident {
3537                name: self.get_interned_string(""),
3538                pos: Position::NONE,
3539            }
3540        };
3541
3542        let branch = self.parse_block(state, settings, false)?.into();
3544
3545        let expr = if catch_var.is_empty() {
3546            Expr::Unit(catch_var.pos)
3547        } else {
3548            state.stack.pop();
3550
3551            Expr::Variable(
3552                #[cfg(not(feature = "no_module"))]
3553                (None, catch_var.name, <_>::default(), 0).into(),
3554                #[cfg(feature = "no_module")]
3555                (None, catch_var.name).into(),
3556                None,
3557                catch_var.pos,
3558            )
3559        };
3560
3561        Ok(Stmt::TryCatch(
3562            FlowControl { expr, body, branch }.into(),
3563            settings.pos,
3564        ))
3565    }
3566
3567    #[cfg(not(feature = "no_function"))]
3569    fn parse_fn(
3570        &self,
3571        state: &mut ParseState,
3572        settings: ParseSettings,
3573        access: crate::FnAccess,
3574        #[cfg(feature = "metadata")] comments: impl IntoIterator<Item = crate::Identifier>,
3575    ) -> ParseResult<ScriptFuncDef> {
3576        let settings = settings.level_up()?;
3577
3578        let (token, pos) = state.input.next().unwrap();
3579
3580        #[cfg(not(feature = "no_object"))]
3582        let ((token, pos), this_type) = {
3583            let (next_token, next_pos) = state.input.peek().unwrap();
3584
3585            match token {
3586                Token::StringConstant(s) if next_token == &Token::Period => {
3587                    eat_token(state.input, &Token::Period);
3588                    let s = match s.as_str() {
3589                        "int" => self.get_interned_string(std::any::type_name::<crate::INT>()),
3590                        #[cfg(not(feature = "no_float"))]
3591                        "float" => self.get_interned_string(std::any::type_name::<crate::FLOAT>()),
3592                        _ => self.get_interned_string(*s),
3593                    };
3594                    (state.input.next().unwrap(), Some(s))
3595                }
3596                Token::StringConstant(..) => {
3597                    return Err(PERR::MissingToken(
3598                        Token::Period.into(),
3599                        "after the type name for 'this'".into(),
3600                    )
3601                    .into_err(*next_pos))
3602                }
3603                Token::Identifier(s) if next_token == &Token::Period => {
3604                    eat_token(state.input, &Token::Period);
3605                    let s = match s.as_str() {
3606                        "int" => self.get_interned_string(std::any::type_name::<crate::INT>()),
3607                        #[cfg(not(feature = "no_float"))]
3608                        "float" => self.get_interned_string(std::any::type_name::<crate::FLOAT>()),
3609                        _ => self.get_interned_string(*s),
3610                    };
3611                    (state.input.next().unwrap(), Some(s))
3612                }
3613                _ => ((token, pos), None),
3614            }
3615        };
3616
3617        let name = match token {
3618            #[cfg(not(feature = "no_custom_syntax"))]
3619            Token::Custom(s) if is_valid_function_name(&s) => *s,
3620            Token::Identifier(s) if is_valid_function_name(&s) => *s,
3621            Token::Reserved(s) => return Err(PERR::Reserved(s.to_string()).into_err(pos)),
3622            _ => return Err(PERR::FnMissingName.into_err(pos)),
3623        };
3624
3625        let no_params = match state.input.peek().unwrap() {
3626            (Token::LeftParen, ..) => {
3627                eat_token(state.input, &Token::LeftParen);
3628                match_token(state.input, &Token::RightParen).0
3629            }
3630            (Token::Unit, ..) => {
3631                eat_token(state.input, &Token::Unit);
3632                true
3633            }
3634            (.., pos) => return Err(PERR::FnMissingParams(name.into()).into_err(*pos)),
3635        };
3636
3637        let mut params = StaticVec::<(ImmutableString, _)>::new_const();
3638
3639        if !no_params {
3640            let sep_err = format!("to separate the parameters of function '{name}'");
3641
3642            loop {
3643                match state.input.next().unwrap() {
3644                    (Token::RightParen, ..) => break,
3645                    (Token::Identifier(s), pos) => {
3646                        if params.iter().any(|(p, _)| p == &*s) {
3647                            return Err(
3648                                PERR::FnDuplicatedParam(name.into(), s.to_string()).into_err(pos)
3649                            );
3650                        }
3651
3652                        let s = self.get_interned_string(*s);
3653                        state.stack.push(s.clone(), ());
3654                        params.push((s, pos));
3655                    }
3656                    (Token::LexError(err), pos) => return Err(err.into_err(pos)),
3657                    (token, pos) if token.is_reserved() => {
3658                        return Err(PERR::Reserved(token.to_string()).into_err(pos))
3659                    }
3660                    (token, pos) if token.is_standard_keyword() => {
3661                        return Err(PERR::VariableExpected.into_err(pos))
3662                    }
3663                    (.., pos) => {
3664                        return Err(PERR::MissingToken(
3665                            Token::RightParen.into(),
3666                            format!("to close the parameters list of function '{name}'"),
3667                        )
3668                        .into_err(pos))
3669                    }
3670                }
3671
3672                match state.input.next().unwrap() {
3673                    (Token::RightParen, ..) => break,
3674                    (Token::Comma, ..) => (),
3675                    (Token::LexError(err), pos) => return Err(err.into_err(pos)),
3676                    (.., pos) => {
3677                        return Err(PERR::MissingToken(Token::Comma.into(), sep_err).into_err(pos))
3678                    }
3679                }
3680            }
3681        }
3682
3683        let body = match state.input.peek().unwrap() {
3685            (Token::LeftBrace, ..) => self.parse_block(state, settings, false)?,
3686            (.., pos) => return Err(PERR::FnMissingBody(name.into()).into_err(*pos)),
3687        }
3688        .into();
3689
3690        let mut params: FnArgsVec<_> = params.into_iter().map(|(p, ..)| p).collect();
3691        params.shrink_to_fit();
3692
3693        Ok(ScriptFuncDef {
3694            name: self.get_interned_string(name),
3695            access,
3696            #[cfg(not(feature = "no_object"))]
3697            this_type,
3698            params,
3699            body,
3700            #[cfg(feature = "metadata")]
3701            comments: comments.into_iter().collect(),
3702        })
3703    }
3704
3705    #[cfg(not(feature = "no_function"))]
3707    #[cfg(not(feature = "no_closure"))]
3708    fn make_curry_from_externals(
3709        &self,
3710        state: &mut ParseState,
3711        fn_expr: Expr,
3712        externals: impl AsRef<[Ident]> + IntoIterator<Item = Ident>,
3713        pos: Position,
3714    ) -> Expr {
3715        if externals.as_ref().is_empty() {
3717            return fn_expr;
3718        }
3719
3720        let num_externals = externals.as_ref().len();
3721        let mut args = FnArgsVec::with_capacity(externals.as_ref().len() + 1);
3722
3723        args.push(fn_expr);
3724
3725        args.extend(
3726            externals
3727                .as_ref()
3728                .iter()
3729                .cloned()
3730                .map(|Ident { name, pos }| {
3731                    let (index, is_func) = self.access_var(state, &name, pos);
3732                    let idx = match index {
3733                        Some(n) if !is_func => u8::try_from(n.get()).ok().and_then(NonZeroU8::new),
3734                        _ => None,
3735                    };
3736                    #[cfg(not(feature = "no_module"))]
3737                    return Expr::Variable((index, name, <_>::default(), 0).into(), idx, pos);
3738                    #[cfg(feature = "no_module")]
3739                    return Expr::Variable((index, name).into(), idx, pos);
3740                }),
3741        );
3742
3743        let expr = FnCallExpr {
3744            #[cfg(not(feature = "no_module"))]
3745            namespace: crate::ast::Namespace::NONE,
3746            name: self.get_interned_string(crate::engine::KEYWORD_FN_PTR_CURRY),
3747            hashes: FnCallHashes::from_native_only(calc_fn_hash(
3748                None,
3749                crate::engine::KEYWORD_FN_PTR_CURRY,
3750                num_externals + 1,
3751            )),
3752            args,
3753            op_token: None,
3754            capture_parent_scope: false,
3755        }
3756        .into_fn_call_expr(pos);
3757
3758        let mut statements = StaticVec::with_capacity(2);
3761        statements.push(Stmt::Share(
3762            externals
3763                .into_iter()
3764                .map(|var| {
3765                    let (index, _) = self.access_var(state, &var.name, var.pos);
3766                    (var, index)
3767                })
3768                .collect::<FnArgsVec<_>>()
3769                .into(),
3770        ));
3771        statements.push(Stmt::Expr(expr.into()));
3772        Expr::Stmt(StmtBlock::new(statements, pos, Position::NONE).into())
3773    }
3774
3775    #[cfg(not(feature = "no_function"))]
3777    fn parse_anon_fn(
3778        &self,
3779        state: &mut ParseState,
3780        settings: ParseSettings,
3781        skip_parameters: bool,
3782    ) -> ParseResult<Expr> {
3783        let new_state = &mut ParseState::new(
3786            state.external_constants,
3787            state.input,
3788            state.tokenizer_control.clone(),
3789            state.lib,
3790        );
3791
3792        #[cfg(not(feature = "no_module"))]
3793        {
3794            new_state.global_imports.clone_from(&state.global_imports);
3800            new_state.global_imports.extend(state.imports.clone());
3801        }
3802
3803        let mut params_list = StaticVec::<ImmutableString>::new_const();
3804
3805        if !skip_parameters
3807            && new_state.input.next().unwrap().0 != Token::Or
3808            && !match_token(new_state.input, &Token::Pipe).0
3809        {
3810            loop {
3811                match new_state.input.next().unwrap() {
3812                    (Token::Pipe, ..) => break,
3813                    (Token::Identifier(s), pos) => {
3814                        if params_list.iter().any(|p| p == &*s) {
3815                            return Err(
3816                                PERR::FnDuplicatedParam(String::new(), s.to_string()).into_err(pos)
3817                            );
3818                        }
3819
3820                        let s = self.get_interned_string(*s);
3821                        new_state.stack.push(s.clone(), ());
3822                        params_list.push(s);
3823                    }
3824                    (Token::LexError(err), pos) => return Err(err.into_err(pos)),
3825                    (token, pos) if token.is_reserved() => {
3826                        return Err(PERR::Reserved(token.to_string()).into_err(pos))
3827                    }
3828                    (token, pos) if token.is_standard_keyword() => {
3829                        return Err(PERR::VariableExpected.into_err(pos))
3830                    }
3831                    (.., pos) => {
3832                        return Err(PERR::MissingToken(
3833                            Token::Pipe.into(),
3834                            "to close the parameters list of anonymous function or closure".into(),
3835                        )
3836                        .into_err(pos))
3837                    }
3838                }
3839
3840                match new_state.input.next().unwrap() {
3841                    (Token::Pipe, ..) => break,
3842                    (Token::Comma, ..) => (),
3843                    (Token::LexError(err), pos) => return Err(err.into_err(pos)),
3844                    (.., pos) => {
3845                        return Err(PERR::MissingToken(
3846                            Token::Comma.into(),
3847                            "to separate the parameters of anonymous function".into(),
3848                        )
3849                        .into_err(pos))
3850                    }
3851                }
3852            }
3853        }
3854
3855        #[cfg(not(feature = "no_closure"))]
3857        let options = self.options & !LangOptions::STRICT_VAR; #[cfg(feature = "no_closure")]
3859        let options = self.options | (settings.options & LangOptions::STRICT_VAR);
3860
3861        let flags = ParseSettingFlags::FN_SCOPE
3863            | ParseSettingFlags::CLOSURE_SCOPE
3864            | (settings.flags
3865                & (ParseSettingFlags::DISALLOW_UNQUOTED_MAP_PROPERTIES
3866                    | ParseSettingFlags::DISALLOW_STATEMENTS_IN_BLOCKS));
3867
3868        let new_settings = ParseSettings {
3869            flags,
3870            options,
3871            ..settings
3872        };
3873
3874        let body = self.parse_stmt(new_state, new_settings.level_up()?)?;
3876
3877        let _ = new_settings; #[cfg(not(feature = "no_closure"))]
3882        let (mut params, _externals) = {
3883            let externals = std::mem::take(&mut new_state.external_vars);
3884
3885            let mut params = FnArgsVec::with_capacity(params_list.len() + externals.len());
3886            params.extend(externals.iter().map(|Ident { name, .. }| name.clone()));
3887
3888            (params, externals)
3889        };
3890        #[cfg(feature = "no_closure")]
3891        let (mut params, _externals) = (
3892            FnArgsVec::with_capacity(params_list.len()),
3893            ThinVec::<Ident>::new(),
3894        );
3895
3896        let _ = new_state; params.append(&mut params_list);
3899
3900        let hasher = &mut get_hasher();
3902        params.iter().for_each(|p| p.hash(hasher));
3903        body.hash(hasher);
3904        let hash = hasher.finish();
3905        let fn_name = self.get_interned_string(make_anonymous_fn(hash));
3906
3907        let fn_def = Shared::new(ScriptFuncDef {
3909            name: fn_name.clone(),
3910            access: crate::FnAccess::Public,
3911            #[cfg(not(feature = "no_object"))]
3912            this_type: None,
3913            params,
3914            body: body.into(),
3915            #[cfg(not(feature = "no_function"))]
3916            #[cfg(feature = "metadata")]
3917            comments: <_>::default(),
3918        });
3919
3920        let fn_ptr = crate::FnPtr {
3922            name: fn_name,
3923            curry: ThinVec::new(),
3924            #[cfg(not(feature = "no_function"))]
3925            env: None,
3926            typ: crate::types::fn_ptr::FnPtrType::Script(fn_def.clone()),
3927        };
3928
3929        let expr = Expr::DynamicConstant(Box::new(fn_ptr.into()), new_settings.pos);
3930
3931        #[cfg(not(feature = "no_closure"))]
3934        for Ident { name, pos } in &_externals {
3935            let (index, is_func) = self.access_var(state, name, *pos);
3936
3937            if !is_func
3938                && index.is_none()
3939                && !settings.has_flag(ParseSettingFlags::CLOSURE_SCOPE)
3940                && settings.has_option(LangOptions::STRICT_VAR)
3941                && !state
3942                    .external_constants
3943                    .map_or(false, |scope| scope.contains(name))
3944            {
3945                return Err(PERR::VariableUndefined(name.to_string()).into_err(*pos));
3949            }
3950        }
3951
3952        let hash_script = calc_fn_hash(None, &fn_def.name, fn_def.params.len());
3953        state.lib.insert(hash_script, fn_def);
3954
3955        #[cfg(not(feature = "no_closure"))]
3956        let expr = self.make_curry_from_externals(state, expr, _externals, settings.pos);
3957
3958        Ok(expr)
3959    }
3960
3961    pub(crate) fn parse_global_expr(
3963        &self,
3964        mut state: ParseState,
3965        process_settings: impl FnOnce(&mut ParseSettings),
3966        #[cfg(not(feature = "no_optimize"))] optimization_level: crate::OptimizationLevel,
3967    ) -> ParseResult<AST> {
3968        let options = self.options & !LangOptions::STMT_EXPR & !LangOptions::LOOP_EXPR;
3969
3970        let mut settings = ParseSettings {
3971            level: 0,
3972            flags: ParseSettingFlags::GLOBAL_LEVEL
3973                | ParseSettingFlags::DISALLOW_STATEMENTS_IN_BLOCKS,
3974            options,
3975            pos: Position::START,
3976            #[cfg(not(feature = "unchecked"))]
3977            max_expr_depth: self.max_expr_depth(),
3978        };
3979        process_settings(&mut settings);
3980
3981        let expr = self.parse_expr(&mut state, settings)?;
3982
3983        match state.input.peek().unwrap() {
3984            (Token::EOF, ..) => (),
3985            (token, pos) => return Err(LexError::UnexpectedInput(token.to_string()).into_err(*pos)),
3987        }
3988
3989        let mut statements = StmtBlockContainer::new_const();
3990        statements.push(Stmt::Expr(expr.into()));
3991
3992        #[cfg(not(feature = "no_optimize"))]
3993        return Ok(self.optimize_into_ast(
3994            state.external_constants,
3995            statements,
3996            #[cfg(not(feature = "no_function"))]
3997            state.lib.values().cloned().collect::<Vec<_>>(),
3998            optimization_level,
3999        ));
4000
4001        #[cfg(feature = "no_optimize")]
4002        return Ok(AST::new(
4003            statements,
4004            #[cfg(not(feature = "no_function"))]
4005            crate::Module::from(state.lib.values().cloned()),
4006        ));
4007    }
4008
4009    fn parse_global_level(
4011        &self,
4012        state: &mut ParseState,
4013        process_settings: impl FnOnce(&mut ParseSettings),
4014    ) -> ParseResult<(StmtBlockContainer, Vec<Shared<ScriptFuncDef>>)> {
4015        let mut statements = StmtBlockContainer::new_const();
4016
4017        let mut settings = ParseSettings {
4018            level: 0,
4019            flags: ParseSettingFlags::GLOBAL_LEVEL,
4020            options: self.options,
4021            pos: Position::START,
4022            #[cfg(not(feature = "unchecked"))]
4023            max_expr_depth: self.max_expr_depth(),
4024        };
4025        process_settings(&mut settings);
4026
4027        while state.input.peek().unwrap().0 != Token::EOF {
4028            let stmt = self.parse_stmt(state, settings)?;
4029
4030            if stmt.is_noop() {
4031                continue;
4032            }
4033
4034            let need_semicolon = !stmt.is_self_terminated();
4035
4036            statements.push(stmt);
4037
4038            match state.input.peek().unwrap() {
4039                (Token::EOF, ..) => break,
4041                (Token::SemiColon, ..) if need_semicolon => {
4043                    eat_token(state.input, &Token::SemiColon);
4044                }
4045                (Token::SemiColon, ..) if !need_semicolon => (),
4047                _ if !need_semicolon => (),
4049                (Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
4051                (.., pos) => {
4053                    return Err(PERR::MissingToken(
4055                        Token::SemiColon.into(),
4056                        "to terminate this statement".into(),
4057                    )
4058                    .into_err(*pos));
4059                }
4060            }
4061        }
4062
4063        #[cfg(not(feature = "no_function"))]
4064        let lib = state.lib.values().cloned().collect();
4065        #[cfg(feature = "no_function")]
4066        let lib = Vec::new();
4067
4068        Ok((statements, lib))
4069    }
4070
4071    #[inline]
4073    pub(crate) fn parse(
4074        &self,
4075        mut state: ParseState,
4076        #[cfg(not(feature = "no_optimize"))] optimization_level: crate::OptimizationLevel,
4077    ) -> ParseResult<AST> {
4078        let (statements, _lib) = self.parse_global_level(&mut state, |_| {})?;
4079
4080        #[cfg(not(feature = "no_optimize"))]
4081        return Ok(self.optimize_into_ast(
4082            state.external_constants,
4083            statements,
4084            #[cfg(not(feature = "no_function"))]
4085            _lib,
4086            optimization_level,
4087        ));
4088
4089        #[cfg(feature = "no_optimize")]
4090        return Ok(AST::new(
4091            statements,
4092            #[cfg(not(feature = "no_function"))]
4093            {
4094                let mut new_lib = crate::Module::new();
4095                new_lib.extend(_lib);
4096                new_lib
4097            },
4098        ));
4099    }
4100}