about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--grammar.ebnf12
-rw-r--r--src/interpret/walker.rs43
-rw-r--r--src/lex/lexer.rs7
-rw-r--r--src/lex/token.rs10
-rw-r--r--src/parse/ast.rs55
-rw-r--r--src/parse/ast/expression.rs127
-rw-r--r--src/parse/ast/mod.rs21
-rw-r--r--src/parse/ast/statement.rs39
-rw-r--r--src/parse/ast/value.rs106
-rw-r--r--src/parse/macros.rs59
-rw-r--r--src/parse/mod.rs1
-rw-r--r--src/parse/parser.rs252
12 files changed, 612 insertions, 120 deletions
diff --git a/grammar.ebnf b/grammar.ebnf
index 425c64a..d99f268 100644
--- a/grammar.ebnf
+++ b/grammar.ebnf
@@ -25,7 +25,7 @@ UnaryExpression = ( "-" | "!" ) UnaryExpression | UnitExpression ;
                 
 (* Unaffected Expressions *)
 
-UnitExpression = FLOAT | INT | STR | GroupExpression | BlockExpression | FnExpression | | TypeExpression | FormExpression | IfExpression;
+UnitExpression = FLOAT | INT | STR | GroupExpression | BlockExpression | FnExpression | TypeExpression | FormExpression | IfExpression;
 
 GroupExpression = "(" Expression ")";
 BlockExpression = Block;
@@ -37,16 +37,14 @@ IfExpression = "if" Expression Block { "elif" Expression Block } [ "else" Block
 
 (* Parts *)
 
-FnHeader = (FnSingleParameter | FnMultipleParameters) ["->" Type];
-FnSingleParameter = "self" | FnParameter;
-FnMultipleParameters = "(" FnSingleParameter { "," FnParameter} ")";
-FnParameter = IdentiferType;
+FnHeader = (FnParameters) ["->" Type];
+FnParameters = ("self" | FnParameter) { "," FnParameter};
 
 (* Utils *)
 
 Block = "{" { Statement } [Expression] "}";
-TypeBlock = "{" [ IdentiferType ] { "," IdentiferType } "}";
+TypeBlock = "{" [ TypedIdentifier ] { "," TypedIdentifier } "}";
 
-IdentiferType = IDENTIFIER ":" Type;
+TypedIdentifier = IDENTIFIER [":" Type];
 (* NOTE: Type doesn't include anything other than simple named types for now. *)
 Type = IDENTIFIER;
diff --git a/src/interpret/walker.rs b/src/interpret/walker.rs
index e301d44..817e94e 100644
--- a/src/interpret/walker.rs
+++ b/src/interpret/walker.rs
@@ -3,7 +3,10 @@ use std::{
     ops::{Add, Div, Mul, Neg, Sub},
 };
 
-use crate::{lex::token::TokenVariant::*, parse::ast::Expression};
+use crate::parse::ast::{
+    expression::Expression,
+    value::{BinaryOperator, Literal, UnaryOperator},
+};
 use anyhow::Result;
 
 // No state for now.
@@ -20,12 +23,20 @@ impl Walker {
                 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!(),
+                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!(),
                 };
 
                 Ok(new_value)
@@ -33,25 +44,25 @@ impl Walker {
             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!(),
+                let new_value = match op {
+                    UnaryOperator::Plus => value,
+                    UnaryOperator::Minus => -value,
+                    UnaryOperator::Not => todo!("Implement boolean arithmetic."),
                 };
 
                 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!(),
+                let value = match token {
+                    Literal::Int(int) => WalkValue::Int(*int as i64),
+                    Literal::Float(float) => WalkValue::Float(*float as f64),
+                    _ => todo!(),
                 };
 
                 Ok(value)
             }
+            _ => todo!(),
         }
     }
 }
