aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/interpret/operator.rs30
-rw-r--r--src/interpret/walker.rs189
-rw-r--r--src/lex/token.rs2
-rw-r--r--src/main.rs4
-rw-r--r--src/parse/ast/expression.rs4
-rw-r--r--src/parse/ast/statement.rs2
-rw-r--r--src/parse/parser.rs18
7 files changed, 142 insertions, 107 deletions
diff --git a/src/interpret/operator.rs b/src/interpret/operator.rs
index ce062c7..42c501e 100644
--- a/src/interpret/operator.rs
+++ b/src/interpret/operator.rs
@@ -1,6 +1,10 @@
use thiserror::Error;
-use crate::{parse::ast::expression::Expression, types::bag::TypeBag};
+use crate::{
+ error::{RHError, RHErrorKind},
+ parse::ast::expression::{Expression, ExpressionKind},
+ types::bag::TypeBag,
+};
use super::{
value::{Value, ValueKind},
@@ -261,12 +265,26 @@ impl<'t> ValueOperator<'t> {
// Yes, we create a new walker for every function call,
// it's *way* easier that way.
let mut walker = Walker::new(scope, self.types.clone());
- let result = walker.walk_expression(&Expression::Block(Box::new(called.node.body.clone())));
- if let Err(WalkerError::Return(returned)) = result {
- Ok(returned)
- } else {
- result
+ // Re-assemble the function body into an expression.
+ let body_expression = Expression {
+ kind: ExpressionKind::Block(Box::new(called.node.body.clone())),
+ at: called.node.body.at,
+ };
+
+ // Evaluate the function body.
+ let result = walker.walk_expression(&body_expression);
+
+ match result {
+ Err(RHError {
+ kind: RHErrorKind::Run(err),
+ ..
+ }) => match err {
+ WalkerError::Return(returned_value) => Ok(returned_value),
+ _ => Err(err),
+ },
+ Err(_) => panic!("Walker returned non-walker error."),
+ Ok(result) => Ok(result),
}
}
}
diff --git a/src/interpret/walker.rs b/src/interpret/walker.rs
index 01bde11..52f68c8 100644
--- a/src/interpret/walker.rs
+++ b/src/interpret/walker.rs
@@ -1,16 +1,19 @@
use std::{cell::RefCell, collections::HashMap, rc::Rc};
use crate::{
+ error::{ErrorLocation, RHError, RHErrorKind},
interpret::{
operator::ValueOperator,
value::{FnValue, ValueKind},
},
+ lex::token::Location,
parse::ast::{
- expression::Expression,
+ expression::{Expression, ExpressionKind},
nodes::{
- BinaryOperator as BinOp, BlockNode, SimpleLiteral, StrPart, UnaryOperator as UnOp,
+ BinaryOperatorKind as BinOp, BlockExpression, SimpleLiteralKind, StrPartKind,
+ UnaryOperatorKind as UnOp,
},
- statement::Statement,
+ statement::{Statement, StatementKind},
Program,
},
types::{bag::TypeBag, TypeKind},
@@ -41,64 +44,70 @@ impl Walker {
Walker { scope, types }
}
- pub fn walk(&mut self, program: &Program) {
+ pub fn walk(&mut self, program: &Program) -> Result<(), RHError> {
self.scope.nest();
for statement in program.statements.iter() {
- self.walk_statement(statement).expect("Runtime error.");
+ self.walk_statement(statement)?;
}
+ Ok(())
}
- fn walk_statement(&mut self, statement: &Statement) -> Result<Option<Value>, WalkerError> {
- let result = match statement {
- Statement::Expression(node) => {
+ fn walk_statement(&mut self, statement: &Statement) -> Result<Option<Value>, RHError> {
+ let result = match &statement.kind {
+ StatementKind::Expression(node) => {
self.walk_expression(node)?;
None
}
- Statement::Print(node) => {
+ StatementKind::Print(node) => {
let result = self.walk_expression(node)?;
println!("{}", result);
None
}
// FIXME: Returns are always expected to have a return even though `return;` is valid.
- Statement::Return(node) => {
+ StatementKind::Return(node) => {
// If there's a function running above us it will catch this error.
- return Err(WalkerError::Return(self.walk_expression(node)?));
+ return Err(walker_error(
+ statement.at,
+ WalkerError::Return(self.walk_expression(node)?),
+ ));
}
- Statement::Break(node) => {
+ StatementKind::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));
+ return Err(walker_error(statement.at, WalkerError::LoopBreak(returned)));
}
// Same here.
- Statement::Continue => return Err(WalkerError::LoopContinue),
+ StatementKind::Continue => {
+ return Err(walker_error(statement.at, WalkerError::LoopContinue));
+ }
};
Ok(result)
}
- pub fn walk_expression(&mut self, node: &Expression) -> Result<Value, WalkerError> {
- match node {
- Expression::Binary { left, op, right } => {
+ pub fn walk_expression(&mut self, node: &Expression) -> Result<Value, RHError> {
+ match &node.kind {
+ ExpressionKind::Binary { left, op, right } => {
// Assignment
- match op {
+ match op.kind {
BinOp::ConstAssign => return self.assing_to_lvalue(left, right, true),
BinOp::Assign => return self.assing_to_lvalue(left, right, false),
_ => {}
}
// Short-circuting operators
- if let BinOp::And | BinOp::Or = op {
+ if let BinOp::And | BinOp::Or = op.kind {
let left_value = self.walk_expression(left)?;
let is_left_true = match left_value.kind {
ValueKind::Bool(bool) => bool,
- _ => return Err(WalkerError::WrongAndOrType),
+ _ => return Err(walker_error(left.at, WalkerError::WrongAndOrType)),
};
- if let BinOp::And = op {
+ if let BinOp::And = op.kind {
if !is_left_true {
return Ok(Value::bool(false, &self.types));
}
@@ -115,7 +124,7 @@ impl Walker {
let exe = ValueOperator::new(&self.types);
// Other operators
- match op {
+ match op.kind {
BinOp::Plus => exe.add(left, right),
BinOp::Minus => exe.sub(left, right),
BinOp::Star => exe.mul(left, right),
@@ -127,23 +136,22 @@ impl Walker {
BinOp::Gte => exe.gte(left, right),
BinOp::Lt => exe.gt(right, left),
BinOp::Lte => exe.gte(right, left),
-
_ => unreachable!(),
}
- .map_err(WalkerError::OperationError)
+ .map_err(|err| walker_error(op.at, WalkerError::OperationError(err)))
}
- Expression::Unary { op, right } => {
+ ExpressionKind::Unary { op, right } => {
let value = self.walk_expression(right)?;
let exe = ValueOperator::new(&self.types);
- match op {
+ match op.kind {
UnOp::Minus => exe.neg(value),
UnOp::Not => exe.not(value),
}
- .map_err(WalkerError::OperationError)
+ .map_err(|err| walker_error(op.at, WalkerError::OperationError(err)))
}
- Expression::Call(node) => {
+ ExpressionKind::Call(node) => {
let called = self.walk_expression(&node.called)?;
let mut argument_values = Vec::new();
@@ -153,18 +161,19 @@ impl Walker {
let exe = ValueOperator::new(&self.types);
exe.call(&called, argument_values)
+ .map_err(|err| walker_error(node.at, err))
}
- Expression::ArrayAccess(node) => {
+ ExpressionKind::ArrayAccess(node) => {
let array = self.walk_expression(&node.array)?;
let index = self.walk_expression(&node.index)?;
let exe = ValueOperator::new(&self.types);
exe.subscript(array, index)
- .map_err(WalkerError::OperationError)
+ .map_err(|err| walker_error(node.at, WalkerError::OperationError(err)))
}
- Expression::MemberAccess(_) => todo!("Structures not implemented yet."),
- Expression::Group(node) => self.walk_expression(node),
- Expression::ArrayLiteral(node) => {
+ ExpressionKind::MemberAccess(_) => todo!("Structures not implemented yet."),
+ ExpressionKind::Group(node) => self.walk_expression(node),
+ ExpressionKind::ArrayLiteral(node) => {
let mut elements = Vec::new();
for expression in &node.elements {
elements.push(self.walk_expression(expression)?);
@@ -175,23 +184,23 @@ impl Walker {
typ: self.types.create_type(TypeKind::Array(self.types.void())),
})
}
- Expression::SimpleLiteral(token) => {
- let value = match token {
- SimpleLiteral::Int(int) => Value::int(*int as i64, &self.types),
- SimpleLiteral::Float(float) => Value::float(*float as f64, &self.types),
- SimpleLiteral::Bool(bool) => Value::bool(*bool, &self.types),
+ ExpressionKind::SimpleLiteral(node) => {
+ let value = match node.kind {
+ SimpleLiteralKind::Int(int) => Value::int(int as i64, &self.types),
+ SimpleLiteralKind::Float(float) => Value::float(float as f64, &self.types),
+ SimpleLiteralKind::Bool(bool) => Value::bool(bool, &self.types),
};
Ok(value)
}
- Expression::Block(block) => self.walk_block(block.as_ref()),
- Expression::StrLiteral(node) => {
+ ExpressionKind::Block(block) => self.walk_block(block.as_ref()),
+ ExpressionKind::StrLiteral(node) => {
let mut buffer = String::new();
for part in &node.parts {
- match part {
- StrPart::Literal(literal) => buffer.push_str(literal),
- StrPart::Embed(embed) => {
+ match &part.kind {
+ StrPartKind::Literal(literal) => buffer.push_str(literal),
+ StrPartKind::Embed(embed) => {
buffer.push_str(&self.walk_expression(embed)?.to_string())
}
};
@@ -199,7 +208,7 @@ impl Walker {
Ok(Value::str(buffer, &self.types))
}
- Expression::FnLiteral(node) => Ok(Value {
+ ExpressionKind::FnLiteral(node) => Ok(Value {
kind: ValueKind::Fn(Rc::new(RefCell::new(FnValue {
node: node.as_ref().clone(),
scope: self.scope.clone(),
@@ -210,7 +219,7 @@ impl Walker {
returns: self.types.void(),
}),
}),
- Expression::If(if_node) => {
+ ExpressionKind::If(if_node) => {
for conditional in &if_node.conditionals {
if let ValueKind::Bool(bool) =
self.walk_expression(&conditional.condition)?.kind
@@ -219,7 +228,10 @@ impl Walker {
return self.walk_block(&conditional.block);
}
} else {
- return Err(WalkerError::WrongIfConditionType);
+ return Err(walker_error(
+ conditional.at,
+ WalkerError::WrongIfConditionType,
+ ));
}
}
@@ -229,52 +241,48 @@ impl Walker {
Ok(Value::void(&self.types))
}
}
- Expression::Loop(loop_node) => {
- if let Some(condition) = &loop_node.condition {
- loop {
- if let ValueKind::Bool(should_repeat) =
- self.walk_expression(condition)?.kind
- {
- if should_repeat {
- match self.walk_block(&loop_node.body) {
- Err(WalkerError::LoopBreak(loop_value)) => {
- return Ok(loop_value.unwrap_or(Value::void(&self.types)));
- }
- // 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 {
+ ExpressionKind::Loop(loop_node) => {
+ loop {
+ if let Some(condition) = &loop_node.condition {
+ let condition_value = self.walk_expression(condition)?;
+ if let ValueKind::Bool(should_repeat) = condition_value.kind {
+ if !should_repeat {
return Ok(Value::void(&self.types));
}
} else {
- return Err(WalkerError::WrongLoopConditionType);
+ return Err(walker_error(
+ condition.at,
+ 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(&self.types)));
+
+ match self.walk_block(&loop_node.body) {
+ Err(RHError {
+ kind: RHErrorKind::Run(err),
+ at: ErrorLocation::Specific(at),
+ }) => match err {
+ WalkerError::LoopBreak(loop_value) => {
+ return Ok(loop_value.unwrap_or(Value::void(&self.types)));
}
- Err(WalkerError::LoopContinue) => {}
- Err(x) => return Err(x),
- _ => {}
- }
+ // Do nothing for continue and continue looping of course, you dummy.
+ WalkerError::LoopContinue => {}
+ // This is probably an actual error.
+ _ => return Err(walker_error(at, err)),
+ },
+ Err(_) => panic!("Walker returned non-walker error."),
+ _ => {}
}
}
}
- Expression::Identifier(ident) => self
+ ExpressionKind::Identifier(ident) => self
.scope
.get_var(ident, &self.types)
- .map_err(WalkerError::ScopeError),
+ .map_err(|err| walker_error(node.at, WalkerError::ScopeError(err))),
}
}
- fn walk_block(&mut self, block: &BlockNode) -> Result<Value, WalkerError> {
+ fn walk_block(&mut self, block: &BlockExpression) -> Result<Value, RHError> {
self.scope.nest();
for statement in block.statements.iter() {
@@ -297,11 +305,11 @@ impl Walker {
lvalue: &Expression,
rvalue: &Expression,
is_constant: bool,
- ) -> Result<Value, WalkerError> {
+ ) -> Result<Value, RHError> {
// Maybe other expressions could also be l-values, but these are fine for now.
- match lvalue {
- Expression::MemberAccess(_) => todo!("Structures not implemented yet."),
- Expression::ArrayAccess(node) => {
+ match &lvalue.kind {
+ ExpressionKind::MemberAccess(_) => todo!("Structures not implemented yet."),
+ ExpressionKind::ArrayAccess(node) => {
let mut array = self.walk_expression(&node.array)?;
let index = self.walk_expression(&node.index)?;
let value = self.walk_expression(rvalue)?;
@@ -309,21 +317,28 @@ impl Walker {
let exe = ValueOperator::new(&self.types);
exe.subscript_assign(&mut array, index, value)
- .map_err(WalkerError::OperationError)
+ .map_err(|err| walker_error(node.at, WalkerError::OperationError(err)))
}
- Expression::Identifier(ident) => {
+ ExpressionKind::Identifier(ident) => {
let value = self.walk_expression(rvalue)?;
self.scope
.set_var(ident, value.clone(), is_constant)
- .map_err(WalkerError::ScopeError)?;
+ .map_err(|err| walker_error(lvalue.at, WalkerError::ScopeError(err)))?;
return Ok(value);
}
- _ => Err(WalkerError::NonLValueAssignment),
+ _ => Err(walker_error(lvalue.at, WalkerError::NonLValueAssignment)),
}
}
}
-// TODO: Add source maps to the errors.
+// This assumes walker errors are always at a specific error location.
+fn walker_error(at: Location, walker_error: WalkerError) -> RHError {
+ RHError {
+ at: ErrorLocation::Specific(at),
+ kind: RHErrorKind::Run(walker_error),
+ }
+}
+
#[derive(Error, Debug)]
pub enum WalkerError {
#[error("Loop expressions can only take boolean values as conditions.")]
diff --git a/src/lex/token.rs b/src/lex/token.rs
index 9d6ded0..9435784 100644
--- a/src/lex/token.rs
+++ b/src/lex/token.rs
@@ -1,4 +1,4 @@
-use std::fmt::{write, Display};
+use std::fmt::Display;
#[derive(Clone, Copy, Debug)]
pub struct Location {
diff --git a/src/main.rs b/src/main.rs
index 63f2347..a670f92 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -32,7 +32,7 @@ fn file(filename: impl AsRef<Path>) {
let node = handle_error(parser.parse(), &contents);
let mut walker = Walker::root();
- walker.walk(&node);
+ handle_error(walker.walk(&node), &contents);
}
fn repl() {
@@ -55,7 +55,7 @@ fn repl() {
let mut parser = Parser::new(lexer);
let node = handle_error(parser.expression(), &input_buffer);
- let result = walker.walk_expression(&node).expect("Failed interpreting.");
+ let result = handle_error(walker.walk_expression(&node), &input_buffer);
println!("🥕: {:?}\n", result);
}
diff --git a/src/parse/ast/expression.rs b/src/parse/ast/expression.rs
index e883aaa..e67150a 100644
--- a/src/parse/ast/expression.rs
+++ b/src/parse/ast/expression.rs
@@ -52,7 +52,7 @@ impl Display for Expression {
impl Expression {
pub(crate) fn nested_fmt(&self, f: &mut Formatter<'_>, depth: usize) -> fmt::Result {
let pad = " ".repeat(depth);
- match self.kind {
+ match &self.kind {
ExpressionKind::Binary { left, op, right } => {
writeln!(f, "{}Binary:", pad)?;
writeln!(f, "{}- Left:", pad)?;
@@ -100,7 +100,7 @@ impl Expression {
writeln!(f, "{}Str:", pad)?;
for (i, statement) in expr.parts.iter().enumerate() {
writeln!(f, "{}- {}:", pad, i)?;
- match statement.kind {
+ match &statement.kind {
StrPartKind::Literal(literal) => {
writeln!(f, "{}{}", " ".repeat(depth + 1), literal.clone())
}
diff --git a/src/parse/ast/statement.rs b/src/parse/ast/statement.rs
index 7eb9978..7ed91dc 100644
--- a/src/parse/ast/statement.rs
+++ b/src/parse/ast/statement.rs
@@ -32,7 +32,7 @@ impl Statement {
depth: usize,
) -> std::fmt::Result {
let pad = " ".repeat(depth);
- match self.kind {
+ match &self.kind {
StatementKind::Expression(expression) => expression.nested_fmt(f, depth)?,
StatementKind::Print(expression) => {
writeln!(f, "{}Print:", pad)?;
diff --git a/src/parse/parser.rs b/src/parse/parser.rs
index 4363bbb..19f26b1 100644
--- a/src/parse/parser.rs
+++ b/src/parse/parser.rs
@@ -303,7 +303,10 @@ impl<T: Iterator<Item = Token>> Parser<T> {
_ => unreachable!(),
};
- left = Expression { at: left.at, kind };
+ left = Expression {
+ at: token.location,
+ kind,
+ };
}
Ok(left)
@@ -311,6 +314,8 @@ impl<T: Iterator<Item = Token>> Parser<T> {
fn unit_expression(&mut self) -> Result<Expression, RHError> {
if let Some(token) = self.tokens.peek() {
+ let location = token.location;
+
let kind = match token.kind {
Int(_) | Float(_) | Str(_) | KeywordTrue | KeywordFalse => {
let literal = self.tokens.next().unwrap();
@@ -352,10 +357,7 @@ impl<T: Iterator<Item = Token>> Parser<T> {
)),
}?;
- Ok(Expression {
- at: token.location,
- kind,
- })
+ Ok(Expression { at: location, kind })
} else {
Err(parser_error(
ErrorLocation::Eof,
@@ -492,9 +494,9 @@ impl<T: Iterator<Item = Token>> Parser<T> {
let if_block = self.generic_block()?;
conditionals.push(ConditionalBlockNode {
+ at: if_condition.at,
condition: if_condition,
block: if_block,
- at: if_condition.at,
});
// Elifs
@@ -503,9 +505,9 @@ impl<T: Iterator<Item = Token>> Parser<T> {
let elif_block = self.generic_block()?;
conditionals.push(ConditionalBlockNode {
+ at: elif_condition.at,
condition: elif_condition,
block: elif_block,
- at: elif_condition.at,
});
}
@@ -559,8 +561,8 @@ impl<T: Iterator<Item = Token>> Parser<T> {
let expression = self.expression()?;
if consume_if!(self, SemiColon).is_some() {
statements.push(Statement {
- kind: StatementKind::Expression(expression),
at: expression.at,
+ kind: StatementKind::Expression(expression),
});
} else {
tail_expression = Some(expression);