about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/interpret/mod.rs4
-rw-r--r--src/interpret/scope.rs45
-rw-r--r--src/interpret/value.rs181
-rw-r--r--src/interpret/walker.rs225
-rw-r--r--src/parse/ast/expression.rs38
-rw-r--r--src/parse/ast/mod.rs2
-rw-r--r--src/parse/ast/nodes.rs (renamed from src/parse/ast/value.rs)36
-rw-r--r--src/parse/ast/statement.rs2
-rw-r--r--src/parse/parser.rs33
9 files changed, 387 insertions, 179 deletions
diff --git a/src/interpret/mod.rs b/src/interpret/mod.rs
index 2544ca3..813f45d 100644
--- a/src/interpret/mod.rs
+++ b/src/interpret/mod.rs
@@ -1 +1,3 @@
-pub mod walker;
\ No newline at end of file
+mod scope;
+mod value;
+pub mod walker;
diff --git a/src/interpret/scope.rs b/src/interpret/scope.rs
new file mode 100644
index 0000000..de32692
--- /dev/null
+++ b/src/interpret/scope.rs
@@ -0,0 +1,45 @@
+use super::value::Value;
+use crate::parse::ast::nodes::Identifier;
+use std::collections::HashMap;
+
+pub struct Scope {
+    scopes: Vec<HashMap<Identifier, Value>>,
+}
+
+impl Scope {
+    pub fn new() -> Self {
+        Scope { scopes: Vec::new() }
+    }
+
+    pub fn nest(&mut self) {
+        self.scopes.push(HashMap::new());
+    }
+
+    pub fn unnest(&mut self) {
+        self.scopes.pop();
+    }
+
+    pub fn set_var(&mut self, ident: &Identifier, value: Value) {
+        for scope in self.scopes.iter_mut() {
+            if scope.contains_key(ident) {
+                scope.insert(ident.clone(), value);
+                return;
+            }
+        }
+
+        let inner_scope = self
+            .scopes
+            .last_mut()
+            .expect("Tried accessing scope after last frame is gone.");
+        inner_scope.insert(ident.clone(), value);
+    }
+
+    pub fn get_var(&self, ident: &Identifier) -> Option<Value> {
+        for scope in self.scopes.iter().rev() {
+            if let Some(value) = scope.get(ident) {
+                return Some(value.clone());
+            }
+        }
+        None
+    }
+}
diff --git a/src/interpret/value.rs b/src/interpret/value.rs
new file mode 100644
index 0000000..0c7843c
--- /dev/null
+++ b/src/interpret/value.rs
@@ -0,0 +1,181 @@
+use crate::parse::ast::nodes::FnNode;
+use anyhow::{anyhow, Result};
+use std::{cell::RefCell, rc::Rc};
+
+type Ref<T> = RefCell<Rc<T>>;
+
+#[derive(Clone, Debug)]
+pub enum Value {
+    Str(String),
+    Float(f64),
+    Int(i64),
+    Fn(Ref<FnNode>),
+    Void,
+}
+
+impl Value {
+    pub fn add(self, rhs: Value) -> Result<Value> {
+        match self {
+            Value::Str(l) => match rhs {
+                Value::Str(r) => Ok(Value::Str(l + &r)),
+                Value::Float(r) => Ok(Value::Str(l + &r.to_string())),
+                Value::Int(r) => Ok(Value::Str(l + &r.to_string())),
+                _ => Err(anyhow!("Right operand can't be added.")),
+            },
+            Value::Float(l) => match rhs {
+                Value::Str(r) => Ok(Value::Str(l.to_string() + &r)),
+                Value::Float(r) => Ok(Value::Float(l + r)),
+                Value::Int(r) => Ok(Value::Float(l + r as f64)),
+                _ => Err(anyhow!("Right operand can't be added.")),
+            },
+            Value::Int(l) => match rhs {
+                Value::Str(r) => Ok(Value::Str(l.to_string() + &r)),
+                Value::Float(r) => Ok(Value::Float(l as f64 + r)),
+                Value::Int(r) => Ok(Value::Int(l + r)),
+                _ => Err(anyhow!("Right operand can't be added.")),
+            },
+            _ => Err(anyhow!("Left operand can't be added.")),
+        }
+    }
+
+    pub fn sub(self, rhs: Value) -> Result<Value> {
+        match self {
+            Value::Float(l) => match rhs {
+                Value::Float(r) => Ok(Value::Float(l - r)),
+                Value::Int(r) => Ok(Value::Float(l - r as f64)),
+                _ => Err(anyhow!("Right operand can't be substracted.")),
+            },
+            Value::Int(l) => match rhs {
+                Value::Float(r) => Ok(Value::Float(l as f64 - r)),
+                Value::Int(r) => Ok(Value::Int(l - r)),
+                _ => Err(anyhow!("Right operand can't be substracted.")),
+            },
+            _ => Err(anyhow!("Left operand can't be substracted from.")),
+        }
+    }
+
+    pub fn mul(self, rhs: Value) -> Result<Value> {
+        match self {
+            Value::Float(l) => match rhs {
+                Value::Float(r) => Ok(Value::Float(l * r)),
+                Value::Int(r) => Ok(Value::Float(l * r as f64)),
+                _ => Err(anyhow!("Right operand can't be multiplied.")),
+            },
+            Value::Int(l) => match rhs {
+                Value::Float(r) => Ok(Value::Float(l as f64 * r)),
+                Value::Int(r) => Ok(Value::Int(l * r)),
+                _ => Err(anyhow!("Right operand can't be multiplied.")),
+            },
+            _ => Err(anyhow!("Left operand can't be multiplied.")),
+        }
+    }
+
+    pub fn div(self, rhs: Value) -> Result<Value> {
+        match self {
+            Value::Float(l) => match rhs {
+                Value::Float(r) => Ok(Value::Float(l / r)),
+                Value::Int(r) => Ok(Value::Float(l / r as f64)),
+                _ => Err(anyhow!("Right operand can't be multiplied.")),
+            },
+            Value::Int(l) => match rhs {
+                Value::Float(r) => Ok(Value::Float(l as f64 / r)),
+                Value::Int(r) => Ok(Value::Float(l as f64 / r as f64)),
+                _ => Err(anyhow!("Right operand can't be multiplied.")),
+            },
+            _ => Err(anyhow!("Left operand can't be multiplied.")),
+        }
+    }
+}
+
+// pub enum Value {
+//     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::Float(int as f64 / other_int as f64),
+//             },
+//         }
+//     }
+// }
+
+// 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/interpret/walker.rs b/src/interpret/walker.rs
index 817e94e..576cfb5 100644
--- a/src/interpret/walker.rs
+++ b/src/interpret/walker.rs
@@ -1,161 +1,138 @@
-use std::{
-    fmt::Display,
-    ops::{Add, Div, Mul, Neg, Sub},
-};
+use std::{cell::RefCell, rc::Rc};
 
 use crate::parse::ast::{
     expression::Expression,
-    value::{BinaryOperator, Literal, UnaryOperator},
+    nodes::{BinaryOperator as BinOp, Literal, UnaryOperator as UnOp},
+    statement::Statement,
+    Program,
 };
