lots of new things! almost a language

This commit is contained in:
Scott Richmond 2024-11-10 20:12:19 -05:00
parent bb683b09b4
commit 9f0cef5207
5 changed files with 223 additions and 76 deletions

View File

@ -9,3 +9,4 @@ edition = "2021"
ariadne = { git = "https://github.com/zesterer/ariadne" } ariadne = { git = "https://github.com/zesterer/ariadne" }
chumsky = { git = "https://github.com/zesterer/chumsky", features = ["label"] } chumsky = { git = "https://github.com/zesterer/chumsky", features = ["label"] }
imbl = "3.0.0" imbl = "3.0.0"
tailcall = "1.0.1"

View File

@ -26,7 +26,6 @@
// * [ ] perf testing // * [ ] perf testing
use chumsky::{input::Stream, prelude::*}; use chumsky::{input::Stream, prelude::*};
use std::rc::Rc;
mod spans; mod spans;
@ -34,7 +33,6 @@ mod lexer;
use crate::lexer::*; use crate::lexer::*;
mod value; mod value;
use crate::value::*;
mod parser; mod parser;
use crate::parser::*; use crate::parser::*;
@ -43,7 +41,10 @@ mod vm;
use crate::vm::*; use crate::vm::*;
pub fn main() { pub fn main() {
let src = "when { 0 -> :false; true -> :true}"; let src = "
#{:a 1, :b 2}
";
let (tokens, lex_errs) = lexer().parse(src).into_output_errors(); let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
if lex_errs.len() > 0 { if lex_errs.len() > 0 {
println!("{:?}", lex_errs); println!("{:?}", lex_errs);
@ -51,15 +52,15 @@ pub fn main() {
} }
let tokens = tokens.unwrap(); let tokens = tokens.unwrap();
let to_parse = tokens.clone(); let to_parse = tokens.clone();
for (token, _) in tokens { // for (token, _) in tokens {
println!("{}", token) // println!("{}", token)
} // }
let (ast, _) = parser() let (ast, _) = parser()
.parse(Stream::from_iter(to_parse).map((0..src.len()).into(), |(t, s)| (t, s))) .parse(Stream::from_iter(to_parse).map((0..src.len()).into(), |(t, s)| (t, s)))
.unwrap(); .unwrap();
println!("{}", ast); // println!("{}", ast);
let mut ctx = vec![("foo", Value::Number(42.0))]; let mut ctx = vec![];
let result = eval(&ast, &mut ctx).unwrap(); let result = eval(&ast, &mut ctx).unwrap();

View File

@ -32,6 +32,18 @@ impl<'src> fmt::Display for MatchClause<'src> {
} }
} }
#[derive(Clone, Debug, PartialEq)]
pub struct Pair<'src> {
pub key: &'src str,
pub value: Spanned<Ast<'src>>,
}
impl<'src> fmt::Display for Pair<'src> {
fn fmt(self: &Pair<'src>, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "pair: {}: {}", self.key, self.value.0)
}
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Ast<'src> { pub enum Ast<'src> {
Error, Error,
@ -47,20 +59,19 @@ pub enum Ast<'src> {
Tuple(Vec<Spanned<Self>>), Tuple(Vec<Spanned<Self>>),
Arguments(Vec<Spanned<Self>>), Arguments(Vec<Spanned<Self>>),
List(Vec<Spanned<Self>>), List(Vec<Spanned<Self>>),
Pair(&'src str, Box<Spanned<Self>>), Dict(Vec<Pair<'src>>),
Dict(Vec<Spanned<Self>>),
Let(Box<Spanned<Pattern<'src>>>, Box<Spanned<Self>>), Let(Box<Spanned<Pattern<'src>>>, Box<Spanned<Self>>),
Box(&'src str, Box<Spanned<Self>>), Box(&'src str, Box<Spanned<Self>>),
Synthetic(Box<Spanned<Self>>, Box<Spanned<Self>>, Vec<Spanned<Self>>), Synthetic(Box<Spanned<Self>>, Box<Spanned<Self>>, Vec<Spanned<Self>>),
When(Vec<Spanned<WhenClause<'src>>>), When(Vec<Spanned<WhenClause<'src>>>),
Match(Box<Spanned<Self>>, Vec<Spanned<MatchClause<'src>>>), Match(Box<Spanned<Self>>, Vec<MatchClause<'src>>),
Fn(&'src str, Vec<Spanned<MatchClause<'src>>>), Fn(&'src str, Vec<MatchClause<'src>>),
FnDeclaration(&'src str), FnDeclaration(&'src str),
Panic(Box<Spanned<Self>>), Panic(Box<Spanned<Self>>),
Do(Vec<Spanned<Self>>), Do(Vec<Spanned<Self>>),
Repeat(Box<Spanned<Self>>, Box<Spanned<Self>>), Repeat(Box<Spanned<Self>>, Box<Spanned<Self>>),
Loop(Box<Spanned<Self>>, Vec<Spanned<Self>>), // Loop(Box<Spanned<Self>>, Vec<Spanned<Self>>),
Recur(Vec<Spanned<Self>>), // Recur(Vec<Spanned<Self>>),
} }
impl<'src> fmt::Display for Ast<'src> { impl<'src> fmt::Display for Ast<'src> {
@ -89,13 +100,12 @@ impl<'src> fmt::Display for Ast<'src> {
Ast::Let(pattern, expression) => { Ast::Let(pattern, expression) => {
write!(f, "Let: {} = {}", pattern.0, expression.0) write!(f, "Let: {} = {}", pattern.0, expression.0)
} }
Ast::Pair(kw, expr) => write!(f, "{} {}", kw, expr.0),
Ast::Dict(entries) => write!( Ast::Dict(entries) => write!(
f, f,
"#{{{}}}", "#{{{}}}",
entries entries
.iter() .iter()
.map(|(pair, _)| pair.to_string()) .map(|pair| pair.to_string())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", ") .join(", ")
), ),
@ -134,11 +144,54 @@ impl<'src> fmt::Display for Ast<'src> {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n") .join("\n")
), ),
_ => unimplemented!(), Ast::Placeholder => todo!(),
Ast::Box(_name, _rhs) => todo!(),
Ast::Match(value, clauses) => {
write!(
f,
"match: {} with {}",
&value.0.to_string(),
clauses
.iter()
.map(|clause| clause.to_string())
.collect::<Vec<_>>()
.join("\n")
)
}
Ast::Fn(name, clauses) => {
write!(
f,
"fn: {}\n{}",
name,
clauses
.iter()
.map(|clause| clause.to_string())
.collect::<Vec<_>>()
.join("\n")
)
}
Ast::FnDeclaration(_name) => todo!(),
Ast::Panic(_expr) => todo!(),
Ast::Do(_exprs) => todo!(),
Ast::Repeat(_times, _body) => todo!(),
// Ast::Loop(init, body) => todo!(),
// Ast::Recur(args) => todo!(),
} }
} }
} }
#[derive(Clone, Debug, PartialEq)]
pub struct PairPattern<'src> {
pub key: &'src str,
pub patt: Spanned<Pattern<'src>>,
}
impl<'src> fmt::Display for PairPattern<'src> {
fn fmt(self: &PairPattern<'src>, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "pair pattern: {}: {}", self.key, self.patt.0)
}
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Pattern<'src> { pub enum Pattern<'src> {
Nil, Nil,
@ -153,8 +206,7 @@ pub enum Pattern<'src> {
List(Vec<Spanned<Self>>), List(Vec<Spanned<Self>>),
// is this the right representation for Dicts? // is this the right representation for Dicts?
// Could/should this also be a Vec? // Could/should this also be a Vec?
Pair(&'src str, Box<Spanned<Self>>), Dict(Vec<Spanned<PairPattern<'src>>>),
Dict(Vec<Spanned<Self>>),
} }
impl<'src> fmt::Display for Pattern<'src> { impl<'src> fmt::Display for Pattern<'src> {
@ -184,7 +236,6 @@ impl<'src> fmt::Display for Pattern<'src> {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", ") .join(", ")
), ),
Pattern::Pair(kw, expr) => write!(f, "{} {}", kw, expr.0),
Pattern::Dict(entries) => write!( Pattern::Dict(entries) => write!(
f, f,
"#{{{}}}", "#{{{}}}",
@ -260,11 +311,14 @@ where
let pair_pattern = select! {Token::Keyword(k) => k} let pair_pattern = select! {Token::Keyword(k) => k}
.then(pattern.clone()) .then(pattern.clone())
.map_with(|(kw, patt), e| (Pattern::Pair(kw, Box::new(patt)), e.span())); .map_with(|(key, patt), e| (PairPattern { key, patt }, e.span()));
let shorthand_pattern = select! {Token::Word(w) => w}.map_with(|w, e| { let shorthand_pattern = select! {Token::Word(w) => w}.map_with(|w, e| {
( (
Pattern::Pair(w, Box::new((Pattern::Word(w), e.span()))), PairPattern {
key: w,
patt: ((Pattern::Word(w), e.span())),
},
e.span(), e.span(),
) )
}); });
@ -358,10 +412,12 @@ where
let pair = select! {Token::Keyword(k) => k} let pair = select! {Token::Keyword(k) => k}
.then(simple.clone()) .then(simple.clone())
.map_with(|(kw, expr), e| (Ast::Pair(kw, Box::new(expr)), e.span())); .map_with(|(key, value), e| Pair { key, value });
let shorthand = select! {Token::Word(w) => w} let shorthand = select! {Token::Word(w) => w}.map_with(|w, e| Pair {
.map_with(|w, e| (Ast::Pair(w, Box::new((Ast::Word(w), e.span()))), e.span())); key: w,
value: ((Ast::Word(w), e.span())),
});
let dict = pair let dict = pair
.or(shorthand) .or(shorthand)
@ -442,15 +498,10 @@ where
.clone() .clone()
.then_ignore(just(Token::Punctuation("->"))) .then_ignore(just(Token::Punctuation("->")))
.then(expr.clone()) .then(expr.clone())
.map_with(|(patt, body), e| { .map_with(|(patt, body), _| MatchClause {
( patt,
MatchClause { guard: None,
patt, body,
guard: None,
body,
},
e.span(),
)
}); });
let match_ = just(Token::Reserved("match")) let match_ = just(Token::Reserved("match"))
@ -499,15 +550,10 @@ where
.clone() .clone()
.then_ignore(just(Token::Punctuation("->"))) .then_ignore(just(Token::Punctuation("->")))
.then(nonbinding.clone()) .then(nonbinding.clone())
.map_with(|(patt, body), e| { .map_with(|(patt, body), _| MatchClause {
( patt,
MatchClause { body,
patt, guard: None,
body,
guard: None,
},
e.span(),
)
}) })
.labelled("function clause"); .labelled("function clause");

View File

@ -1,39 +1,32 @@
use crate::parser::*; use crate::parser::*;
use crate::spans::*;
use imbl::*; use imbl::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::fmt; use std::fmt;
use std::rc::Rc; use std::rc::Rc;
#[derive(Clone, Debug, PartialEq)]
pub struct Clause<'src> {
patt: Pattern<'src>,
span: Span,
body: Ast<'src>,
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Fn<'src> { pub struct Fn<'src> {
name: &'src str, pub name: &'src str,
span: Span, pub body: &'src Vec<MatchClause<'src>>,
body: Vec<Clause<'src>>,
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Value<'src> { pub enum Value<'src> {
Nil, Nil,
Placeholder,
Boolean(bool), Boolean(bool),
Number(f64), Number(f64),
Keyword(&'src str), Keyword(&'src str),
String(&'src str), String(&'src str),
// on the heap for now // on the heap for now
Tuple(Rc<Vec<Self>>), Tuple(Rc<Vec<Self>>),
Args(Rc<Vec<Self>>),
// ref-counted, immutable, persistent // ref-counted, immutable, persistent
List(Vector<Self>), List(Vector<Self>),
// ref-counted, immutable, persistent // ref-counted, immutable, persistent
Dict(HashMap<&'src str, Self>), Dict(HashMap<&'src str, Self>),
Box(&'src str, Rc<RefCell<Self>>), Box(&'src str, Rc<RefCell<Self>>),
// Fn(Rc<Fn<'src>>), Fn(Rc<Fn<'src>>),
// Set(HashSet<Self>), // Set(HashSet<Self>),
// Sets are hard // Sets are hard
// Sets require Eq // Sets require Eq
@ -55,9 +48,12 @@ impl<'src> Clone for Value<'src> {
Value::Keyword(s) => Value::Keyword(s), Value::Keyword(s) => Value::Keyword(s),
Value::Number(n) => Value::Number(n.clone()), Value::Number(n) => Value::Number(n.clone()),
Value::Tuple(t) => Value::Tuple(t.clone()), Value::Tuple(t) => Value::Tuple(t.clone()),
Value::Args(a) => Value::Args(a.clone()),
Value::Fn(f) => Value::Fn(f.clone()),
Value::List(l) => Value::List(l.clone()), Value::List(l) => Value::List(l.clone()),
Value::Dict(d) => Value::Dict(d.clone()), Value::Dict(d) => Value::Dict(d.clone()),
Value::Box(name, b) => Value::Box(name, b.clone()), Value::Box(name, b) => Value::Box(name, b.clone()),
Value::Placeholder => Value::Placeholder,
} }
} }
} }
@ -70,8 +66,8 @@ impl<'src> fmt::Display for Value<'src> {
Value::Number(n) => write!(f, "{}", n), Value::Number(n) => write!(f, "{}", n),
Value::Keyword(k) => write!(f, ":{}", k), Value::Keyword(k) => write!(f, ":{}", k),
Value::String(s) => write!(f, "\"{}\"", s), Value::String(s) => write!(f, "\"{}\"", s),
// Value::Fn(fun) => write!(f, "fn {}", fun.name), Value::Fn(fun) => write!(f, "fn {}", fun.name),
Value::Tuple(t) => write!( Value::Tuple(t) | Value::Args(t) => write!(
f, f,
"({})", "({})",
t.iter() t.iter()
@ -87,8 +83,16 @@ impl<'src> fmt::Display for Value<'src> {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", ") .join(", ")
), ),
Value::Dict(d) => write!(f, "#{{{:?}}}", d), Value::Dict(d) => write!(
f,
"#{{{}}}",
d.iter()
.map(|(k, v)| format!(":{k} {v}"))
.collect::<Vec<_>>()
.join(", ")
),
Value::Box(name, b) => todo!(), Value::Box(name, b) => todo!(),
Value::Placeholder => write!(f, "_"),
} }
} }
} }

