rudy_parser/
expressions.rs

1//! Expression parsing for debugger evaluation
2//!
3//! This module provides parsing for Rust-like expressions for use in
4//! debugger evaluation. Supports field access, array indexing, dereferencing,
5//! and other common expression forms.
6
7use std::fmt;
8
9use anyhow::{Result, anyhow};
10use itertools::Itertools;
11
12/// Represents a parsed expression
13#[derive(Debug, Clone, PartialEq)]
14pub enum Expression {
15    /// Simple variable reference (e.g., `foo`)
16    Variable(String),
17
18    /// Field access (e.g., `foo.bar`, `self.field`)
19    FieldAccess {
20        base: Box<Expression>,
21        field: String,
22    },
23
24    /// Array/slice indexing (e.g., `arr[5]`, `slice[idx]`)
25    Index {
26        base: Box<Expression>,
27        index: Box<Expression>,
28    },
29
30    /// Pointer dereferencing (e.g., `*ptr`, `**ptr_ptr`)
31    Deref(Box<Expression>),
32
33    /// Address-of operator (e.g., `&var`, `&mut var`)
34    AddressOf {
35        mutable: bool,
36        expr: Box<Expression>,
37    },
38
39    /// Literal number (e.g., `42`, `0xff`)
40    NumberLiteral(u64),
41
42    /// String literal (e.g., `"hello"`, `"created"`)
43    StringLiteral(String),
44
45    /// Parenthesized expression (e.g., `(foo)`)
46    Parenthesized(Box<Expression>),
47
48    /// Method call (e.g., `foo.bar()`, `vec.len()`)
49    MethodCall {
50        base: Box<Expression>,
51        method: String,
52        args: Vec<Expression>,
53    },
54
55    /// Function call (e.g., `foo()`, `bar(1, 2)`)
56    FunctionCall {
57        function: String,
58        args: Vec<Expression>,
59    },
60}
61
62impl fmt::Display for Expression {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        match self {
65            Expression::Variable(name) => write!(f, "{name}"),
66            Expression::FieldAccess { base, field } => write!(f, "{base}.{field}"),
67            Expression::Index { base, index } => write!(f, "{base}[{index}]"),
68            Expression::Deref(expr) => write!(f, "*{expr}"),
69            Expression::AddressOf { mutable, expr } => {
70                if *mutable {
71                    write!(f, "&mut {expr}")
72                } else {
73                    write!(f, "&{expr}")
74                }
75            }
76            Expression::NumberLiteral(value) => write!(f, "{value}"),
77            Expression::StringLiteral(value) => write!(f, "\"{value}\""),
78            Expression::Parenthesized(expr) => write!(f, "({expr})"),
79            Expression::MethodCall { base, method, args } => {
80                write!(f, "{base}.{method}({})", args.iter().join(", "))
81            }
82            Expression::FunctionCall { function, args } => {
83                write!(f, "{function}({})", args.iter().join(", "))
84            }
85        }
86    }
87}
88
89/// Simple tokenizer for expressions
90#[derive(Debug, Clone, PartialEq)]
91enum Token {
92    Identifier(String),
93    Number(u64),
94    String(String),
95    Dot,
96    Star,
97    Ampersand,
98    /// '['
99    LeftBracket,
100    /// ']'
101    RightBracket,
102    /// '('
103    LeftParen,
104    /// ')'
105    RightParen,
106    /// ','
107    Comma,
108    Mut,
109    Eof,
110}
111
112struct Tokenizer<'a> {
113    input: &'a str,
114    position: usize,
115}
116
117impl<'a> Tokenizer<'a> {
118    fn new(input: &'a str) -> Self {
119        Self { input, position: 0 }
120    }
121
122    fn current_char(&self) -> Option<char> {
123        self.input.chars().nth(self.position)
124    }
125
126    fn advance(&mut self) {
127        if self.position < self.input.len() {
128            self.position += 1;
129        }
130    }
131
132    fn skip_whitespace(&mut self) {
133        while let Some(ch) = self.current_char() {
134            if ch.is_whitespace() {
135                self.advance();
136            } else {
137                break;
138            }
139        }
140    }
141
142    fn read_identifier(&mut self) -> String {
143        let start = self.position;
144        while let Some(ch) = self.current_char() {
145            if ch.is_ascii_alphanumeric() || ch == '_' {
146                self.advance();
147            } else {
148                break;
149            }
150        }
151        self.input[start..self.position].to_string()
152    }
153
154    fn read_number(&mut self) -> Result<u64> {
155        let start = self.position;
156
157        // Check for hex prefix
158        if self.input[self.position..].starts_with("0x")
159            || self.input[self.position..].starts_with("0X")
160        {
161            self.advance(); // skip '0'
162            self.advance(); // skip 'x'
163            while let Some(ch) = self.current_char() {
164                if ch.is_ascii_hexdigit() {
165                    self.advance();
166                } else {
167                    break;
168                }
169            }
170            let hex_str = &self.input[start + 2..self.position];
171            u64::from_str_radix(hex_str, 16).map_err(|e| anyhow!("Invalid hex number: {}", e))
172        } else {
173            // Regular decimal number
174            while let Some(ch) = self.current_char() {
175                if ch.is_ascii_digit() {
176                    self.advance();
177                } else {
178                    break;
179                }
180            }
181            self.input[start..self.position]
182                .parse()
183                .map_err(|e| anyhow!("Invalid number: {}", e))
184        }
185    }
186
187    fn read_string(&mut self) -> Result<String> {
188        // Skip opening quote
189        self.advance();
190        let start = self.position;
191
192        while let Some(ch) = self.current_char() {
193            if ch == '"' {
194                // Found closing quote
195                let content = self.input[start..self.position].to_string();
196                self.advance(); // Skip closing quote
197                return Ok(content);
198            } else if ch == '\\' {
199                // Handle escape sequences (basic support)
200                self.advance(); // Skip backslash
201                if self.current_char().is_some() {
202                    self.advance(); // Skip escaped character
203                }
204            } else {
205                self.advance();
206            }
207        }
208
209        Err(anyhow!("Unterminated string literal"))
210    }
211
212    fn next_token(&mut self) -> Result<Token> {
213        self.skip_whitespace();
214
215        match self.current_char() {
216            None => Ok(Token::Eof),
217            Some('.') => {
218                self.advance();
219                Ok(Token::Dot)
220            }
221            Some('*') => {
222                self.advance();
223                Ok(Token::Star)
224            }
225            Some('&') => {
226                self.advance();
227                Ok(Token::Ampersand)
228            }
229            Some('[') => {
230                self.advance();
231                Ok(Token::LeftBracket)
232            }
233            Some(']') => {
234                self.advance();
235                Ok(Token::RightBracket)
236            }
237            Some('(') => {
238                self.advance();
239                Ok(Token::LeftParen)
240            }
241            Some(')') => {
242                self.advance();
243                Ok(Token::RightParen)
244            }
245            Some(',') => {
246                self.advance();
247                Ok(Token::Comma)
248            }
249            Some(ch) if ch.is_ascii_alphabetic() || ch == '_' => {
250                let ident = self.read_identifier();
251                if ident == "mut" {
252                    Ok(Token::Mut)
253                } else {
254                    Ok(Token::Identifier(ident))
255                }
256            }
257            Some(ch) if ch.is_ascii_digit() => {
258                let number = self.read_number()?;
259                Ok(Token::Number(number))
260            }
261            Some('"') => {
262                let string = self.read_string()?;
263                Ok(Token::String(string))
264            }
265            Some(ch) => Err(anyhow!("Unexpected character: '{}'", ch)),
266        }
267    }
268}
269
270/// Simple recursive descent parser
271struct Parser {
272    tokens: Vec<Token>,
273    position: usize,
274}
275
276impl Parser {
277    fn new(input: &str) -> Result<Self> {
278        let mut tokenizer = Tokenizer::new(input);
279        let mut tokens = Vec::new();
280
281        loop {
282            let token = tokenizer.next_token()?;
283            let is_eof = token == Token::Eof;
284            tokens.push(token);
285            if is_eof {
286                break;
287            }
288        }
289
290        Ok(Self {
291            tokens,
292            position: 0,
293        })
294    }
295
296    fn current_token(&self) -> &Token {
297        self.tokens.get(self.position).unwrap_or(&Token::Eof)
298    }
299
300    fn advance(&mut self) {
301        if self.position < self.tokens.len() {
302            self.position += 1;
303        }
304    }
305
306    fn expect(&mut self, expected: Token) -> Result<()> {
307        if std::mem::discriminant(self.current_token()) == std::mem::discriminant(&expected) {
308            self.advance();
309            Ok(())
310        } else {
311            Err(anyhow!(
312                "Expected {:?}, found {:?}",
313                expected,
314                self.current_token()
315            ))
316        }
317    }
318
319    pub fn parse(&mut self) -> Result<Expression> {
320        self.parse_expression()
321    }
322
323    fn parse_expression(&mut self) -> Result<Expression> {
324        self.parse_unary()
325    }
326
327    fn parse_unary(&mut self) -> Result<Expression> {
328        match self.current_token() {
329            Token::Star => {
330                self.advance();
331                let expr = self.parse_unary()?;
332                Ok(Expression::Deref(Box::new(expr)))
333            }
334            Token::Ampersand => {
335                self.advance();
336                let mutable = matches!(self.current_token(), Token::Mut);
337                if mutable {
338                    self.advance();
339                }
340                let expr = self.parse_unary()?;
341                Ok(Expression::AddressOf {
342                    mutable,
343                    expr: Box::new(expr),
344                })
345            }
346            _ => self.parse_postfix(),
347        }
348    }
349
350    fn parse_postfix(&mut self) -> Result<Expression> {
351        let mut expr = self.parse_primary()?;
352
353        loop {
354            match self.current_token() {
355                Token::Dot => {
356                    self.advance();
357                    if let Token::Identifier(field) = self.current_token() {
358                        let field = field.clone();
359                        self.advance();
360
361                        // Check if this is a method call
362                        if matches!(self.current_token(), Token::LeftParen) {
363                            self.advance(); // consume '('
364                            let args = self.parse_arguments()?;
365                            self.expect(Token::RightParen)?;
366                            expr = Expression::MethodCall {
367                                base: Box::new(expr),
368                                method: field,
369                                args,
370                            };
371                        } else {
372                            expr = Expression::FieldAccess {
373                                base: Box::new(expr),
374                                field,
375                            };
376                        }
377                    } else {
378                        return Err(anyhow!("Expected field name after '.'"));
379                    }
380                }
381                Token::LeftBracket => {
382                    self.advance();
383                    let index = self.parse_expression()?;
384                    self.expect(Token::RightBracket)?;
385                    expr = Expression::Index {
386                        base: Box::new(expr),
387                        index: Box::new(index),
388                    };
389                }
390                _ => break,
391            }
392        }
393
394        Ok(expr)
395    }
396
397    fn parse_primary(&mut self) -> Result<Expression> {
398        match self.current_token() {
399            Token::Identifier(name) => {
400                let name = name.clone();
401                self.advance();
402
403                // Check if this is a function call
404                if matches!(self.current_token(), Token::LeftParen) {
405                    self.advance(); // consume '('
406                    let args = self.parse_arguments()?;
407                    self.expect(Token::RightParen)?;
408                    Ok(Expression::FunctionCall {
409                        function: name,
410                        args,
411                    })
412                } else {
413                    Ok(Expression::Variable(name))
414                }
415            }
416            Token::Number(value) => {
417                let value = *value;
418                self.advance();
419                Ok(Expression::NumberLiteral(value))
420            }
421            Token::String(value) => {
422                let value = value.clone();
423                self.advance();
424                Ok(Expression::StringLiteral(value))
425            }
426            Token::LeftParen => {
427                self.advance();
428                let expr = self.parse_expression()?;
429                self.expect(Token::RightParen)?;
430                Ok(Expression::Parenthesized(Box::new(expr)))
431            }
432            _ => Err(anyhow!(
433                "Expected identifier, number, string, or '(', found {:?}",
434                self.current_token()
435            )),
436        }
437    }
438
439    fn parse_arguments(&mut self) -> Result<Vec<Expression>> {
440        let mut args = Vec::new();
441
442        // Handle empty argument list
443        if matches!(self.current_token(), Token::RightParen) {
444            return Ok(args);
445        }
446
447        // Parse first argument
448        args.push(self.parse_expression()?);
449
450        // Parse remaining arguments
451        while matches!(self.current_token(), Token::Comma) {
452            self.advance(); // consume ','
453            args.push(self.parse_expression()?);
454        }
455
456        Ok(args)
457    }
458}
459
460/// Parse a string into an Expression
461pub fn parse_expression(input: &str) -> Result<Expression> {
462    let mut parser = Parser::new(input)?;
463    parser.parse()
464}
465
466#[cfg(test)]
467mod tests {
468    use super::*;
469
470    #[track_caller]
471    fn parse(s: &str) -> Expression {
472        match parse_expression(s) {
473            Ok(expr) => expr,
474            Err(e) => panic!("Failed to parse expression '{s}': {e}"),
475        }
476    }
477
478    #[test]
479    fn test_variable() {
480        let expr = parse("foo");
481        assert_eq!(expr, Expression::Variable("foo".to_string()));
482    }
483
484    #[test]
485    fn test_number_literal() {
486        let expr = parse("42");
487        assert_eq!(expr, Expression::NumberLiteral(42));
488
489        let expr = parse("0xff");
490        assert_eq!(expr, Expression::NumberLiteral(0xff));
491    }
492
493    #[test]
494    fn test_string_literal() {
495        let expr = parse(r#""hello""#);
496        assert_eq!(expr, Expression::StringLiteral("hello".to_string()));
497
498        let expr = parse(r#""created""#);
499        assert_eq!(expr, Expression::StringLiteral("created".to_string()));
500    }
501
502    #[test]
503    fn test_field_access() {
504        let expr = parse("foo.bar");
505        assert_eq!(
506            expr,
507            Expression::FieldAccess {
508                base: Box::new(Expression::Variable("foo".to_string())),
509                field: "bar".to_string(),
510            }
511        );
512    }
513
514    #[test]
515    fn test_chained_field_access() {
516        let expr = parse("foo.bar.baz");
517        assert_eq!(
518            expr,
519            Expression::FieldAccess {
520                base: Box::new(Expression::FieldAccess {
521                    base: Box::new(Expression::Variable("foo".to_string())),
522                    field: "bar".to_string(),
523                }),
524                field: "baz".to_string(),
525            }
526        );
527    }
528
529    #[test]
530    fn test_index_access() {
531        let expr = parse("arr[0]");
532        assert_eq!(
533            expr,
534            Expression::Index {
535                base: Box::new(Expression::Variable("arr".to_string())),
536                index: Box::new(Expression::NumberLiteral(0)),
537            }
538        );
539
540        // Test string indexing
541        let expr = parse(r#"map["key"]"#);
542        assert_eq!(
543            expr,
544            Expression::Index {
545                base: Box::new(Expression::Variable("map".to_string())),
546                index: Box::new(Expression::StringLiteral("key".to_string())),
547            }
548        );
549    }
550
551    #[test]
552    fn test_deref() {
553        let expr = parse("*ptr");
554        assert_eq!(
555            expr,
556            Expression::Deref(Box::new(Expression::Variable("ptr".to_string())))
557        );
558    }
559
560    #[test]
561    fn test_address_of() {
562        let expr = parse("&var");
563        assert_eq!(
564            expr,
565            Expression::AddressOf {
566                mutable: false,
567                expr: Box::new(Expression::Variable("var".to_string())),
568            }
569        );
570
571        let expr = parse("&mut var");
572        assert_eq!(
573            expr,
574            Expression::AddressOf {
575                mutable: true,
576                expr: Box::new(Expression::Variable("var".to_string())),
577            }
578        );
579    }
580
581    #[test]
582    fn test_parenthesized() {
583        let expr = parse("(foo)");
584        assert_eq!(
585            expr,
586            Expression::Parenthesized(Box::new(Expression::Variable("foo".to_string())))
587        );
588    }
589
590    #[test]
591    fn test_complex_expressions() {
592        // Test field access with indexing: obj.field[0]
593        let expr = parse("obj.field[0]");
594        assert_eq!(
595            expr,
596            Expression::Index {
597                base: Box::new(Expression::FieldAccess {
598                    base: Box::new(Expression::Variable("obj".to_string())),
599                    field: "field".to_string(),
600                }),
601                index: Box::new(Expression::NumberLiteral(0)),
602            }
603        );
604
605        // Test dereferencing field access: *obj.ptr
606        let expr = parse("*obj.ptr");
607        assert_eq!(
608            expr,
609            Expression::Deref(Box::new(Expression::FieldAccess {
610                base: Box::new(Expression::Variable("obj".to_string())),
611                field: "ptr".to_string(),
612            }))
613        );
614    }
615
616    #[test]
617    fn test_display_formatting() {
618        assert_eq!(parse("foo").to_string(), "foo");
619        assert_eq!(parse("42").to_string(), "42");
620        assert_eq!(parse(r#""hello""#).to_string(), r#""hello""#);
621        assert_eq!(parse("foo.bar").to_string(), "foo.bar");
622        assert_eq!(parse("arr[0]").to_string(), "arr[0]");
623        assert_eq!(parse(r#"map["key"]"#).to_string(), r#"map["key"]"#);
624        assert_eq!(parse("*ptr").to_string(), "*ptr");
625        assert_eq!(parse("&var").to_string(), "&var");
626        assert_eq!(parse("&mut var").to_string(), "&mut var");
627        assert_eq!(parse("(foo)").to_string(), "(foo)");
628    }
629
630    #[test]
631    fn test_method_call() {
632        // No arguments
633        let expr = parse("vec.len()");
634        assert_eq!(
635            expr,
636            Expression::MethodCall {
637                base: Box::new(Expression::Variable("vec".to_string())),
638                method: "len".to_string(),
639                args: vec![],
640            }
641        );
642
643        // With arguments
644        let expr = parse("vec.push(42)");
645        assert_eq!(
646            expr,
647            Expression::MethodCall {
648                base: Box::new(Expression::Variable("vec".to_string())),
649                method: "push".to_string(),
650                args: vec![Expression::NumberLiteral(42)],
651            }
652        );
653
654        // Multiple arguments
655        let expr = parse(r#"map.insert("key", 42)"#);
656        assert_eq!(
657            expr,
658            Expression::MethodCall {
659                base: Box::new(Expression::Variable("map".to_string())),
660                method: "insert".to_string(),
661                args: vec![
662                    Expression::StringLiteral("key".to_string()),
663                    Expression::NumberLiteral(42)
664                ],
665            }
666        );
667
668        // Chained method calls
669        let expr = parse("vec.iter().count()");
670        assert_eq!(
671            expr,
672            Expression::MethodCall {
673                base: Box::new(Expression::MethodCall {
674                    base: Box::new(Expression::Variable("vec".to_string())),
675                    method: "iter".to_string(),
676                    args: vec![],
677                }),
678                method: "count".to_string(),
679                args: vec![],
680            }
681        );
682    }
683
684    #[test]
685    fn test_function_call() {
686        // No arguments
687        let expr = parse("foo()");
688        assert_eq!(
689            expr,
690            Expression::FunctionCall {
691                function: "foo".to_string(),
692                args: vec![],
693            }
694        );
695
696        // With arguments
697        let expr = parse("bar(1, 2)");
698        assert_eq!(
699            expr,
700            Expression::FunctionCall {
701                function: "bar".to_string(),
702                args: vec![Expression::NumberLiteral(1), Expression::NumberLiteral(2)],
703            }
704        );
705    }
706
707    #[test]
708    fn test_method_call_display() {
709        assert_eq!(parse("vec.len()").to_string(), "vec.len()");
710        assert_eq!(parse("vec.push(42)").to_string(), "vec.push(42)");
711        assert_eq!(
712            parse(r#"map.insert("key", 42)"#).to_string(),
713            r#"map.insert("key", 42)"#
714        );
715        assert_eq!(parse("foo()").to_string(), "foo()");
716        assert_eq!(parse("bar(1, 2)").to_string(), "bar(1, 2)");
717    }
718}