Skip to content

Commit

Permalink
Parse trait defintions
Browse files Browse the repository at this point in the history
  • Loading branch information
cburgdorf committed May 5, 2022
1 parent e2b91ff commit aef8fa7
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 1 deletion.
1 change: 1 addition & 0 deletions crates/analyzer/src/db/queries/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ pub fn module_all_items(db: &dyn AnalyzerDb, module: ModuleId) -> Rc<[Item]> {
}))))
}
ast::ModuleStmt::Pragma(_) => None,
ast::ModuleStmt::Trait(_) => None,
ast::ModuleStmt::Use(_) => None,
ast::ModuleStmt::Event(node) => Some(Item::Event(db.intern_event(Rc::new(Event {
ast: node.clone(),
Expand Down
17 changes: 17 additions & 0 deletions crates/parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub enum ModuleStmt {
Contract(Node<Contract>),
Constant(Node<ConstantDecl>),
Struct(Node<Struct>),
Trait(Node<Trait>),
Function(Node<Function>),
Event(Node<Event>),
ParseError(Span),
Expand Down Expand Up @@ -87,6 +88,12 @@ pub struct Struct {
pub pub_qual: Option<Span>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub struct Trait {
pub name: Node<SmolStr>,
pub pub_qual: Option<Span>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Hash, Clone)]
pub enum TypeDesc {
Unit,
Expand Down Expand Up @@ -425,6 +432,7 @@ impl Spanned for ModuleStmt {
match self {
ModuleStmt::Pragma(inner) => inner.span,
ModuleStmt::Use(inner) => inner.span,
ModuleStmt::Trait(inner) => inner.span,
ModuleStmt::TypeAlias(inner) => inner.span,
ModuleStmt::Contract(inner) => inner.span,
ModuleStmt::Constant(inner) => inner.span,
Expand Down Expand Up @@ -456,6 +464,7 @@ impl fmt::Display for ModuleStmt {
match self {
ModuleStmt::Pragma(node) => write!(f, "{}", node.kind),
ModuleStmt::Use(node) => write!(f, "{}", node.kind),
ModuleStmt::Trait(node) => write!(f, "{}", node.kind),
ModuleStmt::TypeAlias(node) => write!(f, "{}", node.kind),
ModuleStmt::Contract(node) => write!(f, "{}", node.kind),
ModuleStmt::Constant(node) => write!(f, "{}", node.kind),
Expand Down Expand Up @@ -523,6 +532,14 @@ impl fmt::Display for ConstantDecl {
}
}

impl fmt::Display for Trait {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
writeln!(f, "trait {}:", self.name.kind)?;

Ok(())
}
}

impl fmt::Display for TypeAlias {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "type {} = {}", self.name.kind, self.typ.kind)
Expand Down
1 change: 1 addition & 0 deletions crates/parser/src/grammar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ pub mod contracts;
pub mod expressions;
pub mod functions;
pub mod module;
pub mod traits;
pub mod types;
2 changes: 2 additions & 0 deletions crates/parser/src/grammar/module.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::contracts::parse_contract_def;
use super::expressions::parse_expr;
use super::functions::parse_fn_def;
use super::traits::parse_trait_def;
use super::types::{
parse_event_def, parse_path_tail, parse_struct_def, parse_type_alias, parse_type_desc,
};
Expand Down Expand Up @@ -44,6 +45,7 @@ pub fn parse_module_stmt(par: &mut Parser) -> ParseResult<ModuleStmt> {
TokenKind::Use => ModuleStmt::Use(parse_use(par)?),
TokenKind::Contract => ModuleStmt::Contract(parse_contract_def(par, None)?),
TokenKind::Struct => ModuleStmt::Struct(parse_struct_def(par, None)?),
TokenKind::Trait => ModuleStmt::Trait(parse_trait_def(par, None)?),
TokenKind::Type => ModuleStmt::TypeAlias(parse_type_alias(par, None)?),
TokenKind::Const => ModuleStmt::Constant(parse_constant(par, None)?),

Expand Down
55 changes: 55 additions & 0 deletions crates/parser/src/grammar/traits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use crate::ast::Trait;
use crate::grammar::functions::parse_single_word_stmt;
use crate::node::{Node, Span};
use crate::{ParseFailed, ParseResult, Parser, TokenKind};

/// Parse a trait definition.
/// # Panics
/// Panics if the next token isn't `trait`.
pub fn parse_trait_def(par: &mut Parser, trait_pub_qual: Option<Span>) -> ParseResult<Node<Trait>> {
let trait_tok = par.assert(TokenKind::Trait);

// trait Event:
// pass
//

let trait_name = par.expect_with_notes(
TokenKind::Name,
"failed to parse trait definition",
|_| vec!["Note: `trait` must be followed by a name, which must start with a letter and contain only letters, numbers, or underscores".into()],
)?;

let header_span = trait_tok.span + trait_name.span;
par.enter_block(header_span, "trait definition")?;

loop {
match par.peek() {
Some(TokenKind::Pass) => {
parse_single_word_stmt(par)?;
}
Some(TokenKind::Dedent) => {
par.next()?;
break;
}
None => break,
Some(_) => {
let tok = par.next()?;
par.unexpected_token_error(
tok.span,
"failed to parse trait definition body",
vec![],
);
return Err(ParseFailed);
}
};
}

let span = header_span + trait_pub_qual;
Ok(Node::new(
Trait {
name: Node::new(trait_name.text.into(), trait_name.span),
pub_qual: trait_pub_qual,
},
span,
))
}
3 changes: 3 additions & 0 deletions crates/parser/src/lexer/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ pub enum TokenKind {
SelfValue,
#[token("struct")]
Struct,
#[token("trait")]
Trait,
#[token("type")]
Type,
#[token("unsafe")]
Expand Down Expand Up @@ -249,6 +251,7 @@ impl TokenKind {
Revert => "keyword `revert`",
SelfValue => "keyword `self`",
Struct => "keyword `struct`",
Trait => "keyword `trait`",
Type => "keyword `type`",
Unsafe => "keyword `unsafe`",
While => "keyword `while`",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ error: failed to parse module
1if x:
^^ unexpected token
= Note: expected import, contract, struct, type, const or event
= Note: expected import, contract, struct, trait, type, const or event


7 changes: 7 additions & 0 deletions foo.fe
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
trait Foo:
pass

contract Meh:

pub fn bar<T>(x: T) -> bool:
return true

0 comments on commit aef8fa7

Please sign in to comment.