lots of new things! almost a language
This commit is contained in:
parent
bb683b09b4
commit
9f0cef5207
|
@ -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"
|
||||
|
|
17
src/main.rs
17
src/main.rs
|
@ -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();
|
||||
|
||||
|
|
116
src/parser.rs
116
src/parser.rs
|
@ -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");
|
||||
|
||||
|
|
34
src/value.rs
34
src/value.rs
|
@ -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
131
src/vm.rs
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user