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, 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        path.push(ident);
315
316        // Check for nested field access
317        loop {
318            self.skip_whitespace();
319            if self.peek_str(".") {
320                self.consume_str(".")?;
321                let next_ident = self.parse_identifier()?;
322                path.push(next_ident);
323            } else {
324                break;
325            }
326        }
327
328        // Check for method call
329        self.skip_whitespace();
330        if self.peek_str("(") {
331            self.consume_str("(")?;
332            let mut args = Vec::new();
333
334            // Parse arguments
335            loop {
336                self.skip_whitespace();
337                if self.peek_str(")") {
338                    break;
339                }
340
341                let arg = self.parse()?;
342                args.push(arg);
343
344                self.skip_whitespace();
345                if self.peek_str(",") {
346                    self.consume_str(",")?;
347                } else {
348                    break;
349                }
350            }
351
352            self.consume_str(")")?;
353
354            // Method call on the path
355            let method = path.pop().ok_or("Empty path for method call")?;
356            let receiver = if path.is_empty() {
357                Expr::Literal(LiteralExpr::String("self".to_string()))
358            } else {
359                Expr::FieldAccess(FieldAccessExpr { path })
360            };
361
362            return Ok(Expr::MethodCall(MethodCallExpr {
363                receiver: Box::new(receiver),
364                method,
365                args,
366            }));
367        }
368
369        // Just field access
370        Ok(Expr::FieldAccess(FieldAccessExpr { path }))
371    }
372
373    fn parse_string_literal(&mut self) -> Result<Expr, String> {
374        let quote = if self.peek_str("\"") { "\"" } else { "'" };
375        self.consume_str(quote)?;
376
377        let mut value = String::new();
378        while self.pos < self.input.len() {
379            let c = self.input[self.pos..].chars().next().unwrap();
380            if c.to_string() == quote {
381                self.pos += 1;
382                break;
383            }
384            if c == '\\' {
385                // Handle escape sequences
386                self.pos += 1;
387                if self.pos < self.input.len() {
388                    let next = self.input[self.pos..].chars().next().unwrap();
389                    value.push(next);
390                    self.pos += next.len_utf8();
391                }
392            } else {
393                value.push(c);
394                self.pos += c.len_utf8();
395            }
396        }
397
398        Ok(Expr::Literal(LiteralExpr::String(value)))
399    }
400
401    fn parse_number_literal(&mut self) -> Result<Expr, String> {
402        let start = self.pos;
403        let mut is_float = false;
404
405        if self.peek_str("-") {
406            self.pos += 1;
407        }
408
409        while self.pos < self.input.len() {
410            let c = self.input[self.pos..].chars().next().unwrap();
411            if c.is_ascii_digit() {
412                self.pos += 1;
413            } else if c == '.' && !is_float {
414                is_float = true;
415                self.pos += 1;
416            } else {
417                break;
418            }
419        }
420
421        let num_str = &self.input[start..self.pos];
422
423        if is_float {
424            let value: f64 = num_str
425                .parse()
426                .map_err(|e| format!("Invalid float: {}", e))?;
427            Ok(Expr::Literal(LiteralExpr::Float(value)))
428        } else {
429            let value: i64 = num_str
430                .parse()
431                .map_err(|e| format!("Invalid integer: {}", e))?;
432            Ok(Expr::Literal(LiteralExpr::Integer(value)))
433        }
434    }
435
436    fn parse_identifier(&mut self) -> Result<String, String> {
437        let start = self.pos;
438
439        if self.pos >= self.input.len() {
440            return Err("Expected identifier".to_string());
441        }
442
443        let first = self.input[self.pos..].chars().next().unwrap();
444        if !first.is_alphabetic() && first != '_' {
445            return Err(format!("Expected identifier, got '{}'", first));
446        }
447
448        self.pos += first.len_utf8();
449
450        while self.pos < self.input.len() {
451            let c = self.input[self.pos..].chars().next().unwrap();
452            if c.is_alphanumeric() || c == '_' {
453                self.pos += c.len_utf8();
454            } else {
455                break;
456            }
457        }
458
459        Ok(self.input[start..self.pos].to_string())
460    }
461
462    fn skip_whitespace(&mut self) {
463        while self.pos < self.input.len() {
464            if let Some(c) = self.input[self.pos..].chars().next() {
465                if c.is_whitespace() {
466                    self.pos += c.len_utf8();
467                } else {
468                    break;
469                }
470            } else {
471                break;
472            }
473        }
474    }
475
476    fn peek_str(&self, s: &str) -> bool {
477        self.input[self.pos..].starts_with(s)
478    }
479
480    fn peek_keyword(&self, keyword: &str) -> bool {
481        let remaining = &self.input[self.pos..];
482        if !remaining.starts_with(keyword) {
483            return false;
484        }
485        // Check that it's followed by whitespace or non-identifier
486        if let Some(next_char) = remaining[keyword.len()..].chars().next() {
487            !next_char.is_alphanumeric() && next_char != '_'
488        } else {
489            true
490        }
491    }
492
493    fn peek_digit(&self) -> bool {
494        self.input[self.pos..]
495            .chars()
496            .next()
497            .map(|c| c.is_ascii_digit())
498            .unwrap_or(false)
499    }
500
501    fn peek_alpha(&self) -> bool {
502        self.input[self.pos..]
503            .chars()
504            .next()
505            .map(|c| c.is_alphabetic())
506            .unwrap_or(false)
507    }
508
509    fn consume_str(&mut self, s: &str) -> Result<(), String> {
510        if self.peek_str(s) {
511            self.pos += s.len();
512            Ok(())
513        } else {
514            Err(format!("Expected '{}'", s))
515        }
516    }
517
518    fn consume_keyword(&mut self, keyword: &str) -> Result<(), String> {
519        if self.peek_keyword(keyword) {
520            self.pos += keyword.len();
521            Ok(())
522        } else {
523            Err(format!("Expected keyword '{}'", keyword))
524        }
525    }
526}