-use anyhow::Result;
+use anyhow::{anyhow, Result};
+
+use super::{scope::Scope, value::Value};
 
 // No state for now.
-pub struct Walker {}
+pub struct Walker {
+    scope: Scope,
+}
 
 impl Walker {
     pub fn new() -> Self {
-        Walker {}
+        Walker {
+            scope: Scope::new(),
+        }
     }
 
-    pub fn walk(&self, node: &Expression) -> Result<WalkValue> {
+    pub fn walk(&mut self, program: &Program) {
+        self.scope.nest();
+        for statement in program.statements.iter() {
+            self.walk_statement(statement).expect("Runtime error.");
+        }
+    }
+
+    fn walk_statement(&mut self, statement: &Statement) -> Result<Option<Value>> {
+        let result = match statement {
+            Statement::Expression(node) => {
+                self.walk_expression(node)?;
+                None
+            }
+            Statement::Print(node) => {
+                let result = self.walk_expression(node)?;
+                println!("{:?}", result);
+                None
+            }
+            Statement::Return(node) => Some(self.walk_expression(node)?),
+        };
+
+        Ok(result)
+    }
+
+    fn walk_expression(&mut self, node: &Expression) -> Result<Value> {
         match node {
             Expression::Binary { left, op, right } => {
-                let left_value = self.walk(left)?;
-                let right_value = self.walk(right)?;
-
                 let new_value = match op {
-                    BinaryOperator::Plus => left_value + right_value,
-                    BinaryOperator::Minus => left_value - right_value,
-                    BinaryOperator::Star => left_value * right_value,
-                    BinaryOperator::Slash => left_value / right_value,
-                    BinaryOperator::Eq => todo!(),
-                    BinaryOperator::Neq => todo!(),
-                    BinaryOperator::Gt => todo!(),
-                    BinaryOperator::Gte => todo!(),
-                    BinaryOperator::Lt => todo!(),
-                    BinaryOperator::Lte => todo!(),
-                    BinaryOperator::Assign => todo!(),
-                    BinaryOperator::ConstAssign => todo!(),
-                    BinaryOperator::Dot => todo!(),
-                };
+                    BinOp::Plus => self
+                        .walk_expression(left)?
+                        .add(self.walk_expression(right)?),
+                    BinOp::Minus => self
+                        .walk_expression(left)?
+                        .sub(self.walk_expression(right)?),
+                    BinOp::Star => self
+                        .walk_expression(left)?
+                        .mul(self.walk_expression(right)?),
+                    BinOp::Slash => self
+                        .walk_expression(left)?
+                        .div(self.walk_expression(right)?),
+                    // No difference between assignments for now.
+                    BinOp::Assign | BinOp::ConstAssign => {
+                        let identifier = match left.as_ref() {
+                            Expression::Identifier(i) => i,
+                            _ => todo!("Lvalues can only be identifiers."),
+                        };
+
+                        let value = self.walk_expression(right)?;
+                        self.scope.set_var(identifier, value.clone());
+                        Ok(value)
+                    }
+                    // Boolean logic comes later.
+                    BinOp::Eq | BinOp::Neq | BinOp::Gt | BinOp::Gte | BinOp::Lt | BinOp::Lte => {
+                        todo!()
+                    }
+                    // No structure access yet.
+                    BinOp::Dot => todo!(),
+                }?;
 
                 Ok(new_value)
             }
             Expression::Unary { op, right } => {
-                let value = self.walk(right)?;
+                let value = self.walk_expression(right)?;
 
                 let new_value = match op {
-                    UnaryOperator::Plus => value,
-                    UnaryOperator::Minus => -value,
-                    UnaryOperator::Not => todo!("Implement boolean arithmetic."),
+                    UnOp::Plus => value,
+                    UnOp::Minus => todo!(),
+                    UnOp::Not => todo!("Implement boolean arithmetic."),
                 };
 
                 Ok(new_value)
             }
-            Expression::Group(node) => self.walk(node),
+            Expression::Group(node) => self.walk_expression(node),
             Expression::Literal(token) => {
                 let value = match token {
-                    Literal::Int(int) => WalkValue::Int(*int as i64),
-                    Literal::Float(float) => WalkValue::Float(*float as f64),
-                    _ => todo!(),
+                    Literal::Int(int) => Value::Int(*int as i64),
+                    Literal::Float(float) => Value::Float(*float as f64),
+                    Literal::Str(string) => Value::Str(string.clone()),
                 };
 
                 Ok(value)
             }
-            _ => todo!(),
-        }
-    }
-}
+            Expression::Block(block) => {
+                self.scope.nest();
 
-pub enum WalkValue {
-    Float(f64),
-    Int(i64),
-}
+                for statement in block.statements.iter() {
+                    self.walk_statement(statement)?;
+                }
 
-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::Float(int as f64 / other_int as f64),
-            },
-        }
-    }
-}
-
-impl Neg for WalkValue {
-    type Output = Self;
+                let result = if let Some(tail_expression) = &block.tail_expression {
+                    Ok(self.walk_expression(tail_expression)?)
+                } else {
+                    Ok(Value::Void)
+                };
 
-    fn neg(self) -> Self::Output {
-        match self {
-            Self::Float(float) => Self::Float(-float),
-            Self::Int(int) => Self::Int(-int),
-        }
-    }
-}
+                self.scope.unnest();
 
