bril_frontend/
parser.rs

1// Copyright (C) 2024 Ethan Uppal.
2//
3// This Source Code Form is subject to the terms of the Mozilla Public License,
4// v. 2.0. If a copy of the MPL was not distributed with this file, You can
5// obtain one at https://mozilla.org/MPL/2.0/.
6
7use crate::{
8    ast,
9    lexer::{Token, TokenPattern, KEYWORD_LIKE},
10    loc::{Loc, Span, Spanned, WithLocation},
11};
12
13#[derive(Debug)]
14pub struct Diagnostic {
15    pub message: String,
16    pub span: Span,
17    pub labels: Vec<(String, Option<Span>)>,
18}
19
20impl Diagnostic {
21    pub fn new(message: impl Into<String>, spanned: impl Spanned) -> Self {
22        Self {
23            message: message.into(),
24            span: spanned.span(),
25            labels: vec![],
26        }
27    }
28
29    pub fn label(mut self, text: impl Into<String>, spanned: impl Spanned) -> Self {
30        self.labels.push((text.into(), Some(spanned.span())));
31        self
32    }
33
34    pub fn explain(mut self, text: impl Into<String>) -> Self {
35        self.labels.push((text.into(), None));
36        self
37    }
38}
39
40pub struct Parser<'tokens, 'source: 'tokens> {
41    index: usize,
42    tokens: &'tokens [Loc<Token<'source>>],
43    diagnostics: Vec<Diagnostic>,
44}
45
46pub struct ParserFailedMarker;
47
48pub type Result<T> = std::result::Result<T, ParserFailedMarker>;
49
50macro_rules! try_op {
51    (@parse_argument; $self:ident; Token::Identifier) => {
52        $self.parse_local_name("Expected variable name for argument")?
53    };
54    (@parse_argument; $self:ident; Token::Label) => {
55        {
56            let label = $self.eat(Token::Label(""), "Expected label for argument")?.map(Token::assume_label);
57            let span = label.span();
58            $crate::ast::Label { name: label }.at(span)
59        }
60    };
61    (@parse_argument; $self:ident; Token::FunctionName) => {
62        $self.eat(Token::FunctionName(""), "Expected function name for argument")?.map(Token::assume_function_name)
63    };
64    (@parse_argument; $self:ident; Vec::from) => {
65        {
66            let mut arguments = vec![];
67            while !$self.is_eof() && !$self.is_at(&Token::Semi) {
68                arguments.push($self.parse_local_name("Only variable names are valid variadic arguments")?)
69            }
70            arguments
71        }
72    };
73    (@parse_argument; $self:ident; Option::from) => {
74        {
75            if !$self.is_eof() && !$self.is_at(&Token::Semi) {
76                Some($self.parse_local_name("Only variable names are valid optional arguments")?)
77            } else {
78                None
79            }
80        }
81    };
82    (
83        $self:ident;
84        $op_name:ident:$name:literal =>
85        $enum:ident::$variant:ident$(($($argument_name:ident as $scope:ident::$token:ident),*))?
86    ) => {
87        if $op_name.inner == $name {
88            #[allow(unused_assignments)]
89            #[allow(unused_mut)]
90            let mut end = $op_name.span();
91            $($(
92                let $argument_name = try_op!(@parse_argument; $self; $scope::$token);
93                if let Some(span) = $crate::loc::MaybeSpanned::try_span(&$argument_name) {
94                    end = span;
95                }
96            )*)*
97            let op = $crate::ast::$enum::$variant $(($($argument_name),*))*;
98            return Ok(op.between($op_name, end));
99        }
100    };
101}
102
103#[allow(clippy::result_unit_err)]
104impl<'tokens, 'source: 'tokens> Parser<'tokens, 'source> {
105    pub fn new(tokens: &'tokens [Loc<Token<'source>>]) -> Self {
106        Self {
107            index: 0,
108            tokens,
109            diagnostics: vec![],
110        }
111    }
112
113    pub fn diagnostics(&self) -> &[Diagnostic] {
114        &self.diagnostics
115    }
116
117    pub fn is_eof(&self) -> bool {
118        self.index == self.tokens.len()
119    }
120
121    pub fn eof_span(&self) -> Span {
122        self.tokens
123            .last()
124            .map(|last| last.span.end..last.span.end)
125            .unwrap_or(0..0)
126    }
127
128    pub fn get(&self, offset: isize) -> Option<&Loc<Token<'source>>> {
129        let get_index = ((self.index as isize) + offset) as usize;
130        if !(offset < 0 && (-offset) as usize > self.index) && get_index < self.tokens.len() {
131            Some(&self.tokens[get_index])
132        } else {
133            None
134        }
135    }
136
137    pub fn is_at(&self, pattern: &Token) -> bool {
138        self.get(0)
139            .filter(|token| token.matches_against(pattern.clone()))
140            .is_some()
141    }
142
143    pub fn next_is(&self, pattern: &Token) -> bool {
144        self.get(1)
145            .filter(|token| token.matches_against(pattern.clone()))
146            .is_some()
147    }
148
149    pub fn advance(&mut self) {
150        self.index += 1;
151    }
152
153    pub fn try_eat(&mut self, pattern: Token) -> Option<Loc<Token<'source>>> {
154        if self.is_at(&pattern) {
155            let result = self.get(0).expect("is_at is true so we're not EOF").clone();
156            self.advance();
157            Some(result)
158        } else {
159            None
160        }
161    }
162
163    pub fn eat<'a>(
164        &mut self,
165        pattern: impl TokenPattern<'a>,
166        message: impl Into<String>,
167    ) -> Result<Loc<Token<'source>>> {
168        let matches = pattern.matches().collect::<Vec<_>>();
169        if matches.iter().any(|token| self.is_at(token)) {
170            let result = self.get(0).expect("is_at is true so we're not EOF").clone();
171            self.advance();
172            Ok(result)
173        } else {
174            if let Some(current) = self.tokens.get(self.index) {
175                self.diagnostics.push(
176                    Diagnostic::new(
177                        format!(
178                            "Unexpected '{}', expected {}",
179                            current.pattern_name(),
180                            matches
181                                .into_iter()
182                                .map(|token| format!("'{}'", token.pattern_name()))
183                                .collect::<Vec<_>>()
184                                .join(", ")
185                        ),
186                        current,
187                    )
188                    .explain(message),
189                );
190            } else {
191                self.diagnostics.push(
192                    Diagnostic::new(
193                        format!(
194                            "Unexpected EOF, expected {}",
195                            matches
196                                .into_iter()
197                                .map(|token| format!("'{}'", token.pattern_name()))
198                                .collect::<Vec<_>>()
199                                .join(", ")
200                        ),
201                        self.eof_span(),
202                    )
203                    .explain(message),
204                );
205            }
206
207            Err(ParserFailedMarker)
208        }
209    }
210
211    pub fn skip_newlines(&mut self) {
212        while self.is_at(&Token::Newline) {
213            self.advance();
214        }
215    }
216
217    pub fn recover(
218        &mut self,
219        goals: impl IntoIterator<Item = Token<'source>>,
220        message: impl Into<String>,
221    ) {
222        assert!(
223            !self.diagnostics.is_empty(),
224            "INTERNAL BUG: Cannot recover without first reporting an error in self.diagnostics"
225        );
226
227        let current = self
228            .get(0)
229            .map(|token| token.span())
230            .unwrap_or(self.eof_span());
231        let mut goals = goals.into_iter();
232        while !self.is_eof() {
233            if goals.any(|goal| self.is_at(&goal)) {
234                return;
235            }
236            self.index += 1;
237        }
238
239        self.diagnostics
240            .push(Diagnostic::new(message, current).explain("Recovery started here"));
241    }
242
243    pub fn parse_separated<'a, U, F: FnMut(&mut Self) -> Result<U>>(
244        &mut self,
245        mut f: F,
246        separators: impl TokenPattern<'a>,
247        terminators: impl TokenPattern<'a>,
248        message: impl Into<String>,
249    ) -> Result<(Vec<U>, Loc<Token<'source>>)> {
250        let separators = separators.matches().collect::<Vec<_>>();
251        let terminators = terminators.matches().collect::<Vec<_>>();
252
253        let mut result = vec![];
254
255        while !self.is_eof() {
256            for terminator in &terminators {
257                if let Some(terminator) = self.try_eat(terminator.clone()) {
258                    return Ok((result, terminator));
259                }
260            }
261
262            if self.is_eof() {
263                break;
264            }
265
266            if !result.is_empty() {
267                if separators
268                    .iter()
269                    .cloned()
270                    .any(|separator| self.is_at(&separator))
271                {
272                    self.advance();
273                } else {
274                    self.diagnostics.push(
275                        Diagnostic::new(
276                            format!(
277                                "Unexpected EOF, expected separator (one of: {})",
278                                separators
279                                    .iter()
280                                    .map(|separator| format!("'{}'", separator.pattern_name()))
281                                    .collect::<Vec<_>>()
282                                    .join(", "),
283                            ),
284                            self.eof_span(),
285                        )
286                        .explain(message),
287                    );
288                    return Err(ParserFailedMarker);
289                }
290            }
291
292            result.push(f(self)?);
293        }
294
295        self.diagnostics.push(
296            Diagnostic::new(
297                format!(
298                    "Unexpected EOF, expected terminator (one of: {})",
299                    terminators
300                        .into_iter()
301                        .map(|terminator| format!("'{}'", terminator.pattern_name()))
302                        .collect::<Vec<_>>()
303                        .join(", "),
304                ),
305                self.eof_span(),
306            )
307            .explain(message),
308        );
309        Err(ParserFailedMarker)
310    }
311
312    pub fn parse_local_name(&mut self, message: impl Into<String>) -> Result<Loc<&'source str>> {
313        Ok(self
314            .eat(KEYWORD_LIKE, message)?
315            .map(Token::assume_identifier_like))
316    }
317
318    pub fn parse_imported_function_alias(
319        &mut self,
320        as_token: Loc<()>,
321    ) -> Result<Loc<ast::ImportedFunctionAlias<'source>>> {
322        let name = self
323            .eat(
324                Token::FunctionName(""),
325                "Expected function alias name after `as`",
326            )?
327            .map(Token::assume_function_name);
328
329        Ok(ast::ImportedFunctionAlias {
330            as_token: as_token.clone(),
331            name: name.clone(),
332        }
333        .between(as_token, name))
334    }
335
336    pub fn parse_imported_function(&mut self) -> Result<Loc<ast::ImportedFunction<'source>>> {
337        let name = self
338            .eat(Token::FunctionName(""), "Expected function name to import")?
339            .map(Token::assume_function_name);
340
341        let mut alias = None;
342        if let Some(as_token) = self.try_eat(Token::As) {
343            alias = Some(self.parse_imported_function_alias(as_token.without_inner())?);
344        }
345
346        let start = name.span();
347        let end = alias
348            .as_ref()
349            .map(|alias| alias.span())
350            .unwrap_or(name.span());
351        Ok(ast::ImportedFunction { name, alias }.between(start, end))
352    }
353
354    pub fn parse_import(&mut self, from_token: Loc<()>) -> Result<Loc<ast::Import<'source>>> {
355        let path = self
356            .eat(Token::Path(""), "Expected path after `from`")?
357            .map(Token::assume_path);
358
359        let import_token = self
360            .eat(Token::Import, "Expected `import` token after path")?
361            .without_inner();
362
363        let (imported_functions, terminator) = self.parse_separated(
364            Self::parse_imported_function,
365            Token::Comma,
366            Token::Semi,
367            "Failed to parse imported function",
368        )?;
369
370        let _ = self.eat(Token::Newline, "Expected newline after import")?;
371
372        Ok(ast::Import {
373            from_token: from_token.clone(),
374            path,
375            import_token,
376            imported_functions,
377        }
378        .between(&from_token, &terminator))
379    }
380
381    pub fn parse_label(&mut self) -> Result<Loc<ast::Label<'source>>> {
382        let name = self
383            .eat(Token::Label(""), "Expected label")?
384            .map(Token::assume_label);
385        let span = name.span();
386        Ok(ast::Label { name }.at(span))
387    }
388
389    pub fn parse_constant_value(&mut self) -> Result<Loc<ast::ConstantValue>> {
390        if let Some(integer) = self.try_eat(Token::Integer(0)) {
391            let span = integer.span();
392            Ok(ast::ConstantValue::IntegerLiteral(integer.map(Token::assume_integer)).at(span))
393        } else if let Some(float) = self.try_eat(Token::Float(0.0)) {
394            let span = float.span();
395            Ok(ast::ConstantValue::FloatLiteral(float.map(Token::assume_float)).at(span))
396        } else if let Some(character) = self.try_eat(Token::Character(' ')) {
397            let span = character.span();
398            Ok(
399                ast::ConstantValue::CharacterLiteral(character.map(Token::assume_character))
400                    .at(span),
401            )
402        } else if let Some(true_literal) = self.try_eat(Token::True) {
403            let span = true_literal.span();
404            Ok(ast::ConstantValue::BooleanLiteral(true.at(&span)).at(span))
405        } else if let Some(false_literal) = self.try_eat(Token::False) {
406            let span = false_literal.span();
407            Ok(ast::ConstantValue::BooleanLiteral(false.at(&span)).at(span))
408        } else {
409            self.diagnostics.push(
410                Diagnostic::new(
411                    "Unknown constant value: expected integer, float, or character",
412                    self.get(0)
413                        .map(|token| token.span())
414                        .unwrap_or(self.eof_span()),
415                )
416                .explain("This is not a valid constant value"),
417            );
418            Err(ParserFailedMarker)
419        }
420    }
421
422    pub fn parse_constant(
423        &mut self,
424        name: Loc<&'source str>,
425        type_annotation: Option<Loc<ast::TypeAnnotation>>,
426        equals_token: Loc<()>,
427        const_token: Loc<()>,
428    ) -> Result<Loc<ast::Constant<'source>>> {
429        let value = self.parse_constant_value()?;
430        let semi_token = self
431            .eat(
432                Token::Semi,
433                "Expected semicolon at end of constant instruction",
434            )?
435            .without_inner();
436        let start = name.span();
437        let end = semi_token.span();
438        Ok(ast::Constant {
439            name,
440            type_annotation,
441            equals_token,
442            const_token,
443            value,
444            semi_token,
445        }
446        .between(start, end))
447    }
448
449    pub fn parse_value_operation_op(
450        &mut self,
451        op_name: Loc<&'source str>,
452    ) -> Result<Loc<ast::ValueOperationOp<'source>>> {
453        try_op!(self; op_name: "add" => ValueOperationOp::Add(lhs as Token::Identifier, rhs as Token::Identifier));
454        try_op!(self; op_name: "mul" => ValueOperationOp::Mul(lhs as Token::Identifier, rhs as Token::Identifier));
455        try_op!(self; op_name: "sub" => ValueOperationOp::Sub(lhs as Token::Identifier, rhs as Token::Identifier));
456        try_op!(self; op_name: "div" => ValueOperationOp::Div(lhs as Token::Identifier, rhs as Token::Identifier));
457        try_op!(self; op_name: "eq" => ValueOperationOp::Eq(lhs as Token::Identifier, rhs as Token::Identifier));
458        try_op!(self; op_name: "lt" => ValueOperationOp::Lt(lhs as Token::Identifier, rhs as Token::Identifier));
459        try_op!(self; op_name: "gt" => ValueOperationOp::Gt(lhs as Token::Identifier, rhs as Token::Identifier));
460        try_op!(self; op_name: "le" => ValueOperationOp::Le(lhs as Token::Identifier, rhs as Token::Identifier));
461        try_op!(self; op_name: "ge" => ValueOperationOp::Ge(lhs as Token::Identifier, rhs as Token::Identifier));
462        try_op!(self; op_name: "not" => ValueOperationOp::Not(value as Token::Identifier));
463        try_op!(self; op_name: "and" => ValueOperationOp::And(lhs as Token::Identifier, rhs as Token::Identifier));
464        try_op!(self; op_name: "or" => ValueOperationOp::Or(lhs as Token::Identifier, rhs as Token::Identifier));
465        try_op!(self; op_name: "call" => ValueOperationOp::Call(destination as Token::FunctionName, arguments as Vec::from));
466        try_op!(self; op_name: "id" => ValueOperationOp::Id(value as Token::Identifier));
467
468        try_op!(self; op_name: "fadd" => ValueOperationOp::Fadd(lhs as Token::Identifier, rhs as Token::Identifier));
469        try_op!(self; op_name: "fmul" => ValueOperationOp::Fmul(lhs as Token::Identifier, rhs as Token::Identifier));
470        try_op!(self; op_name: "fsub" => ValueOperationOp::Fsub(lhs as Token::Identifier, rhs as Token::Identifier));
471        try_op!(self; op_name: "fdiv" => ValueOperationOp::Fdiv(lhs as Token::Identifier, rhs as Token::Identifier));
472        try_op!(self; op_name: "feq" => ValueOperationOp::Feq(lhs as Token::Identifier, rhs as Token::Identifier));
473        try_op!(self; op_name: "flt" => ValueOperationOp::Flt(lhs as Token::Identifier, rhs as Token::Identifier));
474        try_op!(self; op_name: "fle" => ValueOperationOp::Fle(lhs as Token::Identifier, rhs as Token::Identifier));
475        try_op!(self; op_name: "fgt" => ValueOperationOp::Fgt(lhs as Token::Identifier, rhs as Token::Identifier));
476        try_op!(self; op_name: "fge" => ValueOperationOp::Fge(lhs as Token::Identifier, rhs as Token::Identifier));
477
478        try_op!(self; op_name: "alloc" => ValueOperationOp::Alloc(size as Token::Identifier));
479        try_op!(self; op_name: "load" => ValueOperationOp::Load(pointer as Token::Identifier));
480        try_op!(self; op_name: "ptradd" => ValueOperationOp::PtrAdd(pointer as Token::Identifier, offset as Token::Identifier));
481
482        try_op!(self; op_name: "ceq" => ValueOperationOp::Ceq(lhs as Token::Identifier, rhs as Token::Identifier));
483        try_op!(self; op_name: "clt" => ValueOperationOp::Clt(lhs as Token::Identifier, rhs as Token::Identifier));
484        try_op!(self; op_name: "cle" => ValueOperationOp::Cle(lhs as Token::Identifier, rhs as Token::Identifier));
485        try_op!(self; op_name: "cgt" => ValueOperationOp::Cgt(lhs as Token::Identifier, rhs as Token::Identifier));
486        try_op!(self; op_name: "cge" => ValueOperationOp::Cge(lhs as Token::Identifier, rhs as Token::Identifier));
487        try_op!(self; op_name: "char2int" => ValueOperationOp::Char2Int(value as Token::Identifier));
488        try_op!(self; op_name: "int2char" => ValueOperationOp::Int2Char(value as Token::Identifier));
489
490        self.diagnostics.push(
491            Diagnostic::new("Unknown value operation", op_name)
492                .explain("Could not parse identifier as value operation")
493                .explain("If this is a valid operation name, file an issue at <https://github.com/ethanuppal/bril-lsp>"),
494        );
495
496        Err(ParserFailedMarker)
497    }
498
499    pub fn parse_value_operation(
500        &mut self,
501        name: Loc<&'source str>,
502        type_annotation: Option<Loc<ast::TypeAnnotation>>,
503        equals_token: Loc<()>,
504        op_name: Loc<&'source str>,
505    ) -> Result<Loc<ast::ValueOperation<'source>>> {
506        let op = self.parse_value_operation_op(op_name)?;
507        let semi_token = self
508            .eat(
509                Token::Semi,
510                "Expected semicolon at end of value operation instruction",
511            )?
512            .without_inner();
513        let start = name.span();
514        let end = semi_token.span();
515        Ok(ast::ValueOperation {
516            name,
517            type_annotation,
518            equals_token,
519            op,
520            semi_token,
521        }
522        .between(start, end))
523    }
524
525    pub fn parse_effect_operation_op(&mut self) -> Result<Loc<ast::EffectOperationOp<'source>>> {
526        let op_name = self
527            .eat(
528                Token::Identifier(""),
529                "Missing operation name for effect operation",
530            )?
531            .map(Token::assume_identifier);
532
533        try_op!(self; op_name: "jmp" => EffectOperationOp::Jmp(destination as Token::Label));
534        try_op!(self; op_name: "br" => EffectOperationOp::Br(condition as Token::Identifier, if_true as Token::Label, if_false as Token::Label));
535        try_op!(self; op_name: "call" => EffectOperationOp::Call(destination as Token::FunctionName, arguments as Vec::from));
536        try_op!(self; op_name: "ret" => EffectOperationOp::Ret(value as Option::from));
537        try_op!(self; op_name: "print" => EffectOperationOp::Print(value as Vec::from));
538        try_op!(self; op_name: "nop" => EffectOperationOp::Nop);
539
540        try_op!(self; op_name: "store" => EffectOperationOp::Store(pointer as Token::Identifier, value as Token::Identifier));
541        try_op!(self; op_name: "free" => EffectOperationOp::Free(pointer as Token::Identifier));
542
543        self.diagnostics.push(
544            Diagnostic::new("Unknown effect operation", op_name)
545                .explain("Could not parse identifier as effect operation")
546                .explain("If this is a valid operation name, file an issue at <https://github.com/ethanuppal/bril-lsp>"),
547        );
548
549        Err(ParserFailedMarker)
550    }
551
552    pub fn parse_effect_operation(&mut self) -> Result<Loc<ast::EffectOperation<'source>>> {
553        let op = self.parse_effect_operation_op()?;
554        let semi_token = self
555            .eat(
556                Token::Semi,
557                "Expected semicolon at end of effect operation instruction",
558            )?
559            .without_inner();
560        let start = op.span();
561        let end = semi_token.span();
562        Ok(ast::EffectOperation { op, semi_token }.between(start, end))
563    }
564
565    pub fn parse_instruction(&mut self) -> Result<Loc<ast::Instruction<'source>>> {
566        let is_not_effect_operation = self
567            .get(1)
568            .map(|token| {
569                token.matches_against(Token::Colon) || token.matches_against(Token::Equals)
570            })
571            .unwrap_or(false);
572
573        if is_not_effect_operation {
574            let name =
575                self.parse_local_name("Expected destination variable name in instruction")?;
576
577            let type_annotation = if self.is_at(&Token::Colon) {
578                Some(self.parse_type_annotation()?)
579            } else {
580                None
581            };
582
583            let equals_token = self
584                .eat(Token::Equals, "Missing = after variable")?
585                .without_inner();
586
587            let instruction_name = self
588                .eat(Token::Identifier(""), "Missing instruction name")?
589                .map(Token::assume_identifier);
590
591            if instruction_name.inner == "const" {
592                let constant = self.parse_constant(
593                    name,
594                    type_annotation,
595                    equals_token,
596                    instruction_name.without_inner(),
597                )?;
598                let span = constant.span();
599                Ok(ast::Instruction::Constant(constant).at(span))
600            } else {
601                let value_operation = self.parse_value_operation(
602                    name,
603                    type_annotation,
604                    equals_token,
605                    instruction_name,
606                )?;
607                let span = value_operation.span();
608                Ok(ast::Instruction::ValueOperation(value_operation).at(span))
609            }
610        } else {
611            let effect_operation = self.parse_effect_operation()?;
612            let span = effect_operation.span();
613            Ok(ast::Instruction::EffectOperation(effect_operation).at(span))
614        }
615    }
616
617    pub fn parse_function_code(&mut self) -> Result<Loc<ast::FunctionCode<'source>>> {
618        if let Some(newline_token) = self.try_eat(Token::Newline) {
619            let empty_line_span = newline_token.span();
620            Ok(ast::FunctionCode::EmptyLine(newline_token.without_inner()).at(empty_line_span))
621        } else if let Some(comment) = self.try_eat(Token::Comment("")) {
622            let _ = self.eat(Token::Newline, "Expected newline after comment")?;
623            let comment_span = comment.span();
624            Ok(ast::FunctionCode::Comment(comment.map(Token::assume_comment)).at(comment_span))
625        } else if self.is_at(&Token::Label("")) {
626            let label = self.parse_label()?;
627            let colon_token = self
628                .eat(Token::Colon, "Expected colon after label in function")?
629                .without_inner();
630            let start = label.span();
631            let end = colon_token.span();
632
633            let comment = self
634                .try_eat(Token::Comment(""))
635                .map(|comment| comment.map(Token::assume_comment));
636
637            let _ = self.eat(Token::Newline, "Missing newline after label")?;
638            Ok(ast::FunctionCode::Label {
639                label,
640                colon_token,
641                comment,
642            }
643            .between(start, end))
644        } else {
645            let instruction = self.parse_instruction()?;
646
647            let comment = self
648                .try_eat(Token::Comment(""))
649                .map(|comment| comment.map(Token::assume_comment));
650
651            let _ = self.eat(Token::Newline, "Missing newline after instruction")?;
652            let span = instruction.span();
653            Ok(ast::FunctionCode::Instruction {
654                inner: instruction,
655                comment,
656            }
657            .at(span))
658        }
659    }
660
661    pub fn parse_type(&mut self) -> Result<Loc<ast::Type>> {
662        let ty = self
663            .eat(Token::Identifier(""), "Expected type")?
664            .map(Token::assume_identifier);
665
666        Ok(match ty.inner {
667            "int" => ast::Type::Int.at(ty),
668            "bool" => ast::Type::Bool.at(ty),
669            "float" => ast::Type::Float.at(ty),
670            "char" => ast::Type::Char.at(ty),
671            "ptr" => {
672                self.eat(Token::LeftAngle, "Missing inner type for pointer type")?;
673                let inner = self.parse_type()?;
674                let end = self.eat(
675                    Token::RightAngle,
676                    "Missing right angle after pointer inner type",
677                )?;
678                ast::Type::Ptr(Box::new(inner)).between(ty, end)
679            }
680            _ => {
681                self.diagnostics
682                    .push(Diagnostic::new("Unknown type", ty).explain("This is not a valid type"));
683                return Err(ParserFailedMarker);
684            }
685        })
686    }
687
688    pub fn parse_type_annotation(&mut self) -> Result<Loc<ast::TypeAnnotation>> {
689        let colon_token = self
690            .eat(Token::Colon, "Need colon before type in type annotation")?
691            .without_inner();
692        self.skip_newlines();
693        let ty = self.parse_type()?;
694        let start = colon_token.span();
695        let end = ty.span();
696        Ok(ast::TypeAnnotation { colon_token, ty }.between(start, end))
697    }
698
699    pub fn parse_function_parameter(
700        &mut self,
701    ) -> Result<(Loc<&'source str>, Loc<ast::TypeAnnotation>)> {
702        self.skip_newlines();
703        let name = self.parse_local_name("Expected parameter name")?;
704        self.skip_newlines();
705        let annotation = self.parse_type_annotation()?;
706        self.skip_newlines();
707        Ok((name, annotation))
708    }
709
710    pub fn parse_function(
711        &mut self,
712        name: Loc<&'source str>,
713    ) -> Result<Loc<ast::Function<'source>>> {
714        let parameters = if self.try_eat(Token::LeftPar).is_some() {
715            self.parse_separated(
716                Self::parse_function_parameter,
717                Token::Comma,
718                Token::RightPar,
719                "Failed to parse function parameters",
720            )?
721            .0
722        } else {
723            vec![]
724        };
725
726        self.skip_newlines();
727
728        let return_type = if self.is_at(&Token::Colon) {
729            Some(self.parse_type_annotation()?)
730        } else {
731            None
732        };
733
734        self.skip_newlines();
735
736        self.eat(Token::LeftBrace, "Missing left brace to open function")?;
737
738        self.skip_newlines();
739
740        let mut body = vec![];
741        while !self.is_eof() && !self.is_at(&Token::RightBrace) {
742            let index = self.index;
743
744            if let Ok(code) = self.parse_function_code() {
745                body.push(code);
746            } else {
747                self.index = index;
748                self.recover([Token::Semi, Token::RightBrace], "Failed to find another label or instruction in this function body to recover from");
749                if self.is_eof() || self.is_at(&Token::RightBrace) {
750                    return Err(ParserFailedMarker);
751                } else {
752                    self.advance();
753                }
754            }
755        }
756
757        let end = self.eat(Token::RightBrace, "Missing left brace to open function")?;
758
759        let _ = self.try_eat(Token::Newline);
760
761        Ok(ast::Function {
762            name: name.clone(),
763            parameters,
764            return_type,
765            body,
766        }
767        .between(name, end))
768    }
769
770    pub fn parse_program(&mut self) -> Result<ast::Program<'source>> {
771        self.skip_newlines();
772
773        let mut items = vec![];
774        while !self.is_eof() {
775            if let Some(newline_token) = self.try_eat(Token::Newline) {
776                items.push(ast::TopLevelItem::Newline(newline_token.without_inner()));
777                self.skip_newlines();
778            } else if self.is_at(&Token::Newline) {
779                // single newline
780                self.advance();
781            } else if let Some(comment_token) = self.try_eat(Token::Comment("")) {
782                let _ = self.eat(Token::Newline, "Expected newline after comment")?;
783                items.push(ast::TopLevelItem::Comment(
784                    comment_token.map(Token::assume_comment),
785                ));
786            } else if let Some(from_token) = self.try_eat(Token::From) {
787                if let Ok(import) = self.parse_import(from_token.without_inner()) {
788                    items.push(ast::TopLevelItem::Import(import));
789                } else {
790                    self.recover(
791                        [Token::Import, Token::FunctionName("")],
792                        "Failed to find another valid import or function to recover from",
793                    );
794                }
795            } else if let Some(function_name) = self.try_eat(Token::FunctionName("")) {
796                if let Ok(function) =
797                    self.parse_function(function_name.map(Token::assume_function_name))
798                {
799                    items.push(ast::TopLevelItem::Function(function));
800                } else {
801                    self.recover(
802                        [Token::Import, Token::FunctionName("")],
803                        "Failed to find another valid import or function to recover from",
804                    );
805                }
806            } else {
807                self.diagnostics.push(
808                    Diagnostic::new("Unexpected token", self.get(0).expect("We're not eof"))
809                        .explain("Top-level Bril constructs are imports or functions"),
810                );
811                self.recover(
812                    [Token::Import, Token::FunctionName("")],
813                    "Failed to find another valid import or function to recover from",
814                );
815            }
816        }
817
818        if self.diagnostics.is_empty() {
819            Ok(ast::Program { items })
820        } else {
821            Err(ParserFailedMarker)
822        }
823    }
824}