interpreter: Include location in error type

This commit is contained in:
John 2025-04-15 23:42:21 -04:00
parent fa5244dcf9
commit b09a610c6c
8 changed files with 224 additions and 122 deletions

View File

@ -79,7 +79,7 @@ pub macro builtin(
// Allow for single argument `fn foo(args @ ..)` pattern
#[allow(clippy::redundant_at_rest_pattern, irrefutable_let_patterns)]
let [$($arg),*] = _args else {
Err($crate::error::Error::TypeError)?
Err($crate::error::Error::TypeError())?
};
$body.map(Into::into)
}
@ -166,7 +166,7 @@ pub const Builtins: &[Builtin] = &builtins![
}
ConValue::Array(t) => t.len() as _,
ConValue::Tuple(t) => t.len() as _,
_ => Err(Error::TypeError)?,
_ => Err(Error::TypeError())?,
})
}
@ -191,7 +191,7 @@ pub const Math: &[Builtin] = &builtins![
Ok(match (lhs, rhs) {
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a * b),
_ => Err(Error::TypeError)?
_ => Err(Error::TypeError())?
})
}
@ -200,7 +200,7 @@ pub const Math: &[Builtin] = &builtins![
Ok(match (lhs, rhs){
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a / b),
_ => Err(Error::TypeError)?
_ => Err(Error::TypeError())?
})
}
@ -209,7 +209,7 @@ pub const Math: &[Builtin] = &builtins![
Ok(match (lhs, rhs) {
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a % b),
_ => Err(Error::TypeError)?,
_ => Err(Error::TypeError())?,
})
}
@ -219,7 +219,7 @@ pub const Math: &[Builtin] = &builtins![
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a + b),
(ConValue::String(a), ConValue::String(b)) => (a.to_string() + &b.to_string()).into(),
_ => Err(Error::TypeError)?
_ => Err(Error::TypeError())?
})
}
@ -228,7 +228,7 @@ pub const Math: &[Builtin] = &builtins![
Ok(match (lhs, rhs) {
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a - b),
_ => Err(Error::TypeError)?,
_ => Err(Error::TypeError())?,
})
}
@ -237,7 +237,7 @@ pub const Math: &[Builtin] = &builtins![
Ok(match (lhs, rhs) {
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a << b),
_ => Err(Error::TypeError)?,
_ => Err(Error::TypeError())?,
})
}
@ -246,7 +246,7 @@ pub const Math: &[Builtin] = &builtins![
Ok(match (lhs, rhs) {
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a >> b),
_ => Err(Error::TypeError)?,
_ => Err(Error::TypeError())?,
})
}
@ -256,7 +256,7 @@ pub const Math: &[Builtin] = &builtins![
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a & b),
_ => Err(Error::TypeError)?,
_ => Err(Error::TypeError())?,
})
}
@ -266,7 +266,7 @@ pub const Math: &[Builtin] = &builtins![
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a | b),
_ => Err(Error::TypeError)?,
_ => Err(Error::TypeError())?,
})
}
@ -276,7 +276,7 @@ pub const Math: &[Builtin] = &builtins![
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a ^ b),
_ => Err(Error::TypeError)?,
_ => Err(Error::TypeError())?,
})
}
@ -307,7 +307,7 @@ pub const Math: &[Builtin] = &builtins![
ConValue::Empty => ConValue::Empty,
ConValue::Int(v) => ConValue::Int(v.wrapping_neg()),
ConValue::Float(v) => ConValue::Float(-v),
_ => Err(Error::TypeError)?,
_ => Err(Error::TypeError())?,
})
}
@ -317,7 +317,7 @@ pub const Math: &[Builtin] = &builtins![
ConValue::Empty => ConValue::Empty,
ConValue::Int(v) => ConValue::Int(!v),
ConValue::Bool(v) => ConValue::Bool(!v),
_ => Err(Error::TypeError)?,
_ => Err(Error::TypeError())?,
})
}

View File