-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),
+                result
+            }
+            Expression::Fn(fn_node) => {
+                let node = fn_node.as_ref().clone();
+                Ok(Value::Fn(RefCell::new(Rc::new(node))))
+            }
+            Expression::If(_) => todo!(),
+            Expression::Identifier(ident) => {
+                if let Some(value) = self.scope.get_var(ident) {
+                    Ok(value)
+                } else {
+                    Err(anyhow!("Unknown identifier: {}.", ident))
+                }
+            }
         }
     }
 }
diff --git a/src/parse/ast/expression.rs b/src/parse/ast/expression.rs
index 8563492..1749c40 100644
--- a/src/parse/ast/expression.rs
+++ b/src/parse/ast/expression.rs
@@ -1,10 +1,8 @@
 use std::fmt::{self, Display, Formatter};
 
-use super::value::{
-    BinaryOperator, Block, ConditionalBlock, FnHeader, Identifier, Literal, UnaryOperator,
-};
+use super::nodes::{BinaryOperator, BlockNode, FnNode, Identifier, IfNode, Literal, UnaryOperator};
 
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub enum Expression {
     Binary {
         left: Box<Expression>,
@@ -16,15 +14,9 @@ pub enum Expression {
         right: Box<Expression>,
     },
     Group(Box<Expression>),
-    Block(Box<Block>),
-    Fn {
-        header: FnHeader,
-        body: Box<Block>,
-    },
-    If {
-        conditionals: Vec<ConditionalBlock>,
-        else_block: Option<Box<Block>>,
-    },
+    Block(Box<BlockNode>),
+    Fn(Box<FnNode>),
+    If(Box<IfNode>),
     Literal(Literal),
     Identifier(Identifier),
 }
@@ -60,16 +52,16 @@ impl Expression {
             Expression::Block(block) => {
                 Self::block_fmt(f, block, depth + 1)?;
             }
-            Expression::Fn { header, body } => {
+            Expression::Fn(node) => {
                 write!(f, "{}Fn (", pad)?;
 
                 // Write self receiver
-                if header.has_self_receiver {
+                if node.header.has_self_receiver {
                     write!(f, "self, ")?;
                 }
 
                 // Write parameters
-                for p in header.parameters.iter() {
+                for p in node.header.parameters.iter() {
                     write!(
                         f,
                         "{}: {}, ",
@@ -82,9 +74,9 @@ impl Expression {
                 writeln!(
                     f,
                     ") -> {}:",
-                    header.return_type.as_ref().unwrap_or(&"_".into())
+                    node.header.return_type.as_ref().unwrap_or(&"_".into())
                 )?;
-                Self::block_fmt(f, body, depth + 1)?;
+                Self::block_fmt(f, &node.body, depth + 1)?;
             }
             Expression::Literal(literal) => {
                 writeln!(f, "{}Literal: {:?}", pad, literal)?;
@@ -92,25 +84,25 @@ impl Expression {
             Expression::Identifier(identifier) => {
                 writeln!(f, "{}Identifier: {:?}", pad, identifier)?;
             }
-            Expression::If { conditionals, else_block } => {
+            Expression::If(node) => {
                 writeln!(f, "{}If:", pad)?;
-                for (i, c) in conditionals.iter().enumerate() {
+                for (i, c) in node.conditionals.iter().enumerate() {
                     writeln!(f, "{}- Condition {}:", pad, i)?;
                     c.condition.nested_fmt(f, depth + 1)?;
                     writeln!(f, "{}- Body {}:", pad, i)?;
                     Self::block_fmt(f, &c.block, depth + 1)?;
                 }
-                if let Some(e) = else_block {
+                if let Some(e) = &node.else_block {
                     writeln!(f, "{}- Else:", pad)?;
                     Self::block_fmt(f, e, depth + 1)?;
                 }
-            },
+            }
         }
 
         Ok(())
     }
 
-    fn block_fmt(f: &mut Formatter<'_>, block: &Block, depth: usize) -> fmt::Result {
+    fn block_fmt(f: &mut Formatter<'_>, block: &BlockNode, depth: usize) -> fmt::Result {
         let pad = "  ".repeat(depth);
         writeln!(f, "{}Block:", pad)?;
         for (i, statement) in block.statements.iter().enumerate() {
diff --git a/src/parse/ast/mod.rs b/src/parse/ast/mod.rs
index 257675f..93944b2 100644
--- a/src/parse/ast/mod.rs
+++ b/src/parse/ast/mod.rs
@@ -4,7 +4,7 @@ use self::statement::Statement;
 
 pub mod expression;
 pub mod statement;
-pub mod value;
+pub mod nodes;
 
 #[derive(Debug)]
 pub struct Program {
diff --git a/src/parse/ast/value.rs b/src/parse/ast/nodes.rs
index 263cb58..2347d5b 100644
--- a/src/parse/ast/value.rs
+++ b/src/parse/ast/nodes.rs
@@ -2,7 +2,7 @@ use crate::lex::token::{Token, TokenVariant::*};
 
 use super::{expression::Expression, statement::Statement};
 
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
 pub enum BinaryOperator {
     Plus,
     Minus,
@@ -35,12 +35,12 @@ impl BinaryOperator {
             Assign => Self::Assign,
             ConstAssign => Self::ConstAssign,
             Dot => Self::Dot,
-            _ => panic!("Can't create binary operator from '{:?}'.", token.variant)
+            _ => panic!("Can't create binary operator from '{:?}'.", token.variant),
         }
     }
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone, Copy)]
 pub enum UnaryOperator {
     Plus,
     Minus,
@@ -53,12 +53,12 @@ impl UnaryOperator {
             OpPlus => Self::Plus,
             OpMinus => Self::Minus,
             OpNot => Self::Not,
-            _ => panic!("Can't create unary operator from '{:?}'.", token.variant)
+            _ => panic!("Can't create unary operator from '{:?}'.", token.variant),
         }
     }
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub enum Literal {
     Int(u32),
     Float(f32),
@@ -71,7 +71,7 @@ impl Literal {
             Int(int) => Self::Int(int),
             Float(float) => Self::Float(float),
             Str(string) => Self::Str(string),
-            _ => panic!("Can't create literal from '{:?}'.", token.variant)
+            _ => panic!("Can't create literal from '{:?}'.", token.variant),
         }
     }
 }
@@ -80,27 +80,39 @@ pub type Identifier = String;
 
 // If the contraint is None the type will have to be inferred
 // during analysis.
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub struct TypedIdentifier {
     pub identifier: Identifier,
     pub type_constraint: Option<Identifier>,
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone)]
+pub struct FnNode {
+    pub header: FnHeader,
+    pub body: BlockNode,
+}
+
+#[derive(Debug, Clone)]
 pub struct FnHeader {
     pub has_self_receiver: bool,
     pub parameters: Vec<TypedIdentifier>,
     pub return_type: Option<Identifier>,
 }
 
-#[derive(Debug)]
-pub struct Block {
+#[derive(Debug, Clone)]
+pub struct IfNode {
+    pub conditionals: Vec<ConditionalBlock>,
+    pub else_block: Option<BlockNode>,
+}
+
+#[derive(Debug, Clone)]
+pub struct BlockNode {
     pub statements: Vec<Statement>,
     pub tail_expression: Option<Expression>,
 }
 
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub struct ConditionalBlock {
     pub condition: Expression,
-    pub block: Block,
+    pub block: BlockNode,
 }
diff --git a/src/parse/ast/statement.rs b/src/parse/ast/statement.rs
index eec589e..b0e626d 100644
--- a/src/parse/ast/statement.rs
+++ b/src/parse/ast/statement.rs
@@ -2,7 +2,7 @@ use std::fmt::Display;
 
 use super::expression::Expression;
 
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 pub enum Statement {
     Expression(Expression),
     Print(Expression),
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 0316a35..0e865da 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -1,6 +1,6 @@
 use super::ast::expression::Expression;
+use super::ast::nodes::UnaryOperator;
 use super::ast::statement::Statement;
-use super::ast::value::UnaryOperator;
 use super::ast::Program;
 use crate::check;
 use crate::consume;
@@ -8,12 +8,14 @@ use crate::consume_if;
 use crate::inner;
 use crate::lex::token::Token;
 use crate::lex::token::TokenVariant::*;
-use crate::parse::ast::value::BinaryOperator;
-use crate::parse::ast::value::Block;
-use crate::parse::ast::value::ConditionalBlock;
-use crate::parse::ast::value::FnHeader;
-use crate::parse::ast::value::Literal;
-use crate::parse::ast::value::TypedIdentifier;
+use crate::parse::ast::nodes::BinaryOperator;
+use crate::parse::ast::nodes::BlockNode;
+use crate::parse::ast::nodes::ConditionalBlock;
+use crate::parse::ast::nodes::FnHeader;
+use crate::parse::ast::nodes::FnNode;
+use crate::parse::ast::nodes::IfNode;
+use crate::parse::ast::nodes::Literal;
+use crate::parse::ast::nodes::TypedIdentifier;
 use anyhow::anyhow;
 use anyhow::Result;
 use std::iter::Peekable;
@@ -203,10 +205,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
 
                     let body = self.block()?;
 
-                    Ok(Expression::Fn {
-                        header,
-                        body: Box::new(body),
-                    })
+                    Ok(Expression::Fn(Box::new(FnNode { header, body })))
                 }
                 KeywordIf => {
                     consume!(self, KeywordIf)?;
@@ -232,16 +231,16 @@ impl<T: Iterator<Item = Token>> Parser<T> {
                         });
                     }
 
-                    let else_conditional = if consume_if!(self, KeywordElse).is_some() {
+                    let else_block = if consume_if!(self, KeywordElse).is_some() {
                         Some(self.block()?)
                     } else {
                         None
                     };
 
-                    Ok(Expression::If {
+                    Ok(Expression::If(Box::new(IfNode {
                         conditionals,
-                        else_block: else_conditional.map(Box::new),
-                    })
+                        else_block,
+                    })))
                 }
                 _ => Err(anyhow!("Unexpected token: {:?}", token.variant)),
             }
@@ -250,7 +249,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         }
     }
 
-    fn block(&mut self) -> Result<Block> {
+    fn block(&mut self) -> Result<BlockNode> {
         consume!(self, BlockOpen)?;
 
         let mut statements = Vec::new();
@@ -279,7 +278,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
 
         consume!(self, BlockClose)?;
 
-        Ok(Block {
+        Ok(BlockNode {
             statements,
             tail_expression,
         })