diff options
Diffstat (limited to 'support/texlab/crates/syntax/src/bibtex.rs')
-rw-r--r-- | support/texlab/crates/syntax/src/bibtex.rs | 299 |
1 files changed, 12 insertions, 287 deletions
diff --git a/support/texlab/crates/syntax/src/bibtex.rs b/support/texlab/crates/syntax/src/bibtex.rs index b568fbf8e8..97ff6f6150 100644 --- a/support/texlab/crates/syntax/src/bibtex.rs +++ b/support/texlab/crates/syntax/src/bibtex.rs @@ -1,57 +1,19 @@ -use rowan::{ast::AstNode, NodeOrToken}; +mod cst; +mod kind; -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] -#[allow(non_camel_case_types)] -#[repr(u16)] -pub enum SyntaxKind { - WHITESPACE, - JUNK, - L_DELIM, - R_DELIM, - L_CURLY, - R_CURLY, - COMMA, - POUND, - QUOTE, - EQ, - TYPE, - WORD, - NAME, - INTEGER, - NBSP, - ACCENT_NAME, - COMMAND_NAME, - - PREAMBLE, - STRING, - ENTRY, - FIELD, - VALUE, - LITERAL, - JOIN, - ACCENT, - COMMAND, - CURLY_GROUP, - QUOTE_GROUP, - ROOT, -} - -pub use SyntaxKind::*; - -impl From<SyntaxKind> for rowan::SyntaxKind { - fn from(kind: SyntaxKind) -> Self { - Self(kind as u16) - } -} +pub use self::{ + cst::*, + kind::SyntaxKind::{self, *}, +}; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] -pub enum Lang {} +pub enum BibtexLanguage {} -impl rowan::Language for Lang { +impl rowan::Language for BibtexLanguage { type Kind = SyntaxKind; fn kind_from_raw(raw: rowan::SyntaxKind) -> Self::Kind { - assert!(raw.0 <= SyntaxKind::ROOT as u16); + assert!(raw.0 <= ROOT as u16); unsafe { std::mem::transmute::<u16, SyntaxKind>(raw.0) } } @@ -60,245 +22,8 @@ impl rowan::Language for Lang { } } -pub type SyntaxNode = rowan::SyntaxNode<Lang>; - -pub type SyntaxToken = rowan::SyntaxToken<Lang>; - -pub type SyntaxElement = rowan::SyntaxElement<Lang>; - -macro_rules! ast_node { - (name: $name:ident, kinds: [$($kind:pat),+], traits: [$($trait: ident),*]) => { - #[derive(Clone)] - pub struct $name { - node: SyntaxNode, - } - - impl AstNode for $name { - type Language = Lang; - - fn can_cast(kind: SyntaxKind) -> bool { - match kind { - $($kind => true,)+ - _ => false, - } - } - - fn cast(node: SyntaxNode) -> Option<Self> - where - Self: Sized, - { - match node.kind() { - $($kind => Some(Self { node}),)+ - _ => None, - } - } - - fn syntax(&self) -> &SyntaxNode { - &self.node - } - } - - $( - impl $trait for $name { } - )* - }; -} - -macro_rules! ast_node_enum { - (name: $name:ident, variants: [$($variant:ident),+]) => { - #[derive(Clone)] - pub enum $name { - $($variant($variant),)* - } - - impl AstNode for $name { - type Language = Lang; - - fn can_cast(kind: SyntaxKind) -> bool { - false $(|| $variant::can_cast(kind))+ - } - - fn cast(node: SyntaxNode) -> Option<Self> - where - Self: Sized, - { - None $(.or_else(|| $variant::cast(node.clone()).map(Self::$variant)))* - } - - fn syntax(&self) -> &SyntaxNode { - match self { - $(Self::$variant(node) => node.syntax(),)* - } - } - } - - $( - impl From<$variant> for $name { - fn from(node: $variant) -> Self { - Self::$variant(node) - } - } - )* - }; -} - -pub trait HasType: AstNode<Language = Lang> { - fn type_token(&self) -> Option<SyntaxToken> { - self.syntax() - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|token| token.kind() == TYPE) - } -} - -pub trait HasDelims: AstNode<Language = Lang> { - fn left_delim_token(&self) -> Option<SyntaxToken> { - self.syntax() - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|token| token.kind() == L_DELIM) - } - - fn right_delim_token(&self) -> Option<SyntaxToken> { - self.syntax() - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|token| token.kind() == R_DELIM) - } -} - -pub trait HasName: AstNode<Language = Lang> { - fn name_token(&self) -> Option<SyntaxToken> { - self.syntax() - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|token| token.kind() == NAME) - } -} - -pub trait HasEq: AstNode<Language = Lang> { - fn eq_token(&self) -> Option<SyntaxToken> { - self.syntax() - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|token| token.kind() == EQ) - } -} - -pub trait HasComma: AstNode<Language = Lang> { - fn comma_token(&self) -> Option<SyntaxToken> { - self.syntax() - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|token| token.kind() == COMMA) - } -} - -pub trait HasPound: AstNode<Language = Lang> { - fn pound_token(&self) -> Option<SyntaxToken> { - self.syntax() - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|token| token.kind() == POUND) - } -} - -pub trait HasInteger: AstNode<Language = Lang> { - fn integer_token(&self) -> Option<SyntaxToken> { - self.syntax() - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|token| token.kind() == INTEGER) - } -} - -pub trait HasCommandName: AstNode<Language = Lang> { - fn command_name_token(&self) -> Option<SyntaxToken> { - self.syntax() - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|token| token.kind() == COMMAND_NAME) - } -} - -pub trait HasAccentName: AstNode<Language = Lang> { - fn accent_name_token(&self) -> Option<SyntaxToken> { - self.syntax() - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|token| token.kind() == ACCENT_NAME) - } -} - -pub trait HasWord: AstNode<Language = Lang> { - fn word_token(&self) -> Option<SyntaxToken> { - self.syntax() - .children_with_tokens() - .filter_map(NodeOrToken::into_token) - .find(|token| token.kind() == WORD) - } -} - -pub trait HasValue: AstNode<Language = Lang> { - fn value(&self) -> Option<Value> { - self.syntax().children().find_map(Value::cast) - } -} - -ast_node!(name: Root, kinds: [ROOT], traits: []); - -impl Root { - pub fn strings(&self) -> impl Iterator<Item = StringDef> { - self.syntax().children().filter_map(StringDef::cast) - } - - pub fn entries(&self) -> impl Iterator<Item = Entry> { - self.syntax().children().filter_map(Entry::cast) - } - - pub fn find_entry(&self, name: &str) -> Option<Entry> { - self.entries().find(|entry| { - entry - .name_token() - .map_or(false, |token| token.text() == name) - }) - } -} - -ast_node!(name: Preamble, kinds: [PREAMBLE], traits: [HasType, HasDelims, HasValue]); - -ast_node!(name: StringDef, kinds: [STRING], traits: [HasType, HasDelims, HasName, HasEq, HasValue]); - -ast_node!(name: Entry, kinds: [ENTRY], traits: [HasType, HasDelims, HasName, HasComma]); - -impl Entry { - pub fn fields(&self) -> impl Iterator<Item = Field> { - self.syntax().children().filter_map(Field::cast) - } -} - -ast_node!(name: Field, kinds: [FIELD], traits: [HasName, HasEq, HasValue, HasComma]); - -ast_node_enum!(name: Value, variants: [Literal, CurlyGroup, QuoteGroup, Join, Accent, Command]); - -ast_node!(name: Literal, kinds: [LITERAL], traits: [HasName, HasInteger]); - -ast_node!(name: CurlyGroup, kinds: [CURLY_GROUP], traits: []); - -ast_node!(name: QuoteGroup, kinds: [QUOTE_GROUP], traits: []); - -ast_node!(name: Join, kinds: [JOIN], traits: [HasPound]); - -impl Join { - pub fn left_value(&self) -> Option<Value> { - self.syntax().children().find_map(Value::cast) - } - - pub fn right_value(&self) -> Option<Value> { - self.syntax().children().filter_map(Value::cast).nth(1) - } -} +pub type SyntaxNode = rowan::SyntaxNode<BibtexLanguage>; -ast_node!(name: Accent, kinds: [ACCENT], traits: [HasAccentName, HasWord]); +pub type SyntaxToken = rowan::SyntaxToken<BibtexLanguage>; -ast_node!(name: Command, kinds: [COMMAND], traits: [HasCommandName]); +pub type SyntaxElement = rowan::SyntaxElement<BibtexLanguage>; |