131
src/vm.rs
View File

@ -1,6 +1,8 @@
use crate::parser::*; use crate::parser::*;
use crate::value::*; use crate::value::*;
use imbl::HashMap;
use imbl::Vector; use imbl::Vector;
use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@ -48,7 +50,7 @@ where
} }
} }
pub fn matchh<'src, 'a>( pub fn match_pattern<'src, 'a>(
patt: &Pattern<'src>, patt: &Pattern<'src>,
val: &Value<'src>, val: &Value<'src>,
ctx: &'a mut Vec<(&'src str, Value<'src>)>, ctx: &'a mut Vec<(&'src str, Value<'src>)>,
@ -71,7 +73,7 @@ pub fn matchh<'src, 'a>(
}; };
let to = ctx.len(); let to = ctx.len();
for i in 0..x.len() { for i in 0..x.len() {
if let None = matchh(&x[i].0, &y[i], ctx) { if let None = match_pattern(&x[i].0, &y[i], ctx) {
while ctx.len() > to { while ctx.len() > to {
ctx.pop(); ctx.pop();
} }
@ -86,7 +88,7 @@ pub fn matchh<'src, 'a>(
}; };
let to = ctx.len(); let to = ctx.len();
for i in 0..x.len() { for i in 0..x.len() {
if let None = matchh(&x[i].0, y.get(i).unwrap(), ctx) { if let None = match_pattern(&x[i].0, y.get(i).unwrap(), ctx) {
while ctx.len() > to { while ctx.len() > to {
ctx.pop(); ctx.pop();
} }
@ -95,14 +97,60 @@ pub fn matchh<'src, 'a>(
} }
Some(ctx) Some(ctx)
} }
(Pattern::Pair(_, _), _) => todo!("dictionary patterns still to do"),
(Pattern::Dict(_), _) => todo!("dictionary patterns still to do"), (Pattern::Dict(_), _) => todo!("dictionary patterns still to do"),
_ => None, _ => None,
} }
} }
pub fn match_clauses<'src, 'a>(
value: &Value<'src>,
clauses: &'src Vec<MatchClause<'src>>,
ctx: &'a mut Vec<(&'src str, Value<'src>)>,
) -> Result<Value<'src>, LudusError> {
let to = ctx.len();
for MatchClause { patt, body, .. } in clauses.iter() {
if let Some(ctx) = match_pattern(&patt.0, value, ctx) {
let res = eval(&body.0, ctx);
while ctx.len() > to {
ctx.pop();
}
return res;
}
}
Err(LudusError {
msg: "no match".to_string(),
})
}
pub fn apply<'src, 'a>(
callee: Value<'src>,
caller: Value<'src>,
ctx: &'a mut Vec<(&'src str, Value<'src>)>,
) -> Result<Value<'src>, LudusError> {
match (callee, caller) {
(Value::Keyword(kw), Value::Dict(dict)) => {
if let Some(val) = dict.get(kw) {
Ok(val.clone())
} else {
Ok(Value::Nil)
}
}
(Value::Dict(_dict), Value::Keyword(_kw)) => todo!(),
(Value::Fn(f), Value::Tuple(args)) => {
let args = Value::Tuple(args);
match_clauses(&args, f.body, ctx)
}
(Value::Fn(_f), Value::Args(_args)) => todo!(),
(_, Value::Keyword(_)) => Ok(Value::Nil),
(_, Value::Args(_)) => Err(LudusError {
msg: "you may only call a function".to_string(),
}),
_ => unreachable!(),
}
}
pub fn eval<'src, 'a>( pub fn eval<'src, 'a>(
ast: &Ast<'src>, ast: &'src Ast<'src>,
ctx: &'a mut Vec<(&'src str, Value<'src>)>, ctx: &'a mut Vec<(&'src str, Value<'src>)>,
) -> Result<Value<'src>, LudusError> { ) -> Result<Value<'src>, LudusError> {
match ast { match ast {
@ -154,20 +202,57 @@ pub fn eval<'src, 'a>(
} }
Ast::Let(patt, expr) => { Ast::Let(patt, expr) => {
let val = eval(&expr.0, ctx)?; let val = eval(&expr.0, ctx)?;
match matchh(&patt.0, &val, ctx) { match match_pattern(&patt.0, &val, ctx) {
Some(_) => Ok(val), Some(_) => Ok(val),
None => Err(LudusError { None => Err(LudusError {
msg: "No match".to_string(), msg: "No match".to_string(),
}), }),
} }
} }
Ast::Placeholder => todo!(), Ast::Placeholder => Ok(Value::Placeholder),
Ast::Error => todo!(), Ast::Error => unreachable!(),
Ast::Dict(_) => todo!(), Ast::Arguments(a) => {
Ast::Arguments(_) => todo!(), let mut args = vec![];
Ast::Pair(_, _) => todo!(), for (arg, _) in a.iter() {
Ast::Box(_, _) => todo!(), let arg = eval(&arg, ctx)?;
Ast::Synthetic(_, _, _) => todo!(), args.push(arg);
}
if args.iter().any(|arg| {
if let Value::Placeholder = arg {
true
} else {
false
}
}) {
Ok(Value::Args(Rc::new(args)))
} else {
Ok(Value::Tuple(Rc::new(args)))
}
}
Ast::Dict(pairs) => {
let mut dict = HashMap::new();
for Pair { key, value } in pairs {
let value = eval(&value.0, ctx)?;
dict.insert(*key, value);
}
Ok(Value::Dict(dict))
}
Ast::Box(name, expr) => {
let val = eval(&expr.0, ctx)?;
let boxed = Value::Box(name, Rc::new(RefCell::new(val)));
ctx.push((name, boxed.clone()));
Ok(boxed)
}
Ast::Synthetic(root, first, rest) => {
let root = eval(&root.0, ctx)?;
let first = eval(&first.0, ctx)?;
let mut curr = apply(root, first, ctx)?;
for term in rest.iter() {
let next = eval(&term.0, ctx)?;
curr = apply(curr, next, ctx)?;
}
Ok(curr)
}
Ast::When(clauses) => { Ast::When(clauses) => {
for clause in clauses.iter() { for clause in clauses.iter() {
let WhenClause { cond, body } = &clause.0; let WhenClause { cond, body } = &clause.0;
@ -179,8 +264,18 @@ pub fn eval<'src, 'a>(
msg: "no match".to_string(), msg: "no match".to_string(),
}); });
} }
Ast::Match(_, _) => todo!(), Ast::Match(value, clauses) => {
Ast::Fn(_, _) => todo!(), let value = eval(&value.0, ctx)?;
match_clauses(&value, clauses, ctx)
}
Ast::Fn(name, clauses) => {
let the_fn = Value::Fn::<'src>(Rc::new(Fn::<'src> {
name,
body: clauses,
}));
ctx.push((name, the_fn.clone()));
Ok(the_fn)
}
Ast::FnDeclaration(_) => todo!(), Ast::FnDeclaration(_) => todo!(),
Ast::Panic(msg) => { Ast::Panic(msg) => {
let msg = eval(&msg.0, ctx)?; let msg = eval(&msg.0, ctx)?;
@ -201,12 +296,12 @@ pub fn eval<'src, 'a>(
} }
} }
for _ in 0..times_num { for _ in 0..times_num {
let _ = eval(&body.0, ctx)?; eval(&body.0, ctx)?;
} }
Ok(Value::Nil) Ok(Value::Nil)
} }
Ast::Do(_) => todo!(), Ast::Do(_) => todo!(),
Ast::Loop(_, _) => todo!(), // Ast::Loop(_, _) => todo!(),
Ast::Recur(_) => todo!(), // Ast::Recur(_) => todo!(),
} }
} }