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> {
|
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
|
|
||||||
|
|
18
src/lexer.rs
18
src/lexer.rs
|
@ -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()))
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
118
src/parser.rs
118
src/parser.rs
|
@ -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();
|
||||||
|
|
||||||
|
|
16
src/value.rs
16
src/value.rs
|
@ -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!(),
|
||||||
|
|
36
src/vm.rs
36
src/vm.rs
|
@ -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!(),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user