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}