Skip to main content

ps_parser/
parser.rs

1mod command;
2mod error;
3mod formatting;
4mod predicates;
5mod script_result;
6mod stream_message;
7mod token;
8mod value;
9mod variables;
10
11use std::collections::{HashMap, HashSet};
12
13pub(crate) use command::CommandError;
14use command::{Command, CommandElem};
15pub(crate) use stream_message::StreamMessage;
16use value::{
17    ClassProperties, ClassType, Convert, Encoding, MethodName, Param, RuntimeObjectTrait,
18    RuntimeTypeTrait, ScriptBlock, ValError, ValResult,
19};
20use variables::{Scope, SessionScope, TopScope};
21type ParserResult<T> = core::result::Result<T, ParserError>;
22use error::ParserError;
23type PestError = pest::error::Error<Rule>;
24use pest::Parser;
25use predicates::{ArithmeticPred, BitwisePred, LogicalPred, StringPred};
26pub use script_result::{PsValue, ScriptResult};
27pub use token::{CommandToken, ExpressionToken, MethodToken, StringExpandableToken, Token, Tokens};
28pub(crate) use value::Val;
29use value::ValType;
30pub use variables::Variables;
31use variables::{VarName, VariableError};
32
33use crate::parser::{command::CommandOutput, value::RuntimeError};
34
35type Pair<'i> = ::pest::iterators::Pair<'i, Rule>;
36type Pairs<'i> = ::pest::iterators::Pairs<'i, Rule>;
37
38pub(crate) const NEWLINE: &str = "\n";
39
40macro_rules! unexpected_token {
41    ($pair:expr) => {
42        panic!("Unexpected token: {:?}", $pair.as_rule())
43    };
44}
45
46macro_rules! check_rule {
47    ($pair:expr, $rule:pat) => {
48        if !matches!($pair.as_rule(), $rule) {
49            panic!(
50                "Unexpected token: {:?}, instead of {}",
51                $pair.as_rule(),
52                stringify!($rule)
53            );
54        }
55    };
56}
57
58macro_rules! not_implemented {
59    ($token:expr) => {
60        Err(ParserError::NotImplemented(format!(
61            "Not implemented: {:?}",
62            $token.as_rule()
63        )))
64    };
65}
66
67// stack overflow aborts the process, so deep nesting is rejected with an error before that happens
68const STACK_BUDGET: usize = 512 * 1024;
69const PEST_STACK_PER_LEVEL: usize = if cfg!(debug_assertions) { 40 * 1024 } else { 8 * 1024 };
70
71thread_local! {
72    static STACK_BASE: std::cell::Cell<Option<usize>> = const { std::cell::Cell::new(None) };
73}
74
75struct StackBase(bool);
76
77impl StackBase {
78    fn enter() -> Self {
79        let here = 0u8;
80        let outermost = STACK_BASE.with(|base| base.get().is_none());
81        if outermost {
82            STACK_BASE.with(|base| base.set(Some(&here as *const u8 as usize)));
83            EVAL_STEPS.set(0);
84            DEADLINE.set(Some(std::time::Instant::now() + TIME_BUDGET));
85        }
86        StackBase(outermost)
87    }
88}
89
90impl Drop for StackBase {
91    fn drop(&mut self) {
92        if self.0 {
93            STACK_BASE.with(|base| base.set(None));
94            DEADLINE.set(None);
95        }
96    }
97}
98
99fn check_stack(extra: usize) -> ParserResult<()> {
100    let here = 0u8;
101    let used = STACK_BASE
102        .with(|base| base.get())
103        .map_or(0, |base| base.saturating_sub(&here as *const u8 as usize));
104    if used + extra > STACK_BUDGET {
105        Err(ParserError::NestingTooDeep)
106    } else {
107        Ok(())
108    }
109}
110
111// the stack guard bounds recursion depth but not width, e.g. `function f { f; f }; f` makes 2^depth calls;
112// real scripts need a few thousand steps, a function call step costs ~13us in release
113const EVAL_STEPS_BUDGET: u64 = 100_000;
114// a step's cost is not bounded (a call re-parses the function body), so parse and eval time is capped too
115const TIME_BUDGET: std::time::Duration = std::time::Duration::from_secs(1);
116
117thread_local! {
118    static EVAL_STEPS: std::cell::Cell<u64> = const { std::cell::Cell::new(0) };
119    static DEADLINE: std::cell::Cell<Option<std::time::Instant>> = const { std::cell::Cell::new(None) };
120}
121
122fn deadline_passed() -> bool {
123    DEADLINE.get().is_some_and(|d| std::time::Instant::now() > d)
124}
125
126fn eval_step() -> ParserResult<()> {
127    let steps = EVAL_STEPS.get() + 1;
128    EVAL_STEPS.set(steps);
129    if steps > EVAL_STEPS_BUDGET || deadline_passed() {
130        Err(ParserError::EvalBudgetExceeded)
131    } else {
132        Ok(())
133    }
134}
135
136// counts code nesting only: brackets inside strings and comments don't make pest recurse
137fn max_nesting(input: &str) -> usize {
138    let chars: Vec<char> = input.chars().collect();
139    let skip_until = |mut i: usize, end: [char; 2]| {
140        while i + 1 < chars.len() && [chars[i], chars[i + 1]] != end {
141            i += 1;
142        }
143        i + 1
144    };
145    // '"' / '@' mark an open "..." / @"..."@ string, anything else an open bracket
146    let mut stack: Vec<char> = vec![];
147    let (mut depth, mut max) = (0usize, 0usize);
148    let mut i = 0;
149    while i < chars.len() {
150        let (c, next) = (chars[i], chars.get(i + 1).copied());
151        match stack.last() {
152            Some(&string @ ('"' | '@')) => match (c, next) {
153                ('`', _) | ('"', Some('"')) if string == '"' => i += 1,
154                ('`', _) => i += 1,
155                ('"', _) if string == '"' => _ = stack.pop(),
156                ('"', Some('@')) => {
157                    stack.pop();
158                    i += 1;
159                }
160                ('$', Some('(')) => {
161                    stack.push('(');
162                    depth += 1;
163                    max = max.max(depth);
164                    i += 1;
165                }
166                _ => {}
167            },
168            _ => match (c, next) {
169                ('`', _) => i += 1,
170                ('#', _) => {
171                    while i + 1 < chars.len() && chars[i + 1] != '\n' {
172                        i += 1;
173                    }
174                }
175                ('<', Some('#')) => i = skip_until(i + 2, ['#', '>']),
176                ('@', Some('\'')) => i = skip_until(i + 2, ['\'', '@']),
177                ('@', Some('"')) => {
178                    stack.push('@');
179                    i += 1;
180                }
181                ('\'', _) => {
182                    i += 1;
183                    while i < chars.len() && (chars[i] != '\'' || next_is(&chars, i, '\'')) {
184                        i += if chars[i] == '\'' { 2 } else { 1 };
185                    }
186                }
187                ('"', _) => stack.push('"'),
188                ('(' | '{' | '[', _) => {
189                    stack.push(c);
190                    depth += 1;
191                    max = max.max(depth);
192                }
193                (')' | '}' | ']', _) if stack.last().is_some() => {
194                    stack.pop();
195                    depth -= 1;
196                }
197                _ => {}
198            },
199        }
200        i += 1;
201    }
202    max
203}
204
205fn next_is(chars: &[char], i: usize, c: char) -> bool {
206    chars.get(i + 1) == Some(&c)
207}
208
209// PEG backtracking is exponential on some inputs (e.g. unclosed brackets), so grammar rule calls
210// are capped; real code needs ~100 rule calls per input byte
211const PARSE_STEPS_BASE: u64 = 1_000_000;
212const PARSE_STEPS_PER_BYTE: u64 = 1_000;
213
214thread_local! {
215    static PARSE_STEPS: std::cell::Cell<u64> = const { std::cell::Cell::new(0) };
216    static PARSE_BUDGET: std::cell::Cell<u64> = const { std::cell::Cell::new(u64::MAX) };
217}
218
219// called on entry of every grammar rule by the parser generated in build.rs; once the budget is
220// spent all rules fail at once
221pub(crate) fn parse_step<T>(state: T) -> Result<T, T> {
222    let steps = PARSE_STEPS.get() + 1;
223    PARSE_STEPS.set(steps);
224    if steps > PARSE_BUDGET.get() || (steps % 4096 == 0 && deadline_passed()) {
225        PARSE_BUDGET.set(0);
226        Err(state)
227    } else {
228        Ok(state)
229    }
230}
231
232fn parse_program(input: &str) -> ParserResult<Pairs<'_>> {
233    PARSE_STEPS.set(0);
234    PARSE_BUDGET.set(
235        PARSE_STEPS_BASE.saturating_add(PARSE_STEPS_PER_BYTE.saturating_mul(input.len() as u64)),
236    );
237    let res = PowerShellSession::parse(Rule::program, input);
238    let exceeded = PARSE_STEPS.get() > PARSE_BUDGET.get();
239    PARSE_BUDGET.set(u64::MAX);
240    res.map_err(|err| {
241        if exceeded {
242            ParserError::ParseBudgetExceeded
243        } else {
244            err.into()
245        }
246    })
247}
248
249#[derive(Default, Clone)]
250pub(crate) struct Results {
251    output: Vec<StreamMessage>,
252    deobfuscated: Vec<String>,
253}
254
255impl Results {
256    fn new() -> Self {
257        Self {
258            output: Vec::new(),
259            deobfuscated: Vec::new(),
260        }
261    }
262}
263
264include!(concat!(env!("OUT_DIR"), "/powershell_parser.rs"));
265
266pub struct PowerShellSession {
267    variables: Variables,
268    tokens: Tokens,
269    errors: Vec<ParserError>,
270    results: Vec<Results>,
271    skip_error: u32,
272    default_scope: TopScope,
273    types_map: HashMap<String, Box<dyn RuntimeTypeTrait>>,
274    // blocks whose tokens were already collected; re-collecting nested blocks is exponential
275    collected: HashSet<String>,
276    // index of the last failed element access, reused by parse_access instead of evaluating it again
277    failed_index: Option<((usize, usize), Val)>,
278}
279
280impl Clone for PowerShellSession {
281    fn clone(&self) -> Self {
282        Self {
283            variables: self.variables.clone(),
284            ..Default::default()
285        }
286    }
287}
288
289impl Default for PowerShellSession {
290    fn default() -> Self {
291        Self::new()
292    }
293}
294const CONVERT: Convert = Convert {};
295const ENCODING: Encoding = Encoding {};
296impl<'a> PowerShellSession {
297    /// Creates a new PowerShell parsing session with default settings.
298    ///
299    /// The session is initialized with built-in variables like `$true`,
300    /// `$false`, `$null`, and special variables like `$?` for error status
301    /// tracking.
302    ///
303    /// # Returns
304    ///
305    /// A new `PowerShellSession` instance ready for script evaluation.
306    ///
307    /// # Examples
308    ///
309    /// ```rust
310    /// use ps_parser::PowerShellSession;
311    ///
312    /// let mut session = PowerShellSession::new();
313    /// let result = session.safe_eval("$true").unwrap();
314    /// assert_eq!(result, "True");
315    /// ```
316    pub fn new() -> Self {
317        let mut types_map = HashMap::new();
318        types_map.insert(
319            CONVERT.full_name().to_ascii_lowercase(),
320            Box::new(CONVERT) as _,
321        );
322        types_map.insert(
323            ENCODING.full_name().to_ascii_lowercase(),
324            Box::new(ENCODING) as _,
325        );
326
327        Self {
328            variables: Variables::new(),
329            tokens: Tokens::new(),
330            errors: Vec::new(),
331            results: Vec::new(),
332            skip_error: 0,
333            default_scope: TopScope::Session,
334            types_map,
335            collected: HashSet::new(),
336            failed_index: None,
337        }
338    }
339
340    /// Creates a new PowerShell session with the provided variables.
341    ///
342    /// This constructor allows you to initialize the session with a custom set
343    /// of variables, such as environment variables or variables loaded from
344    /// configuration files.
345    ///
346    /// # Arguments
347    ///
348    /// * `variables` - A `Variables` instance containing the initial variable
349    ///   set.
350    ///
351    /// # Returns
352    ///
353    /// A new `PowerShellSession` instance with the provided variables.
354    ///
355    /// # Examples
356    ///
357    /// ```rust
358    /// use ps_parser::{PowerShellSession, Variables};
359    ///
360    /// let env_vars = Variables::env();
361    /// let mut session = PowerShellSession::new().with_variables(env_vars);
362    /// let username = session.safe_eval("$env:USERNAME").unwrap();
363    /// ```
364    pub fn with_variables(mut self, variables: Variables) -> Self {
365        self.variables = variables;
366        self
367    }
368
369    /// Safely evaluates a PowerShell script and returns the output as a string.
370    ///
371    /// This method parses and evaluates the provided PowerShell script,
372    /// handling errors gracefully and returning the result as a formatted
373    /// string. It's the recommended method for simple script evaluation.
374    ///
375    /// # Arguments
376    ///
377    /// * `script` - A string slice containing the PowerShell script to
378    ///   evaluate.
379    ///
380    /// # Returns
381    ///
382    /// * `Result<String, ParserError>` - The output of the script evaluation,
383    ///   or an error if parsing/evaluation fails.
384    ///
385    /// # Examples
386    ///
387    /// ```rust
388    /// use ps_parser::PowerShellSession;
389    ///
390    /// let mut session = PowerShellSession::new();
391    ///
392    /// // Simple arithmetic
393    /// let result = session.safe_eval("1 + 2 * 3").unwrap();
394    /// assert_eq!(result, "7");
395    ///
396    /// // Variable assignment and retrieval
397    /// let result = session.safe_eval("$name = 'World'; \"Hello $name\"").unwrap();
398    /// assert_eq!(result, "Hello World");
399    /// ```
400    pub fn safe_eval(&mut self, script: &str) -> Result<String, ParserError> {
401        let script_res = self.parse_command(script)?;
402        Ok(script_res.result().to_string())
403    }
404
405    pub fn deobfuscate_script(&mut self, script: &str) -> Result<String, ParserError> {
406        self.push_scope_session();
407        let script_res = self.parse_script(script)?;
408        self.pop_scope_session();
409        Ok(script_res.deobfuscated().to_string())
410    }
411
412    pub fn env_variables(&self) -> HashMap<String, PsValue> {
413        self.variables
414            .get_env()
415            .into_iter()
416            .map(|(k, v)| (k, v.into()))
417            .collect()
418    }
419
420    pub fn session_variables(&self) -> HashMap<String, PsValue> {
421        self.variables
422            .get_global()
423            .into_iter()
424            .map(|(k, v)| (k, v.into()))
425            .collect()
426    }
427
428    /// Parses and evaluates a PowerShell script, returning detailed results.
429    ///
430    /// This method provides comprehensive information about the parsing and
431    /// evaluation process, including the final result, generated output,
432    /// any errors encountered, and the tokenized representation of the
433    /// script. It's particularly useful for debugging and deobfuscation.
434    ///
435    /// # Arguments
436    ///
437    /// * `input` - A string slice containing the PowerShell script to parse and
438    ///   evaluate.
439    ///
440    /// # Returns
441    ///
442    /// * `Result<ScriptResult, ParserError>` - A detailed result containing the
443    ///   evaluation outcome, output, errors, and tokens, or a parsing error if
444    ///   the script is malformed.
445    ///
446    /// # Examples
447    ///
448    /// ```rust
449    /// use ps_parser::PowerShellSession;
450    ///
451    /// let mut session = PowerShellSession::new();
452    /// let script_result = session.parse_command("$a = 42; Write-Output $a").unwrap();
453    ///
454    /// println!("Final result: {:?}", script_result.result());
455    /// println!("Generated output: {:?}", script_result.output());
456    /// println!("Parsing errors: {:?}", script_result.errors());
457    /// println!("Deobfuscated code: {:?}", script_result.deobfuscated());
458    /// ```
459    pub fn parse_script(&mut self, input: &str) -> Result<ScriptResult, ParserError> {
460        self.default_scope = TopScope::Script;
461        self.variables.init(self.default_scope.clone());
462        self.collected.clear();
463        let _stack_base = StackBase::enter();
464
465        let (script_last_output, mut result) = self.parse_subscript(input)?;
466        self.variables.clear_script_functions();
467        Ok(ScriptResult::new(
468            script_last_output,
469            std::mem::take(&mut result.output),
470            std::mem::take(&mut result.deobfuscated),
471            std::mem::take(&mut self.tokens),
472            std::mem::take(&mut self.errors),
473            self.variables
474                .script_scope()
475                .into_iter()
476                .map(|(k, v)| (k, v.into()))
477                .collect(),
478        ))
479    }
480
481    pub fn parse_command(&mut self, input: &str) -> Result<ScriptResult, ParserError> {
482        self.default_scope = TopScope::Session;
483        self.variables.init(self.default_scope.clone());
484        self.collected.clear();
485        let _stack_base = StackBase::enter();
486
487        let (script_last_output, mut result) = self.parse_subscript(input)?;
488        self.variables.clear_script_functions();
489        Ok(ScriptResult::new(
490            script_last_output,
491            std::mem::take(&mut result.output),
492            std::mem::take(&mut result.deobfuscated),
493            std::mem::take(&mut self.tokens),
494            std::mem::take(&mut self.errors),
495            self.variables
496                .script_scope()
497                .into_iter()
498                .map(|(k, v)| (k, v.into()))
499                .collect(),
500        ))
501    }
502
503    pub(crate) fn parse_subscript(&mut self, input: &str) -> Result<(Val, Results), ParserError> {
504        check_stack(max_nesting(input) * PEST_STACK_PER_LEVEL)?;
505        let mut pairs = parse_program(input)?;
506        //create new scope for script
507        self.results.push(Results::new());
508
509        let program_token = pairs.next().expect("");
510
511        let mut script_last_output = Val::default();
512
513        if let Rule::program = program_token.as_rule() {
514            let mut pairs = program_token.into_inner();
515            let _script_param_block_token = pairs.next().unwrap();
516            if let Some(named_blocks) = pairs.peek()
517                && named_blocks.as_rule() == Rule::named_blocks
518            {
519                //todo
520                let _ = pairs.next();
521            }
522            for token in pairs {
523                let token_str = token.as_str();
524                match token.as_rule() {
525                    Rule::statement_terminator => continue,
526                    Rule::EOI => break,
527                    _ => {}
528                };
529
530                let results_len = self.results.len();
531                let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
532                    self.eval_statement(token.clone())
533                }))
534                .unwrap_or_else(|payload| {
535                    self.results.truncate(results_len);
536                    let msg = payload
537                        .downcast_ref::<&str>()
538                        .map(|s| s.to_string())
539                        .or_else(|| payload.downcast_ref::<String>().cloned())
540                        .unwrap_or_default();
541                    Err(ParserError::Panic(msg))
542                });
543                self.variables.set_status(result.is_ok());
544
545                if let Ok(Val::NonDisplayed(_)) = &result {
546                    continue;
547                }
548
549                script_last_output = match result {
550                    Ok(val) => {
551                        if val != Val::Null {
552                            self.add_output_statement(val.display().into());
553                            self.add_deobfuscated_statement(val.cast_to_script());
554                        }
555
556                        val
557                    }
558                    Err(e) => {
559                        self.errors.push(e);
560                        self.add_deobfuscated_statement(token_str.into());
561                        Val::Null
562                    }
563                };
564            }
565        }
566
567        Ok((script_last_output, self.results.pop().unwrap_or_default()))
568    }
569
570    fn add_function(
571        &mut self,
572        name: String,
573        func: ScriptBlock,
574        scope: TopScope,
575    ) -> ParserResult<Val> {
576        // let func_str= func.to_function(&name, &scope);
577        // self.add_deobfuscated_statement(func_str);
578
579        if let TopScope::Session = scope {
580            self.variables.add_global_function(name.clone(), func);
581        } else {
582            self.variables.add_script_function(name.clone(), func);
583        }
584
585        Err(ParserError::Skip)
586    }
587
588    pub(crate) fn parse_function_statement(&mut self, token: Pair<'a>) -> ParserResult<Val> {
589        check_rule!(token, Rule::function_statement);
590
591        let mut pair = token.into_inner();
592
593        let function_keyword_token = pair.next().unwrap();
594        check_rule!(function_keyword_token, Rule::function_keyword);
595
596        let mut next_token = pair.next().unwrap();
597        let scope: TopScope = if next_token.as_rule() == Rule::scope_keyword {
598            let scope = Scope::from(next_token.as_str());
599            next_token = pair.next().unwrap();
600            scope.into()
601        } else {
602            self.default_scope.clone()
603        };
604
605        let function_name_token = next_token;
606        check_rule!(function_name_token, Rule::function_name);
607        let fname = function_name_token.as_str().to_ascii_lowercase();
608
609        let Some(mut next_token) = pair.next() else {
610            //empty function
611            return self.add_function(fname, ScriptBlock::empty(), scope);
612        };
613
614        let params = if next_token.as_rule() == Rule::parameter_list {
615            let param_list = self.parse_parameter_list(next_token)?;
616            if let Some(token) = pair.next() {
617                next_token = token;
618            } else {
619                return self.add_function(fname, ScriptBlock::empty(), scope);
620            }
621
622            param_list
623        } else {
624            Vec::new()
625        };
626        check_rule!(next_token, Rule::script_block);
627
628        let mut script_block = self.parse_script_block(next_token)?;
629
630        if script_block.params.0.is_empty() {
631            script_block = script_block.with_params(params);
632        }
633
634        self.add_function(fname, script_block, scope)
635    }
636
637    pub(crate) fn eval_if_statement(&mut self, token: Pair<'a>) -> ParserResult<Val> {
638        check_rule!(token, Rule::if_statement);
639
640        //collect tokens from each case
641        self.if_statement_collect_tokens(token.clone());
642
643        let mut pair = token.into_inner();
644        let condition_token = pair.next().unwrap();
645        let true_token = pair.next().unwrap();
646        let condition_val = self.eval_pipeline(condition_token.clone())?;
647        let res = if condition_val.cast_to_bool() {
648            self.eval_statement_block(true_token)?
649        } else if let Some(mut token) = pair.next() {
650            if token.as_rule() == Rule::elseif_clauses {
651                for else_if in token.into_inner() {
652                    let mut pairs = else_if.into_inner();
653                    let condition_token = pairs.next().unwrap();
654                    let statement_token = pairs.next().unwrap();
655                    let condition_val = self.eval_pipeline(condition_token)?;
656                    if condition_val.cast_to_bool() {
657                        return self.eval_statement_block(statement_token);
658                    }
659                }
660                let Some(token2) = pair.next() else {
661                    return Ok(Val::Null);
662                };
663                token = token2;
664            }
665            if token.as_rule() == Rule::else_condition {
666                let statement_token = token.into_inner().next().unwrap();
667                self.eval_statement_block(statement_token)?
668            } else {
669                Val::Null
670            }
671        } else {
672            Val::Null
673        };
674
675        Ok(res)
676    }
677
678    pub(crate) fn if_statement_collect_tokens(&mut self, token: Pair<'a>) {
679        //we want collect tokens from each case, but we need to preserve all variables
680        //to consider: maybe instead of collecting tokens, we should return whole
681        // deobfuscated if statement
682        if !self.collected.insert(token.as_str().to_string()) {
683            return;
684        }
685        let results = self.results.clone();
686        let current_variables = self.variables.clone();
687        if let Err(err) = self.impl_if_statement_collect_tokens(token.clone()) {
688            log::debug!("Error during if_statement_collect_tokens: {:?}", err);
689        }
690        self.variables = current_variables;
691        self.results = results;
692    }
693
694    pub(crate) fn impl_if_statement_collect_tokens(&mut self, token: Pair<'a>) -> ParserResult<()> {
695        check_rule!(token, Rule::if_statement);
696
697        let mut pair = token.into_inner();
698        let condition_token = pair.next().unwrap();
699        let true_token = pair.next().unwrap();
700        let _condition_val = self
701            .eval_pipeline(condition_token.clone())
702            .unwrap_or_default();
703        if let Err(err) = self.eval_statement_block(true_token) {
704            log::debug!(
705                "Error during if_statement_collect_tokens (true block): {:?}",
706                err
707            );
708        }
709        if let Some(mut token) = pair.next() {
710            if token.as_rule() == Rule::elseif_clauses {
711                for else_if in token.into_inner() {
712                    let mut pairs = else_if.into_inner();
713                    let condition_token = pairs.next().unwrap();
714                    let statement_token = pairs.next().unwrap();
715                    let _condition_val = self.eval_pipeline(condition_token).unwrap_or_default();
716
717                    if let Err(err) = self.eval_statement_block(statement_token) {
718                        log::debug!(
719                            "Error during if_statement_collect_tokens (else if block): {:?}",
720                            err
721                        );
722                    }
723                }
724                let Some(token2) = pair.next() else {
725                    return Ok(());
726                };
727                token = token2;
728            }
729            if token.as_rule() == Rule::else_condition {
730                let statement_token = token.into_inner().next().unwrap();
731                if let Err(err) = self.eval_statement_block(statement_token) {
732                    log::debug!(
733                        "Error during if_statement_collect_tokens (else block): {:?}",
734                        err
735                    );
736                }
737            }
738        }
739        Ok(())
740    }
741
742    pub(crate) fn statement_block_collect_tokens(&mut self, token: Pair<'a>) {
743        check_rule!(token, Rule::statement_block);
744        //we want collect tokens from each case, but we need to preserve all variables
745        //to consider: maybe instead of collecting tokens, we should return whole
746        // deobfuscated if statement
747        if !self.collected.insert(token.as_str().to_string()) {
748            return;
749        }
750        let results = self.results.clone();
751        let current_variables = self.variables.clone();
752        if let Err(err) = self.eval_statement_block(token.clone()) {
753            log::debug!("Error during if_statement_collect_tokens: {:?}", err);
754        }
755        self.variables = current_variables;
756        self.results = results;
757    }
758
759    fn eval_flow_control_statement(&mut self, token: Pair<'a>) -> ParserResult<Val> {
760        check_rule!(token, Rule::flow_control_statement);
761        let token = token.into_inner().next().unwrap();
762
763        Ok(match token.as_rule() {
764            Rule::flow_control_label_statement => Val::Null, //TODO
765            Rule::flow_control_pipeline_statement => {
766                let token = token.into_inner().next().unwrap();
767                //todo: throw, return or exit
768                if let Some(pipeline_token) = token.into_inner().next() {
769                    self.eval_pipeline(pipeline_token)?
770                } else {
771                    Val::Null
772                }
773            }
774            _ => unexpected_token!(token),
775        })
776    }
777
778    fn parse_switch_statement(&mut self, token: Pair<'a>) -> ParserResult<Val> {
779        check_rule!(token, Rule::switch_statement);
780        let mut pairs = token.into_inner();
781
782        let mut token = pairs.next().unwrap();
783        if Rule::switch_parameters == token.as_rule() {
784            token = pairs.next().unwrap();
785        }
786
787        let condition = match token.as_rule() {
788            Rule::pipeline => self.eval_pipeline(token).ok(),
789            Rule::switch_filename => None, //TODO: implement switch -file
790            _ => None,
791        };
792
793        for case_token in pairs {
794            check_rule!(case_token, Rule::switch_clause);
795            let v = self.parse_switch_case(case_token, &condition);
796            match v.len() {
797                0 => {}
798                1 => return Ok(v.into_iter().next().unwrap()),
799                _ => return Ok(Val::Array(v)),
800            }
801        }
802
803        Ok(Val::Null)
804    }
805
806    fn parse_switch_case(&mut self, token: Pair<'a>, switch_condition: &Option<Val>) -> Vec<Val> {
807        check_rule!(token, Rule::switch_clause);
808        let mut pairs = token.into_inner();
809
810        let switch_clause_condition = pairs.next().unwrap();
811        let clause_body = pairs.next().unwrap();
812        check_rule!(clause_body, Rule::statement_block);
813
814        //first collect tokens
815        self.statement_block_collect_tokens(clause_body.clone());
816
817        //now we can evaluate the condition
818        if switch_clause_condition
819            .as_str()
820            .eq_ignore_ascii_case("default")
821            && let Ok(result) = self.safe_eval_statements(clause_body.clone())
822        {
823            return result;
824        } else if switch_clause_condition.as_rule() == Rule::primary_expression
825            && let Some(condition) = switch_condition
826        {
827            let val = self
828                .eval_primary_expression(switch_clause_condition)
829                .unwrap_or_default();
830
831            if condition.eq(val, false).unwrap_or_default()
832                && let Ok(result) = self.safe_eval_statements(clause_body)
833            {
834                return result;
835            }
836        }
837        vec![]
838    }
839
840    fn parse_class_statement(&mut self, token: Pair<'a>) -> ParserResult<Val> {
841        check_rule!(token, Rule::class_statement);
842        let mut pair = token.into_inner();
843
844        let class_name_token = pair.next().unwrap();
845        check_rule!(class_name_token, Rule::simple_name);
846        let class_name = class_name_token.as_str().to_string();
847
848        let mut properties = ClassProperties::new();
849        let mut methods: HashMap<String, ScriptBlock> = HashMap::new();
850
851        for member_token in pair {
852            match member_token.as_rule() {
853                Rule::class_property_definition => {
854                    let prop_pair = member_token.into_inner();
855
856                    // we don't want care about attributes here. It's todo in future
857                    let mut prop_pair = prop_pair.skip_while(|p| p.as_rule() == Rule::attribute);
858
859                    let mut token = prop_pair.next().unwrap();
860                    let _is_static = if token.as_rule() == Rule::class_attribute_static {
861                        token = prop_pair.next().unwrap();
862                        true
863                    } else {
864                        false
865                    };
866
867                    let _is_hidden = if token.as_rule() == Rule::class_attribute_hidden {
868                        token = prop_pair.next().unwrap();
869                        true
870                    } else {
871                        false
872                    };
873
874                    let ttype = if token.as_rule() == Rule::type_literal {
875                        let ttype = self.get_valtype_from_type_literal(token)?;
876                        token = prop_pair.next().unwrap();
877                        Some(ttype)
878                    } else {
879                        None
880                    };
881                    check_rule!(token, Rule::variable);
882                    let var_name = Self::parse_variable(token)?;
883                    let default_val = if let Some(expression_token) = prop_pair.next() {
884                        Some(self.eval_expression(expression_token)?)
885                    } else {
886                        None
887                    };
888                    properties.add_property(var_name.name, ttype, default_val);
889                }
890                Rule::class_method_definition => {
891                    let prop_pair = member_token.into_inner();
892
893                    // we don't want care about attributes here. It's todo in future
894                    let mut prop_pair = prop_pair.skip_while(|p| p.as_rule() == Rule::attribute);
895
896                    let mut token = prop_pair.next().unwrap();
897                    let _is_static = if token.as_rule() == Rule::class_attribute_static {
898                        token = prop_pair.next().unwrap();
899                        true
900                    } else {
901                        false
902                    };
903
904                    let _is_hidden = if token.as_rule() == Rule::class_attribute_hidden {
905                        token = prop_pair.next().unwrap();
906                        true
907                    } else {
908                        false
909                    };
910
911                    let _ttype = if token.as_rule() == Rule::type_literal {
912                        let ttype = self.eval_type_literal(token)?.ttype();
913                        token = prop_pair.next().unwrap();
914                        Some(ttype)
915                    } else {
916                        None
917                    };
918                    check_rule!(token, Rule::simple_name);
919                    let method_name = token.as_str().to_ascii_lowercase();
920
921                    let mut token = prop_pair.next().unwrap();
922                    let parameters = if token.as_rule() == Rule::parameter_list {
923                        let params = self.parse_parameter_list(token)?;
924                        token = prop_pair.next().unwrap();
925                        params
926                    } else {
927                        vec![]
928                    };
929                    check_rule!(token, Rule::script_block);
930
931                    let method_name = MethodName::new(method_name.as_str(), &parameters);
932                    let script_block = self.parse_script_block(token)?.with_params(parameters);
933                    methods.insert(method_name.full_name().to_string(), script_block);
934                }
935                Rule::statement_terminator | Rule::simple_name => {}
936                _ => unexpected_token!(member_token),
937            }
938        }
939        let class_type = ClassType::new(class_name.clone(), properties, HashMap::new(), methods);
940        self.types_map.insert(
941            class_name.to_ascii_lowercase(),
942            Box::new(class_type.clone()),
943        );
944        Ok(Val::Null)
945    }
946
947    fn eval_statement(&mut self, token: Pair<'a>) -> ParserResult<Val> {
948        check_stack(0)?;
949        eval_step()?;
950        match token.as_rule() {
951            Rule::pipeline => self.eval_pipeline(token),
952            Rule::if_statement => self.eval_if_statement(token),
953            Rule::flow_control_statement => self.eval_flow_control_statement(token),
954            Rule::function_statement => self.parse_function_statement(token),
955            Rule::statement_terminator => Ok(Val::Null),
956            Rule::class_statement => self.parse_class_statement(token),
957            Rule::switch_statement => self.parse_switch_statement(token),
958            Rule::EOI => Ok(Val::Null),
959            _ => {
960                not_implemented!(token)
961            }
962        }
963    }
964
965    fn safe_eval_sub_expr(&mut self, token: Pair<'a>) -> ParserResult<Val> {
966        check_rule!(token, Rule::sub_expression);
967        let Some(inner_token) = token.into_inner().next() else {
968            return Ok(Val::Null);
969        };
970        let mut inner_val = self.eval_pipeline(inner_token)?;
971        if let Val::ScriptText(script) = &mut inner_val {
972            *script = format!("$({})", script);
973            //self.tokens.push(Token::SubExpression(script.clone()));
974        }
975        Ok(inner_val)
976    }
977
978    fn eval_statement_block(&mut self, token: Pair<'a>) -> ParserResult<Val> {
979        Ok(self
980            .safe_eval_statements(token)?
981            .iter()
982            .last()
983            .cloned()
984            .unwrap_or(Val::Null))
985    }
986
987    fn eval_statements(&mut self, token: Pair<'a>) -> ParserResult<Vec<Val>> {
988        //check_rule!(token, Rule::statements);
989        let pairs = token.into_inner();
990        let mut statements = vec![];
991
992        for token in pairs {
993            let s = self.eval_statement(token)?;
994            statements.push(s);
995        }
996        Ok(statements)
997    }
998
999    fn safe_eval_statements(&mut self, token: Pair<'a>) -> ParserResult<Vec<Val>> {
1000        //check_rule!(token, Rule::statements);
1001        let pairs = token.into_inner();
1002        let mut statements = vec![];
1003
1004        for token in pairs {
1005            match self.eval_statement(token.clone()) {
1006                Ok(s) => statements.push(s),
1007                Err(err) => {
1008                    self.errors.push(err);
1009                    statements.push(Val::ScriptText(token.as_str().to_string()));
1010                }
1011            }
1012        }
1013        Ok(statements)
1014    }
1015
1016    fn parse_dq(&mut self, token: Pair<'a>) -> ParserResult<String> {
1017        let mut res_str = String::new();
1018        let pairs = token.into_inner();
1019        for token in pairs {
1020            let token = token.into_inner().next().unwrap();
1021            let token_str = token.as_str();
1022            let res = match token.as_rule() {
1023                Rule::variable => self.get_variable(token).map(|v| v.cast_to_string()),
1024                Rule::sub_expression => self.safe_eval_sub_expr(token).map(|v| v.cast_to_string()),
1025                Rule::backtick_escape => Ok(token
1026                    .as_str()
1027                    .strip_prefix("`")
1028                    .unwrap_or_default()
1029                    .to_string()),
1030                _ => Ok(token.as_str().to_string()),
1031            };
1032            match res {
1033                Ok(s) => res_str.push_str(s.as_str()),
1034                Err(err) => {
1035                    self.errors.push(err);
1036                    res_str.push_str(token_str);
1037                }
1038            }
1039        }
1040        Ok(res_str)
1041    }
1042
1043    fn eval_string_literal(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1044        check_rule!(token, Rule::string_literal);
1045        let mut pair = token.into_inner();
1046        let token = pair.next().unwrap();
1047        let cloned_token = token.clone();
1048
1049        let mut is_expandable = false;
1050        let res = match token.as_rule() {
1051            Rule::doublequoted_string_literal | Rule::doublequoted_multiline_string_literal => {
1052                is_expandable = true;
1053                self.parse_dq(token)?
1054            }
1055            Rule::singlequoted_string_literal => {
1056                let token_string = token.as_str().to_string();
1057                let stripped_prefix = token_string
1058                    .strip_prefix("'")
1059                    .unwrap_or(token_string.as_str());
1060                let stripped_suffix = stripped_prefix.strip_suffix("'").unwrap_or(stripped_prefix);
1061                stripped_suffix.to_string()
1062            }
1063            Rule::singlequoted_multiline_string_literal => {
1064                let mut res_str = String::new();
1065                let pairs = token.into_inner();
1066                for token in pairs {
1067                    res_str.push_str(token.as_str());
1068                }
1069                res_str
1070            }
1071            _ => unexpected_token!(token),
1072        };
1073        let ps_token = if is_expandable {
1074            Token::string_expandable(cloned_token.as_str().to_string(), res.clone())
1075        } else {
1076            Token::String(res.clone())
1077        };
1078        self.tokens.push(ps_token);
1079
1080        Ok(Val::String(res.into()))
1081    }
1082
1083    fn get_variable(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1084        check_rule!(token, Rule::variable);
1085        let var_name = Self::parse_variable(token)?;
1086        let Some(var) = self.variables.get(&var_name, &self.types_map) else {
1087            return Err(ParserError::VariableError(VariableError::NotDefined(
1088                var_name.name,
1089            )));
1090        };
1091        Ok(var)
1092    }
1093
1094    fn parse_scoped_variable(token: Pair<'a>) -> ParserResult<VarName> {
1095        //can be scoped or splatted
1096        let mut pairs = token.into_inner();
1097        let mut token = pairs.next().unwrap();
1098
1099        let scope = if token.as_rule() == Rule::scope_keyword {
1100            let scope = token.as_str().to_ascii_lowercase();
1101            token = pairs.next().unwrap();
1102            check_rule!(token, Rule::var_name);
1103            Some(Scope::from(scope.as_str()))
1104        } else {
1105            None
1106        };
1107        Ok(VarName::new(scope, token.as_str().to_ascii_lowercase()))
1108    }
1109
1110    fn skip_value_access(&mut self, token: Pair<'a>) -> ParserResult<()> {
1111        check_rule!(token, Rule::value_access);
1112        let mut pair = token.into_inner();
1113        let token = pair.next().unwrap();
1114        let mut val = self.eval_value(token)?;
1115        if let Some(access) = pair.next() {
1116            let _ = self.eval_element_access_ref(access, &mut val)?;
1117        }
1118        Err(ParserError::Skip)
1119    }
1120
1121    // fn get_assignable_variable<'b>(&mut self, pairs: Pairs<'a>, object: &'b mut
1122    // Val) -> ParserResult<&'b mut Val> {     let mut var = object;
1123    //     for token in pairs {
1124    //             let tmp = self.variable_access(token, &mut var)?;
1125    //             var = tmp;
1126    //     }
1127    //     Ok(var)
1128    // }
1129
1130    fn parse_assignable_variable(
1131        &mut self,
1132        token: Pair<'a>,
1133    ) -> ParserResult<(VarName, Option<Pairs<'a>>)> {
1134        check_rule!(token, Rule::assignable_variable);
1135        let mut pair = token.into_inner();
1136        let token = pair.next().unwrap();
1137        match token.as_rule() {
1138            Rule::variable => {
1139                let var_name = Self::parse_variable(token)?;
1140
1141                Ok((var_name, None))
1142            }
1143            Rule::variable_access => {
1144                let mut pairs = token.into_inner();
1145                let var_token = pairs.next().unwrap();
1146                let var_name = Self::parse_variable(var_token)?;
1147                // let mut object = &mut var;
1148                // for token in pairs {
1149                //     object = self.variable_access(token, &mut object)?;
1150                // }
1151                Ok((var_name, Some(pairs)))
1152            }
1153            Rule::value_access => self
1154                .skip_value_access(token)
1155                .map(|()| (Default::default(), None)),
1156            _ => unexpected_token!(token),
1157        }
1158    }
1159
1160    fn parse_variable(token: Pair<'a>) -> ParserResult<VarName> {
1161        check_rule!(token, Rule::variable);
1162        let mut pair = token.into_inner();
1163        let token = pair.next().unwrap();
1164
1165        Ok(match token.as_rule() {
1166            Rule::special_variable => {
1167                VarName::new_with_scope(Scope::Special, token.as_str().to_string())
1168            }
1169            Rule::parenthesized_variable => {
1170                Self::parse_variable(token.into_inner().next().unwrap())?
1171            }
1172            Rule::braced_variable => {
1173                let token = token.into_inner().next().unwrap();
1174                let var = token.as_str().to_ascii_lowercase();
1175                let splits: Vec<&str> = var.split(":").collect();
1176                if splits.len() == 2 {
1177                    VarName::new_with_scope(Scope::from(splits[0]), splits[1].to_string())
1178                } else {
1179                    VarName::new(None, var)
1180                }
1181            }
1182            Rule::scoped_variable => Self::parse_scoped_variable(token)?,
1183            _ => unexpected_token!(token),
1184        })
1185    }
1186
1187    fn eval_pre_arithmetic(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1188        check_rule!(token, Rule::pre_arithmetic);
1189        let mut pair = token.into_inner();
1190        let token = pair.next().unwrap();
1191
1192        let res = match token.as_rule() {
1193            Rule::pre_plus_expression => {
1194                let token = token.into_inner().next().unwrap();
1195                match token.as_rule() {
1196                    Rule::variable => {
1197                        let var_name = Self::parse_variable(token)?;
1198                        self.variables
1199                            .get(&var_name, &self.types_map)
1200                            .unwrap_or_default()
1201                    }
1202                    Rule::parenthesized_expression => self.eval_parenthesized_expression(token)?,
1203                    _ => unexpected_token!(token),
1204                }
1205            }
1206            Rule::pre_minus_expression => {
1207                let token = token.into_inner().next().unwrap();
1208                let mut v = Val::default();
1209                let to_sub = match token.as_rule() {
1210                    Rule::variable => {
1211                        let var_name = Self::parse_variable(token)?;
1212                        self.variables
1213                            .get(&var_name, &self.types_map)
1214                            .unwrap_or_default()
1215                    }
1216                    Rule::parenthesized_expression => self.eval_parenthesized_expression(token)?,
1217                    _ => unexpected_token!(token),
1218                };
1219                v.sub(to_sub)?;
1220                v
1221            }
1222            Rule::pre_inc_expression => {
1223                let variable_token = token.into_inner().next().unwrap();
1224                let var_name = Self::parse_variable(variable_token)?;
1225                let mut var = self
1226                    .variables
1227                    .get(&var_name, &self.types_map)
1228                    .unwrap_or_default();
1229                var.inc()?;
1230
1231                self.variables.set(&var_name, var.clone())?;
1232                var
1233            }
1234            Rule::pre_dec_expression => {
1235                let variable_token = token.into_inner().next().unwrap();
1236                let var_name = Self::parse_variable(variable_token)?;
1237                let mut var = self
1238                    .variables
1239                    .get(&var_name, &self.types_map)
1240                    .unwrap_or_default();
1241                var.dec()?;
1242
1243                self.variables.set(&var_name, var.clone())?;
1244                var
1245            }
1246            _ => unexpected_token!(token),
1247        };
1248
1249        Ok(res)
1250    }
1251
1252    fn eval_expression_with_unary_operator(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1253        check_rule!(token, Rule::expression_with_unary_operator);
1254        let mut pair = token.into_inner();
1255        let token = pair.next().unwrap();
1256
1257        let res = match token.as_rule() {
1258            Rule::pre_arithmetic => self.eval_pre_arithmetic(token)?,
1259            Rule::cast_expression => self.eval_cast_expression(token)?,
1260            Rule::negate_op => {
1261                let unary_token = pair.next().unwrap();
1262                let unary = self.eval_unary_exp(unary_token)?;
1263                Val::Bool(!unary.cast_to_bool())
1264            }
1265            Rule::bitwise_negate_op => {
1266                let unary_token = pair.next().unwrap();
1267                let unary = self.eval_unary_exp(unary_token)?;
1268                Val::Int(!unary.cast_to_int()?)
1269            }
1270            _ => unexpected_token!(token),
1271        };
1272
1273        Ok(res)
1274    }
1275
1276    fn eval_argument_list(&mut self, token: Pair<'a>) -> ParserResult<Vec<Val>> {
1277        check_rule!(token, Rule::argument_list);
1278        let mut pairs = token.into_inner();
1279        let token = pairs.next().unwrap();
1280
1281        self.skip_error += 1;
1282
1283        let arg = self.eval_expression(token.clone())?;
1284        self.skip_error -= 1;
1285
1286        if let Val::Array(vec) = arg {
1287            Ok(vec)
1288        } else {
1289            Ok(vec![arg])
1290        }
1291    }
1292
1293    fn eval_member_access(&mut self, token: Pair<'a>) -> ParserResult<String> {
1294        //check_rule!(token, Rule::member_access);
1295        let member_name_token = token.into_inner().next().unwrap();
1296        let member_name = member_name_token.as_str().to_ascii_lowercase();
1297
1298        Ok(member_name)
1299    }
1300
1301    fn method_is_static(&mut self, token: Pair<'a>) -> bool {
1302        check_rule!(token, Rule::method_invocation);
1303        let mut pairs = token.into_inner();
1304
1305        let access = pairs.next().unwrap();
1306        match access.as_rule() {
1307            Rule::member_access => false,
1308            Rule::static_access => true,
1309            _ => unexpected_token!(access),
1310        }
1311    }
1312
1313    fn eval_method_invocation(
1314        &mut self,
1315        token: Pair<'a>,
1316        object: &Val,
1317    ) -> ParserResult<(String, Vec<Val>)> {
1318        check_rule!(token, Rule::method_invocation);
1319        let token_string = token.as_str().to_string();
1320
1321        let mut pairs = token.into_inner();
1322
1323        let access = pairs.next().unwrap();
1324        let method_name = self.eval_member_access(access)?;
1325
1326        let args = if let Some(token) = pairs.next() {
1327            check_rule!(token, Rule::argument_list);
1328            match self.eval_argument_list(token) {
1329                Ok(args) => args,
1330                Err(e) => {
1331                    log::debug!("eval_argument_list error: {:?}", e);
1332
1333                    //nevertheless push the function token
1334                    self.tokens.push(Token::method(
1335                        token_string.clone(),
1336                        object.clone().into(),
1337                        method_name.clone(),
1338                        Vec::new(),
1339                    ));
1340                    Err(e)?
1341                }
1342            }
1343        } else {
1344            Vec::new()
1345        };
1346
1347        self.tokens.push(Token::method(
1348            token_string,
1349            object.clone().into(),
1350            method_name.clone(),
1351            args.clone().iter().map(|arg| arg.clone().into()).collect(),
1352        ));
1353        Ok((method_name, args))
1354    }
1355
1356    fn eval_element_access_ref<'b>(
1357        &mut self,
1358        token: Pair<'a>,
1359        object: &'b mut Val,
1360    ) -> ParserResult<&'b mut Val> {
1361        let mut pairs = token.into_inner();
1362        let index_token = pairs.next().unwrap();
1363        check_rule!(index_token, Rule::expression);
1364        let index = self.eval_expression(index_token)?;
1365        Ok(object.get_index_ref(index)?)
1366    }
1367
1368    fn eval_element_access(&mut self, token: Pair<'a>, object: &Val) -> ParserResult<Val> {
1369        let key = (token.as_str().as_ptr() as usize, token.as_str().len());
1370        let mut pairs = token.into_inner();
1371        let index_token = pairs.next().unwrap();
1372        check_rule!(index_token, Rule::expression);
1373        let index = self.eval_expression(index_token)?;
1374        object.get_index(index.clone()).map_err(|err| {
1375            self.failed_index = Some((key, index));
1376            err.into()
1377        })
1378    }
1379
1380    fn variable_access<'b>(
1381        &mut self,
1382        token: Pair<'a>,
1383        object: &'b mut Val,
1384    ) -> ParserResult<&'b mut Val> {
1385        fn get_member_name(token: Pair<'_>) -> &'_ str {
1386            token.into_inner().next().unwrap().as_str()
1387        }
1388        match token.as_rule() {
1389            Rule::static_access => {
1390                //todo
1391                Err(ParserError::NotImplemented(
1392                    "modificable static_member".into(),
1393                ))
1394            }
1395            Rule::member_access => Ok(object.member(get_member_name(token))?),
1396            Rule::element_access => Ok(self.eval_element_access_ref(token, object)?),
1397            _ => unexpected_token!(token),
1398        }
1399    }
1400
1401    fn value_access(&mut self, token: Pair<'a>, object: &mut Val) -> ParserResult<Val> {
1402        fn get_member_name(token: Pair<'_>) -> &'_ str {
1403            token.into_inner().next().unwrap().as_str()
1404        }
1405        Ok(match token.as_rule() {
1406            Rule::static_access => {
1407                let Val::RuntimeType(rt) = object else {
1408                    return Err(RuntimeError::MethodNotFound(
1409                        "Readonly static members can only be accessed on types".to_string(),
1410                    )
1411                    .into());
1412                };
1413                rt.readonly_static_member(get_member_name(token))?
1414            }
1415            Rule::member_access => object.readonly_member(get_member_name(token))?.clone(),
1416            Rule::method_invocation => {
1417                let static_method = self.method_is_static(token.clone());
1418                let (function_name, args) = self.eval_method_invocation(token, object)?;
1419                let mangled_name = MethodName::from_args(function_name.as_str(), &args);
1420
1421                if static_method {
1422                    let Val::RuntimeType(rt) = object else {
1423                        return Err(RuntimeError::MethodNotFound(
1424                            "Static method can be called only on type".to_string(),
1425                        )
1426                        .into());
1427                    };
1428
1429                    let mut call = rt.static_method(mangled_name)?;
1430                    call(args)?
1431                } else {
1432                    let mut call = object.method(mangled_name)?;
1433                    call(object, args)?
1434                }
1435            }
1436            Rule::element_access => self.eval_element_access(token, object)?,
1437            _ => unexpected_token!(token),
1438        })
1439    }
1440
1441    fn eval_value_access(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1442        check_rule!(token, Rule::value_access);
1443        let mut pairs = token.into_inner();
1444        let token = pairs.next().unwrap();
1445
1446        let mut object = self.eval_value(token)?;
1447        for token in pairs {
1448            object = self.value_access(token, &mut object)?;
1449        }
1450        log::debug!("Success eval_access: {:?}", object);
1451        Ok(object)
1452    }
1453
1454    fn parse_access(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1455        check_rule!(token, Rule::value_access);
1456        let mut pairs = token.into_inner();
1457        let token = pairs.next().unwrap();
1458
1459        let mut object = self
1460            .eval_value(token.clone())
1461            .map(|v| v.cast_to_script())
1462            .unwrap_or(token.as_str().to_string());
1463
1464        for token in pairs {
1465            match token.as_rule() {
1466                Rule::static_access => {
1467                    object.push_str(token.as_str());
1468                }
1469                Rule::member_access => {
1470                    object.push_str(token.as_str());
1471                }
1472                Rule::method_invocation => {
1473                    let static_method = self.method_is_static(token.clone());
1474                    let (method_name, args) = self
1475                        .eval_method_invocation(token.clone(), &Val::ScriptText(object.clone()))?;
1476                    log::trace!("Method: {:?} {:?}", &method_name, &args);
1477
1478                    let separator = if static_method { "::" } else { "." };
1479                    object = format!(
1480                        "{}{separator}{}({})",
1481                        object,
1482                        method_name.to_ascii_lowercase(),
1483                        args.iter()
1484                            .map(|arg| arg.cast_to_script())
1485                            .collect::<Vec<String>>()
1486                            .join(", ")
1487                    )
1488                }
1489                Rule::element_access => {
1490                    let key = (token.as_str().as_ptr() as usize, token.as_str().len());
1491                    let index = match self.failed_index.take_if(|(failed_key, _)| *failed_key == key) {
1492                        Some((_, index)) => index,
1493                        _ => {
1494                            let mut pairs = token.into_inner();
1495                            let index_token = pairs.next().unwrap();
1496                            check_rule!(index_token, Rule::expression);
1497                            self.eval_expression(index_token)?
1498                        }
1499                    };
1500                    object = format!("{}[{}]", object, index);
1501                }
1502                _ => unexpected_token!(token),
1503            }
1504        }
1505        Ok(Val::String(object.into()))
1506    }
1507
1508    fn eval_primary_expression(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1509        check_rule!(token, Rule::primary_expression);
1510        let mut pair = token.into_inner();
1511        let token = pair.next().unwrap();
1512        let res = match token.as_rule() {
1513            Rule::value_access if token.clone().into_inner().count() == 1 => {
1514                self.eval_value(token.into_inner().next().unwrap())?
1515            }
1516            Rule::value_access => match self.eval_value_access(token.clone()) {
1517                Ok(res) => res,
1518                Err(ParserError::NestingTooDeep) => Err(ParserError::NestingTooDeep)?,
1519                Err(err) => {
1520                    log::debug!("eval_access error: {:?}", err);
1521                    self.errors.push(err);
1522                    self.parse_access(token)?
1523                }
1524            },
1525            Rule::value => self.eval_value(token)?,
1526            Rule::post_inc_expression => {
1527                let variable_token = token.into_inner().next().unwrap();
1528                let var_name = Self::parse_variable(variable_token)?;
1529                let mut var = self
1530                    .variables
1531                    .get(&var_name, &self.types_map)
1532                    .unwrap_or_default();
1533                let var_to_return = var.clone();
1534
1535                var.inc()?;
1536                self.variables.set(&var_name, var.clone())?;
1537
1538                //if var_to_return.ttype() ==
1539                var_to_return
1540            }
1541            Rule::post_dec_expression => {
1542                let variable_token = token.into_inner().next().unwrap();
1543                let var_name = Self::parse_variable(variable_token)?;
1544                let mut var = self
1545                    .variables
1546                    .get(&var_name, &self.types_map)
1547                    .unwrap_or_default();
1548                let var_to_return = var.clone();
1549
1550                var.dec()?;
1551                self.variables.set(&var_name, var.clone())?;
1552
1553                var_to_return
1554            }
1555            _ => unexpected_token!(token),
1556        };
1557
1558        Ok(res)
1559    }
1560
1561    fn get_valtype_from_type_literal(&mut self, token: Pair<'a>) -> ParserResult<ValType> {
1562        let type_literal = self.parse_type_literal(token)?;
1563        Ok(ValType::cast(type_literal.as_str(), &self.types_map)?)
1564    }
1565
1566    fn eval_type_literal(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1567        let type_literal = self.parse_type_literal(token)?;
1568        match ValType::runtime_type_from_str(type_literal.as_str(), &self.types_map) {
1569            Ok(val_type) => Ok(val_type),
1570            Err(err) => {
1571                self.errors.push(err.into());
1572                Ok(Val::Null)
1573            }
1574        }
1575    }
1576
1577    fn parse_type_literal(&mut self, token: Pair<'a>) -> ParserResult<String> {
1578        check_rule!(token, Rule::type_literal);
1579
1580        let token = token.into_inner().next().unwrap();
1581        check_rule!(token, Rule::type_spec);
1582        let type_literal = token.as_str().to_ascii_lowercase();
1583        self.tokens.push(Token::type_literal(type_literal.clone()));
1584        Ok(type_literal)
1585    }
1586
1587    fn parse_script_block(&mut self, token: Pair<'a>) -> ParserResult<ScriptBlock> {
1588        check_rule!(token, Rule::script_block);
1589
1590        let raw_text = token.as_str().to_string();
1591
1592        let mut pairs = token.into_inner();
1593        let Some(token) = pairs.next() else {
1594            return Ok(ScriptBlock::new(vec![], String::new(), raw_text));
1595        };
1596
1597        let params = self.parse_script_param_block(token.clone())?;
1598        //let params_str = token.as_str().to_string();
1599
1600        let script_body = if let Some(token) = pairs.next() {
1601            check_rule!(token, Rule::script_block_body);
1602            token.as_str().to_string()
1603        } else {
1604            String::new()
1605        };
1606        //todo is it necessary?
1607        // Ok(if let Ok(deobfuscated_body) =
1608        // self.deobfuscate_script(&script_body) {
1609        //     ScriptBlock::new(params, deobfuscated_body.clone(),
1610        // format!("{};{}", params_str, deobfuscated_body)) } else {
1611        //     ScriptBlock::new(params, script_body, raw_text)
1612        // })
1613        self.script_block_collect_tokens(&script_body);
1614
1615        Ok(ScriptBlock::new(params, script_body, raw_text))
1616    }
1617
1618    pub(crate) fn script_block_collect_tokens(&mut self, script_body: &str) {
1619        //we want collect tokens from each case, but we need to preserve all variables
1620        //to consider: maybe instead of collecting tokens, we should return whole
1621        // deobfuscated if statement
1622        if !self.collected.insert(script_body.to_string()) {
1623            return;
1624        }
1625        let results = self.results.clone();
1626        let current_variables = self.variables.clone();
1627        let errors = self.errors.clone();
1628        if let Err(err) = self.parse_subscript(script_body) {
1629            log::debug!("Error during script_block_collect_tokens: {:?}", err);
1630        }
1631        self.variables = current_variables;
1632        self.results = results;
1633        self.errors = errors;
1634    }
1635
1636    fn parse_script_block_expression(&mut self, token: Pair<'a>) -> ParserResult<ScriptBlock> {
1637        check_rule!(token, Rule::script_block_expression);
1638        let mut pairs = token.into_inner();
1639        self.parse_script_block(pairs.next().unwrap())
1640    }
1641
1642    fn eval_hash_key(&mut self, token: Pair<'a>) -> ParserResult<String> {
1643        check_rule!(token, Rule::key_expression);
1644        let mut pairs = token.into_inner();
1645        let key_token = pairs.next().unwrap();
1646
1647        Ok(match key_token.as_rule() {
1648            Rule::simple_name => key_token.as_str().to_ascii_lowercase(),
1649            Rule::unary_exp => self
1650                .eval_unary_exp(key_token)?
1651                .cast_to_string()
1652                .to_ascii_lowercase(),
1653            _ => unexpected_token!(key_token),
1654        })
1655    }
1656
1657    fn eval_hash_entry(&mut self, token: Pair<'a>) -> ParserResult<(String, Val)> {
1658        check_rule!(token, Rule::hash_entry);
1659
1660        let mut pairs = token.into_inner();
1661        let token_key = pairs.next().unwrap();
1662        let token_value = pairs.next().unwrap();
1663        let value = match token_value.as_rule() {
1664            //Rule::statement => self.eval_statement(token_value)?,
1665            Rule::type_literal => self.eval_type_literal(token_value)?,
1666            _ => self.eval_statement(token_value)?,
1667        };
1668
1669        Ok((self.eval_hash_key(token_key)?, value))
1670    }
1671
1672    fn eval_hash_literal(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1673        check_rule!(token, Rule::hash_literal_expression);
1674        let pairs = token.into_inner();
1675        let mut hash = HashMap::new();
1676        for token in pairs {
1677            let (key, value) = self.eval_hash_entry(token)?;
1678            hash.insert(key, value);
1679        }
1680        Ok(Val::HashTable(hash))
1681    }
1682
1683    fn eval_parenthesized_expression(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1684        check_rule!(token, Rule::parenthesized_expression);
1685        let token = token.into_inner().next().unwrap();
1686        self.safe_eval_pipeline(token)
1687    }
1688
1689    fn eval_value(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1690        check_rule!(token, Rule::value);
1691        let mut pair = token.into_inner();
1692        let token = pair.next().unwrap();
1693
1694        let res = match token.as_rule() {
1695            Rule::parenthesized_expression => self.eval_parenthesized_expression(token)?,
1696            Rule::sub_expression | Rule::array_expression => {
1697                let statements = self.eval_statements(token)?;
1698                if statements.len() == 1 {
1699                    if let Val::Array(_) = statements[0] {
1700                        statements[0].clone()
1701                    } else {
1702                        Val::Array(statements)
1703                    }
1704                } else {
1705                    Val::Array(statements)
1706                }
1707            }
1708            Rule::script_block_expression => {
1709                Val::ScriptBlock(self.parse_script_block_expression(token)?)
1710            }
1711            Rule::hash_literal_expression => self.eval_hash_literal(token)?,
1712            Rule::string_literal => self.eval_string_literal(token)?,
1713            Rule::number_literal => self.eval_number_literal(token)?,
1714            Rule::type_literal => self.eval_type_literal(token)?,
1715            Rule::variable => self.get_variable(token)?,
1716            _ => unexpected_token!(token),
1717        };
1718        log::debug!("eval_value - res: {:?}", res);
1719        Ok(res)
1720    }
1721
1722    fn eval_number_literal(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1723        check_rule!(token, Rule::number_literal);
1724        let mut negate = false;
1725        let mut pairs = token.into_inner();
1726        let mut token = pairs.next().unwrap();
1727
1728        //first handle prefix sign: + or -
1729        if token.as_rule() == Rule::minus {
1730            negate = true;
1731            token = pairs.next().unwrap();
1732        } else if token.as_rule() == Rule::plus {
1733            token = pairs.next().unwrap();
1734        }
1735
1736        let mut val = self.eval_number(token)?;
1737
1738        if negate {
1739            val.neg()?;
1740        }
1741
1742        if let Some(unit) = pairs.next() {
1743            let unit = unit.as_str().to_ascii_lowercase();
1744            let unit_int = match unit.as_str() {
1745                "k" => 1024,
1746                "m" => 1024 * 1024,
1747                "g" => 1024 * 1024 * 1024,
1748                "t" => 1024 * 1024 * 1024 * 1024,
1749                "p" => 1024 * 1024 * 1024 * 1024 * 1024,
1750                _ => 1,
1751            };
1752            val.mul(Val::Int(unit_int))?;
1753        }
1754        Ok(val)
1755    }
1756
1757    fn eval_number(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1758        check_rule!(token, Rule::number);
1759        let mut pairs = token.into_inner();
1760        let token = pairs.next().unwrap();
1761        let v = match token.as_rule() {
1762            Rule::decimal_integer => {
1763                let int_val = token.into_inner().next().unwrap();
1764                Val::Int(int_val.as_str().parse::<i64>().unwrap())
1765            }
1766            Rule::hex_integer => {
1767                let int_val = token.into_inner().next().unwrap();
1768                Val::Int(i64::from_str_radix(int_val.as_str(), 16).unwrap())
1769            }
1770            Rule::float => {
1771                let float_str = token.as_str().trim();
1772                Val::Float(float_str.parse::<f64>()?)
1773                //todo: handle all border cases
1774            }
1775            _ => unexpected_token!(token),
1776        };
1777        Ok(v)
1778    }
1779
1780    fn eval_unary_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1781        check_rule!(token, Rule::unary_exp);
1782        let token = token.into_inner().next().unwrap();
1783        match token.as_rule() {
1784            Rule::expression_with_unary_operator => self.eval_expression_with_unary_operator(token),
1785            Rule::primary_expression => self.eval_primary_expression(token),
1786            _ => unexpected_token!(token),
1787        }
1788    }
1789
1790    fn eval_array_literal_exp_special_case(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1791        check_rule!(token, Rule::array_literal_exp_special_case);
1792        let mut pairs = token.into_inner();
1793        let token = pairs.next().unwrap();
1794
1795        let val = self.eval_array_literal_exp(token)?;
1796        Ok(Val::Array(vec![val]))
1797    }
1798
1799    fn safe_parse_arg(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1800        Ok(if self.skip_error > 0 {
1801            match self.eval_unary_exp(token.clone()) {
1802                Ok(val) => val,
1803                Err(err) => {
1804                    self.errors.push(err);
1805                    Val::ScriptText(token.as_str().to_string())
1806                }
1807            }
1808        } else {
1809            self.eval_unary_exp(token.clone())?
1810        })
1811    }
1812
1813    fn eval_array_literal_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1814        check_rule!(token, Rule::array_literal_exp);
1815        let mut arr = Vec::new();
1816        let mut pairs = token.into_inner();
1817        let token = pairs.next().unwrap();
1818
1819        //if array literal starts with ',' we must eval single element as array too
1820        if let Rule::array_literal_exp_special_case = token.as_rule() {
1821            return self.eval_array_literal_exp_special_case(token);
1822        }
1823
1824        arr.push(self.safe_parse_arg(token)?);
1825        for token in pairs {
1826            arr.push(self.safe_parse_arg(token)?);
1827        }
1828
1829        Ok(if arr.len() == 1 {
1830            arr[0].clone()
1831        } else {
1832            Val::Array(arr)
1833        })
1834    }
1835
1836    fn eval_range_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1837        fn range(mut left: i64, right: i64) -> ParserResult<Vec<Val>> {
1838            if left.abs_diff(right) >= value::MAX_ARRAY_LEN as u64 {
1839                Err(ValError::ArgumentOutOfRange("..".to_string(), right))?
1840            }
1841            let mut v = Vec::new();
1842            if left <= right {
1843                loop {
1844                    v.push(left);
1845                    if left == right {
1846                        break;
1847                    }
1848                    left += 1;
1849                }
1850            } else {
1851                loop {
1852                    v.push(left);
1853                    if left == right {
1854                        break;
1855                    }
1856                    left -= 1;
1857                }
1858            }
1859            Ok(v.into_iter().map(Val::Int).collect())
1860        }
1861        check_rule!(token, Rule::range_exp);
1862        let mut pairs = token.into_inner();
1863        let mut token = pairs.next().unwrap();
1864
1865        let _is_minus = if let Rule::additive_op = token.as_rule() {
1866            token = pairs.next().unwrap();
1867            true
1868        } else {
1869            false
1870        };
1871
1872        let res = match token.as_rule() {
1873            Rule::decimal_integer => {
1874                let int_val = token.into_inner().next().unwrap();
1875                let left = int_val.as_str().parse::<i64>().map_err(|_| {
1876                    ValError::InvalidCast(int_val.as_str().to_string(), "Int64".to_string())
1877                })?;
1878                let mut token = pairs.next().unwrap();
1879                let _is_minus = if let Rule::additive_op = token.as_rule() {
1880                    token = pairs.next().unwrap();
1881                    true
1882                } else {
1883                    false
1884                };
1885                let right = self.eval_array_literal_exp(token)?.cast_to_int()?;
1886                Val::Array(range(left, right)?)
1887            }
1888            Rule::array_literal_exp => {
1889                let res = self.eval_array_literal_exp(token)?;
1890                if let Some(token) = pairs.next() {
1891                    let left = res.cast_to_int()?;
1892                    let right = self.eval_array_literal_exp(token)?.cast_to_int()?;
1893                    Val::Array(range(left, right)?)
1894                } else {
1895                    res
1896                }
1897            }
1898            _ => unexpected_token!(token),
1899        };
1900
1901        Ok(res)
1902    }
1903
1904    fn eval_format_impl(
1905        &mut self,
1906        format: Vec<Val>,
1907        mut pairs: Pairs<'a>,
1908    ) -> ParserResult<Option<Vec<Val>>> {
1909        Ok(if let Some(token) = pairs.next() {
1910            let second_fmt = self.eval_range_exp(token)?;
1911            let format_arg =
1912                if let Some(vec_args) = self.eval_format_impl(second_fmt.cast_to_array(), pairs)? {
1913                    vec_args
1914                } else {
1915                    second_fmt.into_array()
1916                };
1917
1918            Some(
1919                formatting::format_ps_vec(format, &format_arg)?
1920                    .iter()
1921                    .map(|v| Val::String(v.into()))
1922                    .collect(),
1923            )
1924        } else {
1925            None
1926        })
1927    }
1928
1929    fn eval_format_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1930        check_rule!(token, Rule::format_exp);
1931        let mut pairs = token.into_inner();
1932        let format = self.eval_range_exp(pairs.next().unwrap())?;
1933        if let Some(vec_args) = self.eval_format_impl(format.cast_to_array(), pairs)? {
1934            Ok(Val::String(
1935                vec_args
1936                    .iter()
1937                    .map(|v| v.cast_to_string())
1938                    .collect::<Vec<_>>()
1939                    .join(" ")
1940                    .into(),
1941            ))
1942        } else {
1943            Ok(format)
1944        }
1945    }
1946
1947    fn eval_mult(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1948        check_rule!(token, Rule::multiplicative_exp);
1949        let mut pairs = token.into_inner();
1950        let mut res = self.eval_format_exp(pairs.next().unwrap())?;
1951        while let Some(op) = pairs.next() {
1952            let Some(fun) = ArithmeticPred::get(op.as_str()) else {
1953                log::error!("No arithmetic function for operator: {}", op.as_str());
1954                return Err(ParserError::NotImplemented(format!(
1955                    "No arithmetic function for operator: {}",
1956                    op.as_str()
1957                )));
1958            };
1959
1960            let postfix = pairs.next().unwrap();
1961            let right_op = self.eval_format_exp(postfix)?;
1962            res = fun(res, right_op)?;
1963        }
1964
1965        Ok(res)
1966    }
1967
1968    fn eval_additive(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1969        check_rule!(token, Rule::additive_exp);
1970
1971        let mut pairs = token.into_inner();
1972        let token = pairs.next().unwrap();
1973        let mut res = match token.as_rule() {
1974            Rule::multiplicative_exp => self.eval_mult(token)?,
1975            _ => unexpected_token!(token),
1976        };
1977        while let Some(op) = pairs.next() {
1978            //check_rule!(op, Rule::additive_op); plus or minus
1979            let Some(fun) = ArithmeticPred::get(op.as_str()) else {
1980                log::error!("No arithmetic function for operator: {}", op.as_str());
1981                return Err(ParserError::NotImplemented(format!(
1982                    "No arithmetic function for operator: {}",
1983                    op.as_str()
1984                )));
1985            };
1986
1987            let mult = pairs.next().unwrap();
1988            let right_op = match mult.as_rule() {
1989                Rule::multiplicative_exp => self.eval_mult(mult)?,
1990                Rule::pre_arithmetic => self.eval_pre_arithmetic(mult)?,
1991                _ => unexpected_token!(mult),
1992            };
1993            res = fun(res, right_op)?;
1994        }
1995
1996        Ok(res)
1997    }
1998
1999    fn eval_split_special_case(
2000        &mut self,
2001        script_block: ScriptBlock,
2002        input: Val,
2003    ) -> ParserResult<Vec<String>> {
2004        let mut res_vec = vec![];
2005        let mut parts = String::new();
2006        let input_str = input.cast_to_string();
2007        let characters = input_str.chars();
2008
2009        // filtered_elements.join("")
2010        for ch in characters {
2011            let b = match script_block.run(vec![], self, Some(Val::String(ch.to_string().into()))) {
2012                Err(er) => {
2013                    self.errors.push(er);
2014                    false
2015                }
2016                Ok(res) => res.val.cast_to_bool(),
2017            };
2018
2019            if b {
2020                res_vec.push(parts);
2021                parts = String::new();
2022            } else {
2023                parts.push(ch);
2024            }
2025        }
2026        self.variables.reset_ps_item();
2027        Ok(res_vec)
2028    }
2029
2030    fn eval_comparison_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2031        check_rule!(token, Rule::comparison_exp);
2032        let mut pairs = token.into_inner();
2033        let token = pairs.next().unwrap();
2034
2035        // we need to handle strange case. -split and -join can be invoke without
2036        // previous expression, eg. "-join 'some'"
2037        let mut res = if token.as_rule() == Rule::additive_exp {
2038            self.eval_additive(token)?
2039        } else {
2040            Val::Null
2041        };
2042
2043        while let Some(op) = pairs.next() {
2044            let Some(fun) = StringPred::get(op.as_str()) else {
2045                log::error!("No string predicate for operator: {}", op.as_str());
2046                return Err(ParserError::NotImplemented(format!(
2047                    "No string predicate for operator: {}",
2048                    op.as_str()
2049                )));
2050            };
2051
2052            let token = pairs.next().unwrap();
2053            let right_op = match token.as_rule() {
2054                Rule::script_block_expression => {
2055                    let script_block = self.parse_script_block_expression(token)?;
2056
2057                    return Ok(Val::Array(
2058                        self.eval_split_special_case(script_block, res)?
2059                            .into_iter()
2060                            .map(|s| Val::String(s.into()))
2061                            .collect::<Vec<_>>(),
2062                    ));
2063                }
2064                Rule::additive_exp => self.eval_additive(token)?,
2065                //Rule::type_literal => self.eval_type_literal(token)?,
2066                _ => unexpected_token!(token),
2067            };
2068            log::trace!("res: {:?}, right_op: {:?}", &res, &right_op);
2069            res = fun(res, right_op)?;
2070            log::trace!("res: {:?}", &res);
2071        }
2072
2073        Ok(res)
2074    }
2075
2076    fn parse_script_param_block(&mut self, token: Pair<'a>) -> ParserResult<Vec<Param>> {
2077        check_rule!(token, Rule::script_param_block);
2078        let mut pairs = token.into_inner();
2079        let Some(param_block_token) = pairs.next() else {
2080            return Ok(vec![]);
2081        };
2082        self.parse_param_block(param_block_token)
2083    }
2084
2085    fn parse_param_block(&mut self, token: Pair<'a>) -> ParserResult<Vec<Param>> {
2086        check_rule!(token, Rule::param_block);
2087        let mut pairs = token.into_inner();
2088
2089        let Some(token) = pairs.next() else {
2090            return Ok(vec![]);
2091        };
2092
2093        let option_param_token = match token.as_rule() {
2094            Rule::attribute_list => {
2095                //self.parse_attribute_list(token)?;
2096                pairs.next()
2097            }
2098            Rule::parameter_list => Some(token),
2099            _ => unexpected_token!(token),
2100        };
2101
2102        let Some(param_token) = option_param_token else {
2103            return Ok(vec![]);
2104        };
2105        self.parse_parameter_list(param_token)
2106    }
2107
2108    fn parse_parameter_list(&mut self, token: Pair<'a>) -> ParserResult<Vec<Param>> {
2109        check_rule!(token, Rule::parameter_list);
2110        let mut params = vec![];
2111        let param_list_pairs = token.into_inner();
2112        for script_parameter_token in param_list_pairs {
2113            check_rule!(script_parameter_token, Rule::script_parameter);
2114            params.push(self.parse_script_parameter(script_parameter_token)?);
2115        }
2116        Ok(params)
2117    }
2118
2119    fn parse_attribute_list(&mut self, token: Pair<'a>) -> ParserResult<Option<ValType>> {
2120        check_rule!(token, Rule::attribute_list);
2121        let attribute_list_pairs = token.into_inner();
2122        for attribute_token in attribute_list_pairs {
2123            check_rule!(attribute_token, Rule::attribute);
2124            let attribute_type_token = attribute_token.into_inner().next().unwrap();
2125            match attribute_type_token.as_rule() {
2126                Rule::attribute_info => {
2127                    //skip for now
2128                    continue;
2129                }
2130                Rule::type_literal => {
2131                    return Ok(Some(
2132                        self.get_valtype_from_type_literal(attribute_type_token)?,
2133                    ));
2134                }
2135                _ => unexpected_token!(attribute_type_token),
2136            }
2137        }
2138        Ok(None)
2139    }
2140    fn parse_script_parameter(&mut self, token: Pair<'a>) -> ParserResult<Param> {
2141        check_rule!(token, Rule::script_parameter);
2142        let mut pairs = token.into_inner();
2143        let mut token = pairs.next().unwrap();
2144
2145        let type_literal = if token.as_rule() == Rule::attribute_list {
2146            let type_literal = self.parse_attribute_list(token).unwrap_or(None);
2147            token = pairs.next().unwrap();
2148            type_literal
2149        } else {
2150            None
2151        };
2152
2153        check_rule!(token, Rule::variable);
2154        let var_name = Self::parse_variable(token)?;
2155
2156        let default_value = if let Some(default_value_token) = pairs.next() {
2157            check_rule!(default_value_token, Rule::script_parameter_default);
2158            let default_value_expr = default_value_token.into_inner().next().unwrap();
2159            let default_value = self.eval_primary_expression(default_value_expr)?;
2160            Some(default_value)
2161        } else {
2162            None
2163        };
2164        Ok(Param::new(type_literal, var_name.name, default_value))
2165    }
2166
2167    fn eval_bitwise_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2168        check_rule!(token, Rule::bitwise_exp);
2169
2170        let mut pairs = token.into_inner();
2171        let mut res = self.eval_as_exp(pairs.next().unwrap())?;
2172        while let Some(op) = pairs.next() {
2173            check_rule!(op, Rule::bitwise_operator);
2174            let Some(fun) = BitwisePred::get(op.as_str()) else {
2175                log::error!("No bitwise predicate for operator: {}", op.as_str());
2176                return Err(ParserError::NotImplemented(format!(
2177                    "No bitwise predicate for operator: {}",
2178                    op.as_str()
2179                )));
2180            };
2181
2182            let mult = pairs.next().unwrap();
2183            let right_op = self.eval_as_exp(mult)?;
2184            res = fun(res, right_op)?;
2185        }
2186
2187        Ok(res)
2188    }
2189
2190    fn eval_as_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2191        check_rule!(token, Rule::as_expression);
2192
2193        let mut pairs = token.into_inner();
2194        let mut res = self.eval_comparison_exp(pairs.next().unwrap())?;
2195        for token in pairs {
2196            let runtime_object = match token.as_rule() {
2197                Rule::primary_expression => self.eval_primary_expression(token)?,
2198                _ => unexpected_token!(token),
2199            };
2200
2201            res = res.cast(&runtime_object).unwrap_or_default();
2202        }
2203
2204        Ok(res)
2205    }
2206
2207    fn parse_cmdlet_command_name(&mut self, token: Pair<'a>) -> ParserResult<Command> {
2208        check_rule!(token, Rule::cmdlet_command);
2209
2210        let mut pairs = token.into_inner();
2211        let token = pairs.next().unwrap();
2212        let command_name = match token.as_rule() {
2213            Rule::command_name => token.as_str(),
2214            Rule::where_command_name => "where-object",
2215            Rule::foreach_command_name => "foreach-object",
2216            Rule::powershell_command_name => "powershell",
2217            _ => unexpected_token!(token),
2218        };
2219
2220        let mut command = Command::cmdlet(command_name);
2221        if Rule::command_name == token.as_rule() {
2222            command.set_session_scope(SessionScope::New);
2223        }
2224        Ok(command)
2225    }
2226
2227    fn parse_command_args(&mut self, pairs: Pairs<'a>) -> ParserResult<Vec<CommandElem>> {
2228        let mut args = vec![];
2229        for command_element_token in pairs {
2230            let token_string = command_element_token.as_str().to_string();
2231            match command_element_token.as_rule() {
2232                Rule::command_argument => {
2233                    let arg_token = command_element_token.into_inner().next().unwrap();
2234                    let arg = match arg_token.as_rule() {
2235                        Rule::array_literal_exp => self.eval_array_literal_exp(arg_token)?,
2236                        Rule::script_block_expression => {
2237                            Val::ScriptBlock(self.parse_script_block_expression(arg_token)?)
2238                        }
2239                        Rule::parenthesized_expression => {
2240                            self.eval_parenthesized_expression(arg_token)?
2241                        }
2242                        Rule::generic_token => {
2243                            let s = arg_token.as_str();
2244                            self.tokens.push(Token::String(s.into()));
2245                            Val::ScriptText(s.into())
2246                        }
2247                        _ => Val::ScriptText(arg_token.as_str().to_string()),
2248                    };
2249                    args.push(CommandElem::Argument(arg));
2250                }
2251                Rule::command_parameter => {
2252                    args.push(CommandElem::Parameter(token_string.to_ascii_lowercase()))
2253                }
2254                Rule::argument_list => {
2255                    let expression_token = command_element_token.into_inner().next().unwrap();
2256                    let Ok(expr_res) = self.eval_expression(expression_token) else {
2257                        continue;
2258                    };
2259                    if let Val::Array(arr) = expr_res {
2260                        for v in arr {
2261                            args.push(CommandElem::Argument(v));
2262                        }
2263                    } else {
2264                        args.push(CommandElem::Argument(expr_res));
2265                    }
2266                }
2267                Rule::splatten_arg => {
2268                    let var_name = Self::parse_scoped_variable(command_element_token)?;
2269                    let var = self
2270                        .variables
2271                        .get(&var_name, &self.types_map)
2272                        .unwrap_or_default();
2273                    if let Val::HashTable(h) = var {
2274                        for (k, v) in h {
2275                            args.push(CommandElem::Parameter(format!("-{}", k)));
2276                            args.push(CommandElem::Argument(v));
2277                        }
2278                    }
2279                }
2280                Rule::redirection => { //todo: implement redirection
2281                }
2282                Rule::stop_parsing => { //todo: stop parsing
2283                }
2284                _ => unexpected_token!(command_element_token),
2285            }
2286        }
2287        Ok(args)
2288    }
2289
2290    fn eval_command(&mut self, token: Pair<'a>, piped_arg: Option<Val>) -> ParserResult<Val> {
2291        check_rule!(token, Rule::command);
2292        let command_str = token.as_str().to_string();
2293
2294        let mut pairs = token.into_inner();
2295        let command_token = pairs.next().unwrap();
2296        let mut command = match command_token.as_rule() {
2297            Rule::cmdlet_command => self.parse_cmdlet_command_name(command_token)?,
2298            Rule::invocation_command => self.parse_invocation_command(command_token)?,
2299            _ => unexpected_token!(command_token),
2300        };
2301
2302        let mut args = self.parse_command_args(pairs)?;
2303        // the piped value was already tokenized upstream; keeping it here makes tokens quadratic in pipeline length
2304        let token_args = args.iter().map(CommandElem::display).collect();
2305        if let Some(arg) = piped_arg {
2306            args.insert(0, CommandElem::Argument(arg));
2307        }
2308
2309        command.with_args(args);
2310        self.tokens
2311            .push(Token::command(command_str, command.name(), token_args));
2312
2313        match command.execute(self) {
2314            Ok(CommandOutput {
2315                val,
2316                deobfuscated: _deobfuscated,
2317            }) => Ok(val),
2318            Err(e) => {
2319                self.errors.push(e);
2320                Ok(Val::ScriptText(command.to_string()))
2321            }
2322        }
2323
2324        // if let Some(msg) = deobfuscated {
2325        //     self.add_deobfuscated_statement(msg);
2326        // }
2327    }
2328
2329    fn add_deobfuscated_statement(&mut self, msg: String) {
2330        if let Some(last) = self.results.last_mut() {
2331            last.deobfuscated.push(msg);
2332        }
2333    }
2334
2335    fn add_output_statement(&mut self, msg: StreamMessage) {
2336        if let Some(last) = self.results.last_mut() {
2337            last.output.push(msg);
2338        }
2339    }
2340
2341    fn parse_invocation_command(&mut self, token: Pair<'a>) -> ParserResult<Command> {
2342        check_rule!(token, Rule::invocation_command);
2343
2344        let invocation_command_token = token.into_inner().next().unwrap();
2345
2346        let mut session_scope = match invocation_command_token.as_rule() {
2347            Rule::current_scope_invocation_command => SessionScope::Current,
2348            Rule::new_scope_invocation_command => SessionScope::New,
2349            _ => unexpected_token!(invocation_command_token),
2350        };
2351
2352        let token_inner = invocation_command_token.into_inner().next().unwrap();
2353
2354        let mut command = match token_inner.as_rule() {
2355            Rule::cmdlet_command => {
2356                session_scope = SessionScope::New;
2357                self.parse_cmdlet_command_name(token_inner)?
2358            }
2359            Rule::primary_expression => {
2360                let primary = self.eval_primary_expression(token_inner)?;
2361                if let Val::ScriptBlock(script_block) = primary {
2362                    Command::script_block(script_block)
2363                } else {
2364                    Command::cmdlet(&primary.cast_to_script())
2365                }
2366            }
2367            Rule::path_command_name => Command::path(token_inner.as_str()),
2368            _ => unexpected_token!(token_inner),
2369        };
2370
2371        command.set_session_scope(session_scope);
2372        Ok(command)
2373    }
2374
2375    fn eval_redirected_expression(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2376        check_rule!(token, Rule::redirected_expression);
2377
2378        let expression_token = token.into_inner().next().unwrap();
2379        //todo: handle redirections
2380
2381        self.eval_expression(expression_token)
2382    }
2383
2384    fn eval_expression(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2385        check_stack(0)?;
2386        eval_step()?;
2387        check_rule!(token, Rule::expression);
2388        let token_string = token.as_str().trim().to_string();
2389
2390        let mut pairs = token.into_inner();
2391        let mut res = self.eval_bitwise_exp(pairs.next().unwrap())?;
2392        while let Some(op) = pairs.next() {
2393            check_rule!(op, Rule::logical_operator);
2394            let Some(fun) = LogicalPred::get(op.as_str()) else {
2395                log::error!("No logical predicate for operator: {}", op.as_str());
2396                return Err(ParserError::NotImplemented(format!(
2397                    "No logical predicate for operator: {}",
2398                    op.as_str()
2399                )));
2400            };
2401
2402            let mult = pairs.next().unwrap();
2403            let right_op = self.eval_bitwise_exp(mult)?;
2404            res = Val::Bool(fun(res, right_op));
2405        }
2406        self.tokens
2407            .push(Token::expression(token_string, res.clone().into()));
2408
2409        if let Val::String(value::PsString(s)) = &res {
2410            self.tokens.push(Token::String(s.clone()));
2411        }
2412
2413        Ok(res)
2414    }
2415
2416    fn eval_pipeline_tail(&mut self, token: Pair<'a>, mut piped_arg: Val) -> ParserResult<Val> {
2417        check_rule!(token, Rule::pipeline_tail);
2418        let pairs = token.into_inner();
2419
2420        for token in pairs {
2421            //self.variables.set_ps_item(arg);
2422            piped_arg = self.eval_command(token, Some(piped_arg))?;
2423        }
2424
2425        Ok(piped_arg)
2426    }
2427
2428    fn eval_pipeline_with_tail(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2429        check_rule!(token, Rule::pipeline_with_tail);
2430        let mut pairs = token.into_inner();
2431        let token = pairs.next().unwrap();
2432
2433        let result: Val = match token.as_rule() {
2434            Rule::redirected_expression => self.eval_redirected_expression(token)?,
2435            Rule::command => self.eval_command(token, None)?,
2436            _ => unexpected_token!(token),
2437        };
2438
2439        if let Some(token) = pairs.next() {
2440            match token.as_rule() {
2441                Rule::pipeline_tail => Ok(self.eval_pipeline_tail(token, result)?),
2442                _ => unexpected_token!(token),
2443            }
2444        } else {
2445            Ok(result)
2446        }
2447    }
2448
2449    fn eval_pipeline(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2450        check_stack(0)?;
2451        check_rule!(token, Rule::pipeline);
2452        let mut pairs = token.into_inner();
2453        let token = pairs.next().unwrap();
2454
2455        match token.as_rule() {
2456            Rule::assignment_exp => self.eval_assigment_exp(token),
2457            Rule::pipeline_with_tail => self.eval_pipeline_with_tail(token),
2458            _ => unexpected_token!(token),
2459        }
2460    }
2461
2462    fn safe_eval_pipeline(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2463        let res = self.eval_pipeline(token.clone());
2464
2465        let v = match res {
2466            Ok(val) => val,
2467            Err(err) => {
2468                self.errors.push(err);
2469                Val::ScriptText(token.as_str().to_string())
2470            }
2471        };
2472
2473        Ok(v)
2474    }
2475
2476    fn eval_cast_expression(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2477        check_rule!(token, Rule::cast_expression);
2478
2479        let mut pairs = token.into_inner();
2480        let type_token = pairs.next().unwrap();
2481        check_rule!(type_token, Rule::type_literal);
2482        let val_type = self.eval_type_literal(type_token)?;
2483        let token = pairs.next().unwrap();
2484        let res = match token.as_rule() {
2485            Rule::parenthesized_expression => self.eval_parenthesized_expression(token)?,
2486            Rule::unary_exp => self.eval_unary_exp(token)?,
2487            _ => unexpected_token!(token),
2488        };
2489        Ok(res.cast(&val_type)?)
2490    }
2491
2492    fn eval_assigment_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2493        check_rule!(token, Rule::assignment_exp);
2494
2495        let mut specified_type = None;
2496
2497        let mut pairs = token.into_inner();
2498        let mut token = pairs.next().unwrap();
2499        if token.as_rule() == Rule::type_literal {
2500            specified_type = Some(self.eval_type_literal(token)?);
2501            token = pairs.next().unwrap();
2502        }
2503        let (var_name, access) = self.parse_assignable_variable(token)?;
2504        let mut variable = self
2505            .variables
2506            .get(&var_name, &self.types_map)
2507            .unwrap_or_default();
2508        let mut accessed_elem = &mut variable;
2509
2510        // sometimes we have variable access like $a[0].Property, and we need access
2511        // property by reference
2512        if let Some(access) = access {
2513            for token in access {
2514                accessed_elem = self.variable_access(token, accessed_elem)?;
2515            }
2516        }
2517        let assignement_op = pairs.next().unwrap();
2518
2519        //get operand
2520        let op = assignement_op.into_inner().next().unwrap();
2521        let pred = ArithmeticPred::get(op.as_str());
2522
2523        let right_token = pairs.next().unwrap();
2524        let right_op = self.eval_statement(right_token.clone())?;
2525
2526        let Some(pred) = pred else {
2527            log::error!("No arithmetic function for operator: {}", op.as_str());
2528            return Err(ParserError::NotImplemented(format!(
2529                "No arithmetic function for operator: {}",
2530                op.as_str()
2531            )));
2532        };
2533
2534        *accessed_elem = pred(accessed_elem.clone(), right_op)?;
2535        if let Some(runtime_type) = specified_type {
2536            *accessed_elem = accessed_elem.cast(&runtime_type)?;
2537        }
2538        self.variables.set(&var_name, variable.clone())?;
2539        //we want save each assignment statement
2540        self.add_deobfuscated_statement(format!("{} = {}", var_name, variable.cast_to_script()));
2541
2542        Ok(Val::NonDisplayed(Box::new(variable)))
2543    }
2544
2545    fn push_scope_session(&mut self) {
2546        self.variables.push_scope_session();
2547    }
2548
2549    fn pop_scope_session(&mut self) {
2550        self.variables.pop_scope_session();
2551    }
2552}
2553
2554#[cfg(test)]
2555mod tests {
2556    use pest::Parser;
2557
2558    use super::*;
2559
2560    #[test]
2561    fn comment_and_semicolon() {
2562        let input = r#"
2563# This is a single line comment
2564$a = 1; $b = 2; Write-Output $a
2565
2566Write-Output "Hello"  # Another comment
2567
2568<#
2569    This is a
2570    multi-line block comment
2571#>
2572"#;
2573
2574        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2575    }
2576
2577    #[test]
2578    fn while_loop() {
2579        let input = r#"
2580while ($true) {
2581    if ($someCondition) {
2582        break
2583    }
2584    # other code
2585}
2586"#;
2587
2588        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2589    }
2590
2591    #[test]
2592    fn foreach_loop() {
2593        let input = r#"
2594foreach ($n in $numbers) {
2595    Write-Output $n
2596}
2597"#;
2598
2599        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2600    }
2601
2602    #[test]
2603    fn for_loop() {
2604        let input = r#"
2605# Comma separated assignment expressions enclosed in parentheses.
2606for (($i = 0), ($j = 0); $i -lt 10; $i++)
2607{
2608    "`$i:$i"
2609    "`$j:$j"
2610}
2611"#;
2612
2613        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2614    }
2615
2616    #[test]
2617    fn switch() {
2618        let input = r#"
2619switch ($var) {
2620    "a" { Write-Output "A" }
2621    1 { Write-Output "One" }
2622    default { Write-Output "Other" }
2623}
2624"#;
2625
2626        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2627    }
2628
2629    #[test]
2630    fn functions() {
2631        let input = r#"
2632function Get-Square {
2633    param($x)
2634    return $x * $x
2635}
2636
2637function Say-Hello {
2638    Write-Output "Hello"
2639}
2640"#;
2641
2642        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2643    }
2644
2645    #[test]
2646    fn if_expression() {
2647        let input = r#"
2648$x="hello"
2649        Write-Host $x
2650        $y = 42
2651        Start-Process "notepad.exe"
2652
2653        $x = 42
2654if ($x -eq 1) {
2655    Write-Output "One"
2656} elseif ($x -eq 2) {
2657    Write-Output "Two"
2658} else {
2659    Write-Output "Other"
2660}
2661"#;
2662
2663        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2664    }
2665
2666    #[test]
2667    fn command() {
2668        let input = r#"
2669Get-Process | Where-Object { $_.CPU -gt 100 }
2670"#;
2671
2672        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2673    }
2674
2675    #[test]
2676    fn range() {
2677        let input = r#"
2678$numbers = 1..5
2679"#;
2680
2681        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2682    }
2683
2684    #[test]
2685    fn literals() {
2686        let input = r#"
2687$hex = 0xFF
2688
2689$name = "Alice"
2690$msg = "Hello, $name. Today is $day."
2691$escaped = "She said: `"Hi`""
2692$literal = 'Hello, $name'
2693"#;
2694
2695        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2696    }
2697
2698    #[test]
2699    fn floats() {
2700        let input = r#"
2701    $pi = 3.1415
2702$half = .5
2703"#;
2704
2705        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2706    }
2707
2708    #[test]
2709    fn arrays() {
2710        let input = r#"
2711$a = 1, 2, 3
2712$b = @("one", "two", "three")
2713$c = @(1, 2, @(3, 4))
2714"#;
2715
2716        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2717    }
2718
2719    #[test]
2720    fn static_method_call() {
2721        let input = r#"
2722[Threading.Thread]::Sleep(399)
2723"#;
2724
2725        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2726    }
2727
2728    #[test]
2729    fn neg_pipeline() {
2730        let input = r#"
2731-not $input | Where-Object { $_ -gt 5 }
2732"#;
2733
2734        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2735    }
2736
2737    #[test]
2738    fn amsi_fail() {
2739        let input = r#"
2740#Matt Graebers second Reflection method 
2741$VMRviwsbtehQfPtxbt=$null;
2742$ilryNQSTt="System.$([cHAR]([ByTE]0x4d)+[ChAR]([byte]0x61)+[chAr](110)+[cHar]([byTE]0x61)+[cHaR](103)+[cHar](101*64/64)+[chaR]([byTE]0x6d)+[cHAr](101)+[CHAr]([byTE]0x6e)+[Char](116*103/103)).$([Char]([ByTe]0x41)+[Char](117+70-70)+[CHAr]([ByTE]0x74)+[CHar]([bYte]0x6f)+[CHar]([bytE]0x6d)+[ChaR]([ByTe]0x61)+[CHar]([bYte]0x74)+[CHAR]([byte]0x69)+[Char](111*26/26)+[chAr]([BYTe]0x6e)).$(('Âmsí'+'Ùtìl'+'s').NORmalizE([ChAR](44+26)+[chAR](111*9/9)+[cHar](82+32)+[ChaR](109*34/34)+[cHaR](68+24-24)) -replace [ChAr](92)+[CHaR]([BYTe]0x70)+[Char]([BytE]0x7b)+[CHaR]([BYTe]0x4d)+[chAR](110)+[ChAr](15+110))"
2743
2744"#;
2745
2746        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2747    }
2748
2749    #[test]
2750    fn max_nesting_ignores_strings_and_comments() {
2751        assert_eq!(max_nesting("((1))"), 2);
2752        assert_eq!(max_nesting("$x -replace '\\(', ''"), 0);
2753        assert_eq!(max_nesting(&"$x = $x -replace '\\(', ''\n".repeat(100)), 0);
2754        assert_eq!(max_nesting("\"(((\""), 0);
2755        assert_eq!(max_nesting("\"$(1 + $(2))\""), 2);
2756        assert_eq!(max_nesting("\"a $(\"b $(1)\")\""), 2);
2757        assert_eq!(max_nesting("# ((((\n(1)"), 1);
2758        assert_eq!(max_nesting("<# (((( #> (1)"), 1);
2759        assert_eq!(max_nesting("@'\n((((\n'@\n(1)"), 1);
2760        assert_eq!(max_nesting("@\"\n(( \" $(1)\n\"@"), 1);
2761        assert_eq!(max_nesting("'it''s ((' + (1)"), 1);
2762        assert_eq!(max_nesting("\"say \"\"(\"\" $(1)\""), 1);
2763        assert_eq!(max_nesting("\"`\"(\" + (1)"), 1);
2764        assert_eq!(max_nesting("`(1"), 0);
2765    }
2766
2767    #[test]
2768    fn failed_index_not_evaluated_twice() {
2769        let mut ps = PowerShellSession::new();
2770        assert_eq!(ps.safe_eval("$a=@(1,2); $i=5; $a[0][$i++]; $i").unwrap(), "6");
2771    }
2772
2773    #[test]
2774    fn unclosed_nesting_hits_parse_budget() {
2775        for open in ["(", "$(", "@(", "{"] {
2776            let start = std::time::Instant::now();
2777            // bypasses the stack guard, which in debug builds rejects this depth on its own
2778            let input = open.repeat(24);
2779            let res = parse_program(&input);
2780            assert_eq!(res.err(), Some(ParserError::ParseBudgetExceeded), "{open}");
2781            assert!(start.elapsed().as_secs() < 5, "{open}: {:?}", start.elapsed());
2782        }
2783    }
2784
2785    #[test]
2786    fn pipeline_tokens_do_not_grow_with_piped_values() {
2787        let script = vec!["Foo-Bar"; 2000].join(" | ");
2788        let res = PowerShellSession::new().parse_command(&script).unwrap();
2789        let arg_bytes: usize = res
2790            .tokens()
2791            .all()
2792            .iter()
2793            .filter_map(|t| match t {
2794                Token::Command(cmd) => Some(cmd.args().iter().map(String::len).sum::<usize>()),
2795                _ => None,
2796            })
2797            .sum();
2798        assert!(arg_bytes < script.len(), "{arg_bytes}");
2799    }
2800
2801    #[test]
2802    fn wide_call_tree_hits_eval_budget() {
2803        // 10^6 calls at depth 7, shallow enough for the stack guard
2804        let mut script = "function f0 { 1 }\n".to_string();
2805        for i in 1..7 {
2806            script += &format!("function f{i} {{ {} }}\n", vec![format!("f{}", i - 1); 10].join("; "));
2807        }
2808        script += "f6";
2809
2810        let start = std::time::Instant::now();
2811        let res = PowerShellSession::new().parse_command(&script).unwrap();
2812        assert!(res.errors().contains(&ParserError::EvalBudgetExceeded));
2813        assert!(start.elapsed().as_secs() < 60, "{:?}", start.elapsed());
2814    }
2815
2816    #[test]
2817    fn recursion_with_large_body_hits_eval_deadline() {
2818        // every call re-parses the body but counts as a few steps only; debug builds parse ~10x slower
2819        let repeat = if cfg!(debug_assertions) { 2000 } else { 8000 };
2820        let script = format!("function f {{ f; f; {} }}; f", "$a = 1; ".repeat(repeat));
2821
2822        let start = std::time::Instant::now();
2823        let hit_budget = match PowerShellSession::new().parse_command(&script) {
2824            Ok(res) => res.errors().contains(&ParserError::EvalBudgetExceeded),
2825            // a loaded machine can run out of time already in the top-level parse
2826            Err(err) => err == ParserError::ParseBudgetExceeded,
2827        };
2828        assert!(hit_budget);
2829        assert!(start.elapsed().as_secs() < 10, "{:?}", start.elapsed());
2830    }
2831}