Skip to main content

somni_parser/
parser.rs

1//! Grammar parser.
2//!
3//! This module parses the following grammar (minus comments, which are ignored):
4//!
5//! ```text
6//! program -> item* EOF;
7//! item -> function | global | extern_fn | struct_def; // TODO types.
8//!
9//! extern_fn -> 'extern' 'fn' identifier '(' function_argument ( ',' function_argument )* ','? ')' return_decl? ;
10//! global -> 'var' identifier ':' type '=' static_initializer ';' ;
11//!
12//! struct_def -> 'struct' identifier '{' ( struct_field ( ',' struct_field )* ','? )? '}' ;
13//! struct_field -> identifier ':' type ;
14//!
15//! static_initializer -> right_hand_expression ; // The language does not currently support function calls.
16//!
17//! function -> 'fn' identifier '(' function_argument ( ',' function_argument )* ','? ')' return_decl? body ;
18//! function_argument -> identifier ':' '&'? type ;
19//! return_decl -> '->' type ;
20//! type -> identifier ;
21//!
22//! body -> '{' statement '}' ;
23//! statement -> 'var' identifier (':' type)? '=' right_hand_expression ';' (statement)?
24//!            | 'return' right_hand_expression? ';' (statement)?
25//!            | 'break' ';' (statement)?
26//!            | 'continue' ';' (statement)?
27//!            | 'if' condition body ( 'else' body )? (statement)?
28//!            | 'loop' body (statement)?
29//!            | 'while' condition body (statement)?
30//!            | 'for' identifier ( ':' type )? 'in' condition body (statement)?
31//!            | body (statement)?
32//!            | expression ';' (statement)?
33//!            | right_hand_expression // implicit return statmenet
34//!
35//! expression -> (left_hand_expression '=')? right_hand_expression ;
36//!
37//! // A place: a variable, a whole-value dereference, or a path of field accesses.
38//! left_hand_expression -> '*' identifier
39//!                       | identifier ( '.' identifier )* ; // Should be a valid expression, too.
40//!
41//! // `condition` (used by `if`/`while`/`for`) is identical to `right_hand_expression`
42//! // except a *top-level* struct literal is not allowed, so a `{` unambiguously begins
43//! // the following block. Struct literals remain reachable inside parentheses.
44//! right_hand_expression -> binary2 ( '||' binary2 )* ;
45//! condition             -> right_hand_expression ; // minus a top-level struct_literal in `primary`
46//! binary2 -> binary3 ( '&&' binary3 )* ;
47//! binary3 -> binary4 ( ( '<' | '<=' | '>' | '>=' | '==' | '!=' ) binary4 )* ;
48//! binary4 -> binary5 ( '|' binary5 )* ;
49//! binary5 -> binary6 ( '^' binary6 )* ;
50//! binary6 -> binary7 ( '&' binary7 )* ;
51//! binary7 -> binary8 ( ( '<<' | '>>' ) binary8 )* ;
52//! binary8 -> binary9 ( ( '+' | '-' ) binary9 )* ;
53//! binary9 -> unary ( ( '*' | '/', '%' ) unary )* ;
54//! unary -> ('!' | '-' | '&' | '*' )* postfix ;
55//! postfix -> primary ( '.' identifier )* ; // field access binds tighter than any unary prefix
56//! primary -> literal
57//!          | identifier struct_literal        // only where struct literals are allowed (see `condition`)
58//!          | identifier ( '(' call_arguments ')' )?
59//!          | '(' right_hand_expression ')' ;
60//! struct_literal -> '{' ( struct_literal_field ( ',' struct_literal_field )* ','? )? '}' ;
61//! struct_literal_field -> identifier ':' right_hand_expression ;
62//! call_arguments -> right_hand_expression ( ',' right_hand_expression )* ','? ;
63//! literal -> NUMBER | STRING | 'true' | 'false' ;
64//! ```
65//!
66//! `NUMBER`: Non-negative integers (binary, decimal, hexadecimal) and floats.
67//! `STRING`: Double-quoted strings with escape sequences.
68
69use std::{
70    fmt::{Debug, Display},
71    num::{ParseFloatError, ParseIntError},
72    ops::ControlFlow,
73};
74
75use crate::{
76    Error, Location,
77    ast::{
78        Body, Break, Continue, Else, EmptyReturn, Expression, ExternalFunction, For, Function,
79        FunctionArgument, GlobalVariable, If, Item, LeftHandExpression, Literal, LiteralValue,
80        Loop, Program, ReturnDecl, ReturnWithValue, RightHandExpression, Statement, StructDef,
81        StructField, StructLiteralField, TypeHint, VariableDefinition,
82    },
83    lexer::{Token, TokenKind, Tokenizer},
84    parser::private::Sealed,
85};
86
87mod private {
88    pub trait Sealed {}
89
90    impl Sealed for u32 {}
91    impl Sealed for u64 {}
92    impl Sealed for u128 {}
93    impl Sealed for f32 {}
94    impl Sealed for f64 {}
95}
96
97/// Parse literals into Somni integers.
98pub trait IntParser: Sized + Sealed {
99    fn parse(str: &str, radix: u32) -> Result<Self, ParseIntError>;
100}
101
102impl IntParser for u32 {
103    fn parse(str: &str, radix: u32) -> Result<Self, ParseIntError> {
104        u32::from_str_radix(str, radix)
105    }
106}
107impl IntParser for u64 {
108    fn parse(str: &str, radix: u32) -> Result<Self, ParseIntError> {
109        u64::from_str_radix(str, radix)
110    }
111}
112impl IntParser for u128 {
113    fn parse(str: &str, radix: u32) -> Result<Self, ParseIntError> {
114        u128::from_str_radix(str, radix)
115    }
116}
117
118/// Parse literals into Somni floats.
119pub trait FloatParser: Sized + Sealed {
120    fn parse(str: &str) -> Result<Self, ParseFloatError>;
121}
122
123impl FloatParser for f32 {
124    fn parse(str: &str) -> Result<Self, ParseFloatError> {
125        str.parse::<f32>()
126    }
127}
128impl FloatParser for f64 {
129    fn parse(str: &str) -> Result<Self, ParseFloatError> {
130        str.parse::<f64>()
131    }
132}
133
134/// Defines the numeric types used in the parser.
135pub trait TypeSet: Debug + Default {
136    type Integer: IntParser + Clone + Copy + PartialEq + Debug;
137    type Float: FloatParser + Clone + Copy + PartialEq + Debug;
138}
139
140/// Use 64-bit integers and 64-bit floats (default).
141#[derive(Debug, Default)]
142pub struct DefaultTypeSet;
143impl Sealed for DefaultTypeSet {}
144
145impl TypeSet for DefaultTypeSet {
146    type Integer = u64;
147    type Float = f64;
148}
149
150/// Use 32-bit integers and floats.
151#[derive(Debug, Default)]
152pub struct TypeSet32;
153impl Sealed for TypeSet32 {}
154impl TypeSet for TypeSet32 {
155    type Integer = u32;
156    type Float = f32;
157}
158
159/// Use 128-bit integers and 64-bit floats.
160#[derive(Debug, Default)]
161pub struct TypeSet128;
162impl Sealed for TypeSet128 {}
163impl TypeSet for TypeSet128 {
164    type Integer = u128;
165    type Float = f64;
166}
167
168impl<T> Program<T>
169where
170    T: TypeSet,
171{
172    fn parse(stream: &mut TokenStream<'_, impl Tokenizer>) -> Result<Self, Error> {
173        let mut items = Vec::new();
174
175        while !stream.end()? {
176            items.push(Item::parse(stream)?);
177        }
178
179        Ok(Program { items })
180    }
181}
182
183impl<T> Item<T>
184where
185    T: TypeSet,
186{
187    fn parse(stream: &mut TokenStream<'_, impl Tokenizer>) -> Result<Self, Error> {
188        if let Some(struct_def) = StructDef::try_parse(stream)? {
189            return Ok(Item::Struct(struct_def));
190        }
191        if let Some(global_var) = GlobalVariable::try_parse(stream)? {
192            return Ok(Item::GlobalVariable(global_var));
193        }
194        if let Some(function) = ExternalFunction::try_parse(stream)? {
195            return Ok(Item::ExternFunction(function));
196        }
197        if let Some(function) = Function::try_parse(stream)? {
198            return Ok(Item::Function(function));
199        }
200
201        Err(stream.error("Expected global variable, function, or struct definition"))
202    }
203}
204
205impl StructDef {
206    fn try_parse(stream: &mut TokenStream<'_, impl Tokenizer>) -> Result<Option<Self>, Error> {
207        let Some(struct_token) = stream.take_match(TokenKind::Identifier, &["struct"])? else {
208            return Ok(None);
209        };
210
211        let name = stream.expect_match(TokenKind::Identifier, &[])?;
212        let opening_brace = stream.expect_match(TokenKind::Symbol, &["{"])?;
213
214        let mut fields = Vec::new();
215        while let Some(field_name) = stream.take_match(TokenKind::Identifier, &[])? {
216            let colon = stream.expect_match(TokenKind::Symbol, &[":"])?;
217            let field_type = TypeHint::parse(stream)?;
218
219            fields.push(StructField {
220                name: field_name,
221                colon,
222                field_type,
223            });
224
225            if stream.take_match(TokenKind::Symbol, &[","])?.is_none() {
226                break;
227            }
228        }
229
230        let closing_brace = stream.expect_match(TokenKind::Symbol, &["}"])?;
231
232        Ok(Some(StructDef {
233            struct_token,
234            name,
235            opening_brace,
236            fields,
237            closing_brace,
238        }))
239    }
240}
241
242impl<T> GlobalVariable<T>
243where
244    T: TypeSet,
245{
246    fn try_parse(stream: &mut TokenStream<'_, impl Tokenizer>) -> Result<Option<Self>, Error> {
247        let Some(decl_token) = stream.take_match(TokenKind::Identifier, &["var"])? else {
248            return Ok(None);
249        };
250
251        let identifier = stream.expect_match(TokenKind::Identifier, &[])?;
252        let colon = stream.expect_match(TokenKind::Symbol, &[":"])?;
253        let type_token = TypeHint::parse(stream)?;
254        let equals_token = stream.expect_match(TokenKind::Symbol, &["="])?;
255        let initializer = Expression::Expression {
256            expression: RightHandExpression::parse(stream)?,
257        };
258        let semicolon = stream.expect_match(TokenKind::Symbol, &[";"])?;
259
260        Ok(Some(GlobalVariable {
261            decl_token,
262            identifier,
263            colon,
264            type_token,
265            equals_token,
266            initializer,
267            semicolon,
268        }))
269    }
270}
271
272impl ExternalFunction {
273    fn try_parse(stream: &mut TokenStream<'_, impl Tokenizer>) -> Result<Option<Self>, Error> {
274        let Some(extern_fn_token) = stream.take_match(TokenKind::Identifier, &["extern"])? else {
275            return Ok(None);
276        };
277        let Some(fn_token) = stream.take_match(TokenKind::Identifier, &["fn"])? else {
278            return Ok(None);
279        };
280
281        let name = stream.expect_match(TokenKind::Identifier, &[])?;
282        let opening_paren = stream.expect_match(TokenKind::Symbol, &["("])?;
283
284        let mut arguments = Vec::new();
285        while let Some(arg_name) = stream.take_match(TokenKind::Identifier, &[])? {
286            let colon = stream.expect_match(TokenKind::Symbol, &[":"])?;
287            let reference_token = stream.take_match(TokenKind::Symbol, &["&"])?;
288            let type_token = TypeHint::parse(stream)?;
289
290            arguments.push(FunctionArgument {
291                name: arg_name,
292                colon,
293                reference_token,
294                arg_type: type_token,
295            });
296
297            if stream.take_match(TokenKind::Symbol, &[","])?.is_none() {
298                break;
299            }
300        }
301
302        let closing_paren = stream.expect_match(TokenKind::Symbol, &[")"])?;
303
304        let return_decl =
305            if let Some(return_token) = stream.take_match(TokenKind::Symbol, &["->"])? {
306                Some(ReturnDecl {
307                    return_token,
308                    return_type: TypeHint::parse(stream)?,
309                })
310            } else {
311                None
312            };
313
314        let semicolon = stream.expect_match(TokenKind::Symbol, &[";"])?;
315
316        Ok(Some(ExternalFunction {
317            extern_fn_token,
318            fn_token,
319            name,
320            opening_paren,
321            arguments,
322            closing_paren,
323            return_decl,
324            semicolon,
325        }))
326    }
327}
328
329impl<T> Function<T>
330where
331    T: TypeSet,
332{
333    fn try_parse(stream: &mut TokenStream<'_, impl Tokenizer>) -> Result<Option<Self>, Error> {
334        let Some(fn_token) = stream.take_match(TokenKind::Identifier, &["fn"])? else {
335            return Ok(None);
336        };
337
338        let name = stream.expect_match(TokenKind::Identifier, &[])?;
339        let opening_paren = stream.expect_match(TokenKind::Symbol, &["("])?;
340
341        let mut arguments = Vec::new();
342        while let Some(arg_name) = stream.take_match(TokenKind::Identifier, &[])? {
343            let colon = stream.expect_match(TokenKind::Symbol, &[":"])?;
344            let reference_token = stream.take_match(TokenKind::Symbol, &["&"])?;
345            let type_token = TypeHint::parse(stream)?;
346
347            arguments.push(FunctionArgument {
348                name: arg_name,
349                colon,
350                reference_token,
351                arg_type: type_token,
352            });
353
354            if stream.take_match(TokenKind::Symbol, &[","])?.is_none() {
355                break;
356            }
357        }
358
359        let closing_paren = stream.expect_match(TokenKind::Symbol, &[")"])?;
360
361        let return_decl =
362            if let Some(return_token) = stream.take_match(TokenKind::Symbol, &["->"])? {
363                Some(ReturnDecl {
364                    return_token,
365                    return_type: TypeHint::parse(stream)?,
366                })
367            } else {
368                None
369            };
370
371        let body = Body::parse(stream)?;
372
373        Ok(Some(Function {
374            fn_token,
375            name,
376            opening_paren,
377            arguments,
378            closing_paren,
379            return_decl,
380            body,
381        }))
382    }
383}
384
385impl<T> Body<T>
386where
387    T: TypeSet,
388{
389    fn parse(stream: &mut TokenStream<'_, impl Tokenizer>) -> Result<Self, Error> {
390        let opening_brace = stream.expect_match(TokenKind::Symbol, &["{"])?;
391
392        let mut body = Vec::new();
393        while Statement::<T>::matches(stream)? {
394            let (statement, stop) = match Statement::parse(stream)? {
395                ControlFlow::Continue(statement) => (statement, false),
396                ControlFlow::Break(statement) => (statement, true),
397            };
398            body.push(statement);
399            if stop {
400                break;
401            }
402        }
403
404        let closing_brace = stream.expect_match(TokenKind::Symbol, &["}"])?;
405
406        Ok(Body {
407            opening_brace,
408            statements: body,
409            closing_brace,
410        })
411    }
412}
413
414impl TypeHint {
415    fn parse(stream: &mut TokenStream<'_, impl Tokenizer>) -> Result<Self, Error> {
416        let type_name = stream.expect_match(TokenKind::Identifier, &[])?;
417
418        Ok(TypeHint { type_name })
419    }
420}
421
422impl<T> Statement<T>
423where
424    T: TypeSet,
425{
426    fn matches(stream: &mut TokenStream<'_, impl Tokenizer>) -> Result<bool, Error> {
427        stream
428            .peek_match(TokenKind::Symbol, &["}"])
429            .map(|t| t.is_none())
430    }
431
432    fn parse(
433        stream: &mut TokenStream<'_, impl Tokenizer>,
434    ) -> Result<ControlFlow<Self, Self>, Error> {
435        if let Some(return_token) = stream.take_match(TokenKind::Identifier, &["return"])? {
436            let return_kind =
437                if let Some(semicolon) = stream.take_match(TokenKind::Symbol, &[";"])? {
438                    // Continue, parsing unreachable code is allowed
439                    Statement::EmptyReturn(EmptyReturn {
440                        return_token,
441                        semicolon,
442                    })
443                } else {
444                    let expr = RightHandExpression::parse(stream)?;
445                    let semicolon = stream.expect_match(TokenKind::Symbol, &[";"])?;
446                    Statement::Return(ReturnWithValue {
447                        return_token,
448                        expression: expr,
449                        semicolon,
450                    })
451                };
452
453            // Continue, parsing unreachable code is allowed
454            return Ok(ControlFlow::Continue(return_kind));
455        }
456
457        if let Some(decl_token) = stream.take_match(TokenKind::Identifier, &["var"])? {
458            let identifier = stream.expect_match(TokenKind::Identifier, &[])?;
459
460            let type_token = if stream.take_match(TokenKind::Symbol, &[":"])?.is_some() {
461                Some(TypeHint::parse(stream)?)
462            } else {
463                None
464            };
465
466            let equals_token = stream.expect_match(TokenKind::Symbol, &["="])?;
467            let expression = RightHandExpression::parse(stream)?;
468            let semicolon = stream.expect_match(TokenKind::Symbol, &[";"])?;
469
470            return Ok(ControlFlow::Continue(Statement::VariableDefinition(
471                VariableDefinition {
472                    decl_token,
473                    identifier,
474                    type_token,
475                    equals_token,
476                    initializer: expression,
477                    semicolon,
478                },
479            )));
480        }
481
482        if let Some(if_token) = stream.take_match(TokenKind::Identifier, &["if"])? {
483            let condition = RightHandExpression::parse_no_struct(stream)?;
484            let body = Body::parse(stream)?;
485
486            let else_branch =
487                if let Some(else_token) = stream.take_match(TokenKind::Identifier, &["else"])? {
488                    let else_body = Body::parse(stream)?;
489
490                    Some(Else {
491                        else_token,
492                        else_body,
493                    })
494                } else {
495                    None
496                };
497
498            return Ok(ControlFlow::Continue(Statement::If(If {
499                if_token,
500                condition,
501                body,
502                else_branch,
503            })));
504        }
505
506        if let Some(loop_token) = stream.take_match(TokenKind::Identifier, &["loop"])? {
507            let body = Body::parse(stream)?;
508            return Ok(ControlFlow::Continue(Statement::Loop(Loop {
509                loop_token,
510                body,
511            })));
512        }
513
514        if let Some(while_token) = stream.take_match(TokenKind::Identifier, &["while"])? {
515            // Desugar while into loop { if condition { loop_body; } else { break; } }
516            let condition = RightHandExpression::parse_no_struct(stream)?;
517            let body = Body::parse(stream)?;
518            return Ok(ControlFlow::Continue(Statement::Loop(Loop {
519                loop_token: while_token,
520                body: Body {
521                    opening_brace: body.opening_brace,
522                    closing_brace: body.closing_brace,
523                    statements: vec![Statement::If(If {
524                        if_token: while_token,
525                        condition: condition.clone(),
526                        body: body.clone(),
527                        else_branch: Some(Else {
528                            else_token: while_token,
529                            else_body: Body {
530                                opening_brace: body.opening_brace,
531                                closing_brace: body.closing_brace,
532                                statements: vec![Statement::Break(Break {
533                                    break_token: while_token,
534                                    semicolon: while_token,
535                                })],
536                            },
537                        }),
538                    })],
539                },
540            })));
541        }
542
543        if let Some(for_token) = stream.take_match(TokenKind::Identifier, &["for"])? {
544            let variable = stream.expect_match(TokenKind::Identifier, &[])?;
545            // The `: type` annotation is optional; when omitted the loop
546            // variable's type is inferred from its usage in the body.
547            let var_type = match stream.take_match(TokenKind::Symbol, &[":"])? {
548                Some(_) => Some(TypeHint::parse(stream)?),
549                None => None,
550            };
551            let in_token = stream.expect_match(TokenKind::Identifier, &["in"])?;
552            let iterable = RightHandExpression::parse_no_struct(stream)?;
553            let body = Body::parse(stream)?;
554
555            return Ok(ControlFlow::Continue(Statement::For(For {
556                for_token,
557                variable,
558                var_type,
559                in_token,
560                iterable,
561                body,
562            })));
563        }
564
565        if let Some(break_token) = stream.take_match(TokenKind::Identifier, &["break"])? {
566            let semicolon = stream.expect_match(TokenKind::Symbol, &[";"])?;
567            // Continue, unreachable code is allowed
568            return Ok(ControlFlow::Continue(Statement::Break(Break {
569                break_token,
570                semicolon,
571            })));
572        }
573        if let Some(continue_token) = stream.take_match(TokenKind::Identifier, &["continue"])? {
574            let semicolon = stream.expect_match(TokenKind::Symbol, &[";"])?;
575            // Continue, unreachable code is allowed
576            return Ok(ControlFlow::Continue(Statement::Continue(Continue {
577                continue_token,
578                semicolon,
579            })));
580        }
581
582        if let Ok(Some(_)) = stream.peek_match(TokenKind::Symbol, &["{"]) {
583            return Ok(ControlFlow::Continue(Statement::Scope(Body::parse(
584                stream,
585            )?)));
586        }
587
588        let save = stream.clone();
589        let expression = Expression::parse(stream)?;
590        match stream.take_match(TokenKind::Symbol, &[";"])? {
591            Some(semicolon) => Ok(ControlFlow::Continue(Statement::Expression {
592                expression,
593                semicolon,
594            })),
595            None => {
596                // No semicolon, re-parse as a right-hand expression
597                *stream = save;
598                let expression = RightHandExpression::parse(stream)?;
599
600                Ok(ControlFlow::Break(Statement::ImplicitReturn(expression)))
601            }
602        }
603    }
604}
605
606impl<T> Literal<T>
607where
608    T: TypeSet,
609{
610    fn parse(stream: &mut TokenStream<'_, impl Tokenizer>) -> Result<Self, Error> {
611        let token = stream.peek_expect()?;
612
613        let token_source = stream.source(token.location);
614        let location = token.location;
615
616        let literal_value = match token.kind {
617            TokenKind::BinaryInteger => {
618                let token_source = token_source.replace("_", "");
619                Self::parse_integer_literal(&token_source[2..], 2)
620                    .map_err(|_| stream.error("Invalid binary integer literal"))?
621            }
622            TokenKind::DecimalInteger => {
623                let token_source = token_source.replace("_", "");
624                Self::parse_integer_literal(&token_source, 10)
625                    .map_err(|_| stream.error("Invalid integer literal"))?
626            }
627            TokenKind::HexInteger => {
628                let token_source = token_source.replace("_", "");
629                Self::parse_integer_literal(&token_source[2..], 16)
630                    .map_err(|_| stream.error("Invalid hexadecimal integer literal"))?
631            }
632            TokenKind::Float => {
633                let token_source = token_source.replace("_", "");
634                <T::Float as FloatParser>::parse(&token_source)
635                    .map(LiteralValue::Float)
636                    .map_err(|_| stream.error("Invalid float literal"))?
637            }
638            TokenKind::String => match unescape(&token_source[1..token_source.len() - 1]) {
639                Ok(string) => LiteralValue::String(string),
640                Err(offset) => {
641                    return Err(Error {
642                        error: String::from("Invalid escape sequence in string literal")
643                            .into_boxed_str(),
644                        location: Location {
645                            start: token.location.start + offset,
646                            end: token.location.start + offset + 1,
647                        },
648                    });
649                }
650            },
651            TokenKind::Identifier if token_source == "true" => LiteralValue::Boolean(true),
652            TokenKind::Identifier if token_source == "false" => LiteralValue::Boolean(false),
653            _ => return Err(stream.error("Expected literal (number, string, or boolean)")),
654        };
655
656        stream.expect_match(token.kind, &[])?;
657        Ok(Self {
658            value: literal_value,
659            location,
660        })
661    }
662
663    fn parse_integer_literal(
664        token_source: &str,
665        radix: u32,
666    ) -> Result<LiteralValue<T>, ParseIntError> {
667        <T::Integer as IntParser>::parse(token_source, radix).map(LiteralValue::Integer)
668    }
669}
670
671fn unescape(s: &str) -> Result<String, usize> {
672    let mut result = String::new();
673    let mut escaped = false;
674    for (i, c) in s.char_indices().peekable() {
675        if escaped {
676            match c {
677                'n' => result.push('\n'),
678                't' => result.push('\t'),
679                '\\' => result.push('\\'),
680                '"' => result.push('"'),
681                '\'' => result.push('\''),
682                _ => return Err(i), // Invalid escape sequence
683            }
684            escaped = false;
685        } else if c == '\\' {
686            escaped = true;
687        } else {
688            result.push(c);
689        }
690    }
691
692    Ok(result)
693}
694
695impl LeftHandExpression {
696    fn parse<T: TypeSet>(stream: &mut TokenStream<'_, impl Tokenizer>) -> Result<Self, Error> {
697        const UNARY_OPERATORS: &[&str] = &["*"];
698        if let Some(operator) = stream.take_match(TokenKind::Symbol, UNARY_OPERATORS)? {
699            // `*name` — a whole-value dereference target. Field paths through a
700            // dereference are not valid lvalues (reference fields are unsupported).
701            return Ok(Self::Deref {
702                operator,
703                name: Self::parse_name::<T>(stream)?,
704            });
705        }
706
707        // A place path: `name` followed by zero or more `.field` accesses.
708        let mut expr = Self::Name {
709            variable: Self::parse_name::<T>(stream)?,
710        };
711        while let Some(dot) = stream.take_match(TokenKind::Symbol, &["."])? {
712            let field = stream.expect_match(TokenKind::Identifier, &[])?;
713            expr = Self::Field {
714                base: Box::new(expr),
715                dot,
716                field,
717            };
718        }
719
720        Ok(expr)
721    }
722
723    fn parse_name<T: TypeSet>(
724        stream: &mut TokenStream<'_, impl Tokenizer>,
725    ) -> Result<Token, Error> {
726        let token = stream.peek_expect()?;
727        match token.kind {
728            TokenKind::Identifier => {
729                // true, false?
730                match Literal::<T>::parse(stream) {
731                    Ok(_) => Err(Error {
732                        error: "Parse error: Literals are not valid on the left-hand side"
733                            .to_string()
734                            .into_boxed_str(),
735                        location: token.location,
736                    }),
737                    _ => stream
738                        .take_match(TokenKind::Identifier, &[])
739                        .map(|v| v.unwrap()),
740                }
741            }
742            _ => Err(stream.error("Expected variable name or deref operator")),
743        }
744    }
745}
746
747impl<T> Expression<T>
748where
749    T: TypeSet,
750{
751    fn parse(stream: &mut TokenStream<'_, impl Tokenizer>) -> Result<Self, Error> {
752        let save = stream.clone();
753
754        let expression = RightHandExpression::<T>::parse(stream)?;
755
756        if let Ok(Some(operator)) = stream.take_match(TokenKind::Symbol, &["="]) {
757            // Re-parse as an assignment
758            *stream = save;
759            let left_expr = LeftHandExpression::parse::<T>(stream)?;
760            stream.expect_match(TokenKind::Symbol, &["="])?;
761            let right_expr = RightHandExpression::parse(stream)?;
762
763            Ok(Self::Assignment {
764                left_expr,
765                operator,
766                right_expr,
767            })
768        } else {
769            Ok(Self::Expression { expression })
770        }
771    }
772}
773
774impl<T> RightHandExpression<T>
775where
776    T: TypeSet,
777{
778    fn parse(stream: &mut TokenStream<'_, impl Tokenizer>) -> Result<Self, Error> {
779        Self::parse_inner(stream, true)
780    }
781
782    /// Parses a right-hand expression that does not permit a *top-level* struct
783    /// literal. Used for control-flow conditions and iterables, where a bare
784    /// `Name { ... }` would be ambiguous with the following block. Struct literals
785    /// remain reachable within parentheses.
786    fn parse_no_struct(stream: &mut TokenStream<'_, impl Tokenizer>) -> Result<Self, Error> {
787        Self::parse_inner(stream, false)
788    }
789
790    fn parse_inner(
791        stream: &mut TokenStream<'_, impl Tokenizer>,
792        allow_struct: bool,
793    ) -> Result<Self, Error> {
794        // We define the binary operators from the lowest precedence to the highest.
795        // Each recursive call to `parse_binary` will handle one level of precedence, and pass
796        // the rest to the inner calls of `parse_binary`.
797        let operators: &[&[&str]] = &[
798            &["||"],
799            &["&&"],
800            &["<", "<=", ">", ">=", "==", "!="],
801            &["|"],
802            &["^"],
803            &["&"],
804            &["<<", ">>"],
805            &["+", "-"],
806            &["*", "/", "%"],
807        ];
808
809        Self::parse_binary(stream, operators, allow_struct)
810    }
811
812    fn parse_binary(
813        stream: &mut TokenStream<'_, impl Tokenizer>,
814        binary_operators: &[&[&str]],
815        allow_struct: bool,
816    ) -> Result<Self, Error> {
817        let Some((current, higher)) = binary_operators.split_first() else {
818            unreachable!("At least one operator set is expected");
819        };
820
821        let mut expr = if higher.is_empty() {
822            Self::parse_unary(stream, allow_struct)?
823        } else {
824            Self::parse_binary(stream, higher, allow_struct)?
825        };
826
827        while let Some(operator) = stream.take_match(TokenKind::Symbol, current)? {
828            let rhs = if higher.is_empty() {
829                Self::parse_unary(stream, allow_struct)?
830            } else {
831                Self::parse_binary(stream, higher, allow_struct)?
832            };
833
834            expr = Self::BinaryOperator {
835                name: operator,
836                operands: Box::new([expr, rhs]),
837            };
838        }
839
840        Ok(expr)
841    }
842
843    fn parse_unary(
844        stream: &mut TokenStream<'_, impl Tokenizer>,
845        allow_struct: bool,
846    ) -> Result<Self, Error> {
847        const UNARY_OPERATORS: &[&str] = &["!", "-", "&", "*"];
848        if let Some(operator) = stream.take_match(TokenKind::Symbol, UNARY_OPERATORS)? {
849            let operand = Self::parse_unary(stream, allow_struct)?;
850            Ok(Self::UnaryOperator {
851                name: operator,
852                operand: Box::new(operand),
853            })
854        } else {
855            Self::parse_postfix(stream, allow_struct)
856        }
857    }
858
859    /// Parses a primary followed by zero or more `.field` accesses. Field access
860    /// is a postfix operator binding tighter than any unary prefix.
861    fn parse_postfix(
862        stream: &mut TokenStream<'_, impl Tokenizer>,
863        allow_struct: bool,
864    ) -> Result<Self, Error> {
865        let mut expr = Self::parse_primary(stream, allow_struct)?;
866
867        while let Some(dot) = stream.take_match(TokenKind::Symbol, &["."])? {
868            let field = stream.expect_match(TokenKind::Identifier, &[])?;
869            expr = Self::FieldAccess {
870                base: Box::new(expr),
871                dot,
872                field,
873            };
874        }
875
876        Ok(expr)
877    }
878
879    fn parse_primary(
880        stream: &mut TokenStream<'_, impl Tokenizer>,
881        allow_struct: bool,
882    ) -> Result<Self, Error> {
883        let token = stream.peek_expect()?;
884
885        match token.kind {
886            TokenKind::Identifier => {
887                // true, false?
888                if let Ok(literal) = Literal::<T>::parse(stream) {
889                    return Ok(Self::Literal { value: literal });
890                }
891
892                // A struct literal `Name { ... }` — only when permitted in this
893                // position, and only when an identifier is directly followed by `{`.
894                if allow_struct {
895                    let name = stream.expect_match(TokenKind::Identifier, &[])?;
896                    if stream.peek_match(TokenKind::Symbol, &["{"])?.is_some() {
897                        return Self::parse_struct_literal(stream, name);
898                    }
899                    return Self::parse_call_tail(stream, name);
900                }
901
902                Self::parse_call(stream)
903            }
904            TokenKind::Symbol if stream.source(token.location) == "(" => {
905                stream.take_match(token.kind, &[])?;
906                // Inside parentheses, struct literals are always allowed again.
907                let expr = Self::parse(stream)?;
908                stream.expect_match(TokenKind::Symbol, &[")"])?;
909                Ok(expr)
910            }
911            TokenKind::HexInteger
912            | TokenKind::DecimalInteger
913            | TokenKind::BinaryInteger
914            | TokenKind::Float
915            | TokenKind::String => Literal::<T>::parse(stream).map(|value| Self::Literal { value }),
916            _ => Err(stream.error("Expected variable, literal, or '('")),
917        }
918    }
919
920    fn parse_struct_literal(
921        stream: &mut TokenStream<'_, impl Tokenizer>,
922        name: Token,
923    ) -> Result<Self, Error> {
924        let opening_brace = stream.expect_match(TokenKind::Symbol, &["{"])?;
925
926        let mut fields = Vec::new();
927        while let Some(field_name) = stream.take_match(TokenKind::Identifier, &[])? {
928            let colon = stream.expect_match(TokenKind::Symbol, &[":"])?;
929            // Field values are full expressions; struct literals are allowed here.
930            let value = Self::parse(stream)?;
931
932            fields.push(StructLiteralField {
933                name: field_name,
934                colon,
935                value,
936            });
937
938            if stream.take_match(TokenKind::Symbol, &[","])?.is_none() {
939                break;
940            }
941        }
942
943        let closing_brace = stream.expect_match(TokenKind::Symbol, &["}"])?;
944
945        Ok(Self::StructLiteral {
946            name,
947            opening_brace,
948            fields,
949            closing_brace,
950        })
951    }
952
953    fn parse_call(stream: &mut TokenStream<'_, impl Tokenizer>) -> Result<Self, Error> {
954        let token = stream.expect_match(TokenKind::Identifier, &[])?;
955        Self::parse_call_tail(stream, token)
956    }
957
958    /// Parses the tail of a call/variable reference after the leading identifier
959    /// has already been consumed.
960    fn parse_call_tail(
961        stream: &mut TokenStream<'_, impl Tokenizer>,
962        token: Token,
963    ) -> Result<Self, Error> {
964        if stream.take_match(TokenKind::Symbol, &["("])?.is_none() {
965            return Ok(Self::Variable { variable: token });
966        };
967
968        let mut arguments = Vec::new();
969        while stream.peek_match(TokenKind::Symbol, &[")"])?.is_none() {
970            let arg = Self::parse(stream)?;
971            arguments.push(arg);
972
973            if stream.take_match(TokenKind::Symbol, &[","])?.is_none() {
974                break;
975            }
976        }
977        stream.expect_match(TokenKind::Symbol, &[")"])?;
978
979        Ok(Self::FunctionCall {
980            name: token,
981            arguments: arguments.into_boxed_slice(),
982        })
983    }
984}
985
986#[derive(Clone)]
987struct TokenStream<'s, I>
988where
989    I: Tokenizer,
990{
991    source: &'s str,
992    tokens: I,
993}
994
995impl<'s, I> TokenStream<'s, I>
996where
997    I: Tokenizer,
998{
999    fn new(source: &'s str, tokens: I) -> Self {
1000        TokenStream { source, tokens }
1001    }
1002
1003    /// Fast-forwards the token iterator past comments.
1004    fn skip_comments(&mut self) -> Result<(), Error> {
1005        let mut peekable = self.tokens.clone();
1006        while let Some(token) = peekable.next() {
1007            if token?.kind == TokenKind::Comment {
1008                self.tokens = peekable.clone();
1009            } else {
1010                break;
1011            }
1012        }
1013
1014        Ok(())
1015    }
1016
1017    fn end(&mut self) -> Result<bool, Error> {
1018        self.skip_comments()?;
1019
1020        Ok(self.tokens.clone().next().is_none())
1021    }
1022
1023    fn peek(&mut self) -> Result<Option<Token>, Error> {
1024        self.skip_comments()?;
1025
1026        match self.tokens.clone().next() {
1027            Some(Ok(token)) => Ok(Some(token)),
1028            Some(Err(error)) => Err(error),
1029            None => Ok(None),
1030        }
1031    }
1032
1033    fn peek_expect(&mut self) -> Result<Token, Error> {
1034        self.peek()?.ok_or_else(|| Error {
1035            location: Location {
1036                start: self.source.len(),
1037                end: self.source.len(),
1038            },
1039            error: String::from("Unexpected end of input").into_boxed_str(),
1040        })
1041    }
1042
1043    fn peek_match(
1044        &mut self,
1045        token_kind: TokenKind,
1046        source: &[&str],
1047    ) -> Result<Option<Token>, Error> {
1048        let Some(token) = self.peek()? else {
1049            return Ok(None);
1050        };
1051
1052        let peeked = if token.kind == token_kind
1053            && (source.is_empty() || source.contains(&self.source(token.location)))
1054        {
1055            Some(token)
1056        } else {
1057            None
1058        };
1059
1060        Ok(peeked)
1061    }
1062
1063    fn take_match(
1064        &mut self,
1065        token_kind: TokenKind,
1066        source: &[&str],
1067    ) -> Result<Option<Token>, Error> {
1068        self.peek_match(token_kind, source).map(|token| {
1069            if let Some(token) = token {
1070                self.tokens.next();
1071                Some(token)
1072            } else {
1073                None
1074            }
1075        })
1076    }
1077
1078    /// Takes the next token if it matches the expected kind and source.
1079    /// Returns an error if the token does not match.
1080    ///
1081    /// If `source` is empty, it only checks the token kind.
1082    /// If `source` is not empty, it checks if the token's source matches any of the provided strings.
1083    fn expect_match(&mut self, token_kind: TokenKind, source: &[&str]) -> Result<Token, Error> {
1084        if let Some(token) = self.take_match(token_kind, source)? {
1085            Ok(token)
1086        } else {
1087            let token = self.peek()?;
1088            let found = if let Some(token) = token {
1089                if token.kind == token_kind {
1090                    format!("found '{}'", self.source(token.location))
1091                } else {
1092                    format!("found {:?}", token.kind)
1093                }
1094            } else {
1095                "reached end of input".to_string()
1096            };
1097            match source {
1098                [] => Err(self.error(format_args!("Expected {token_kind:?}, {found}"))),
1099                [s] => Err(self.error(format_args!("Expected '{s}', {found}"))),
1100                _ => Err(self.error(format_args!("Expected one of {source:?}, {found}"))),
1101            }
1102        }
1103    }
1104
1105    fn error(&self, message: impl Display) -> Error {
1106        Error {
1107            error: format!("Parse error: {message}").into_boxed_str(),
1108            location: if let Some(Ok(token)) = self.tokens.clone().next() {
1109                token.location
1110            } else {
1111                Location {
1112                    start: self.source.len(),
1113                    end: self.source.len(),
1114                }
1115            },
1116        }
1117    }
1118
1119    fn source(&self, location: Location) -> &'s str {
1120        location.extract(self.source)
1121    }
1122}
1123
1124pub fn parse<T>(source: &str) -> Result<Program<T>, Error>
1125where
1126    T: TypeSet,
1127{
1128    let tokens = crate::lexer::tokenize(source);
1129    let mut stream = TokenStream::new(source, tokens);
1130
1131    Program::<T>::parse(&mut stream)
1132}
1133
1134pub fn parse_expression<T>(source: &str) -> Result<Expression<T>, Error>
1135where
1136    T: TypeSet,
1137{
1138    let tokens = crate::lexer::tokenize(source);
1139    let mut stream = TokenStream::new(source, tokens);
1140
1141    Expression::<T>::parse(&mut stream)
1142}
1143
1144#[cfg(test)]
1145mod tests {
1146    use super::*;
1147
1148    #[test]
1149    fn test_unescape() {
1150        assert_eq!(unescape(r#"Hello\nWorld\t!"#).unwrap(), "Hello\nWorld\t!");
1151        assert_eq!(unescape(r#"Hello\\World"#).unwrap(), "Hello\\World");
1152        assert_eq!(unescape(r#"Hello\zWorld"#), Err(6)); // Invalid escape sequence
1153    }
1154
1155    fn parse_ok(source: &str) {
1156        parse::<DefaultTypeSet>(source)
1157            .unwrap_or_else(|e| panic!("expected `{source}` to parse, got: {e}"));
1158    }
1159
1160    fn parse_err(source: &str) {
1161        assert!(
1162            parse::<DefaultTypeSet>(source).is_err(),
1163            "expected `{source}` to fail parsing"
1164        );
1165    }
1166
1167    #[test]
1168    fn test_parse_struct_definition() {
1169        parse_ok("struct Point { x: int, y: int }");
1170        parse_ok("struct Point { x: int, y: int, }"); // trailing comma
1171        parse_ok("struct Empty {}");
1172        parse_ok("struct Line { start: Point, end: Point }"); // nested struct field
1173    }
1174
1175    #[test]
1176    fn test_parse_field_access_and_struct_literal() {
1177        parse_ok("fn f() -> int { var p = Point { x: 1, y: 2 }; return p.x; }");
1178        parse_ok("fn f() -> int { return foo.x.y; }"); // chained
1179        parse_ok("fn f() -> int { return get().x; }"); // on a call result
1180        parse_ok("fn f() -> int { return &p.x; }"); // & binds looser than .
1181    }
1182
1183    #[test]
1184    fn test_parse_field_assignment() {
1185        parse_ok("fn f() { p.x = 1; }");
1186        parse_ok("fn f() { p.x.y = 1; }"); // nested write
1187    }
1188
1189    #[test]
1190    fn test_struct_literal_forbidden_in_condition() {
1191        // A bare struct literal in an `if` condition would be ambiguous with the block.
1192        parse_err("fn f() { if Point { x: 1 } { return; } }");
1193        // Parenthesizing makes it explicit and legal.
1194        parse_ok("fn f() { if (Point { x: 1 }) == p { return; } }");
1195    }
1196
1197    #[test]
1198    fn test_out_of_range_literal() {
1199        let source = "0x100000000";
1200
1201        let result = parse_expression::<TypeSet32>(source).expect_err("Parsing should fail");
1202        assert_eq!(
1203            "Parse error: Invalid hexadecimal integer literal",
1204            result.error.as_ref()
1205        );
1206    }
1207
1208    #[test]
1209    fn test_grouped_numeric_literal() {
1210        let source = "1_000_000";
1211
1212        let result = parse_expression::<TypeSet32>(source).unwrap();
1213
1214        assert_eq!(source, result.location().extract(source));
1215    }
1216
1217    #[test]
1218    fn test_parse_strings() {
1219        type LitVal = LiteralValue<TypeSet32>;
1220
1221        let test_data = [
1222            (r#""hel_lo""#, Ok(LitVal::String(r#"hel_lo"#.to_string()))),
1223            ("1_000", Ok(LitVal::Integer(1000))),
1224            ("true", Ok(LitVal::Boolean(true))),
1225            ("false", Ok(LitVal::Boolean(false))),
1226            (
1227                "fal_se",
1228                Err("Parse error: Expected literal (number, string, or boolean)"),
1229            ),
1230        ];
1231
1232        for (source, expected) in test_data {
1233            let tokens = crate::lexer::tokenize(source);
1234            let mut stream = TokenStream::new(source, tokens);
1235
1236            let lit = match Literal::<TypeSet32>::parse(&mut stream) {
1237                Ok(lit) => lit,
1238                Err(err) => {
1239                    let Err(expected_err) = expected else {
1240                        panic!(
1241                            "Expected parsing to succeed, but it failed with error: {}",
1242                            err
1243                        );
1244                    };
1245                    assert_eq!(expected_err, err.to_string());
1246                    continue;
1247                }
1248            };
1249
1250            let Ok(expected) = expected else {
1251                panic!("Expected error, but `{source}` was parsed successfully");
1252            };
1253
1254            match (lit.value, expected) {
1255                (LitVal::Integer(a), LitVal::Integer(b)) => assert_eq!(a, b),
1256                (LitVal::Float(a), LitVal::Float(b)) => assert_eq!(a, b),
1257                (LitVal::String(a), LitVal::String(b)) => assert_eq!(a, b),
1258                (LitVal::Boolean(a), LitVal::Boolean(b)) => assert_eq!(a, b),
1259                _ => panic!("Unexpected literal type"),
1260            }
1261        }
1262    }
1263}