summaryrefslogtreecommitdiff
path: root/support/texlab/src/syntax/latex/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'support/texlab/src/syntax/latex/parser.rs')
-rw-r--r--support/texlab/src/syntax/latex/parser.rs135
1 files changed, 135 insertions, 0 deletions
diff --git a/support/texlab/src/syntax/latex/parser.rs b/support/texlab/src/syntax/latex/parser.rs
new file mode 100644
index 0000000000..40693071c2
--- /dev/null
+++ b/support/texlab/src/syntax/latex/parser.rs
@@ -0,0 +1,135 @@
+use super::ast::*;
+use std::iter::Peekable;
+use std::sync::Arc;
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+enum LatexScope {
+ Root,
+ Group,
+ Options,
+}
+
+pub struct LatexParser<I: Iterator<Item = LatexToken>> {
+ tokens: Peekable<I>,
+}
+
+impl<I: Iterator<Item = LatexToken>> LatexParser<I> {
+ pub fn new(tokens: I) -> Self {
+ LatexParser {
+ tokens: tokens.peekable(),
+ }
+ }
+
+ pub fn root(&mut self) -> LatexRoot {
+ let children = self.content(LatexScope::Root);
+ LatexRoot::new(children)
+ }
+
+ fn content(&mut self, scope: LatexScope) -> Vec<LatexContent> {
+ let mut children = Vec::new();
+ while let Some(ref token) = self.tokens.peek() {
+ match token.kind {
+ LatexTokenKind::Word | LatexTokenKind::BeginOptions => {
+ children.push(LatexContent::Text(self.text(scope)));
+ }
+ LatexTokenKind::Command => {
+ children.push(LatexContent::Command(self.command()));
+ }
+ LatexTokenKind::Comma => {
+ let node = LatexComma::new(self.tokens.next().unwrap());
+ children.push(LatexContent::Comma(Arc::new(node)));
+ }
+ LatexTokenKind::Math => {
+ children.push(LatexContent::Math(self.math()));
+ }
+ LatexTokenKind::BeginGroup => {
+ children.push(LatexContent::Group(self.group(LatexGroupKind::Group)));
+ }
+ LatexTokenKind::EndGroup => {
+ if scope == LatexScope::Root {
+ self.tokens.next();
+ } else {
+ return children;
+ }
+ }
+ LatexTokenKind::EndOptions => {
+ if scope == LatexScope::Options {
+ return children;
+ } else {
+ children.push(LatexContent::Text(self.text(scope)));
+ }
+ }
+ }
+ }
+ children
+ }
+
+ fn command(&mut self) -> Arc<LatexCommand> {
+ let name = self.tokens.next().unwrap();
+
+ let mut options = Vec::new();
+ let mut args = Vec::new();
+ while let Some(token) = self.tokens.peek() {
+ match token.kind {
+ LatexTokenKind::BeginGroup => {
+ args.push(self.group(LatexGroupKind::Group));
+ }
+ LatexTokenKind::BeginOptions => {
+ options.push(self.group(LatexGroupKind::Options));
+ }
+ _ => {
+ break;
+ }
+ }
+ }
+ Arc::new(LatexCommand::new(name, options, args))
+ }
+
+ fn group(&mut self, kind: LatexGroupKind) -> Arc<LatexGroup> {
+ let left = self.tokens.next().unwrap();
+ let scope = match kind {
+ LatexGroupKind::Group => LatexScope::Group,
+ LatexGroupKind::Options => LatexScope::Options,
+ };
+ let children = self.content(scope);
+ let right_kind = match kind {
+ LatexGroupKind::Group => LatexTokenKind::EndGroup,
+ LatexGroupKind::Options => LatexTokenKind::EndOptions,
+ };
+
+ let right = if self.next_of_kind(right_kind) {
+ self.tokens.next()
+ } else {
+ None
+ };
+
+ Arc::new(LatexGroup::new(left, children, right, kind))
+ }
+
+ fn text(&mut self, scope: LatexScope) -> Arc<LatexText> {
+ let mut words = Vec::new();
+ while let Some(ref token) = self.tokens.peek() {
+ let kind = token.kind;
+ let opts = kind == LatexTokenKind::EndOptions && scope != LatexScope::Options;
+ if kind == LatexTokenKind::Word || kind == LatexTokenKind::BeginOptions || opts {
+ words.push(self.tokens.next().unwrap());
+ } else {
+ break;
+ }
+ }
+ Arc::new(LatexText::new(words))
+ }
+
+ fn math(&mut self) -> Arc<LatexMath> {
+ let token = self.tokens.next().unwrap();
+ Arc::new(LatexMath::new(token))
+ }
+
+ fn next_of_kind(&mut self, kind: LatexTokenKind) -> bool {
+ if let Some(ref token) = self.tokens.peek() {
+ token.kind == kind
+ } else {
+ false
+ }
+ }
+}