fe_parser/grammar/
contracts.rs1use super::functions::parse_fn_def;
2use super::types::{parse_field, parse_opt_qualifier};
3
4use crate::ast::{Contract, ContractStmt};
5use crate::node::{Node, Span};
6use crate::{ParseFailed, ParseResult, Parser, TokenKind};
7
8pub fn parse_contract_def(
18 par: &mut Parser,
19 contract_pub_qual: Option<Span>,
20) -> ParseResult<Node<Contract>> {
21 let contract_tok = par.assert(TokenKind::Contract);
22 let contract_name = par.expect_with_notes(
23 TokenKind::Name,
24 "failed to parse contract definition",
25 |_| vec!["Note: `contract` must be followed by a name, which must start with a letter and contain only letters, numbers, or underscores".into()],
26 )?;
27
28 let mut span = contract_tok.span + contract_name.span;
29 par.enter_block(span, "contract definition")?;
30
31 let mut fields = vec![];
32 let mut defs = vec![];
33
34 loop {
35 par.eat_newlines();
36 let mut pub_qual = parse_opt_qualifier(par, TokenKind::Pub);
37 let const_qual = parse_opt_qualifier(par, TokenKind::Const);
38 if pub_qual.is_none() && const_qual.is_some() && par.peek() == Some(TokenKind::Pub) {
39 pub_qual = parse_opt_qualifier(par, TokenKind::Pub);
40 par.error(
41 pub_qual.unwrap() + const_qual,
42 "`const pub` should be written `pub const`",
43 );
44 }
45
46 match par.peek_or_err()? {
47 TokenKind::Name => {
48 let field = parse_field(par, vec![], pub_qual, const_qual)?;
49 if !defs.is_empty() {
50 par.error(
51 field.span,
52 "contract field definitions must come before any function definitions",
53 );
54 }
55 fields.push(field);
56 }
57 TokenKind::Fn | TokenKind::Unsafe => {
58 if let Some(span) = const_qual {
59 par.error(
60 span,
61 "`const` qualifier can't be used with function definitions",
62 );
63 }
64 defs.push(ContractStmt::Function(parse_fn_def(par, pub_qual)?));
65 }
66 TokenKind::BraceClose => {
67 span += par.next()?.span;
68 break;
69 }
70 _ => {
71 let tok = par.next()?;
72 par.unexpected_token_error(
73 &tok,
74 "failed to parse contract definition body",
75 vec![],
76 );
77 return Err(ParseFailed);
78 }
79 };
80 }
81
82 Ok(Node::new(
83 Contract {
84 name: Node::new(contract_name.text.into(), contract_name.span),
85 fields,
86 body: defs,
87 pub_qual: contract_pub_qual,
88 },
89 span,
90 ))
91}