diff options
Diffstat (limited to 'support/texlab/crates/syntax/src')
-rw-r--r-- | support/texlab/crates/syntax/src/bibtex.rs | 299 | ||||
-rw-r--r-- | support/texlab/crates/syntax/src/bibtex/cst.rs | 244 | ||||
-rw-r--r-- | support/texlab/crates/syntax/src/bibtex/kind.rs | 43 | ||||
-rw-r--r-- | support/texlab/crates/syntax/src/lib.rs | 13 |
4 files changed, 299 insertions, 300 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>; diff --git a/support/texlab/crates/syntax/src/bibtex/cst.rs b/support/texlab/crates/syntax/src/bibtex/cst.rs new file mode 100644 index 0000000000..eb67fdb0d7 --- /dev/null +++ b/support/texlab/crates/syntax/src/bibtex/cst.rs @@ -0,0 +1,244 @@ +use rowan::{ast::AstNode, NodeOrToken}; + +use super::{ + BibtexLanguage, + SyntaxKind::{self, *}, + SyntaxNode, SyntaxToken, +}; + +macro_rules! cst_node { + (name: $name:ident, kinds: [$($kind:pat),+], traits: [$($trait: ident),*]) => { + #[derive(Clone)] + pub struct $name { + node: SyntaxNode, + } + + impl AstNode for $name { + type Language = BibtexLanguage; + + 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! cst_node_enum { + (name: $name:ident, variants: [$($variant:ident),+]) => { + #[derive(Clone)] + pub enum $name { + $($variant($variant),)* + } + + impl AstNode for $name { + type Language = BibtexLanguage; + + 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 = BibtexLanguage> { + 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 = BibtexLanguage> { + 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 = BibtexLanguage> { + 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 = BibtexLanguage> { + 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 = BibtexLanguage> { + 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 = BibtexLanguage> { + 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 = BibtexLanguage> { + 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 = BibtexLanguage> { + 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 = BibtexLanguage> { + 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 = BibtexLanguage> { + 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 = BibtexLanguage> { + fn value(&self) -> Option<Value> { + self.syntax().children().find_map(Value::cast) + } +} + +cst_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) + }) + } +} + +cst_node!(name: Preamble, kinds: [PREAMBLE], traits: [HasType, HasDelims, HasValue]); + +cst_node!(name: StringDef, kinds: [STRING], traits: [HasType, HasDelims, HasName, HasEq, HasValue]); + +cst_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) + } +} + +cst_node!(name: Field, kinds: [FIELD], traits: [HasName, HasEq, HasValue, HasComma]); + +cst_node_enum!(name: Value, variants: [Literal, CurlyGroup, QuoteGroup, Join, Accent, Command]); + +cst_node!(name: Literal, kinds: [LITERAL], traits: [HasName, HasInteger]); + +cst_node!(name: CurlyGroup, kinds: [CURLY_GROUP], traits: []); + +cst_node!(name: QuoteGroup, kinds: [QUOTE_GROUP], traits: []); + +cst_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) + } +} + +cst_node!(name: Accent, kinds: [ACCENT], traits: [HasAccentName, HasWord]); + +cst_node!(name: Command, kinds: [COMMAND], traits: [HasCommandName]); diff --git a/support/texlab/crates/syntax/src/bibtex/kind.rs b/support/texlab/crates/syntax/src/bibtex/kind.rs new file mode 100644 index 0000000000..7817f47495 --- /dev/null +++ b/support/texlab/crates/syntax/src/bibtex/kind.rs @@ -0,0 +1,43 @@ +#[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) + } +} diff --git a/support/texlab/crates/syntax/src/lib.rs b/support/texlab/crates/syntax/src/lib.rs index c2c0552652..dc8761b73d 100644 --- a/support/texlab/crates/syntax/src/lib.rs +++ b/support/texlab/crates/syntax/src/lib.rs @@ -20,16 +20,3 @@ pub struct BuildError { pub struct BuildLog { pub errors: Vec<BuildError>, } - -#[macro_export] -macro_rules! match_ast { - (match $node:ident { $($tt:tt)* }) => { $crate::match_ast!(match ($node) { $($tt)* }) }; - - (match ($node:expr) { - $( $( $path:ident )::+ ($it:pat) => $res:expr, )* - _ => $catch_all:expr $(,)? - }) => {{ - $( if let Some($it) = $($path::)+cast($node.clone()) { $res } else )* - { $catch_all } - }}; -} |