interpreter: Include location in error type
This commit is contained in:
parent
fa5244dcf9
commit
b09a610c6c
@ -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())?,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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::{
|
||||
|
@ -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}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user