checkpoint
bendn 2025-02-24
parent 04ffefe · commit a85a92e
-rw-r--r--Cargo.toml2
-rw-r--r--src/exec.rs625
-rw-r--r--src/lexer.rs15
-rw-r--r--src/main.rs17
-rw-r--r--src/parser.rs31
-rw-r--r--src/parser/fun.rs43
-rw-r--r--src/parser/types.rs48
-rw-r--r--src/ui.rs36
-rw-r--r--stackd13
9 files changed, 750 insertions, 80 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 259b164..78233a5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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,
diff --git a/src/ui.rs b/src/ui.rs
index 8482346..54bb40c 100644
--- a/src/ui.rs
+++ b/src/ui.rs
@@ -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(())
diff --git a/stackd b/stackd
index 656220e..6a64b8e 100644
--- a/stackd
+++ b/stackd
@@ -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'