about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2021-10-23 22:01:52 +0200
committerMel <einebeere@gmail.com>2021-10-23 22:01:52 +0200
commit8a6eb35a900081967db16d313ab7ed470de6570f (patch)
treed58dd702d8a742c7554545bc4e291480649e3663 /src
parentda14afd74e1659af6ce4553360ac5dd0ce933db8 (diff)
downloadrabbithole-8a6eb35a900081967db16d313ab7ed470de6570f.tar.zst
rabbithole-8a6eb35a900081967db16d313ab7ed470de6570f.zip
Loop expressions and concrete walker errors.
Diffstat (limited to 'src')
-rw-r--r--src/interpret/value.rs103
-rw-r--r--src/interpret/walker.rs97
-rw-r--r--src/lex/lexer.rs3
-rw-r--r--src/lex/mod.rs2
-rw-r--r--src/lex/token.rs3
-rw-r--r--src/parse/ast/expression.rs15
-rw-r--r--src/parse/ast/mod.rs2
-rw-r--r--src/parse/ast/nodes.rs6
-rw-r--r--src/parse/ast/statement.rs13
-rw-r--r--src/parse/parser.rs218
10 files changed, 321 insertions, 141 deletions
diff --git a/src/interpret/value.rs b/src/interpret/value.rs
index 27f2668..86fe094 100644
--- a/src/interpret/value.rs
+++ b/src/interpret/value.rs
@@ -1,6 +1,6 @@
 use crate::parse::ast::nodes::FnNode;
-use anyhow::{anyhow, Result};
 use std::{cell::RefCell, fmt::Display, rc::Rc};
+use thiserror::Error;
 
 type Ref<T> = RefCell<Rc<T>>;
 
@@ -15,79 +15,79 @@ pub enum Value {
 }
 
 impl Value {
-    pub fn add(self, rhs: Value) -> Result<Value> {
+    pub fn add(self, rhs: Value) -> Result<Value, OperationError> {
         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::Str(ref l) => match rhs {
+                Value::Str(r) => Ok(Value::Str(format!("{}{}", l, r))),
+                Value::Float(r) => Ok(Value::Str(format!("{}{}", l, r))),
+                Value::Int(r) => Ok(Value::Str(format!("{}{}", l, r))),
+                r => Err(OperationError::AddTypes(self, r)),
             },
             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.")),
+                r => Err(OperationError::AddTypes(self, r)),
             },
             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.")),
+                r => Err(OperationError::AddTypes(self, r)),
             },
-            _ => Err(anyhow!("Left operand can't be added.")),
+            _ => Err(OperationError::AddTypes(self, rhs)),
         }
     }
 
-    pub fn sub(self, rhs: Value) -> Result<Value> {
+    pub fn sub(self, rhs: Value) -> Result<Value, OperationError> {
         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.")),
+                r => Err(OperationError::SubTypes(self, r)),
             },
             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.")),
+                r => Err(OperationError::SubTypes(self, r)),
             },
-            _ => Err(anyhow!("Left operand can't be substracted from.")),
+            _ => Err(OperationError::SubTypes(self, rhs)),
         }
     }
 
-    pub fn mul(self, rhs: Value) -> Result<Value> {
+    pub fn mul(self, rhs: Value) -> Result<Value, OperationError> {
         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.")),
+                r => Err(OperationError::MulTypes(self, r)),
             },
             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.")),
+                r => Err(OperationError::MulTypes(self, r)),
             },
-            _ => Err(anyhow!("Left operand can't be multiplied.")),
+            _ => Err(OperationError::MulTypes(self, rhs)),
         }
     }
 
-    pub fn div(self, rhs: Value) -> Result<Value> {
+    pub fn div(self, rhs: Value) -> Result<Value, OperationError> {
         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.")),
+                r => Err(OperationError::DivTypes(self, r)),
             },
             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.")),
+                r => Err(OperationError::DivTypes(self, r)),
             },
-            _ => Err(anyhow!("Left operand can't be multiplied.")),
+            _ => Err(OperationError::DivTypes(self, rhs)),
         }
     }
 
