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