checkpoint
| -rw-r--r-- | Cargo.toml | 2 | ||||
| -rw-r--r-- | src/exec.rs | 625 | ||||
| -rw-r--r-- | src/lexer.rs | 15 | ||||
| -rw-r--r-- | src/main.rs | 17 | ||||
| -rw-r--r-- | src/parser.rs | 31 | ||||
| -rw-r--r-- | src/parser/fun.rs | 43 | ||||
| -rw-r--r-- | src/parser/types.rs | 48 | ||||
| -rw-r--r-- | src/ui.rs | 36 | ||||
| -rw-r--r-- | stackd | 13 |
9 files changed, 750 insertions, 80 deletions
@@ -1,7 +1,7 @@ [package] name = "kale" version = "0.1.0" -edition = "2021" +edition = "2024" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 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 +} diff --git a/src/lexer.rs b/src/lexer.rs index e3943d4..f787f1e 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -10,7 +10,7 @@ macro_rules! tokens { #[logos(skip r"[\n\s]+")] #[allow(dead_code)] pub enum Token<'strings> { - #[regex("/[^\n/]+/", priority = 8)] + #[regex("/[^\n/]+/?", priority = 8)] Comment(&'strings str), #[regex(r"[0-9]+", |lex| lex.slice().parse().ok())] #[regex(r"0[xX][0-9a-fA-F]+", |lex| u64::from_str_radix(&lex.slice()[2..], 16).ok())] @@ -24,12 +24,12 @@ macro_rules! tokens { #[regex(r"'.'", |lex| lex.slice().as_bytes()[1] as char)] Char(char), // todo ignore alot - #[regex(r"[^\s\(\)\[\]\{\}⎬0-9λ'\-←→=≡+×\|*√<\-¯∧∨⊻÷%]", priority = 7, callback = |lex| { + #[regex(r"[^\s\(\)\[\]\{\}⎬0-9λ'\-←→=≢≡+×\|*√<\-¯∧∨⊻÷%]", priority = 7, callback = |lex| { EMOJI.is_match(lex.slice()) .then_some(logos::Filter::Skip) .unwrap_or(logos::Filter::Emit(lex.slice())) })] - #[regex(r"'[^']+'", priority = 8, callback = |lex| &lex.slice()[1..lex.slice().len() - 1])] + #[regex(r"'[^'0-9][^']+'", priority = 8, callback = |lex| &lex.slice()[1..lex.slice().len() - 1])] Ident(&'strings str), #[token("[", chr::<'['>)] #[token("(", chr::<'('>)] @@ -65,12 +65,11 @@ macro_rules! tokens { tokens! { "λ" => Lambda, - "←" => Ret, "⎬" => Array, "→" => Place, "≡" => Eq, + "≢" => Ne, "^" => Dup, - // "🐘" => Both, "&" => And, "|" => Both, "🔀" => Flip, @@ -88,6 +87,8 @@ tokens! { ">" => Gt, "≤" => Le, "≥" => Ge, + "÷" => Div, + "%" => Mod, "🪪" => Type, "📏" => Length, "👩👩👧👧" => Group, @@ -97,9 +98,8 @@ tokens! { "📶" => Sort, "∧" => BitAnd, "∨" => Or, + "!" => Not, "⊕" => Xor, - "÷" => Div, - "%" => Mod, "🔓" => Mask, "🔒" => Index, "🚧" => Split, @@ -110,6 +110,7 @@ tokens! { "🐋" => If, "🐬" => EagerIf, "🇳🇿" => Zip, + "🧐" => Debug, "." => Call, } diff --git a/src/main.rs b/src/main.rs index 2efcf49..ef5bcab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,16 @@ -#![feature(iter_intersperse, formatting_options)] - -use parser::types::Ast; +#![feature( + iter_intersperse, + formatting_options, + impl_trait_in_bindings, + arbitrary_self_types +)] mod array; +mod exec; mod lexer; mod parser; mod ui; fn main() { - parser::parse_s( - &std::fs::read_to_string(std::env::args().nth(1).unwrap()).unwrap(), - Ast::parse(), - ); + let x = std::fs::read_to_string(std::env::args().nth(1).unwrap()).unwrap(); + let y = parser::parse_s(&x, parser::top()); + exec::exec(y, &x); } diff --git a/src/parser.rs b/src/parser.rs index b1cf87d..721eaac 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,6 +1,6 @@ pub mod types; use crate::lexer::{Lexer, Token}; -use chumsky::{input::Stream, prelude::*, Parser}; +use chumsky::{Parser, input::Stream, prelude::*}; pub mod fun; pub mod util; use types::*; @@ -9,37 +9,42 @@ use util::*; use self::fun::Function; impl<'s> Value<'s> { - pub fn parse() -> parser![Self] { + pub fn parse() -> parser![Spanned<Self>] { select! { Token::Char(x) => Value::Int(x as _), Token::Int(x) => Value::Int(x), Token::Float(x) => Value::Float(x), Token::String(s) => Value::String(s), } + .map_with(spanned!()) .labelled("value") } } impl<'s> Expr<'s> { - pub fn parse() -> parser![Self] { - recursive::<_, Expr, _, _, _>(|expr| { - let inline_expr = Value::parse().map(Expr::Value); + pub fn parse() -> parser![Spanned<Expr<'s>>] { + recursive(|expr| { + let inline_expr: parser![Spanned<Expr>] = Value::parse().map(|x| x.map(Expr::Value)); let λ = Λ::parse(expr.clone()); - choice(( inline_expr, - Function::parse(λ.clone()).map(Expr::Function), - λ.map(Expr::Lambda), + Function::parse(λ.clone().map(Spanned::unspan())) + .map(Expr::Function) + .map_with(spanned!()), + λ.map(|x| x.map(|x| Expr::Value(Value::Lambda(x)))), )) .labelled("expr") }) } } -impl<'s> Ast<'s> { - pub fn parse() -> parser![Self] { - Expr::parse().repeated().collect().map(Ast::Module) - } + +pub fn top<'s>() -> parser![Spanned<Λ<'s>>] { + Expr::parse() + .repeated() + .collect() + .map(Λ) + .map_with(spanned!()) } #[test] @@ -51,7 +56,7 @@ fn parse_expr() { "{:?}", crate::lexer::lex(src).map(|x| x.0).collect::<Vec<_>>() ); - parse_s(src, Ast::parse()); + parse_s(src, top()); } pub fn stream(lexer: Lexer<'_>, len: usize) -> types::Input<'_> { diff --git a/src/parser/fun.rs b/src/parser/fun.rs index a763a81..f81e475 100644 --- a/src/parser/fun.rs +++ b/src/parser/fun.rs @@ -1,18 +1,18 @@ use super::types::*; use super::util::*; use crate::lexer::Token; -use chumsky::{prelude::*, Parser}; +use chumsky::{Parser, prelude::*}; #[derive(Debug, Clone)] -enum NumberΛ<'s> { +pub enum NumberΛ<'s> { Number(u64), - Λ(Λ<'s>), + Λ(Spanned<Λ<'s>>), } #[derive(Debug, Clone)] pub enum Function<'s> { Both(Λ<'s>), - And(Λ<'s>, Λ<'s>), + And(Spanned<Λ<'s>>, Spanned<Λ<'s>>), If { then: Λ<'s>, or: Λ<'s> }, Array(Option<NumberΛ<'s>>), Map(Λ<'s>), @@ -27,6 +27,7 @@ pub enum Function<'s> { Mul, Pow, Type, + Ne, Merge, Sqrt, Lt, @@ -59,11 +60,11 @@ pub enum Function<'s> { } impl<'s> Λ<'s> { - pub fn parse(exp: parser![Expr<'s>]) -> parser![Self] { + pub fn parse(exp: parser![Spanned<Expr<'s>>]) -> parser![Spanned<Self>] { exp.repeated() .collect() .delimited_by(t!['('], t![')']) - .map(|x| Self(x)) + .map_with(|x, e| Spanned::from((Self(x), e.span()))) .labelled("lambda") } } @@ -82,6 +83,7 @@ impl<'s> Function<'s> { Token::Pow => Pow, Token::Sqrt => Sqrt, Token::Lt => Lt, + Token::Not => Not, Token::Index => Index, Token::Merge => Merge, Token::Shl => Shl, @@ -104,6 +106,7 @@ impl<'s> Function<'s> { Token::With => With, Token::Split => Split, Token::First => First, + Token::Ne => Ne, Token::Type => Type, Token::Last => Last, Token::Ident(x) => Ident(x), @@ -112,7 +115,7 @@ impl<'s> Function<'s> { let fn_param = choice(( basic - .map(|x| Λ(vec![Expr::Function(x)])) + .map_with(|x, e| Λ(vec![Expr::Function(x).spun(e.span())])) .labelled("function"), λ.clone(), )) @@ -131,7 +134,8 @@ impl<'s> Function<'s> { ($name:ident) => { fn_param .clone() - .then(fn_param.clone()) + .map_with(spanned!()) + .then(fn_param.clone().map_with(spanned!())) .then_ignore(just(Token::$name)) .map(|(a, b)| $name(a, b)) .labelled(stringify!($name)) @@ -142,18 +146,23 @@ impl<'s> Function<'s> { one![Both], one![Reduce], one![Map], - λ.clone().then_ignore(just(Token::Group)).map(Group), - just(Token::Array) - .ignore_then( + λ.clone() + .then_ignore(just(Token::Group).labelled("group")) + .map(Group), + choice(( + just(Token::Array).ignore_then( fn_param .clone() + .map_with(spanned!()) .map(NumberΛ::Λ) - .or(select! { Token::Int(x) => NumberΛ::Number(x)}), - ) - .map(Some) - .map(Array) - .labelled("array") - .boxed(), + .or(select! { Token::Int(x) => NumberΛ::Number(x) }) + .map(Some) + .map(Array), + ), + just(Token::Array).map(|_| Array(None)), + )) + .labelled("array") + .boxed(), fn_param .clone() .then(fn_param.clone()) diff --git a/src/parser/types.rs b/src/parser/types.rs index b9197e6..1cb23e3 100644 --- a/src/parser/types.rs +++ b/src/parser/types.rs @@ -18,13 +18,8 @@ pub type Input<'s> = MappedInput< fn((Token<'_>, SimpleSpan)) -> (Token<'_>, SimpleSpan), >; -#[derive(Debug)] -pub enum Ast<'s> { - Module(Vec<Expr<'s>>), -} - #[derive(Clone, Default)] -pub struct Λ<'s>(pub Vec<Expr<'s>>); +pub struct Λ<'s>(pub Vec<Spanned<Expr<'s>>>); impl std::fmt::Debug for Λ<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match &*self.0 { @@ -50,7 +45,7 @@ pub enum Value<'s> { Float(f64), Int(u64), String(Cow<'s, str>), - Unit, + Lambda(Λ<'s>), } impl std::fmt::Debug for Value<'_> { @@ -59,7 +54,7 @@ impl std::fmt::Debug for Value<'_> { Self::Float(x) => write!(f, "{x}"), Self::Int(x) => write!(f, "{x}"), Self::String(x) => write!(f, "\"{x}\""), - Self::Unit => write!(f, "()"), + Self::Lambda(s) => s.fmt(f), } } } @@ -67,29 +62,32 @@ impl std::fmt::Debug for Value<'_> { impl std::fmt::Debug for Expr<'_> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self::NoOp => write!(f, "nop"), Self::Function(x) => x.fmt(f), Self::Value(x) => x.fmt(f), - Self::Ident(x) => x.fmt(f), - Self::Lambda(x) => x.fmt(f), - Self::Let { name, rhs } => write!(f, "let({rhs:?} -> {name})"), } } } + #[derive(Clone)] pub enum Expr<'s> { - NoOp, Function(super::fun::Function<'s>), Value(Value<'s>), - Ident(&'s str), - Lambda(Λ<'s>), - Let { name: &'s str, rhs: Box<Expr<'s>> }, } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Clone)] pub struct Spanned<T> { + pub(crate) span: SimpleSpan, pub inner: T, - pub span: Span, +} +impl<T: std::fmt::Debug> std::fmt::Debug for Spanned<T> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.inner.fmt(f) + } +} +impl<T> Spanned<T> { + fn new(inner: T, span: SimpleSpan) -> Self { + Self { inner, span } + } } impl<T> Deref for Spanned<T> { @@ -101,13 +99,25 @@ impl<T> Deref for Spanned<T> { } impl<T> Spanned<T> { - pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Spanned<U> { + pub fn map<U>(self, f: impl Fn(T) -> U) -> Spanned<U> { Spanned { inner: f(self.inner), span: self.span, } } + pub fn unspan() -> impl Fn(Spanned<T>) -> T + Copy { + |x| x.inner + } + + pub fn span(&self) -> SimpleSpan { + self.span + } + pub fn raw(self) -> (T, SimpleSpan) { + let Spanned { inner, span } = self; + (inner, span) + } + pub fn dummy(inner: T) -> Spanned<T> { Spanned { inner, @@ -1,13 +1,40 @@ +use crate::exec::Error as ExecutionError; use crate::parser::types::Error; -use chumsky::{error::RichReason, prelude::*}; -use codespan_reporting::diagnostic::LabelStyle::{Primary, Secondary}; +use chumsky::error::RichReason; +use codespan_reporting::diagnostic::LabelStyle::{self, Primary, Secondary}; use codespan_reporting::diagnostic::{Diagnostic, Label}; use codespan_reporting::files::SimpleFiles; use codespan_reporting::term::termcolor::{ColorChoice, StandardStream}; use codespan_reporting::term::Chars; use comat::cformat as cmt; -use itertools::Itertools; + +pub fn display_execution<T>(x: Result<T, ExecutionError>, code: &str) -> T { + let e = match x { + Ok(x) => return x, + Err(e) => e, + }; + let mut files = SimpleFiles::new(); + files.add("x.kale", code); + let mut d = Diagnostic::<usize>::new(codespan_reporting::diagnostic::Severity::Error) + .with_message(e.name) + .with_label( + Label::new(LabelStyle::Primary, 0, e.message.span()).with_message(e.message.raw().0), + ); + for label in e.labels { + d = d.with_label( + Label::new(LabelStyle::Secondary, 0, label.span()).with_message(label.raw().0), + ); + } + + d = d.with_notes(e.notes); + + let writer = StandardStream::stderr(ColorChoice::Always); + let mut config = codespan_reporting::term::Config::default(); + config.chars = Chars::box_drawing(); + codespan_reporting::term::emit(&mut writer.lock(), &config, &files, &d).unwrap(); + std::process::exit(2); +} pub fn display<T>(result: Result<T, Vec<Error>>, code: &str) -> Result<T, ()> { let e = match result { @@ -48,8 +75,6 @@ pub fn display<T>(result: Result<T, Vec<Error>>, code: &str) -> Result<T, ()> { // }; // } } - dbg!(e.contexts().collect::<Vec<_>>()); - for (l, span) in e.contexts() { d = d.with_label(Label { style: Secondary, @@ -67,7 +92,6 @@ pub fn display<T>(result: Result<T, Vec<Error>>, code: &str) -> Result<T, ()> { let writer = StandardStream::stderr(ColorChoice::Always); let mut config = codespan_reporting::term::Config::default(); config.chars = Chars::box_drawing(); - codespan_reporting::term::emit(&mut writer.lock(), &config, &files, &d).unwrap(); } Err(()) @@ -1,22 +1,15 @@ "1abc25hriwm4" -/ { str → int } / +/ { str → int } ( (('0'≥)🗺) (('9'≤)🗺)&∧ 🔓0 1¯🔒 - ⬇10×+⬆ + (10×+)⬇ ) → l (^0<¯🐬) → ⟐ -/ [x] -> [x] int / -(^(1)🗺+↘️) → '📏' - -/ run function on all values, pushing to the stack / -⏭️line -/ reduce the stack / -+↘️ ("\n"≢)👩👩👧👧 l🗺 @@ -26,4 +19,4 @@ 2🪟 (s-(🔀-)🐋 (≥1)(≤3)&s∧!)🗺+↘️0≡ ) → 'd2p1' -(📏1+⏫( / array, int / ^🇽 'd2p1')🗺+↘️0≢) → 'd2p2' +(📏1+⏫(^🇽 'd2p1')🗺+↘️0≢) → 'd2p2' |