Skip to content

Commit 79e52e4

Browse files
committed
Parse trait defintions
1 parent 7621ff9 commit 79e52e4

File tree

8 files changed

+87
-1
lines changed

8 files changed

+87
-1
lines changed

crates/analyzer/src/db/queries/module.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ pub fn module_all_items(db: &dyn AnalyzerDb, module: ModuleId) -> Rc<[Item]> {
9595
}))))
9696
}
9797
ast::ModuleStmt::Pragma(_) => None,
98+
ast::ModuleStmt::Trait(_) => None,
9899
ast::ModuleStmt::Use(_) => None,
99100
ast::ModuleStmt::Event(node) => Some(Item::Event(db.intern_event(Rc::new(Event {
100101
ast: node.clone(),

crates/parser/src/ast.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub enum ModuleStmt {
2121
Contract(Node<Contract>),
2222
Constant(Node<ConstantDecl>),
2323
Struct(Node<Struct>),
24+
Trait(Node<Trait>),
2425
Function(Node<Function>),
2526
Event(Node<Event>),
2627
ParseError(Span),
@@ -87,6 +88,12 @@ pub struct Struct {
8788
pub pub_qual: Option<Span>,
8889
}
8990

91+
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
92+
pub struct Trait {
93+
pub name: Node<SmolStr>,
94+
pub pub_qual: Option<Span>,
95+
}
96+
9097
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
9198
pub enum TypeDesc {
9299
Unit,
@@ -415,6 +422,7 @@ impl Spanned for ModuleStmt {
415422
match self {
416423
ModuleStmt::Pragma(inner) => inner.span,
417424
ModuleStmt::Use(inner) => inner.span,
425+
ModuleStmt::Trait(inner) => inner.span,
418426
ModuleStmt::TypeAlias(inner) => inner.span,
419427
ModuleStmt::Contract(inner) => inner.span,
420428
ModuleStmt::Constant(inner) => inner.span,
@@ -461,6 +469,7 @@ impl fmt::Display for ModuleStmt {
461469
match self {
462470
ModuleStmt::Pragma(node) => write!(f, "{}", node.kind),
463471
ModuleStmt::Use(node) => write!(f, "{}", node.kind),
472+
ModuleStmt::Trait(node) => write!(f, "{}", node.kind),
464473
ModuleStmt::TypeAlias(node) => write!(f, "{}", node.kind),
465474
ModuleStmt::Contract(node) => write!(f, "{}", node.kind),
466475
ModuleStmt::Constant(node) => write!(f, "{}", node.kind),
@@ -534,6 +543,14 @@ impl fmt::Display for ConstantDecl {
534543
}
535544
}
536545

546+
impl fmt::Display for Trait {
547+
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
548+
writeln!(f, "trait {}:", self.name.kind)?;
549+
550+
Ok(())
551+
}
552+
}
553+
537554
impl fmt::Display for TypeAlias {
538555
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
539556
let TypeAlias {

crates/parser/src/grammar.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,5 @@ pub mod contracts;
22
pub mod expressions;
33
pub mod functions;
44
pub mod module;
5+
pub mod traits;
56
pub mod types;

crates/parser/src/grammar/module.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::contracts::parse_contract_def;
22
use super::expressions::parse_expr;
33
use super::functions::parse_fn_def;
4+
use super::traits::parse_trait_def;
45
use super::types::{
56
parse_event_def, parse_path_tail, parse_struct_def, parse_type_alias, parse_type_desc,
67
};
@@ -42,6 +43,7 @@ pub fn parse_module_stmt(par: &mut Parser) -> ParseResult<ModuleStmt> {
4243
TokenKind::Use => ModuleStmt::Use(parse_use(par)?),
4344
TokenKind::Contract => ModuleStmt::Contract(parse_contract_def(par, None)?),
4445
TokenKind::Struct => ModuleStmt::Struct(parse_struct_def(par, None)?),
46+
TokenKind::Trait => ModuleStmt::Trait(parse_trait_def(par, None)?),
4547
TokenKind::Type => ModuleStmt::TypeAlias(parse_type_alias(par, None)?),
4648
TokenKind::Const => ModuleStmt::Constant(parse_constant(par, None)?),
4749

crates/parser/src/grammar/traits.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use crate::ast::Trait;
2+
use crate::grammar::functions::parse_single_word_stmt;
3+
use crate::node::{Node, Span};
4+
use crate::{ParseFailed, ParseResult, Parser, TokenKind};
5+
6+
/// Parse a trait definition.
7+
/// # Panics
8+
/// Panics if the next token isn't `trait`.
9+
pub fn parse_trait_def(par: &mut Parser, trait_pub_qual: Option<Span>) -> ParseResult<Node<Trait>> {
10+
let trait_tok = par.assert(TokenKind::Trait);
11+
12+
// trait Event:
13+
// pass
14+
//
15+
16+
let trait_name = par.expect_with_notes(
17+
TokenKind::Name,
18+
"failed to parse trait definition",
19+
|_| vec!["Note: `trait` must be followed by a name, which must start with a letter and contain only letters, numbers, or underscores".into()],
20+
)?;
21+
22+
let header_span = trait_tok.span + trait_name.span;
23+
par.enter_block(header_span, "trait definition")?;
24+
25+
loop {
26+
match par.peek() {
27+
Some(TokenKind::Pass) => {
28+
parse_single_word_stmt(par)?;
29+
}
30+
Some(TokenKind::Dedent) => {
31+
par.next()?;
32+
break;
33+
}
34+
None => break,
35+
Some(_) => {
36+
let tok = par.next()?;
37+
par.unexpected_token_error(
38+
tok.span,
39+
"failed to parse trait definition body",
40+
vec![],
41+
);
42+
return Err(ParseFailed);
43+
}
44+
};
45+
}
46+
47+
let span = header_span + trait_pub_qual;
48+
Ok(Node::new(
49+
Trait {
50+
name: Node::new(trait_name.text.into(), trait_name.span),
51+
pub_qual: trait_pub_qual,
52+
},
53+
span,
54+
))
55+
}

crates/parser/src/lexer/token.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ pub enum TokenKind {
9393
SelfValue,
9494
#[token("struct")]
9595
Struct,
96+
#[token("trait")]
97+
Trait,
9698
#[token("type")]
9799
Type,
98100
#[token("unsafe")]
@@ -237,6 +239,7 @@ impl TokenKind {
237239
Revert => "keyword `revert`",
238240
SelfValue => "keyword `self`",
239241
Struct => "keyword `struct`",
242+
Trait => "keyword `trait`",
240243
Type => "keyword `type`",
241244
Unsafe => "keyword `unsafe`",
242245
While => "keyword `while`",

crates/parser/tests/cases/snapshots/cases__errors__module_bad_stmt.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@ error: failed to parse module
99
1if x { y }
1010
^^ unexpected token
1111
12-
= Note: expected import, contract, struct, type, const or event
12+
= Note: expected import, contract, struct, trait, type, const or event
1313

1414

foo.fe

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
trait Foo:
2+
pass
3+
4+
contract Meh:
5+
6+
pub fn bar<T>(x: T) -> bool:
7+
return true

0 commit comments

Comments
 (0)