devalang_core/core/parser/
driver.rs

1use crate::core::{
2    lexer::token::{ Token, TokenKind },
3    parser::{
4        handler::{
5            arrow_call::parse_arrow_call,
6            at::parse_at_token,
7            bank::parse_bank_token,
8            condition::parse_condition_token,
9            dot::parse_dot_token,
10            identifier::{ function::parse_function_token, parse_identifier_token },
11            loop_::parse_loop_token,
12            tempo::parse_tempo_token,
13        },
14        statement::Statement,
15    },
16    shared::value::Value,
17    store::global::GlobalStore,
18};
19
20#[derive(Debug, Clone, PartialEq)]
21pub struct Parser {
22    pub resolve_modules: bool,
23    pub tokens: Vec<Token>,
24    pub token_index: usize,
25    pub current_module: String,
26    pub previous: Option<Token>,
27}
28
29impl Parser {
30    pub fn new() -> Self {
31        Parser {
32            resolve_modules: false,
33            tokens: Vec::new(),
34            token_index: 0,
35            current_module: String::new(),
36            previous: None,
37        }
38    }
39
40    pub fn set_current_module(&mut self, module_path: String) {
41        self.current_module = module_path;
42    }
43
44    pub fn advance(&mut self) -> Option<&Token> {
45        if self.is_eof() {
46            return None;
47        }
48
49        self.previous = self.tokens.get(self.token_index).cloned();
50        self.token_index += 1;
51
52        self.tokens.get(self.token_index - 1)
53    }
54
55    pub fn peek_is(&self, expected: &str) -> bool {
56        self.peek().map_or(false, |t| t.lexeme == expected)
57    }
58
59    pub fn peek_nth(&self, n: usize) -> Option<&Token> {
60        if self.token_index + n < self.tokens.len() {
61            self.tokens.get(self.token_index + n)
62        } else {
63            None
64        }
65    }
66
67    pub fn peek_nth_kind(&self, n: usize) -> Option<TokenKind> {
68        self.peek_nth(n).map(|t| t.kind.clone())
69    }
70
71    pub fn advance_if(&mut self, kind: TokenKind) -> bool {
72        if self.match_token(kind) { true } else { false }
73    }
74
75    pub fn match_token(&mut self, kind: TokenKind) -> bool {
76        if let Some(tok) = self.peek() {
77            if tok.kind == kind {
78                self.advance();
79                return true;
80            }
81        }
82        false
83    }
84
85    pub fn previous_clone(&self) -> Option<Token> {
86        self.previous.clone()
87    }
88
89    pub fn parse_block(
90        &self,
91        tokens: Vec<Token>,
92        global_store: &mut GlobalStore
93    ) -> Vec<Statement> {
94        let mut inner_parser = Parser {
95            resolve_modules: self.resolve_modules,
96            tokens,
97            token_index: 0,
98            current_module: self.current_module.clone(),
99            previous: None,
100        };
101
102        inner_parser.parse_tokens(inner_parser.tokens.clone(), global_store)
103    }
104
105    pub fn parse_tokens(
106        &mut self,
107        tokens: Vec<Token>,
108        global_store: &mut GlobalStore
109    ) -> Vec<Statement> {
110        // Filtrer uniquement les espaces, mais conserver les Newline car
111        // certaines constructions (ex: print ...) s'appuient sur la fin de ligne.
112        self.tokens = tokens
113            .into_iter()
114            .filter(|t| t.kind != TokenKind::Whitespace)
115            .collect();
116        self.token_index = 0;
117
118        let mut statements = Vec::new();
119
120        while !self.is_eof() {
121            let token = match self.peek() {
122                Some(t) => t.clone(),
123                None => {
124                    break;
125                }
126            };
127
128            if token.kind == TokenKind::Newline {
129                self.advance();
130                continue;
131            }
132
133            let statement = match &token.kind {
134                TokenKind::At => parse_at_token(self, global_store),
135                TokenKind::Identifier => {
136                    if let Some(next) = self.peek_nth(1).cloned() {
137                        if next.kind == TokenKind::Arrow {
138                            parse_arrow_call(self, global_store)
139                        } else {
140                            parse_identifier_token(self, global_store)
141                        }
142                    } else {
143                        parse_identifier_token(self, global_store)
144                    }
145                }
146                TokenKind::Dot => parse_dot_token(self, global_store),
147                TokenKind::Tempo => parse_tempo_token(self, global_store),
148                TokenKind::Bank => parse_bank_token(self, global_store),
149                TokenKind::Loop => parse_loop_token(self, global_store),
150                TokenKind::If => parse_condition_token(self, global_store),
151                TokenKind::Function => parse_function_token(self, global_store),
152
153                | TokenKind::Else // Ignore else, already handled in `parse_condition_token`
154                | TokenKind::Comment
155                | TokenKind::Equals
156                | TokenKind::Colon
157                | TokenKind::Number
158                | TokenKind::String
159                | TokenKind::LBrace
160                | TokenKind::RBrace
161                | TokenKind::Comma
162                | TokenKind::Dedent
163                | TokenKind::Indent => {
164                    self.advance();
165                    continue;
166                }
167
168                TokenKind::EOF => {
169                    break;
170                }
171
172                _ => {
173                    println!("Unhandled token: {:?}", token);
174                    self.advance();
175                    Statement::unknown()
176                }
177            };
178
179            statements.push(statement);
180        }
181
182        statements
183    }
184
185    pub fn check_token(&self, kind: TokenKind) -> bool {
186        self.peek().map_or(false, |t| t.kind == kind)
187    }
188
189    pub fn peek_kind(&self) -> Option<TokenKind> {
190        self.peek().map(|t| t.kind.clone())
191    }
192
193    pub fn parse_map_value(&mut self) -> Option<Value> {
194        if !self.match_token(TokenKind::LBrace) {
195            return None;
196        }
197
198        let mut map = std::collections::HashMap::new();
199
200        while !self.check_token(TokenKind::RBrace) && !self.is_eof() {
201            // Skip separators and formatting before the key
202            while
203                self.check_token(TokenKind::Newline) ||
204                self.check_token(TokenKind::Whitespace) ||
205                self.check_token(TokenKind::Indent) ||
206                self.check_token(TokenKind::Dedent) ||
207                self.check_token(TokenKind::Comma)
208            {
209                self.advance();
210            }
211
212            // Check if we are at the closing brace of the map
213            if self.check_token(TokenKind::RBrace) {
214                break;
215            }
216
217            let key = if let Some(token) = self.advance() {
218                match token.kind {
219                    | TokenKind::Whitespace
220                    | TokenKind::Indent
221                    | TokenKind::Dedent
222                    | TokenKind::Newline => {
223                        continue;
224                    }
225                    _ => token.lexeme.clone(),
226                }
227            } else {
228                break;
229            };
230
231            // Skip newlines and whitespace before colon
232            while self.check_token(TokenKind::Newline) || self.check_token(TokenKind::Whitespace) {
233                self.advance();
234            }
235
236            if !self.match_token(TokenKind::Colon) {
237                println!("Expected ':' after map key '{}'", key);
238                break;
239            }
240
241            // Skip separators and formatting before value
242            while
243                self.check_token(TokenKind::Newline) ||
244                self.check_token(TokenKind::Whitespace) ||
245                self.check_token(TokenKind::Indent) ||
246                self.check_token(TokenKind::Dedent) ||
247                self.check_token(TokenKind::Comma)
248            {
249                self.advance();
250            }
251
252            let value = if let Some(token) = self.peek_clone() {
253                match token.kind {
254                    TokenKind::String => {
255                        self.advance();
256                        Value::String(token.lexeme.clone())
257                    }
258                    TokenKind::Number => {
259                        let mut number_str = token.lexeme.clone();
260                        self.advance(); // consume the first number
261
262                        if let Some(dot_token) = self.peek_clone() {
263                            if dot_token.kind == TokenKind::Dot {
264                                self.advance(); // consume the dot
265
266                                if let Some(decimal_token) = self.peek_clone() {
267                                    if decimal_token.kind == TokenKind::Number {
268                                        self.advance(); // consume the number after the dot
269                                        number_str.push('.');
270                                        number_str.push_str(&decimal_token.lexeme);
271                                    } else {
272                                        println!(
273                                            "Expected number after dot, got {:?}",
274                                            decimal_token
275                                        );
276                                        return Some(Value::Null);
277                                    }
278                                } else {
279                                    println!("Expected number after dot, but reached EOF");
280                                    return Some(Value::Null);
281                                }
282                            }
283                        }
284
285                        Value::Number(number_str.parse::<f32>().unwrap_or(0.0))
286                    }
287
288                    TokenKind::Identifier => {
289                        self.advance();
290                        Value::Identifier(token.lexeme.clone())
291                    }
292                    _ => {
293                        println!("Unexpected token in map value: {:?}", token);
294                        Value::Null
295                    }
296                }
297            } else {
298                Value::Null
299            };
300
301            map.insert(key, value);
302
303            // Optionally skip a trailing comma after the value
304            while self.check_token(TokenKind::Comma) || self.check_token(TokenKind::Whitespace) || self.check_token(TokenKind::Newline) {
305                self.advance();
306            }
307        }
308
309        if !self.match_token(TokenKind::RBrace) {
310            println!("Expected '}}' at end of map");
311        }
312
313        Some(Value::Map(map))
314    }
315
316    // Parse an array value like [1, 2, 3] or ["a", b]
317    pub fn parse_array_value(&mut self) -> Option<Value> {
318        if !self.match_token(TokenKind::LBracket) {
319            return None;
320        }
321
322        let mut arr: Vec<Value> = Vec::new();
323
324        while !self.check_token(TokenKind::RBracket) && !self.is_eof() {
325            // Skip formatting tokens
326            while
327                self.check_token(TokenKind::Newline) ||
328                self.check_token(TokenKind::Whitespace) ||
329                self.check_token(TokenKind::Indent) ||
330                self.check_token(TokenKind::Dedent) ||
331                self.check_token(TokenKind::Comma)
332            {
333                self.advance();
334            }
335
336            if self.check_token(TokenKind::RBracket) {
337                break;
338            }
339
340            if let Some(token) = self.peek_clone() {
341                let value = match token.kind {
342                    TokenKind::String => { self.advance(); Value::String(token.lexeme.clone()) }
343                    TokenKind::Number => {
344                        // Support simple decimals split as number '.' number
345                        let mut number_str = token.lexeme.clone();
346                        self.advance();
347                        if let Some(dot) = self.peek_clone() {
348                            if dot.kind == TokenKind::Dot {
349                                if let Some(next) = self.peek_nth(1).cloned() {
350                                    if next.kind == TokenKind::Number {
351                                        self.advance(); // consume dot
352                                        self.advance(); // consume next number
353                                        number_str.push('.');
354                                        number_str.push_str(&next.lexeme);
355                                    }
356                                }
357                            }
358                        }
359                        Value::Number(number_str.parse::<f32>().unwrap_or(0.0))
360                    }
361                    TokenKind::Identifier => { self.advance(); Value::Identifier(token.lexeme.clone()) }
362                    TokenKind::LBrace => {
363                        // Allow inline maps inside arrays
364                        if let Some(v) = self.parse_map_value() { v } else { Value::Null }
365                    }
366                    TokenKind::LBracket => {
367                        // Nested arrays
368                        if let Some(v) = self.parse_array_value() { v } else { Value::Null }
369                    }
370                    _ => { self.advance(); Value::Null }
371                };
372
373                // Only push non-null (retain alignment with permissive parsing)
374                if value != Value::Null { arr.push(value); }
375
376                // Optional trailing comma handled by the skipper at loop start
377            } else {
378                break;
379            }
380        }
381
382        if !self.match_token(TokenKind::RBracket) {
383            println!("Expected ']' at end of array");
384        }
385
386        Some(Value::Array(arr))
387    }
388
389    pub fn peek(&self) -> Option<&Token> {
390        self.tokens.get(self.token_index)
391    }
392
393    pub fn peek_clone(&self) -> Option<Token> {
394        self.tokens.get(self.token_index).cloned()
395    }
396
397    pub fn expect(&mut self, kind: TokenKind) -> Result<&Token, String> {
398        let tok = self.advance().ok_or("Unexpected end of input")?;
399        if tok.kind == kind {
400            Ok(tok)
401        } else {
402            Err(format!("Expected {:?}, got {:?}", kind, tok.kind))
403        }
404    }
405
406    pub fn collect_block_tokens(&mut self, base_indent: usize) -> Vec<Token> {
407        let mut tokens = Vec::new();
408
409        while let Some(tok) = self.peek() {
410            if tok.indent <= base_indent && tok.kind != TokenKind::Newline {
411                break;
412            }
413            tokens.push(self.advance().unwrap().clone());
414        }
415
416        tokens
417    }
418
419    pub fn collect_until<F>(&mut self, condition: F) -> Vec<Token> where F: Fn(&Token) -> bool {
420        let mut collected = Vec::new();
421        while let Some(token) = self.peek() {
422            if condition(token) {
423                break;
424            }
425            if token.kind == TokenKind::EOF {
426                break;
427            }
428            collected.push(self.advance().unwrap().clone());
429        }
430
431        collected
432    }
433
434    pub fn is_eof(&self) -> bool {
435        self.token_index >= self.tokens.len()
436    }
437
438    pub fn parse_block_until_next_else(
439        &mut self,
440        base_indent: usize,
441        global_store: &mut GlobalStore
442    ) -> Vec<Statement> {
443        let mut block_tokens = Vec::new();
444
445        while let Some(tok) = self.peek() {
446            // Stop if we encounter an 'else' at same indent level
447            if tok.lexeme == "else" && tok.indent == base_indent {
448                break;
449            }
450            block_tokens.push(self.advance().unwrap().clone());
451        }
452
453        self.parse_block(block_tokens, global_store)
454    }
455
456    pub fn parse_condition_until_colon(&mut self) -> Option<Value> {
457        let tokens = self.collect_until(|t| t.kind == TokenKind::Colon);
458        if tokens.is_empty() {
459            return None;
460        }
461
462        let condition = tokens
463            .iter()
464            .map(|t| t.lexeme.clone())
465            .collect::<Vec<_>>()
466            .join(" ");
467
468        Some(Value::String(condition))
469    }
470
471    pub fn parse_block_until_else_or_dedent(
472        &mut self,
473        base_indent: usize,
474        global_store: &mut GlobalStore
475    ) -> Vec<Statement> {
476        let mut tokens = Vec::new();
477
478        while let Some(tok) = self.peek() {
479            if tok.lexeme == "else" && tok.indent == base_indent {
480                break;
481            }
482            if tok.indent < base_indent && tok.kind != TokenKind::Newline {
483                break;
484            }
485            tokens.push(self.advance().unwrap().clone());
486        }
487
488        self.parse_block(tokens, global_store)
489    }
490}