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" }
chumsky = { git = "https://github.com/zesterer/chumsky", features = ["label"] }
imbl = "3.0.0"
tailcall = "1.0.1"

View File

@ -26,7 +26,6 @@
// * [ ] perf testing
use chumsky::{input::Stream, prelude::*};
use std::rc::Rc;
mod spans;
@ -34,7 +33,6 @@ mod lexer;
use crate::lexer::*;
mod value;
use crate::value::*;
mod parser;
use crate::parser::*;
@ -43,7 +41,10 @@ mod vm;
use crate::vm::*;
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();
if lex_errs.len() > 0 {
println!("{:?}", lex_errs);
@ -51,15 +52,15 @@ pub fn main() {
}
let tokens = tokens.unwrap();
let to_parse = tokens.clone();
for (token, _) in tokens {
println!("{}", token)
}
// for (token, _) in tokens {
// println!("{}", token)
// }
let (ast, _) = parser()
.parse(Stream::from_iter(to_parse).map((0..src.len()).into(), |(t, s)| (t, s)))
.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();

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

View File

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

131
src/vm.rs
View File

@ -1,6 +1,8 @@
use crate::parser::*;
use crate::value::*;
use imbl::HashMap;
use imbl::Vector;
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Clone, Debug)]
@ -48,7 +50,7 @@ where
}
}
pub fn matchh<'src, 'a>(
pub fn match_pattern<'src, 'a>(
patt: &Pattern<'src>,
val: &Value<'src>,
ctx: &'a mut Vec<(&'src str, Value<'src>)>,
@ -71,7 +73,7 @@ pub fn matchh<'src, 'a>(
};
let to = ctx.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 {
ctx.pop();
}
@ -86,7 +88,7 @@ pub fn matchh<'src, 'a>(
};
let to = ctx.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 {
ctx.pop();
}
@ -95,14 +97,60 @@ pub fn matchh<'src, 'a>(
}
Some(ctx)
}
(Pattern::Pair(_, _), _) => todo!("dictionary patterns still to do"),
(Pattern::Dict(_), _) => todo!("dictionary patterns still to do"),
_ => 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>(
ast: &Ast<'src>,
ast: &'src Ast<'src>,
ctx: &'a mut Vec<(&'src str, Value<'src>)>,
) -> Result<Value<'src>, LudusError> {
match ast {
@ -154,20 +202,57 @@ pub fn eval<'src, 'a>(
}
Ast::Let(patt, expr) => {
let val = eval(&expr.0, ctx)?;
match matchh(&patt.0, &val, ctx) {
match match_pattern(&patt.0, &val, ctx) {
Some(_) => Ok(val),
None => Err(LudusError {
msg: "No match".to_string(),
}),
}
}
Ast::Placeholder => todo!(),
Ast::Error => todo!(),
Ast::Dict(_) => todo!(),
Ast::Arguments(_) => todo!(),
Ast::Pair(_, _) => todo!(),
Ast::Box(_, _) => todo!(),
Ast::Synthetic(_, _, _) => todo!(),
Ast::Placeholder => Ok(Value::Placeholder),
Ast::Error => unreachable!(),
Ast::Arguments(a) => {
let mut args = vec![];
for (arg, _) in a.iter() {
let arg = eval(&arg, ctx)?;
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) => {
for clause in clauses.iter() {
let WhenClause { cond, body } = &clause.0;
@ -179,8 +264,18 @@ pub fn eval<'src, 'a>(
msg: "no match".to_string(),
});
}
Ast::Match(_, _) => todo!(),
Ast::Fn(_, _) => todo!(),
Ast::Match(value, clauses) => {
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::Panic(msg) => {
let msg = eval(&msg.0, ctx)?;
@ -201,12 +296,12 @@ pub fn eval<'src, 'a>(
}
}
for _ in 0..times_num {
let _ = eval(&body.0, ctx)?;
eval(&body.0, ctx)?;
}
Ok(Value::Nil)
}
Ast::Do(_) => todo!(),
Ast::Loop(_, _) => todo!(),
Ast::Recur(_) => todo!(),
// Ast::Loop(_, _) => todo!(),
// Ast::Recur(_) => todo!(),
}
}