1use crate::ast::{
2 self, Enum, Field, GenericArg, Impl, Path, Trait, TypeAlias, TypeDesc, Variant, VariantKind,
3};
4use crate::grammar::expressions::parse_expr;
5use crate::grammar::functions::{parse_fn_def, parse_fn_sig};
6use crate::node::{Node, Span};
7use crate::Token;
8use crate::{ParseFailed, ParseResult, Parser, TokenKind};
9use fe_common::diagnostics::Label;
10use if_chain::if_chain;
11use smol_str::SmolStr;
12use vec1::Vec1;
13
14pub fn parse_struct_def(
18 par: &mut Parser,
19 pub_qual: Option<Span>,
20) -> ParseResult<Node<ast::Struct>> {
21 let struct_tok = par.assert(TokenKind::Struct);
22 let name = par.expect_with_notes(TokenKind::Name, "failed to parse struct definition", |_| {
23 vec!["Note: a struct name must start with a letter or underscore, and contain letters, numbers, or underscores".into()]
24 })?;
25
26 let mut span = struct_tok.span + name.span;
27 let mut fields = vec![];
28 let mut functions = vec![];
29 par.enter_block(span, "struct body must start with `{`")?;
30
31 loop {
32 par.eat_newlines();
33
34 let attributes = if let Some(attr) = par.optional(TokenKind::Hash) {
35 let attr_name = par.expect_with_notes(TokenKind::Name, "failed to parse attribute definition", |_|
36 vec!["Note: an attribute name must start with a letter or underscore, and contain letters, numbers, or underscores".into()])?;
37 vec![Node::new(attr_name.text.into(), attr.span + attr_name.span)]
39 } else {
40 vec![]
41 };
42
43 par.eat_newlines();
44
45 let pub_qual = par.optional(TokenKind::Pub).map(|tok| tok.span);
46 match par.peek_or_err()? {
47 TokenKind::Name => {
48 let field = parse_field(par, attributes, pub_qual, None)?;
49 if !functions.is_empty() {
50 par.error(
51 field.span,
52 "struct field definitions must come before any function definitions",
53 );
54 }
55 fields.push(field);
56 }
57 TokenKind::Fn | TokenKind::Unsafe => {
58 functions.push(parse_fn_def(par, pub_qual)?);
59 }
60 TokenKind::BraceClose if pub_qual.is_none() => {
61 span += par.next()?.span;
62 break;
63 }
64 _ => {
65 let tok = par.next()?;
66 par.unexpected_token_error(&tok, "failed to parse struct definition", vec![]);
67 return Err(ParseFailed);
68 }
69 }
70 }
71 Ok(Node::new(
72 ast::Struct {
73 name: name.into(),
74 fields,
75 functions,
76 pub_qual,
77 },
78 span,
79 ))
80}
81
82#[allow(clippy::unnecessary_literal_unwrap)]
83pub fn parse_enum_def(par: &mut Parser, pub_qual: Option<Span>) -> ParseResult<Node<Enum>> {
87 let enum_tok = par.assert(TokenKind::Enum);
88 let name = par.expect_with_notes(
89 TokenKind::Name,
90 "failed to parse enum definition",
91 |_| vec!["Note: `enum` must be followed by a name, which must start with a letter and contain only letters, numbers, or underscores".into()],
92 )?;
93
94 let mut span = enum_tok.span + name.span;
95 let mut variants = vec![];
96 let mut functions = vec![];
97
98 par.enter_block(span, "enum definition")?;
99 loop {
100 par.eat_newlines();
101 match par.peek_or_err()? {
102 TokenKind::Name => {
103 let variant = parse_variant(par)?;
104 if !functions.is_empty() {
105 par.error(
106 variant.span,
107 "enum variant definitions must come before any function definitions",
108 );
109 }
110 variants.push(variant);
111 }
112
113 TokenKind::Fn | TokenKind::Unsafe => {
114 functions.push(parse_fn_def(par, None)?);
115 }
116
117 TokenKind::Pub => {
118 let pub_qual = Some(par.next().unwrap().span);
119 match par.peek() {
120 Some(TokenKind::Fn | TokenKind::Unsafe) => {
121 functions.push(parse_fn_def(par, pub_qual)?);
122 }
123
124 _ => {
125 par.error(
126 pub_qual.unwrap(),
127 "expected `fn` or `unsafe fn` after `pub`",
128 );
129 }
130 }
131 }
132
133 TokenKind::BraceClose => {
134 span += par.next()?.span;
135 break;
136 }
137
138 _ => {
139 let tok = par.next()?;
140 par.unexpected_token_error(&tok, "failed to parse enum definition body", vec![]);
141 return Err(ParseFailed);
142 }
143 };
144 }
145
146 Ok(Node::new(
147 ast::Enum {
148 name: name.into(),
149 variants,
150 functions,
151 pub_qual,
152 },
153 span,
154 ))
155}
156
157pub fn parse_trait_def(par: &mut Parser, pub_qual: Option<Span>) -> ParseResult<Node<Trait>> {
161 let trait_tok = par.assert(TokenKind::Trait);
162
163 let trait_name = par.expect_with_notes(
165 TokenKind::Name,
166 "failed to parse trait definition",
167 |_| vec!["Note: `trait` must be followed by a name, which must start with a letter and contain only letters, numbers, or underscores".into()],
168 )?;
169
170 let header_span = trait_tok.span + trait_name.span;
171 let mut functions = vec![];
172 par.enter_block(header_span, "trait definition")?;
173
174 loop {
175 match par.peek_or_err()? {
176 TokenKind::Fn => {
177 functions.push(parse_fn_sig(par, None)?);
179 par.expect_with_notes(
180 TokenKind::Semi,
181 "failed to parse trait definition",
182 |_| vec!["Note: trait functions must appear without body and followed by a semicolon.".into()],
183 )?;
184 par.eat_newlines();
185 }
186 TokenKind::BraceClose => {
187 par.next()?;
188 break;
189 }
190 _ => {
191 let tok = par.next()?;
192 par.unexpected_token_error(&tok, "failed to parse trait definition body", vec![]);
193 return Err(ParseFailed);
194 }
195 };
196 }
197
198 let span = header_span + pub_qual;
199 Ok(Node::new(
200 Trait {
201 name: Node::new(trait_name.text.into(), trait_name.span),
202 functions,
203 pub_qual,
204 },
205 span,
206 ))
207}
208
209pub fn parse_impl_def(par: &mut Parser) -> ParseResult<Node<Impl>> {
213 let impl_tok = par.assert(TokenKind::Impl);
214
215 let trait_name =
217 par.expect_with_notes(TokenKind::Name, "failed to parse `impl` definition", |_| {
218 vec!["Note: `impl` must be followed by the name of a trait".into()]
219 })?;
220
221 let for_tok =
222 par.expect_with_notes(TokenKind::For, "failed to parse `impl` definition", |_| {
223 vec![format!(
224 "Note: `impl {}` must be followed by the keyword `for`",
225 trait_name.text
226 )]
227 })?;
228
229 let receiver = parse_type_desc(par)?;
230 let mut functions = vec![];
231
232 let header_span = impl_tok.span + trait_name.span + for_tok.span + receiver.span;
233
234 par.enter_block(header_span, "impl definition")?;
235
236 loop {
237 par.eat_newlines();
238 match par.peek_or_err()? {
239 TokenKind::Fn => {
240 functions.push(parse_fn_def(par, None)?);
241 }
242 TokenKind::BraceClose => {
243 par.next()?;
244 break;
245 }
246 _ => {
247 let tok = par.next()?;
248 par.unexpected_token_error(&tok, "failed to parse `impl` definition body", vec![]);
249 return Err(ParseFailed);
250 }
251 };
252 }
253
254 Ok(Node::new(
255 Impl {
256 impl_trait: Node::new(trait_name.text.into(), trait_name.span),
257 receiver,
258 functions,
259 },
260 header_span,
261 ))
262}
263
264pub fn parse_type_alias(par: &mut Parser, pub_qual: Option<Span>) -> ParseResult<Node<TypeAlias>> {
268 let type_tok = par.assert(TokenKind::Type);
269 let name = par.expect(TokenKind::Name, "failed to parse type declaration")?;
270 par.expect_with_notes(TokenKind::Eq, "failed to parse type declaration", |_| {
271 vec![
272 "Note: a type alias name must be followed by an equals sign and a type description"
273 .into(),
274 format!("Example: `type {} = Map<address, u64>`", name.text),
275 ]
276 })?;
277 let typ = parse_type_desc(par)?;
278 let span = type_tok.span + pub_qual + typ.span;
279 Ok(Node::new(
280 TypeAlias {
281 name: name.into(),
282 typ,
283 pub_qual,
284 },
285 span,
286 ))
287}
288
289pub fn parse_field(
292 par: &mut Parser,
293 attributes: Vec<Node<SmolStr>>,
294 pub_qual: Option<Span>,
295 const_qual: Option<Span>,
296) -> ParseResult<Node<Field>> {
297 let name = par.expect(TokenKind::Name, "failed to parse field definition")?;
298 par.expect_with_notes(
299 TokenKind::Colon,
300 "failed to parse field definition",
301 |next| {
302 let mut notes = vec![];
303 if name.text == "def" && next.kind == TokenKind::Name {
304 notes.push("Hint: use `fn` to define a function".into());
305 notes.push(format!(
306 "Example: `{}fn {}( ...`",
307 if pub_qual.is_some() { "pub " } else { "" },
308 next.text
309 ));
310 }
311 notes
312 .push("Note: field name must be followed by a colon and a type description".into());
313 notes.push(format!(
314 "Example: {}{}{}: address",
315 if pub_qual.is_some() { "pub " } else { "" },
316 if const_qual.is_some() { "const " } else { "" },
317 name.text
318 ));
319 notes
320 },
321 )?;
322
323 let typ = parse_type_desc(par)?;
324 let value = if par.peek() == Some(TokenKind::Eq) {
325 par.next()?;
326 Some(parse_expr(par)?)
327 } else {
328 None
329 };
330 par.expect_stmt_end("field definition")?;
331 let span = name.span + pub_qual + const_qual + &typ;
332 Ok(Node::new(
333 Field {
334 is_pub: pub_qual.is_some(),
335 is_const: const_qual.is_some(),
336 attributes,
337 name: name.into(),
338 typ,
339 value,
340 },
341 span,
342 ))
343}
344
345pub fn parse_variant(par: &mut Parser) -> ParseResult<Node<Variant>> {
349 let name = par.expect(TokenKind::Name, "failed to parse enum variant")?;
350 let mut span = name.span;
351
352 let kind = match par.peek_or_err()? {
353 TokenKind::ParenOpen => {
354 span += par.next().unwrap().span;
355 let mut tys = vec![];
356 loop {
357 match par.peek_or_err()? {
358 TokenKind::ParenClose => {
359 span += par.next().unwrap().span;
360 break;
361 }
362
363 _ => {
364 let ty = parse_type_desc(par)?;
365 span += ty.span;
366 tys.push(ty);
367 if par.peek_or_err()? == TokenKind::Comma {
368 par.next()?;
369 } else {
370 span += par
371 .expect(
372 TokenKind::ParenClose,
373 "unexpected token while parsing enum variant",
374 )?
375 .span;
376 break;
377 }
378 }
379 }
380 }
381
382 VariantKind::Tuple(tys)
383 }
384
385 _ => VariantKind::Unit,
386 };
387
388 par.expect_stmt_end("enum variant")?;
389 Ok(Node::new(
390 Variant {
391 name: name.into(),
392 kind,
393 },
394 span,
395 ))
396}
397
398pub fn parse_opt_qualifier(par: &mut Parser, tk: TokenKind) -> Option<Span> {
400 if par.peek() == Some(tk) {
401 let tok = par.next().unwrap();
402 Some(tok.span)
403 } else {
404 None
405 }
406}
407
408pub fn parse_generic_args(par: &mut Parser) -> ParseResult<Node<Vec<GenericArg>>> {
413 use TokenKind::*;
414 let mut span = par.assert(Lt).span;
415
416 let mut args = vec![];
417
418 let expect_end = |par: &mut Parser| {
419 match par.peek_or_err()? {
421 Gt => Ok(par.next()?.span),
422 GtGt => Ok(par.split_next()?.span),
423 _ => {
424 let tok = par.next()?;
425 par.unexpected_token_error(
426 &tok,
427 "Unexpected token while parsing generic arg list",
428 vec![],
429 );
430 Err(ParseFailed)
431 }
432 }
433 };
434
435 loop {
436 match par.peek_or_err()? {
437 Gt => {
438 span += par.next()?.span;
439 break;
440 }
441 GtGt => {
442 span += par.split_next()?.span;
443 break;
444 }
445 Name | ParenOpen => {
447 let typ = parse_type_desc(par)?;
448 args.push(GenericArg::TypeDesc(Node::new(typ.kind, typ.span)));
449 if par.peek() == Some(Comma) {
450 par.next()?;
451 } else {
452 span += expect_end(par)?;
453 break;
454 }
455 }
456 Int => {
458 let tok = par.next()?;
459 if let Ok(num) = tok.text.parse() {
460 args.push(GenericArg::Int(Node::new(num, tok.span)));
461 if par.peek() == Some(Comma) {
462 par.next()?;
463 } else {
464 span += expect_end(par)?;
465 break;
466 }
467 } else {
468 par.error(tok.span, "failed to parse integer literal");
469 return Err(ParseFailed);
470 }
471 }
472 BraceOpen => {
474 let brace_open = par.next()?;
475 let expr = parse_expr(par)?;
476 if !matches!(par.next()?.kind, BraceClose) {
477 par.error(brace_open.span, "missing closing delimiter `}`");
478 return Err(ParseFailed);
479 }
480
481 args.push(GenericArg::ConstExpr(expr));
482
483 if par.peek() == Some(Comma) {
484 par.next()?;
485 } else {
486 span += expect_end(par)?;
487 break;
488 }
489 }
490
491 _ => {
493 let tok = par.next()?;
494 par.unexpected_token_error(
495 &tok,
496 "failed to parse generic type argument list",
497 vec![],
498 );
499 return Err(ParseFailed);
500 }
501 }
502 }
503 Ok(Node::new(args, span))
504}
505
506pub fn parse_path_tail<'a>(
508 par: &mut Parser<'a>,
509 head: Node<SmolStr>,
510) -> (Path, Span, Option<Token<'a>>) {
511 let mut span = head.span;
512 let mut segments = vec![head];
513 while let Some(delim) = par.optional(TokenKind::ColonColon) {
514 if let Some(name) = par.optional(TokenKind::Name) {
515 span += name.span;
516 segments.push(name.into());
517 } else {
518 return (Path { segments }, span, Some(delim));
519 }
520 }
521 (Path { segments }, span, None)
522}
523
524pub fn parse_type_desc(par: &mut Parser) -> ParseResult<Node<TypeDesc>> {
526 use TokenKind::*;
527 let mut typ = match par.peek_or_err()? {
528 SelfType => {
529 let _self = par.next()?;
530 Node::new(TypeDesc::SelfType, _self.span)
531 }
532 Name => {
533 let name = par.next()?;
534 match par.peek() {
535 Some(ColonColon) => {
536 let (path, span, trailing_delim) = parse_path_tail(par, name.into());
537 if let Some(colons) = trailing_delim {
538 let next = par.next()?;
539 par.fancy_error(
540 "failed to parse type description",
541 vec![
542 Label::secondary(colons.span, "path delimiter"),
543 Label::primary(next.span, "expected a name"),
544 ],
545 vec![],
546 );
547 return Err(ParseFailed);
548 }
549 Node::new(TypeDesc::Path(path), span)
550 }
551 Some(Lt) => {
552 let args = parse_generic_args(par)?;
553 let span = name.span + args.span;
554 Node::new(
555 TypeDesc::Generic {
556 base: name.into(),
557 args,
558 },
559 span,
560 )
561 }
562 _ => Node::new(
563 TypeDesc::Base {
564 base: name.text.into(),
565 },
566 name.span,
567 ),
568 }
569 }
570 ParenOpen => {
571 let mut span = par.next()?.span;
572 let mut items = vec![];
573 loop {
574 match par.peek_or_err()? {
575 ParenClose => {
576 span += par.next()?.span;
577 break;
578 }
579
580 Name | ParenOpen => {
581 let item = parse_type_desc(par)?;
582 span += item.span;
583 items.push(item);
584 if par.peek_or_err()? == Comma {
585 par.next()?;
586 } else {
587 span += par
588 .expect(
589 ParenClose,
590 "Unexpected token while parsing tuple type description",
591 )?
592 .span;
593 break;
594 }
595 }
596
597 _ => {
598 let tok = par.next()?;
599 par.unexpected_token_error(
600 &tok,
601 "failed to parse type description",
602 vec![],
603 );
604 return Err(ParseFailed);
605 }
606 }
607 }
608 if items.is_empty() {
609 Node::new(TypeDesc::Unit, span)
610 } else {
611 Node::new(
612 TypeDesc::Tuple {
613 items: Vec1::try_from_vec(items).expect("couldn't convert vec to vec1"),
614 },
615 span,
616 )
617 }
618 }
619 _ => {
620 let tok = par.next()?;
621 par.unexpected_token_error(&tok, "failed to parse type description", vec![]);
622 return Err(ParseFailed);
623 }
624 };
625
626 while par.peek() == Some(BracketOpen) {
627 let l_brack = par.next()?.span;
628
629 if_chain! {
630 if let Some(size_token) = par.optional(TokenKind::Int);
631 if let Ok(dimension) = size_token.text.parse::<usize>();
632 if let Some(r_brack) = par.optional(TokenKind::BracketClose);
633 then {
634 let span = typ.span + l_brack + r_brack.span;
635 par.fancy_error(
636 "Outdated array syntax",
637 vec![
638 Label::primary(
639 span,
640 ""
641 )
642 ],
643 vec![
644 format!("Hint: Use `Array<{}, {}>`", typ.kind, dimension)
645 ]
646 );
647 typ = Node::new(
648 TypeDesc::Generic {
649 base: Node::new("Array".into(), typ.span),
650 args: Node::new(vec![
651 GenericArg::TypeDesc(
652 Node::new(typ.kind, typ.span)
653 ),
654 GenericArg::Int(
655 Node::new(dimension, size_token.span)
656 )
657 ], span)
658 },
659 span,
660 );
661 } else {
662 par.fancy_error(
663 "Unexpected token while parsing type description",
664 vec![
665 Label::primary(
666 l_brack,
667 "Unexpected token"
668 )
669 ],
670 vec![
671 format!("Hint: To define an array type use `Array<{}, 10>`", typ.kind)
672 ]
673 );
674 return Err(ParseFailed);
675 }
676 }
677 }
678
679 Ok(typ)
680}