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                self.collect_block_tokens(token.clone());
961                not_implemented!(token)
962            }
963        }
964    }
965
966    // collects tokens of try, while... blocks, which are not evaluated
967    fn collect_block_tokens(&mut self, token: Pair<'a>) {
968        fn blocks<'a>(token: Pair<'a>, out: &mut Vec<Pair<'a>>) {
969            for pair in token.into_inner() {
970                if pair.as_rule() == Rule::statement_block {
971                    out.push(pair);
972                } else {
973                    blocks(pair, out);
974                }
975            }
976        }
977
978        let mut statement_blocks = vec![];
979        blocks(token, &mut statement_blocks);
980        let results = self.results.clone();
981        let current_variables = self.variables.clone();
982        for block in statement_blocks {
983            if let Err(err) = self.eval_statement_block(block) {
984                log::debug!("Error during collect_block_tokens: {:?}", err);
985            }
986        }
987        self.variables = current_variables;
988        self.results = results;
989    }
990
991    fn safe_eval_sub_expr(&mut self, token: Pair<'a>) -> ParserResult<Val> {
992        check_rule!(token, Rule::sub_expression);
993        let Some(inner_token) = token.into_inner().next() else {
994            return Ok(Val::Null);
995        };
996        let mut inner_val = self.eval_pipeline(inner_token)?;
997        if let Val::ScriptText(script) = &mut inner_val {
998            *script = format!("$({})", script);
999            //self.tokens.push(Token::SubExpression(script.clone()));
1000        }
1001        Ok(inner_val)
1002    }
1003
1004    fn eval_statement_block(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1005        Ok(self
1006            .safe_eval_statements(token)?
1007            .iter()
1008            .last()
1009            .cloned()
1010            .unwrap_or(Val::Null))
1011    }
1012
1013    fn eval_statements(&mut self, token: Pair<'a>) -> ParserResult<Vec<Val>> {
1014        //check_rule!(token, Rule::statements);
1015        let pairs = token.into_inner();
1016        let mut statements = vec![];
1017
1018        for token in pairs {
1019            let s = self.eval_statement(token)?;
1020            statements.push(s);
1021        }
1022        Ok(statements)
1023    }
1024
1025    fn safe_eval_statements(&mut self, token: Pair<'a>) -> ParserResult<Vec<Val>> {
1026        //check_rule!(token, Rule::statements);
1027        let pairs = token.into_inner();
1028        let mut statements = vec![];
1029
1030        for token in pairs {
1031            match self.eval_statement(token.clone()) {
1032                Ok(s) => statements.push(s),
1033                Err(err) => {
1034                    self.errors.push(err);
1035                    statements.push(Val::ScriptText(token.as_str().to_string()));
1036                }
1037            }
1038        }
1039        Ok(statements)
1040    }
1041
1042    fn parse_dq(&mut self, token: Pair<'a>) -> ParserResult<String> {
1043        let mut res_str = String::new();
1044        let pairs = token.into_inner();
1045        for token in pairs {
1046            let token = token.into_inner().next().unwrap();
1047            let token_str = token.as_str();
1048            let res = match token.as_rule() {
1049                Rule::variable => self.get_variable(token).map(|v| v.cast_to_string()),
1050                Rule::sub_expression => self.safe_eval_sub_expr(token).map(|v| v.cast_to_string()),
1051                Rule::backtick_escape => Ok(token
1052                    .as_str()
1053                    .strip_prefix("`")
1054                    .unwrap_or_default()
1055                    .to_string()),
1056                _ => Ok(token.as_str().to_string()),
1057            };
1058            match res {
1059                Ok(s) => res_str.push_str(s.as_str()),
1060                Err(err) => {
1061                    self.errors.push(err);
1062                    res_str.push_str(token_str);
1063                }
1064            }
1065        }
1066        Ok(res_str)
1067    }
1068
1069    fn eval_string_literal(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1070        check_rule!(token, Rule::string_literal);
1071        let mut pair = token.into_inner();
1072        let token = pair.next().unwrap();
1073        let cloned_token = token.clone();
1074
1075        let mut is_expandable = false;
1076        let res = match token.as_rule() {
1077            Rule::doublequoted_string_literal | Rule::doublequoted_multiline_string_literal => {
1078                is_expandable = true;
1079                self.parse_dq(token)?
1080            }
1081            Rule::singlequoted_string_literal => {
1082                let token_string = token.as_str().to_string();
1083                let stripped_prefix = token_string
1084                    .strip_prefix("'")
1085                    .unwrap_or(token_string.as_str());
1086                let stripped_suffix = stripped_prefix.strip_suffix("'").unwrap_or(stripped_prefix);
1087                stripped_suffix.to_string()
1088            }
1089            Rule::singlequoted_multiline_string_literal => {
1090                let mut res_str = String::new();
1091                let pairs = token.into_inner();
1092                for token in pairs {
1093                    res_str.push_str(token.as_str());
1094                }
1095                res_str
1096            }
1097            _ => unexpected_token!(token),
1098        };
1099        let ps_token = if is_expandable {
1100            Token::string_expandable(cloned_token.as_str().to_string(), res.clone())
1101        } else {
1102            Token::String(res.clone())
1103        };
1104        self.tokens.push(ps_token);
1105
1106        Ok(Val::String(res.into()))
1107    }
1108
1109    fn get_variable(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1110        check_rule!(token, Rule::variable);
1111        let var_name = Self::parse_variable(token)?;
1112        let Some(var) = self.variables.get(&var_name, &self.types_map) else {
1113            return Err(ParserError::VariableError(VariableError::NotDefined(
1114                var_name.name,
1115            )));
1116        };
1117        Ok(var)
1118    }
1119
1120    fn parse_scoped_variable(token: Pair<'a>) -> ParserResult<VarName> {
1121        //can be scoped or splatted
1122        let mut pairs = token.into_inner();
1123        let mut token = pairs.next().unwrap();
1124
1125        let scope = if token.as_rule() == Rule::scope_keyword {
1126            let scope = token.as_str().to_ascii_lowercase();
1127            token = pairs.next().unwrap();
1128            check_rule!(token, Rule::var_name);
1129            Some(Scope::from(scope.as_str()))
1130        } else {
1131            None
1132        };
1133        Ok(VarName::new(scope, token.as_str().to_ascii_lowercase()))
1134    }
1135
1136    fn skip_value_access(&mut self, token: Pair<'a>) -> ParserResult<()> {
1137        check_rule!(token, Rule::value_access);
1138        let mut pair = token.into_inner();
1139        let token = pair.next().unwrap();
1140        let mut val = self.eval_value(token)?;
1141        if let Some(access) = pair.next() {
1142            let _ = self.eval_element_access_ref(access, &mut val)?;
1143        }
1144        Err(ParserError::Skip)
1145    }
1146
1147    // fn get_assignable_variable<'b>(&mut self, pairs: Pairs<'a>, object: &'b mut
1148    // Val) -> ParserResult<&'b mut Val> {     let mut var = object;
1149    //     for token in pairs {
1150    //             let tmp = self.variable_access(token, &mut var)?;
1151    //             var = tmp;
1152    //     }
1153    //     Ok(var)
1154    // }
1155
1156    fn parse_assignable_variable(
1157        &mut self,
1158        token: Pair<'a>,
1159    ) -> ParserResult<(VarName, Option<Pairs<'a>>)> {
1160        check_rule!(token, Rule::assignable_variable);
1161        let mut pair = token.into_inner();
1162        let token = pair.next().unwrap();
1163        match token.as_rule() {
1164            Rule::variable => {
1165                let var_name = Self::parse_variable(token)?;
1166
1167                Ok((var_name, None))
1168            }
1169            Rule::variable_access => {
1170                let mut pairs = token.into_inner();
1171                let var_token = pairs.next().unwrap();
1172                let var_name = Self::parse_variable(var_token)?;
1173                // let mut object = &mut var;
1174                // for token in pairs {
1175                //     object = self.variable_access(token, &mut object)?;
1176                // }
1177                Ok((var_name, Some(pairs)))
1178            }
1179            Rule::value_access => self
1180                .skip_value_access(token)
1181                .map(|()| (Default::default(), None)),
1182            _ => unexpected_token!(token),
1183        }
1184    }
1185
1186    fn parse_variable(token: Pair<'a>) -> ParserResult<VarName> {
1187        check_rule!(token, Rule::variable);
1188        let mut pair = token.into_inner();
1189        let token = pair.next().unwrap();
1190
1191        Ok(match token.as_rule() {
1192            Rule::special_variable => {
1193                VarName::new_with_scope(Scope::Special, token.as_str().to_string())
1194            }
1195            Rule::parenthesized_variable => {
1196                Self::parse_variable(token.into_inner().next().unwrap())?
1197            }
1198            Rule::braced_variable => {
1199                let token = token.into_inner().next().unwrap();
1200                let var = token.as_str().to_ascii_lowercase();
1201                let splits: Vec<&str> = var.split(":").collect();
1202                if splits.len() == 2 {
1203                    VarName::new_with_scope(Scope::from(splits[0]), splits[1].to_string())
1204                } else {
1205                    VarName::new(None, var)
1206                }
1207            }
1208            Rule::scoped_variable => Self::parse_scoped_variable(token)?,
1209            _ => unexpected_token!(token),
1210        })
1211    }
1212
1213    fn eval_pre_arithmetic(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1214        check_rule!(token, Rule::pre_arithmetic);
1215        let mut pair = token.into_inner();
1216        let token = pair.next().unwrap();
1217
1218        let res = match token.as_rule() {
1219            Rule::pre_plus_expression => {
1220                let token = token.into_inner().next().unwrap();
1221                match token.as_rule() {
1222                    Rule::variable => {
1223                        let var_name = Self::parse_variable(token)?;
1224                        self.variables
1225                            .get(&var_name, &self.types_map)
1226                            .unwrap_or_default()
1227                    }
1228                    Rule::parenthesized_expression => self.eval_parenthesized_expression(token)?,
1229                    _ => unexpected_token!(token),
1230                }
1231            }
1232            Rule::pre_minus_expression => {
1233                let token = token.into_inner().next().unwrap();
1234                let mut v = Val::default();
1235                let to_sub = match token.as_rule() {
1236                    Rule::variable => {
1237                        let var_name = Self::parse_variable(token)?;
1238                        self.variables
1239                            .get(&var_name, &self.types_map)
1240                            .unwrap_or_default()
1241                    }
1242                    Rule::parenthesized_expression => self.eval_parenthesized_expression(token)?,
1243                    _ => unexpected_token!(token),
1244                };
1245                v.sub(to_sub)?;
1246                v
1247            }
1248            Rule::pre_inc_expression => {
1249                let variable_token = token.into_inner().next().unwrap();
1250                let var_name = Self::parse_variable(variable_token)?;
1251                let mut var = self
1252                    .variables
1253                    .get(&var_name, &self.types_map)
1254                    .unwrap_or_default();
1255                var.inc()?;
1256
1257                self.variables.set(&var_name, var.clone())?;
1258                var
1259            }
1260            Rule::pre_dec_expression => {
1261                let variable_token = token.into_inner().next().unwrap();
1262                let var_name = Self::parse_variable(variable_token)?;
1263                let mut var = self
1264                    .variables
1265                    .get(&var_name, &self.types_map)
1266                    .unwrap_or_default();
1267                var.dec()?;
1268
1269                self.variables.set(&var_name, var.clone())?;
1270                var
1271            }
1272            _ => unexpected_token!(token),
1273        };
1274
1275        Ok(res)
1276    }
1277
1278    fn eval_expression_with_unary_operator(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1279        check_rule!(token, Rule::expression_with_unary_operator);
1280        let mut pair = token.into_inner();
1281        let token = pair.next().unwrap();
1282
1283        let res = match token.as_rule() {
1284            Rule::pre_arithmetic => self.eval_pre_arithmetic(token)?,
1285            Rule::cast_expression => self.eval_cast_expression(token)?,
1286            Rule::negate_op => {
1287                let unary_token = pair.next().unwrap();
1288                let unary = self.eval_unary_exp(unary_token)?;
1289                Val::Bool(!unary.cast_to_bool())
1290            }
1291            Rule::bitwise_negate_op => {
1292                let unary_token = pair.next().unwrap();
1293                let unary = self.eval_unary_exp(unary_token)?;
1294                Val::Int(!unary.cast_to_int()?)
1295            }
1296            _ => unexpected_token!(token),
1297        };
1298
1299        Ok(res)
1300    }
1301
1302    fn eval_argument_list(&mut self, token: Pair<'a>) -> ParserResult<Vec<Val>> {
1303        check_rule!(token, Rule::argument_list);
1304        let mut pairs = token.into_inner();
1305        let token = pairs.next().unwrap();
1306
1307        self.skip_error += 1;
1308
1309        let arg = self.eval_expression(token.clone())?;
1310        self.skip_error -= 1;
1311
1312        if let Val::Array(vec) = arg {
1313            Ok(vec)
1314        } else {
1315            Ok(vec![arg])
1316        }
1317    }
1318
1319    fn eval_member_access(&mut self, token: Pair<'a>) -> ParserResult<String> {
1320        //check_rule!(token, Rule::member_access);
1321        let member_name_token = token.into_inner().next().unwrap();
1322        let member_name = member_name_token.as_str().to_ascii_lowercase();
1323
1324        Ok(member_name)
1325    }
1326
1327    fn method_is_static(&mut self, token: Pair<'a>) -> bool {
1328        check_rule!(token, Rule::method_invocation);
1329        let mut pairs = token.into_inner();
1330
1331        let access = pairs.next().unwrap();
1332        match access.as_rule() {
1333            Rule::member_access => false,
1334            Rule::static_access => true,
1335            _ => unexpected_token!(access),
1336        }
1337    }
1338
1339    fn eval_method_invocation(
1340        &mut self,
1341        token: Pair<'a>,
1342        object: &Val,
1343    ) -> ParserResult<(String, Vec<Val>)> {
1344        check_rule!(token, Rule::method_invocation);
1345        let token_string = token.as_str().to_string();
1346
1347        let mut pairs = token.into_inner();
1348
1349        let access = pairs.next().unwrap();
1350        let method_name = self.eval_member_access(access)?;
1351
1352        let args = if let Some(token) = pairs.next() {
1353            check_rule!(token, Rule::argument_list);
1354            match self.eval_argument_list(token) {
1355                Ok(args) => args,
1356                Err(e) => {
1357                    log::debug!("eval_argument_list error: {:?}", e);
1358
1359                    //nevertheless push the function token
1360                    self.tokens.push(Token::method(
1361                        token_string.clone(),
1362                        object.clone().into(),
1363                        method_name.clone(),
1364                        Vec::new(),
1365                    ));
1366                    Err(e)?
1367                }
1368            }
1369        } else {
1370            Vec::new()
1371        };
1372
1373        self.tokens.push(Token::method(
1374            token_string,
1375            object.clone().into(),
1376            method_name.clone(),
1377            args.clone().iter().map(|arg| arg.clone().into()).collect(),
1378        ));
1379        Ok((method_name, args))
1380    }
1381
1382    fn eval_element_access_ref<'b>(
1383        &mut self,
1384        token: Pair<'a>,
1385        object: &'b mut Val,
1386    ) -> ParserResult<&'b mut Val> {
1387        let mut pairs = token.into_inner();
1388        let index_token = pairs.next().unwrap();
1389        check_rule!(index_token, Rule::expression);
1390        let index = self.eval_expression(index_token)?;
1391        Ok(object.get_index_ref(index)?)
1392    }
1393
1394    fn eval_element_access(&mut self, token: Pair<'a>, object: &Val) -> ParserResult<Val> {
1395        let key = (token.as_str().as_ptr() as usize, token.as_str().len());
1396        let mut pairs = token.into_inner();
1397        let index_token = pairs.next().unwrap();
1398        check_rule!(index_token, Rule::expression);
1399        let index = self.eval_expression(index_token)?;
1400        object.get_index(index.clone()).map_err(|err| {
1401            self.failed_index = Some((key, index));
1402            err.into()
1403        })
1404    }
1405
1406    fn variable_access<'b>(
1407        &mut self,
1408        token: Pair<'a>,
1409        object: &'b mut Val,
1410    ) -> ParserResult<&'b mut Val> {
1411        fn get_member_name(token: Pair<'_>) -> &'_ str {
1412            token.into_inner().next().unwrap().as_str()
1413        }
1414        match token.as_rule() {
1415            Rule::static_access => {
1416                //todo
1417                Err(ParserError::NotImplemented(
1418                    "modificable static_member".into(),
1419                ))
1420            }
1421            Rule::member_access => Ok(object.member(get_member_name(token))?),
1422            Rule::element_access => Ok(self.eval_element_access_ref(token, object)?),
1423            _ => unexpected_token!(token),
1424        }
1425    }
1426
1427    fn value_access(&mut self, token: Pair<'a>, object: &mut Val) -> ParserResult<Val> {
1428        fn get_member_name(token: Pair<'_>) -> &'_ str {
1429            token.into_inner().next().unwrap().as_str()
1430        }
1431        Ok(match token.as_rule() {
1432            Rule::static_access => {
1433                let Val::RuntimeType(rt) = object else {
1434                    return Err(RuntimeError::MethodNotFound(
1435                        "Readonly static members can only be accessed on types".to_string(),
1436                    )
1437                    .into());
1438                };
1439                rt.readonly_static_member(get_member_name(token))?
1440            }
1441            Rule::member_access => object.readonly_member(get_member_name(token))?.clone(),
1442            Rule::method_invocation => {
1443                let static_method = self.method_is_static(token.clone());
1444                let (function_name, args) = self.eval_method_invocation(token, object)?;
1445                let mangled_name = MethodName::from_args(function_name.as_str(), &args);
1446
1447                if static_method {
1448                    let Val::RuntimeType(rt) = object else {
1449                        return Err(RuntimeError::MethodNotFound(
1450                            "Static method can be called only on type".to_string(),
1451                        )
1452                        .into());
1453                    };
1454
1455                    let mut call = rt.static_method(mangled_name)?;
1456                    call(args)?
1457                } else {
1458                    let mut call = object.method(mangled_name)?;
1459                    call(object, args)?
1460                }
1461            }
1462            Rule::element_access => self.eval_element_access(token, object)?,
1463            _ => unexpected_token!(token),
1464        })
1465    }
1466
1467    fn eval_value_access(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1468        check_rule!(token, Rule::value_access);
1469        let mut pairs = token.into_inner();
1470        let token = pairs.next().unwrap();
1471
1472        let mut object = self.eval_value(token)?;
1473        for token in pairs {
1474            object = self.value_access(token, &mut object)?;
1475        }
1476        log::debug!("Success eval_access: {:?}", object);
1477        Ok(object)
1478    }
1479
1480    fn parse_access(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1481        check_rule!(token, Rule::value_access);
1482        let mut pairs = token.into_inner();
1483        let token = pairs.next().unwrap();
1484
1485        let mut object = self
1486            .eval_value(token.clone())
1487            .map(|v| v.cast_to_script())
1488            .unwrap_or(token.as_str().to_string());
1489
1490        for token in pairs {
1491            match token.as_rule() {
1492                Rule::static_access => {
1493                    object.push_str(token.as_str());
1494                }
1495                Rule::member_access => {
1496                    object.push_str(token.as_str());
1497                }
1498                Rule::method_invocation => {
1499                    let static_method = self.method_is_static(token.clone());
1500                    let (method_name, args) = self
1501                        .eval_method_invocation(token.clone(), &Val::ScriptText(object.clone()))?;
1502                    log::trace!("Method: {:?} {:?}", &method_name, &args);
1503
1504                    let separator = if static_method { "::" } else { "." };
1505                    object = format!(
1506                        "{}{separator}{}({})",
1507                        object,
1508                        method_name.to_ascii_lowercase(),
1509                        args.iter()
1510                            .map(|arg| arg.cast_to_script())
1511                            .collect::<Vec<String>>()
1512                            .join(", ")
1513                    )
1514                }
1515                Rule::element_access => {
1516                    let key = (token.as_str().as_ptr() as usize, token.as_str().len());
1517                    let index = match self.failed_index.take_if(|(failed_key, _)| *failed_key == key) {
1518                        Some((_, index)) => index,
1519                        _ => {
1520                            let mut pairs = token.into_inner();
1521                            let index_token = pairs.next().unwrap();
1522                            check_rule!(index_token, Rule::expression);
1523                            self.eval_expression(index_token)?
1524                        }
1525                    };
1526                    object = format!("{}[{}]", object, index);
1527                }
1528                _ => unexpected_token!(token),
1529            }
1530        }
1531        Ok(Val::String(object.into()))
1532    }
1533
1534    fn eval_primary_expression(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1535        check_rule!(token, Rule::primary_expression);
1536        let mut pair = token.into_inner();
1537        let token = pair.next().unwrap();
1538        let res = match token.as_rule() {
1539            Rule::value_access if token.clone().into_inner().count() == 1 => {
1540                self.eval_value(token.into_inner().next().unwrap())?
1541            }
1542            Rule::value_access => match self.eval_value_access(token.clone()) {
1543                Ok(res) => res,
1544                Err(ParserError::NestingTooDeep) => Err(ParserError::NestingTooDeep)?,
1545                Err(err) => {
1546                    log::debug!("eval_access error: {:?}", err);
1547                    self.errors.push(err);
1548                    self.parse_access(token)?
1549                }
1550            },
1551            Rule::value => self.eval_value(token)?,
1552            Rule::post_inc_expression => {
1553                let variable_token = token.into_inner().next().unwrap();
1554                let var_name = Self::parse_variable(variable_token)?;
1555                let mut var = self
1556                    .variables
1557                    .get(&var_name, &self.types_map)
1558                    .unwrap_or_default();
1559                let var_to_return = var.clone();
1560
1561                var.inc()?;
1562                self.variables.set(&var_name, var.clone())?;
1563
1564                //if var_to_return.ttype() ==
1565                var_to_return
1566            }
1567            Rule::post_dec_expression => {
1568                let variable_token = token.into_inner().next().unwrap();
1569                let var_name = Self::parse_variable(variable_token)?;
1570                let mut var = self
1571                    .variables
1572                    .get(&var_name, &self.types_map)
1573                    .unwrap_or_default();
1574                let var_to_return = var.clone();
1575
1576                var.dec()?;
1577                self.variables.set(&var_name, var.clone())?;
1578
1579                var_to_return
1580            }
1581            _ => unexpected_token!(token),
1582        };
1583
1584        Ok(res)
1585    }
1586
1587    fn get_valtype_from_type_literal(&mut self, token: Pair<'a>) -> ParserResult<ValType> {
1588        let type_literal = self.parse_type_literal(token)?;
1589        Ok(ValType::cast(type_literal.as_str(), &self.types_map)?)
1590    }
1591
1592    fn eval_type_literal(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1593        let type_literal = self.parse_type_literal(token)?;
1594        match ValType::runtime_type_from_str(type_literal.as_str(), &self.types_map) {
1595            Ok(val_type) => Ok(val_type),
1596            Err(err) => {
1597                self.errors.push(err.into());
1598                Ok(Val::Null)
1599            }
1600        }
1601    }
1602
1603    fn parse_type_literal(&mut self, token: Pair<'a>) -> ParserResult<String> {
1604        check_rule!(token, Rule::type_literal);
1605
1606        let token = token.into_inner().next().unwrap();
1607        check_rule!(token, Rule::type_spec);
1608        let type_literal = token.as_str().to_ascii_lowercase();
1609        self.tokens.push(Token::type_literal(type_literal.clone()));
1610        Ok(type_literal)
1611    }
1612
1613    fn parse_script_block(&mut self, token: Pair<'a>) -> ParserResult<ScriptBlock> {
1614        check_rule!(token, Rule::script_block);
1615
1616        let raw_text = token.as_str().to_string();
1617
1618        let mut pairs = token.into_inner();
1619        let Some(token) = pairs.next() else {
1620            return Ok(ScriptBlock::new(vec![], String::new(), raw_text));
1621        };
1622
1623        let params = self.parse_script_param_block(token.clone())?;
1624        //let params_str = token.as_str().to_string();
1625
1626        let script_body = if let Some(token) = pairs.next() {
1627            check_rule!(token, Rule::script_block_body);
1628            token.as_str().to_string()
1629        } else {
1630            String::new()
1631        };
1632        //todo is it necessary?
1633        // Ok(if let Ok(deobfuscated_body) =
1634        // self.deobfuscate_script(&script_body) {
1635        //     ScriptBlock::new(params, deobfuscated_body.clone(),
1636        // format!("{};{}", params_str, deobfuscated_body)) } else {
1637        //     ScriptBlock::new(params, script_body, raw_text)
1638        // })
1639        self.script_block_collect_tokens(&script_body);
1640
1641        Ok(ScriptBlock::new(params, script_body, raw_text))
1642    }
1643
1644    pub(crate) fn script_block_collect_tokens(&mut self, script_body: &str) {
1645        //we want collect tokens from each case, but we need to preserve all variables
1646        //to consider: maybe instead of collecting tokens, we should return whole
1647        // deobfuscated if statement
1648        if !self.collected.insert(script_body.to_string()) {
1649            return;
1650        }
1651        let results = self.results.clone();
1652        let current_variables = self.variables.clone();
1653        let errors = self.errors.clone();
1654        if let Err(err) = self.parse_subscript(script_body) {
1655            log::debug!("Error during script_block_collect_tokens: {:?}", err);
1656        }
1657        self.variables = current_variables;
1658        self.results = results;
1659        self.errors = errors;
1660    }
1661
1662    fn parse_script_block_expression(&mut self, token: Pair<'a>) -> ParserResult<ScriptBlock> {
1663        check_rule!(token, Rule::script_block_expression);
1664        let mut pairs = token.into_inner();
1665        self.parse_script_block(pairs.next().unwrap())
1666    }
1667
1668    fn eval_hash_key(&mut self, token: Pair<'a>) -> ParserResult<String> {
1669        check_rule!(token, Rule::key_expression);
1670        let mut pairs = token.into_inner();
1671        let key_token = pairs.next().unwrap();
1672
1673        Ok(match key_token.as_rule() {
1674            Rule::simple_name => key_token.as_str().to_ascii_lowercase(),
1675            Rule::unary_exp => self
1676                .eval_unary_exp(key_token)?
1677                .cast_to_string()
1678                .to_ascii_lowercase(),
1679            _ => unexpected_token!(key_token),
1680        })
1681    }
1682
1683    fn eval_hash_entry(&mut self, token: Pair<'a>) -> ParserResult<(String, Val)> {
1684        check_rule!(token, Rule::hash_entry);
1685
1686        let mut pairs = token.into_inner();
1687        let token_key = pairs.next().unwrap();
1688        let token_value = pairs.next().unwrap();
1689        let value = match token_value.as_rule() {
1690            //Rule::statement => self.eval_statement(token_value)?,
1691            Rule::type_literal => self.eval_type_literal(token_value)?,
1692            _ => self.eval_statement(token_value)?,
1693        };
1694
1695        Ok((self.eval_hash_key(token_key)?, value))
1696    }
1697
1698    fn eval_hash_literal(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1699        check_rule!(token, Rule::hash_literal_expression);
1700        let pairs = token.into_inner();
1701        let mut hash = HashMap::new();
1702        for token in pairs {
1703            let (key, value) = self.eval_hash_entry(token)?;
1704            hash.insert(key, value);
1705        }
1706        Ok(Val::HashTable(hash))
1707    }
1708
1709    fn eval_parenthesized_expression(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1710        check_rule!(token, Rule::parenthesized_expression);
1711        let token = token.into_inner().next().unwrap();
1712        self.safe_eval_pipeline(token)
1713    }
1714
1715    fn eval_value(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1716        check_rule!(token, Rule::value);
1717        let mut pair = token.into_inner();
1718        let token = pair.next().unwrap();
1719
1720        let res = match token.as_rule() {
1721            Rule::parenthesized_expression => self.eval_parenthesized_expression(token)?,
1722            Rule::sub_expression | Rule::array_expression => {
1723                let statements = self.eval_statements(token)?;
1724                if statements.len() == 1 {
1725                    if let Val::Array(_) = statements[0] {
1726                        statements[0].clone()
1727                    } else {
1728                        Val::Array(statements)
1729                    }
1730                } else {
1731                    Val::Array(statements)
1732                }
1733            }
1734            Rule::script_block_expression => {
1735                Val::ScriptBlock(self.parse_script_block_expression(token)?)
1736            }
1737            Rule::hash_literal_expression => self.eval_hash_literal(token)?,
1738            Rule::string_literal => self.eval_string_literal(token)?,
1739            Rule::number_literal => self.eval_number_literal(token)?,
1740            Rule::type_literal => self.eval_type_literal(token)?,
1741            Rule::variable => self.get_variable(token)?,
1742            _ => unexpected_token!(token),
1743        };
1744        log::debug!("eval_value - res: {:?}", res);
1745        Ok(res)
1746    }
1747
1748    fn eval_number_literal(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1749        check_rule!(token, Rule::number_literal);
1750        let mut negate = false;
1751        let mut pairs = token.into_inner();
1752        let mut token = pairs.next().unwrap();
1753
1754        //first handle prefix sign: + or -
1755        if token.as_rule() == Rule::minus {
1756            negate = true;
1757            token = pairs.next().unwrap();
1758        } else if token.as_rule() == Rule::plus {
1759            token = pairs.next().unwrap();
1760        }
1761
1762        let mut val = self.eval_number(token)?;
1763
1764        if negate {
1765            val.neg()?;
1766        }
1767
1768        if let Some(unit) = pairs.next() {
1769            let unit = unit.as_str().to_ascii_lowercase();
1770            let unit_int = match unit.as_str() {
1771                "k" => 1024,
1772                "m" => 1024 * 1024,
1773                "g" => 1024 * 1024 * 1024,
1774                "t" => 1024 * 1024 * 1024 * 1024,
1775                "p" => 1024 * 1024 * 1024 * 1024 * 1024,
1776                _ => 1,
1777            };
1778            val.mul(Val::Int(unit_int))?;
1779        }
1780        Ok(val)
1781    }
1782
1783    fn eval_number(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1784        check_rule!(token, Rule::number);
1785        let mut pairs = token.into_inner();
1786        let token = pairs.next().unwrap();
1787        let v = match token.as_rule() {
1788            Rule::decimal_integer => {
1789                let int_val = token.into_inner().next().unwrap();
1790                Val::Int(int_val.as_str().parse::<i64>().unwrap())
1791            }
1792            Rule::hex_integer => {
1793                let int_val = token.into_inner().next().unwrap();
1794                Val::Int(i64::from_str_radix(int_val.as_str(), 16).unwrap())
1795            }
1796            Rule::float => {
1797                let float_str = token.as_str().trim();
1798                Val::Float(float_str.parse::<f64>()?)
1799                //todo: handle all border cases
1800            }
1801            _ => unexpected_token!(token),
1802        };
1803        Ok(v)
1804    }
1805
1806    fn eval_unary_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1807        check_rule!(token, Rule::unary_exp);
1808        let token = token.into_inner().next().unwrap();
1809        match token.as_rule() {
1810            Rule::expression_with_unary_operator => self.eval_expression_with_unary_operator(token),
1811            Rule::primary_expression => self.eval_primary_expression(token),
1812            _ => unexpected_token!(token),
1813        }
1814    }
1815
1816    fn eval_array_literal_exp_special_case(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1817        check_rule!(token, Rule::array_literal_exp_special_case);
1818        let mut pairs = token.into_inner();
1819        let token = pairs.next().unwrap();
1820
1821        let val = self.eval_array_literal_exp(token)?;
1822        Ok(Val::Array(vec![val]))
1823    }
1824
1825    fn safe_parse_arg(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1826        Ok(if self.skip_error > 0 {
1827            match self.eval_unary_exp(token.clone()) {
1828                Ok(val) => val,
1829                Err(err) => {
1830                    self.errors.push(err);
1831                    Val::ScriptText(token.as_str().to_string())
1832                }
1833            }
1834        } else {
1835            self.eval_unary_exp(token.clone())?
1836        })
1837    }
1838
1839    fn eval_array_literal_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1840        check_rule!(token, Rule::array_literal_exp);
1841        let mut arr = Vec::new();
1842        let mut pairs = token.into_inner();
1843        let token = pairs.next().unwrap();
1844
1845        //if array literal starts with ',' we must eval single element as array too
1846        if let Rule::array_literal_exp_special_case = token.as_rule() {
1847            return self.eval_array_literal_exp_special_case(token);
1848        }
1849
1850        arr.push(self.safe_parse_arg(token)?);
1851        for token in pairs {
1852            arr.push(self.safe_parse_arg(token)?);
1853        }
1854
1855        Ok(if arr.len() == 1 {
1856            arr[0].clone()
1857        } else {
1858            Val::Array(arr)
1859        })
1860    }
1861
1862    fn eval_range_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1863        fn range(mut left: i64, right: i64) -> ParserResult<Vec<Val>> {
1864            if left.abs_diff(right) >= value::MAX_ARRAY_LEN as u64 {
1865                Err(ValError::ArgumentOutOfRange("..".to_string(), right))?
1866            }
1867            let mut v = Vec::new();
1868            if left <= right {
1869                loop {
1870                    v.push(left);
1871                    if left == right {
1872                        break;
1873                    }
1874                    left += 1;
1875                }
1876            } else {
1877                loop {
1878                    v.push(left);
1879                    if left == right {
1880                        break;
1881                    }
1882                    left -= 1;
1883                }
1884            }
1885            Ok(v.into_iter().map(Val::Int).collect())
1886        }
1887        check_rule!(token, Rule::range_exp);
1888        let mut pairs = token.into_inner();
1889        let mut token = pairs.next().unwrap();
1890
1891        let _is_minus = if let Rule::additive_op = token.as_rule() {
1892            token = pairs.next().unwrap();
1893            true
1894        } else {
1895            false
1896        };
1897
1898        let res = match token.as_rule() {
1899            Rule::decimal_integer => {
1900                let int_val = token.into_inner().next().unwrap();
1901                let left = int_val.as_str().parse::<i64>().map_err(|_| {
1902                    ValError::InvalidCast(int_val.as_str().to_string(), "Int64".to_string())
1903                })?;
1904                let mut token = pairs.next().unwrap();
1905                let _is_minus = if let Rule::additive_op = token.as_rule() {
1906                    token = pairs.next().unwrap();
1907                    true
1908                } else {
1909                    false
1910                };
1911                let right = self.eval_array_literal_exp(token)?.cast_to_int()?;
1912                Val::Array(range(left, right)?)
1913            }
1914            Rule::array_literal_exp => {
1915                let res = self.eval_array_literal_exp(token)?;
1916                if let Some(token) = pairs.next() {
1917                    let left = res.cast_to_int()?;
1918                    let right = self.eval_array_literal_exp(token)?.cast_to_int()?;
1919                    Val::Array(range(left, right)?)
1920                } else {
1921                    res
1922                }
1923            }
1924            _ => unexpected_token!(token),
1925        };
1926
1927        Ok(res)
1928    }
1929
1930    fn eval_format_impl(
1931        &mut self,
1932        format: Vec<Val>,
1933        mut pairs: Pairs<'a>,
1934    ) -> ParserResult<Option<Vec<Val>>> {
1935        Ok(if let Some(token) = pairs.next() {
1936            let second_fmt = self.eval_range_exp(token)?;
1937            let format_arg =
1938                if let Some(vec_args) = self.eval_format_impl(second_fmt.cast_to_array(), pairs)? {
1939                    vec_args
1940                } else {
1941                    second_fmt.into_array()
1942                };
1943
1944            Some(
1945                formatting::format_ps_vec(format, &format_arg)?
1946                    .iter()
1947                    .map(|v| Val::String(v.into()))
1948                    .collect(),
1949            )
1950        } else {
1951            None
1952        })
1953    }
1954
1955    fn eval_format_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1956        check_rule!(token, Rule::format_exp);
1957        let mut pairs = token.into_inner();
1958        let format = self.eval_range_exp(pairs.next().unwrap())?;
1959        if let Some(vec_args) = self.eval_format_impl(format.cast_to_array(), pairs)? {
1960            Ok(Val::String(
1961                vec_args
1962                    .iter()
1963                    .map(|v| v.cast_to_string())
1964                    .collect::<Vec<_>>()
1965                    .join(" ")
1966                    .into(),
1967            ))
1968        } else {
1969            Ok(format)
1970        }
1971    }
1972
1973    fn eval_mult(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1974        check_rule!(token, Rule::multiplicative_exp);
1975        let mut pairs = token.into_inner();
1976        let mut res = self.eval_format_exp(pairs.next().unwrap())?;
1977        while let Some(op) = pairs.next() {
1978            let Some(fun) = ArithmeticPred::get(op.as_str()) else {
1979                log::error!("No arithmetic function for operator: {}", op.as_str());
1980                return Err(ParserError::NotImplemented(format!(
1981                    "No arithmetic function for operator: {}",
1982                    op.as_str()
1983                )));
1984            };
1985
1986            let postfix = pairs.next().unwrap();
1987            let right_op = self.eval_format_exp(postfix)?;
1988            res = fun(res, right_op)?;
1989        }
1990
1991        Ok(res)
1992    }
1993
1994    fn eval_additive(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1995        check_rule!(token, Rule::additive_exp);
1996
1997        let mut pairs = token.into_inner();
1998        let token = pairs.next().unwrap();
1999        let mut res = match token.as_rule() {
2000            Rule::multiplicative_exp => self.eval_mult(token)?,
2001            _ => unexpected_token!(token),
2002        };
2003        while let Some(op) = pairs.next() {
2004            //check_rule!(op, Rule::additive_op); plus or minus
2005            let Some(fun) = ArithmeticPred::get(op.as_str()) else {
2006                log::error!("No arithmetic function for operator: {}", op.as_str());
2007                return Err(ParserError::NotImplemented(format!(
2008                    "No arithmetic function for operator: {}",
2009                    op.as_str()
2010                )));
2011            };
2012
2013            let mult = pairs.next().unwrap();
2014            let right_op = match mult.as_rule() {
2015                Rule::multiplicative_exp => self.eval_mult(mult)?,
2016                Rule::pre_arithmetic => self.eval_pre_arithmetic(mult)?,
2017                _ => unexpected_token!(mult),
2018            };
2019            res = fun(res, right_op)?;
2020        }
2021
2022        Ok(res)
2023    }
2024
2025    fn eval_split_special_case(
2026        &mut self,
2027        script_block: ScriptBlock,
2028        input: Val,
2029    ) -> ParserResult<Vec<String>> {
2030        let mut res_vec = vec![];
2031        let mut parts = String::new();
2032        let input_str = input.cast_to_string();
2033        let characters = input_str.chars();
2034
2035        // filtered_elements.join("")
2036        for ch in characters {
2037            let b = match script_block.run(vec![], self, Some(Val::String(ch.to_string().into()))) {
2038                Err(er) => {
2039                    self.errors.push(er);
2040                    false
2041                }
2042                Ok(res) => res.val.cast_to_bool(),
2043            };
2044
2045            if b {
2046                res_vec.push(parts);
2047                parts = String::new();
2048            } else {
2049                parts.push(ch);
2050            }
2051        }
2052        self.variables.reset_ps_item();
2053        Ok(res_vec)
2054    }
2055
2056    fn eval_comparison_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2057        check_rule!(token, Rule::comparison_exp);
2058        let mut pairs = token.into_inner();
2059        let token = pairs.next().unwrap();
2060
2061        // we need to handle strange case. -split and -join can be invoke without
2062        // previous expression, eg. "-join 'some'"
2063        let mut res = if token.as_rule() == Rule::additive_exp {
2064            self.eval_additive(token)?
2065        } else {
2066            Val::Null
2067        };
2068
2069        while let Some(op) = pairs.next() {
2070            let Some(fun) = StringPred::get(op.as_str()) else {
2071                log::error!("No string predicate for operator: {}", op.as_str());
2072                return Err(ParserError::NotImplemented(format!(
2073                    "No string predicate for operator: {}",
2074                    op.as_str()
2075                )));
2076            };
2077
2078            let token = pairs.next().unwrap();
2079            let right_op = match token.as_rule() {
2080                Rule::script_block_expression => {
2081                    let script_block = self.parse_script_block_expression(token)?;
2082
2083                    return Ok(Val::Array(
2084                        self.eval_split_special_case(script_block, res)?
2085                            .into_iter()
2086                            .map(|s| Val::String(s.into()))
2087                            .collect::<Vec<_>>(),
2088                    ));
2089                }
2090                Rule::additive_exp => self.eval_additive(token)?,
2091                //Rule::type_literal => self.eval_type_literal(token)?,
2092                _ => unexpected_token!(token),
2093            };
2094            log::trace!("res: {:?}, right_op: {:?}", &res, &right_op);
2095            res = fun(res, right_op)?;
2096            log::trace!("res: {:?}", &res);
2097        }
2098
2099        Ok(res)
2100    }
2101
2102    fn parse_script_param_block(&mut self, token: Pair<'a>) -> ParserResult<Vec<Param>> {
2103        check_rule!(token, Rule::script_param_block);
2104        let mut pairs = token.into_inner();
2105        let Some(param_block_token) = pairs.next() else {
2106            return Ok(vec![]);
2107        };
2108        self.parse_param_block(param_block_token)
2109    }
2110
2111    fn parse_param_block(&mut self, token: Pair<'a>) -> ParserResult<Vec<Param>> {
2112        check_rule!(token, Rule::param_block);
2113        let mut pairs = token.into_inner();
2114
2115        let Some(token) = pairs.next() else {
2116            return Ok(vec![]);
2117        };
2118
2119        let option_param_token = match token.as_rule() {
2120            Rule::attribute_list => {
2121                //self.parse_attribute_list(token)?;
2122                pairs.next()
2123            }
2124            Rule::parameter_list => Some(token),
2125            _ => unexpected_token!(token),
2126        };
2127
2128        let Some(param_token) = option_param_token else {
2129            return Ok(vec![]);
2130        };
2131        self.parse_parameter_list(param_token)
2132    }
2133
2134    fn parse_parameter_list(&mut self, token: Pair<'a>) -> ParserResult<Vec<Param>> {
2135        check_rule!(token, Rule::parameter_list);
2136        let mut params = vec![];
2137        let param_list_pairs = token.into_inner();
2138        for script_parameter_token in param_list_pairs {
2139            check_rule!(script_parameter_token, Rule::script_parameter);
2140            params.push(self.parse_script_parameter(script_parameter_token)?);
2141        }
2142        Ok(params)
2143    }
2144
2145    fn parse_attribute_list(&mut self, token: Pair<'a>) -> ParserResult<Option<ValType>> {
2146        check_rule!(token, Rule::attribute_list);
2147        let attribute_list_pairs = token.into_inner();
2148        for attribute_token in attribute_list_pairs {
2149            check_rule!(attribute_token, Rule::attribute);
2150            let attribute_type_token = attribute_token.into_inner().next().unwrap();
2151            match attribute_type_token.as_rule() {
2152                Rule::attribute_info => {
2153                    //skip for now
2154                    continue;
2155                }
2156                Rule::type_literal => {
2157                    return Ok(Some(
2158                        self.get_valtype_from_type_literal(attribute_type_token)?,
2159                    ));
2160                }
2161                _ => unexpected_token!(attribute_type_token),
2162            }
2163        }
2164        Ok(None)
2165    }
2166    fn parse_script_parameter(&mut self, token: Pair<'a>) -> ParserResult<Param> {
2167        check_rule!(token, Rule::script_parameter);
2168        let mut pairs = token.into_inner();
2169        let mut token = pairs.next().unwrap();
2170
2171        let type_literal = if token.as_rule() == Rule::attribute_list {
2172            let type_literal = self.parse_attribute_list(token).unwrap_or(None);
2173            token = pairs.next().unwrap();
2174            type_literal
2175        } else {
2176            None
2177        };
2178
2179        check_rule!(token, Rule::variable);
2180        let var_name = Self::parse_variable(token)?;
2181
2182        let default_value = if let Some(default_value_token) = pairs.next() {
2183            check_rule!(default_value_token, Rule::script_parameter_default);
2184            let default_value_expr = default_value_token.into_inner().next().unwrap();
2185            let default_value = self.eval_primary_expression(default_value_expr)?;
2186            Some(default_value)
2187        } else {
2188            None
2189        };
2190        Ok(Param::new(type_literal, var_name.name, default_value))
2191    }
2192
2193    fn eval_bitwise_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2194        check_rule!(token, Rule::bitwise_exp);
2195
2196        let mut pairs = token.into_inner();
2197        let mut res = self.eval_as_exp(pairs.next().unwrap())?;
2198        while let Some(op) = pairs.next() {
2199            check_rule!(op, Rule::bitwise_operator);
2200            let Some(fun) = BitwisePred::get(op.as_str()) else {
2201                log::error!("No bitwise predicate for operator: {}", op.as_str());
2202                return Err(ParserError::NotImplemented(format!(
2203                    "No bitwise predicate for operator: {}",
2204                    op.as_str()
2205                )));
2206            };
2207
2208            let mult = pairs.next().unwrap();
2209            let right_op = self.eval_as_exp(mult)?;
2210            res = fun(res, right_op)?;
2211        }
2212
2213        Ok(res)
2214    }
2215
2216    fn eval_as_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2217        check_rule!(token, Rule::as_expression);
2218
2219        let mut pairs = token.into_inner();
2220        let mut res = self.eval_comparison_exp(pairs.next().unwrap())?;
2221        for token in pairs {
2222            let runtime_object = match token.as_rule() {
2223                Rule::primary_expression => self.eval_primary_expression(token)?,
2224                _ => unexpected_token!(token),
2225            };
2226
2227            res = res.cast(&runtime_object).unwrap_or_default();
2228        }
2229
2230        Ok(res)
2231    }
2232
2233    fn parse_cmdlet_command_name(&mut self, token: Pair<'a>) -> ParserResult<Command> {
2234        check_rule!(token, Rule::cmdlet_command);
2235
2236        let mut pairs = token.into_inner();
2237        let token = pairs.next().unwrap();
2238        let command_name = match token.as_rule() {
2239            Rule::command_name => token.as_str(),
2240            Rule::where_command_name => "where-object",
2241            Rule::foreach_command_name => "foreach-object",
2242            Rule::powershell_command_name => "powershell",
2243            _ => unexpected_token!(token),
2244        };
2245
2246        let mut command = Command::cmdlet(command_name);
2247        if Rule::command_name == token.as_rule() {
2248            command.set_session_scope(SessionScope::New);
2249        }
2250        Ok(command)
2251    }
2252
2253    fn parse_command_args(&mut self, pairs: Pairs<'a>) -> ParserResult<Vec<CommandElem>> {
2254        let mut args = vec![];
2255        for command_element_token in pairs {
2256            let token_string = command_element_token.as_str().to_string();
2257            match command_element_token.as_rule() {
2258                Rule::command_argument => {
2259                    let arg_token = command_element_token.into_inner().next().unwrap();
2260                    let arg = match arg_token.as_rule() {
2261                        Rule::array_literal_exp => self.eval_array_literal_exp(arg_token.clone()),
2262                        Rule::script_block_expression => Ok(Val::ScriptBlock(
2263                            self.parse_script_block_expression(arg_token.clone())?,
2264                        )),
2265                        Rule::parenthesized_expression => {
2266                            self.eval_parenthesized_expression(arg_token.clone())
2267                        }
2268                        Rule::generic_token => {
2269                            let s = arg_token.as_str();
2270                            self.tokens.push(Token::String(s.into()));
2271                            Ok(Val::ScriptText(s.into()))
2272                        }
2273                        _ => Ok(Val::ScriptText(arg_token.as_str().to_string())),
2274                    };
2275                    // an argument that cannot be evaluated, e.g. an unknown variable, stays as text
2276                    let arg = arg.unwrap_or_else(|err| {
2277                        self.errors.push(err);
2278                        Val::ScriptText(arg_token.as_str().to_string())
2279                    });
2280                    args.push(CommandElem::Argument(arg));
2281                }
2282                Rule::command_parameter => {
2283                    args.push(CommandElem::Parameter(token_string.to_ascii_lowercase()))
2284                }
2285                Rule::argument_list => {
2286                    let expression_token = command_element_token.into_inner().next().unwrap();
2287                    let Ok(expr_res) = self.eval_expression(expression_token) else {
2288                        continue;
2289                    };
2290                    if let Val::Array(arr) = expr_res {
2291                        for v in arr {
2292                            args.push(CommandElem::Argument(v));
2293                        }
2294                    } else {
2295                        args.push(CommandElem::Argument(expr_res));
2296                    }
2297                }
2298                Rule::splatten_arg => {
2299                    let var_name = Self::parse_scoped_variable(command_element_token)?;
2300                    let var = self
2301                        .variables
2302                        .get(&var_name, &self.types_map)
2303                        .unwrap_or_default();
2304                    if let Val::HashTable(h) = var {
2305                        for (k, v) in h {
2306                            args.push(CommandElem::Parameter(format!("-{}", k)));
2307                            args.push(CommandElem::Argument(v));
2308                        }
2309                    }
2310                }
2311                Rule::redirection => { //todo: implement redirection
2312                }
2313                Rule::stop_parsing => { //todo: stop parsing
2314                }
2315                _ => unexpected_token!(command_element_token),
2316            }
2317        }
2318        Ok(args)
2319    }
2320
2321    fn eval_command(&mut self, token: Pair<'a>, piped_arg: Option<Val>) -> ParserResult<Val> {
2322        check_rule!(token, Rule::command);
2323        let command_str = token.as_str().to_string();
2324
2325        let mut pairs = token.into_inner();
2326        let command_token = pairs.next().unwrap();
2327        let mut command = match command_token.as_rule() {
2328            Rule::cmdlet_command => self.parse_cmdlet_command_name(command_token)?,
2329            Rule::invocation_command => self.parse_invocation_command(command_token)?,
2330            _ => unexpected_token!(command_token),
2331        };
2332
2333        let mut args = self.parse_command_args(pairs)?;
2334        // the piped value was already tokenized upstream; keeping it here makes tokens quadratic in pipeline length
2335        let token_args = args.iter().map(CommandElem::display).collect();
2336        if let Some(arg) = piped_arg {
2337            args.insert(0, CommandElem::Argument(arg));
2338        }
2339
2340        command.with_args(args);
2341        self.tokens
2342            .push(Token::command(command_str, command.name(), token_args));
2343
2344        match command.execute(self) {
2345            Ok(CommandOutput {
2346                val,
2347                deobfuscated: _deobfuscated,
2348            }) => Ok(val),
2349            Err(e) => {
2350                self.errors.push(e);
2351                Ok(Val::ScriptText(command.to_string()))
2352            }
2353        }
2354
2355        // if let Some(msg) = deobfuscated {
2356        //     self.add_deobfuscated_statement(msg);
2357        // }
2358    }
2359
2360    fn add_deobfuscated_statement(&mut self, msg: String) {
2361        if let Some(last) = self.results.last_mut() {
2362            last.deobfuscated.push(msg);
2363        }
2364    }
2365
2366    fn add_output_statement(&mut self, msg: StreamMessage) {
2367        if let Some(last) = self.results.last_mut() {
2368            last.output.push(msg);
2369        }
2370    }
2371
2372    fn parse_invocation_command(&mut self, token: Pair<'a>) -> ParserResult<Command> {
2373        check_rule!(token, Rule::invocation_command);
2374
2375        let invocation_command_token = token.into_inner().next().unwrap();
2376
2377        let mut session_scope = match invocation_command_token.as_rule() {
2378            Rule::current_scope_invocation_command => SessionScope::Current,
2379            Rule::new_scope_invocation_command => SessionScope::New,
2380            _ => unexpected_token!(invocation_command_token),
2381        };
2382
2383        let token_inner = invocation_command_token.into_inner().next().unwrap();
2384
2385        let mut command = match token_inner.as_rule() {
2386            Rule::cmdlet_command => {
2387                session_scope = SessionScope::New;
2388                self.parse_cmdlet_command_name(token_inner)?
2389            }
2390            Rule::primary_expression => {
2391                let primary = self.eval_primary_expression(token_inner)?;
2392                if let Val::ScriptBlock(script_block) = primary {
2393                    Command::script_block(script_block)
2394                } else {
2395                    Command::cmdlet(&primary.cast_to_string())
2396                }
2397            }
2398            Rule::path_command_name => Command::path(token_inner.as_str()),
2399            _ => unexpected_token!(token_inner),
2400        };
2401
2402        command.set_session_scope(session_scope);
2403        Ok(command)
2404    }
2405
2406    fn eval_redirected_expression(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2407        check_rule!(token, Rule::redirected_expression);
2408
2409        let expression_token = token.into_inner().next().unwrap();
2410        //todo: handle redirections
2411
2412        self.eval_expression(expression_token)
2413    }
2414
2415    fn eval_expression(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2416        check_stack(0)?;
2417        eval_step()?;
2418        check_rule!(token, Rule::expression);
2419        let token_string = token.as_str().trim().to_string();
2420
2421        let mut pairs = token.into_inner();
2422        let mut res = self.eval_bitwise_exp(pairs.next().unwrap())?;
2423        while let Some(op) = pairs.next() {
2424            check_rule!(op, Rule::logical_operator);
2425            let Some(fun) = LogicalPred::get(op.as_str()) else {
2426                log::error!("No logical predicate for operator: {}", op.as_str());
2427                return Err(ParserError::NotImplemented(format!(
2428                    "No logical predicate for operator: {}",
2429                    op.as_str()
2430                )));
2431            };
2432
2433            let mult = pairs.next().unwrap();
2434            let right_op = self.eval_bitwise_exp(mult)?;
2435            res = Val::Bool(fun(res, right_op));
2436        }
2437        self.tokens
2438            .push(Token::expression(token_string, res.clone().into()));
2439
2440        if let Val::String(value::PsString(s)) = &res {
2441            self.tokens.push(Token::String(s.clone()));
2442        }
2443
2444        Ok(res)
2445    }
2446
2447    fn eval_pipeline_tail(&mut self, token: Pair<'a>, mut piped_arg: Val) -> ParserResult<Val> {
2448        check_rule!(token, Rule::pipeline_tail);
2449        let pairs = token.into_inner();
2450
2451        for token in pairs {
2452            //self.variables.set_ps_item(arg);
2453            piped_arg = self.eval_command(token, Some(piped_arg))?;
2454        }
2455
2456        Ok(piped_arg)
2457    }
2458
2459    fn eval_pipeline_with_tail(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2460        check_rule!(token, Rule::pipeline_with_tail);
2461        let mut pairs = token.into_inner();
2462        let token = pairs.next().unwrap();
2463
2464        let result: Val = match token.as_rule() {
2465            Rule::redirected_expression => self.eval_redirected_expression(token)?,
2466            Rule::command => self.eval_command(token, None)?,
2467            _ => unexpected_token!(token),
2468        };
2469
2470        if let Some(token) = pairs.next() {
2471            match token.as_rule() {
2472                Rule::pipeline_tail => Ok(self.eval_pipeline_tail(token, result)?),
2473                _ => unexpected_token!(token),
2474            }
2475        } else {
2476            Ok(result)
2477        }
2478    }
2479
2480    fn eval_pipeline(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2481        check_stack(0)?;
2482        check_rule!(token, Rule::pipeline);
2483        let mut pairs = token.into_inner();
2484        let token = pairs.next().unwrap();
2485
2486        match token.as_rule() {
2487            Rule::assignment_exp => self.eval_assigment_exp(token),
2488            Rule::pipeline_with_tail => self.eval_pipeline_with_tail(token),
2489            _ => unexpected_token!(token),
2490        }
2491    }
2492
2493    fn safe_eval_pipeline(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2494        let res = self.eval_pipeline(token.clone());
2495
2496        let v = match res {
2497            Ok(val) => val,
2498            Err(err) => {
2499                self.errors.push(err);
2500                Val::ScriptText(token.as_str().to_string())
2501            }
2502        };
2503
2504        Ok(v)
2505    }
2506
2507    fn eval_cast_expression(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2508        check_rule!(token, Rule::cast_expression);
2509
2510        let mut pairs = token.into_inner();
2511        let type_token = pairs.next().unwrap();
2512        check_rule!(type_token, Rule::type_literal);
2513        let val_type = self.eval_type_literal(type_token)?;
2514        let token = pairs.next().unwrap();
2515        let res = match token.as_rule() {
2516            Rule::parenthesized_expression => self.eval_parenthesized_expression(token)?,
2517            Rule::unary_exp => self.eval_unary_exp(token)?,
2518            _ => unexpected_token!(token),
2519        };
2520        Ok(res.cast(&val_type)?)
2521    }
2522
2523    fn eval_assigment_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
2524        check_rule!(token, Rule::assignment_exp);
2525
2526        let mut specified_type = None;
2527
2528        let mut pairs = token.into_inner();
2529        let mut token = pairs.next().unwrap();
2530        if token.as_rule() == Rule::type_literal {
2531            specified_type = Some(self.eval_type_literal(token)?);
2532            token = pairs.next().unwrap();
2533        }
2534        let (var_name, access) = self.parse_assignable_variable(token)?;
2535        let mut variable = self
2536            .variables
2537            .get(&var_name, &self.types_map)
2538            .unwrap_or_default();
2539        let mut accessed_elem = &mut variable;
2540
2541        // sometimes we have variable access like $a[0].Property, and we need access
2542        // property by reference
2543        if let Some(access) = access {
2544            for token in access {
2545                accessed_elem = self.variable_access(token, accessed_elem)?;
2546            }
2547        }
2548        let assignement_op = pairs.next().unwrap();
2549
2550        //get operand
2551        let op = assignement_op.into_inner().next().unwrap();
2552        let pred = ArithmeticPred::get(op.as_str());
2553
2554        let right_token = pairs.next().unwrap();
2555        let right_op = self.eval_statement(right_token.clone())?;
2556
2557        let Some(pred) = pred else {
2558            log::error!("No arithmetic function for operator: {}", op.as_str());
2559            return Err(ParserError::NotImplemented(format!(
2560                "No arithmetic function for operator: {}",
2561                op.as_str()
2562            )));
2563        };
2564
2565        *accessed_elem = pred(accessed_elem.clone(), right_op)?;
2566        if let Some(runtime_type) = specified_type {
2567            *accessed_elem = accessed_elem.cast(&runtime_type)?;
2568        }
2569        self.variables.set(&var_name, variable.clone())?;
2570        //we want save each assignment statement
2571        self.add_deobfuscated_statement(format!("{} = {}", var_name, variable.cast_to_script()));
2572
2573        Ok(Val::NonDisplayed(Box::new(variable)))
2574    }
2575
2576    fn push_scope_session(&mut self) {
2577        self.variables.push_scope_session();
2578    }
2579
2580    fn pop_scope_session(&mut self) {
2581        self.variables.pop_scope_session();
2582    }
2583}
2584
2585#[cfg(test)]
2586mod tests {
2587    use pest::Parser;
2588
2589    use super::*;
2590
2591    #[test]
2592    fn comment_and_semicolon() {
2593        let input = r#"
2594# This is a single line comment
2595$a = 1; $b = 2; Write-Output $a
2596
2597Write-Output "Hello"  # Another comment
2598
2599<#
2600    This is a
2601    multi-line block comment
2602#>
2603"#;
2604
2605        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2606    }
2607
2608    #[test]
2609    fn while_loop() {
2610        let input = r#"
2611while ($true) {
2612    if ($someCondition) {
2613        break
2614    }
2615    # other code
2616}
2617"#;
2618
2619        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2620    }
2621
2622    #[test]
2623    fn foreach_loop() {
2624        let input = r#"
2625foreach ($n in $numbers) {
2626    Write-Output $n
2627}
2628"#;
2629
2630        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2631    }
2632
2633    #[test]
2634    fn for_loop() {
2635        let input = r#"
2636# Comma separated assignment expressions enclosed in parentheses.
2637for (($i = 0), ($j = 0); $i -lt 10; $i++)
2638{
2639    "`$i:$i"
2640    "`$j:$j"
2641}
2642"#;
2643
2644        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2645    }
2646
2647    #[test]
2648    fn switch() {
2649        let input = r#"
2650switch ($var) {
2651    "a" { Write-Output "A" }
2652    1 { Write-Output "One" }
2653    default { Write-Output "Other" }
2654}
2655"#;
2656
2657        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2658    }
2659
2660    #[test]
2661    fn functions() {
2662        let input = r#"
2663function Get-Square {
2664    param($x)
2665    return $x * $x
2666}
2667
2668function Say-Hello {
2669    Write-Output "Hello"
2670}
2671"#;
2672
2673        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2674    }
2675
2676    #[test]
2677    fn if_expression() {
2678        let input = r#"
2679$x="hello"
2680        Write-Host $x
2681        $y = 42
2682        Start-Process "notepad.exe"
2683
2684        $x = 42
2685if ($x -eq 1) {
2686    Write-Output "One"
2687} elseif ($x -eq 2) {
2688    Write-Output "Two"
2689} else {
2690    Write-Output "Other"
2691}
2692"#;
2693
2694        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2695    }
2696
2697    #[test]
2698    fn command() {
2699        let input = r#"
2700Get-Process | Where-Object { $_.CPU -gt 100 }
2701"#;
2702
2703        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2704    }
2705
2706    #[test]
2707    fn range() {
2708        let input = r#"
2709$numbers = 1..5
2710"#;
2711
2712        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2713    }
2714
2715    #[test]
2716    fn literals() {
2717        let input = r#"
2718$hex = 0xFF
2719
2720$name = "Alice"
2721$msg = "Hello, $name. Today is $day."
2722$escaped = "She said: `"Hi`""
2723$literal = 'Hello, $name'
2724"#;
2725
2726        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2727    }
2728
2729    #[test]
2730    fn floats() {
2731        let input = r#"
2732    $pi = 3.1415
2733$half = .5
2734"#;
2735
2736        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2737    }
2738
2739    #[test]
2740    fn arrays() {
2741        let input = r#"
2742$a = 1, 2, 3
2743$b = @("one", "two", "three")
2744$c = @(1, 2, @(3, 4))
2745"#;
2746
2747        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2748    }
2749
2750    #[test]
2751    fn static_method_call() {
2752        let input = r#"
2753[Threading.Thread]::Sleep(399)
2754"#;
2755
2756        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2757    }
2758
2759    #[test]
2760    fn neg_pipeline() {
2761        let input = r#"
2762-not $input | Where-Object { $_ -gt 5 }
2763"#;
2764
2765        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2766    }
2767
2768    #[test]
2769    fn amsi_fail() {
2770        let input = r#"
2771#Matt Graebers second Reflection method 
2772$VMRviwsbtehQfPtxbt=$null;
2773$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))"
2774
2775"#;
2776
2777        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
2778    }
2779
2780    #[test]
2781    fn max_nesting_ignores_strings_and_comments() {
2782        assert_eq!(max_nesting("((1))"), 2);
2783        assert_eq!(max_nesting("$x -replace '\\(', ''"), 0);
2784        assert_eq!(max_nesting(&"$x = $x -replace '\\(', ''\n".repeat(100)), 0);
2785        assert_eq!(max_nesting("\"(((\""), 0);
2786        assert_eq!(max_nesting("\"$(1 + $(2))\""), 2);
2787        assert_eq!(max_nesting("\"a $(\"b $(1)\")\""), 2);
2788        assert_eq!(max_nesting("# ((((\n(1)"), 1);
2789        assert_eq!(max_nesting("<# (((( #> (1)"), 1);
2790        assert_eq!(max_nesting("@'\n((((\n'@\n(1)"), 1);
2791        assert_eq!(max_nesting("@\"\n(( \" $(1)\n\"@"), 1);
2792        assert_eq!(max_nesting("'it''s ((' + (1)"), 1);
2793        assert_eq!(max_nesting("\"say \"\"(\"\" $(1)\""), 1);
2794        assert_eq!(max_nesting("\"`\"(\" + (1)"), 1);
2795        assert_eq!(max_nesting("`(1"), 0);
2796    }
2797
2798    #[test]
2799    fn failed_index_not_evaluated_twice() {
2800        let mut ps = PowerShellSession::new();
2801        assert_eq!(ps.safe_eval("$a=@(1,2); $i=5; $a[0][$i++]; $i").unwrap(), "6");
2802    }
2803
2804    #[test]
2805    fn unclosed_nesting_hits_parse_budget() {
2806        for open in ["(", "$(", "@(", "{"] {
2807            let start = std::time::Instant::now();
2808            // bypasses the stack guard, which in debug builds rejects this depth on its own
2809            let input = open.repeat(24);
2810            let res = parse_program(&input);
2811            assert_eq!(res.err(), Some(ParserError::ParseBudgetExceeded), "{open}");
2812            assert!(start.elapsed().as_secs() < 5, "{open}: {:?}", start.elapsed());
2813        }
2814    }
2815
2816    #[test]
2817    fn pipeline_tokens_do_not_grow_with_piped_values() {
2818        let script = vec!["Foo-Bar"; 2000].join(" | ");
2819        let res = PowerShellSession::new().parse_command(&script).unwrap();
2820        let arg_bytes: usize = res
2821            .tokens()
2822            .all()
2823            .iter()
2824            .filter_map(|t| match t {
2825                Token::Command(cmd) => Some(cmd.args().iter().map(String::len).sum::<usize>()),
2826                _ => None,
2827            })
2828            .sum();
2829        assert!(arg_bytes < script.len(), "{arg_bytes}");
2830    }
2831
2832    #[test]
2833    fn wide_call_tree_hits_eval_budget() {
2834        // 10^6 calls at depth 7, shallow enough for the stack guard
2835        let mut script = "function f0 { 1 }\n".to_string();
2836        for i in 1..7 {
2837            script += &format!("function f{i} {{ {} }}\n", vec![format!("f{}", i - 1); 10].join("; "));
2838        }
2839        script += "f6";
2840
2841        let start = std::time::Instant::now();
2842        let res = PowerShellSession::new().parse_command(&script).unwrap();
2843        assert!(res.errors().contains(&ParserError::EvalBudgetExceeded));
2844        assert!(start.elapsed().as_secs() < 60, "{:?}", start.elapsed());
2845    }
2846
2847    #[test]
2848    fn recursion_with_large_body_hits_eval_deadline() {
2849        // every call re-parses the body but counts as a few steps only; debug builds parse ~10x slower
2850        let repeat = if cfg!(debug_assertions) { 2000 } else { 8000 };
2851        let script = format!("function f {{ f; f; {} }}; f", "$a = 1; ".repeat(repeat));
2852
2853        let start = std::time::Instant::now();
2854        let hit_budget = match PowerShellSession::new().parse_command(&script) {
2855            Ok(res) => res.errors().contains(&ParserError::EvalBudgetExceeded),
2856            // a loaded machine can run out of time already in the top-level parse
2857            Err(err) => err == ParserError::ParseBudgetExceeded,
2858        };
2859        assert!(hit_budget);
2860        assert!(start.elapsed().as_secs() < 10, "{:?}", start.elapsed());
2861    }
2862}