diff options
Diffstat (limited to 'support/texlab/src/syntax/bibtex/mod.rs')
-rw-r--r-- | support/texlab/src/syntax/bibtex/mod.rs | 431 |
1 files changed, 376 insertions, 55 deletions
diff --git a/support/texlab/src/syntax/bibtex/mod.rs b/support/texlab/src/syntax/bibtex/mod.rs index 9910390fe7..aa7242c1f7 100644 --- a/support/texlab/src/syntax/bibtex/mod.rs +++ b/support/texlab/src/syntax/bibtex/mod.rs @@ -1,75 +1,396 @@ mod ast; -mod finder; +mod formatter; mod lexer; mod parser; -use self::lexer::BibtexLexer; -use self::parser::BibtexParser; +pub use self::{ast::*, formatter::*}; -pub use self::ast::*; -pub use self::finder::*; -use lsp_types::Position; +use self::{lexer::Lexer, parser::Parser}; -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct BibtexSyntaxTree { - pub root: BibtexRoot, +pub fn open(text: &str) -> Tree { + let lexer = Lexer::new(text); + let parser = Parser::new(lexer); + parser.parse() } -impl BibtexSyntaxTree { - pub fn entries(&self) -> Vec<&BibtexEntry> { - let mut entries: Vec<&BibtexEntry> = Vec::new(); - for declaration in &self.root.children { - if let BibtexDeclaration::Entry(entry) = declaration { - entries.push(&entry); - } - } - entries +#[cfg(test)] +mod tests { + use super::*; + use crate::{ + protocol::{Range, RangeExt}, + syntax::text::SyntaxNode, + }; + use petgraph::graph::NodeIndex; + + #[derive(Debug, Default)] + struct TreeTraversal { + nodes: Vec<NodeIndex>, } - pub fn strings(&self) -> Vec<&BibtexString> { - let mut strings: Vec<&BibtexString> = Vec::new(); - for declaration in &self.root.children { - if let BibtexDeclaration::String(string) = declaration { - strings.push(&string); - } + impl<'a> Visitor<'a> for TreeTraversal { + fn visit(&mut self, tree: &Tree, node: NodeIndex) { + self.nodes.push(node); + tree.walk(self, node); } - strings } - pub fn find(&self, position: Position) -> Vec<BibtexNode> { - let mut finder = BibtexFinder::new(position); - finder.visit_root(&self.root); - finder.results - } + mod range { + use super::*; + use indoc::indoc; - pub fn find_entry(&self, key: &str) -> Option<&BibtexEntry> { - self.entries() - .into_iter() - .find(|entry| entry.key.as_ref().map(BibtexToken::text) == Some(key)) - } + fn verify(expected_ranges: Vec<Range>, text: &str) { + let tree = open(text.trim()); - pub fn resolve_crossref(&self, entry: &BibtexEntry) -> Option<&BibtexEntry> { - if let Some(field) = entry.find_field("crossref") { - if let Some(BibtexContent::BracedContent(content)) = &field.content { - if let Some(BibtexContent::Word(name)) = content.children.get(0) { - return self.find_entry(name.token.text()); - } - } + let mut traversal = TreeTraversal::default(); + traversal.visit(&tree, tree.root); + let actual_ranges: Vec<_> = traversal + .nodes + .into_iter() + .map(|node| tree.graph[node].range()) + .collect(); + + assert_eq!(actual_ranges, expected_ranges); } - None - } -} -impl From<BibtexRoot> for BibtexSyntaxTree { - fn from(root: BibtexRoot) -> Self { - BibtexSyntaxTree { root } - } -} + #[test] + fn empty_document() { + verify(vec![Range::new_simple(0, 0, 0, 0)], ""); + } + + #[test] + fn comment() { + verify( + vec![Range::new_simple(0, 0, 0, 3), Range::new_simple(0, 0, 0, 3)], + "foo", + ); + } + + #[test] + fn preamble_no_left() { + verify( + vec![Range::new_simple(0, 0, 0, 9), Range::new_simple(0, 0, 0, 9)], + "@preamble", + ); + } + + #[test] + fn preamble_no_content() { + verify( + vec![ + Range::new_simple(0, 0, 0, 10), + Range::new_simple(0, 0, 0, 10), + ], + "@preamble{", + ); + } + + #[test] + fn preamble_no_right() { + verify( + vec![ + Range::new_simple(0, 0, 0, 15), + Range::new_simple(0, 0, 0, 15), + Range::new_simple(0, 10, 0, 15), + Range::new_simple(0, 11, 0, 14), + ], + r#"@preamble{"foo""#, + ); + } + + #[test] + fn preamble_complete() { + verify( + vec![ + Range::new_simple(0, 0, 0, 16), + Range::new_simple(0, 0, 0, 16), + Range::new_simple(0, 10, 0, 15), + Range::new_simple(0, 11, 0, 14), + ], + r#"@preamble{"foo"}"#, + ); + } + + #[test] + fn string_no_left() { + verify( + vec![Range::new_simple(0, 0, 0, 7), Range::new_simple(0, 0, 0, 7)], + r#"@string"#, + ); + } + + #[test] + fn string_no_name() { + verify( + vec![Range::new_simple(0, 0, 0, 8), Range::new_simple(0, 0, 0, 8)], + r#"@string{"#, + ); + } + + #[test] + fn string_no_assign() { + verify( + vec![ + Range::new_simple(0, 0, 0, 11), + Range::new_simple(0, 0, 0, 11), + ], + r#"@string{foo"#, + ); + } + + #[test] + fn string_no_value() { + verify( + vec![ + Range::new_simple(0, 0, 0, 13), + Range::new_simple(0, 0, 0, 13), + ], + r#"@string{foo ="#, + ); + } + + #[test] + fn string_no_right() { + verify( + vec![ + Range::new_simple(0, 0, 0, 19), + Range::new_simple(0, 0, 0, 19), + Range::new_simple(0, 14, 0, 19), + Range::new_simple(0, 15, 0, 18), + ], + r#"@string{foo = "bar""#, + ); + } + + #[test] + fn string_complete() { + verify( + vec![ + Range::new_simple(0, 0, 0, 20), + Range::new_simple(0, 0, 0, 20), + Range::new_simple(0, 14, 0, 19), + Range::new_simple(0, 15, 0, 18), + ], + r#"@string{foo = "bar"}"#, + ); + } -impl From<&str> for BibtexSyntaxTree { - fn from(text: &str) -> Self { - let lexer = BibtexLexer::new(text); - let mut parser = BibtexParser::new(lexer); - parser.root().into() + #[test] + fn entry_no_left() { + verify( + vec![Range::new_simple(0, 0, 0, 8), Range::new_simple(0, 0, 0, 8)], + r#"@article"#, + ); + } + + #[test] + fn entry_no_key() { + verify( + vec![Range::new_simple(0, 0, 0, 9), Range::new_simple(0, 0, 0, 9)], + r#"@article{"#, + ); + } + + #[test] + fn entry_no_comma() { + verify( + vec![ + Range::new_simple(0, 0, 0, 12), + Range::new_simple(0, 0, 0, 12), + ], + r#"@article{foo"#, + ); + } + + #[test] + fn entry_no_right() { + verify( + vec![ + Range::new_simple(0, 0, 0, 13), + Range::new_simple(0, 0, 0, 13), + ], + r#"@article{foo,"#, + ); + } + + #[test] + fn entry_parentheses() { + verify( + vec![ + Range::new_simple(0, 0, 0, 14), + Range::new_simple(0, 0, 0, 14), + ], + r#"@article(foo,)"#, + ); + } + + #[test] + fn field_no_assign() { + verify( + vec![ + Range::new_simple(0, 0, 1, 10), + Range::new_simple(0, 0, 1, 10), + Range::new_simple(1, 4, 1, 10), + ], + indoc!( + r#" + @article{foo, + author + "# + ), + ); + } + + #[test] + fn field_no_value() { + verify( + vec![ + Range::new_simple(0, 0, 1, 12), + Range::new_simple(0, 0, 1, 12), + Range::new_simple(1, 4, 1, 12), + ], + indoc!( + r#" + @article{foo, + author = + "# + ), + ); + } + + #[test] + fn field_no_comma() { + verify( + vec![ + Range::new_simple(0, 0, 1, 16), + Range::new_simple(0, 0, 1, 16), + Range::new_simple(1, 4, 1, 16), + Range::new_simple(1, 13, 1, 16), + ], + indoc!( + r#" + @article{foo, + author = bar + "# + ), + ); + } + + #[test] + fn field_complete() { + verify( + vec![ + Range::new_simple(0, 0, 2, 1), + Range::new_simple(0, 0, 2, 1), + Range::new_simple(1, 4, 1, 17), + Range::new_simple(1, 13, 1, 16), + ], + indoc!( + r#" + @article{foo, + author = bar, + } + "# + ), + ); + } + + #[test] + fn entry_two_fields() { + verify( + vec![ + Range::new_simple(0, 0, 3, 1), + Range::new_simple(0, 0, 3, 1), + Range::new_simple(1, 4, 1, 17), + Range::new_simple(1, 13, 1, 16), + Range::new_simple(2, 4, 2, 16), + Range::new_simple(2, 12, 2, 15), + ], + indoc!( + r#" + @article{foo, + author = bar, + title = baz, + } + "# + ), + ); + } + + #[test] + fn quoted_content_no_children() { + verify( + vec![ + Range::new_simple(0, 0, 0, 12), + Range::new_simple(0, 0, 0, 12), + Range::new_simple(0, 10, 0, 11), + ], + r#"@preamble{"}"#, + ); + } + + #[test] + fn quoted_content_no_right() { + verify( + vec![ + Range::new_simple(0, 0, 0, 16), + Range::new_simple(0, 0, 0, 16), + Range::new_simple(0, 10, 0, 15), + Range::new_simple(0, 11, 0, 15), + ], + r#"@preamble{"word}"#, + ); + } + + #[test] + fn braced_content_no_children() { + verify( + vec![ + Range::new_simple(0, 0, 0, 11), + Range::new_simple(0, 0, 0, 11), + Range::new_simple(0, 10, 0, 11), + ], + r#"@preamble{{"#, + ); + } + + #[test] + fn braced_content_no_right() { + verify( + vec![ + Range::new_simple(0, 0, 0, 15), + Range::new_simple(0, 0, 0, 15), + Range::new_simple(0, 10, 0, 15), + Range::new_simple(0, 11, 0, 15), + ], + r#"@preamble{{word"#, + ); + } + + #[test] + fn concat_no_right() { + verify( + vec![ + Range::new_simple(0, 0, 0, 16), + Range::new_simple(0, 0, 0, 16), + Range::new_simple(0, 10, 0, 15), + Range::new_simple(0, 10, 0, 13), + ], + r#"@preamble{foo #}"#, + ); + } + + #[test] + fn concat_complete() { + verify( + vec![ + Range::new_simple(0, 0, 0, 20), + Range::new_simple(0, 0, 0, 20), + Range::new_simple(0, 10, 0, 19), + Range::new_simple(0, 10, 0, 13), + Range::new_simple(0, 16, 0, 19), + ], + r#"@preamble{foo # bar}"#, + ); + } } } |