ps_parser/
parser.rs

1mod command;
2mod error;
3mod predicates;
4mod script_result;
5mod stream_message;
6mod token;
7mod value;
8mod variables;
9
10use std::collections::HashMap;
11
12pub(crate) use command::CommandError;
13use command::{Command, CommandElem};
14pub(crate) use stream_message::StreamMessage;
15use value::{RuntimeObject, ScriptBlock, ValResult};
16use variables::Scope;
17type ParserResult<T> = core::result::Result<T, ParserError>;
18use error::ParserError;
19type PestError = pest::error::Error<Rule>;
20use pest::Parser;
21use pest_derive::Parser;
22use predicates::{ArithmeticPred, BitwisePred, LogicalPred, StringPred};
23pub use script_result::{PsValue, ScriptResult};
24pub use token::{Token, Tokens};
25pub(crate) use value::{Val, ValType};
26pub use variables::Variables;
27use variables::{VarName, VariableError};
28
29use crate::parser::command::CommandOutput;
30
31type Pair<'i> = ::pest::iterators::Pair<'i, Rule>;
32type Pairs<'i> = ::pest::iterators::Pairs<'i, Rule>;
33
34pub(crate) const NEWLINE: &str = "\n";
35
36macro_rules! check_rule {
37    ($pair:expr, $rule:pat) => {
38        if !matches!($pair.as_rule(), $rule) {
39            panic!("rule: {:?}", $pair.as_rule());
40        }
41    };
42}
43
44#[derive(Parser)]
45#[grammar = "powershell.pest"]
46pub struct PowerShellSession {
47    variables: Variables,
48    tokens: Tokens,
49    errors: Vec<ParserError>,
50    output: Vec<StreamMessage>,
51    deobfuscated_statements: Vec<String>,
52}
53
54impl Default for PowerShellSession {
55    fn default() -> Self {
56        Self::new()
57    }
58}
59
60impl<'a> PowerShellSession {
61    /// Creates a new PowerShell parsing session with default settings.
62    ///
63    /// The session is initialized with built-in variables like `$true`,
64    /// `$false`, `$null`, and special variables like `$?` for error status
65    /// tracking.
66    ///
67    /// # Returns
68    ///
69    /// A new `PowerShellSession` instance ready for script evaluation.
70    ///
71    /// # Examples
72    ///
73    /// ```rust
74    /// use ps_parser::PowerShellSession;
75    ///
76    /// let mut session = PowerShellSession::new();
77    /// let result = session.safe_eval("$true").unwrap();
78    /// assert_eq!(result, "True");
79    /// ```
80    pub fn new() -> Self {
81        Self {
82            variables: Variables::new(),
83            tokens: Tokens::new(),
84            errors: Vec::new(),
85            output: Vec::new(),
86            deobfuscated_statements: Vec::new(),
87        }
88    }
89
90    /// Creates a new PowerShell session with the provided variables.
91    ///
92    /// This constructor allows you to initialize the session with a custom set
93    /// of variables, such as environment variables or variables loaded from
94    /// configuration files.
95    ///
96    /// # Arguments
97    ///
98    /// * `variables` - A `Variables` instance containing the initial variable
99    ///   set.
100    ///
101    /// # Returns
102    ///
103    /// A new `PowerShellSession` instance with the provided variables.
104    ///
105    /// # Examples
106    ///
107    /// ```rust
108    /// use ps_parser::{PowerShellSession, Variables};
109    ///
110    /// let env_vars = Variables::env();
111    /// let mut session = PowerShellSession::new().with_variables(env_vars);
112    /// let username = session.safe_eval("$env:USERNAME").unwrap();
113    /// ```
114    pub fn with_variables(mut self, variables: Variables) -> Self {
115        self.variables = variables;
116        self
117    }
118
119    /// Safely evaluates a PowerShell script and returns the output as a string.
120    ///
121    /// This method parses and evaluates the provided PowerShell script,
122    /// handling errors gracefully and returning the result as a formatted
123    /// string. It's the recommended method for simple script evaluation.
124    ///
125    /// # Arguments
126    ///
127    /// * `script` - A string slice containing the PowerShell script to
128    ///   evaluate.
129    ///
130    /// # Returns
131    ///
132    /// * `Result<String, ParserError>` - The output of the script evaluation,
133    ///   or an error if parsing/evaluation fails.
134    ///
135    /// # Examples
136    ///
137    /// ```rust
138    /// use ps_parser::PowerShellSession;
139    ///
140    /// let mut session = PowerShellSession::new();
141    ///
142    /// // Simple arithmetic
143    /// let result = session.safe_eval("1 + 2 * 3").unwrap();
144    /// assert_eq!(result, "7");
145    ///
146    /// // Variable assignment and retrieval
147    /// let result = session.safe_eval("$name = 'World'; \"Hello $name\"").unwrap();
148    /// assert_eq!(result, "Hello World");
149    /// ```
150    pub fn safe_eval(&mut self, script: &str) -> Result<String, ParserError> {
151        Ok(self.parse_input(script)?.result().to_string())
152    }
153
154    /// Parses and evaluates a PowerShell script, returning detailed results.
155    ///
156    /// This method provides comprehensive information about the parsing and
157    /// evaluation process, including the final result, generated output,
158    /// any errors encountered, and the tokenized representation of the
159    /// script. It's particularly useful for debugging and deobfuscation.
160    ///
161    /// # Arguments
162    ///
163    /// * `input` - A string slice containing the PowerShell script to parse and
164    ///   evaluate.
165    ///
166    /// # Returns
167    ///
168    /// * `Result<ScriptResult, ParserError>` - A detailed result containing the
169    ///   evaluation outcome, output, errors, and tokens, or a parsing error if
170    ///   the script is malformed.
171    ///
172    /// # Examples
173    ///
174    /// ```rust
175    /// use ps_parser::PowerShellSession;
176    ///
177    /// let mut session = PowerShellSession::new();
178    /// let script_result = session.parse_input("$a = 42; Write-Output $a").unwrap();
179    ///
180    /// println!("Final result: {:?}", script_result.result());
181    /// println!("Generated output: {:?}", script_result.output());
182    /// println!("Parsing errors: {:?}", script_result.errors());
183    /// println!("Deobfuscated code: {:?}", script_result.deobfuscated());
184    /// ```
185    pub fn parse_input(&mut self, input: &str) -> Result<ScriptResult, ParserError> {
186        let mut pairs = PowerShellSession::parse(Rule::program, input)?;
187        let program_token = pairs.next().expect("");
188
189        //let mut script_statements = Vec::new();
190        let mut script_last_output = Val::default();
191
192        if let Rule::program = program_token.as_rule() {
193            let pairs = program_token.into_inner();
194
195            //println!("token: {} deobfuscated: {:?}", token.as_str(),
196            // &self.deobfuscated_statements);
197            for token in pairs {
198                let token_str = token.as_str();
199                let result = match token.as_rule() {
200                    Rule::pipeline => {
201                        //first assign to output, later create from it script line
202                        //self.eval_pipeline(token.clone())
203                        let mut pairs = token.into_inner();
204                        let token = pairs.next().unwrap();
205
206                        match token.as_rule() {
207                            Rule::assignment_exp => {
208                                let result = self.eval_assigment_exp(token);
209                                //we don't want print assignent result to deobfuscated script.
210                                // Thats why we always return null
211                                result.map(|_| Val::Null)
212                            }
213                            Rule::pipeline_with_tail => self.eval_pipeline_with_tail(token),
214                            _ => panic!("not possible: {:?}", token.as_rule()),
215                        }
216                    }
217                    Rule::statement_terminator => continue,
218                    Rule::EOI => break,
219                    _ => {
220                        log::error!("parse_input not implemented: {:?}", token.as_rule());
221                        Err(ParserError::NotImplemented(format!(
222                            "Not implemented: {:?}",
223                            token.as_rule()
224                        )))
225                    }
226                };
227
228                self.variables.set_status(result.is_ok());
229
230                script_last_output = match result {
231                    Ok(val) => {
232                        if val != Val::Null {
233                            self.output.push(val.display().into());
234                        }
235
236                        val
237                    }
238                    Err(e) => {
239                        self.errors.push(e);
240                        self.deobfuscated_statements.push(token_str.into());
241                        Val::Null
242                    }
243                };
244            }
245        }
246
247        Ok(ScriptResult::new(
248            script_last_output,
249            std::mem::take(&mut self.output),
250            std::mem::take(&mut self.deobfuscated_statements),
251            std::mem::take(&mut self.tokens),
252            std::mem::take(&mut self.errors),
253        ))
254    }
255
256    pub(crate) fn eval_script_block(
257        &mut self,
258        input: &ScriptBlock,
259        ps_item: &Val,
260    ) -> ParserResult<bool> {
261        self.variables.set_ps_item(ps_item.clone());
262        let mut new_session = PowerShellSession::new().with_variables(self.variables.clone());
263        let res = new_session
264            .parse_input(input.0.as_str())?
265            .result()
266            .is_true();
267        self.variables.reset_ps_item();
268        Ok(res)
269    }
270
271    fn eval_statement(&mut self, token: Pair<'a>) -> ParserResult<Val> {
272        match token.as_rule() {
273            Rule::pipeline => self.eval_pipeline(token),
274            _ => Err(ParserError::NotImplemented(format!(
275                "Not implemented: {:?}",
276                token.as_rule()
277            )))?,
278        }
279    }
280
281    fn safe_eval_sub_expr(&mut self, token: Pair<'a>) -> ParserResult<Val> {
282        match self.eval_statements(token.clone()) {
283            Ok(vals) => Ok(Val::Array(vals)),
284            Err(err) => {
285                self.errors.push(err);
286                Ok(Val::ScriptText(token.as_str().to_string()))
287            }
288        }
289    }
290
291    fn eval_statements(&mut self, token: Pair<'a>) -> ParserResult<Vec<Val>> {
292        //check_rule!(token, Rule::statements);
293        let pairs = token.into_inner();
294        let mut statements = vec![];
295
296        for token in pairs {
297            let s = self.eval_statement(token)?;
298            statements.push(s);
299        }
300        Ok(statements)
301    }
302
303    fn parse_dq(&mut self, token: Pair<'a>) -> ParserResult<String> {
304        let mut res_str = String::new();
305        let pairs = token.into_inner();
306        for token in pairs {
307            let token = token.into_inner().next().unwrap();
308            let s = match token.as_rule() {
309                Rule::variable => self.get_variable(token)?.cast_to_string(),
310                Rule::sub_expression => self.safe_eval_sub_expr(token)?.cast_to_string(),
311                Rule::backtick_escape => token
312                    .as_str()
313                    .strip_prefix("`")
314                    .unwrap_or_default()
315                    .to_string(),
316                _ => token.as_str().to_string(),
317            };
318            res_str.push_str(s.as_str());
319        }
320        Ok(res_str)
321    }
322
323    fn eval_string_literal(&mut self, token: Pair<'a>) -> ParserResult<Val> {
324        check_rule!(token, Rule::string_literal);
325        let mut pair = token.into_inner();
326        let token = pair.next().unwrap();
327        let cloned_token = token.clone();
328
329        let mut is_expandable = false;
330        let res = match token.as_rule() {
331            Rule::doublequoted_string_literal | Rule::doublequoted_multiline_string_literal => {
332                is_expandable = true;
333                self.parse_dq(token)?
334            }
335            Rule::singlequoted_string_literal => {
336                if let Some(stripped_prefix) = token.as_str().to_string().strip_prefix("'") {
337                    if let Some(stripped_suffix) = stripped_prefix.to_string().strip_suffix("'") {
338                        stripped_suffix.to_string()
339                    } else {
340                        panic!("no suffix")
341                    }
342                } else {
343                    panic!("no prefix")
344                }
345            }
346            Rule::singlequoted_multiline_string_literal => {
347                let mut res_str = String::new();
348                let pairs = token.into_inner();
349                for token in pairs {
350                    res_str.push_str(token.as_str());
351                }
352                res_str
353            }
354            _ => {
355                panic!("eval_string_literal - token.rule(): {:?}", token.as_rule());
356            }
357        };
358        let ps_token = if is_expandable {
359            Token::StringExpandable(cloned_token.as_str().to_string(), res.clone())
360        } else {
361            Token::String(cloned_token.as_str().to_string())
362        };
363        self.tokens.push(ps_token);
364
365        Ok(Val::String(res.into()))
366    }
367
368    fn get_variable(&mut self, token: Pair<'a>) -> ParserResult<Val> {
369        check_rule!(token, Rule::variable);
370        let var_name = Self::parse_variable(token)?;
371        let Some(var) = self.variables.get(&var_name) else {
372            return Err(ParserError::VariableError(VariableError::NotDefined(
373                var_name.name,
374            )));
375        };
376        Ok(var)
377    }
378
379    fn parse_variable(token: Pair<'a>) -> ParserResult<VarName> {
380        check_rule!(token, Rule::variable);
381        let mut pair = token.into_inner();
382        let token = pair.next().unwrap();
383
384        Ok(match token.as_rule() {
385            Rule::special_variable => VarName::new(Scope::Special, token.as_str().to_string()),
386            Rule::parenthesized_variable => {
387                Self::parse_variable(token.into_inner().next().unwrap())?
388            }
389            Rule::braced_variable => {
390                let token = token.into_inner().next().unwrap();
391                let var = token.as_str().to_ascii_lowercase();
392                let splits: Vec<&str> = var.split(":").collect();
393                if splits.len() == 2 {
394                    VarName::new(Scope::from(splits[0]), splits[1].to_string())
395                } else {
396                    VarName::new(Scope::Global, var)
397                }
398            }
399            Rule::scoped_variable => {
400                let mut pairs = token.into_inner();
401                let mut token = pairs.next().unwrap();
402
403                let scope = if token.as_rule() == Rule::scope_keyword {
404                    let scope = token.as_str().to_ascii_lowercase();
405                    token = pairs.next().unwrap();
406                    check_rule!(token, Rule::var_name);
407                    Scope::from(scope.as_str())
408                } else {
409                    Scope::Global
410                };
411                VarName::new(scope, token.as_str().to_ascii_lowercase())
412            }
413            _ => {
414                panic!("token.rule(): {:?}", token.as_rule());
415            }
416        })
417    }
418
419    fn eval_expression_with_unary_operator(&mut self, token: Pair<'a>) -> ParserResult<Val> {
420        check_rule!(token, Rule::expression_with_unary_operator);
421        let mut pair = token.into_inner();
422        let token = pair.next().unwrap();
423
424        let res = match token.as_rule() {
425            Rule::pre_inc_expression => {
426                let variable_token = token.into_inner().next().unwrap();
427                let var_name = Self::parse_variable(variable_token)?;
428                let mut var = self.variables.get(&var_name).unwrap_or_default();
429                var.inc()?;
430
431                self.variables.set(&var_name, var.clone())?;
432                var
433            }
434            Rule::pre_dec_expression => {
435                let variable_token = token.into_inner().next().unwrap();
436                let var_name = Self::parse_variable(variable_token)?;
437                let mut var = self.variables.get(&var_name).unwrap_or_default();
438                var.dec()?;
439
440                self.variables.set(&var_name, var.clone())?;
441                var
442            }
443            Rule::cast_expression => self.eval_cast_expression(token)?,
444            Rule::negate_op => {
445                let unary_token = pair.next().unwrap();
446                let unary = self.eval_unary_exp(unary_token)?;
447                Val::Bool(!unary.cast_to_bool())
448            }
449            Rule::bitwise_negate_op => {
450                let unary_token = pair.next().unwrap();
451                let unary = self.eval_unary_exp(unary_token)?;
452                Val::Int(!unary.cast_to_int()?)
453            }
454            _ => {
455                panic!("token.rule(): {:?}", token.as_rule());
456            }
457        };
458
459        Ok(res)
460    }
461
462    fn eval_argument_list(&mut self, token: Pair<'a>) -> ParserResult<Vec<Val>> {
463        check_rule!(token, Rule::argument_list);
464        let pairs = token.into_inner();
465
466        let mut args = Vec::new();
467        for token in pairs {
468            args.push(self.eval_expression(token)?);
469        }
470
471        Ok(args)
472    }
473
474    fn eval_member_access(&mut self, token: Pair<'a>) -> ParserResult<String> {
475        //check_rule!(token, Rule::member_access);
476        let member_name_token = token.into_inner().next().unwrap();
477        let member_name = member_name_token.as_str().to_ascii_lowercase();
478
479        Ok(member_name)
480    }
481
482    fn method_is_static(&mut self, token: Pair<'a>) -> bool {
483        check_rule!(token, Rule::method_invocation);
484        let mut pairs = token.into_inner();
485
486        let access = pairs.next().unwrap();
487        match access.as_rule() {
488            Rule::member_access => false,
489            Rule::static_access => true,
490            _ => todo!(),
491        }
492    }
493
494    fn eval_method_invokation(&mut self, token: Pair<'a>) -> ParserResult<(String, Vec<Val>)> {
495        check_rule!(token, Rule::method_invocation);
496        let token_string = token.as_str().to_string();
497
498        let mut pairs = token.into_inner();
499
500        let access = pairs.next().unwrap();
501        //check_rule!(member_access, Rule::member_access);
502        let method_name = self.eval_member_access(access)?;
503
504        let args = if let Some(token) = pairs.next() {
505            check_rule!(token, Rule::argument_list);
506            self.eval_argument_list(token)?
507        } else {
508            Vec::new()
509        };
510
511        self.tokens.push(Token::Function(
512            token_string,
513            method_name.clone(),
514            args.clone().iter().map(|arg| arg.clone().into()).collect(),
515        ));
516        Ok((method_name, args))
517    }
518
519    fn eval_access(&mut self, token: Pair<'a>) -> ParserResult<Val> {
520        fn get_member_name(token: Pair<'_>) -> &'_ str {
521            token.into_inner().next().unwrap().as_str()
522        }
523        check_rule!(token, Rule::access);
524        let mut pairs = token.into_inner();
525        let token = pairs.next().unwrap();
526
527        let mut object = self.eval_value(token)?;
528
529        for token in pairs {
530            match token.as_rule() {
531                Rule::static_access => {
532                    object = object.get_static_member(get_member_name(token))?;
533                }
534                Rule::member_access => {
535                    object = object.get_member(get_member_name(token))?;
536                }
537                Rule::method_invocation => {
538                    let static_method = self.method_is_static(token.clone());
539                    let (function_name, args) = self.eval_method_invokation(token)?;
540                    log::trace!("Method: {:?} {:?}", &function_name, &args);
541                    object = if static_method {
542                        let call = object.get_static_fn(function_name.as_str())?;
543                        call(args)?
544                    } else {
545                        let call = object.get_method(function_name.as_str())?;
546                        call(object, args)?
547                    };
548                }
549                Rule::element_access => {
550                    let mut pairs = token.into_inner();
551                    let index_token = pairs.next().unwrap();
552                    check_rule!(index_token, Rule::expression);
553                    let index = self.eval_expression(index_token)?;
554                    object = object.get_index(index)?;
555                }
556                _ => {
557                    panic!("token.rule(): {:?}", token.as_rule());
558                }
559            }
560        }
561        log::debug!("Success eval_access: {:?}", object);
562        Ok(object)
563    }
564
565    fn parse_access(&mut self, token: Pair<'a>) -> ParserResult<Val> {
566        check_rule!(token, Rule::access);
567        let mut pairs = token.into_inner();
568        let token = pairs.next().unwrap();
569
570        let mut object = token.as_str().to_string();
571
572        for token in pairs {
573            match token.as_rule() {
574                Rule::static_access => {
575                    object.push_str("::");
576                    object.push_str(token.as_str());
577                }
578                Rule::member_access => {
579                    //object.push('.');
580                    object.push_str(token.as_str());
581                }
582                Rule::method_invocation => {
583                    let static_method = self.method_is_static(token.clone());
584                    let (method_name, args) = self.eval_method_invokation(token)?;
585
586                    let separator = if static_method { "::" } else { "." };
587                    object = format!(
588                        "{}{separator}{}({:?})",
589                        object,
590                        method_name.to_ascii_lowercase(),
591                        args
592                    )
593                }
594                Rule::element_access => {
595                    let mut pairs = token.into_inner();
596                    let index_token = pairs.next().unwrap();
597                    check_rule!(index_token, Rule::expression);
598                    let index = self.eval_expression(index_token)?;
599                    object = format!("{}[{}]", object, index);
600                }
601                _ => {
602                    panic!("parse_access token.rule(): {:?}", token.as_rule());
603                }
604            }
605        }
606        Ok(Val::String(object.into()))
607    }
608
609    fn eval_primary_expression(&mut self, token: Pair<'a>) -> ParserResult<Val> {
610        check_rule!(token, Rule::primary_expression);
611        let mut pair = token.into_inner();
612        let token = pair.next().unwrap();
613        let res = match token.as_rule() {
614            Rule::access => match self.eval_access(token.clone()) {
615                Ok(res) => res,
616                Err(err) => {
617                    log::info!("eval_access error: {:?}", err);
618                    self.errors.push(err);
619                    self.parse_access(token)?
620                }
621            },
622            Rule::value => self.eval_value(token)?,
623            Rule::post_inc_expression => {
624                let variable_token = token.into_inner().next().unwrap();
625                let var_name = Self::parse_variable(variable_token)?;
626                let mut var = self.variables.get(&var_name).unwrap_or_default();
627                let var_to_return = var.clone();
628
629                var.inc()?;
630                self.variables.set(&var_name, var.clone())?;
631
632                //if var_to_return.ttype() ==
633                var_to_return
634            }
635            Rule::post_dec_expression => {
636                let variable_token = token.into_inner().next().unwrap();
637                let var_name = Self::parse_variable(variable_token)?;
638                let mut var = self.variables.get(&var_name).unwrap_or_default();
639                let var_to_return = var.clone();
640
641                var.dec()?;
642                self.variables.set(&var_name, var.clone())?;
643
644                var_to_return
645            }
646            _ => {
647                panic!(
648                    "eval_primary_expression: rule: {:?} str: {}",
649                    token.as_rule(),
650                    token.as_str()
651                );
652            }
653        };
654
655        Ok(res)
656    }
657
658    fn eval_type_literal(&mut self, token: Pair<'a>) -> ParserResult<ValType> {
659        check_rule!(token, Rule::type_literal);
660
661        let token = token.into_inner().next().unwrap();
662        check_rule!(token, Rule::type_spec);
663        Ok(ValType::cast(token.as_str())?)
664    }
665
666    fn parse_script_block_expression(&mut self, token: Pair<'a>) -> ParserResult<Val> {
667        check_rule!(token, Rule::script_block_expression);
668
669        let mut pairs = token.into_inner();
670        let token = pairs.next().unwrap();
671
672        Ok(Val::ScriptBlock(ScriptBlock(token.as_str().to_string())))
673    }
674
675    fn eval_hash_key(&mut self, token: Pair<'a>) -> ParserResult<String> {
676        check_rule!(token, Rule::key_expression);
677        let mut pairs = token.into_inner();
678        let key_token = pairs.next().unwrap();
679
680        Ok(match key_token.as_rule() {
681            Rule::simple_name => key_token.as_str().to_ascii_lowercase(),
682            Rule::unary_exp => self
683                .eval_unary_exp(key_token)?
684                .cast_to_string()
685                .to_ascii_lowercase(),
686            _ => {
687                panic!("key_token.rule(): {:?}", key_token.as_rule());
688            }
689        })
690    }
691
692    fn eval_hash_entry(&mut self, token: Pair<'a>) -> ParserResult<(String, Val)> {
693        check_rule!(token, Rule::hash_entry);
694
695        let mut pairs = token.into_inner();
696        let token_key = pairs.next().unwrap();
697        let token_value = pairs.next().unwrap();
698
699        Ok((
700            self.eval_hash_key(token_key)?,
701            self.eval_statement(token_value)?,
702        ))
703    }
704
705    fn eval_hash_literal(&mut self, token: Pair<'a>) -> ParserResult<Val> {
706        check_rule!(token, Rule::hash_literal_expression);
707        let pairs = token.into_inner();
708        let mut hash = HashMap::new();
709        for token in pairs {
710            let (key, value) = self.eval_hash_entry(token)?;
711            hash.insert(key, value);
712        }
713        Ok(Val::HashTable(hash))
714    }
715
716    fn eval_value(&mut self, token: Pair<'a>) -> ParserResult<Val> {
717        check_rule!(token, Rule::value);
718        let mut pair = token.into_inner();
719        let token = pair.next().unwrap();
720
721        let res = match token.as_rule() {
722            Rule::parenthesized_expression => {
723                let token = token.into_inner().next().unwrap();
724                self.safe_eval_pipeline(token)?
725            }
726            Rule::sub_expression | Rule::array_expression => {
727                let statements = self.eval_statements(token)?;
728                if statements.len() == 1 && statements[0].ttype() == ValType::Array {
729                    statements[0].clone()
730                } else {
731                    Val::Array(statements)
732                }
733            }
734            Rule::script_block_expression => self.parse_script_block_expression(token)?,
735            Rule::hash_literal_expression => self.eval_hash_literal(token)?,
736            Rule::string_literal => self.eval_string_literal(token)?,
737            Rule::number_literal => self.eval_number_literal(token)?,
738            Rule::type_literal => Val::init(self.eval_type_literal(token)?)?,
739            Rule::variable => self.get_variable(token)?,
740            _ => {
741                panic!("token.rule(): {:?}", token.as_rule());
742            }
743        };
744        log::debug!("eval_value - res: {:?}", res);
745        Ok(res)
746    }
747
748    fn eval_number_literal(&mut self, token: Pair<'a>) -> ParserResult<Val> {
749        check_rule!(token, Rule::number_literal);
750        let mut negate = false;
751        let mut pairs = token.into_inner();
752        let mut token = pairs.next().unwrap();
753
754        //first handle prefix sign: + or -
755        if token.as_rule() == Rule::minus {
756            negate = true;
757            token = pairs.next().unwrap();
758        } else if token.as_rule() == Rule::plus {
759            token = pairs.next().unwrap();
760        }
761
762        let mut val = self.eval_number(token)?;
763
764        if negate {
765            val.neg()?;
766        }
767
768        if let Some(unit) = pairs.next() {
769            let unit = unit.as_str().to_ascii_lowercase();
770            let unit_int = match unit.as_str() {
771                "k" => 1024,
772                "m" => 1024 * 1024,
773                "g" => 1024 * 1024 * 1024,
774                "t" => 1024 * 1024 * 1024 * 1024,
775                "p" => 1024 * 1024 * 1024 * 1024 * 1024,
776                _ => 1,
777            };
778            val.mul(Val::Int(unit_int))?;
779        }
780        Ok(val)
781    }
782
783    fn eval_number(&mut self, token: Pair<'a>) -> ParserResult<Val> {
784        check_rule!(token, Rule::number);
785        let mut pairs = token.into_inner();
786        let token = pairs.next().unwrap();
787        let v = match token.as_rule() {
788            Rule::decimal_integer => {
789                let int_val = token.into_inner().next().unwrap();
790                Val::Int(int_val.as_str().parse::<i64>().unwrap())
791            }
792            Rule::hex_integer => {
793                let int_val = token.into_inner().next().unwrap();
794                Val::Int(i64::from_str_radix(int_val.as_str(), 16).unwrap())
795            }
796            //todo: parse float in proper way
797            Rule::float => {
798                let float_str = token.as_str().trim();
799
800                match float_str.parse::<f64>() {
801                    Ok(float_val) => Val::Float(float_val),
802                    Err(err) => {
803                        println!("eval_number - invalid float: {}: asd {}", float_str, err);
804                        panic!("eval_number - invalid float: {}: {}", float_str, err);
805                    }
806                }
807            }
808            _ => {
809                panic!("eval_number - token.rule(): {:?}", token.as_rule());
810            }
811        };
812        Ok(v)
813    }
814
815    fn eval_unary_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
816        check_rule!(token, Rule::unary_exp);
817        let token = token.into_inner().next().unwrap();
818        match token.as_rule() {
819            Rule::expression_with_unary_operator => self.eval_expression_with_unary_operator(token),
820            Rule::primary_expression => self.eval_primary_expression(token),
821            _ => {
822                panic!("eval_unary_exp token.rule(): {:?}", token.as_rule());
823            }
824        }
825    }
826
827    fn eval_array_literal_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
828        check_rule!(token, Rule::array_literal_exp);
829        let mut arr = Vec::new();
830        let mut pairs = token.into_inner();
831        arr.push(self.eval_unary_exp(pairs.next().unwrap())?);
832        for token in pairs {
833            arr.push(self.eval_unary_exp(token)?);
834        }
835
836        Ok(if arr.len() == 1 {
837            arr[0].clone()
838        } else {
839            Val::Array(arr)
840        })
841    }
842
843    fn eval_range_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
844        fn range(left: i64, right: i64) -> Vec<Val> {
845            if left < right {
846                (left..=right).collect::<Vec<i64>>()
847            } else {
848                let mut v = (right..=left).collect::<Vec<i64>>();
849                v.reverse();
850                v
851            }
852            .into_iter()
853            .map(Val::Int)
854            .collect::<Vec<Val>>()
855        }
856        check_rule!(token, Rule::range_exp);
857        let mut pairs = token.into_inner();
858        let token = pairs.next().unwrap();
859        let res = match token.as_rule() {
860            Rule::decimal_integer => {
861                let int_val = token.into_inner().next().unwrap();
862                let left = int_val.as_str().parse::<i64>().unwrap();
863                let token = pairs.next().unwrap();
864                let right = self.eval_array_literal_exp(token)?.cast_to_int()?;
865                Val::Array(range(left, right))
866            }
867            Rule::array_literal_exp => {
868                let res = self.eval_array_literal_exp(token)?;
869                if let Some(token) = pairs.next() {
870                    let left = res.cast_to_int()?;
871                    let right = self.eval_array_literal_exp(token)?.cast_to_int()?;
872                    Val::Array(range(left, right))
873                } else {
874                    res
875                }
876            }
877            _ => {
878                panic!("eval_range_exp not implemented: {:?}", token.as_rule());
879            }
880        };
881
882        Ok(res)
883    }
884
885    fn eval_format_impl(&mut self, format: Val, mut pairs: Pairs<'a>) -> ParserResult<Val> {
886        fn format_with_vec(fmt: &str, args: Vec<Val>) -> ParserResult<String> {
887            fn strange_special_case(fmt: &str, n: i64) -> String {
888                fn split_digits(n: i64) -> Vec<u8> {
889                    n.abs() // ignore sign for digit splitting
890                        .to_string()
891                        .chars()
892                        .filter_map(|c| c.to_digit(10).map(|opt| opt as u8))
893                        .collect()
894                }
895
896                //"{0:31sdfg,0100a0b00}" -f 578 evals to 310100a5b78
897                let mut digits = split_digits(n);
898                digits.reverse();
899                let mut fmt_vec = fmt.as_bytes().to_vec();
900                fmt_vec.reverse();
901
902                let mut i = 0;
903                for digit in digits {
904                    while i < fmt_vec.len() {
905                        if fmt_vec[i] != b'0' {
906                            i += 1
907                        } else {
908                            fmt_vec[i] = digit + b'0';
909                            break;
910                        }
911                    }
912                }
913                fmt_vec.reverse();
914                String::from_utf8(fmt_vec).unwrap_or_default()
915            }
916
917            let mut output = String::new();
918            let mut i = 0;
919
920            while i < fmt.len() {
921                if fmt[i..].starts_with('{') {
922                    if let Some(end) = fmt[i..].find('}') {
923                        let token = &fmt[i + 1..i + end];
924                        let formatted = if token.contains(':') {
925                            let mut parts = token.split(':');
926                            let index: usize = if let Some(p) = parts.next() {
927                                p.parse().unwrap_or(0)
928                            } else {
929                                0
930                            };
931
932                            let spec = parts.next();
933                            match args.get(index) {
934                                Some(val) => match spec {
935                                    Some(s) if s.starts_with('N') => {
936                                        let precision = s[1..].parse::<usize>().unwrap_or(2);
937                                        if let Ok(f) = val.cast_to_float() {
938                                            format!("{:.1$}", f, precision)
939                                        } else {
940                                            val.cast_to_string().to_string()
941                                        }
942                                    }
943                                    Some(s) => strange_special_case(s, val.cast_to_int()?),
944                                    None => val.cast_to_string().to_string(),
945                                },
946                                None => format!("{{{}}}", token), /* leave as-is if index out of
947                                                                   * bounds */
948                            }
949                        } else if token.contains(',') {
950                            let mut parts = token.split(',');
951                            let index: usize = parts.next().unwrap().parse().unwrap_or(0);
952                            let spec = parts.next();
953                            match args.get(index) {
954                                Some(val) => match spec {
955                                    Some(s) => {
956                                        let spaces = s.parse::<usize>().unwrap_or(0);
957                                        let spaces_str = " ".repeat(spaces);
958                                        format!("{spaces_str}{}", val.cast_to_string())
959                                    }
960                                    _ => val.cast_to_string().to_string(),
961                                },
962                                None => format!("{{{}}}", token), /* leave as-is if index out of
963                                                                   * bounds */
964                            }
965                        } else {
966                            let index: usize =
967                                Val::String(token.to_string().into()).cast_to_int()? as usize;
968                            match args.get(index) {
969                                Some(val) => val.cast_to_string().to_string(),
970                                None => format!("{{{}}}", token), /* leave as-is if index out of
971                                                                   * bounds */
972                            }
973                        };
974
975                        output.push_str(&formatted);
976                        i += end + 1;
977                    } else {
978                        output.push('{');
979                        i += 1;
980                    }
981                } else {
982                    output.push(fmt[i..].chars().next().unwrap());
983                    i += 1;
984                }
985            }
986
987            Ok(output)
988        }
989
990        Ok(if let Some(token) = pairs.next() {
991            let first_fmt = format.cast_to_string();
992
993            let second_fmt = self.eval_range_exp(token)?;
994            let res = self.eval_format_impl(second_fmt, pairs)?;
995            Val::String(format_with_vec(first_fmt.as_str(), res.cast_to_array())?.into())
996        } else {
997            format
998        })
999    }
1000
1001    fn eval_format_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1002        check_rule!(token, Rule::format_exp);
1003        let mut pairs = token.into_inner();
1004        let format = self.eval_range_exp(pairs.next().unwrap())?;
1005        self.eval_format_impl(format, pairs)
1006    }
1007
1008    fn eval_mult(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1009        check_rule!(token, Rule::multiplicative_exp);
1010        let mut pairs = token.into_inner();
1011        let mut res = self.eval_format_exp(pairs.next().unwrap())?;
1012        while let Some(op) = pairs.next() {
1013            let Some(fun) = ArithmeticPred::get(op.as_str()) else {
1014                panic!(
1015                    "can't find arithmetic function for operator: {}",
1016                    op.as_str()
1017                )
1018            };
1019
1020            let postfix = pairs.next().unwrap();
1021            let right_op = self.eval_format_exp(postfix)?;
1022            res = fun(res, right_op)?;
1023        }
1024
1025        Ok(res)
1026    }
1027
1028    fn eval_additive(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1029        check_rule!(token, Rule::additive_exp);
1030
1031        let mut pairs = token.into_inner();
1032        let mut res = self.eval_mult(pairs.next().unwrap())?;
1033        while let Some(op) = pairs.next() {
1034            //check_rule!(op, Rule::additive_op); plus or minus
1035            let Some(fun) = ArithmeticPred::get(op.as_str()) else {
1036                panic!()
1037            };
1038
1039            let mult = pairs.next().unwrap();
1040            let right_op = self.eval_mult(mult)?;
1041            res = fun(res, right_op)?;
1042        }
1043
1044        Ok(res)
1045    }
1046
1047    fn eval_split_special_case(
1048        &mut self,
1049        token: Pair<'a>,
1050        input: Val,
1051    ) -> ParserResult<Vec<String>> {
1052        let mut res_vec = vec![];
1053        let mut parts = String::new();
1054        let input_str = input.cast_to_string();
1055        let characters = input_str.chars();
1056
1057        // filtered_elements.join("")
1058        for ch in characters {
1059            self.variables
1060                .set_ps_item(Val::String(ch.to_string().into()));
1061
1062            let b = match self.eval_script_block(
1063                &ScriptBlock(token.as_str().to_string()),
1064                &Val::String(ch.to_string().into()),
1065            ) {
1066                Err(er) => {
1067                    self.errors.push(er);
1068                    false
1069                }
1070                Ok(b) => b,
1071            };
1072
1073            if b {
1074                res_vec.push(parts);
1075                parts = String::new();
1076            } else {
1077                parts.push(ch);
1078            }
1079        }
1080        self.variables.reset_ps_item();
1081        Ok(res_vec)
1082    }
1083    fn eval_comparison_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1084        check_rule!(token, Rule::comparison_exp);
1085        let mut pairs = token.into_inner();
1086        let token = pairs.next().unwrap();
1087
1088        // we need to handle strange case. -split and -join can be invoke without
1089        // previous expression, eg. "-join 'some'"
1090        let mut res = if token.as_rule() == Rule::additive_exp {
1091            self.eval_additive(token)?
1092        } else {
1093            Val::Null
1094        };
1095
1096        while let Some(op) = pairs.next() {
1097            let Some(fun) = StringPred::get(op.as_str()) else {
1098                panic!("no operator: {}", op.as_str())
1099            };
1100
1101            let token = pairs.next().unwrap();
1102            let right_op = match token.as_rule() {
1103                Rule::script_block_expression => {
1104                    let mut pairs = token.into_inner();
1105                    let token = pairs.next().unwrap();
1106                    check_rule!(token, Rule::script_block_inner);
1107
1108                    let mut pairs = token.into_inner();
1109                    let mut token = pairs.next().unwrap();
1110                    if token.as_rule() == Rule::param_block {
1111                        //skip for now
1112                        token = pairs.next().unwrap();
1113                    }
1114                    check_rule!(token, Rule::script_block);
1115                    return Ok(Val::Array(
1116                        self.eval_split_special_case(token, res)?
1117                            .into_iter()
1118                            .map(|s| Val::String(s.into()))
1119                            .collect::<Vec<_>>(),
1120                    ));
1121                }
1122                Rule::additive_exp => self.eval_additive(token)?,
1123                _ => {
1124                    panic!("eval_comparison_exp not implemented: {:?}", token.as_rule());
1125                }
1126            };
1127            log::trace!("res: {:?}, right_op: {:?}", &res, &right_op);
1128            res = fun(res, right_op)?;
1129            log::trace!("res: {:?}", &res);
1130        }
1131
1132        Ok(res)
1133    }
1134
1135    fn eval_bitwise_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1136        check_rule!(token, Rule::bitwise_exp);
1137
1138        let mut pairs = token.into_inner();
1139        let mut res = self.eval_comparison_exp(pairs.next().unwrap())?;
1140        while let Some(op) = pairs.next() {
1141            check_rule!(op, Rule::bitwise_operator);
1142            let Some(fun) = BitwisePred::get(op.as_str()) else {
1143                panic!()
1144            };
1145
1146            let mult = pairs.next().unwrap();
1147            let right_op = self.eval_comparison_exp(mult)?;
1148            res = fun(res, right_op);
1149        }
1150
1151        Ok(res)
1152    }
1153
1154    fn parse_long_command(&mut self, token: Pair<'a>) -> ParserResult<(String, Vec<CommandElem>)> {
1155        check_rule!(token, Rule::long_command);
1156
1157        let mut pairs = token.into_inner();
1158        let command_name_token = pairs.next().unwrap();
1159        let command_name = command_name_token.as_str();
1160
1161        let mut args = vec![];
1162        for command_element_token in pairs {
1163            let token_string = command_element_token.as_str().to_string();
1164            match command_element_token.as_rule() {
1165                Rule::command_argument => {
1166                    let arg_token = command_element_token.into_inner().next().unwrap();
1167                    let arg = match arg_token.as_rule() {
1168                        Rule::array_literal_exp => self.eval_array_literal_exp(arg_token)?,
1169                        Rule::parenthesized_expression => {
1170                            let token = arg_token.into_inner().next().unwrap();
1171                            self.eval_pipeline(token)?
1172                        }
1173                        _ => Val::String(arg_token.as_str().to_string().into()),
1174                    };
1175                    args.push(CommandElem::Argument(arg));
1176                }
1177                Rule::command_parameter => args.push(CommandElem::Parameter(token_string)),
1178                Rule::argument_list => args.push(CommandElem::ArgList(token_string)),
1179                Rule::redirection => { //todo: implement redirection
1180                }
1181                Rule::stop_parsing => { //todo: stop parsing
1182                }
1183                Rule::script_block_expression => args.push(CommandElem::Argument(
1184                    self.parse_script_block_expression(command_element_token)?,
1185                )),
1186                _ => panic!(
1187                    "eval_command not implemented: {:?}",
1188                    command_element_token.as_rule()
1189                ),
1190            }
1191        }
1192        Ok((command_name.to_string(), args))
1193    }
1194
1195    fn parse_script_block_command(
1196        &mut self,
1197        token: Pair<'a>,
1198    ) -> ParserResult<(String, Vec<CommandElem>)> {
1199        check_rule!(token, Rule::script_block_command);
1200
1201        let mut pairs = token.into_inner();
1202        let command_name_token = pairs.next().unwrap();
1203        let command_name = command_name_token.as_str();
1204        let command_element_token = pairs.next().unwrap();
1205
1206        check_rule!(command_element_token, Rule::script_block_expression);
1207        let script_block = self.parse_script_block_expression(command_element_token)?;
1208        Ok((
1209            command_name.to_string(),
1210            vec![CommandElem::Argument(script_block)],
1211        ))
1212    }
1213
1214    fn eval_command(&mut self, token: Pair<'a>, input: Option<Val>) -> ParserResult<Val> {
1215        check_rule!(token, Rule::command);
1216
1217        let mut pairs = token.into_inner();
1218        //unfortunately I can't make long_command silent
1219
1220        let mut args = if let Some(v) = input {
1221            vec![CommandElem::Argument(v)]
1222        } else {
1223            Vec::new()
1224        };
1225
1226        let command = pairs.next().unwrap();
1227        let (command_name, mut command_args) = match command.as_rule() {
1228            Rule::script_block_command => self.parse_script_block_command(command)?,
1229            Rule::foreach_command => Err(ParserError::NotImplemented("foreach_command".into()))?,
1230            Rule::long_command => self.parse_long_command(command)?,
1231            Rule::invocation_command => {
1232                Err(ParserError::NotImplemented("invocation_command".into()))?
1233            }
1234            _ => panic!("eval_command not implemented: {:?}", command.as_rule()),
1235        };
1236        args.append(&mut command_args);
1237
1238        let CommandOutput {
1239            val,
1240            deobfuscated,
1241            stream,
1242        } = Command::execute(self, command_name.as_str(), args)?;
1243
1244        if let Some(msg) = deobfuscated {
1245            self.deobfuscated_statements.push(msg);
1246        }
1247
1248        if let Some(msg) = stream {
1249            self.output.push(msg);
1250        }
1251
1252        Ok(val.unwrap_or_default())
1253    }
1254
1255    fn eval_redirected_expression(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1256        check_rule!(token, Rule::redirected_expression);
1257
1258        let expression_token = token.into_inner().next().unwrap();
1259        //todo: handle redirections
1260
1261        self.eval_expression(expression_token)
1262    }
1263
1264    fn eval_expression(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1265        check_rule!(token, Rule::expression);
1266        let token_string = token.as_str().trim().to_string();
1267
1268        let mut pairs = token.into_inner();
1269        let mut res = self.eval_bitwise_exp(pairs.next().unwrap())?;
1270        while let Some(op) = pairs.next() {
1271            check_rule!(op, Rule::logical_operator);
1272            let Some(fun) = LogicalPred::get(op.as_str()) else {
1273                panic!()
1274            };
1275
1276            let mult = pairs.next().unwrap();
1277            let right_op = self.eval_bitwise_exp(mult)?;
1278            res = Val::Bool(fun(res, right_op));
1279        }
1280        self.tokens
1281            .push(Token::Expression(token_string, res.clone().into()));
1282
1283        Ok(res)
1284    }
1285
1286    fn eval_pipeline_tail(&mut self, token: Pair<'a>, input: Val) -> ParserResult<Val> {
1287        check_rule!(token, Rule::pipeline_tail);
1288        let mut arg = input;
1289        let mut pairs = token.into_inner();
1290
1291        while let Some(token) = pairs.next() {
1292            arg = self.eval_command(token, Some(arg))?;
1293        }
1294
1295        Ok(arg)
1296    }
1297
1298    fn eval_pipeline_with_tail(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1299        check_rule!(token, Rule::pipeline_with_tail);
1300        let mut pairs = token.into_inner();
1301        let token = pairs.next().unwrap();
1302
1303        let result: Val = match token.as_rule() {
1304            Rule::redirected_expression => self.eval_redirected_expression(token)?,
1305            Rule::command => self.eval_command(token, None)?,
1306            _ => {
1307                panic!("eval_pipeline not implemented: {:?}", token.as_rule());
1308            }
1309        };
1310
1311        if let Some(token) = pairs.next() {
1312            match token.as_rule() {
1313                Rule::pipeline_tail => Ok(self.eval_pipeline_tail(token, result)?),
1314                _ => {
1315                    panic!("eval_pipeline not implemented: {:?}", token.as_rule());
1316                }
1317            }
1318        } else {
1319            Ok(result)
1320        }
1321    }
1322
1323    fn eval_pipeline(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1324        check_rule!(token, Rule::pipeline);
1325        let mut pairs = token.into_inner();
1326        let token = pairs.next().unwrap();
1327
1328        match token.as_rule() {
1329            Rule::assignment_exp => return self.eval_assigment_exp(token),
1330            Rule::pipeline_with_tail => return self.eval_pipeline_with_tail(token),
1331            _ => panic!("not possible: {:?}", token.as_rule()),
1332        }
1333    }
1334
1335    fn safe_eval_pipeline(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1336        let res = self.eval_pipeline(token.clone());
1337
1338        let v = match res {
1339            Ok(val) => val,
1340            Err(err) => {
1341                self.errors.push(err);
1342                Val::ScriptText(token.as_str().to_string())
1343            }
1344        };
1345
1346        Ok(v)
1347    }
1348
1349    fn eval_cast_expression(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1350        check_rule!(token, Rule::cast_expression);
1351
1352        let mut pairs = token.into_inner();
1353        let type_token = pairs.next().unwrap();
1354        let val_type = self.eval_type_literal(type_token)?;
1355
1356        let token = pairs.next().unwrap();
1357        let mut res = match token.as_rule() {
1358            Rule::parenthesized_expression => {
1359                let token = token.into_inner().next().unwrap();
1360                self.safe_eval_pipeline(token)?
1361            }
1362            Rule::range_exp => self.eval_range_exp(token)?,
1363            Rule::unary_exp => self.eval_unary_exp(token)?,
1364            _ => {
1365                panic!(
1366                    "eval_cast_expression not implemented: {:?}",
1367                    token.as_rule()
1368                );
1369            }
1370        };
1371
1372        Ok(res.cast(val_type)?)
1373    }
1374
1375    fn eval_assigment_exp(&mut self, token: Pair<'a>) -> ParserResult<Val> {
1376        check_rule!(token, Rule::assignment_exp);
1377
1378        let mut pairs = token.into_inner();
1379        let variable_token = pairs.next().unwrap();
1380        let var_name = Self::parse_variable(variable_token)?;
1381        let var = self.variables.get(&var_name).unwrap_or_default();
1382
1383        let assignement_op = pairs.next().unwrap();
1384
1385        //get operand
1386        let op = assignement_op.into_inner().next().unwrap();
1387        let pred = ArithmeticPred::get(op.as_str());
1388
1389        let right_token = pairs.next().unwrap();
1390        let right_op = self.eval_pipeline(right_token.clone())?;
1391
1392        let Some(pred) = pred else { panic!() };
1393        let op_result = pred(var, right_op)?;
1394        self.variables.set(&var_name, op_result.clone())?;
1395
1396        //we want save each assignment statement
1397        self.deobfuscated_statements
1398            .push(format!("{} = {}", var_name, op_result.cast_to_script()));
1399        Ok(op_result)
1400    }
1401}
1402
1403#[cfg(test)]
1404mod tests {
1405    use pest::Parser;
1406
1407    use super::*;
1408
1409    #[test]
1410    fn comment_and_semicolon() {
1411        let input = r#"
1412# This is a single line comment
1413$a = 1; $b = 2; Write-Output $a
1414
1415Write-Output "Hello"  # Another comment
1416
1417<#
1418    This is a
1419    multi-line block comment
1420#>
1421"#;
1422
1423        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
1424    }
1425
1426    #[test]
1427    fn while_loop() {
1428        let input = r#"
1429while ($true) {
1430    if ($someCondition) {
1431        break
1432    }
1433    # other code
1434}
1435"#;
1436
1437        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
1438    }
1439
1440    #[test]
1441    fn foreach_loop() {
1442        let input = r#"
1443foreach ($n in $numbers) {
1444    Write-Output $n
1445}
1446"#;
1447
1448        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
1449    }
1450
1451    #[test]
1452    fn for_loop() {
1453        let input = r#"
1454# Comma separated assignment expressions enclosed in parentheses.
1455for (($i = 0), ($j = 0); $i -lt 10; $i++)
1456{
1457    "`$i:$i"
1458    "`$j:$j"
1459}
1460"#;
1461
1462        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
1463    }
1464
1465    #[test]
1466    fn switch() {
1467        let input = r#"
1468switch ($var) {
1469    "a" { Write-Output "A" }
1470    1 { Write-Output "One" }
1471    default { Write-Output "Other" }
1472}
1473"#;
1474
1475        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
1476    }
1477
1478    #[test]
1479    fn functions() {
1480        let input = r#"
1481function Get-Square {
1482    param($x)
1483    return $x * $x
1484}
1485
1486function Say-Hello {
1487    Write-Output "Hello"
1488}
1489"#;
1490
1491        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
1492    }
1493
1494    #[test]
1495    fn if_expression() {
1496        let input = r#"
1497$x="hello"
1498        Write-Host $x
1499        $y = 42
1500        Start-Process "notepad.exe"
1501
1502        $x = 42
1503if ($x -eq 1) {
1504    Write-Output "One"
1505} elseif ($x -eq 2) {
1506    Write-Output "Two"
1507} else {
1508    Write-Output "Other"
1509}
1510"#;
1511
1512        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
1513    }
1514
1515    #[test]
1516    fn command() {
1517        let input = r#"
1518Get-Process | Where-Object { $_.CPU -gt 100 }
1519"#;
1520
1521        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
1522    }
1523
1524    #[test]
1525    fn range() {
1526        let input = r#"
1527$numbers = 1..5
1528"#;
1529
1530        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
1531    }
1532
1533    #[test]
1534    fn literals() {
1535        let input = r#"
1536$hex = 0xFF
1537
1538$name = "Alice"
1539$msg = "Hello, $name. Today is $day."
1540$escaped = "She said: `"Hi`""
1541$literal = 'Hello, $name'
1542"#;
1543
1544        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
1545    }
1546
1547    #[test]
1548    fn floats() {
1549        let input = r#"
1550    $pi = 3.1415
1551$half = .5
1552"#;
1553
1554        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
1555    }
1556
1557    #[test]
1558    fn arrays() {
1559        let input = r#"
1560$a = 1, 2, 3
1561$b = @("one", "two", "three")
1562$c = @(1, 2, @(3, 4))
1563"#;
1564
1565        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
1566    }
1567
1568    #[test]
1569    fn static_method_call() {
1570        let input = r#"
1571[Threading.Thread]::Sleep(399)
1572"#;
1573
1574        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
1575    }
1576
1577    #[test]
1578    fn neg_pipeline() {
1579        let input = r#"
1580-not $input | Where-Object { $_ -gt 5 }
1581"#;
1582
1583        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
1584    }
1585
1586    #[test]
1587    fn amsi_fail() {
1588        let input = r#"
1589#Matt Graebers second Reflection method 
1590$VMRviwsbtehQfPtxbt=$null;
1591$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))"
1592
1593"#;
1594
1595        let _ = PowerShellSession::parse(Rule::program, input).unwrap();
1596    }
1597}