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> { pub fn doc<'src>(f: &Value<'src>) -> Value<'src> {
match f { match f {
Value::Fn(f) => { Value::Fn(f) => {
let Fn { name, doc, .. } = **f; let name = &f.name;
let doc = &f.doc;
if let Some(docstr) = doc { if let Some(docstr) = doc {
Value::AllocatedString(Rc::new(format!("{name}: {docstr}"))) Value::AllocatedString(Rc::new(format!("{name}: {docstr}")))
} else { } else {
Value::InternedString(doc.unwrap_or("no documentation found")) Value::AllocatedString(Rc::new(format!("{name}: no documentation found")))
} }
} }
_ => Value::InternedString("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![ vec![
("add", Value::Base(Base::Binary(add))), ("add".to_string(), Value::Base(Base::Binary(add))),
("and", Value::Base(Base::Binary(and))), ("and".to_string(), Value::Base(Base::Binary(and))),
("append", Value::Base(Base::Binary(append))), ("append".to_string(), Value::Base(Base::Binary(append))),
("assoc", Value::Base(Base::Ternary(assoc))), ("assoc".to_string(), Value::Base(Base::Ternary(assoc))),
("at", Value::Base(Base::Binary(at))), ("at".to_string(), Value::Base(Base::Binary(at))),
("atan_2", Value::Base(Base::Binary(atan_2))), ("atan_2".to_string(), Value::Base(Base::Binary(atan_2))),
("bool", Value::Base(Base::Unary(r#bool))), ("bool".to_string(), Value::Base(Base::Unary(r#bool))),
("ceil", Value::Base(Base::Unary(ceil))), ("ceil".to_string(), Value::Base(Base::Unary(ceil))),
("chars", Value::Base(Base::Unary(chars))), ("chars".to_string(), Value::Base(Base::Unary(chars))),
("concat", Value::Base(Base::Binary(concat))), ("concat".to_string(), Value::Base(Base::Binary(concat))),
("cos", Value::Base(Base::Unary(cos))), ("cos".to_string(), Value::Base(Base::Unary(cos))),
("count", Value::Base(Base::Unary(count))), ("count".to_string(), Value::Base(Base::Unary(count))),
("dec", Value::Base(Base::Unary(dec))), ("dec".to_string(), Value::Base(Base::Unary(dec))),
("dissoc", Value::Base(Base::Binary(dissoc))), ("dissoc".to_string(), Value::Base(Base::Binary(dissoc))),
("div", Value::Base(Base::Binary(div))), ("div".to_string(), Value::Base(Base::Binary(div))),
("doc!", Value::Base(Base::Unary(doc))), ("doc!".to_string(), Value::Base(Base::Unary(doc))),
("downcase", Value::Base(Base::Unary(downcase))), ("downcase".to_string(), Value::Base(Base::Unary(downcase))),
("eq?", Value::Base(Base::Binary(eq))), ("eq?".to_string(), Value::Base(Base::Binary(eq))),
("first", Value::Base(Base::Unary(first))), ("first".to_string(), Value::Base(Base::Unary(first))),
("floor", Value::Base(Base::Unary(floor))), ("floor".to_string(), Value::Base(Base::Unary(floor))),
("get", Value::Base(Base::Binary(get))), ("get".to_string(), Value::Base(Base::Binary(get))),
("gt?", Value::Base(Base::Binary(gt))), ("gt?".to_string(), Value::Base(Base::Binary(gt))),
("gte?", Value::Base(Base::Binary(gte))), ("gte?".to_string(), Value::Base(Base::Binary(gte))),
("inc", Value::Base(Base::Unary(inc))), ("inc".to_string(), Value::Base(Base::Unary(inc))),
("last", Value::Base(Base::Unary(last))), ("last".to_string(), Value::Base(Base::Unary(last))),
("list", Value::Base(Base::Unary(list))), ("list".to_string(), Value::Base(Base::Unary(list))),
("lt?", Value::Base(Base::Binary(lt))), ("lt?".to_string(), Value::Base(Base::Binary(lt))),
("lte?", Value::Base(Base::Binary(lte))), ("lte?".to_string(), Value::Base(Base::Binary(lte))),
("mod", Value::Base(Base::Binary(r#mod))), ("mod".to_string(), Value::Base(Base::Binary(r#mod))),
("mult", Value::Base(Base::Binary(mult))), ("mult".to_string(), Value::Base(Base::Binary(mult))),
("number", Value::Base(Base::Unary(number))), ("number".to_string(), Value::Base(Base::Unary(number))),
("or", Value::Base(Base::Binary(or))), ("or".to_string(), Value::Base(Base::Binary(or))),
("pi", Value::Number(std::f64::consts::PI)), ("pi".to_string(), Value::Number(std::f64::consts::PI)),
("print!", Value::Base(Base::Unary(print))), ("print!".to_string(), Value::Base(Base::Unary(print))),
("random", Value::Base(Base::Nullary(random))), ("random".to_string(), Value::Base(Base::Nullary(random))),
("range", Value::Base(Base::Binary(range))), ("range".to_string(), Value::Base(Base::Binary(range))),
("rest", Value::Base(Base::Unary(rest))), ("rest".to_string(), Value::Base(Base::Unary(rest))),
("round", Value::Base(Base::Unary(round))), ("round".to_string(), Value::Base(Base::Unary(round))),
("show", Value::Base(Base::Unary(show))), ("show".to_string(), Value::Base(Base::Unary(show))),
("sin", Value::Base(Base::Unary(sin))), ("sin".to_string(), Value::Base(Base::Unary(sin))),
("slice", Value::Base(Base::Ternary(slice))), ("slice".to_string(), Value::Base(Base::Ternary(slice))),
("split", Value::Base(Base::Binary(split))), ("split".to_string(), Value::Base(Base::Binary(split))),
("sqrt", Value::Base(Base::Unary(sqrt))), ("sqrt".to_string(), Value::Base(Base::Unary(sqrt))),
("sqrt_2", Value::Number(std::f64::consts::SQRT_2)), (
("store!", Value::Base(Base::Binary(store))), "sqrt_2".to_string(),
("sub", Value::Base(Base::Binary(sub))), Value::Number(std::f64::consts::SQRT_2),
("tan", Value::Base(Base::Unary(tan))), ),
("trim", Value::Base(Base::Unary(trim))), ("store!".to_string(), Value::Base(Base::Binary(store))),
("triml", Value::Base(Base::Unary(triml))), ("sub".to_string(), Value::Base(Base::Binary(sub))),
("trimr", Value::Base(Base::Unary(trimr))), ("tan".to_string(), Value::Base(Base::Unary(tan))),
("type", Value::Base(Base::Unary(r#type))), ("trim".to_string(), Value::Base(Base::Unary(trim))),
("unbox", Value::Base(Base::Unary(unbox))), ("triml".to_string(), Value::Base(Base::Unary(triml))),
("upcase", Value::Base(Base::Unary(upcase))), ("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; use std::fmt;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum Token<'src> { pub enum Token {
Nil, Nil,
Number(f64), Number(f64),
Word(&'src str), Word(&'static str),
Boolean(bool), Boolean(bool),
Keyword(&'src str), Keyword(&'static str),
String(&'src str), String(&'static str),
// todo: hard code these types // todo: hard code these types
Reserved(&'src str), Reserved(&'static str),
Punctuation(&'src str), Punctuation(&'static str),
} }
impl fmt::Display for Token<'_> { impl fmt::Display for Token {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Token::Number(n) => write!(f, "[Number {}]", n), Token::Number(n) => write!(f, "[Number {}]", n),
@ -30,8 +30,8 @@ impl fmt::Display for Token<'_> {
} }
} }
pub fn lexer<'src>( pub fn lexer(
) -> impl Parser<'src, &'src str, Vec<(Token<'src>, Span)>, extra::Err<Rich<'src, char, Span>>> { ) -> impl Parser<'static, &'static str, Vec<(Token, Span)>, extra::Err<Rich<'static, char, Span>>> {
let number = just('-') let number = just('-')
.or_not() .or_not()
.then(text::int(10).then(just('.').then(text::digits(10)).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() { pub fn main() {
let src = " 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(); let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
if !lex_errs.is_empty() { if !lex_errs.is_empty() {

View File

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

View File

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

View File

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