diff --git a/src/base.rs b/src/base.rs index 09d2fce..ddc8be4 100644 --- a/src/base.rs +++ b/src/base.rs @@ -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 diff --git a/src/lexer.rs b/src/lexer.rs index ad7a4f1..5aecf26 100644 --- a/src/lexer.rs +++ b/src/lexer.rs @@ -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>> { +pub fn lexer( +) -> impl Parser<'static, &'static str, Vec<(Token, Span)>, extra::Err>> { let number = just('-') .or_not() .then(text::int(10).then(just('.').then(text::digits(10)).or_not())) diff --git a/src/main.rs b/src/main.rs index 95ba2ba..9a5d2c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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() { diff --git a/src/parser.rs b/src/parser.rs index 7e8d0ee..8bd03fd 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -5,26 +5,26 @@ use std::fmt; use struct_scalpel::Dissectible; #[derive(Clone, Debug, PartialEq)] -pub struct WhenClause<'src> { - pub cond: Spanned>, - pub body: Spanned>, +pub struct WhenClause { + pub cond: Spanned, + pub body: Spanned, } -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>, - pub guard: Option>>, - pub body: Spanned>, +pub struct MatchClause { + pub patt: Spanned, + pub guard: Option>, + pub body: Spanned, } -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>), Block(Vec>), If(Box>, Box>, Box>), @@ -68,23 +68,23 @@ pub enum Ast<'src> { Arguments(Vec>), List(Vec>), Dict(Vec>), - Let(Box>>, Box>), - Box(&'src str, Box>), + Let(Box>, Box>), + Box(&'static str, Box>), Synthetic(Box>, Box>, Vec>), - When(Vec>>), - Match(Box>, Vec>), - Fn(&'src str, Vec>, Option<&'src str>), - FnDeclaration(&'src str), + When(Vec>), + Match(Box>, Vec), + Fn(&'static str, Vec, Option<&'static str>), + FnDeclaration(&'static str), Panic(Box>), Do(Vec>), Repeat(Box>, Box>), - Splat(&'src str), - Pair(&'src str, Box>), - Loop(Box>, Vec>), + Splat(&'static str), + Pair(&'static str, Box>), + Loop(Box>, Vec), Recur(Vec>), } -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>, +pub struct PairPattern { + pub key: &'static str, + pub patt: Spanned, } -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 Option> + 'src>); +pub struct StringMatcher(pub Box Option>>); -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>, StringMatcher<'src>), - Keyword(&'src str), - Word(&'src str), - As(&'src str, &'src str), + String(&'static str), + Interpolated(Vec>, StringMatcher), + Keyword(&'static str), + Word(&'static str), + As(&'static str, &'static str), Splattern(Box>), Placeholder, Tuple(Vec>), List(Vec>), - Pair(&'src str, Box>), + Pair(&'static str, Box>), Dict(Vec>), } -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>, String> { +fn parse_string(s: &'static str, span: SimpleSpan) -> Result>, 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>, 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>, 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) - }, - SimpleSpan::new(start, span.end), - )); + if current_part == s { + parts.push(( + StringPart::Inline(current_part), + SimpleSpan::new(start, span.end), + )) + } + Ok(parts) } -pub fn compile_string_pattern<'src>(parts: Vec>) -> StringMatcher<'src> { +pub fn compile_string_pattern(parts: Vec>) -> 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>) -> 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>) -> StringMa })) } -pub fn parser<'src, I>( -) -> impl Parser<'src, I, Spanned>, extra::Err, Span>>> + Clone +pub fn parser( +) -> impl Parser<'static, I, Spanned, extra::Err>> + Clone where - I: ValueInput<'src, Token = Token<'src>, Span = Span>, + I: ValueInput<'static, Token = Token, Span = Span>, { let mut expr = Recursive::declare(); diff --git a/src/value.rs b/src/value.rs index e8dea85..900b8c6 100644 --- a/src/value.rs +++ b/src/value.rs @@ -8,9 +8,9 @@ use struct_scalpel::Dissectible; #[derive(Clone, Debug)] pub struct Fn<'src> { - pub name: &'src str, - pub body: &'src Vec>, - pub doc: &'src Option<&'src str>, + pub name: String, + pub body: &'src Vec, + pub doc: Option, } #[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), // on the heap for now Tuple(Rc>), @@ -31,8 +31,8 @@ pub enum Value<'src> { List(Vector), // ref-counted, immutable, persistent // dicts may only use keywords as keys - Dict(HashMap<&'src str, Self>), - Box(&'src str, Rc>), + Dict(HashMap<&'static str, Self>), + Box(&'static str, Rc>), Fn(Rc>), Base(Base<'src>), Recur(Vec), @@ -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!(), diff --git a/src/vm.rs b/src/vm.rs index d668938..207e688 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -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::>(); 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>, - ctx: &mut Vec<(&'src str, Value<'src>)>, + clauses: &'src Vec, + ctx: &mut Vec<(String, Value<'src>)>, ) -> Result, 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, 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, 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!(),