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 for single argument `fn foo(args @ ..)` pattern
|
||||||
#[allow(clippy::redundant_at_rest_pattern, irrefutable_let_patterns)]
|
#[allow(clippy::redundant_at_rest_pattern, irrefutable_let_patterns)]
|
||||||
let [$($arg),*] = _args else {
|
let [$($arg),*] = _args else {
|
||||||
Err($crate::error::Error::TypeError)?
|
Err($crate::error::Error::TypeError())?
|
||||||
};
|
};
|
||||||
$body.map(Into::into)
|
$body.map(Into::into)
|
||||||
}
|
}
|
||||||
@ -166,7 +166,7 @@ pub const Builtins: &[Builtin] = &builtins![
|
|||||||
}
|
}
|
||||||
ConValue::Array(t) => t.len() as _,
|
ConValue::Array(t) => t.len() as _,
|
||||||
ConValue::Tuple(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) {
|
Ok(match (lhs, rhs) {
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a * b),
|
(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){
|
Ok(match (lhs, rhs){
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a / b),
|
(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) {
|
Ok(match (lhs, rhs) {
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a % b),
|
(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::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a + b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a + b),
|
||||||
(ConValue::String(a), ConValue::String(b)) => (a.to_string() + &b.to_string()).into(),
|
(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) {
|
Ok(match (lhs, rhs) {
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a - b),
|
(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) {
|
Ok(match (lhs, rhs) {
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a << b),
|
(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) {
|
Ok(match (lhs, rhs) {
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a >> b),
|
(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::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
|
||||||
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(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::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
|
||||||
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(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::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
|
||||||
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(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::Empty => ConValue::Empty,
|
||||||
ConValue::Int(v) => ConValue::Int(v.wrapping_neg()),
|
ConValue::Int(v) => ConValue::Int(v.wrapping_neg()),
|
||||||
ConValue::Float(v) => ConValue::Float(-v),
|
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::Empty => ConValue::Empty,
|
||||||
ConValue::Int(v) => ConValue::Int(!v),
|
ConValue::Int(v) => ConValue::Int(!v),
|
||||||
ConValue::Bool(v) => ConValue::Bool(!v),
|
ConValue::Bool(v) => ConValue::Bool(!v),
|
||||||
_ => Err(Error::TypeError)?,
|
_ => Err(Error::TypeError())?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
//! Values in the dynamically typed AST interpreter.
|
//! Values in the dynamically typed AST interpreter.
|
||||||
//!
|
//!
|
||||||
//! The most permanent fix is a temporary one.
|
//! 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 crate::env::Place;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
Callable, Environment,
|
||||||
builtin::Builtin,
|
builtin::Builtin,
|
||||||
error::{Error, IResult},
|
error::{Error, IResult},
|
||||||
function::Function,
|
function::Function,
|
||||||
Callable, Environment,
|
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, ops::*, rc::Rc};
|
use std::{collections::HashMap, ops::*, rc::Rc};
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ impl ConValue {
|
|||||||
pub fn truthy(&self) -> IResult<bool> {
|
pub fn truthy(&self) -> IResult<bool> {
|
||||||
match self {
|
match self {
|
||||||
ConValue::Bool(v) => Ok(*v),
|
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> {
|
pub fn index(&self, index: &Self, env: &Environment) -> IResult<ConValue> {
|
||||||
let Self::Int(index) = index else {
|
let Self::Int(index) = index else {
|
||||||
Err(Error::TypeError)?
|
Err(Error::TypeError())?
|
||||||
};
|
};
|
||||||
match self {
|
match self {
|
||||||
ConValue::String(string) => string
|
ConValue::String(string) => string
|
||||||
@ -111,7 +111,7 @@ impl ConValue {
|
|||||||
.get_id(*id)
|
.get_id(*id)
|
||||||
.ok_or(Error::StackOverflow(*id))?
|
.ok_or(Error::StackOverflow(*id))?
|
||||||
.index(&ConValue::Int((*index as usize + start) as isize), env),
|
.index(&ConValue::Int((*index as usize + start) as isize), env),
|
||||||
_ => Err(Error::TypeError),
|
_ => Err(Error::TypeError()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cmp! {
|
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::Bool(a), Self::Bool(b)) => Ok(Self::Bool(a $op b)),
|
||||||
(Self::Char(a), Self::Char(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)),
|
(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::Char(a), ConValue::Char(b)) => {
|
||||||
ConValue::String([a, b].into_iter().collect::<String>().into())
|
ConValue::String([a, b].into_iter().collect::<String>().into())
|
||||||
}
|
}
|
||||||
_ => Err(Error::TypeError)?
|
_ => Err(Error::TypeError())?
|
||||||
]
|
]
|
||||||
BitAnd: bitand = [
|
BitAnd: bitand = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a & b),
|
||||||
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a & b),
|
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a & b),
|
||||||
_ => Err(Error::TypeError)?
|
_ => Err(Error::TypeError())?
|
||||||
]
|
]
|
||||||
BitOr: bitor = [
|
BitOr: bitor = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a | b),
|
||||||
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a | b),
|
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a | b),
|
||||||
_ => Err(Error::TypeError)?
|
_ => Err(Error::TypeError())?
|
||||||
]
|
]
|
||||||
BitXor: bitxor = [
|
BitXor: bitxor = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a ^ b),
|
||||||
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a ^ b),
|
(ConValue::Bool(a), ConValue::Bool(b)) => ConValue::Bool(a ^ b),
|
||||||
_ => Err(Error::TypeError)?
|
_ => Err(Error::TypeError())?
|
||||||
]
|
]
|
||||||
Div: div = [
|
Div: div = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
@ -260,13 +260,13 @@ ops! {
|
|||||||
eprintln!("Warning: Divide by zero in {a} / {b}"); a
|
eprintln!("Warning: Divide by zero in {a} / {b}"); a
|
||||||
})),
|
})),
|
||||||
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a / b),
|
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a / b),
|
||||||
_ => Err(Error::TypeError)?
|
_ => Err(Error::TypeError())?
|
||||||
]
|
]
|
||||||
Mul: mul = [
|
Mul: mul = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_mul(b)),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_mul(b)),
|
||||||
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a * b),
|
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a * b),
|
||||||
_ => Err(Error::TypeError)?
|
_ => Err(Error::TypeError())?
|
||||||
]
|
]
|
||||||
Rem: rem = [
|
Rem: rem = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
@ -274,23 +274,23 @@ ops! {
|
|||||||
println!("Warning: Divide by zero in {a} % {b}"); a
|
println!("Warning: Divide by zero in {a} % {b}"); a
|
||||||
})),
|
})),
|
||||||
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a % b),
|
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a % b),
|
||||||
_ => Err(Error::TypeError)?
|
_ => Err(Error::TypeError())?
|
||||||
]
|
]
|
||||||
Shl: shl = [
|
Shl: shl = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shl(b as _)),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shl(b as _)),
|
||||||
_ => Err(Error::TypeError)?
|
_ => Err(Error::TypeError())?
|
||||||
]
|
]
|
||||||
Shr: shr = [
|
Shr: shr = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shr(b as _)),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_shr(b as _)),
|
||||||
_ => Err(Error::TypeError)?
|
_ => Err(Error::TypeError())?
|
||||||
]
|
]
|
||||||
Sub: sub = [
|
Sub: sub = [
|
||||||
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
(ConValue::Empty, ConValue::Empty) => ConValue::Empty,
|
||||||
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_sub(b)),
|
(ConValue::Int(a), ConValue::Int(b)) => ConValue::Int(a.wrapping_sub(b)),
|
||||||
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a - b),
|
(ConValue::Float(a), ConValue::Float(b)) => ConValue::Float(a - b),
|
||||||
_ => Err(Error::TypeError)?
|
_ => Err(Error::TypeError())?
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
impl std::fmt::Display for ConValue {
|
impl std::fmt::Display for ConValue {
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
use crate::builtin::Builtin;
|
use crate::builtin::Builtin;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
Callable, Interpret,
|
||||||
builtin::{Builtins, Math},
|
builtin::{Builtins, Math},
|
||||||
convalue::ConValue,
|
convalue::ConValue,
|
||||||
error::{Error, IResult},
|
error::{Error, IResult},
|
||||||
function::Function,
|
function::Function,
|
||||||
Callable, Interpret,
|
|
||||||
};
|
};
|
||||||
use cl_ast::{Function as FnDecl, Sym};
|
use cl_ast::{Function as FnDecl, Sym};
|
||||||
use std::{
|
use std::{
|
||||||
|
@ -7,9 +7,117 @@ use super::{convalue::ConValue, env::Place};
|
|||||||
|
|
||||||
pub type IResult<T> = Result<T, Error>;
|
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)
|
/// Represents any error thrown by the [Environment](super::Environment)
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Error {
|
pub enum ErrorKind {
|
||||||
/// Propagate a Return value
|
/// Propagate a Return value
|
||||||
Return(ConValue),
|
Return(ConValue),
|
||||||
/// Propagate a Break value
|
/// Propagate a Break value
|
||||||
@ -49,68 +157,55 @@ pub enum Error {
|
|||||||
MatchNonexhaustive,
|
MatchNonexhaustive,
|
||||||
/// Error produced by a Builtin
|
/// Error produced by a Builtin
|
||||||
BuiltinDebug(String),
|
BuiltinDebug(String),
|
||||||
/// Error with associated line information
|
|
||||||
WithSpan(Box<Error>, Span),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error {
|
impl std::error::Error for ErrorKind {}
|
||||||
/// Adds a [Span] to this [Error], if there isn't already a more specific one.
|
impl std::fmt::Display for ErrorKind {
|
||||||
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 {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Error::Return(value) => write!(f, "return {value}"),
|
ErrorKind::Return(value) => write!(f, "return {value}"),
|
||||||
Error::Break(value) => write!(f, "break {value}"),
|
ErrorKind::Break(value) => write!(f, "break {value}"),
|
||||||
Error::BadBreak(value) => write!(f, "rogue break: {value}"),
|
ErrorKind::BadBreak(value) => write!(f, "rogue break: {value}"),
|
||||||
Error::Continue => "continue".fmt(f),
|
ErrorKind::Continue => "continue".fmt(f),
|
||||||
Error::StackUnderflow => "Stack underflow".fmt(f),
|
ErrorKind::StackUnderflow => "Stack underflow".fmt(f),
|
||||||
Error::StackOverflow(id) => {
|
ErrorKind::StackOverflow(id) => {
|
||||||
write!(f, "Attempt to access <{id}> resulted in stack overflow.")
|
write!(f, "Attempt to access <{id}> resulted in stack overflow.")
|
||||||
}
|
}
|
||||||
Error::ScopeExit => "Exited the last scope. This is a logic bug.".fmt(f),
|
ErrorKind::ScopeExit => "Exited the last scope. This is a logic bug.".fmt(f),
|
||||||
Error::TypeError => "Incompatible types".fmt(f),
|
ErrorKind::TypeError => "Incompatible types".fmt(f),
|
||||||
Error::NotIterable => "`in` clause of `for` loop did not yield an iterable".fmt(f),
|
ErrorKind::NotIterable => "`in` clause of `for` loop did not yield an iterable".fmt(f),
|
||||||
Error::NotIndexable => {
|
ErrorKind::NotIndexable => {
|
||||||
write!(f, "expression cannot be indexed")
|
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}")
|
write!(f, "Index out of bounds: index was {idx}. but len is {len}")
|
||||||
}
|
}
|
||||||
Error::NotAssignable => {
|
ErrorKind::NotAssignable => {
|
||||||
write!(f, "expression is not assignable")
|
write!(f, "expression is not assignable")
|
||||||
}
|
}
|
||||||
Error::NotDefined(value) => {
|
ErrorKind::NotDefined(value) => {
|
||||||
write!(f, "{value} not bound. Did you mean `let {value};`?")
|
write!(f, "{value} not bound. Did you mean `let {value};`?")
|
||||||
}
|
}
|
||||||
Error::NotInitialized(value) => {
|
ErrorKind::NotInitialized(value) => {
|
||||||
write!(f, "{value} bound, but not initialized")
|
write!(f, "{value} bound, but not initialized")
|
||||||
}
|
}
|
||||||
Error::NotCallable(value) => {
|
ErrorKind::NotCallable(value) => {
|
||||||
write!(f, "{value} is not callable.")
|
write!(f, "{value} is not callable.")
|
||||||
}
|
}
|
||||||
Error::ArgNumber { want, got } => {
|
ErrorKind::ArgNumber { want, got } => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"Expected {want} argument{}, got {got}",
|
"Expected {want} argument{}, got {got}",
|
||||||
if *want == 1 { "" } else { "s" }
|
if *want == 1 { "" } else { "s" }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Error::PatFailed(pattern) => {
|
ErrorKind::PatFailed(pattern) => {
|
||||||
write!(f, "Failed to match pattern {pattern}")
|
write!(f, "Failed to match pattern {pattern}")
|
||||||
}
|
}
|
||||||
Error::MatchNonexhaustive => {
|
ErrorKind::MatchNonexhaustive => {
|
||||||
write!(f, "Fell through a non-exhaustive match expression!")
|
write!(f, "Fell through a non-exhaustive match expression!")
|
||||||
}
|
}
|
||||||
Error::BuiltinDebug(s) => write!(f, "DEBUG: {s}"),
|
ErrorKind::BuiltinDebug(s) => write!(f, "DEBUG: {s}"),
|
||||||
Error::WithSpan(e, span) => write!(f, "{}..{}: {e}", span.head, span.tail),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
use collect_upvars::collect_upvars;
|
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 cl_ast::{Function as FnDecl, Sym};
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Ref, RefCell},
|
cell::{Ref, RefCell},
|
||||||
@ -56,10 +58,13 @@ impl Callable for Function {
|
|||||||
|
|
||||||
// Check arg mapping
|
// Check arg mapping
|
||||||
if args.len() != bind.len() {
|
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 {
|
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 {
|
let Some(body) = body else {
|
||||||
return Err(Error::NotDefined(*name));
|
return Err(Error::NotDefined(*name));
|
||||||
@ -68,6 +73,8 @@ impl Callable for Function {
|
|||||||
let upvars = self.upvars.take();
|
let upvars = self.upvars.take();
|
||||||
env.push_frame("upvars", upvars);
|
env.push_frame("upvars", upvars);
|
||||||
|
|
||||||
|
eprintln!("{name}{args:?}");
|
||||||
|
|
||||||
// TODO: completely refactor data storage
|
// TODO: completely refactor data storage
|
||||||
let mut frame = env.frame("fn args");
|
let mut frame = env.frame("fn args");
|
||||||
for (bind, value) in bind.iter().zip(args) {
|
for (bind, value) in bind.iter().zip(args) {
|
||||||
@ -81,9 +88,9 @@ impl Callable for Function {
|
|||||||
self.upvars.replace(upvars);
|
self.upvars.replace(upvars);
|
||||||
}
|
}
|
||||||
match res {
|
match res {
|
||||||
Err(Error::Return(value)) => Ok(value),
|
Err(Error { kind: ErrorKind::Return(value), .. }) => Ok(value),
|
||||||
Err(Error::Break(value)) => Err(Error::BadBreak(value)),
|
Err(Error { kind: ErrorKind::Break(value), .. }) => Err(Error::BadBreak(value)),
|
||||||
result => result,
|
other => other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,7 @@ impl Interpret for UseTree {
|
|||||||
}
|
}
|
||||||
UseTree::Path(PathPart::Ident(name), tree) => {
|
UseTree::Path(PathPart::Ident(name), tree) => {
|
||||||
let Ok(ConValue::Module(m)) = env.get(*name) else {
|
let Ok(ConValue::Module(m)) = env.get(*name) else {
|
||||||
Err(Error::TypeError)?
|
Err(Error::TypeError())?
|
||||||
};
|
};
|
||||||
env.push_frame(name.to_ref(), *m);
|
env.push_frame(name.to_ref(), *m);
|
||||||
let out = get_bindings(tree, env, bindings);
|
let out = get_bindings(tree, env, bindings);
|
||||||
@ -313,7 +313,7 @@ impl Interpret for ExprKind {
|
|||||||
ExprKind::For(v) => v.interpret(env),
|
ExprKind::For(v) => v.interpret(env),
|
||||||
ExprKind::Break(v) => v.interpret(env),
|
ExprKind::Break(v) => v.interpret(env),
|
||||||
ExprKind::Return(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);
|
return expr.interpret(&mut env);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(Error::MatchNonexhaustive)
|
Err(Error::MatchNonexhaustive())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,9 +393,9 @@ mod assignment {
|
|||||||
&mut ConValue::Ref(r) => {
|
&mut ConValue::Ref(r) => {
|
||||||
*env.get_id_mut(r).ok_or(Error::StackOverflow(r))? = Some(value)
|
*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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -411,12 +411,12 @@ mod assignment {
|
|||||||
ExprKind::Unary(Unary { kind: UnaryKind::Deref, tail }) => match *addrof(env, tail)? {
|
ExprKind::Unary(Unary { kind: UnaryKind::Deref, tail }) => match *addrof(env, tail)? {
|
||||||
ConValue::Ref(place) => env
|
ConValue::Ref(place) => env
|
||||||
.get_id_mut(place)
|
.get_id_mut(place)
|
||||||
.ok_or(Error::NotIndexable)?
|
.ok_or(Error::NotIndexable())?
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.ok_or(Error::NotAssignable),
|
.ok_or(Error::NotAssignable()),
|
||||||
_ => Err(Error::TypeError),
|
_ => 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)] => env.get_mut(*name),
|
||||||
[PathPart::Ident(name), rest @ ..] => match env.get_mut(*name)? {
|
[PathPart::Ident(name), rest @ ..] => match env.get_mut(*name)? {
|
||||||
Some(ConValue::Module(env)) => project_path_in_namespace(env, rest),
|
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)
|
t.get_mut(*id as usize)
|
||||||
.ok_or(Error::OobIndex(*id as _, len))
|
.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)
|
a.get_mut(*i as usize)
|
||||||
.ok_or(Error::OobIndex(*i as usize, a_len))
|
.ok_or(Error::OobIndex(*i as usize, a_len))
|
||||||
}
|
}
|
||||||
(ConValue::Slice(_, _), _) => Err(Error::TypeError),
|
(ConValue::Slice(_, _), _) => Err(Error::TypeError()),
|
||||||
_ => Err(Error::NotIndexable),
|
_ => Err(Error::NotIndexable()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,12 +502,12 @@ mod assignment {
|
|||||||
path: &[PathPart],
|
path: &[PathPart],
|
||||||
) -> IResult<&'e mut Option<ConValue>> {
|
) -> IResult<&'e mut Option<ConValue>> {
|
||||||
match path {
|
match path {
|
||||||
[] => Err(Error::NotAssignable),
|
[] => Err(Error::NotAssignable()),
|
||||||
[PathPart::Ident(name)] => env.get_mut(name).ok_or(Error::NotDefined(*name)),
|
[PathPart::Ident(name)] => env.get_mut(name).ok_or(Error::NotDefined(*name)),
|
||||||
[PathPart::Ident(name), rest @ ..] => {
|
[PathPart::Ident(name), rest @ ..] => {
|
||||||
match env.get_mut(name).ok_or(Error::NotDefined(*name))? {
|
match env.get_mut(name).ok_or(Error::NotDefined(*name))? {
|
||||||
Some(ConValue::Module(env)) => project_path_in_namespace(env, rest),
|
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),
|
[PathPart::SelfKw, rest @ ..] => project_path_in_namespace(env, rest),
|
||||||
@ -602,7 +602,7 @@ impl Interpret for Binary {
|
|||||||
BinaryKind::Call => match tail {
|
BinaryKind::Call => match tail {
|
||||||
ConValue::Empty => head.call(env, &[]),
|
ConValue::Empty => head.call(env, &[]),
|
||||||
ConValue::Tuple(args) => head.call(env, &args),
|
ConValue::Tuple(args) => head.call(env, &args),
|
||||||
_ => Err(Error::TypeError),
|
_ => Err(Error::TypeError()),
|
||||||
},
|
},
|
||||||
_ => Ok(head),
|
_ => Ok(head),
|
||||||
}
|
}
|
||||||
@ -615,8 +615,8 @@ impl Interpret for Unary {
|
|||||||
match kind {
|
match kind {
|
||||||
UnaryKind::Loop => loop {
|
UnaryKind::Loop => loop {
|
||||||
match tail.interpret(env) {
|
match tail.interpret(env) {
|
||||||
Err(Error::Break(value)) => return Ok(value),
|
Err(Error { kind: ErrorKind::Break(value), .. }) => break Ok(value),
|
||||||
Err(Error::Continue) => continue,
|
Err(Error { kind: ErrorKind::Continue, .. }) => continue,
|
||||||
e => e?,
|
e => e?,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@ -659,7 +659,7 @@ fn cast(env: &Environment, value: ConValue, ty: Sym) -> IResult<ConValue> {
|
|||||||
ConValue::Ref(v) => {
|
ConValue::Ref(v) => {
|
||||||
return cast(
|
return cast(
|
||||||
env,
|
env,
|
||||||
env.get_id(v).cloned().ok_or(Error::StackUnderflow)?,
|
env.get_id(v).cloned().ok_or(Error::StackUnderflow())?,
|
||||||
ty,
|
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(_) if ty.starts_with('f') => return Ok(value),
|
||||||
ConValue::Float(f) => f as _,
|
ConValue::Float(f) => f as _,
|
||||||
_ if (*ty).eq("str") => return Ok(ConValue::String(format!("{value}").into())),
|
_ if (*ty).eq("str") => return Ok(ConValue::String(format!("{value}").into())),
|
||||||
_ => Err(Error::TypeError)?,
|
_ => Err(Error::TypeError())?,
|
||||||
};
|
};
|
||||||
Ok(match &*ty {
|
Ok(match &*ty {
|
||||||
"u8" => ConValue::Int(value as u8 as _),
|
"u8" => ConValue::Int(value as u8 as _),
|
||||||
@ -694,11 +694,11 @@ impl Interpret for Cast {
|
|||||||
return Ok(ConValue::Empty);
|
return Ok(ConValue::Empty);
|
||||||
};
|
};
|
||||||
let TyKind::Path(Path { absolute: false, parts }) = &ty.kind else {
|
let TyKind::Path(Path { absolute: false, parts }) = &ty.kind else {
|
||||||
Err(Error::TypeError)?
|
Err(Error::TypeError())?
|
||||||
};
|
};
|
||||||
match parts.as_slice() {
|
match parts.as_slice() {
|
||||||
[PathPart::Ident(ty)] => cast(env, value, *ty),
|
[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 Self { value, repeat } = self;
|
||||||
let repeat = match repeat.interpret(env)? {
|
let repeat = match repeat.interpret(env)? {
|
||||||
ConValue::Int(v) => v,
|
ConValue::Int(v) => v,
|
||||||
_ => Err(Error::TypeError)?,
|
_ => Err(Error::TypeError())?,
|
||||||
};
|
};
|
||||||
let value = value.interpret(env)?;
|
let value = value.interpret(env)?;
|
||||||
Ok(ConValue::Array(vec![value; repeat as usize].into()))
|
Ok(ConValue::Array(vec![value; repeat as usize].into()))
|
||||||
@ -876,8 +876,8 @@ impl Interpret for While {
|
|||||||
loop {
|
loop {
|
||||||
if cond.interpret(env)?.truthy()? {
|
if cond.interpret(env)?.truthy()? {
|
||||||
match pass.interpret(env) {
|
match pass.interpret(env) {
|
||||||
Err(Error::Break(value)) => return Ok(value),
|
Err(Error { kind: ErrorKind::Break(value), .. }) => break Ok(value),
|
||||||
Err(Error::Continue) => continue,
|
Err(Error { kind: ErrorKind::Continue, .. }) => continue,
|
||||||
e => e?,
|
e => e?,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
@ -907,19 +907,19 @@ impl Interpret for For {
|
|||||||
[ConValue::Int(from), ConValue::Int(to)] => {
|
[ConValue::Int(from), ConValue::Int(to)] => {
|
||||||
Box::new((from..to).map(ConValue::Int))
|
Box::new((from..to).map(ConValue::Int))
|
||||||
}
|
}
|
||||||
_ => Err(Error::NotIterable)?,
|
_ => Err(Error::NotIterable())?,
|
||||||
},
|
},
|
||||||
("RangeInc", values) => match **values {
|
("RangeInc", values) => match **values {
|
||||||
[ConValue::Int(from), ConValue::Int(to)] => {
|
[ConValue::Int(from), ConValue::Int(to)] => {
|
||||||
Box::new((from..=to).map(ConValue::Int))
|
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::Array(a) => Box::new(a.iter().cloned()),
|
||||||
ConValue::String(s) => Box::new(s.chars().map(ConValue::Char)),
|
ConValue::String(s) => Box::new(s.chars().map(ConValue::Char)),
|
||||||
_ => Err(Error::TypeError)?,
|
_ => Err(Error::TypeError())?,
|
||||||
};
|
};
|
||||||
loop {
|
loop {
|
||||||
let mut env = env.frame("loop variable");
|
let mut env = env.frame("loop variable");
|
||||||
@ -928,9 +928,9 @@ impl Interpret for For {
|
|||||||
env.insert(*name, Some(value));
|
env.insert(*name, Some(value));
|
||||||
}
|
}
|
||||||
match pass.interpret(&mut env) {
|
match pass.interpret(&mut env) {
|
||||||
Err(Error::Break(value)) => return Ok(value),
|
Err(Error { kind: ErrorKind::Break(value), .. }) => break Ok(value),
|
||||||
Err(Error::Continue) => continue,
|
Err(Error { kind: ErrorKind::Continue, .. }) => continue,
|
||||||
result => result?,
|
e => e?,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
break fail.interpret(&mut env);
|
break fail.interpret(&mut env);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
use cl_ast::Sym;
|
use cl_ast::Sym;
|
||||||
use convalue::ConValue;
|
use convalue::ConValue;
|
||||||
use env::Environment;
|
use env::Environment;
|
||||||
use error::{Error, IResult};
|
use error::{Error, ErrorKind, IResult};
|
||||||
use interpret::Interpret;
|
use interpret::Interpret;
|
||||||
|
|
||||||
/// Callable types can be called from within a Conlang program
|
/// Callable types can be called from within a Conlang program
|
||||||
|
@ -82,39 +82,39 @@ pub fn append_sub<'pat>(
|
|||||||
) -> IResult<()> {
|
) -> IResult<()> {
|
||||||
match (pat, value) {
|
match (pat, value) {
|
||||||
(Pattern::Literal(Literal::Bool(a)), ConValue::Bool(b)) => {
|
(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)) => {
|
(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)
|
(Pattern::Literal(Literal::Float(a)), ConValue::Float(b)) => (f64::from_bits(*a) == b)
|
||||||
.then_some(())
|
.then_some(())
|
||||||
.ok_or(Error::NotAssignable),
|
.ok_or(Error::NotAssignable()),
|
||||||
(Pattern::Literal(Literal::Int(a)), ConValue::Int(b)) => {
|
(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)) => {
|
(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::Rest(Some(pat)), value) => match (pat.as_ref(), value) {
|
||||||
(Pattern::Literal(Literal::Int(a)), ConValue::Int(b)) => {
|
(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)) => {
|
(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)) => {
|
(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)) => {
|
(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)) => {
|
(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(()),
|
(Pattern::Name(name), _) if "_".eq(&**name) => Ok(()),
|
||||||
@ -149,7 +149,7 @@ pub fn append_sub<'pat>(
|
|||||||
(Pattern::TupleStruct(path, patterns), ConValue::TupleStruct(parts)) => {
|
(Pattern::TupleStruct(path, patterns), ConValue::TupleStruct(parts)) => {
|
||||||
let (name, values) = *parts;
|
let (name, values) = *parts;
|
||||||
if !path.ends_with(name) {
|
if !path.ends_with(name) {
|
||||||
Err(Error::TypeError)?
|
Err(Error::TypeError())?
|
||||||
}
|
}
|
||||||
match rest_binding(sub, patterns, values.into_vec().into())? {
|
match rest_binding(sub, patterns, values.into_vec().into())? {
|
||||||
Some((pattern, values)) => {
|
Some((pattern, values)) => {
|
||||||
@ -162,10 +162,10 @@ pub fn append_sub<'pat>(
|
|||||||
(Pattern::Struct(path, patterns), ConValue::Struct(parts)) => {
|
(Pattern::Struct(path, patterns), ConValue::Struct(parts)) => {
|
||||||
let (name, mut values) = *parts;
|
let (name, mut values) = *parts;
|
||||||
if !path.ends_with(&name) {
|
if !path.ends_with(&name) {
|
||||||
Err(Error::TypeError)?
|
Err(Error::TypeError())?
|
||||||
}
|
}
|
||||||
for (name, pat) in patterns {
|
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 {
|
match pat {
|
||||||
Some(pat) => append_sub(sub, pat, value)?,
|
Some(pat) => append_sub(sub, pat, value)?,
|
||||||
None => {
|
None => {
|
||||||
@ -178,7 +178,7 @@ pub fn append_sub<'pat>(
|
|||||||
|
|
||||||
_ => {
|
_ => {
|
||||||
// eprintln!("Could not match pattern `{pat}` with value `{value}`!");
|
// eprintln!("Could not match pattern `{pat}` with value `{value}`!");
|
||||||
Err(Error::NotAssignable)
|
Err(Error::NotAssignable())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user