Skip to main content

luaparse_rs/parser/
helpers.rs

1use alloc::vec::Vec;
2
3use super::Parser;
4use crate::{
5    ast::*,
6    lexer::Token,
7    marker::LuaVersion,
8    ParseError,
9};
10
11impl<'src, V: LuaVersion> Parser<'src, V> {
12    pub(super) fn parse_identifier(&mut self) -> Result<Identifier, ParseError> {
13        let name = match self.current() {
14            Token::Identifier(name) => name.clone(),
15            Token::Continue if !V::HAS_CONTINUE => "continue".to_string(),
16            Token::Export if !V::HAS_EXPORT => "export".to_string(),
17            Token::Type if !V::HAS_TYPE_ANNOTATIONS => "type".to_string(),
18            Token::Goto if !V::HAS_GOTO => "goto".to_string(),
19            // . . .
20            _ => {
21                return Err(ParseError::UnexpectedToken {
22                    expected: alloc::vec!["identifier".to_string()],
23                    found: alloc::format!("{:?}", self.current()),
24                    span: self.current_span(),
25                });
26            }
27        };
28        
29        let span = self.current_span();
30        self.advance();
31        Ok(Identifier::new(name, span))
32    }
33
34    pub(super) fn can_be_identifier(&self, token: &Token) -> bool {
35        match token {
36            Token::Identifier(_) => true,
37            Token::Continue => !V::HAS_CONTINUE,
38            Token::Export => !V::HAS_EXPORT,
39            Token::Type => !V::HAS_TYPE_ANNOTATIONS,
40            Token::Goto => !V::HAS_GOTO,
41            Token::Const => !V::HAS_CONST,
42            _ => false,
43        }
44    }
45    
46    pub(super) fn parse_block_until(&mut self, terminators: &[Token]) -> Result<Block, ParseError> {
47        let start = self.current_span().start;
48        let mut statements = Vec::new();
49        
50        while !self.is_eof() {
51            self.skip_comments();
52            
53            if terminators.contains(self.current()) {
54                break;
55            }
56            
57            while matches!(self.current(), Token::Semi) {
58                self.advance();
59                self.skip_comments();
60            }
61            
62            if terminators.contains(self.current()) || self.is_eof() {
63                break;
64            }
65            
66            if matches!(
67                self.current(),
68                Token::Return | Token::Break | Token::Continue
69            ) {
70                statements.push(self.parse_statement()?);
71                while matches!(self.current(), Token::Semi) {
72                    self.advance();
73                }
74                
75                break;
76            }
77            
78            statements.push(self.parse_statement()?);
79            
80            if matches!(self.current(), Token::Semi) {
81                self.advance();
82            }
83        }
84        
85        let end = self.current_span().end;
86        Ok(Block::new(statements, start..end))
87    }
88    
89    pub(super) fn parse_parameters(&mut self) -> Result<Vec<Parameter>, ParseError> {
90        let mut parameters = Vec::new();
91        let mut seen_vararg = false;
92        
93        while !matches!(self.current(), Token::RParen | Token::Eof) {
94            self.skip_comments();
95            
96            if seen_vararg {
97                return Err(ParseError::InvalidSyntax {
98                    message: "varargs (...) must be the last parameter".to_string(),
99                    span: self.current_span(),
100                    help: Some("move ... to the end of parameter list".to_string()),
101                });
102            }
103            
104            if let Token::Dot3 = self.current() {
105                let span = self.current_span();
106                self.advance();
107                
108                self.skip_type_annotation()?;
109                
110                parameters.push(Parameter::vararg(span));
111                seen_vararg = true;
112                
113                self.consume(Token::Comma);
114                continue;
115            }
116            
117            let name = self.parse_identifier()?;
118            
119            let attribute = if V::HAS_VARIABLE_ATTRIBUTES && matches!(self.current(), Token::Less) {
120                self.advance();
121                let attr = self.parse_identifier()?;
122                self.expect(Token::Greater)?;
123                Some(attr)
124            } else {
125                None
126            };
127            
128            let type_annotation = if V::HAS_TYPE_ANNOTATIONS && matches!(self.current(), Token::Colon) {
129                Some(self.parse_type_annotation()?)
130            } else {
131                None
132            };
133            
134            let span = name.span.clone();
135            parameters.push(Parameter::new(Some(name), attribute, type_annotation, false, span));
136            
137            if !self.consume(Token::Comma) {
138                break;
139            }
140        }
141        
142        Ok(parameters)
143    }
144
145    pub(super) fn parse_variable_name(&mut self) -> Result<VariableName, ParseError> {
146        let name = self.parse_identifier()?;
147        
148        let attribute = if V::HAS_VARIABLE_ATTRIBUTES && matches!(self.current(), Token::Less) {
149            self.advance();
150            let attr = self.parse_identifier()?;
151            self.expect(Token::Greater)?;
152            Some(attr)
153        } else {
154            None
155        };
156        
157        self.skip_type_annotation()?;
158        
159        Ok(VariableName::new(name, attribute))
160    }
161    
162    pub(super) fn parse_type_annotation(&mut self) -> Result<TypeAnnotation, ParseError> {
163        let start = self.current_span().start;
164        self.expect(Token::Colon)?;
165        self.skip_type_expression()?;
166        let end = self.current_span().end;
167        Ok(TypeAnnotation::new(start..end))
168    }
169    
170    pub(super) fn skip_type_annotation(&mut self) -> Result<(), ParseError> {
171        if V::HAS_TYPE_ANNOTATIONS && matches!(self.current(), Token::Colon) {
172            self.advance();
173            self.skip_type_expression()?;
174        }
175        Ok(())
176    }
177    
178    pub(super) fn skip_type_expression(&mut self) -> Result<(), ParseError> {
179        loop {
180            self.skip_type_primary()?;
181            
182            while matches!(self.current(), Token::Question) {
183                self.advance();
184            }
185            
186            match self.current() {
187                Token::Pipe | Token::Ampersand => {
188                    self.advance();
189                    continue;
190                }
191                _ => break,
192            }
193        }
194        Ok(())
195    }
196    
197    fn skip_type_primary(&mut self) -> Result<(), ParseError> {
198        match self.current() {
199            Token::Identifier(name) if name == "typeof" => {
200                self.advance();
201                self.expect(Token::LParen)?;
202                // Skip the expression inside typeof(...)
203                // We need to handle nested parens
204                let mut depth = 1;
205                while depth > 0 && !self.is_eof() {
206                    match self.current() {
207                        Token::LParen => {
208                            depth += 1;
209                            self.advance();
210                        }
211                        Token::RParen => {
212                            depth -= 1;
213                            if depth > 0 {
214                                self.advance();
215                            }
216                        }
217                        _ => {
218                            self.advance();
219                        }
220                    }
221                }
222                self.expect(Token::RParen)?;
223                Ok(())
224            }
225            Token::Identifier(_) => {
226                self.advance();
227                
228                while matches!(self.current(), Token::Dot) {
229                    self.advance();
230                    self.expect_identifier()?;
231                }
232                
233                if matches!(self.current(), Token::Less) {
234                    self.skip_generic_args()?;
235                }
236                
237                Ok(())
238            }
239            Token::LBrace => {
240                self.advance();
241                self.skip_table_type()?;
242                self.expect(Token::RBrace)?;
243                Ok(())
244            }
245            Token::LParen => {
246                // Could be:
247                // 1. Function type params: (T, U) -> V
248                // 2. Parenthesized type: (string | number)
249                // 3. Empty tuple: ()
250                // 4. Tuple return type: (number, string)
251                //
252                // Strategy: use try_parse with checkpoint to attempt function type first
253                let checkpoint = self.checkpoint();
254                self.advance(); // consume (
255                
256                // Handle empty parens () immediately — void/unit type
257                if matches!(self.current(), Token::RParen) {
258                    self.advance(); // consume )
259                    // Could be () -> T (function type) or just () (void type)
260                    if matches!(self.current(), Token::Arrow) {
261                        self.advance(); // consume ->
262                        self.skip_type_expression()?;
263                    }
264                    return Ok(());
265                }
266                
267                // Try parsing as function type params first
268                let try_result = (|| -> Result<bool, ParseError> {
269                    self.skip_function_type_params()?;
270                    if !matches!(self.current(), Token::RParen) {
271                        return Ok(false);
272                    }
273                    self.advance();
274                    Ok(matches!(self.current(), Token::Arrow))
275                })();
276                
277                match try_result {
278                    Ok(true) => {
279                        // It parsed as function params and has ->
280                        self.advance(); // consume ->
281                        self.skip_type_expression()?;
282                    }
283                    _ => {
284                        // Fall back: could be parenthesized type or tuple
285                        self.restore(checkpoint);
286                        self.advance(); // consume (
287                        // Parse comma-separated type list
288                        self.skip_type_expression()?;
289                        while self.consume(Token::Comma) {
290                            self.skip_type_expression()?;
291                        }
292                        self.expect(Token::RParen)?;
293                        // Check if it's a function type with ->
294                        if matches!(self.current(), Token::Arrow) {
295                            self.advance();
296                            self.skip_type_expression()?;
297                        }
298                    }
299                }
300                
301                Ok(())
302            }
303            Token::String(_) | Token::Number(_) | Token::True | Token::False | Token::Nil => {
304                self.advance();
305                Ok(())
306            }
307            Token::Less => {
308                // Generic function type: <T, U>(x: T) -> U
309                self.skip_generic_args()?;
310                self.expect(Token::LParen)?;
311                self.skip_function_type_params()?;
312                self.expect(Token::RParen)?;
313                if matches!(self.current(), Token::Arrow) {
314                    self.advance();
315                    self.skip_type_expression()?;
316                }
317                Ok(())
318            }
319            Token::Dot3 => {
320                self.advance();
321                self.skip_type_expression()?;
322                Ok(())
323            }
324            _ => Err(ParseError::InvalidSyntax {
325                message: "expected type expression".to_string(),
326                span: self.current_span(),
327                help: None,
328            }),
329        }
330    }
331    
332    pub fn skip_generic_args(&mut self) -> Result<(), ParseError> {
333        self.expect(Token::Less)?;
334        
335        if matches!(self.current(), Token::Greater) {
336            self.advance();
337            return Ok(());
338        }
339        
340        loop {
341            self.skip_type_expression()?;
342            
343            match self.current() {
344                Token::Comma => {
345                    self.advance();
346                    continue;
347                }
348                Token::Greater => {
349                    self.advance();
350                    break;
351                }
352                Token::RightShift => {
353                    // >> is actually two > closing nested generics like Map<string, Array<number>>
354                    self.split_right_shift();
355                    self.advance(); // consume first >
356                    break;
357                }
358                Token::GreaterEq => {
359                    return Err(ParseError::InvalidSyntax {
360                        message: "unexpected '>=' in generic arguments".to_string(),
361                        span: self.current_span(),
362                        help: Some("use '>' to close generic arguments".to_string()),
363                    });
364                }
365                _ => {
366                    return Err(ParseError::UnexpectedToken {
367                        expected: vec![",".to_string(), ">".to_string()],
368                        found: format!("{:?}", self.current()),
369                        span: self.current_span(),
370                    });
371                }
372            }
373        }
374        
375        Ok(())
376    }
377    
378    fn skip_table_type(&mut self) -> Result<(), ParseError> {
379        while !matches!(self.current(), Token::RBrace | Token::Eof) {
380            self.skip_comments();
381            
382            if matches!(self.current(), Token::Comma | Token::Semi) {
383                self.advance();
384                continue;
385            }
386            
387            if matches!(self.current(), Token::LBracket) {
388                self.advance();
389                self.skip_type_expression()?;
390                self.expect(Token::RBracket)?;
391                self.expect(Token::Colon)?;
392                self.skip_type_expression()?;
393            } else if let Token::Identifier(_) = self.current() {
394                self.advance();
395                if matches!(self.current(), Token::Colon) {
396                    self.advance();
397                    self.skip_type_expression()?;
398                }
399            } else {
400                break;
401            }
402        }
403        
404        Ok(())
405    }
406    
407    fn skip_function_type_params(&mut self) -> Result<(), ParseError> {
408        while !matches!(self.current(), Token::RParen | Token::Eof) {
409            self.skip_comments();
410            
411            if matches!(self.current(), Token::Dot3) {
412                self.advance();
413                if matches!(self.current(), Token::Identifier(_)) {
414                    self.advance();
415                }
416                if matches!(self.current(), Token::Colon) {
417                    self.advance();
418                    self.skip_type_expression()?;
419                }
420                break;
421            }
422            
423            if matches!(self.current(), Token::Identifier(_)) {
424                self.advance();
425                if matches!(self.current(), Token::Colon) {
426                    self.advance();
427                    self.skip_type_expression()?;
428                }
429            } else {
430                self.skip_type_expression()?;
431            }
432            
433            if !self.consume(Token::Comma) {
434                break;
435            }
436        }
437        
438        Ok(())
439    }
440    
441    fn expect_identifier(&mut self) -> Result<(), ParseError> {
442        if matches!(self.current(), Token::Identifier(_)) {
443            self.advance();
444            Ok(())
445        } else {
446            Err(ParseError::UnexpectedToken {
447                expected: vec!["identifier".to_string()],
448                found: format!("{:?}", self.current()),
449                span: self.current_span(),
450            })
451        }
452    }
453    
454    pub(super) fn parse_attributes(&mut self) -> Result<Vec<Attribute>, ParseError> {
455        let mut attributes = Vec::new();
456        
457        while matches!(self.current(), Token::At) {
458            self.advance();
459            
460            let name = self.parse_identifier()?;
461            let fields = if matches!(self.current(), Token::LBracket) {
462                self.advance();
463                let fields = self.parse_attribute_fields()?;
464                self.expect(Token::RBracket)?;
465                Some(fields)
466            } else {
467                None
468            };
469            
470            let span = name.span.clone();
471            attributes.push(Attribute::new(name, fields, span));
472        }
473        
474        Ok(attributes)
475    }
476    
477    fn parse_attribute_fields(&mut self) -> Result<Vec<AttributeField>, ParseError> {
478        let mut fields = Vec::new();
479        
480        while !matches!(self.current(), Token::RBracket | Token::Eof) {
481            self.skip_comments();
482            
483            if matches!(self.current(), Token::Comma) {
484                self.advance();
485                continue;
486            }
487            
488            let checkpoint = self.checkpoint();
489            let key = if let Ok(ident) = self.parse_identifier() {
490                if matches!(self.current(), Token::Eq) {
491                    self.advance();
492                    Some(ident)
493                } else {
494                    self.restore(checkpoint);
495                    None
496                }
497            } else {
498                None
499            };
500            
501            let value = self.parse_attribute_value()?;
502            fields.push(AttributeField::new(key, value));
503            
504            if !self.consume(Token::Comma) {
505                break;
506            }
507        }
508        
509        Ok(fields)
510    }
511    
512    fn parse_attribute_value(&mut self) -> Result<AttributeValue, ParseError> {
513        match self.current() {
514            Token::String(s) => {
515                let s = s.clone();
516                self.advance();
517                Ok(AttributeValue::String(s))
518            }
519            Token::Number(n) => {
520                let n = n.clone();
521                self.advance();
522                Ok(AttributeValue::Number(n))
523            }
524            Token::True => {
525                self.advance();
526                Ok(AttributeValue::Boolean(true))
527            }
528            Token::False => {
529                self.advance();
530                Ok(AttributeValue::Boolean(false))
531            }
532            Token::Identifier(_) => {
533                let ident = self.parse_identifier()?;
534                Ok(AttributeValue::Identifier(ident))
535            }
536            _ => Err(ParseError::UnexpectedToken {
537                expected: vec!["string, number, boolean, or identifier".to_string()],
538                found: format!("{:?}", self.current()),
539                span: self.current_span(),
540            }),
541        }
542    }
543}