@ -1,15 +1,15 @@
//! Values in the dynamically typed AST interpreter.
//!
//! The most permanent fix is a temporary one.
use cl_ast::{format::FmtAdapter, Expr, Sym};
use cl_ast::{Expr, Sym, format::FmtAdapter};
use crate::env::Place;
use super::{
Callable, Environment,
builtin::Builtin,
error::{Error, IResult},
function::Function,
Callable, Environment,
};
use std::{collections::HashMap, ops::*, rc::Rc};
@ -80,7 +80,7 @@ impl ConValue {
pub fn truthy(&self) -> IResult<bool> {
match self {
ConValue::Bool(v) => Ok(*v),
_ => Err(Error::TypeError)?,
_ => Err(Error::TypeError())?,
}
}
@ -95,7 +95,7 @@ impl ConValue {
pub fn index(&self, index: &Self, env: &Environment) -> IResult<ConValue> {
let Self::Int(index) = index else {
Err(Error::TypeError)?
Err(Error::TypeError())?
};
match self {
ConValue::String(string) => string
@ -111,7 +111,7 @@ impl ConValue {
.get_id(*id)
.ok_or(Error::StackOverflow(*id))?
.index(&ConValue::Int((*index as usize + start) as isize), env),
_ => Err(Error::TypeError),
_ => Err(Error::TypeError()),
}
}
cmp! {
@ -164,7 +164,7 @@ macro cmp ($($fn:ident: $empty:literal, $op:tt);*$(;)?) {$(
(Self::Bool(a), Self::Bool(b)) => Ok(Self::Bool(a $op b)),
(Self::Char(a), Self::Char(b)) => Ok(Self::Bool(a $op b)),
(Self::String(a), Self::String(b)) => Ok(Self::Bool(&**a $op &**b)),
_ => Err(Error::TypeError)
_ => Err(Error::TypeError())
}
}
)*}
@ -234,25 +234,25 @@ ops! {
(ConValue::Char(a), ConValue::Char(b)) => {
ConValue::String([a, b].into_iter().collect::<String>().into())
}
_ => Err(Error::TypeError)?
_ => Err(Error::TypeError())?
]
BitAnd: bitand = [
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a & b),
_ => Err(Error::TypeError)?
_ => Err(Error::TypeError())?
]
BitOr: bitor = [
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a | b),
_ => Err(Error::TypeError)?
_ => Err(Error::TypeError())?
]
BitXor: bitxor = [
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a ^ b),
_ => Err(Error::TypeError)?
_ => Err(Error::TypeError())?
]
Div: div = [
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
@ -260,13 +260,13 @@ ops! {
eprintln!("Warning: Divide by zero in {a} / {b}"); a
})),
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a / b),
_ => Err(Error::TypeError)?
_ => Err(Error::TypeError())?
]
Mul: mul = [
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_mul(b)),
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a * b),
_ => Err(Error::TypeError)?
_ => Err(Error::TypeError())?
]
Rem: rem = [
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
@ -274,23 +274,23 @@ ops! {
println!("Warning: Divide by zero in {a} % {b}"); a
})),
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a % b),
_ => Err(Error::TypeError)?
_ => Err(Error::TypeError())?
]
Shl: shl = [
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shl(b as _)),
_ => Err(Error::TypeError)?
_ => Err(Error::TypeError())?
]
Shr: shr = [
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shr(b as _)),
_ => Err(Error::TypeError)?
_ => Err(Error::TypeError())?
]
Sub: sub = [
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_sub(b)),
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a - b),
_ => Err(Error::TypeError)?
_ => Err(Error::TypeError())?
]
}
impl std::fmt::Display for ConValue {

View File

@ -3,11 +3,11 @@
use crate::builtin::Builtin;
use super::{
Callable, Interpret,
builtin::{Builtins, Math},
convalue::ConValue,
error::{Error, IResult},
function::Function,
Callable, Interpret,
};
use cl_ast::{Function as FnDecl, Sym};
use std::{

View File

@ -7,9 +7,117 @@ use super::{convalue::ConValue, env::Place};
pub type IResult<T> = Result<T, Error>;
#[derive(Clone, Debug)]
pub struct Error {
pub kind: ErrorKind,
span: Option<Span>,
}
impl Error {
#![allow(non_snake_case)]
/// Adds a [Span] to this [Error], if there isn't already a more specific one.
pub fn with_span(self, span: Span) -> Self {
Self { span: self.span.or(Some(span)), ..self }
}
pub fn kind(&self) -> &ErrorKind {
&self.kind
}
/// Propagate a Return value
pub fn Return(value: ConValue) -> Self {
Self { kind: ErrorKind::Return(value), span: None }
}
/// Propagate a Break value
pub fn Break(value: ConValue) -> Self {
Self { kind: ErrorKind::Break(value), span: None }
}
/// Break propagated across function bounds
pub fn BadBreak(value: ConValue) -> Self {
Self { kind: ErrorKind::BadBreak(value), span: None }
}
/// Continue to the next iteration of a loop
pub fn Continue() -> Self {
Self { kind: ErrorKind::Continue, span: None }
}
/// Underflowed the stack
pub fn StackUnderflow() -> Self {
Self { kind: ErrorKind::StackUnderflow, span: None }
}
/// Overflowed the stack
pub fn StackOverflow(place: Place) -> Self {
Self { kind: ErrorKind::StackOverflow(place), span: None }
}
/// Exited the last scope
pub fn ScopeExit() -> Self {
Self { kind: ErrorKind::ScopeExit, span: None }
}
/// Type incompatibility
// TODO: store the type information in this error
pub fn TypeError() -> Self {
Self { kind: ErrorKind::TypeError, span: None }
}
/// In clause of For loop didn't yield a Range
pub fn NotIterable() -> Self {
Self { kind: ErrorKind::NotIterable, span: None }
}
/// A value could not be indexed
pub fn NotIndexable() -> Self {
Self { kind: ErrorKind::NotIndexable, span: None }
}
/// An array index went out of bounds
pub fn OobIndex(index: usize, length: usize) -> Self {
Self { kind: ErrorKind::OobIndex(index, length), span: None }
}
/// An expression is not assignable
pub fn NotAssignable() -> Self {
Self { kind: ErrorKind::NotAssignable, span: None }
}
/// A name was not defined in scope before being used
pub fn NotDefined(name: Sym) -> Self {
Self { kind: ErrorKind::NotDefined(name), span: None }
}
/// A name was defined but not initialized
pub fn NotInitialized(name: Sym) -> Self {
Self { kind: ErrorKind::NotInitialized(name), span: None }
}
/// A value was called, but is not callable
pub fn NotCallable(value: ConValue) -> Self {
Self { kind: ErrorKind::NotCallable(value), span: None }
}
/// A function was called with the wrong number of arguments
pub fn ArgNumber(want: usize, got: usize) -> Self {
Self { kind: ErrorKind::ArgNumber { want, got }, span: None }
}
/// A pattern failed to match
pub fn PatFailed(pat: Box<Pattern>) -> Self {
Self { kind: ErrorKind::PatFailed(pat), span: None }
}
/// Fell through a non-exhaustive match
pub fn MatchNonexhaustive() -> Self {
Self { kind: ErrorKind::MatchNonexhaustive, span: None }
}
/// Error produced by a Builtin
pub fn BuiltinDebug(msg: String) -> Self {
Self { kind: ErrorKind::BuiltinDebug(msg), span: None }
}
}
impl std::error::Error for Error {}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self { kind, span } = self;
if let Some(Span { head, tail }) = span {
write!(f, "{head}..{tail}: ")?;
}
write!(f, "{kind}")
}
}
/// Represents any error thrown by the [Environment](super::Environment)
#[derive(Clone, Debug)]
pub enum Error {
pub enum ErrorKind {
/// Propagate a Return value
Return(ConValue),
/// Propagate a Break value
@ -49,68 +157,55 @@ pub enum Error {
MatchNonexhaustive,
/// Error produced by a Builtin
BuiltinDebug(String),
/// Error with associated line information
WithSpan(Box<Error>, Span),
}
impl Error {
/// Adds a [Span] to this [Error], if there isn't already a more specific one.
pub fn with_span(self, span: Span) -> Self {
match self {
Self::WithSpan(..) => self,
err => Self::WithSpan(Box::new(err), span),
}
}
}
impl std::error::Error for Error {}
impl std::fmt::Display for Error {
impl std::error::Error for ErrorKind {}
impl std::fmt::Display for ErrorKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Return(value) => write!(f, "return {value}"),
Error::Break(value) => write!(f, "break {value}"),
Error::BadBreak(value) => write!(f, "rogue break: {value}"),
Error::Continue => "continue".fmt(f),
Error::StackUnderflow => "Stack underflow".fmt(f),
Error::StackOverflow(id) => {
ErrorKind::Return(value) => write!(f, "return {value}"),
ErrorKind::Break(value) => write!(f, "break {value}"),
ErrorKind::BadBreak(value) => write!(f, "rogue break: {value}"),
ErrorKind::Continue => "continue".fmt(f),
ErrorKind::StackUnderflow => "Stack underflow".fmt(f),
ErrorKind::StackOverflow(id) => {
write!(f, "Attempt to access <{id}> resulted in stack overflow.")
}
Error::ScopeExit => "Exited the last scope. This is a logic bug.".fmt(f),
Error::TypeError => "Incompatible types".fmt(f),
Error::NotIterable => "`in` clause of `for` loop did not yield an iterable".fmt(f),
Error::NotIndexable => {
ErrorKind::ScopeExit => "Exited the last scope. This is a logic bug.".fmt(f),
ErrorKind::TypeError => "Incompatible types".fmt(f),
ErrorKind::NotIterable => "`in` clause of `for` loop did not yield an iterable".fmt(f),
ErrorKind::NotIndexable => {
write!(f, "expression cannot be indexed")
}
Error::OobIndex(idx, len) => {
ErrorKind::OobIndex(idx, len) => {
write!(f, "Index out of bounds: index was {idx}. but len is {len}")
}
Error::NotAssignable => {
ErrorKind::NotAssignable => {
write!(f, "expression is not assignable")
}
Error::NotDefined(value) => {
ErrorKind::NotDefined(value) => {
write!(f, "{value} not bound. Did you mean `let {value};`?")
}
Error::NotInitialized(value) => {
ErrorKind::NotInitialized(value) => {
write!(f, "{value} bound, but not initialized")
}
Error::NotCallable(value) => {
ErrorKind::NotCallable(value) => {
write!(f, "{value} is not callable.")
}
Error::ArgNumber { want, got } => {
ErrorKind::ArgNumber { want, got } => {
write!(
f,
"Expected {want} argument{}, got {got}",
if *want == 1 { "" } else { "s" }
)
}
Error::PatFailed(pattern) => {
ErrorKind::PatFailed(pattern) => {
write!(f, "Failed to match pattern {pattern}")
}
Error::MatchNonexhaustive => {
ErrorKind::MatchNonexhaustive => {
write!(f, "Fell through a non-exhaustive match expression!")
}
Error::BuiltinDebug(s) => write!(f, "DEBUG: {s}"),
Error::WithSpan(e, span) => write!(f, "{}..{}: {e}", span.head, span.tail),
ErrorKind::BuiltinDebug(s) => write!(f, "DEBUG: {s}"),
}
}
}

View File

@ -2,7 +2,9 @@
use collect_upvars::collect_upvars;
use super::{pattern, Callable, ConValue, Environment, Error, IResult, Interpret};
use crate::error::ErrorKind;
use super::{Callable, ConValue, Environment, Error, IResult, Interpret, pattern};
use cl_ast::{Function as FnDecl, Sym};
use std::{
cell::{Ref, RefCell},
@ -56,10 +58,13 @@ impl Callable for Function {
// Check arg mapping
if args.len() != bind.len() {
return Err(Error::ArgNumber { want: bind.len(), got: args.len() });
return Err(Error::ArgNumber(bind.len(), args.len()));
}
if self.is_constructor {
return Ok(ConValue::TupleStruct(Box::new((name.to_ref(), args.into()))));
return Ok(ConValue::TupleStruct(Box::new((
name.to_ref(),
args.into(),
))));
}
let Some(body) = body else {
return Err(Error::NotDefined(*name));
@ -68,6 +73,8 @@ impl Callable for Function {
let upvars = self.upvars.take();
env.push_frame("upvars", upvars);
eprintln!("{name}{args:?}");
// TODO: completely refactor data storage
let mut frame = env.frame("fn args");
for (bind, value) in bind.iter().zip(args) {
@ -81,9 +88,9 @@ impl Callable for Function {
self.upvars.replace(upvars);
}
match res {
Err(Error::Return(value)) => Ok(value),
Err(Error::Break(value)) => Err(Error::BadBreak(value)),
result => result,
Err(Error { kind: ErrorKind::Return(value), .. }) => Ok(value),
Err(Error { kind: ErrorKind::Break(value), .. }) => Err(Error::BadBreak(value)),
other => other,
}
}
}

View File

@ -220,7 +220,7 @@ impl Interpret for UseTree {
}
UseTree::Path(PathPart::Ident(name), tree) => {
let Ok(ConValue::Module(m)) = env.get(*name) else {
Err(Error::TypeError)?
Err(Error::TypeError())?
};
env.push_frame(name.to_ref(), *m);
let out = get_bindings(tree, env, bindings);
@ -313,7 +313,7 @@ impl Interpret for ExprKind {
ExprKind::For(v) => v.interpret(env),
ExprKind::Break(v) => v.interpret(env),
ExprKind::Return(v) => v.interpret(env),
ExprKind::Continue => Err(Error::Continue),
ExprKind::Continue => Err(Error::Continue()),
}
}
}
@ -357,7 +357,7 @@ impl Interpret for Match {
return expr.interpret(&mut env);
}
}
Err(Error::MatchNonexhaustive)
Err(Error::MatchNonexhaustive())
}
}
@ -393,9 +393,9 @@ mod assignment {
&mut ConValue::Ref(r) => {
*env.get_id_mut(r).ok_or(Error::StackOverflow(r))? = Some(value)
}
_ => Err(Error::NotAssignable)?,
_ => Err(Error::NotAssignable())?,
},
_ => Err(Error::NotAssignable)?,
_ => Err(Error::NotAssignable())?,
}
Ok(())
}
@ -411,12 +411,12 @@ mod assignment {
ExprKind::Unary(Unary { kind: UnaryKind::Deref, tail }) => match *addrof(env, tail)? {
ConValue::Ref(place) => env
.get_id_mut(place)
.ok_or(Error::NotIndexable)?
.ok_or(Error::NotIndexable())?
.as_mut()
.ok_or(Error::NotAssignable),
_ => Err(Error::TypeError),
.ok_or(Error::NotAssignable()),
_ => Err(Error::TypeError()),
},
_ => Err(Error::TypeError),
_ => Err(Error::TypeError()),
}
}
@ -428,9 +428,9 @@ mod assignment {
[PathPart::Ident(name)] => env.get_mut(*name),
[PathPart::Ident(name), rest @ ..] => match env.get_mut(*name)? {
Some(ConValue::Module(env)) => project_path_in_namespace(env, rest),
_ => Err(Error::NotIndexable),
_ => Err(Error::NotIndexable()),
},
_ => Err(Error::NotAssignable),
_ => Err(Error::NotAssignable()),
}
}
@ -477,7 +477,7 @@ mod assignment {
t.get_mut(*id as usize)
.ok_or(Error::OobIndex(*id as _, len))
}
_ => Err(Error::TypeError),
_ => Err(Error::TypeError()),
}
}
@ -492,8 +492,8 @@ mod assignment {
a.get_mut(*i as usize)
.ok_or(Error::OobIndex(*i as usize, a_len))
}
(ConValue::Slice(_, _), _) => Err(Error::TypeError),
_ => Err(Error::NotIndexable),
(ConValue::Slice(_, _), _) => Err(Error::TypeError()),
_ => Err(Error::NotIndexable()),
}
}
@ -502,12 +502,12 @@ mod assignment {
path: &[PathPart],
) -> IResult<&'e mut Option<ConValue>> {
match path {
[] => Err(Error::NotAssignable),
[] => Err(Error::NotAssignable()),
[PathPart::Ident(name)] => env.get_mut(name).ok_or(Error::NotDefined(*name)),
[PathPart::Ident(name), rest @ ..] => {
match env.get_mut(name).ok_or(Error::NotDefined(*name))? {
Some(ConValue::Module(env)) => project_path_in_namespace(env, rest),
_ => Err(Error::NotIndexable),
_ => Err(Error::NotIndexable()),
}
}
[PathPart::SelfKw, rest @ ..] => project_path_in_namespace(env, rest),
@ -602,7 +602,7 @@ impl Interpret for Binary {
BinaryKind::Call => match tail {
ConValue::Empty => head.call(env, &[]),
ConValue::Tuple(args) => head.call(env, &args),
_ => Err(Error::TypeError),
_ => Err(Error::TypeError()),
},
_ => Ok(head),
}
@ -615,8 +615,8 @@ impl Interpret for Unary {
match kind {
UnaryKind::Loop => loop {
match tail.interpret(env) {
Err(Error::Break(value)) => return Ok(value),
Err(Error::Continue) => continue,
Err(Error { kind: ErrorKind::Break(value), .. }) => break Ok(value),
Err(Error { kind: ErrorKind::Continue, .. }) => continue,
e => e?,
};
},
@ -659,7 +659,7 @@ fn cast(env: &Environment, value: ConValue, ty: Sym) -> IResult<ConValue> {
ConValue::Ref(v) => {
return cast(
env,
env.get_id(v).cloned().ok_or(Error::StackUnderflow)?,
env.get_id(v).cloned().ok_or(Error::StackUnderflow())?,
ty,
);
}
@ -667,7 +667,7 @@ fn cast(env: &Environment, value: ConValue, ty: Sym) -> IResult<ConValue> {
ConValue::Float(_) if ty.starts_with('f') => return Ok(value),
ConValue::Float(f) => f as _,
_ if (*ty).eq("str") => return Ok(ConValue::String(format!("{value}").into())),
_ => Err(Error::TypeError)?,
_ => Err(Error::TypeError())?,
};
Ok(match &*ty {
"u8" => ConValue::Int(value as u8 as _),
@ -694,11 +694,11 @@ impl Interpret for Cast {
return Ok(ConValue::Empty);
};
let TyKind::Path(Path { absolute: false, parts }) = &ty.kind else {
Err(Error::TypeError)?
Err(Error::TypeError())?
};
match parts.as_slice() {
[PathPart::Ident(ty)] => cast(env, value, *ty),
_ => Err(Error::TypeError),
_ => Err(Error::TypeError()),
}
}
}
@ -816,7 +816,7 @@ impl Interpret for ArrayRep {
let Self { value, repeat } = self;
let repeat = match repeat.interpret(env)? {
ConValue::Int(v) => v,
_ => Err(Error::TypeError)?,
_ => Err(Error::TypeError())?,
};
let value = value.interpret(env)?;
Ok(ConValue::Array(vec![value; repeat as usize].into()))
@ -876,8 +876,8 @@ impl Interpret for While {
loop {
if cond.interpret(env)?.truthy()? {
match pass.interpret(env) {
Err(Error::Break(value)) => return Ok(value),
Err(Error::Continue) => continue,
Err(Error { kind: ErrorKind::Break(value), .. }) => break Ok(value),
Err(Error { kind: ErrorKind::Continue, .. }) => continue,
e => e?,
};
} else {
@ -907,19 +907,19 @@ impl Interpret for For {
[ConValue::Int(from), ConValue::Int(to)] => {
Box::new((from..to).map(ConValue::Int))
}
_ => Err(Error::NotIterable)?,
_ => Err(Error::NotIterable())?,
},
("RangeInc", values) => match **values {
[ConValue::Int(from), ConValue::Int(to)] => {
Box::new((from..=to).map(ConValue::Int))
}
_ => Err(Error::NotIterable)?,
_ => Err(Error::NotIterable())?,
},
_ => Err(Error::NotIterable)?,
_ => Err(Error::NotIterable())?,
},
ConValue::Array(a) => Box::new(a.iter().cloned()),
ConValue::String(s) => Box::new(s.chars().map(ConValue::Char)),
_ => Err(Error::TypeError)?,
_ => Err(Error::TypeError())?,
};
loop {
let mut env = env.frame("loop variable");
@ -928,9 +928,9 @@ impl Interpret for For {
env.insert(*name, Some(value));
}
match pass.interpret(&mut env) {
Err(Error::Break(value)) => return Ok(value),
Err(Error::Continue) => continue,
result => result?,
Err(Error { kind: ErrorKind::Break(value), .. }) => break Ok(value),
Err(Error { kind: ErrorKind::Continue, .. }) => continue,
e => e?,
};
} else {
break fail.interpret(&mut env);

View File

@ -5,7 +5,7 @@
use cl_ast::Sym;
use convalue::ConValue;
use env::Environment;
use error::{Error, IResult};
use error::{Error, ErrorKind, IResult};
use interpret::Interpret;
/// Callable types can be called from within a Conlang program

View File

@ -82,39 +82,39 @@ pub fn append_sub<'pat>(
) -> IResult<()> {
match (pat, value) {
(Pattern::Literal(Literal::Bool(a)), ConValue::Bool(b)) => {
(*a == b).then_some(()).ok_or(Error::NotAssignable)
(*a == b).then_some(()).ok_or(Error::NotAssignable())
}
(Pattern::Literal(Literal::Char(a)), ConValue::Char(b)) => {
(*a == b).then_some(()).ok_or(Error::NotAssignable)
(*a == b).then_some(()).ok_or(Error::NotAssignable())
}
(Pattern::Literal(Literal::Float(a)), ConValue::Float(b)) => (f64::from_bits(*a) == b)
.then_some(())
.ok_or(Error::NotAssignable),
.ok_or(Error::NotAssignable()),
(Pattern::Literal(Literal::Int(a)), ConValue::Int(b)) => {
(b == *a as _).then_some(()).ok_or(Error::NotAssignable)
(b == *a as _).then_some(()).ok_or(Error::NotAssignable())
}
(Pattern::Literal(Literal::String(a)), ConValue::String(b)) => {
(*a == *b).then_some(()).ok_or(Error::NotAssignable)
(*a == *b).then_some(()).ok_or(Error::NotAssignable())
}
(Pattern::Literal(_), _) => Err(Error::NotAssignable),
(Pattern::Literal(_), _) => Err(Error::NotAssignable()),
(Pattern::Rest(Some(pat)), value) => match (pat.as_ref(), value) {
(Pattern::Literal(Literal::Int(a)), ConValue::Int(b)) => {
(b < *a as _).then_some(()).ok_or(Error::NotAssignable)
(b < *a as _).then_some(()).ok_or(Error::NotAssignable())
}
(Pattern::Literal(Literal::Char(a)), ConValue::Char(b)) => {
(b < *a as _).then_some(()).ok_or(Error::NotAssignable)
(b < *a as _).then_some(()).ok_or(Error::NotAssignable())
}
(Pattern::Literal(Literal::Bool(a)), ConValue::Bool(b)) => {
(!b & *a).then_some(()).ok_or(Error::NotAssignable)
(!b & *a).then_some(()).ok_or(Error::NotAssignable())
}
(Pattern::Literal(Literal::Float(a)), ConValue::Float(b)) => {
(b < *a as _).then_some(()).ok_or(Error::NotAssignable)
(b < *a as _).then_some(()).ok_or(Error::NotAssignable())
}
(Pattern::Literal(Literal::String(a)), ConValue::String(b)) => {
(&*b < a).then_some(()).ok_or(Error::NotAssignable)
(&*b < a).then_some(()).ok_or(Error::NotAssignable())
}
_ => Err(Error::NotAssignable),
_ => Err(Error::NotAssignable()),
},
(Pattern::Name(name), _) if "_".eq(&**name) => Ok(()),
@ -149,7 +149,7 @@ pub fn append_sub<'pat>(
(Pattern::TupleStruct(path, patterns), ConValue::TupleStruct(parts)) => {
let (name, values) = *parts;
if !path.ends_with(name) {
Err(Error::TypeError)?
Err(Error::TypeError())?
}
match rest_binding(sub, patterns, values.into_vec().into())? {
Some((pattern, values)) => {
@ -162,10 +162,10 @@ pub fn append_sub<'pat>(
(Pattern::Struct(path, patterns), ConValue::Struct(parts)) => {
let (name, mut values) = *parts;
if !path.ends_with(&name) {
Err(Error::TypeError)?
Err(Error::TypeError())?
}
for (name, pat) in patterns {
let value = values.remove(name).ok_or(Error::TypeError)?;
let value = values.remove(name).ok_or(Error::TypeError())?;
match pat {
Some(pat) => append_sub(sub, pat, value)?,
None => {
@ -178,7 +178,7 @@ pub fn append_sub<'pat>(
_ => {
// eprintln!("Could not match pattern `{pat}` with value `{value}`!");
Err(Error::NotAssignable)
Err(Error::NotAssignable())
}
}
}