1use 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}