diff options
Diffstat (limited to 'support/texlab/src/syntax/bibtex/parser.rs')
-rw-r--r-- | support/texlab/src/syntax/bibtex/parser.rs | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/support/texlab/src/syntax/bibtex/parser.rs b/support/texlab/src/syntax/bibtex/parser.rs new file mode 100644 index 0000000000..ffc33da545 --- /dev/null +++ b/support/texlab/src/syntax/bibtex/parser.rs @@ -0,0 +1,219 @@ +use super::ast::*; +use std::iter::Peekable; + +pub struct BibtexParser<I: Iterator<Item = BibtexToken>> { + tokens: Peekable<I>, +} + +impl<I: Iterator<Item = BibtexToken>> BibtexParser<I> { + pub fn new(tokens: I) -> Self { + BibtexParser { + tokens: tokens.peekable(), + } + } + + pub fn root(&mut self) -> BibtexRoot { + let mut children = Vec::new(); + while let Some(ref token) = self.tokens.peek() { + match token.kind { + BibtexTokenKind::PreambleKind => { + let preamble = Box::new(self.preamble()); + children.push(BibtexDeclaration::Preamble(preamble)); + } + BibtexTokenKind::StringKind => { + let string = Box::new(self.string()); + children.push(BibtexDeclaration::String(string)); + } + BibtexTokenKind::EntryKind => { + let entry = Box::new(self.entry()); + children.push(BibtexDeclaration::Entry(entry)); + } + _ => { + let comment = BibtexComment::new(self.tokens.next().unwrap()); + children.push(BibtexDeclaration::Comment(Box::new(comment))); + } + } + } + BibtexRoot::new(children) + } + + fn preamble(&mut self) -> BibtexPreamble { + let ty = self.tokens.next().unwrap(); + + let left = self.expect2(BibtexTokenKind::BeginBrace, BibtexTokenKind::BeginParen); + if left.is_none() { + return BibtexPreamble::new(ty, None, None, None); + } + + if !self.can_match_content() { + return BibtexPreamble::new(ty, left, None, None); + } + let content = self.content(); + + let right = self.expect2(BibtexTokenKind::EndBrace, BibtexTokenKind::EndParen); + BibtexPreamble::new(ty, left, Some(content), right) + } + + fn string(&mut self) -> BibtexString { + let ty = self.tokens.next().unwrap(); + + let left = self.expect2(BibtexTokenKind::BeginBrace, BibtexTokenKind::BeginParen); + if left.is_none() { + return BibtexString::new(ty, None, None, None, None, None); + } + + let name = self.expect1(BibtexTokenKind::Word); + if name.is_none() { + return BibtexString::new(ty, left, None, None, None, None); + } + + let assign = self.expect1(BibtexTokenKind::Assign); + if assign.is_none() { + return BibtexString::new(ty, left, name, None, None, None); + } + + if !self.can_match_content() { + return BibtexString::new(ty, left, name, assign, None, None); + } + let value = self.content(); + + let right = self.expect2(BibtexTokenKind::EndBrace, BibtexTokenKind::EndParen); + BibtexString::new(ty, left, name, assign, Some(value), right) + } + + fn entry(&mut self) -> BibtexEntry { + let ty = self.tokens.next().unwrap(); + + let left = self.expect2(BibtexTokenKind::BeginBrace, BibtexTokenKind::BeginParen); + if left.is_none() { + return BibtexEntry::new(ty, None, None, None, Vec::new(), None); + } + + let name = self.expect1(BibtexTokenKind::Word); + if name.is_none() { + return BibtexEntry::new(ty, left, None, None, Vec::new(), None); + } + + let comma = self.expect1(BibtexTokenKind::Comma); + if comma.is_none() { + return BibtexEntry::new(ty, left, name, None, Vec::new(), None); + } + + let mut fields = Vec::new(); + while self.next_of_kind(BibtexTokenKind::Word) { + fields.push(self.field()); + } + + let right = self.expect2(BibtexTokenKind::EndBrace, BibtexTokenKind::EndParen); + BibtexEntry::new(ty, left, name, comma, fields, right) + } + + fn field(&mut self) -> BibtexField { + let name = self.tokens.next().unwrap(); + + let assign = self.expect1(BibtexTokenKind::Assign); + if assign.is_none() { + return BibtexField::new(name, None, None, None); + } + + if !self.can_match_content() { + return BibtexField::new(name, assign, None, None); + } + let content = self.content(); + + let comma = self.expect1(BibtexTokenKind::Comma); + BibtexField::new(name, assign, Some(content), comma) + } + + fn content(&mut self) -> BibtexContent { + let token = self.tokens.next().unwrap(); + let left = match token.kind { + BibtexTokenKind::PreambleKind + | BibtexTokenKind::StringKind + | BibtexTokenKind::EntryKind + | BibtexTokenKind::Word + | BibtexTokenKind::Assign + | BibtexTokenKind::Comma + | BibtexTokenKind::BeginParen + | BibtexTokenKind::EndParen => BibtexContent::Word(BibtexWord::new(token)), + BibtexTokenKind::Command => BibtexContent::Command(BibtexCommand::new(token)), + BibtexTokenKind::Quote => { + let mut children = Vec::new(); + while self.can_match_content() { + if self.next_of_kind(BibtexTokenKind::Quote) { + break; + } + children.push(self.content()); + } + let right = self.expect1(BibtexTokenKind::Quote); + BibtexContent::QuotedContent(BibtexQuotedContent::new(token, children, right)) + } + BibtexTokenKind::BeginBrace => { + let mut children = Vec::new(); + while self.can_match_content() { + children.push(self.content()); + } + let right = self.expect1(BibtexTokenKind::EndBrace); + BibtexContent::BracedContent(BibtexBracedContent::new(token, children, right)) + } + _ => unreachable!(), + }; + if let Some(operator) = self.expect1(BibtexTokenKind::Concat) { + let right = if self.can_match_content() { + Some(self.content()) + } else { + None + }; + BibtexContent::Concat(Box::new(BibtexConcat::new(left, operator, right))) + } else { + left + } + } + + fn can_match_content(&mut self) -> bool { + if let Some(ref token) = self.tokens.peek() { + match token.kind { + BibtexTokenKind::PreambleKind + | BibtexTokenKind::StringKind + | BibtexTokenKind::EntryKind + | BibtexTokenKind::Word + | BibtexTokenKind::Command + | BibtexTokenKind::Assign + | BibtexTokenKind::Comma + | BibtexTokenKind::Quote + | BibtexTokenKind::BeginBrace + | BibtexTokenKind::BeginParen + | BibtexTokenKind::EndParen => true, + BibtexTokenKind::Concat | BibtexTokenKind::EndBrace => false, + } + } else { + false + } + } + + fn expect1(&mut self, kind: BibtexTokenKind) -> Option<BibtexToken> { + if let Some(ref token) = self.tokens.peek() { + if token.kind == kind { + return self.tokens.next(); + } + } + None + } + + fn expect2(&mut self, kind1: BibtexTokenKind, kind2: BibtexTokenKind) -> Option<BibtexToken> { + if let Some(ref token) = self.tokens.peek() { + if token.kind == kind1 || token.kind == kind2 { + return self.tokens.next(); + } + } + None + } + + fn next_of_kind(&mut self, kind: BibtexTokenKind) -> bool { + if let Some(token) = self.tokens.peek() { + token.kind == kind + } else { + false + } + } +} |