Skip to content

Commit

Permalink
improve error reporting
Browse files Browse the repository at this point in the history
  • Loading branch information
tw-ilson committed Dec 11, 2024
1 parent 9e1f345 commit cef1fe1
Show file tree
Hide file tree
Showing 30 changed files with 454 additions and 261 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
members=[
"libludi",
"interpreter",
"ludic"
]
resolver="2"
5 changes: 5 additions & 0 deletions examples/basic_arithmetic.ludi
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fn main() {
let a = 12;
let b = 4;
a+b
}
8 changes: 4 additions & 4 deletions interpreter/src/array.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::datatypes::{ArrayType, AtomicType};
use libludi::ast::FrameNode;
use libludi::err::{Error, LudiError, Result};
use libludi::err::{Error, LudiError, RuntimeErrorKind, Result};
use libludi::shape::ambassador_impl_ArrayProps;
use libludi::shape::ambassador_impl_ShapeOps;
use libludi::shape::{ArrayProps, Shape, ShapeOps};
Expand Down Expand Up @@ -131,7 +131,7 @@ impl<A> IntoIterator for Array<A> {
}
}
impl TryInto<Shape> for Array<isize> {
type Error = Error;
type Error = anyhow::Error;
fn try_into(self) -> Result<Shape> {
if self.rank() != 1 {
Err(anyhow::anyhow!(
Expand All @@ -149,7 +149,7 @@ impl TryInto<Shape> for Array<isize> {
}

impl TryInto<Shape> for Array<usize> {
type Error = Error;
type Error = anyhow::Error;
fn try_into(self) -> Result<Shape> {
if self.rank() != 1 {
Err(anyhow::anyhow!(
Expand Down Expand Up @@ -208,7 +208,7 @@ impl FromIterator<ArrayType> for Result<ArrayType> {
newaxis +=1;
Ok(array_base.data_raw().into_iter())
} else {
Err(Error::runtime_err("Frame error: mismatched types or shape in frame"))
Err(Error::runtime_err(RuntimeErrorKind::InterpretError, "Frame error: mismatched types or shape in frame").into())
}).flatten_ok().collect::<Result<Vec<_>>>()?,
shape: Shape::new(&[newaxis]).concat(rest_of_shape),
}
Expand Down
41 changes: 26 additions & 15 deletions interpreter/src/datatypes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::interpret::DynamicEnv;

use libludi::ast::{Arg, FnDefNode, FuncSignature};
use libludi::atomic::Literal;
use libludi::err::{Error, LudiError, Result};
use libludi::err::{Error, LudiError, Result, RuntimeErrorKind};
use libludi::shape::ambassador_impl_ArrayProps;
use libludi::shape::ambassador_impl_ShapeOps;
use libludi::shape::{ArrayProps, Shape, ShapeOps};
Expand Down Expand Up @@ -35,7 +35,7 @@ pub trait Data // BinaryOp +
pub enum DataType {
Array(ArrayType),
Atomic(AtomicType),
Unit
Unit,
}
impl Data for DataType {}

Expand Down Expand Up @@ -80,7 +80,6 @@ pub enum ArrayType {
Fn(Array<FunctionData>),
}


#[repr(u8)]
#[derive(derive_more::Display, Eq, Debug, Copy, Clone, PartialEq)]
pub enum DataTypeTag {
Expand Down Expand Up @@ -123,8 +122,9 @@ impl FromIterator<DataType> for Result<DataType> {
} else {
//TODO: add better error information
Err(Error::runtime_err(
RuntimeErrorKind::InterpretError,
"Frame error: found non conforming value in frame",
))
).into())
}
})
.collect::<Result<Result<ArrayType>>>()??,
Expand All @@ -134,13 +134,17 @@ impl FromIterator<DataType> for Result<DataType> {
Ok(a.upgrade())
} else {
Err(Error::runtime_err(
RuntimeErrorKind::InterpretError,
"Frame error: found non conforming value in frame",
))
).into())
}
})
.collect::<Result<Result<ArrayType>>>()??,
Some(DataType::Unit) => return Ok(DataType::Unit),
None => Err(Error::runtime_err("Frame error: empty frame"))?,
None => Err(Error::runtime_err(
RuntimeErrorKind::InterpretError,
"Frame error: empty frame"
))?,
}
}))
}
Expand All @@ -153,7 +157,7 @@ impl FromIterator<DataType> for Result<DataType> {
// }

impl FromStr for DataTypeTag {
type Err = Error;
type Err = anyhow::Error;
fn from_str(s: &str) -> Result<Self> {
match s {
"u8" => Ok(DataTypeTag::UInt8),
Expand All @@ -172,15 +176,21 @@ impl FromStr for DataTypeTag {
"char" => Ok(DataTypeTag::Character),
"bool" => Ok(DataTypeTag::Boolean),
"box" => Err(Error::runtime_err(
RuntimeErrorKind::InterpretError,
"Box type not supported in function signature",
)),
).into()),
"fn" => Err(Error::runtime_err(
RuntimeErrorKind::InterpretError,
"Fn type not suppored in function signature",
)),
).into()),
"()" => Err(Error::runtime_err(
RuntimeErrorKind::InterpretError,
"Unit type not supported in function signature",
)),
_ => Err(Error::runtime_err("not a known builtin type")),
).into()),
_ => Err(Error::runtime_err(
RuntimeErrorKind::InterpretError,
"not a known builtin type",
).into()),
}
}
}
Expand All @@ -192,12 +202,13 @@ pub struct TypeSignature(pub DataTypeTag, pub Shape);
pub struct OptionalTypeSignature(pub Option<DataTypeTag>, pub Shape);