diff --git a/src/lex/lexer.rs b/src/lex/lexer.rs
index 6e188a0..b6fee0d 100644
--- a/src/lex/lexer.rs
+++ b/src/lex/lexer.rs
@@ -181,10 +181,15 @@ impl<'s> Lexer<'s> {
 
         let variant = match buffer.as_str() {
             "fn" => TokenVariant::KeywordFn,
+            "if" => TokenVariant::KeywordIf,
+            "elif" => TokenVariant::KeywordElif,
+            "else" => TokenVariant::KeywordElse,
             "type" => TokenVariant::KeywordType,
             "form" => TokenVariant::KeywordForm,
             "self" => TokenVariant::KeywordSelf,
-            _ => TokenVariant::Identifier(buffer),
+            "return" => TokenVariant::KeywordReturn,
+            "print" => TokenVariant::KeywordPrint,
+            _ => TokenVariant::Ident(buffer),
         };
 
         Token { location, variant }
diff --git a/src/lex/token.rs b/src/lex/token.rs
index 3694525..efd4c5a 100644
--- a/src/lex/token.rs
+++ b/src/lex/token.rs
@@ -10,7 +10,7 @@ pub struct Token {
     pub variant: TokenVariant,
 }
 
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub enum TokenVariant {
     // Basic math operators
     OpPlus,
@@ -45,13 +45,19 @@ pub enum TokenVariant {
     Int(u32),
     Float(f32),
     Str(String),
-    Identifier(String),
+
+    Ident(String),
 
     // Keywords
     KeywordFn,
+    KeywordIf,
+    KeywordElif,
+    KeywordElse,
     KeywordForm,
     KeywordType,
     KeywordSelf,
+    KeywordReturn,
+    KeywordPrint,
 
     Unknown(char),
     Eof,
diff --git a/src/parse/ast.rs b/src/parse/ast.rs
deleted file mode 100644
index 0f7ea34..0000000
--- a/src/parse/ast.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-use std::fmt::Display;
-
-use crate::lex::token::Token;
-
-#[derive(Debug)]
-pub enum Expression {
-    Binary {
-        left: Box<Expression>,
-        op: Token,
-        right: Box<Expression>,
-    },
-    Unary {
-        op: Token,
-        right: Box<Expression>,
-    },
-    Group(Box<Expression>),
-    Literal(Token),
-}
-
-impl Display for Expression {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        self.nested_fmt(f, 0)
-    }
-}
-
-impl Expression {
-    fn nested_fmt(&self, f: &mut std::fmt::Formatter<'_>, depth: usize) -> std::fmt::Result {
-        let pad = "  ".repeat(depth);
-        match self {
-            Expression::Binary { left, op, right } => {
-                writeln!(f, "{}Binary:", pad)?;
-                writeln!(f, "{}- Left:", pad)?;
-                left.nested_fmt(f, depth + 1)?;
-                writeln!(f, "{}- Operator: {:?}", pad, op.variant)?;
-                writeln!(f, "{}- Right:", pad)?;
-                right.nested_fmt(f, depth + 1)?;
-            }
-            Expression::Unary { op, right } => {
-                writeln!(f, "{}Unary:", pad)?;
-                writeln!(f, "{}- Operator: {:?}", pad, op.variant)?;
-                writeln!(f, "{}- Right:", pad)?;
-                right.nested_fmt(f, depth + 1)?;
-            }
-            Expression::Group(node) => {
-                writeln!(f, "{}Group:", pad)?;
-                node.nested_fmt(f, depth + 1)?;
-            }
-            Expression::Literal(token) => {
-                writeln!(f, "{}Literal: {:?}", pad, token.variant)?;
-            }
-        }
-
-        Ok(())
-    }
-}
diff --git a/src/parse/ast/expression.rs b/src/parse/ast/expression.rs
new file mode 100644
index 0000000..8563492
--- /dev/null
+++ b/src/parse/ast/expression.rs
@@ -0,0 +1,127 @@
+use std::fmt::{self, Display, Formatter};
+
+use super::value::{
+    BinaryOperator, Block, ConditionalBlock, FnHeader, Identifier, Literal, UnaryOperator,
+};
+
+#[derive(Debug)]
+pub enum Expression {
+    Binary {
+        left: Box<Expression>,
+        op: BinaryOperator,
+        right: Box<Expression>,
+    },
+    Unary {
+        op: UnaryOperator,
+        right: Box<Expression>,
+    },
+    Group(Box<Expression>),
+    Block(Box<Block>),
+    Fn {
+        header: FnHeader,
+        body: Box<Block>,
+    },
+    If {
+        conditionals: Vec<ConditionalBlock>,
+        else_block: Option<Box<Block>>,
+    },
+    Literal(Literal),
+    Identifier(Identifier),
+}
+
+impl Display for Expression {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        self.nested_fmt(f, 0)
+    }
+}
+
+impl Expression {
+    pub(crate) fn nested_fmt(&self, f: &mut Formatter<'_>, depth: usize) -> fmt::Result {
+        let pad = "  ".repeat(depth);
+        match self {
+            Expression::Binary { left, op, right } => {
+                writeln!(f, "{}Binary:", pad)?;
+                writeln!(f, "{}- Left:", pad)?;
+                left.nested_fmt(f, depth + 1)?;
+                writeln!(f, "{}- Operator: {:?}", pad, op)?;
+                writeln!(f, "{}- Right:", pad)?;
+                right.nested_fmt(f, depth + 1)?;
+            }
+            Expression::Unary { op, right } => {
+                writeln!(f, "{}Unary:", pad)?;
+                writeln!(f, "{}- Operator: {:?}", pad, op)?;
+                writeln!(f, "{}- Right:", pad)?;
+                right.nested_fmt(f, depth + 1)?;
+            }
+            Expression::Group(node) => {
+                writeln!(f, "{}Group:", pad)?;
+                node.nested_fmt(f, depth + 1)?;
+            }
+            Expression::Block(block) => {
+                Self::block_fmt(f, block, depth + 1)?;
+            }
+            Expression::Fn { header, body } => {
+                write!(f, "{}Fn (", pad)?;
+
+                // Write self receiver
+                if header.has_self_receiver {
+                    write!(f, "self, ")?;
+                }
+
+                // Write parameters
+                for p in header.parameters.iter() {
+                    write!(
+                        f,
+                        "{}: {}, ",
+                        p.identifier,
+                        p.type_constraint.as_ref().unwrap_or(&"_".into())
+                    )?;
+                }
+
+                // Write return type
+                writeln!(
+                    f,
+                    ") -> {}:",
+                    header.return_type.as_ref().unwrap_or(&"_".into())
+                )?;
+                Self::block_fmt(f, body, depth + 1)?;
+            }
+            Expression::Literal(literal) => {
+                writeln!(f, "{}Literal: {:?}", pad, literal)?;
+            }
+            Expression::Identifier(identifier) => {
+                writeln!(f, "{}Identifier: {:?}", pad, identifier)?;
+            }
+            Expression::If { conditionals, else_block } => {
+                writeln!(f, "{}If:", pad)?;
+                for (i, c) in 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 {
+                    writeln!(f, "{}- Else:", pad)?;
+                    Self::block_fmt(f, e, depth + 1)?;
+                }
+            },
+        }
+
+        Ok(())
+    }
+
+    fn block_fmt(f: &mut Formatter<'_>, block: &Block, depth: usize) -> fmt::Result {
+        let pad = "  ".repeat(depth);
+        writeln!(f, "{}Block:", pad)?;
+        for (i, statement) in block.statements.iter().enumerate() {
+            writeln!(f, "{}- {}:", pad, i)?;
+            statement.nested_fmt(f, depth + 1)?;
+        }
+        if let Some(tail_expression) = &block.tail_expression {
+            writeln!(f, "{}- Tail:", pad)?;
+            tail_expression.nested_fmt(f, depth + 1)?;
+        }
+
+        Ok(())
+    }
+}
diff --git a/src/parse/ast/mod.rs b/src/parse/ast/mod.rs
new file mode 100644
index 0000000..257675f
--- /dev/null
+++ b/src/parse/ast/mod.rs
@@ -0,0 +1,21 @@
+use std::fmt::Display;
+
+use self::statement::Statement;
+
+pub mod expression;
+pub mod statement;
+pub mod value;
+
+#[derive(Debug)]
+pub struct Program {
+    pub statements: Vec<Statement>,
+}
+
+impl Display for Program {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        for statement in self.statements.iter() {
+            writeln!(f, "{}", statement)?;
+        }
+        Ok(())
+    }
+}
diff --git a/src/parse/ast/statement.rs b/src/parse/ast/statement.rs
new file mode 100644
index 0000000..eec589e
--- /dev/null
+++ b/src/parse/ast/statement.rs
@@ -0,0 +1,39 @@
+use std::fmt::Display;
+
+use super::expression::Expression;
+
+#[derive(Debug)]
+pub enum Statement {
+    Expression(Expression),
+    Print(Expression),
+    Return(Expression),
+}
+
+impl Display for Statement {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.nested_fmt(f, 0)
+    }
+}
+
+impl Statement {
+    pub(crate) fn nested_fmt(
+        &self,
+        f: &mut std::fmt::Formatter<'_>,
+        depth: usize,
+    ) -> std::fmt::Result {
+        let pad = "  ".repeat(depth);
+        match self {
+            Statement::Expression(expression) => expression.nested_fmt(f, depth)?,
+            Statement::Print(expression) => {
+                writeln!(f, "{}Print:", pad)?;
+                expression.nested_fmt(f, depth + 1)?;
+            }
+            Statement::Return(expression) => {
+                writeln!(f, "{}Return:", pad)?;
+                expression.nested_fmt(f, depth + 1)?;
+            }
+        }
+
+        Ok(())
+    }
+}
diff --git a/src/parse/ast/value.rs b/src/parse/ast/value.rs
new file mode 100644
index 0000000..263cb58
--- /dev/null
+++ b/src/parse/ast/value.rs
@@ -0,0 +1,106 @@
+use crate::lex::token::{Token, TokenVariant::*};
+
+use super::{expression::Expression, statement::Statement};
+
+#[derive(Debug)]
+pub enum BinaryOperator {
+    Plus,
+    Minus,
+    Star,
+    Slash,
+    Eq,
+    Neq,
+    Gt,
+    Gte,
+    Lt,
+    Lte,
+    Assign,
+    ConstAssign,
+    Dot,
+}
+
+impl BinaryOperator {
+    pub fn from_token(token: Token) -> Self {
+        match token.variant {
+            OpPlus => Self::Plus,
+            OpMinus => Self::Minus,
+            OpStar => Self::Star,
+            OpSlash => Self::Slash,
+            OpEq => Self::Eq,
+            OpNeq => Self::Neq,
+            OpLt => Self::Lt,
+            OpGt => Self::Gt,
+            OpLte => Self::Lte,
+            OpGte => Self::Gte,
+            Assign => Self::Assign,
+            ConstAssign => Self::ConstAssign,
+            Dot => Self::Dot,
+            _ => panic!("Can't create binary operator from '{:?}'.", token.variant)
+        }
+    }
+}
+
+#[derive(Debug)]
+pub enum UnaryOperator {
+    Plus,
+    Minus,
+    Not,
+}
+
+impl UnaryOperator {
+    pub fn from_token(token: Token) -> Self {
+        match token.variant {
+            OpPlus => Self::Plus,
+            OpMinus => Self::Minus,
+            OpNot => Self::Not,
+            _ => panic!("Can't create unary operator from '{:?}'.", token.variant)
+        }
+    }
+}
+
+#[derive(Debug)]
+pub enum Literal {
+    Int(u32),
+    Float(f32),
+    Str(String),
+}
+
+impl Literal {
+    pub fn from_token(token: Token) -> Self {
+        match token.variant {
+            Int(int) => Self::Int(int),
+            Float(float) => Self::Float(float),
+            Str(string) => Self::Str(string),
+            _ => panic!("Can't create literal from '{:?}'.", token.variant)
+        }
+    }
+}
+
+pub type Identifier = String;
+
+// If the contraint is None the type will have to be inferred
+// during analysis.
+#[derive(Debug)]
+pub struct TypedIdentifier {
+    pub identifier: Identifier,
+    pub type_constraint: Option<Identifier>,
+}
+
+#[derive(Debug)]
+pub struct FnHeader {
+    pub has_self_receiver: bool,
+    pub parameters: Vec<TypedIdentifier>,
+    pub return_type: Option<Identifier>,
+}
+
+#[derive(Debug)]
+pub struct Block {
+    pub statements: Vec<Statement>,
+    pub tail_expression: Option<Expression>,
+}
+
+#[derive(Debug)]
+pub struct ConditionalBlock {
+    pub condition: Expression,
+    pub block: Block,
+}
diff --git a/src/parse/macros.rs b/src/parse/macros.rs
new file mode 100644
index 0000000..0b09152
--- /dev/null
+++ b/src/parse/macros.rs
@@ -0,0 +1,59 @@
+#[macro_export]
+macro_rules! check {
+    ($self:ident, $($variant:pat_param)|+) => {
+        if let Some(token) = $self.tokens.peek() {
+            if let Token {variant: $( $variant )|+, ..} = token {
+                true
+            } else {
+                false
+            }
+        } else {
+            false
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! consume {
+    ($self:ident, $($variant:pat_param)|+) => {
+        if let Some(token) = $self.tokens.next() {
+            if let Token {variant: $( $variant )|+, ..} = token {
+                Ok(token)
+            } else {
+                Err(anyhow!(
+                    // Make a better error message
+                    "Received unexpected token: '{:?}'.",
+                    token.variant
+                ))
+            }
+        } else {
+            // Here too
+            Err(anyhow!("Expected a token."))
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! consume_if {
+    ($self:ident, $($variant:pat_param)|+) => {
+        if let Some(token) = $self.tokens.peek() {
+            if let Token {variant: $( $variant )|+, ..} = token {
+                Some($self.tokens.next().unwrap())
+            } else {
+                None
+            }
+        } else {
+            None
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! inner {
+    ($token:expr, $variant:path ) => {
+        match $token.variant {
+            $variant(inner) => inner,
+            _ => panic!("Tried getting inner content of incorrect variant.")
+        }
+    };
+}
\ No newline at end of file
diff --git a/src/parse/mod.rs b/src/parse/mod.rs
index a310c76..e45e6fa 100644
--- a/src/parse/mod.rs
+++ b/src/parse/mod.rs
@@ -1,2 +1,3 @@
 pub mod ast;
+mod macros;
 pub mod parser;
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index dc99262..0316a35 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -1,7 +1,19 @@
+use super::ast::expression::Expression;
+use super::ast::statement::Statement;
+use super::ast::value::UnaryOperator;
+use super::ast::Program;
+use crate::check;
+use crate::consume;
+use crate::consume_if;
+use crate::inner;
 use crate::lex::token::Token;
-use crate::lex::token::TokenVariant;
 use crate::lex::token::TokenVariant::*;
-use crate::parse::ast::Expression;
+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 anyhow::anyhow;
 use anyhow::Result;
 use std::iter::Peekable;
@@ -17,30 +29,75 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         }
     }
 
-    pub fn parse(&mut self) -> Result<Expression> {
-        self.expression()
+    pub fn parse(&mut self) -> Result<Program> {
+        let mut statements = Vec::new();
+
+        while !check!(self, Eof) {
+            statements.push(self.statement()?);
+        }
+
+        Ok(Program { statements })
+    }
+
+    fn statement(&mut self) -> Result<Statement> {
+        let token = self.tokens.peek().expect("Expected token.");
+        match token.variant {
+            KeywordPrint => self.print_statement(),
+            KeywordReturn => self.return_statement(),
+            _ => self.expression_statement(),
+        }
+    }
+
+    fn return_statement(&mut self) -> Result<Statement> {
+        consume!(self, KeywordReturn)?;
+        let expression = self.expression()?;
+        consume!(self, SemiColon)?;
+        Ok(Statement::Return(expression))
+    }
+
+    fn print_statement(&mut self) -> Result<Statement> {
+        consume!(self, KeywordPrint)?;
+        let expression = self.expression()?;
+        consume!(self, SemiColon)?;
+        Ok(Statement::Print(expression))
+    }
+
+    fn expression_statement(&mut self) -> Result<Statement> {
+        let expression = self.expression()?;
+        consume!(self, SemiColon)?;
+        Ok(Statement::Expression(expression))
     }
 
     fn expression(&mut self) -> Result<Expression> {
-        self.term_expression()
+        self.assignment_expression()
+    }
+
+    fn assignment_expression(&mut self) -> Result<Expression> {
+        // Parse any expressions as l-values for now.
+        let left = self.term_expression()?;
+
+        if let Some(op) = consume_if!(self, Assign | ConstAssign) {
+            let right = self.assignment_expression()?;
+
+            Ok(Expression::Binary {
+                left: Box::new(left),
+                op: BinaryOperator::from_token(op),
+                right: Box::new(right),
+            })
+        } else {
+            Ok(left)
+        }
     }
 
     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();
+        while let Some(op) = consume_if!(self, OpPlus | OpMinus) {
             let right = self.factor_expression()?;
 
             left = Expression::Binary {
                 left: Box::new(left),
-                op,
+                op: BinaryOperator::from_token(op),
                 right: Box::new(right),
             };
         }
@@ -51,19 +108,12 @@ impl<T: Iterator<Item = Token>> Parser<T> {
     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();
+        while let Some(op) = consume_if!(self, OpSlash | OpStar) {
             let right = self.unary_expression()?;
 
             left = Expression::Binary {
                 left: Box::new(left),
-                op,
+                op: BinaryOperator::from_token(op),
                 right: Box::new(right),
             };
         }
@@ -72,13 +122,9 @@ impl<T: Iterator<Item = Token>> Parser<T> {
     }
 
     fn unary_expression(&mut self) -> Result<Expression> {
-        let expression = if let Some(Token {
-            variant: OpPlus | OpMinus | OpNot,
-            ..
-        }) = self.tokens.peek()
-        {
+        let expression = if check!(self, OpPlus | OpMinus | OpNot) {
             Expression::Unary {
-                op: self.tokens.next().unwrap(),
+                op: UnaryOperator::from_token(self.tokens.next().unwrap()),
                 right: Box::new(self.unary_expression()?),
             }
         } else {
@@ -89,20 +135,113 @@ impl<T: Iterator<Item = Token>> Parser<T> {
     }
 
     fn unit_expression(&mut self) -> Result<Expression> {
-        if let Some(token) = self.tokens.next() {
+        if let Some(token) = self.tokens.peek() {
             match token.variant {
-                Int(_) | Float(_) => Ok(Expression::Literal(token)),
+                Int(_) | Float(_) | Str(_) => {
+                    let literal = self.tokens.next().unwrap();
+                    Ok(Expression::Literal(Literal::from_token(literal)))
+                }
+                // Identifier(_) => match self.tokens.next().unwrap().variant {
+                //     Identifier(identifier) => Ok(Expression::Identifier(identifier)),
+                //     _ => unreachable!(),
+                // },
+                Ident(_) => Ok(Expression::Identifier(inner!(
+                    self.tokens.next().unwrap(),
+                    Ident
+                ))),
                 GroupOpen => {
+                    consume!(self, 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."))
+                    consume!(self, GroupClose)?;
+                    Ok(Expression::Group(Box::new(expression)))
+                }
+                BlockOpen => Ok(Expression::Block(Box::new(self.block()?))),
+                KeywordFn => {
+                    consume!(self, KeywordFn)?;
+                    let token = self.tokens.next().expect("Expected function header.");
+
+                    let header = {
+                        let has_self_receiver = if let KeywordSelf = token.variant {
+                            consume_if!(self, Comma);
+                            true
+                        } else {
+                            false
+                        };
+
+                        let mut parameters = Vec::new();
+                        while let Some(token) = consume_if!(self, Ident(_)) {
+                            let parameter_name = inner!(token, Ident);
+
+                            let type_constraint = if consume_if!(self, Colon).is_some() {
+                                Some(inner!(consume!(self, Ident(_))?, Ident))
+                            } else {
+                                None
+                            };
+
+                            parameters.push(TypedIdentifier {
+                                identifier: parameter_name,
+                                type_constraint,
+                            });
+
+                            if consume_if!(self, Comma).is_none() {
+                                break;
+                            }
+                        }
+
+                        let return_type = if consume_if!(self, Arrow).is_some() {
+                            Some(inner!(consume!(self, Ident(_))?, Ident))
+                        } else {
+                            None
+                        };
+
+                        FnHeader {
+                            has_self_receiver,
+                            parameters,
+                            return_type,
+                        }
+                    };
+
+                    let body = self.block()?;
+
+                    Ok(Expression::Fn {
+                        header,
+                        body: Box::new(body),
+                    })
+                }
+                KeywordIf => {
+                    consume!(self, KeywordIf)?;
+
+                    let mut conditionals = Vec::new();
+
+                    let if_condition = self.expression()?;
+                    let if_block = self.block()?;
+
+                    conditionals.push(ConditionalBlock {
+                        condition: if_condition,
+                        block: if_block,
+                    });
+
+                    // Elifs
+                    while consume_if!(self, KeywordElif).is_some() {
+                        let elif_condition = self.expression()?;
+                        let elif_block = self.block()?;
+
+                        conditionals.push(ConditionalBlock {
+                            condition: elif_condition,
+                            block: elif_block,
+                        });
                     }
+
+                    let else_conditional = if consume_if!(self, KeywordElse).is_some() {
+                        Some(self.block()?)
+                    } else {
+                        None
+                    };
+
+                    Ok(Expression::If {
+                        conditionals,
+                        else_block: else_conditional.map(Box::new),
+                    })
                 }
                 _ => Err(anyhow!("Unexpected token: {:?}", token.variant)),
             }
@@ -110,4 +249,39 @@ impl<T: Iterator<Item = Token>> Parser<T> {
             Err(anyhow!("Expected expression."))
         }
     }
+
+    fn block(&mut self) -> Result<Block> {
+        consume!(self, BlockOpen)?;
+
+        let mut statements = Vec::new();
+        let mut tail_expression = None;
+
+        loop {
+            let token = self.tokens.peek().expect("Unclosed block.");
+            match token.variant {
+                KeywordReturn | KeywordPrint => {
+                    statements.push(self.statement()?);
+                }
+                BlockClose => {
+                    break;
+                }
+                _ => {
+                    let expression = self.expression()?;
+                    if consume_if!(self, SemiColon).is_some() {
+                        statements.push(Statement::Expression(expression));
+                    } else {
+                        tail_expression = Some(expression);
+                        break;
+                    }
+                }
+            }
+        }
+
+        consume!(self, BlockClose)?;
+
+        Ok(Block {
+            statements,
+            tail_expression,
+        })
+    }
 }