aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2021-10-18 21:28:52 +0200
committerMel <einebeere@gmail.com>2021-10-18 21:28:52 +0200
commit0881af52f16dc0b6a3900180cce5187d27373901 (patch)
treec5501fdb4597bab6f1c24e0a138ff078794ebe4e
parent0f6f6068ebc33152f57658cf138df0622b44f6a2 (diff)
downloadrabbithole-0881af52f16dc0b6a3900180cce5187d27373901.tar.zst
rabbithole-0881af52f16dc0b6a3900180cce5187d27373901.zip
Simple AST walker.
-rw-r--r--src/interpret/mod.rs1
-rw-r--r--src/interpret/walker.rs150
-rw-r--r--src/main.rs10
3 files changed, 159 insertions, 2 deletions
diff --git a/src/interpret/mod.rs b/src/interpret/mod.rs
new file mode 100644
index 0000000..2544ca3
--- /dev/null
+++ b/src/interpret/mod.rs
@@ -0,0 +1 @@
+pub mod walker; \ No newline at end of file
diff --git a/src/interpret/walker.rs b/src/interpret/walker.rs
new file mode 100644
index 0000000..1602cd2
--- /dev/null
+++ b/src/interpret/walker.rs
@@ -0,0 +1,150 @@
+use std::{
+ fmt::Display,
+ ops::{Add, Div, Mul, Neg, Sub},
+};
+
+use crate::{lex::token::TokenVariant::*, parse::ast::Expression};
+use anyhow::Result;
+
+// No state for now.
+pub struct Walker {}
+
+impl Walker {
+ pub fn new() -> Self {
+ Walker {}
+ }
+
+ pub fn walk(&self, node: &Expression) -> Result<WalkValue> {
+ match node {
+ Expression::Binary { left, op, right } => {
+ let left_value = self.walk(left)?;
+ let right_value = self.walk(right)?;
+
+ let new_value = match op.variant {
+ OpPlus => left_value + right_value,
+ OpMinus => left_value - right_value,
+ OpStar => left_value * right_value,
+ OpSlash => left_value / right_value,
+ _ => unreachable!(),
+ };
+
+ Ok(new_value)
+ }
+ Expression::Unary { op, right } => {
+ let value = self.walk(right)?;
+
+ let new_value = match op.variant {
+ OpPlus => value,
+ OpMinus => -value,
+ OpNot => todo!("Implement boolean arithmetic."),
+ _ => unreachable!(),
+ };
+
+ Ok(new_value)
+ }
+ Expression::Group(node) => self.walk(node),
+ Expression::Literal(token) => {
+ let value = match token.variant {
+ Int(int) => WalkValue::Int(int as i64),
+ Float(float) => WalkValue::Float(float as f64),
+ _ => unreachable!(),
+ };
+
+ Ok(value)
+ }
+ }
+ }
+}
+
+pub enum WalkValue {
+ Float(f64),
+ Int(i64),
+}
+
+impl Add for WalkValue {
+ type Output = Self;
+
+ fn add(self, rhs: Self) -> Self::Output {
+ match self {
+ Self::Float(float) => match rhs {
+ Self::Float(other_float) => Self::Float(float + other_float),
+ Self::Int(other_int) => Self::Float(float + other_int as f64),
+ },
+ Self::Int(int) => match rhs {
+ Self::Float(other_float) => Self::Float(int as f64 + other_float),
+ Self::Int(other_int) => Self::Int(int + other_int),
+ },
+ }
+ }
+}
+
+impl Sub for WalkValue {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Self::Output {
+ match self {
+ Self::Float(float) => match rhs {
+ Self::Float(other_float) => Self::Float(float - other_float),
+ Self::Int(other_int) => Self::Float(float - other_int as f64),
+ },
+ Self::Int(int) => match rhs {
+ Self::Float(other_float) => Self::Float(int as f64 - other_float),
+ Self::Int(other_int) => Self::Int(int - other_int),
+ },
+ }
+ }
+}
+
+impl Mul for WalkValue {
+ type Output = Self;
+
+ fn mul(self, rhs: Self) -> Self::Output {
+ match self {
+ Self::Float(float) => match rhs {
+ Self::Float(other_float) => Self::Float(float * other_float),
+ Self::Int(other_int) => Self::Float(float * other_int as f64),
+ },
+ Self::Int(int) => match rhs {
+ Self::Float(other_float) => Self::Float(int as f64 * other_float),
+ Self::Int(other_int) => Self::Int(int * other_int),
+ },
+ }
+ }
+}
+
+impl Div for WalkValue {
+ type Output = Self;
+
+ fn div(self, rhs: Self) -> Self::Output {
+ match self {
+ Self::Float(float) => match rhs {
+ Self::Float(other_float) => Self::Float(float / other_float),
+ Self::Int(other_int) => Self::Float(float / other_int as f64),
+ },
+ Self::Int(int) => match rhs {
+ Self::Float(other_float) => Self::Float(int as f64 / other_float),
+ Self::Int(other_int) => Self::Int(int / other_int),
+ },
+ }
+ }
+}
+
+impl Neg for WalkValue {
+ type Output = Self;
+
+ fn neg(self) -> Self::Output {
+ match self {
+ Self::Float(float) => Self::Float(-float),
+ Self::Int(int) => Self::Int(-int),
+ }
+ }
+}
+
+impl Display for WalkValue {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Self::Float(float) => write!(f, "{}", float),
+ Self::Int(int) => write!(f, "{}", int),
+ }
+ }
+}
diff --git a/src/main.rs b/src/main.rs
index 3fa6bbf..1825af5 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,9 +1,11 @@
+mod interpret;
mod lex;
mod parse;
use lex::lexer::Lexer;
-use crate::parse::parser::Parser;
+use interpret::walker::Walker;
+use parse::parser::Parser;
fn main() {
let source = "1 * 2 + 3 + (-1)";
@@ -11,5 +13,9 @@ fn main() {
let lexer = Lexer::new(source);
let mut parser = Parser::new(lexer);
- println!("{}", parser.parse().expect("Failed parsing."));
+ let node = parser.parse().expect("Failed parsing.");
+
+ let walker = Walker::new();
+ let result = walker.walk(&node).expect("Failed interpreting.");
+ println!("{}", result);
}