dampen_core/expr/
tokenizer.rs

1#![allow(clippy::unwrap_used)]
2#![allow(dead_code)]
3
4use crate::expr::{
5    BinaryOp, BinaryOpExpr, BindingExpr, ConditionalExpr, Expr, FieldAccessExpr, LiteralExpr,
6    MethodCallExpr, SharedFieldAccessExpr, UnaryOp, UnaryOpExpr,
7};
8use crate::ir::span::Span;
9
10/// Tokenize and parse a binding expression
11pub fn tokenize_binding_expr(
12    input: &str,
13    start_pos: usize,
14    line: u32,
15    column: u32,
16) -> Result<BindingExpr, String> {
17    let mut parser = ExprParser::new(input, start_pos, line, column);
18    let expr = parser.parse()?;
19    let span = Span::new(start_pos, start_pos + input.len(), line, column);
20    Ok(BindingExpr { expr, span })
21}
22
23struct ExprParser<'a> {
24    input: &'a str,
25    pos: usize,
26    start_pos: usize,
27    line: u32,
28    column: u32,
29}
30
31impl<'a> ExprParser<'a> {
32    fn new(input: &'a str, start_pos: usize, line: u32, column: u32) -> Self {
33        Self {
34            input,
35            pos: 0,
36            start_pos,
37            line,
38            column,
39        }
40    }
41
42    fn parse(&mut self) -> Result<Expr, String> {
43        self.parse_conditional()
44    }
45
46    fn parse_conditional(&mut self) -> Result<Expr, String> {
47        self.skip_whitespace();
48        if self.peek_keyword("if") {
49            self.consume_keyword("if")?;
50            self.skip_whitespace();
51            let condition = self.parse_or()?;
52            self.skip_whitespace();
53            self.consume_keyword("then")?;
54            self.skip_whitespace();
55            let then_branch = self.parse_or()?;
56            self.skip_whitespace();
57            self.consume_keyword("else")?;
58            self.skip_whitespace();
59            let else_branch = self.parse_or()?;
60
61            return Ok(Expr::Conditional(ConditionalExpr {
62                condition: Box::new(condition),
63                then_branch: Box::new(then_branch),
64                else_branch: Box::new(else_branch),
65            }));
66        }
67
68        self.parse_or()
69    }
70
71    fn parse_or(&mut self) -> Result<Expr, String> {
72        let mut left = self.parse_and()?;
73
74        loop {
75            self.skip_whitespace();
76            if self.peek_str("||") {
77                self.consume_str("||")?;
78                self.skip_whitespace();
79                let right = self.parse_and()?;
80                left = Expr::BinaryOp(BinaryOpExpr {
81                    left: Box::new(left),
82                    op: BinaryOp::Or,
83                    right: Box::new(right),
84                });
85            } else {
86                break;
87            }
88        }
89
90        Ok(left)
91    }
92
93    fn parse_and(&mut self) -> Result<Expr, String> {
94        let mut left = self.parse_comparison()?;
95
96        loop {
97            self.skip_whitespace();
98            if self.peek_str("&&") {
99                self.consume_str("&&")?;
100                self.skip_whitespace();
101                let right = self.parse_comparison()?;
102                left = Expr::BinaryOp(BinaryOpExpr {
103                    left: Box::new(left),
104                    op: BinaryOp::And,
105                    right: Box::new(right),
106                });
107            } else {
108                break;
109            }
110        }
111
112        Ok(left)
113    }
114
115    fn parse_comparison(&mut self) -> Result<Expr, String> {
116        let mut left = self.parse_additive()?;
117
118        loop {
119            self.skip_whitespace();
120
121            if self.peek_str("==") {
122                self.consume_str("==")?;
123                self.skip_whitespace();
124                let right = self.parse_additive()?;
125                left = Expr::BinaryOp(BinaryOpExpr {
126                    left: Box::new(left),
127                    op: BinaryOp::Eq,
128                    right: Box::new(right),
129                });
130            } else if self.peek_str("!=") {
131                self.consume_str("!=")?;
132                self.skip_whitespace();
133                let right = self.parse_additive()?;
134                left = Expr::BinaryOp(BinaryOpExpr {
135                    left: Box::new(left),
136                    op: BinaryOp::Ne,
137                    right: Box::new(right),
138                });
139            } else if self.peek_str("<=") {
140                self.consume_str("<=")?;
141                self.skip_whitespace();
142                let right = self.parse_additive()?;
143                left = Expr::BinaryOp(BinaryOpExpr {
144                    left: Box::new(left),
145                    op: BinaryOp::Le,
146                    right: Box::new(right),
147                });
148            } else if self.peek_str(">=") {
149                self.consume_str(">=")?;
150                self.skip_whitespace();
151                let right = self.parse_additive()?;
152                left = Expr::BinaryOp(BinaryOpExpr {
153                    left: Box::new(left),
154                    op: BinaryOp::Ge,
155                    right: Box::new(right),
156                });
157            } else if self.peek_str("<") {
158                self.consume_str("<")?;
159                self.skip_whitespace();
160                let right = self.parse_additive()?;
161                left = Expr::BinaryOp(BinaryOpExpr {
162                    left: Box::new(left),
163                    op: BinaryOp::Lt,
164                    right: Box::new(right),
165                });
166            } else if self.peek_str(">") {
167                self.consume_str(">")?;
168                self.skip_whitespace();
169                let right = self.parse_additive()?;
170                left = Expr::BinaryOp(BinaryOpExpr {
171                    left: Box::new(left),
172                    op: BinaryOp::Gt,
173                    right: Box::new(right),
174                });
175            } else {
176                break;
177            }
178        }
179
180        Ok(left)
181    }
182
183    fn parse_additive(&mut self) -> Result<Expr, String> {
184        let mut left = self.parse_multiplicative()?;
185
186        loop {
187            self.skip_whitespace();
188
189            if self.peek_str("+") {
190                self.consume_str("+")?;
191                self.skip_whitespace();
192                let right = self.parse_multiplicative()?;
193                left = Expr::BinaryOp(BinaryOpExpr {
194                    left: Box::new(left),
195                    op: BinaryOp::Add,
196                    right: Box::new(right),
197                });
198            } else if self.peek_str("-") {
199                self.consume_str("-")?;
200                self.skip_whitespace();
201                let right = self.parse_multiplicative()?;
202                left = Expr::BinaryOp(BinaryOpExpr {
203                    left: Box::new(left),
204                    op: BinaryOp::Sub,
205                    right: Box::new(right),
206                });
207            } else {
208                break;
209            }
210        }
211
212        Ok(left)
213    }
214
215    fn parse_multiplicative(&mut self) -> Result<Expr, String> {
216        let mut left = self.parse_unary()?;
217
218        loop {
219            self.skip_whitespace();
220
221            if self.peek_str("*") {
222                self.consume_str("*")?;
223                self.skip_whitespace();
224                let right = self.parse_unary()?;
225                left = Expr::BinaryOp(BinaryOpExpr {
226                    left: Box::new(left),
227                    op: BinaryOp::Mul,
228                    right: Box::new(right),
229                });
230            } else if self.peek_str("/") {
231                self.consume_str("/")?;
232                self.skip_whitespace();
233                let right = self.parse_unary()?;
234                left = Expr::BinaryOp(BinaryOpExpr {
235                    left: Box::new(left),
236                    op: BinaryOp::Div,
237                    right: Box::new(right),
238                });
239            } else {
240                break;
241            }
242        }
243
244        Ok(left)
245    }
246
247    fn parse_unary(&mut self) -> Result<Expr, String> {
248        self.skip_whitespace();
249
250        if self.peek_str("!") {
251            self.consume_str("!")?;
252            let operand = self.parse_unary()?;
253            return Ok(Expr::UnaryOp(UnaryOpExpr {
254                op: UnaryOp::Not,
255                operand: Box::new(operand),
256            }));
257        } else if self.peek_str("-") {
258            self.consume_str("-")?;
259            let operand = self.parse_unary()?;
260            return Ok(Expr::UnaryOp(UnaryOpExpr {
261                op: UnaryOp::Neg,
262                operand: Box::new(operand),
263            }));
264        }
265
266        self.parse_primary()
267    }
268
269    fn parse_primary(&mut self) -> Result<Expr, String> {
270        self.skip_whitespace();
271
272        // Literal string
273        if self.peek_str("\"") || self.peek_str("'") {
274            return self.parse_string_literal();
275        }
276
277        // Literal number
278        if self.peek_digit() || self.peek_str("-") {
279            return self.parse_number_literal();
280        }
281
282        // Literal boolean
283        if self.peek_keyword("true") {
284            self.consume_keyword("true")?;
285            return Ok(Expr::Literal(LiteralExpr::Bool(true)));
286        }
287        if self.peek_keyword("false") {
288            self.consume_keyword("false")?;
289            return Ok(Expr::Literal(LiteralExpr::Bool(false)));
290        }
291
292        // Field access or method call
293        if self.peek_alpha() || self.peek_str("_") {
294            return self.parse_field_or_method();
295        }
296
297        // Parenthesized expression
298        if self.peek_str("(") {
299            self.consume_str("(")?;
300            let expr = self.parse()?;
301            self.skip_whitespace();
302            self.consume_str(")")?;
303            return Ok(expr);
304        }
305
306        Err(format!("Unexpected character at position {}", self.pos))
307    }
308
309    fn parse_field_or_method(&mut self) -> Result<Expr, String> {
310        let mut path = Vec::new();
311
312        // Parse identifier
313        let ident = self.parse_identifier()?;
314
315        // Check if this is a shared state access: `shared.field`
316        let is_shared = ident == "shared";
317
318        if is_shared {
319            // Must have a dot and at least one field after "shared"
320            self.skip_whitespace();
321            if !self.peek_str(".") {
322                // Just "shared" by itself - treat as regular field access (for backward compat)
323                path.push(ident);
324            } else {
325                // Consume the dot after "shared"
326                self.consume_str(".")?;
327
328                // Parse the shared field path
329                let mut shared_path = Vec::new();
330                let first_field = self.parse_identifier()?;
331                shared_path.push(first_field);
332
333                // Check for nested shared field access
334                loop {
335                    self.skip_whitespace();
336                    if self.peek_str(".") {
337                        self.consume_str(".")?;
338                        let next_ident = self.parse_identifier()?;
339                        shared_path.push(next_ident);
340                    } else {
341                        break;
342                    }
343                }
344
345                // Check for method call on shared field
346                self.skip_whitespace();
347                if self.peek_str("(") {
348                    self.consume_str("(")?;
349                    let mut args = Vec::new();
350
351                    // Parse arguments
352                    loop {
353                        self.skip_whitespace();
354                        if self.peek_str(")") {
355                            break;
356                        }
357
358                        let arg = self.parse()?;
359                        args.push(arg);
360
361                        self.skip_whitespace();
362                        if self.peek_str(",") {
363                            self.consume_str(",")?;
364                        } else {
365                            break;
366                        }
367                    }
368
369                    self.consume_str(")")?;
370
371                    // Method call on the shared path
372                    let method = shared_path.pop().ok_or("Empty path for method call")?;
373                    let receiver = if shared_path.is_empty() {
374                        // Just `shared.method()` - receiver is the entire shared context
375                        Expr::SharedFieldAccess(SharedFieldAccessExpr { path: vec![] })
376                    } else {
377                        Expr::SharedFieldAccess(SharedFieldAccessExpr { path: shared_path })
378                    };
379
380                    return Ok(Expr::MethodCall(MethodCallExpr {
381                        receiver: Box::new(receiver),
382                        method,
383                        args,
384                    }));
385                }
386
387                // Just shared field access
388                return Ok(Expr::SharedFieldAccess(SharedFieldAccessExpr {
389                    path: shared_path,
390                }));
391            }
392        } else {
393            path.push(ident);
394        }
395
396        // Check for nested field access
397        loop {
398            self.skip_whitespace();
399            if self.peek_str(".") {
400                self.consume_str(".")?;
401                let next_ident = self.parse_identifier()?;
402                path.push(next_ident);
403            } else {
404                break;
405            }
406        }
407
408        // Check for method call
409        self.skip_whitespace();
410        if self.peek_str("(") {
411            self.consume_str("(")?;
412            let mut args = Vec::new();
413
414            // Parse arguments
415            loop {
416                self.skip_whitespace();
417                if self.peek_str(")") {
418                    break;
419                }
420
421                let arg = self.parse()?;
422                args.push(arg);
423
424                self.skip_whitespace();
425                if self.peek_str(",") {
426                    self.consume_str(",")?;
427                } else {
428                    break;
429                }
430            }
431
432            self.consume_str(")")?;
433
434            // Method call on the path
435            let method = path.pop().ok_or("Empty path for method call")?;
436            let receiver = if path.is_empty() {
437                Expr::Literal(LiteralExpr::String("self".to_string()))
438            } else {
439                Expr::FieldAccess(FieldAccessExpr { path })
440            };
441
442            return Ok(Expr::MethodCall(MethodCallExpr {
443                receiver: Box::new(receiver),
444                method,
445                args,
446            }));
447        }
448
449        // Just field access
450        Ok(Expr::FieldAccess(FieldAccessExpr { path }))
451    }
452
453    fn parse_string_literal(&mut self) -> Result<Expr, String> {
454        let quote = if self.peek_str("\"") { "\"" } else { "'" };
455        self.consume_str(quote)?;
456
457        let mut value = String::new();
458        while self.pos < self.input.len() {
459            let c = self.input[self.pos..].chars().next().unwrap();
460            if c.to_string() == quote {
461                self.pos += 1;
462                break;
463            }
464            if c == '\\' {
465                // Handle escape sequences
466                self.pos += 1;
467                if self.pos < self.input.len() {
468                    let next = self.input[self.pos..].chars().next().unwrap();
469                    value.push(next);
470                    self.pos += next.len_utf8();
471                }
472            } else {
473                value.push(c);
474                self.pos += c.len_utf8();
475            }
476        }
477
478        Ok(Expr::Literal(LiteralExpr::String(value)))
479    }
480
481    fn parse_number_literal(&mut self) -> Result<Expr, String> {
482        let start = self.pos;
483        let mut is_float = false;
484
485        if self.peek_str("-") {
486            self.pos += 1;
487        }
488
489        while self.pos < self.input.len() {
490            let c = self.input[self.pos..].chars().next().unwrap();
491            if c.is_ascii_digit() {
492                self.pos += 1;
493            } else if c == '.' && !is_float {
494                is_float = true;
495                self.pos += 1;
496            } else {
497                break;
498            }
499        }
500
501        let num_str = &self.input[start..self.pos];
502
503        if is_float {
504            let value: f64 = num_str
505                .parse()
506                .map_err(|e| format!("Invalid float: {}", e))?;
507            Ok(Expr::Literal(LiteralExpr::Float(value)))
508        } else {
509            let value: i64 = num_str
510                .parse()
511                .map_err(|e| format!("Invalid integer: {}", e))?;
512            Ok(Expr::Literal(LiteralExpr::Integer(value)))
513        }
514    }
515
516    fn parse_identifier(&mut self) -> Result<String, String> {
517        let start = self.pos;
518
519        if self.pos >= self.input.len() {
520            return Err("Expected identifier".to_string());
521        }
522
523        let first = self.input[self.pos..].chars().next().unwrap();
524        if !first.is_alphabetic() && first != '_' {
525            return Err(format!("Expected identifier, got '{}'", first));
526        }
527
528        self.pos += first.len_utf8();
529
530        while self.pos < self.input.len() {
531            let c = self.input[self.pos..].chars().next().unwrap();
532            if c.is_alphanumeric() || c == '_' {
533                self.pos += c.len_utf8();
534            } else {
535                break;
536            }
537        }
538
539        Ok(self.input[start..self.pos].to_string())
540    }
541
542    fn skip_whitespace(&mut self) {
543        while self.pos < self.input.len() {
544            if let Some(c) = self.input[self.pos..].chars().next() {
545                if c.is_whitespace() {
546                    self.pos += c.len_utf8();
547                } else {
548                    break;
549                }
550            } else {
551                break;
552            }
553        }
554    }
555
556    fn peek_str(&self, s: &str) -> bool {
557        self.input[self.pos..].starts_with(s)
558    }
559
560    fn peek_keyword(&self, keyword: &str) -> bool {
561        let remaining = &self.input[self.pos..];
562        if !remaining.starts_with(keyword) {
563            return false;
564        }
565        // Check that it's followed by whitespace or non-identifier
566        if let Some(next_char) = remaining[keyword.len()..].chars().next() {
567            !next_char.is_alphanumeric() && next_char != '_'
568        } else {
569            true
570        }
571    }
572
573    fn peek_digit(&self) -> bool {
574        self.input[self.pos..]
575            .chars()
576            .next()
577            .map(|c| c.is_ascii_digit())
578            .unwrap_or(false)
579    }
580
581    fn peek_alpha(&self) -> bool {
582        self.input[self.pos..]
583            .chars()
584            .next()
585            .map(|c| c.is_alphabetic())
586            .unwrap_or(false)
587    }
588
589    fn consume_str(&mut self, s: &str) -> Result<(), String> {
590        if self.peek_str(s) {
591            self.pos += s.len();
592            Ok(())
593        } else {
594            Err(format!("Expected '{}'", s))
595        }
596    }
597
598    fn consume_keyword(&mut self, keyword: &str) -> Result<(), String> {
599        if self.peek_keyword(keyword) {
600            self.pos += keyword.len();
601            Ok(())
602        } else {
603            Err(format!("Expected keyword '{}'", keyword))
604        }
605    }
606}