-    pub fn eq(self, rhs: Value) -> Result<Value> {
+    pub fn eq(self, rhs: Value) -> Result<Value, OperationError> {
         match self {
             Value::Str(l) => match rhs {
                 Value::Str(r) => Ok(Value::Bool(l == r)),
@@ -109,7 +109,7 @@ impl Value {
         }
     }
 
-    pub fn neq(self, rhs: Value) -> Result<Value> {
+    pub fn neq(self, rhs: Value) -> Result<Value, OperationError> {
         if let Ok(Value::Bool(value)) = self.eq(rhs) {
             Ok(Value::Bool(!value))
         } else {
@@ -117,50 +117,63 @@ impl Value {
         }
     }
 
-    pub fn gt(self, rhs: Value) -> Result<Value> {
+    pub fn gt(self, rhs: Value) -> Result<Value, OperationError> {
         match self {
             Value::Float(r) => match rhs {
                 Value::Float(l) => Ok(Value::Bool(r > l)),
                 Value::Int(l) => Ok(Value::Bool(r > l as f64)),
-                _ => Err(anyhow!("Right operand can't be compared.")),
+                r => Err(OperationError::CompareTypes(self, r)),
             },
             Value::Int(r) => match rhs {
                 Value::Float(l) => Ok(Value::Bool(r as f64 > l)),
                 Value::Int(l) => Ok(Value::Bool(r > l)),
-                _ => Err(anyhow!("Right operand can't be compared.")),
+                r => Err(OperationError::CompareTypes(self, r)),
             },
-            _ => Err(anyhow!("Left operand can't be compared.")),
+            _ => Err(OperationError::CompareTypes(self, rhs)),
         }
     }
 
-    pub fn gte(self, rhs: Value) -> Result<Value> {
+    pub fn gte(self, rhs: Value) -> Result<Value, OperationError> {
         match self {
             Value::Float(r) => match rhs {
                 Value::Float(l) => Ok(Value::Bool(r >= l)),
                 Value::Int(l) => Ok(Value::Bool(r >= l as f64)),
-                _ => Err(anyhow!("Right operand can't be compared.")),
+                r => Err(OperationError::CompareTypes(self, r)),
             },
             Value::Int(r) => match rhs {
                 Value::Float(l) => Ok(Value::Bool(r as f64 >= l)),
                 Value::Int(l) => Ok(Value::Bool(r >= l)),
-                _ => Err(anyhow!("Right operand can't be compared.")),
+                r => Err(OperationError::CompareTypes(self, r)),
             },
-            _ => Err(anyhow!("Left operand can't be compared.")),
+            _ => Err(OperationError::CompareTypes(self, rhs)),
         }
     }
 
-    pub fn neg(self) -> Result<Value> {
+    pub fn neg(self) -> Result<Value, OperationError> {
         match self {
             Value::Float(float) => Ok(Value::Float(-float)),
             Value::Int(int) => Ok(Value::Int(-int)),
-            _ => Err(anyhow!("Can't negate value.")),
+            _ => Err(OperationError::NegType(self)),
         }
     }
 
-    pub fn not(self) -> Result<Value> {
+    pub fn not(self) -> Result<Value, OperationError> {
         match self {
             Value::Bool(bool) => Ok(Value::Bool(bool)),
-            _ => Err(anyhow!("Can't flip non-bool value.")),
+            _ => Err(OperationError::NotType(self)),
+        }
+    }
+}
+
+impl Value {
+    pub fn type_name(&self) -> &'static str {
+        match self {
+            Value::Str(_) => "Str",
+            Value::Float(_) => "Float",
+            Value::Int(_) => "Int",
+            Value::Bool(_) => "Bool",
+            Value::Fn(_) => "Fn",
+            Value::Void => "Void",
         }
     }
 }
@@ -177,3 +190,21 @@ impl Display for Value {
         }
     }
 }
+
+#[derive(Error, Debug)]
+pub enum OperationError {
+    #[error("Can't add value '{0}' of type '{}' to value '{1}' of type '{}'.", .0.type_name(), .1.type_name())]
+    AddTypes(Value, Value),
+    #[error("Can't subtract value '{1}' of type '{}' from value '{0}' of type '{}'.", .1.type_name(), .0.type_name())]
+    SubTypes(Value, Value),
+    #[error("Can't multiply value '{0}' of type '{}' with value '{1}' of type '{}'.", .0.type_name(), .1.type_name())]
+    MulTypes(Value, Value),
+    #[error("Can't divide value '{0}' of type '{}' by value '{1}' of type '{}'.", .0.type_name(), .1.type_name())]
+    DivTypes(Value, Value),
+    #[error("Can't compare value '{0}' of type '{}' with value '{1}' of type '{}'.", .0.type_name(), .1.type_name())]
+    CompareTypes(Value, Value),
+    #[error("Can't negate value '{0}' of type '{}'.", .0.type_name())]
+    NegType(Value),
+    #[error("Can't flip value '{0}' of type '{}'.", .0.type_name())]
+    NotType(Value),
+}
diff --git a/src/interpret/walker.rs b/src/interpret/walker.rs
index 7684747..db37a26 100644
--- a/src/interpret/walker.rs
+++ b/src/interpret/walker.rs
@@ -2,13 +2,16 @@ use std::{cell::RefCell, rc::Rc};
 
 use crate::parse::ast::{
     expression::Expression,
-    nodes::{BinaryOperator as BinOp, BlockNode, Literal, UnaryOperator as UnOp},
+    nodes::{BinaryOperator as BinOp, BlockNode, Identifier, Literal, UnaryOperator as UnOp},
     statement::Statement,
     Program,
 };
-use anyhow::{anyhow, Result};
+use thiserror::Error;
 
-use super::{scope::Scope, value::Value};
+use super::{
+    scope::Scope,
+    value::{OperationError, Value},
+};
 
 pub struct Walker {
     scope: Scope,
@@ -28,7 +31,7 @@ impl Walker {
         }
     }
 
-    fn walk_statement(&mut self, statement: &Statement) -> Result<Option<Value>> {
+    fn walk_statement(&mut self, statement: &Statement) -> Result<Option<Value>, WalkerError> {
         let result = match statement {
             Statement::Expression(node) => {
                 self.walk_expression(node)?;
@@ -40,12 +43,23 @@ impl Walker {
                 None
             }
             Statement::Return(node) => Some(self.walk_expression(node)?),
+            Statement::Break(node) => {
+                let returned = if let Some(expression) = node {
+                    Some(self.walk_expression(expression)?)
+                } else {
+                    None
+                };
+                // If there's a loop above us it will catch this error.
+                return Err(WalkerError::LoopBreak(returned));
+            }
+            // Same here.
+            Statement::Continue => return Err(WalkerError::LoopContinue),
         };
 
         Ok(result)
     }
 
-    pub fn walk_expression(&mut self, node: &Expression) -> Result<Value> {
+    pub fn walk_expression(&mut self, node: &Expression) -> Result<Value, WalkerError> {
         match node {
             Expression::Binary { left, op, right } => {
                 // Assignment
@@ -79,7 +93,8 @@ impl Walker {
                     // No structure access yet.
                     BinOp::Dot => todo!(),
                     _ => unreachable!(),
-                }?;
+                }
+                .map_err(WalkerError::OperationError)?;
 
                 Ok(new_value)
             }
@@ -87,9 +102,10 @@ impl Walker {
                 let value = self.walk_expression(right)?;
 
                 let new_value = match op {
-                    UnOp::Minus => value.neg()?,
-                    UnOp::Not => value.not()?,
-                };
+                    UnOp::Minus => value.neg(),
+                    UnOp::Not => value.not(),
+                }
+                .map_err(WalkerError::OperationError)?;
 
                 Ok(new_value)
             }
@@ -116,9 +132,7 @@ impl Walker {
                             return self.walk_block(&conditional.block);
                         }
                     } else {
-                        return Err(anyhow!(
-                            "If and Elif expressions can only take boolean values as conditions."
-                        ));
+                        return Err(WalkerError::WrongIfConditionType);
                     }
                 }
 
@@ -128,17 +142,53 @@ impl Walker {
                     Ok(Value::Void)
                 }
             }
+            Expression::Loop(loop_node) => {
+                if let Some(condition) = &loop_node.condition {
+                    loop {
+                        if let Value::Bool(should_repeat) = self.walk_expression(condition)? {
+                            if should_repeat {
+                                match self.walk_block(&loop_node.body) {
+                                    Err(WalkerError::LoopBreak(loop_value)) => {
+                                        return Ok(loop_value.unwrap_or(Value::Void));
+                                    }
+                                    // Do nothing for continue and continue looping of course, you dummy.
+                                    Err(WalkerError::LoopContinue) => {}
+                                    // This is probably an actual error.
+                                    Err(x) => return Err(x),
+                                    _ => {}
+                                }
+                            } else {
+                                return Ok(Value::Void);
+                            }
+                        } else {
+                            return Err(WalkerError::WrongLoopConditionType);
+                        }
+                    }
+                } else {
+                    // Same as above.
+                    loop {
+                        match self.walk_block(&loop_node.body) {
+                            Err(WalkerError::LoopBreak(loop_value)) => {
+                                break Ok(loop_value.unwrap_or(Value::Void));
+                            }
+                            Err(WalkerError::LoopContinue) => {}
+                            Err(x) => return Err(x),
+                            _ => {}
+                        }
+                    }
+                }
+            }
             Expression::Identifier(ident) => {
                 if let Some(value) = self.scope.get_var(ident) {
                     Ok(value)
                 } else {
-                    Err(anyhow!("Unknown identifier: {}.", ident))
+                    Err(WalkerError::UnknownIdentifier(ident.clone()))
                 }
             }
         }
     }
 
-    fn walk_block(&mut self, block: &BlockNode) -> Result<Value> {
+    fn walk_block(&mut self, block: &BlockNode) -> Result<Value, WalkerError> {
         self.scope.nest();
 
         for statement in block.statements.iter() {
@@ -156,3 +206,22 @@ impl Walker {
         result
     }
 }
+
+// TODO: Add source maps to the errors.
+#[derive(Error, Debug)]
+pub enum WalkerError {
+    #[error("Unknown identifier '{0}'")]
+    UnknownIdentifier(Identifier),
+    #[error("Loop expressions can only take boolean values as conditions.")]
+    WrongLoopConditionType,
+    #[error("If and Elif expressions can only take boolean values as conditions.")]
+    WrongIfConditionType,
+    #[error(transparent)]
+    OperationError(OperationError),
+    // These are used for loop control flow and are only errors
+    // if continue and break statements are used outside of loops.
+    #[error("Continue statements are only valid inside loops.")]
+    LoopContinue,
+    #[error("Break statements are only valid inside loops.")]
+    LoopBreak(Option<Value>),
+}
diff --git a/src/lex/lexer.rs b/src/lex/lexer.rs
index 4d980d6..60301c3 100644
--- a/src/lex/lexer.rs
+++ b/src/lex/lexer.rs
@@ -190,12 +190,15 @@ impl<'s> Lexer<'s> {
             "if" => TokenVariant::KeywordIf,
             "elif" => TokenVariant::KeywordElif,
             "else" => TokenVariant::KeywordElse,
+            "loop" => TokenVariant::KeywordLoop,
             "type" => TokenVariant::KeywordType,
             "form" => TokenVariant::KeywordForm,
             "self" => TokenVariant::KeywordSelf,
             "true" => TokenVariant::KeywordTrue,
             "false" => TokenVariant::KeywordFalse,
             "return" => TokenVariant::KeywordReturn,
+            "break" => TokenVariant::KeywordBreak,
+            "continue" => TokenVariant::KeywordContinue,
             "print" => TokenVariant::KeywordPrint,
             _ => TokenVariant::Ident(buffer),
         };
diff --git a/src/lex/mod.rs b/src/lex/mod.rs
index f785280..e12719b 100644
--- a/src/lex/mod.rs
+++ b/src/lex/mod.rs
@@ -1,2 +1,2 @@
 pub mod lexer;
-pub mod token;
\ No newline at end of file
+pub mod token;
diff --git a/src/lex/token.rs b/src/lex/token.rs
index 5debbfd..2fb5d5b 100644
--- a/src/lex/token.rs
+++ b/src/lex/token.rs
@@ -53,11 +53,14 @@ pub enum TokenVariant {
     KeywordIf,
     KeywordElif,
     KeywordElse,
+    KeywordLoop,
     KeywordForm,
     KeywordType,
     KeywordTrue,
     KeywordFalse,
     KeywordSelf,
+    KeywordBreak,
+    KeywordContinue,
     KeywordReturn,
     KeywordPrint,
 
diff --git a/src/parse/ast/expression.rs b/src/parse/ast/expression.rs
index 1749c40..c7f6d9b 100644
--- a/src/parse/ast/expression.rs
+++ b/src/parse/ast/expression.rs
@@ -1,6 +1,8 @@
 use std::fmt::{self, Display, Formatter};
 
-use super::nodes::{BinaryOperator, BlockNode, FnNode, Identifier, IfNode, Literal, UnaryOperator};
+use super::nodes::{
+    BinaryOperator, BlockNode, FnNode, Identifier, IfNode, Literal, LoopNode, UnaryOperator,
+};
 
 #[derive(Debug, Clone)]
 pub enum Expression {
@@ -17,6 +19,7 @@ pub enum Expression {
     Block(Box<BlockNode>),
     Fn(Box<FnNode>),
     If(Box<IfNode>),
+    Loop(Box<LoopNode>),
     Literal(Literal),
     Identifier(Identifier),
 }
@@ -97,6 +100,16 @@ impl Expression {
                     Self::block_fmt(f, e, depth + 1)?;
                 }
             }
+            Expression::Loop(node) => {
+                writeln!(f, "{}Loop:", pad)?;
+                if let Some(loop_condition) = &node.condition {
+                    writeln!(f, "{}- Condition:", pad)?;
+                    loop_condition.nested_fmt(f, depth + 1)?;
+                }
+
+                writeln!(f, "{}- Body:", pad)?;
+                Self::block_fmt(f, &node.body, depth + 1)?;
+            }
         }
 
         Ok(())
diff --git a/src/parse/ast/mod.rs b/src/parse/ast/mod.rs
index 93944b2..7d0b58b 100644
--- a/src/parse/ast/mod.rs
+++ b/src/parse/ast/mod.rs
@@ -3,8 +3,8 @@ use std::fmt::Display;
 use self::statement::Statement;
 
 pub mod expression;
-pub mod statement;
 pub mod nodes;
+pub mod statement;
 
 #[derive(Debug)]
 pub struct Program {
diff --git a/src/parse/ast/nodes.rs b/src/parse/ast/nodes.rs
index 822ffb6..2a4f7c0 100644
--- a/src/parse/ast/nodes.rs
+++ b/src/parse/ast/nodes.rs
@@ -107,6 +107,12 @@ pub struct IfNode {
 }
 
 #[derive(Debug, Clone)]
+pub struct LoopNode {
+    pub condition: Option<Expression>,
+    pub body: BlockNode,
+}
+
+#[derive(Debug, Clone)]
 pub struct BlockNode {
     pub statements: Vec<Statement>,
     pub tail_expression: Option<Expression>,
diff --git a/src/parse/ast/statement.rs b/src/parse/ast/statement.rs
index b0e626d..99ee0e0 100644
--- a/src/parse/ast/statement.rs
+++ b/src/parse/ast/statement.rs
@@ -6,6 +6,8 @@ use super::expression::Expression;
 pub enum Statement {
     Expression(Expression),
     Print(Expression),
+    Break(Option<Expression>),
+    Continue,
     Return(Expression),
 }
 
@@ -32,6 +34,17 @@ impl Statement {
                 writeln!(f, "{}Return:", pad)?;
                 expression.nested_fmt(f, depth + 1)?;
             }
+            Statement::Break(expression) => {
+                if let Some(returned_on_break) = expression {
+                    writeln!(f, "{}Break:", pad)?;
+                    returned_on_break.nested_fmt(f, depth + 1)?;
+                } else {
+                    writeln!(f, "{}Break", pad)?;
+                }
+            }
+            Statement::Continue => {
+                writeln!(f, "{}Continue", pad)?;
+            }
         }
 
         Ok(())
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 9b72597..4a84101 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -1,4 +1,5 @@
 use super::ast::expression::Expression;
+use super::ast::nodes::LoopNode;
 use super::ast::nodes::UnaryOperator;
 use super::ast::statement::Statement;
 use super::ast::Program;
@@ -46,6 +47,8 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         match token.variant {
             KeywordPrint => self.print_statement(),
             KeywordReturn => self.return_statement(),
+            KeywordBreak => self.break_statement(),
+            KeywordContinue => self.continue_statement(),
             _ => self.expression_statement(),
         }
     }
@@ -57,6 +60,24 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         Ok(Statement::Return(expression))
     }
 
+    fn break_statement(&mut self) -> Result<Statement> {
+        consume!(self, KeywordBreak)?;
+        let returned_on_break = if consume_if!(self, SemiColon).is_none() {
+            let expression = self.expression()?;
+            consume!(self, SemiColon)?;
+            Some(expression)
+        } else {
+            None
+        };
+        Ok(Statement::Break(returned_on_break))
+    }
+
+    fn continue_statement(&mut self) -> Result<Statement> {
+        consume!(self, KeywordContinue)?;
+        consume!(self, SemiColon)?;
+        Ok(Statement::Continue)
+    }
+
     fn print_statement(&mut self) -> Result<Statement> {
         consume!(self, KeywordPrint)?;
         let expression = self.expression()?;
@@ -179,105 +200,126 @@ impl<T: Iterator<Item = Token>> Parser<T> {
                     self.tokens.next().unwrap(),
                     Ident
                 ))),
-                GroupOpen => {
-                    consume!(self, GroupOpen)?;
-                    let expression = self.expression()?;
-                    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(Box::new(FnNode { header, body })))
-                }
-                KeywordIf => {
-                    consume!(self, KeywordIf)?;
+                GroupOpen => Ok(Expression::Group(Box::new(self.group()?))),
+                BlockOpen => Ok(Expression::Block(Box::new(self.generic_block()?))),
+                KeywordFn => Ok(Expression::Fn(Box::new(self.function()?))),
+                KeywordIf => Ok(Expression::If(Box::new(self.conditional()?))),
+                KeywordLoop => Ok(Expression::Loop(Box::new(self.repeating()?))),
+                _ => Err(anyhow!("Unexpected token: {:?}", token.variant)),
+            }
+        } else {
+            Err(anyhow!("Expected expression."))
+        }
+    }
 
