Diffstat (limited to 'src/exec.rs')
-rw-r--r--src/exec.rs611
1 files changed, 467 insertions, 144 deletions
diff --git a/src/exec.rs b/src/exec.rs
index cc95429..1627082 100644
--- a/src/exec.rs
+++ b/src/exec.rs
@@ -1,17 +1,15 @@
-use std::{
- collections::{HashMap, VecDeque},
- fmt::Display,
- mem::take,
- ops::{Add, AddAssign, Sub, SubAssign},
-};
-
-use chumsky::span::SimpleSpan;
-
+use crate::parser::types::Span;
use crate::parser::{
fun::{Function, NumberΛ},
types::*,
util::Spanner,
};
+use chumsky::span::{SimpleSpan, Span as _};
+use std::{
+ collections::HashMap,
+ fmt::Display,
+ ops::{Add, Deref, DerefMut},
+};
#[derive(Clone, Copy, PartialEq, Default)]
pub struct Argc {
input: usize,
@@ -22,6 +20,7 @@ impl std::fmt::Debug for Argc {
write!(f, "{}.{}", self.input, self.output)
}
}
+type Result<T> = std::result::Result<T, Error>;
impl Argc {
pub fn takes(input: usize) -> Self {
@@ -36,14 +35,193 @@ impl Argc {
}
#[derive(Clone)]
+pub enum Array {
+ Array(Vec<Array>),
+ Int(Vec<i128>),
+ Float(Vec<f64>),
+}
+impl Array {
+ fn ty(&self) -> &'static str {
+ match self {
+ Array::Array(_) => "array",
+ Array::Int(_) => "int",
+ Array::Float(_) => "float",
+ }
+ }
+}
+
+macro_rules! each {
+ ($y:expr,$x:expr,$in:ty => $into: ty) => {
+ match $y {
+ Array::Int(x) => annote::<$in, $into>($x)(x),
+ Array::Float(x) => annote::<$in, $into>($x)(x),
+ Array::Array(x) => annote::<$in, $into>($x)(x),
+ }
+ };
+}
+impl Array {
+ fn len(&self) -> usize {
+ each!(self, |x| x.len(), &Vec<_> => usize)
+ }
+ fn iter(&self) -> Box<dyn Iterator<Item = Val<'static>> + '_> {
+ match self {
+ Array::Array(items) => Box::new(items.iter().cloned().map(Val::Array)),
+ Array::Int(items) => Box::new(items.iter().copied().map(Val::Int)),
+ Array::Float(items) => Box::new(items.iter().copied().map(Val::Float)),
+ }
+ }
+}
+
+impl std::fmt::Debug for Array {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ match self {
+ Self::Array(x) => x.fmt(f),
+ Self::Int(x) => x.fmt(f),
+ Self::Float(x) => x.fmt(f),
+ }
+ }
+}
+
+impl From<Vec<i128>> for Array {
+ fn from(value: Vec<i128>) -> Self {
+ Array::Int(value)
+ }
+}
+impl From<Vec<f64>> for Array {
+ fn from(value: Vec<f64>) -> Self {
+ Array::Float(value)
+ }
+}
+impl From<Vec<Array>> for Array {
+ fn from(value: Vec<Array>) -> Self {
+ Array::Array(value)
+ }
+}
+
+impl Array {
+ #[track_caller]
+ fn new_unchecked<'s>(value: impl Iterator<Item = Val<'s>>) -> Self {
+ let mut v = value.peekable();
+ let Some(inner) = v.peek() else {
+ return Array::Int(vec![]);
+ };
+ match inner {
+ Val::Array(_) => Array::Array(
+ v.into_iter()
+ .map(|x| match x {
+ Val::Array(x) => x,
+ _ => panic!(),
+ })
+ .collect(),
+ ),
+ Val::Float(_) => Array::Float(
+ v.into_iter()
+ .map(|x| match x {
+ Val::Float(x) => x,
+ _ => panic!(),
+ })
+ .collect(),
+ ),
+ Val::Int(_) => Array::Int(
+ v.into_iter()
+ .map(|x| match x {
+ Val::Int(x) => x,
+ _ => panic!(),
+ })
+ .collect(),
+ ),
+ Val::Lambda(_) => panic!(),
+ }
+ }
+ fn of<'s>(entire: Span, value: impl Iterator<Item = Spanned<Val<'s>>>) -> Result<Self> {
+ let mut v = value.peekable();
+ let Some(Spanned { inner, span }) = v.peek() else {
+ return Ok(Array::Int(vec![]));
+ };
+ Ok(match inner {
+ Val::Array(_) => Array::Array(
+ v.into_iter()
+ .map(|x| match x.inner {
+ Val::Array(x) => Ok(x),
+ _ => Err(Error::ef(entire, "array", x.ty().spun(x.span))),
+ })
+ .collect::<Result<_>>()?,
+ ),
+ Val::Float(_) => Array::Float(
+ v.into_iter()
+ .map(|x| match x.inner {
+ Val::Float(x) => Ok(x),
+ _ => Err(Error::ef(entire, "float", x.ty().spun(x.span))),
+ })
+ .collect::<Result<_>>()?,
+ ),
+ Val::Int(_) => Array::Int(
+ v.into_iter()
+ .map(|x| match x.inner {
+ Val::Int(x) => Ok(x),
+ _ => Err(Error::ef(entire, "int", x.ty().spun(x.span))),
+ })
+ .collect::<Result<_>>()?,
+ ),
+ Val::Lambda(_) => {
+ return Err(Error::ef(entire, "int | array | float", "λ".spun(*span)));
+ }
+ })
+ }
+ fn new(entire: Span, value: Vec<Spanned<Val<'_>>>) -> Result<Self> {
+ let Some(Spanned { inner, span }) = value.first() else {
+ return Ok(Array::Int(vec![]));
+ };
+ Ok(match inner {
+ Val::Array(_) => Array::Array(
+ value
+ .into_iter()
+ .map(|x| match x.inner {
+ Val::Array(x) => Ok(x),
+ _ => Err(Error::ef(entire, "array", x.ty().spun(x.span))),
+ })
+ .collect::<Result<_>>()?,
+ ),
+ Val::Float(_) => Array::Float(
+ value
+ .into_iter()
+ .map(|x| match x.inner {
+ Val::Float(x) => Ok(x),
+ _ => Err(Error::ef(entire, "float", x.ty().spun(x.span))),
+ })
+ .collect::<Result<_>>()?,
+ ),
+ Val::Int(_) => Array::Int(
+ value
+ .into_iter()
+ .map(|x| match x.inner {
+ Val::Int(x) => Ok(x),
+ _ => Err(Error::ef(entire, "int", x.ty().spun(x.span))),
+ })
+ .collect::<Result<_>>()?,
+ ),
+ Val::Lambda(_) => {
+ return Err(Error::ef(entire, "int | array | float", "λ".spun(*span)));
+ }
+ })
+ }
+}
+
+#[derive(Clone)]
pub enum Val<'s> {
- Array(Vec<Val<'s>>),
+ Array(Array),
Lambda(Λ<'s>),
Int(i128),
Float(f64),
}
-impl Val<'_> {
+impl<'s> Val<'s> {
+ fn assert_array(self: Spanned<Val<'s>>, span: Span) -> Result<Spanned<Array>> {
+ match self.inner {
+ Self::Array(x) => Ok(x.spun(self.span)),
+ x => Err(Error::ef(span, "array", x.ty().spun(self.span))),
+ }
+ }
fn ty(&self) -> &'static str {
match self {
Self::Array(_) => "array",
@@ -78,46 +256,40 @@ impl From<bool> for Val<'_> {
}
}
-impl<'a> From<Vec<Val<'a>>> for Val<'a> {
- fn from(value: Vec<Val<'a>>) -> Self {
- Self::Array(value)
- }
-}
-
-impl ConcreteVal {
- fn val(self) -> Val<'static> {
- match self {
- ConcreteVal::Array(x) => {
- Val::Array(x.into_iter().map(ConcreteVal::val).collect::<Vec<_>>())
- }
- ConcreteVal::Int(x) => Val::Int(x),
- ConcreteVal::Float(x) => Val::Float(x),
- }
- }
-}
+// impl ConcreteVal {
+// fn val(self) -> Val<'static> {
+// match self {
+// ConcreteVal::Array(x) => {
+// Val::Array(x.into_iter().map(ConcreteVal::val).collect::<Vec<_>>())
+// }
+// ConcreteVal::Int(x) => Val::Int(x),
+// ConcreteVal::Float(x) => Val::Float(x),
+// }
+// }
+// }
impl<'s> Val<'s> {
- pub fn concrete(self: Spanned<Self>, user: SimpleSpan) -> Result<Spanned<ConcreteVal>, Error> {
- let (x, span) = self.raw();
- Ok(match x {
- Val::Array(x) => ConcreteVal::Array(
- x.into_iter()
- .map(|x| x.spun(span).concrete(user).map(|x| x.inner))
- .collect::<Result<Vec<_>, _>>()?,
- ),
- Val::Float(x) => ConcreteVal::Float(x),
- Val::Int(x) => ConcreteVal::Int(x),
- Val::Lambda(..) => {
- return Err(Error {
- name: "value not concrete (λ)".into(),
- message: "concrete value required here".to_string().spun(user),
- labels: vec!["created here".to_string().spun(span)],
- notes: vec![],
- });
- }
- }
- .spun(span))
- }
+ // pub fn concrete(self: Spanned<Self>, user: SimpleSpan) -> Result<Spanned<ConcreteVal>> {
+ // let (x, span) = self.raw();
+ // Ok(match x {
+ // Val::Array(x) => ConcreteVal::Array(
+ // x.into_iter()
+ // .map(|x| x.spun(span).concrete(user).map(|x| x.inner))
+ // .collect::<Result<Vec<_>, _>>()?,
+ // ),
+ // Val::Float(x) => ConcreteVal::Float(x),
+ // Val::Int(x) => ConcreteVal::Int(x),
+ // Val::Lambda(..) => {
+ // return Err(Error {
+ // name: "value not concrete (λ)".into(),
+ // message: "concrete value required here".to_string().spun(user),
+ // labels: vec!["created here".to_string().spun(span)],
+ // notes: vec![],
+ // });
+ // }
+ // }
+ // .spun(span))
+ // }
}
impl std::fmt::Debug for Val<'_> {
@@ -171,10 +343,16 @@ impl<'s> Stack<'s> {
fn new() -> Self {
Self(Vec::from([Vec::with_capacity(200)]))
}
+ fn take(&mut self, take: usize) -> impl Iterator<Item = Spanned<Val<'s>>> {
+ let n = self.len();
+ self.drain(n - take..)
+ }
+ pub fn of(x: impl Iterator<Item = Spanned<Val<'s>>>) -> Self {
+ Self(vec![x.collect()])
+ }
pub fn push(&mut self, x: Spanned<Val<'s>>) {
self.curr().push(x);
}
- #[track_caller]
pub fn pop(&mut self) -> Option<Spanned<Val<'s>>> {
self.curr().pop()
}
@@ -186,6 +364,19 @@ impl<'s> Stack<'s> {
}
}
+impl<'s> Deref for Stack<'s> {
+ type Target = Vec<Spanned<Val<'s>>>;
+
+ fn deref(&self) -> &Self::Target {
+ self.0.last().unwrap()
+ }
+}
+impl<'s> DerefMut for Stack<'s> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ self.curr()
+ }
+}
+
#[derive(Debug)]
pub struct Error {
pub name: String,
@@ -194,8 +385,19 @@ pub struct Error {
pub notes: Vec<String>,
}
+impl Default for Error {
+ fn default() -> Self {
+ Self {
+ name: Default::default(),
+ message: String::default().spun(Span::new((), 0..0)),
+ labels: Default::default(),
+ notes: Default::default(),
+ }
+ }
+}
+
impl Error {
- pub fn stack_empty(span: SimpleSpan) -> Self {
+ pub fn stack_empty(span: Span) -> Self {
Error {
name: "stack empty".into(),
message: "empty stack".to_string().spun(span),
@@ -204,7 +406,7 @@ impl Error {
}
}
- pub fn ef(span: SimpleSpan, expected: impl Display, found: Spanned<impl Display>) -> Self {
+ pub fn ef(span: Span, expected: impl Display, found: Spanned<impl Display>) -> Self {
Error {
name: "type mismatch".to_string(),
labels: vec![format!("found {found}, not an {expected}").spun(found.span())],
@@ -228,7 +430,7 @@ impl Annotate for Error {
}
}
-impl<T> Annotate for Result<T, Error> {
+impl<T> Annotate for Result<T> {
fn label(self, message: Spanned<impl Into<String>>) -> Self {
self.map_err(|x| x.label(message))
}
@@ -243,6 +445,7 @@ fn x() {
crate::parser::parse_s("5 + 1 2 ×", crate::parser::top()).argc() == Argc::takes(1).into(2)
);
assert!(crate::parser::parse_s("¯", crate::parser::top()).argc() == Argc::takes(1).into(1));
+ assert!(crate::parser::parse_s("0≥", crate::parser::top()).argc() == Argc::takes(1).into(1));
}
impl Add<Argc> for Argc {
@@ -263,8 +466,20 @@ impl Add<Argc> for Argc {
fn size_fn<'s>(f: &Function<'s>) -> Argc {
use Function::*;
match f {
- Add | Mul | Div | Xor | Mod | Pow | Eq | Ne | BitAnd | Or => Argc::takes(2).into(1),
- Neg | Sqrt | Not => Argc::takes(1).into(1),
+ Index | Add | Mul | Div | Xor | Mod | Pow | Eq | Ne | BitAnd | Or | Ge | Le | Lt | Gt => {
+ Argc::takes(2).into(1)
+ }
+ With(x) => Argc::takes(1).into(x.argc().output),
+ Open | Neg | Sqrt | Not => Argc::takes(1).into(1),
+ Flip => Argc::takes(2).into(2),
+ Dup => Argc::takes(1).into(2),
+ Zap => Argc::takes(1).into(0),
+ Mask => Argc::takes(2).into(1),
+ // With => Argc::takes(1).into(),
+ And(a, b) => {
+ Argc::takes(a.argc().input.max(b.argc().input)).into(a.argc().output + b.argc().output)
+ }
+ Both(x) => Argc::takes(x.argc().input * 2).into(x.argc().output * 2),
_ => Argc {
input: 0,
output: 0,
@@ -278,7 +493,12 @@ fn size_expr<'s>(x: &Expr<'s>) -> Argc {
Expr::Value(_) => Argc::produces(1),
}
}
-
+fn normalize_index(x: i128, size: usize) -> usize {
+ match x {
+ ..0 => (size as i128 + x) as usize,
+ _ => x as usize,
+ }
+}
impl<'s> Λ<'s> {
pub fn sized(x: &[Spanned<Expr<'s>>]) -> Argc {
// 5 + (borrows) 1 2 *
@@ -292,7 +512,7 @@ fn exec_lambda<'s>(
x: Spanned<Λ<'s>>,
c: &mut Context<'s, '_>,
stack: &mut Stack<'s>,
-) -> Result<(), Error> {
+) -> Result<()> {
let (x, upper) = x.raw();
for elem in x.0 {
let (elem, span) = elem.raw();
@@ -327,7 +547,7 @@ fn exec_lambda<'s>(
Value::Int(x) => Val::Int(x as i128),
Value::Float(x) => Val::Float(x),
Value::String(x) => {
- Val::Array(x.bytes().map(|x| Val::Int(x as i128)).collect())
+ Val::Array(Array::Int(x.bytes().map(|x| x as i128).collect()))
}
Value::Lambda(x) => Val::Lambda(x),
}
@@ -341,57 +561,85 @@ fn exec_lambda<'s>(
}
fn pervasive_binop<'a>(
- a: &Val<'a>,
- b: &Val<'a>,
- map: impl Fn(&Val<'a>, &Val<'a>) -> Result<Val<'a>, Error> + Copy,
- mismatch: impl FnOnce() -> Error + Clone,
-) -> Result<Val<'a>, Error> {
- use Val::*;
- match (a, b) {
- (Array(x), Array(y)) => {
+ span: SimpleSpan,
+ a: &Spanned<Val<'a>>,
+ b: &Spanned<Val<'a>>,
+ map: impl Fn(&Val<'a>, &Val<'a>) -> Result<Val<'a>> + Copy,
+) -> Result<Val<'a>> {
+ match (&a.inner, &b.inner) {
+ (Val::Array(x), Val::Array(y)) => {
if x.len() != y.len() {
- return Err(mismatch());
+ return Err(Error {
+ name: "argument length mismatch".to_string(),
+ message: "for this function".to_string().spun(span),
+ labels: vec![],
+ notes: vec![],
+ }
+ .label("first argument".spun(a.span))
+ .label("second argument".spun(b.span)));
+ }
+ if x.ty() != y.ty() {
+ return Err(Error {
+ name: "array type mismatch".to_string(),
+ message: "for this function".to_string().spun(span),
+ ..Default::default()
+ })
+ .label(format!("first argument of type {}", x.ty()).spun(a.span))
+ .label(format!("second argument of type {}", y.ty()).spun(b.span));
}
- x.into_iter()
- .zip(y)
- .map(|(x, y)| pervasive_binop(x, y, map, mismatch.clone()))
- .collect::<Result<Vec<_>, _>>()
- .map(Array)
+ x.iter()
+ .zip(y.iter())
+ .map(|(x, y)| {
+ pervasive_binop(span, &x.spun(a.span), &y.spun(b.span), map)
+ .map(|x| x.spun(span))
+ })
+ .collect::<Result<_>>()
+ .and_then(|x| Array::new(span, x))
+ .map(Val::Array)
}
- (Array(x), y) | (y, Array(x)) => x
- .into_iter()
- .map(|x| pervasive_binop(&x, &y, map, mismatch.clone()))
- .collect::<Result<Vec<_>, _>>()
- .map(Array),
+ (Val::Array(x), y) | (y, Val::Array(x)) => x
+ .iter()
+ .map(|x| {
+ pervasive_binop(span, &x.spun(a.span), &y.clone().spun(b.span), map)
+ .map(|x| x.spun(span))
+ })
+ .collect::<Result<_>>()
+ .and_then(|x| Array::new(span, x))
+ .map(Val::Array),
(x, y) => map(x, y),
}
}
fn pervasive_unop<'s>(
- x: Val<'s>,
- f: impl Fn(Val<'s>) -> Result<Val<'s>, Error> + Copy,
-) -> Result<Val<'s>, Error> {
+ Spanned { inner: x, span }: Spanned<Val<'s>>,
+ f: impl Fn(Val<'s>) -> Result<Val<'s>> + Copy,
+) -> Result<Val<'s>> {
match x {
Val::Array(x) => x
- .into_iter()
- .map(|x| match x {
- x @ Val::Array(_) => pervasive_unop(x, f),
- x => f(x),
+ .iter()
+ .map(|x| {
+ match x {
+ x @ Val::Array(_) => pervasive_unop(x.spun(span), f),
+ x => f(x),
+ }
+ .map(|x| x.spun(span))
})
- .collect::<Result<_, _>>()
+ .collect::<Result<_>>()
+ .and_then(|x| Array::new(span, x))
.map(Val::Array),
x => f(x),
}
}
impl<'s> Function<'s> {
- pub fn execute(
- self: Spanned<Self>,
- c: &Context<'s, '_>,
- stack: &mut Stack<'s>,
- ) -> Result<(), Error> {
+ pub fn execute(self: Spanned<Self>, c: &Context<'s, '_>, stack: &mut Stack<'s>) -> Result<()> {
let (x, span) = self.raw();
+ macro_rules! pop {
+ () => {
+ stack.pop().ok_or(Error::stack_empty(span))?
+ };
+ }
macro_rules! concrete_ab {
($x:tt) => {
concrete_ab!(|a, b| a $x b)
@@ -406,7 +654,8 @@ impl<'s> Function<'s> {
"got second argument from here".spun(b_.span()),
))?;
stack.push(pervasive_binop(
- &*a_, &*b_, |a, b| {
+ span,
+ &a_, &b_, |a, b| {
match (a, b) {
(Val::Float(x), Val::Int(y)) | (Val::Int(y), Val::Float(x)) =>
Ok(Val::from(($a)(x, &(*y as f64)))),
@@ -419,12 +668,6 @@ impl<'s> Function<'s> {
_ => unreachable!(),
}
},
- || Error{
- name: "argument length mismatch".to_string(),
- message: "for this function".to_string().spun(span),
- labels: vec![],
- notes:vec![],
- }.label("first argument".spun(a_.span())).label("second argument".spun(b_.span())),
)?.spun(span));
}};
@@ -432,39 +675,25 @@ impl<'s> Function<'s> {
macro_rules! number_ab {
($a:expr) => {{
- let a_ = stack.pop().ok_or(Error::stack_empty(span))?;
+ let a_ = pop!();
let b_ = stack.pop().ok_or(
Error::stack_empty(span).label("got first argument from here".spun(a_.span())),
)?;
stack.push(
- pervasive_binop(
- &*a_,
- &*b_,
- |a, b| match (a, b) {
- (Val::Float(_), Val::Float(_)) => {
- Err(Error::ef(span, "int", "float".spun(a_.span()))
- .label("float (not int)".spun(b_.span())))
- }
- (Val::Int(x), Val::Int(y)) => Ok(Val::from(($a)(x, y))),
- (x, Val::Int(_)) => {
- Err(Error::ef(span, "expected int", x.ty().spun(a_.span())))
- }
- (Val::Int(_), x) => {
- Err(Error::ef(span, "expected int", x.ty().spun(b_.span())))
- }
- _ => unreachable!(),
- },
- || {
- Error {
- name: "argument length mismatch".to_string(),
- message: "for this function".to_string().spun(span),
- labels: vec![],
- notes: vec![],
- }
- .label("first argument".spun(a_.span()))
- .label("second argument".spun(b_.span()))
- },
- )?
+ pervasive_binop(span, &a_, &b_, |a, b| match (a, b) {
+ (Val::Float(_), Val::Float(_)) => {
+ Err(Error::ef(span, "int", "float".spun(a_.span()))
+ .label("float (not int)".spun(b_.span())))
+ }
+ (Val::Int(x), Val::Int(y)) => Ok(Val::from(($a)(x, y))),
+ (x, Val::Int(_)) => {
+ Err(Error::ef(span, "expected int", x.ty().spun(a_.span())))
+ }
+ (Val::Int(_), x) => {
+ Err(Error::ef(span, "expected int", x.ty().spun(b_.span())))
+ }
+ _ => unreachable!(),
+ })?
.spun(span),
)
}};
@@ -485,7 +714,8 @@ impl<'s> Function<'s> {
unary!(|x| $x x)
};
($x:expr) => {{
- let (x, xspan) = stack.pop().ok_or(Error::stack_empty(span))?.raw();
+ let x = pop!();
+ let xspan = x.span();
stack.push(
pervasive_unop(x, |x| {
Ok(match x {
@@ -531,6 +761,7 @@ impl<'s> Function<'s> {
f64::sqrt(*self)
}
}
+
match x {
Self::Add => concrete_ab!(+),
Self::Sub => concrete_ab!(-),
@@ -553,7 +784,7 @@ impl<'s> Function<'s> {
NumberΛ::Number(x) => x as usize,
NumberΛ::Λ(x) => {
exec_lambda(x, &mut Context::inherits(c), stack)?;
- let (y, yspan) = stack.pop().ok_or(Error::stack_empty(span))?.raw();
+ let (y, yspan) = pop!().raw();
match y {
Val::Int(x) => x as usize,
z => {
@@ -562,44 +793,132 @@ impl<'s> Function<'s> {
}
}
};
- let r = stack.curr().len() - r;
- let result = stack.curr().split_off(r);
- stack.push(Val::Array(result.into_iter().map(|x| x.inner).collect()).spun(span))
+ let r = stack.len() - r;
+ let result = stack.split_off(r);
+ stack.push(Val::Array(Array::new(span, result)?).spun(span))
}
Self::Array(None) => {
- let drained = stack.curr().drain(..).map(|x| x.inner).collect();
+ let drained = Array::of(span, stack.drain(..))?;
stack.push(Val::Array(drained).spun(span));
}
Self::Dup => {
- let x = stack.pop().ok_or(Error::stack_empty(span))?.clone();
+ let x = pop!().clone();
+ stack.push(x.clone());
stack.push(x);
}
+ Self::Zap => drop(stack.pop()),
Self::Flip => {
- let x = stack.pop().ok_or(Error::stack_empty(span))?;
- let y = stack.pop().ok_or(Error::stack_empty(span))?;
+ let x = pop!();
+ let y = pop!();
stack.push(y);
stack.push(x);
}
- // basically ⎬^⎬2 (x)🗺
Self::And(x, y) => {
let xargs = x.argc();
let yargs = y.argc();
let requires = yargs.input.max(xargs.input);
- let n = stack.curr().len();
- let s = Stack(vec![stack.curr().drain(n - requires..).collect::<Vec<_>>()]);
+ let s = Stack::of(stack.take(requires));
let mut a = s.clone();
exec_lambda(x, &mut Context::inherits(c), &mut a)?;
- let n = a.curr().len();
- let x = a.curr().drain(n - xargs.output..);
+ let x = a.take(xargs.output);
let mut a = s.clone();
exec_lambda(y, &mut Context::inherits(c), &mut a)?;
- let n = a.curr().len();
- let y = a.curr().drain(n - yargs.output..);
+ let y = a.take(yargs.output);
+
+ stack.extend(x);
+ stack.extend(y);
+ }
+ Self::Both(x) => {
+ let xargs = x.argc();
+ let mut a = Stack::of(stack.take(xargs.input));
+ exec_lambda(x.clone(), &mut Context::inherits(c), &mut a)?;
- stack.curr().extend(x);
- stack.curr().extend(y);
+ let mut b = Stack::of(stack.take(xargs.input));
+ exec_lambda(x, &mut Context::inherits(c), &mut b)?;
+
+ stack.extend(b.take(xargs.output));
+ stack.extend(a.take(xargs.output));
+ }
+ Self::Mask => {
+ let mask = pop!().assert_array(span)?;
+ let a = pop!().assert_array(span)?;
+ let Array::Int(m) = mask.inner else {
+ return Err(Error::ef(span, "array[bit]", mask.ty().spun(mask.span)));
+ };
+ if a.len() != m.len() {
+ return Err(Error {
+ name: "argument length mismatch".to_string(),
+ message: "for this function".to_string().spun(span),
+ labels: vec![],
+ notes: vec![],
+ }
+ .label("first argument".spun(a.span))
+ .label("second argument".spun(mask.span)));
+ }
+ stack.push(
+ Val::Array(Array::new_unchecked(
+ a.iter().zip(m).filter(|(_, x)| *x == 1).map(|(x, _)| x),
+ ))
+ .spun(span),
+ );
+ }
+ Self::With(λ) => {
+ let array = pop!().assert_array(span)?;
+ let mut a = Stack::of(array.iter().map(|x| x.spun(array.span)));
+ exec_lambda(λ, &mut Context::inherits(c), &mut a)?;
+ stack.extend(a.drain(..));
+ }
+ Self::Index => {
+ let index = pop!().assert_array(span)?.try_map(|x, s| match x {
+ Array::Int(x) => Ok(x),
+ x => Err(Error::ef(span, "array[int]", x.ty().spun(s))),
+ })?;
+ let array = pop!().assert_array(span)?;
+ let out = each!(
+ array.inner,
+ |x| index
+ .iter()
+ .map(|y| x.get(normalize_index(*y, x.len())).cloned().ok_or_else(|| {
+ Error {
+ name: format!(
+ "index ({y}) out of bounds for arra of length {}",
+ x.len()
+ ),
+ message: "here".to_string().spun(span),
+ ..Default::default()
+ }
+ .label("index from".spun(index.span))
+ .label("array from".spun(array.span))
+ }))
+ .collect::<Result<Vec<_>>>().map(Array::from).map(Val::Array),
+ Vec<_> => Result<Val>
+ )?;
+ stack.push(out.spun(span));
+ }
+ Self::Open => {
+ let x = pop!().assert_array(span)?.try_map(|x, s| match x {
+ Array::Int(x) => String::from_utf8(x.into_iter().map(|x| x as u8).collect())
+ .map_err(|e| {
+ Error::ef(span, "valid utf8", "invalid utf8".spun(s))
+ .note(e.utf8_error().to_string())
+ }),
+ x => Err(Error::ef(span, "array", x.ty().spun(s))),
+ })?;
+ stack.push(
+ Val::Array(Array::Int(
+ std::fs::read(&*x)
+ .map_err(|e| {
+ Error::ef(span, "valid file", "invalid file".spun(x.span))
+ .note(e.to_string())
+ })?
+ .into_iter()
+ .map(|x| x as i128)
+ .collect(),
+ ))
+ .spun(x.span),
+ );
}
_ => (),
}
@@ -610,3 +929,7 @@ impl<'s> Function<'s> {
fn annotate<'a, T>(f: impl FnOnce(&T) -> T) -> impl FnOnce(&T) -> T {
f
}
+
+fn annote<'a, T, U>(f: impl FnOnce(T) -> U) -> impl FnOnce(T) -> U {
+ f
+}