aboutsummaryrefslogtreecommitdiff
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.rs204
10 files changed, 314 insertions, 134 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.");
+ 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."))
+ }
+ }
+
+ fn group(&mut self) -> Result<Expression> {
+ consume!(self, GroupOpen)?;
+ let expression = self.expression()?;
+ consume!(self, GroupClose)?;
+ Ok(expression)
+ }
+
+ fn function(&mut self) -> Result<FnNode> {
+ 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 header = {
- let has_self_receiver = if let KeywordSelf = token.variant {
- consume_if!(self, Comma);
- true
- } else {
- false
- };
+ let type_constraint = if consume_if!(self, Colon).is_some() {
+ Some(inner!(consume!(self, Ident(_))?, Ident))
+ } else {
+ None
+ };
- let mut parameters = Vec::new();
- while let Some(token) = consume_if!(self, Ident(_)) {
- let parameter_name = inner!(token, Ident);
+ parameters.push(TypedIdentifier {
+ identifier: parameter_name,
+ type_constraint,
+ });
- let type_constraint = if consume_if!(self, Colon).is_some() {
- Some(inner!(consume!(self, Ident(_))?, Ident))
- } else {
- None
- };
+ if consume_if!(self, Comma).is_none() {
+ break;
+ }
+ }
- parameters.push(TypedIdentifier {
- identifier: parameter_name,
- type_constraint,
- });
+ let return_type = if consume_if!(self, Arrow).is_some() {
+ Some(inner!(consume!(self, Ident(_))?, Ident))
+ } else {
+ None
+ };
- if consume_if!(self, Comma).is_none() {
- break;
- }
- }
+ FnHeader {
+ has_self_receiver,
+ parameters,
+ return_type,
+ }
+ };
- let return_type = if consume_if!(self, Arrow).is_some() {
- Some(inner!(consume!(self, Ident(_))?, Ident))
- } else {
- None
- };
+ let body = self.generic_block()?;
- FnHeader {
- has_self_receiver,
- parameters,
- return_type,
- }
- };
+ Ok(FnNode { header, body })
+ }
- let body = self.block()?;
+ fn conditional(&mut self) -> Result<IfNode> {
+ consume!(self, KeywordIf)?;
- Ok(Expression::Fn(Box::new(FnNode { header, body })))
- }
- KeywordIf => {
- consume!(self, KeywordIf)?;
+ let mut conditionals = Vec::new();
- let mut conditionals = Vec::new();
+ let if_condition = self.expression()?;
+ let if_block = self.generic_block()?;
- let if_condition = self.expression()?;
- let if_block = self.block()?;
+ conditionals.push(ConditionalBlock {
+ condition: if_condition,
+ block: if_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()?;
- // 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,
+ });
+ }
- 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
+ };
- let else_block = if consume_if!(self, KeywordElse).is_some() {
- Some(self.block()?)
- } else {
- None
- };
+ Ok(IfNode {
+ conditionals,
+ else_block,
+ })
+ }
- Ok(Expression::If(Box::new(IfNode {
- conditionals,
- else_block,
- })))
- }
- _ => Err(anyhow!("Unexpected token: {:?}", token.variant)),
- }
+ 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 {
- Err(anyhow!("Expected expression."))
- }
+ 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 => {