Diffstat (limited to 'src/exec.rs')
| -rw-r--r-- | src/exec.rs | 625 |
1 files changed, 625 insertions, 0 deletions
diff --git a/src/exec.rs b/src/exec.rs new file mode 100644 index 0000000..b535f88 --- /dev/null +++ b/src/exec.rs @@ -0,0 +1,625 @@ +use std::{ + collections::{HashMap, VecDeque}, + fmt::Display, + mem::take, + ops::{Add, Sub, SubAssign}, +}; + +use chumsky::span::SimpleSpan; + +use crate::parser::{ + fun::{Function, NumberΛ}, + types::*, + util::Spanner, +}; +#[derive(Clone, Copy, PartialEq)] +struct Argc { + input: usize, + output: usize, +} +impl std::fmt::Debug for Argc { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}.{}", self.input, self.output) + } +} + +impl Argc { + pub fn takes(input: usize) -> Self { + Self { input, output: 0 } + } + pub fn produces(output: usize) -> Self { + Self { input: 0, output } + } + pub fn into(self, output: usize) -> Self { + Self { output, ..self } + } +} + +#[derive(Clone)] +pub enum Val<'s> { + Array(Vec<Val<'s>>), + Lambda(Λ<'s>, Argc), + Int(i128), + Float(f64), +} + +impl Val<'_> { + fn ty(&self) -> &'static str { + match self { + Self::Array(_) => "array", + Self::Float(_) => "float", + Self::Int(_) => "int", + Self::Lambda(..) => "lambda", + } + } +} + +#[derive(Clone, Debug)] +pub enum ConcreteVal { + Array(Vec<ConcreteVal>), + Int(i128), + Float(f64), +} +impl From<f64> for Val<'_> { + fn from(value: f64) -> Self { + Self::Float(value) + } +} + +impl From<i128> for Val<'_> { + fn from(value: i128) -> Self { + Self::Int(value) + } +} + +impl From<bool> for Val<'_> { + fn from(value: bool) -> Self { + Self::Int(value as i128) + } +} + +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<'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)) + } +} + +impl std::fmt::Debug for Val<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Array(x) => x.fmt(f), + Self::Lambda(x, _) => x.fmt(f), + Self::Int(x) => write!(f, "{x}"), + Self::Float(x) => write!(f, "{x}"), + } + } +} + +pub struct Context<'s, 'v> { + pub inherits: Option<&'v Context<'s, 'v>>, + pub variables: HashMap<&'s str, Spanned<Val<'s>>>, +} + +impl<'s, 'v> Default for Context<'s, 'v> { + fn default() -> Self { + Self { + inherits: None, + variables: Default::default(), + } + } +} + +impl<'s, 'v> Context<'s, 'v> { + fn inherits(x: &'v Context<'s, 'v>) -> Self { + Self { + inherits: Some(x), + variables: Default::default(), + } + } +} +pub fn exec(x: Spanned<Λ<'_>>, code: &str) { + crate::ui::display_execution( + exec_lambda(x, &mut Context::default(), &mut Stack::new()), + code, + ); +} +impl std::fmt::Debug for Stack<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(f, "{:#?}", self.cur()) + } +} + +#[derive(Clone)] +pub struct Stack<'s>(Vec<Vec<Spanned<Val<'s>>>>); +impl<'s> Stack<'s> { + fn new() -> Self { + Self(Vec::from([Vec::with_capacity(200)])) + } + 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() + } + pub fn curr(&mut self) -> &mut Vec<Spanned<Val<'s>>> { + self.0.last_mut().unwrap() + } + pub fn cur(&self) -> &[Spanned<Val<'s>>] { + self.0.last().unwrap() + } +} + +#[derive(Debug)] +pub struct Error { + pub name: String, + pub message: Spanned<String>, + pub labels: Vec<Spanned<String>>, + pub notes: Vec<String>, +} + +impl Error { + pub fn stack_empty(span: SimpleSpan) -> Self { + Error { + name: "stack empty".into(), + message: "empty stack".to_string().spun(span), + labels: vec![], + notes: vec![], + } + } + + pub fn ef(span: SimpleSpan, 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())], + message: format!("expected {expected} found {found}").spun(span), + notes: vec![], + } + } +} +trait Annotate { + fn label(self, message: Spanned<impl Into<String>>) -> Self; + fn note(self, message: impl Into<String>) -> Self; +} +impl Annotate for Error { + fn label(mut self, message: Spanned<impl Into<String>>) -> Self { + self.labels.push(message.map(|x| x.into())); + self + } + fn note(mut self, message: impl Into<String>) -> Self { + self.notes.push(message.into()); + self + } +} + +impl<T> Annotate for Result<T, Error> { + fn label(self, message: Spanned<impl Into<String>>) -> Self { + self.map_err(|x| x.label(message)) + } + fn note(self, message: impl Into<String>) -> Self { + self.map_err(|x| x.note(message)) + } +} + +#[test] +fn x() { + assert!( + size_lambda(crate::parser::parse_s("5 + 1 2 ×", crate::parser::top()).inner) + == Argc::takes(1).into(2) + ); + assert!( + size_lambda(crate::parser::parse_s("¯", crate::parser::top()).inner) + == Argc::takes(1).into(1) + ); +} + +impl SubAssign<Argc> for Argc { + fn sub_assign(&mut self, rhs: Argc) { + match self.output.checked_sub(rhs.input) { + Some(x) => { + self.output = x + rhs.output; + } + None => { + self.input += rhs.input - self.output; + self.output = rhs.output; + } + } + } +} + +fn size_lambda<'s>(lambda: Λ<'s>) -> Argc { + let mut a = Argc { + input: 0, + output: 0, + }; + // 5 + 1 2 * + // { 0, 1 } -> { 1, 1 } -> { 1, 3 } -> { 1, 2 } + for elem in lambda.0 { + let x = format!("{elem:?}"); + a -= match elem.inner { + Expr::Function(function) => { + use Function::*; + match function { + Add | Mul | Div | Xor | Mod | Pow => Argc::takes(2).into(1), + Neg => Argc::takes(1).into(1), + _ => Argc { + input: 0, + output: 0, + }, + } + } + Expr::Value(_) => Argc::produces(1), + }; + println!("{x} → {a:?}"); + } + a +} +fn exec_lambda<'s>( + x: Spanned<Λ<'s>>, + c: &mut Context<'s, '_>, + stack: &mut Stack<'s>, +) -> Result<(), Error> { + let (x, upper) = x.raw(); + for elem in x.0 { + let (elem, span) = elem.raw(); + match elem { + Expr::Function(x) => match x { + Function::Ident(x) => { + let (x, span) = c + .variables + .get(x) + .unwrap_or_else(|| { + println!("couldnt find definition for variable {x} at ast node {x:?}"); + std::process::exit(1); + }) + .clone() + .raw(); + match x { + Val::Lambda(x, _) => { + exec_lambda(x.spun(span), &mut Context::inherits(c), stack)? + } + x => stack.push(x.spun(span)), + } + } + Function::Define(x) => { + c.variables + .insert(x, stack.pop().ok_or(Error::stack_empty(span))?); + } + x => x.spun(span).execute(c, stack)?, + }, + Expr::Value(x) => { + stack.push( + match x { + 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()) + } + Value::Lambda(x) => Val::Lambda( + x, + Argc { + input: 0, + output: 0, + }, + ), + } + .spun(span), + ); + } + } + } + println!("{stack:?}"); + Ok(()) +} + +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)) => { + if x.len() != y.len() { + return Err(mismatch()); + } + + x.into_iter() + .zip(y) + .map(|(x, y)| pervasive_binop(x, y, map, mismatch.clone())) + .collect::<Result<Vec<_>, _>>() + .map(Array) + } + (Array(x), y) | (y, Array(x)) => x + .into_iter() + .map(|x| pervasive_binop(&x, &y, map, mismatch.clone())) + .collect::<Result<Vec<_>, _>>() + .map(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> { + match x { + Val::Array(x) => x + .into_iter() + .map(|x| match x { + x @ Val::Array(_) => pervasive_unop(x, f), + x => f(x), + }) + .collect::<Result<_, _>>() + .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> { + let (x, span) = self.raw(); + macro_rules! concrete_ab { + ($x:tt) => { + concrete_ab!(|a, b| a $x b) + }; + ($a: expr) => {{ + let b_ = stack + .pop() + .ok_or(Error::stack_empty(span, ))?; + let a_ = stack + .pop() + .ok_or(Error::stack_empty(span).label( + "got second argument from here".spun(b_.span()), + ))?; + stack.push(pervasive_binop( + &*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)))), + (Val::Int(x), Val::Int(y)) => Ok(Val::from(($a)(x, y))), + (Val::Float(x), Val::Float(y)) => Ok(Val::from(($a)(x, y))), + (x, Val::Float(_) | Val::Int(_)) => + Err(Error::ef(span, "expected number", x.ty().spun(a_.span()))), + (Val::Float(_) | Val::Int(_), x) => + Err(Error::ef(span, "expected number", 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())), + )?.spun(span)); + }}; + + } + + macro_rules! number_ab { + ($a:expr) => {{ + let a_ = stack.pop().ok_or(Error::stack_empty(span))?; + 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())) + }, + )? + .spun(span), + ) + }}; + } + macro_rules! unary_num { + ($x:tt) => {{ + let x = stack + .pop() + .ok_or(Error::stack_empty(span))?; + let Val::Int(x) = x.inner else { + return Err(Error::ef(span, "integer", x.ty().spun(x.span()))); + }; + stack.push(Val::Int($x x).spun(span)); + }}; + } + macro_rules! unary { + ($x:tt) => { + unary!(|x| $x x) + }; + ($x:expr) => {{ + let (x, xspan) = stack.pop().ok_or(Error::stack_empty(span))?.raw(); + stack.push( + pervasive_unop(x, |x| { + Ok(match x { + Val::Int(x) => Val::Int(annotate::<i128>($x)(&x)), + Val::Float(x) => Val::Float(annotate::<f64>($x)(&x)), + _ => { + return Err(Error::ef(span, "number", x.ty().spun(xspan))); + } + }) + })? + .spun(span), + ); + }}; + } + trait Help { + fn pow(&self, other: &Self) -> Self; + fn rem(&self, other: &Self) -> Self; + fn sqrt(&self) -> Self; + } + impl Help for i128 { + fn pow(&self, other: &Self) -> Self { + i128::pow(*self, (*other).try_into().expect("please no")) + } + + fn rem(&self, other: &Self) -> Self { + self.rem_euclid(*other) + } + + fn sqrt(&self) -> Self { + self.isqrt() + } + } + impl Help for f64 { + fn pow(&self, other: &Self) -> Self { + self.powf(*other) + } + + fn rem(&self, other: &Self) -> Self { + self.rem_euclid(*other) + } + + fn sqrt(&self) -> Self { + f64::sqrt(*self) + } + } + match x { + Self::Add => concrete_ab!(+), + Self::Sub => concrete_ab!(-), + Self::Mul => concrete_ab!(*), + Self::Div => concrete_ab!(/), + Self::Mod => concrete_ab!(Help::rem), + Self::Pow => concrete_ab!(Help::pow), + Self::BitAnd => number_ab!(|a, b| a & b), + Self::Or => number_ab!(|a, b| a | b), + Self::Xor => number_ab!(|a, b| a ^ b), + Self::Lt => concrete_ab!(<), + Self::Gt => concrete_ab!(>), + Self::Le => concrete_ab!(<=), + Self::Ge => concrete_ab!(>=), + Self::Not => unary_num!(!), + Self::Neg => unary!(-), + Self::Sqrt => unary!(Help::sqrt), + Self::Array(Some(x)) => { + let r = match x { + 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(); + match y { + Val::Int(x) => x as usize, + z => { + return Err(Error::ef(span, "int", z.ty().spun(yspan))); + } + } + } + }; + 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)) + } + Self::Array(None) => { + let drained = stack.curr().drain(..).map(|x| x.inner).collect(); + stack.push(Val::Array(drained).spun(span)); + } + Self::Dup => { + let x = stack.pop().ok_or(Error::stack_empty(span))?.clone(); + stack.push(x); + } + Self::Flip => { + let x = stack.pop().ok_or(Error::stack_empty(span))?; + let y = stack.pop().ok_or(Error::stack_empty(span))?; + stack.push(y); + stack.push(x); + } + // basically ⎬^⎬2 (x)🗺 + Self::And(x, y) => { + println!("exec and"); + let n = stack.curr().len(); + let mut a = stack.clone(); + exec_lambda(x, &mut Context::inherits(c), &mut a)?; + let delta = -1; + let mut x = + a.0.pop() + .unwrap() + .drain((n as i64 + delta) as usize..) + .collect::<Vec<_>>(); + + let mut a = stack.clone(); + exec_lambda(y, &mut Context::inherits(c), &mut a)?; + let delta = -1; + let mut y = + a.0.pop() + .unwrap() + .drain((n as i64 + delta) as usize..) + .collect::<Vec<_>>(); + stack.curr().truncate(n - 1); + // pain (TODO: argc???) + stack.push(x.pop().unwrap()); + stack.push(y.pop().unwrap()); + } + _ => (), + } + Ok(()) + } +} + +fn annotate<'a, T>(f: impl FnOnce(&T) -> T) -> impl FnOnce(&T) -> T { + f +} |