-                    let mut conditionals = Vec::new();
+    fn group(&mut self) -> Result<Expression> {
+        consume!(self, GroupOpen)?;
+        let expression = self.expression()?;
+        consume!(self, GroupClose)?;
+        Ok(expression)
+    }
 
-                    let if_condition = self.expression()?;
-                    let if_block = self.block()?;
+    fn function(&mut self) -> Result<FnNode> {
+        consume!(self, KeywordFn)?;
+        let token = self.tokens.next().expect("Expected function header.");
 
-                    conditionals.push(ConditionalBlock {
-                        condition: if_condition,
-                        block: if_block,
-                    });
+        let header = {
+            let has_self_receiver = if let KeywordSelf = token.variant {
+                consume_if!(self, Comma);
+                true
+            } else {
+                false
+            };
 
-                    // Elifs
-                    while consume_if!(self, KeywordElif).is_some() {
-                        let elif_condition = self.expression()?;
-                        let elif_block = self.block()?;
+            let mut parameters = Vec::new();
+            while let Some(token) = consume_if!(self, Ident(_)) {
+                let parameter_name = inner!(token, Ident);
 
-                        conditionals.push(ConditionalBlock {
-                            condition: elif_condition,
-                            block: elif_block,
-                        });
-                    }
+                let type_constraint = if consume_if!(self, Colon).is_some() {
+                    Some(inner!(consume!(self, Ident(_))?, Ident))
+                } else {
+                    None
+                };
 
-                    let else_block = if consume_if!(self, KeywordElse).is_some() {
-                        Some(self.block()?)
-                    } else {
-                        None
-                    };
+                parameters.push(TypedIdentifier {
+                    identifier: parameter_name,
+                    type_constraint,
+                });
 
-                    Ok(Expression::If(Box::new(IfNode {
-                        conditionals,
-                        else_block,
-                    })))
+                if consume_if!(self, Comma).is_none() {
+                    break;
                 }
-                _ => Err(anyhow!("Unexpected token: {:?}", token.variant)),
             }
-        } else {
-            Err(anyhow!("Expected expression."))
+
+            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.generic_block()?;
+
+        Ok(FnNode { header, body })
+    }
+
+    fn conditional(&mut self) -> Result<IfNode> {
+        consume!(self, KeywordIf)?;
+
+        let mut conditionals = Vec::new();
+
+        let if_condition = self.expression()?;
+        let if_block = self.generic_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.generic_block()?;
+
+            conditionals.push(ConditionalBlock {
+                condition: elif_condition,
+                block: elif_block,
+            });
         }
+
+        let else_block = if consume_if!(self, KeywordElse).is_some() {
+            Some(self.generic_block()?)
+        } else {
+            None
+        };
+
+        Ok(IfNode {
+            conditionals,
+            else_block,
+        })
+    }
+
+    fn repeating(&mut self) -> Result<LoopNode> {
+        consume!(self, KeywordLoop)?;
+
+        let condition = if consume_if!(self, KeywordIf).is_some() {
+            let expression = self.expression()?;
+            Some(expression)
+        } else {
+            None
+        };
+
+        let body = self.generic_block()?;
+        Ok(LoopNode { body, condition })
     }
 
-    fn block(&mut self) -> Result<BlockNode> {
+    fn generic_block(&mut self) -> Result<BlockNode> {
         consume!(self, BlockOpen)?;
 
         let mut statements = Vec::new();
@@ -286,7 +328,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
         loop {
             let token = self.tokens.peek().expect("Unclosed block.");
             match token.variant {
-                KeywordReturn | KeywordPrint => {
+                KeywordReturn | KeywordPrint | KeywordContinue | KeywordBreak => {
                     statements.push(self.statement()?);
                 }
                 BlockClose => {