impl TryFrom<OptionalTypeSignature> for TypeSignature {
type Error = Error;
type Error = anyhow::Error;
fn try_from(value: OptionalTypeSignature) -> Result<Self> {
Ok(TypeSignature(
value
.0
.ok_or(Error::runtime_err("expected explicit type annotations"))?,
value.0.ok_or(Error::runtime_err(
RuntimeErrorKind::InterpretError,
"expected explicit type annotations",
))?,
value.1,
))
}
Expand Down
2 changes: 1 addition & 1 deletion interpreter/src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ impl Callable for FunctionData {
));
}
e.push_with(
zip(self.params().into_iter(), arguments.into_iter()).map(|(Arg(name, ty), value)| {
zip(self.params().into_iter(), arguments.into_iter()).map(|(Arg(name, _ty), value)| {
//TODO: check type agreement
(name.clone(), value.into())
}),
Expand Down
44 changes: 22 additions & 22 deletions interpreter/src/interpret.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use itertools::Itertools;
use libludi::{
ast::*,
env::Env,
err::{Error, LudiError, Result},
err::{Error, LudiError, Result, RuntimeErrorKind},
shape::{ArrayProps, Shape, ShapeOps},
token::Token,
types::{self, Atom, AtomicDataType, PrimitiveFuncType, Type},
Expand Down Expand Up @@ -177,9 +177,9 @@ impl Interpret for FnCallNode {
// interpreter should prevent branches diverge...
}
}
_ => Err(Error::runtime_err(
_ => Err(Error::runtime_err(RuntimeErrorKind::InterpretError,
"if expression expected boolean condition",
)),
).into()),
}
}
PrimitiveFuncType::Gt => {
Expand All @@ -195,9 +195,9 @@ impl Interpret for FnCallNode {
DataType::Atomic(AtomicType::Float(a)),
DataType::Atomic(AtomicType::Float(b)),
) => Ok(DataType::Atomic(AtomicType::Boolean(a > b))),
_ => Err(Error::runtime_err(
_ => Err(Error::runtime_err(RuntimeErrorKind::InterpretError,
"type error: '>' op is not defined for between these types",
)),
).into()),
}
}
PrimitiveFuncType::GtEq => {
Expand All @@ -213,9 +213,9 @@ impl Interpret for FnCallNode {
DataType::Atomic(AtomicType::Float(a)),
DataType::Atomic(AtomicType::Float(b)),
) => Ok(DataType::Atomic(AtomicType::Boolean(a >= b))),
_ => Err(Error::runtime_err(
_ => Err(Error::runtime_err(RuntimeErrorKind::InterpretError,
"type error: '>=' op is not defined for between these types",
)),
).into()),
}
}
PrimitiveFuncType::Lt => {
Expand All @@ -231,9 +231,9 @@ impl Interpret for FnCallNode {
DataType::Atomic(AtomicType::Float(a)),
DataType::Atomic(AtomicType::Float(b)),
) => Ok(DataType::Atomic(AtomicType::Boolean(a < b))),
_ => Err(Error::runtime_err(
_ => Err(Error::runtime_err(RuntimeErrorKind::InterpretError,
"type error: '<' op is not defined for between these types",
)),
).into()),
}
}
PrimitiveFuncType::LtEq => {
Expand All @@ -249,9 +249,9 @@ impl Interpret for FnCallNode {
DataType::Atomic(AtomicType::Float(a)),
DataType::Atomic(AtomicType::Float(b)),
) => Ok(DataType::Atomic(AtomicType::Boolean(a <= b))),
_ => Err(Error::runtime_err(
_ => Err(Error::runtime_err(RuntimeErrorKind::InterpretError,
"type error: '<=' op is not defined for between these types",
)),
).into()),
}
}
PrimitiveFuncType::Ne => {
Expand All @@ -271,9 +271,9 @@ impl Interpret for FnCallNode {
DataType::Atomic(AtomicType::Character(a)),
DataType::Atomic(AtomicType::Character(b)),
) => Ok(DataType::Atomic(AtomicType::Boolean(a != b))),
_ => Err(Error::runtime_err(
_ => Err(Error::runtime_err(RuntimeErrorKind::InterpretError,
"type error: '!=' op is not defined for between these types",
)),
).into()),
}
}
PrimitiveFuncType::Eq => {
Expand All @@ -293,9 +293,9 @@ impl Interpret for FnCallNode {
DataType::Atomic(AtomicType::Character(a)),
DataType::Atomic(AtomicType::Character(b)),
) => Ok(DataType::Atomic(AtomicType::Boolean(a == b))),
_ => Err(Error::runtime_err(
_ => Err(Error::runtime_err(RuntimeErrorKind::InterpretError,
"type error: '==' op is not defined for between these types",
)),
).into()),
}
}
PrimitiveFuncType::And => {
Expand All @@ -308,9 +308,9 @@ impl Interpret for FnCallNode {
DataType::Atomic(AtomicType::Boolean(a)),
DataType::Atomic(AtomicType::Boolean(b)),
) => Ok(DataType::Atomic(AtomicType::Boolean(a && b))),
_ => Err(Error::runtime_err(
_ => Err(Error::runtime_err(RuntimeErrorKind::InterpretError,
"type error: 'and' op is not defined for between these types",
)),
).into()),
}
}
PrimitiveFuncType::Or => {
Expand All @@ -323,9 +323,9 @@ impl Interpret for FnCallNode {
DataType::Atomic(AtomicType::Boolean(a)),
DataType::Atomic(AtomicType::Boolean(b)),
) => Ok(DataType::Atomic(AtomicType::Boolean(a || b))),
_ => Err(Error::runtime_err(
_ => Err(Error::runtime_err(RuntimeErrorKind::InterpretError,
"type error: 'or' op is not defined for between these types",
)),
).into()),
}
}
PrimitiveFuncType::Not => {
Expand All @@ -335,9 +335,9 @@ impl Interpret for FnCallNode {
DataType::Atomic(AtomicType::Boolean(a)) => {
Ok(DataType::Atomic(AtomicType::Boolean(!a)))
}
_ => Err(Error::runtime_err(
_ => Err(Error::runtime_err(RuntimeErrorKind::InterpretError,
"type error: 'not' op is not defined for between these types",
)),
).into()),
}
}
PrimitiveFuncType::Neg => {
Expand All @@ -353,7 +353,7 @@ impl Interpret for FnCallNode {
crate::datatypes::ArrayType::Int(Iota::iota(i.try_into()?)),
)),
DataType::Array(ArrayType::Int(_a_i)) => todo!(),
_ => Err(Error::runtime_err("error: Iota expects integer")),
_ => Err(Error::runtime_err(RuntimeErrorKind::InterpretError, "error: Iota expects integer").into()),
}
}
PrimitiveFuncType::Reshape => {
Expand Down
Loading

0 comments on commit cef1fe1

Please sign in to comment.