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