finish fighting with lifetimes: string pattern matching works!
This commit is contained in:
parent
5a64c6623c
commit
6ba05f31e6
172
src/base.rs
172
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
|
||||
|
|
18
src/lexer.rs
18
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<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()))
|
||||
|
|
|
@ -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() {
|
||||
|
|
118
src/parser.rs
118
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<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();
|
||||
|
||||
|
|
16
src/value.rs
16
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<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!(),
|
||||
|
|
36
src/vm.rs
36
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::<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!(),
|
||||
|
|
Loading…
Reference in New Issue
Block a user