diff --git a/src/ast/file.rs b/src/ast/file.rs index c0cfb7b..a909bab 100644 --- a/src/ast/file.rs +++ b/src/ast/file.rs @@ -1,6 +1,6 @@ use super::{ enumeration::Enum, global_variable::GlobalVar, structure::Structure, type_alias::TypeAlias, - Function, HelperExpr, SettingsId, + Function, HelperExpr, SettingsId, Trait, }; #[derive(Clone, Debug)] @@ -11,6 +11,7 @@ pub struct AstFile { pub global_variables: Vec, pub enums: Vec, pub helper_exprs: Vec, + pub traits: Vec, pub settings: Option, } @@ -24,6 +25,7 @@ impl AstFile { enums: vec![], helper_exprs: vec![], settings: None, + traits: vec![], } } } diff --git a/src/ast/mod.rs b/src/ast/mod.rs index f4b4e52..9f8ac6f 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -10,6 +10,7 @@ mod helper_expr; mod module; mod stmt; mod structure; +mod traits; mod type_alias; mod workspace; @@ -26,5 +27,6 @@ pub use helper_expr::*; pub use module::*; pub use stmt::*; pub use structure::*; +pub use traits::*; pub use type_alias::*; pub use workspace::*; diff --git a/src/ast/traits.rs b/src/ast/traits.rs new file mode 100644 index 0000000..5cecba5 --- /dev/null +++ b/src/ast/traits.rs @@ -0,0 +1,9 @@ +use super::Privacy; +use crate::source_files::Source; + +#[derive(Clone, Debug)] +pub struct Trait { + pub name: String, + pub source: Source, + pub privacy: Privacy, +} diff --git a/src/lexer/identifier_state.rs b/src/lexer/identifier_state.rs index 1ffcf3e..7cc064d 100644 --- a/src/lexer/identifier_state.rs +++ b/src/lexer/identifier_state.rs @@ -43,6 +43,7 @@ impl IdentifierState { "zeroed" => TokenKind::ZeroedKeyword, "pragma" => TokenKind::PragmaKeyword, "pub" => TokenKind::PubKeyword, + "trait" => TokenKind::TraitKeyword, _ => TokenKind::Identifier(identifier), } .at(self.start_source) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index d40f98d..f0f3525 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -13,6 +13,7 @@ mod parse_helper_expr; mod parse_stmt; mod parse_structure; mod parse_top_level; +mod parse_trait; mod parse_type; mod parse_type_alias; mod parse_util; diff --git a/src/parser/parse_top_level.rs b/src/parser/parse_top_level.rs index 762caf0..ed54c92 100644 --- a/src/parser/parse_top_level.rs +++ b/src/parser/parse_top_level.rs @@ -71,6 +71,10 @@ impl<'a, I: Inflow> Parser<'a, I> { let helper_expr = self.parse_helper_expr(annotations)?; ast_file.helper_exprs.push(helper_expr); } + TokenKind::TraitKeyword => { + let trait_decl = self.parse_trait(annotations)?; + ast_file.traits.push(trait_decl); + } TokenKind::EndOfFile => { // End-of-file is only okay if no preceeding annotations if !annotations.is_empty() { diff --git a/src/parser/parse_trait.rs b/src/parser/parse_trait.rs new file mode 100644 index 0000000..0609c4e --- /dev/null +++ b/src/parser/parse_trait.rs @@ -0,0 +1,44 @@ +use super::{ + annotation::{Annotation, AnnotationKind}, + error::ParseError, + Parser, +}; +use crate::{ + ast::{Privacy, Trait}, + inflow::Inflow, + token::{Token, TokenKind}, +}; + +impl<'a, I: Inflow> Parser<'a, I> { + pub fn parse_trait(&mut self, annotations: Vec) -> Result { + let source = self.source_here(); + self.input.advance(); + + let name = self.parse_identifier(Some("for trait name after 'trait' keyword"))?; + self.ignore_newlines(); + + let mut privacy = Privacy::Private; + + for annotation in annotations { + match annotation.kind { + AnnotationKind::Public => privacy = Privacy::Public, + _ => return Err(self.unexpected_annotation(&annotation, Some("for trait"))), + } + } + + self.ignore_newlines(); + self.parse_token(TokenKind::OpenCurly, Some("to begin trait body"))?; + + while !self.input.peek_is_or_eof(TokenKind::CloseCurly) { + todo!("parse trait body"); + } + + self.parse_token(TokenKind::CloseCurly, Some("to end trait body"))?; + + Ok(Trait { + name, + source, + privacy, + }) + } +} diff --git a/src/token.rs b/src/token.rs index e4d51f2..96ebed5 100644 --- a/src/token.rs +++ b/src/token.rs @@ -82,6 +82,7 @@ pub enum TokenKind { ZeroedKeyword, PragmaKeyword, PubKeyword, + TraitKeyword, Member, Add, Subtract, @@ -172,6 +173,7 @@ impl Display for TokenKind { TokenKind::ZeroedKeyword => f.write_str("'zeroed' keyword"), TokenKind::PragmaKeyword => f.write_str("'pragma' keyword"), TokenKind::PubKeyword => f.write_str("'pub' keyword"), + TokenKind::TraitKeyword => f.write_str("'trait' keyword"), TokenKind::Member => f.write_str("'.'"), TokenKind::Add => f.write_str("'+'"), TokenKind::Subtract => f.write_str("'-'"), @@ -300,6 +302,7 @@ impl TokenKind { | TokenKind::ZeroedKeyword | TokenKind::PragmaKeyword | TokenKind::PubKeyword + | TokenKind::TraitKeyword | TokenKind::OpenAngle | TokenKind::Comma | TokenKind::Colon