finish fighting with lifetimes: string pattern matching works!

This commit is contained in:
Scott Richmond 2024-12-07 23:56:19 -05:00
parent 5a64c6623c
commit 6ba05f31e6
6 changed files with 159 additions and 207 deletions

View File

@ -50,11 +50,12 @@ pub fn store<'src>(b: &Value<'src>, val: &Value<'src>) -> Value<'src> {
pub fn doc<'src>(f: &Value<'src>) -> Value<'src> {
match f {
Value::Fn(f) => {
let Fn { name, doc, .. } = **f;
let name = &f.name;
let doc = &f.doc;
if let Some(docstr) = doc {
Value::AllocatedString(Rc::new(format!("{name}: {docstr}")))
} else {
Value::InternedString(doc.unwrap_or("no documentation found"))
Value::AllocatedString(Rc::new(format!("{name}: no documentation found")))
}
}
_ => Value::InternedString("no documentation found"),
@ -569,116 +570,63 @@ pub fn r#mod<'src>(x: &Value, y: &Value) -> Value<'src> {
}
}
pub fn base<'src>() -> Vec<(&'src str, Value<'src>)> {
pub fn base<'src>() -> Vec<(String, Value<'src>)> {
vec![
("add", Value::Base(Base::Binary(add))),
("and", Value::Base(Base::Binary(and))),
("append", Value::Base(Base::Binary(append))),
("assoc", Value::Base(Base::Ternary(assoc))),
("at", Value::Base(Base::Binary(at))),
("atan_2", Value::Base(Base::Binary(atan_2))),
("bool", Value::Base(Base::Unary(r#bool))),
("ceil", Value::Base(Base::Unary(ceil))),
("chars", Value::Base(Base::Unary(chars))),
("concat", Value::Base(Base::Binary(concat))),
("cos", Value::Base(Base::Unary(cos))),
("count", Value::Base(Base::Unary(count))),
("dec", Value::Base(Base::Unary(dec))),
("dissoc", Value::Base(Base::Binary(dissoc))),
("div", Value::Base(Base::Binary(div))),
("doc!", Value::Base(Base::Unary(doc))),
("downcase", Value::Base(Base::Unary(downcase))),
("eq?", Value::Base(Base::Binary(eq))),
("first", Value::Base(Base::Unary(first))),
("floor", Value::Base(Base::Unary(floor))),
("get", Value::Base(Base::Binary(get))),
("gt?", Value::Base(Base::Binary(gt))),
("gte?", Value::Base(Base::Binary(gte))),
("inc", Value::Base(Base::Unary(inc))),
("last", Value::Base(Base::Unary(last))),
("list", Value::Base(Base::Unary(list))),
("lt?", Value::Base(Base::Binary(lt))),
("lte?", Value::Base(Base::Binary(lte))),
("mod", Value::Base(Base::Binary(r#mod))),
("mult", Value::Base(Base::Binary(mult))),
("number", Value::Base(Base::Unary(number))),
("or", Value::Base(Base::Binary(or))),
("pi", Value::Number(std::f64::consts::PI)),
("print!", Value::Base(Base::Unary(print))),
("random", Value::Base(Base::Nullary(random))),
("range", Value::Base(Base::Binary(range))),
("rest", Value::Base(Base::Unary(rest))),
("round", Value::Base(Base::Unary(round))),
("show", Value::Base(Base::Unary(show))),
("sin", Value::Base(Base::Unary(sin))),
("slice", Value::Base(Base::Ternary(slice))),
("split", Value::Base(Base::Binary(split))),
("sqrt", Value::Base(Base::Unary(sqrt))),
("sqrt_2", Value::Number(std::f64::consts::SQRT_2)),
("store!", Value::Base(Base::Binary(store))),
("sub", Value::Base(Base::Binary(sub))),
("tan", Value::Base(Base::Unary(tan))),
("trim", Value::Base(Base::Unary(trim))),
("triml", Value::Base(Base::Unary(triml))),
("trimr", Value::Base(Base::Unary(trimr))),
("type", Value::Base(Base::Unary(r#type))),
("unbox", Value::Base(Base::Unary(unbox))),
("upcase", Value::Base(Base::Unary(upcase))),
("add".to_string(), Value::Base(Base::Binary(add))),
("and".to_string(), Value::Base(Base::Binary(and))),
("append".to_string(), Value::Base(Base::Binary(append))),
("assoc".to_string(), Value::Base(Base::Ternary(assoc))),
("at".to_string(), Value::Base(Base::Binary(at))),
("atan_2".to_string(), Value::Base(Base::Binary(atan_2))),
("bool".to_string(), Value::Base(Base::Unary(r#bool))),
("ceil".to_string(), Value::Base(Base::Unary(ceil))),
("chars".to_string(), Value::Base(Base::Unary(chars))),
("concat".to_string(), Value::Base(Base::Binary(concat))),
("cos".to_string(), Value::Base(Base::Unary(cos))),
("count".to_string(), Value::Base(Base::Unary(count))),
("dec".to_string(), Value::Base(Base::Unary(dec))),
("dissoc".to_string(), Value::Base(Base::Binary(dissoc))),
("div".to_string(), Value::Base(Base::Binary(div))),
("doc!".to_string(), Value::Base(Base::Unary(doc))),
("downcase".to_string(), Value::Base(Base::Unary(downcase))),
("eq?".to_string(), Value::Base(Base::Binary(eq))),
("first".to_string(), Value::Base(Base::Unary(first))),
("floor".to_string(), Value::Base(Base::Unary(floor))),
("get".to_string(), Value::Base(Base::Binary(get))),
("gt?".to_string(), Value::Base(Base::Binary(gt))),
("gte?".to_string(), Value::Base(Base::Binary(gte))),
("inc".to_string(), Value::Base(Base::Unary(inc))),
("last".to_string(), Value::Base(Base::Unary(last))),
("list".to_string(), Value::Base(Base::Unary(list))),
("lt?".to_string(), Value::Base(Base::Binary(lt))),
("lte?".to_string(), Value::Base(Base::Binary(lte))),
("mod".to_string(), Value::Base(Base::Binary(r#mod))),
("mult".to_string(), Value::Base(Base::Binary(mult))),
("number".to_string(), Value::Base(Base::Unary(number))),
("or".to_string(), Value::Base(Base::Binary(or))),
("pi".to_string(), Value::Number(std::f64::consts::PI)),
("print!".to_string(), Value::Base(Base::Unary(print))),
("random".to_string(), Value::Base(Base::Nullary(random))),
("range".to_string(), Value::Base(Base::Binary(range))),
("rest".to_string(), Value::Base(Base::Unary(rest))),
("round".to_string(), Value::Base(Base::Unary(round))),
("show".to_string(), Value::Base(Base::Unary(show))),
("sin".to_string(), Value::Base(Base::Unary(sin))),
("slice".to_string(), Value::Base(Base::Ternary(slice))),
("split".to_string(), Value::Base(Base::Binary(split))),
("sqrt".to_string(), Value::Base(Base::Unary(sqrt))),
(
"sqrt_2".to_string(),
Value::Number(std::f64::consts::SQRT_2),
),
("store!".to_string(), Value::Base(Base::Binary(store))),
("sub".to_string(), Value::Base(Base::Binary(sub))),
("tan".to_string(), Value::Base(Base::Unary(tan))),
("trim".to_string(), Value::Base(Base::Unary(trim))),
("triml".to_string(), Value::Base(Base::Unary(triml))),
("trimr".to_string(), Value::Base(Base::Unary(trimr))),
("type".to_string(), Value::Base(Base::Unary(r#type))),
("unbox".to_string(), Value::Base(Base::Unary(unbox))),
("upcase".to_string(), Value::Base(Base::Unary(upcase))),
]
}
// * [x] atan_2 (x) -> number
// * [x] ceil (x) -> number
// * [x] cos (x) -> number
// * [x] floor (x) -> number
// * [x] gt (x, y) -> bool
// * [x] gte! (x, y) -> bool
// * [x] lt (x) -> bool
// * [x] lte (x) -> bool
// * [x] mod (x, y) -> number
// * [x] pi
// * [x] random () -> number
// * [x] round (x) -> number
// * [x] sin (x) -> number
// * [x] sqrt (x) -> number
// * [x] tan (x) -> number
// * [x] add (x, y) -> number
// * [x] and (x, y) -> value
// * [x] append (x, y) -> list
// * [x] assoc (x, y) -> dict
// * [x] bool (x) -> bool
// * [x] chars (x) -> list
// * [x] concat (x, y) -> value
// * [x] count (x) -> number
// * [x] dec (x) -> number
// * [x] dissoc (x, y) -> dict
// * [x] div (x, y) -> number
// * [x] doc (x) -> string
// * [x] downcase (x) -> string
// * [x] eq (x, y) -> bool
// * [x] first (x) -> value
// * [x] get (x, y) -> value
// * [x] inc (x) -> number
// * [x] last (x) -> value
// * [x] or (x, y) -> value
// * [x] print! (x) -> :ok
// * [x] range () -> list
// * [x] rest (x) -> coll
// * [x] show (x) -> string
// * [x] slice (x, y, z) -> list
// * [x] split (x, y) -> list(string)
// * [x] store! (x, y) -> value
// * [x] sub (x, y) -> number
// * [x] to_list (x) -> list
// * [x] to_number (x) -> number
// * [x] trim (x) -> string
// * [x] triml (x) -> string
// * [x] trimr (x) -> string
// * [x] type (x) -> keyword
// * [x] unbox (x) -> value
// * [x] upcase (x) -> string
// * [x] ~prn (x) -> value~
// * [x] ~push (x) -> list~
// * [x] ~str_slice (x, y, z) -> string~
// * [x] ~stringify (x) -> string~
// * [~] disj (x) -> set

View File

@ -3,19 +3,19 @@ use chumsky::prelude::*;
use std::fmt;
#[derive(Clone, Debug, PartialEq)]
pub enum Token<'src> {
pub enum Token {
Nil,
Number(f64),
Word(&'src str),
Word(&'static str),
Boolean(bool),
Keyword(&'src str),
String(&'src str),
Keyword(&'static str),
String(&'static str),
// todo: hard code these types
Reserved(&'src str),
Punctuation(&'src str),
Reserved(&'static str),
Punctuation(&'static str),
}
impl fmt::Display for Token<'_> {
impl fmt::Display for Token {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Token::Number(n) => write!(f, "[Number {}]", n),
@ -30,8 +30,8 @@ impl fmt::Display for Token<'_> {
}
}
pub fn lexer<'src>(
) -> impl Parser<'src, &'src str, Vec<(Token<'src>, Span)>, extra::Err<Rich<'src, char, Span>>> {
pub fn lexer(
) -> impl Parser<'static, &'static str, Vec<(Token, Span)>, extra::Err<Rich<'static, char, Span>>> {
let number = just('-')
.or_not()
.then(text::int(10).then(just('.').then(text::digits(10)).or_not()))

View File

@ -58,7 +58,7 @@ use crate::base::*;
pub fn main() {
let src = "
let \"{foo}bar{baz}\" = \"foo var baz\"
let \"foo {bar} baz\" = \"foo bar baz\"
";
let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
if !lex_errs.is_empty() {

View File

@ -5,26 +5,26 @@ use std::fmt;
use struct_scalpel::Dissectible;
#[derive(Clone, Debug, PartialEq)]
pub struct WhenClause<'src> {
pub cond: Spanned<Ast<'src>>,
pub body: Spanned<Ast<'src>>,
pub struct WhenClause {
pub cond: Spanned<Ast>,
pub body: Spanned<Ast>,
}
impl<'src> fmt::Display for WhenClause<'src> {
fn fmt(self: &WhenClause<'src>, f: &mut fmt::Formatter) -> fmt::Result {
impl fmt::Display for WhenClause {
fn fmt(self: &WhenClause, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "cond: {}, body: {}", self.cond.0, self.body.0)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct MatchClause<'src> {
pub patt: Spanned<Pattern<'src>>,
pub guard: Option<Spanned<Ast<'src>>>,
pub body: Spanned<Ast<'src>>,
pub struct MatchClause {
pub patt: Spanned<Pattern>,
pub guard: Option<Spanned<Ast>>,
pub body: Spanned<Ast>,
}
impl<'src> fmt::Display for MatchClause<'src> {
fn fmt(self: &MatchClause<'src>, f: &mut fmt::Formatter) -> fmt::Result {
impl fmt::Display for MatchClause {
fn fmt(self: &MatchClause, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"pattern: {}, guard: {:?} body: {}",
@ -52,15 +52,15 @@ impl fmt::Display for StringPart {
}
#[derive(Clone, Debug, PartialEq, Dissectible)]
pub enum Ast<'src> {
pub enum Ast {
Error,
Placeholder,
Nil,
Boolean(bool),
Number(f64),
Keyword(&'src str),
Word(&'src str),
String(&'src str),
Keyword(&'static str),
Word(&'static str),
String(&'static str),
Interpolated(Vec<Spanned<StringPart>>),
Block(Vec<Spanned<Self>>),
If(Box<Spanned<Self>>, Box<Spanned<Self>>, Box<Spanned<Self>>),
@ -68,23 +68,23 @@ pub enum Ast<'src> {
Arguments(Vec<Spanned<Self>>),
List(Vec<Spanned<Self>>),
Dict(Vec<Spanned<Self>>),
Let(Box<Spanned<Pattern<'src>>>, Box<Spanned<Self>>),
Box(&'src str, Box<Spanned<Self>>),
Let(Box<Spanned<Pattern>>, Box<Spanned<Self>>),
Box(&'static str, Box<Spanned<Self>>),
Synthetic(Box<Spanned<Self>>, Box<Spanned<Self>>, Vec<Spanned<Self>>),
When(Vec<Spanned<WhenClause<'src>>>),
Match(Box<Spanned<Self>>, Vec<MatchClause<'src>>),
Fn(&'src str, Vec<MatchClause<'src>>, Option<&'src str>),
FnDeclaration(&'src str),
When(Vec<Spanned<WhenClause>>),
Match(Box<Spanned<Self>>, Vec<MatchClause>),
Fn(&'static str, Vec<MatchClause>, Option<&'static str>),
FnDeclaration(&'static str),
Panic(Box<Spanned<Self>>),
Do(Vec<Spanned<Self>>),
Repeat(Box<Spanned<Self>>, Box<Spanned<Self>>),
Splat(&'src str),
Pair(&'src str, Box<Spanned<Self>>),
Loop(Box<Spanned<Self>>, Vec<MatchClause<'src>>),
Splat(&'static str),
Pair(&'static str, Box<Spanned<Self>>),
Loop(Box<Spanned<Self>>, Vec<MatchClause>),
Recur(Vec<Spanned<Self>>),
}
impl fmt::Display for Ast<'_> {
impl fmt::Display for Ast {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Ast::Error => write!(f, "Error"),
@ -236,62 +236,62 @@ impl fmt::Display for Ast<'_> {
}
#[derive(Clone, Debug, PartialEq)]
pub struct PairPattern<'src> {
pub key: &'src str,
pub patt: Spanned<Pattern<'src>>,
pub struct PairPattern {
pub key: &'static str,
pub patt: Spanned<Pattern>,
}
impl<'src> fmt::Display for PairPattern<'src> {
fn fmt(self: &PairPattern<'src>, f: &mut fmt::Formatter) -> fmt::Result {
impl fmt::Display for PairPattern {
fn fmt(self: &PairPattern, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "pair pattern: {}: {}", self.key, self.patt.0)
}
}
pub struct StringMatcher<'src>(pub Box<dyn Fn(String) -> Option<Vec<(String, String)>> + 'src>);
pub struct StringMatcher(pub Box<dyn Fn(String) -> Option<Vec<(String, String)>>>);
impl PartialEq for StringMatcher<'_> {
impl PartialEq for StringMatcher {
fn eq(&self, _other: &StringMatcher) -> bool {
true
}
}
impl<'src> Clone for StringMatcher<'src> {
fn clone(&self) -> StringMatcher<'src> {
impl Clone for StringMatcher {
fn clone(&self) -> StringMatcher {
unreachable!()
}
}
impl fmt::Display for StringMatcher<'_> {
impl fmt::Display for StringMatcher {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "string matcher")
}
}
impl fmt::Debug for StringMatcher<'_> {
impl fmt::Debug for StringMatcher {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "string matcher")
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum Pattern<'src> {
pub enum Pattern {
Nil,
Boolean(bool),
Number(f64),
String(&'src str),
Interpolated(Vec<Spanned<StringPart>>, StringMatcher<'src>),
Keyword(&'src str),
Word(&'src str),
As(&'src str, &'src str),
String(&'static str),
Interpolated(Vec<Spanned<StringPart>>, StringMatcher),
Keyword(&'static str),
Word(&'static str),
As(&'static str, &'static str),
Splattern(Box<Spanned<Self>>),
Placeholder,
Tuple(Vec<Spanned<Self>>),
List(Vec<Spanned<Self>>),
Pair(&'src str, Box<Spanned<Self>>),
Pair(&'static str, Box<Spanned<Self>>),
Dict(Vec<Spanned<Self>>),
}
impl fmt::Display for Pattern<'_> {
impl fmt::Display for Pattern {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Pattern::Nil => write!(f, "nil"),
@ -349,7 +349,7 @@ fn is_word_char(c: char) -> bool {
matches!(c, '_' | '/' | '?' | '!')
}
fn parse_string(s: &str, span: SimpleSpan) -> Result<Vec<Spanned<StringPart>>, String> {
fn parse_string(s: &'static str, span: SimpleSpan) -> Result<Vec<Spanned<StringPart>>, String> {
let mut parts = vec![];
let mut current_part = String::new();
let mut start = span.start;
@ -386,7 +386,7 @@ fn parse_string(s: &str, span: SimpleSpan) -> Result<Vec<Spanned<StringPart>>, S
'}' => {
if is_word {
parts.push((
StringPart::Word(current_part),
StringPart::Word(current_part.clone()),
SimpleSpan::new(start, start + i),
));
current_part = String::new();
@ -413,21 +413,17 @@ fn parse_string(s: &str, span: SimpleSpan) -> Result<Vec<Spanned<StringPart>>, S
}
}
if current_part == s {
parts.push((
if is_word {
let part = current_part.clone();
StringPart::Word(part)
} else if current_part == s {
StringPart::Inline(current_part)
} else {
StringPart::Data(current_part)
},
StringPart::Inline(current_part),
SimpleSpan::new(start, span.end),
));
))
}
Ok(parts)
}
pub fn compile_string_pattern<'src>(parts: Vec<Spanned<StringPart>>) -> StringMatcher<'src> {
pub fn compile_string_pattern(parts: Vec<Spanned<StringPart>>) -> StringMatcher {
StringMatcher(Box::new(move |scrutinee| {
let mut last_match = 0;
let mut parts_iter = parts.iter();
@ -457,6 +453,10 @@ pub fn compile_string_pattern<'src>(parts: Vec<Spanned<StringPart>>) -> StringMa
match to_test.find(part) {
None => return None,
Some(i) => {
matches.push((
word.clone(),
to_test.get(last_match..i).unwrap().to_string(),
));
last_match = i + part.len();
continue;
}
@ -471,10 +471,10 @@ pub fn compile_string_pattern<'src>(parts: Vec<Spanned<StringPart>>) -> StringMa
}))
}
pub fn parser<'src, I>(
) -> impl Parser<'src, I, Spanned<Ast<'src>>, extra::Err<Rich<'src, Token<'src>, Span>>> + Clone
pub fn parser<I>(
) -> impl Parser<'static, I, Spanned<Ast>, extra::Err<Rich<'static, Token, Span>>> + Clone
where
I: ValueInput<'src, Token = Token<'src>, Span = Span>,
I: ValueInput<'static, Token = Token, Span = Span>,
{
let mut expr = Recursive::declare();

View File

@ -8,9 +8,9 @@ use struct_scalpel::Dissectible;
#[derive(Clone, Debug)]
pub struct Fn<'src> {
pub name: &'src str,
pub body: &'src Vec<MatchClause<'src>>,
pub doc: &'src Option<&'src str>,
pub name: String,
pub body: &'src Vec<MatchClause>,
pub doc: Option<String>,
}
#[derive(Debug, Dissectible)]
@ -19,10 +19,10 @@ pub enum Value<'src> {
Placeholder,
Boolean(bool),
Number(f64),
Keyword(&'src str),
Keyword(&'static str),
// TODO: add a "runtime-generated" string type that wraps a Rust String
// this is necessary for nice documentation and string interpolation
InternedString(&'src str),
InternedString(&'static str),
AllocatedString(Rc<String>),
// on the heap for now
Tuple(Rc<Vec<Self>>),
@ -31,8 +31,8 @@ pub enum Value<'src> {
List(Vector<Self>),
// ref-counted, immutable, persistent
// dicts may only use keywords as keys
Dict(HashMap<&'src str, Self>),
Box(&'src str, Rc<RefCell<Self>>),
Dict(HashMap<&'static str, Self>),
Box(&'static str, Rc<RefCell<Self>>),
Fn(Rc<Fn<'src>>),
Base(Base<'src>),
Recur(Vec<Self>),
@ -62,7 +62,7 @@ impl<'src> Clone for Value<'src> {
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::Box(name, b) => Value::Box(*name, b.clone()),
Value::Placeholder => Value::Placeholder,
Value::Base(b) => Value::Base(b.clone()),
Value::Recur(..) => unreachable!(),

View File

@ -53,10 +53,10 @@ where
}
pub fn match_pattern<'src, 'a>(
patt: &Pattern<'src>,
patt: &Pattern,
val: &Value<'src>,
ctx: &'a mut Vec<(&'src str, Value<'src>)>,
) -> Option<&'a mut Vec<(&'src str, Value<'src>)>> {
ctx: &'a mut Vec<(String, Value<'src>)>,
) -> Option<&'a mut Vec<(String, Value<'src>)>> {
match (patt, val) {
(Pattern::Nil, Value::Nil) => Some(ctx),
(Pattern::Placeholder, _) => Some(ctx),
@ -64,14 +64,17 @@ pub fn match_pattern<'src, 'a>(
(Pattern::Boolean(x), Value::Boolean(y)) => match_eq(x, y, ctx),
(Pattern::Keyword(x), Value::Keyword(y)) => match_eq(x, y, ctx),
(Pattern::String(x), Value::InternedString(y)) => match_eq(x, y, ctx),
(Pattern::String(x), Value::AllocatedString(y)) => match_eq(&x.to_string(), &**y, ctx),
(Pattern::String(x), Value::AllocatedString(y)) => match_eq(&x.to_string(), y, ctx),
(Pattern::Interpolated(_, StringMatcher(matcher)), Value::InternedString(y)) => {
match matcher(y.to_string()) {
Some(matches) => {
let mut matches = matches
.iter()
.map(|(word, string)| {
(word, Value::AllocatedString(Rc::new(string.clone())))
(
word.clone(),
Value::AllocatedString(Rc::new(string.clone())),
)
})
.collect::<Vec<_>>();
ctx.append(&mut matches);
@ -81,14 +84,14 @@ pub fn match_pattern<'src, 'a>(
}
}
(Pattern::Word(w), val) => {
ctx.push((w, val.clone()));
ctx.push((w.to_string(), val.clone()));
Some(ctx)
}
(Pattern::As(word, type_str), value) => {
let ludus_type = r#type(value);
let type_kw = Value::Keyword(type_str);
if type_kw == ludus_type {
ctx.push((word, value.clone()));
ctx.push((word.to_string(), value.clone()));
Some(ctx)
} else {
None
@ -178,7 +181,7 @@ pub fn match_pattern<'src, 'a>(
for key in matched.iter() {
unmatched.remove(*key);
}
ctx.push((w, Value::Dict(unmatched)));
ctx.push((w.to_string(), Value::Dict(unmatched)));
}
Pattern::Placeholder => (),
_ => unreachable!(),
@ -194,8 +197,8 @@ pub fn match_pattern<'src, 'a>(
pub fn match_clauses<'src>(
value: &Value<'src>,
clauses: &'src Vec<MatchClause<'src>>,
ctx: &mut Vec<(&'src str, Value<'src>)>,
clauses: &'src Vec<MatchClause>,
ctx: &mut Vec<(String, Value<'src>)>,
) -> Result<Value<'src>, LudusError> {
let to = ctx.len();
for MatchClause { patt, body, guard } in clauses.iter() {
@ -231,7 +234,7 @@ pub fn match_clauses<'src>(
pub fn apply<'src>(
callee: Value<'src>,
caller: Value<'src>,
ctx: &mut Vec<(&'src str, Value<'src>)>,
ctx: &mut Vec<(String, Value<'src>)>,
) -> Result<Value<'src>, LudusError> {
match (callee, caller) {
(Value::Keyword(kw), Value::Dict(dict)) => {
@ -300,8 +303,8 @@ pub fn apply<'src>(
}
pub fn eval<'src, 'a>(
ast: &'src Ast<'src>,
ctx: &'a mut Vec<(&'src str, Value<'src>)>,
ast: &'src Ast,
ctx: &'a mut Vec<(String, Value<'src>)>,
) -> Result<Value<'src>, LudusError> {
match ast {
Ast::Nil => Ok(Value::Nil),
@ -435,7 +438,7 @@ pub fn eval<'src, 'a>(
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()));
ctx.push((name.to_string(), boxed.clone()));
Ok(boxed)
}
Ast::Synthetic(root, first, rest) => {
@ -464,12 +467,13 @@ pub fn eval<'src, 'a>(
match_clauses(&value, clauses, ctx)
}
Ast::Fn(name, clauses, doc) => {
let doc = doc.map(|s| s.to_string());
let the_fn = Value::Fn::<'src>(Rc::new(Fn::<'src> {
name,
name: name.to_string(),
body: clauses,
doc,
}));
ctx.push((name, the_fn.clone()));
ctx.push((name.to_string(), the_fn.clone()));
Ok(the_fn)
}
Ast::FnDeclaration(_name) => todo!(),