about summary refs log tree commit diff
path: root/src/parse/parser.rs
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2021-10-18 20:37:57 +0200
committerMel <einebeere@gmail.com>2021-10-18 20:37:57 +0200
commit0f6f6068ebc33152f57658cf138df0622b44f6a2 (patch)
tree6c67ae6b88fcea74d1ac7105ebf121c2658ffa72 /src/parse/parser.rs
parent338bffe40ffea3f7cec94e8da8d96813b7f844ff (diff)
downloadrabbithole-0f6f6068ebc33152f57658cf138df0622b44f6a2.tar.zst
rabbithole-0f6f6068ebc33152f57658cf138df0622b44f6a2.zip
Basic expression parsing
Diffstat (limited to 'src/parse/parser.rs')
-rw-r--r--src/parse/parser.rs113
1 files changed, 113 insertions, 0 deletions
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
new file mode 100644
index 0000000..dc99262
--- /dev/null
+++ b/src/parse/parser.rs
@@ -0,0 +1,113 @@
+use crate::lex::token::Token;
+use crate::lex::token::TokenVariant;
+use crate::lex::token::TokenVariant::*;
+use crate::parse::ast::Expression;
+use anyhow::anyhow;
+use anyhow::Result;
+use std::iter::Peekable;
+
+pub struct Parser<T: Iterator> {
+    tokens: Peekable<T>,
+}
+
+impl<T: Iterator<Item = Token>> Parser<T> {
+    pub fn new(tokens: T) -> Self {
+        Parser {
+            tokens: tokens.peekable(),
+        }
+    }
+
+    pub fn parse(&mut self) -> Result<Expression> {
+        self.expression()
+    }
+
+    fn expression(&mut self) -> Result<Expression> {
+        self.term_expression()
+    }
+
+    fn term_expression(&mut self) -> Result<Expression> {
+        let mut left = self.factor_expression()?;
+
+        while matches!(
+            self.tokens.peek(),
+            Some(Token {
+                variant: OpPlus | OpMinus,
+                ..
+            })
+        ) {
+            let op = self.tokens.next().unwrap();
+            let right = self.factor_expression()?;
+
+            left = Expression::Binary {
+                left: Box::new(left),
+                op,
+                right: Box::new(right),
+            };
+        }
+
+        Ok(left)
+    }
+
+    fn factor_expression(&mut self) -> Result<Expression> {
+        let mut left = self.unary_expression()?;
+
+        while matches!(
+            self.tokens.peek(),
+            Some(Token {
+                variant: OpSlash | OpStar,
+                ..
+            })
+        ) {
+            let op = self.tokens.next().unwrap();
+            let right = self.unary_expression()?;
+
+            left = Expression::Binary {
+                left: Box::new(left),
+                op,
+                right: Box::new(right),
+            };
+        }
+
+        Ok(left)
+    }
+
+    fn unary_expression(&mut self) -> Result<Expression> {
+        let expression = if let Some(Token {
+            variant: OpPlus | OpMinus | OpNot,
+            ..
+        }) = self.tokens.peek()
+        {
+            Expression::Unary {
+                op: self.tokens.next().unwrap(),
+                right: Box::new(self.unary_expression()?),
+            }
+        } else {
+            self.unit_expression()?
+        };
+
+        Ok(expression)
+    }
+
+    fn unit_expression(&mut self) -> Result<Expression> {
+        if let Some(token) = self.tokens.next() {
+            match token.variant {
+                Int(_) | Float(_) => Ok(Expression::Literal(token)),
+                GroupOpen => {
+                    let expression = self.expression()?;
+                    if let Some(Token {
+                        variant: TokenVariant::GroupClose,
+                        ..
+                    }) = self.tokens.next()
+                    {
+                        Ok(Expression::Group(Box::new(expression)))
+                    } else {
+                        Err(anyhow!("Expected ')' after grouping."))
+                    }
+                }
+                _ => Err(anyhow!("Unexpected token: {:?}", token.variant)),
+            }
+        } else {
+            Err(anyhow!("Expected expression."))
+        }
+    }
+}