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" }
|
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"
|
||||||
|
|
17
src/main.rs
17
src/main.rs
|
@ -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();
|
||||||
|
|
||||||
|
|
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)]
|
#[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");
|
||||||
|
|
||||||
|
|
34
src/value.rs
34
src/value.rs
|
@ -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
131
src/vm.rs
|
@ -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!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user