2024-10-31 20:59:26 +00:00
|
|
|
use crate::lexer::*;
|
|
|
|
use crate::spans::*;
|
|
|
|
use chumsky::{input::ValueInput, prelude::*, recursive::Recursive};
|
|
|
|
use std::fmt;
|
2024-11-21 23:50:13 +00:00
|
|
|
use struct_scalpel::Dissectible;
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-12-10 23:40:43 +00:00
|
|
|
// #[derive(Clone, Debug, PartialEq)]
|
|
|
|
// pub struct WhenClause {
|
|
|
|
// pub cond: Spanned<Ast>,
|
|
|
|
// pub body: Spanned<Ast>,
|
|
|
|
// }
|
|
|
|
|
|
|
|
// 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 {
|
|
|
|
// pub patt: Spanned<Pattern>,
|
|
|
|
// pub guard: Option<Spanned<Ast>>,
|
|
|
|
// pub body: Spanned<Ast>,
|
|
|
|
// }
|
|
|
|
|
|
|
|
// impl fmt::Display for MatchClause {
|
|
|
|
// fn fmt(self: &MatchClause, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
// write!(
|
|
|
|
// f,
|
|
|
|
// "pattern: {}, guard: {:?} body: {}",
|
|
|
|
// self.patt.0, self.guard, self.body.0
|
|
|
|
// )
|
|
|
|
// }
|
|
|
|
// }
|
2024-11-09 19:10:08 +00:00
|
|
|
|
2024-12-04 20:03:09 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
2024-12-04 23:30:03 +00:00
|
|
|
pub enum StringPart {
|
|
|
|
Data(String),
|
|
|
|
Word(String),
|
|
|
|
Inline(String),
|
2024-12-04 20:03:09 +00:00
|
|
|
}
|
|
|
|
|
2024-12-04 23:30:03 +00:00
|
|
|
impl fmt::Display for StringPart {
|
|
|
|
fn fmt(self: &StringPart, f: &mut fmt::Formatter) -> fmt::Result {
|
2024-12-04 20:03:09 +00:00
|
|
|
let rep = match self {
|
2024-12-04 23:30:03 +00:00
|
|
|
StringPart::Word(s) => format!("{{{s}}}"),
|
|
|
|
StringPart::Data(s) => s.to_string(),
|
|
|
|
StringPart::Inline(s) => s.to_string(),
|
2024-12-04 20:03:09 +00:00
|
|
|
};
|
|
|
|
write!(f, "{}", rep)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-21 23:50:13 +00:00
|
|
|
#[derive(Clone, Debug, PartialEq, Dissectible)]
|
2024-12-08 04:56:19 +00:00
|
|
|
pub enum Ast {
|
2024-12-10 23:40:43 +00:00
|
|
|
// a special Error node
|
|
|
|
// may come in handy?
|
2024-10-31 20:59:26 +00:00
|
|
|
Error,
|
2024-12-10 23:40:43 +00:00
|
|
|
|
|
|
|
// expression nodes
|
2024-10-31 20:59:26 +00:00
|
|
|
Placeholder,
|
2024-11-01 03:53:48 +00:00
|
|
|
Nil,
|
|
|
|
Boolean(bool),
|
|
|
|
Number(f64),
|
2024-12-08 04:56:19 +00:00
|
|
|
Keyword(&'static str),
|
|
|
|
Word(&'static str),
|
|
|
|
String(&'static str),
|
2024-12-04 23:30:03 +00:00
|
|
|
Interpolated(Vec<Spanned<StringPart>>),
|
2024-10-31 20:59:26 +00:00
|
|
|
Block(Vec<Spanned<Self>>),
|
|
|
|
If(Box<Spanned<Self>>, Box<Spanned<Self>>, Box<Spanned<Self>>),
|
|
|
|
Tuple(Vec<Spanned<Self>>),
|
|
|
|
Arguments(Vec<Spanned<Self>>),
|
|
|
|
List(Vec<Spanned<Self>>),
|
2024-11-21 21:41:46 +00:00
|
|
|
Dict(Vec<Spanned<Self>>),
|
2024-12-10 23:40:43 +00:00
|
|
|
Let(Box<Spanned<Self>>, Box<Spanned<Self>>),
|
|
|
|
LBox(&'static str, Box<Spanned<Self>>),
|
2024-10-31 20:59:26 +00:00
|
|
|
Synthetic(Box<Spanned<Self>>, Box<Spanned<Self>>, Vec<Spanned<Self>>),
|
2024-12-10 23:40:43 +00:00
|
|
|
When(Vec<Spanned<Self>>),
|
|
|
|
WhenClause(Box<Spanned<Self>>, Box<Spanned<Self>>),
|
|
|
|
Match(Box<Spanned<Self>>, Vec<Spanned<Self>>),
|
|
|
|
MatchClause(
|
|
|
|
Box<Spanned<Self>>,
|
|
|
|
Box<Option<Spanned<Self>>>,
|
|
|
|
Box<Spanned<Self>>,
|
|
|
|
),
|
|
|
|
Fn(&'static str, Vec<Spanned<Self>>, Option<&'static str>),
|
2024-12-08 04:56:19 +00:00
|
|
|
FnDeclaration(&'static str),
|
2024-10-31 20:59:26 +00:00
|
|
|
Panic(Box<Spanned<Self>>),
|
|
|
|
Do(Vec<Spanned<Self>>),
|
|
|
|
Repeat(Box<Spanned<Self>>, Box<Spanned<Self>>),
|
2024-12-08 04:56:19 +00:00
|
|
|
Splat(&'static str),
|
|
|
|
Pair(&'static str, Box<Spanned<Self>>),
|
2024-12-10 23:40:43 +00:00
|
|
|
Loop(Box<Spanned<Self>>, Vec<Spanned<Self>>),
|
2024-11-21 21:41:46 +00:00
|
|
|
Recur(Vec<Spanned<Self>>),
|
2024-12-10 23:40:43 +00:00
|
|
|
|
|
|
|
// pattern nodes
|
|
|
|
NilPattern,
|
|
|
|
BooleanPattern(bool),
|
|
|
|
NumberPattern(f64),
|
|
|
|
StringPattern(&'static str),
|
|
|
|
InterpolatedPattern(Vec<Spanned<StringPart>>, StringMatcher),
|
|
|
|
KeywordPattern(&'static str),
|
|
|
|
WordPattern(&'static str),
|
|
|
|
AsPattern(&'static str, &'static str),
|
|
|
|
Splattern(Box<Spanned<Self>>),
|
|
|
|
PlaceholderPattern,
|
|
|
|
TuplePattern(Vec<Spanned<Self>>),
|
|
|
|
ListPattern(Vec<Spanned<Self>>),
|
|
|
|
PairPattern(&'static str, Box<Spanned<Self>>),
|
|
|
|
DictPattern(Vec<Spanned<Self>>),
|
2024-10-31 20:59:26 +00:00
|
|
|
}
|
|
|
|
|
2024-12-08 04:56:19 +00:00
|
|
|
impl fmt::Display for Ast {
|
2024-10-31 20:59:26 +00:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
2024-12-10 23:40:43 +00:00
|
|
|
use Ast::*;
|
2024-10-31 20:59:26 +00:00
|
|
|
match self {
|
2024-12-10 23:40:43 +00:00
|
|
|
Error => write!(f, "Error"),
|
|
|
|
Nil => write!(f, "nil"),
|
|
|
|
String(s) => write!(f, "String: \"{}\"", s),
|
|
|
|
Interpolated(strs) => {
|
2024-12-04 20:03:09 +00:00
|
|
|
write!(
|
|
|
|
f,
|
2024-12-04 23:30:03 +00:00
|
|
|
"Interpolated: \"{}\"",
|
2024-12-04 20:03:09 +00:00
|
|
|
strs.iter()
|
|
|
|
.map(|(s, _)| s.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("")
|
|
|
|
)
|
|
|
|
}
|
2024-12-10 23:40:43 +00:00
|
|
|
Boolean(b) => write!(f, "Boolean: {}", b),
|
|
|
|
Number(n) => write!(f, "Number: {}", n),
|
|
|
|
Keyword(k) => write!(f, "Keyword: :{}", k),
|
|
|
|
Word(w) => write!(f, "Word: {}", w),
|
|
|
|
Block(b) => write!(
|
2024-10-31 20:59:26 +00:00
|
|
|
f,
|
|
|
|
"Block: <{}>",
|
|
|
|
b.iter()
|
|
|
|
.map(|(line, _)| line.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("\n")
|
|
|
|
),
|
2024-12-10 23:40:43 +00:00
|
|
|
If(cond, then_branch, else_branch) => write!(
|
2024-10-31 20:59:26 +00:00
|
|
|
f,
|
|
|
|
"If: {} Then: {} Else: {}",
|
|
|
|
cond.0, then_branch.0, else_branch.0
|
|
|
|
),
|
2024-12-10 23:40:43 +00:00
|
|
|
Let(pattern, expression) => {
|
2024-10-31 20:59:26 +00:00
|
|
|
write!(f, "Let: {} = {}", pattern.0, expression.0)
|
|
|
|
}
|
2024-12-10 23:40:43 +00:00
|
|
|
Dict(entries) => write!(
|
2024-10-31 20:59:26 +00:00
|
|
|
f,
|
|
|
|
"#{{{}}}",
|
|
|
|
entries
|
|
|
|
.iter()
|
2024-11-22 00:54:50 +00:00
|
|
|
.map(|pair| pair.0.to_string())
|
2024-10-31 20:59:26 +00:00
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(", ")
|
|
|
|
),
|
2024-12-10 23:40:43 +00:00
|
|
|
List(l) => write!(
|
2024-10-31 20:59:26 +00:00
|
|
|
f,
|
|
|
|
"List: [{}]",
|
|
|
|
l.iter()
|
|
|
|
.map(|(line, _)| line.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("\n")
|
|
|
|
),
|
2024-12-10 23:40:43 +00:00
|
|
|
Tuple(t) | Ast::Arguments(t) => write!(
|
2024-10-31 20:59:26 +00:00
|
|
|
f,
|
|
|
|
"Tuple: ({})",
|
|
|
|
t.iter()
|
|
|
|
.map(|(line, _)| line.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("\n")
|
|
|
|
),
|
2024-12-10 23:40:43 +00:00
|
|
|
Synthetic(root, first, rest) => write!(
|
2024-10-31 20:59:26 +00:00
|
|
|
f,
|
|
|
|
"Synth: [{}, {}, {}]",
|
|
|
|
root.0,
|
|
|
|
first.0,
|
|
|
|
rest.iter()
|
|
|
|
.map(|(term, _)| term.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("\n")
|
|
|
|
),
|
2024-12-10 23:40:43 +00:00
|
|
|
When(clauses) => write!(
|
2024-11-09 19:10:08 +00:00
|
|
|
f,
|
|
|
|
"When: [{}]",
|
|
|
|
clauses
|
|
|
|
.iter()
|
|
|
|
.map(|clause| clause.0.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("\n")
|
|
|
|
),
|
2024-12-10 23:40:43 +00:00
|
|
|
Placeholder => todo!(),
|
|
|
|
LBox(_name, _rhs) => todo!(),
|
|
|
|
Match(value, clauses) => {
|
2024-11-11 01:12:19 +00:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"match: {} with {}",
|
|
|
|
&value.0.to_string(),
|
|
|
|
clauses
|
|
|
|
.iter()
|
2024-12-10 23:40:43 +00:00
|
|
|
.map(|clause| clause.0.to_string())
|
2024-11-11 01:12:19 +00:00
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("\n")
|
|
|
|
)
|
|
|
|
}
|
2024-12-10 23:40:43 +00:00
|
|
|
Fn(name, clauses, _) => {
|
2024-11-11 01:12:19 +00:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"fn: {}\n{}",
|
|
|
|
name,
|
|
|
|
clauses
|
|
|
|
.iter()
|
2024-12-10 23:40:43 +00:00
|
|
|
.map(|clause| clause.0.to_string())
|
2024-11-11 01:12:19 +00:00
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("\n")
|
|
|
|
)
|
|
|
|
}
|
2024-12-10 23:40:43 +00:00
|
|
|
FnDeclaration(_name) => todo!(),
|
|
|
|
Panic(_expr) => todo!(),
|
|
|
|
Do(terms) => {
|
2024-11-11 22:50:58 +00:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"do: {}",
|
|
|
|
terms
|
|
|
|
.iter()
|
|
|
|
.map(|(term, _)| term.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(" > ")
|
|
|
|
)
|
|
|
|
}
|
2024-12-10 23:40:43 +00:00
|
|
|
Repeat(_times, _body) => todo!(),
|
|
|
|
Splat(word) => {
|
2024-11-21 21:41:46 +00:00
|
|
|
write!(f, "splat: {}", word)
|
|
|
|
}
|
2024-12-10 23:40:43 +00:00
|
|
|
Pair(k, v) => {
|
2024-11-22 00:54:50 +00:00
|
|
|
write!(f, "pair: {} {}", k, v.0)
|
2024-11-21 21:41:46 +00:00
|
|
|
}
|
2024-12-10 23:40:43 +00:00
|
|
|
Loop(init, body) => {
|
2024-11-21 21:41:46 +00:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"loop: {} with {}",
|
2024-11-22 00:54:50 +00:00
|
|
|
init.0,
|
2024-11-21 21:41:46 +00:00
|
|
|
body.iter()
|
2024-12-10 23:40:43 +00:00
|
|
|
.map(|clause| clause.0.to_string())
|
2024-11-21 21:41:46 +00:00
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("\n")
|
|
|
|
)
|
|
|
|
}
|
2024-12-10 23:40:43 +00:00
|
|
|
Recur(args) => {
|
2024-11-21 21:41:46 +00:00
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"recur: {}",
|
|
|
|
args.iter()
|
|
|
|
.map(|(arg, _)| arg.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(", ")
|
|
|
|
)
|
|
|
|
}
|
2024-12-10 23:40:43 +00:00
|
|
|
MatchClause(pattern, guard, body) => {
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"match clause: {} if {:?} -> {}",
|
|
|
|
pattern.0, guard, body.0
|
|
|
|
)
|
|
|
|
}
|
|
|
|
WhenClause(cond, body) => {
|
|
|
|
write!(f, "when clause: {} -> {}", cond.0, body.0)
|
|
|
|
}
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-12-10 23:40:43 +00:00
|
|
|
NilPattern => write!(f, "nil"),
|
|
|
|
BooleanPattern(b) => write!(f, "{}", b),
|
|
|
|
NumberPattern(n) => write!(f, "{}", n),
|
|
|
|
StringPattern(s) => write!(f, "{}", s),
|
|
|
|
KeywordPattern(k) => write!(f, ":{}", k),
|
|
|
|
WordPattern(w) => write!(f, "{}", w),
|
|
|
|
AsPattern(w, t) => write!(f, "{} as {}", w, t),
|
|
|
|
Splattern(p) => write!(f, "...{}", p.0),
|
|
|
|
PlaceholderPattern => write!(f, "_"),
|
|
|
|
TuplePattern(t) => write!(
|
2024-10-31 20:59:26 +00:00
|
|
|
f,
|
|
|
|
"({})",
|
|
|
|
t.iter()
|
|
|
|
.map(|x| x.0.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(", ")
|
|
|
|
),
|
2024-12-10 23:40:43 +00:00
|
|
|
ListPattern(l) => write!(
|
2024-10-31 20:59:26 +00:00
|
|
|
f,
|
|
|
|
"({})",
|
|
|
|
l.iter()
|
|
|
|
.map(|x| x.0.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(", ")
|
|
|
|
),
|
2024-12-10 23:40:43 +00:00
|
|
|
DictPattern(entries) => write!(
|
2024-10-31 20:59:26 +00:00
|
|
|
f,
|
|
|
|
"#{{{}}}",
|
|
|
|
entries
|
|
|
|
.iter()
|
|
|
|
.map(|(pair, _)| pair.to_string())
|
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join(", ")
|
|
|
|
),
|
2024-12-10 23:40:43 +00:00
|
|
|
PairPattern(key, value) => write!(f, ":{} {}", key, value.0),
|
|
|
|
InterpolatedPattern(strprts, _) => write!(
|
2024-12-04 23:30:03 +00:00
|
|
|
f,
|
2024-12-07 23:26:25 +00:00
|
|
|
"interpolated: \"{}\"",
|
2024-12-04 23:30:03 +00:00
|
|
|
strprts
|
|
|
|
.iter()
|
2024-12-07 23:26:25 +00:00
|
|
|
.map(|part| part.0.to_string())
|
2024-12-04 23:30:03 +00:00
|
|
|
.collect::<Vec<_>>()
|
|
|
|
.join("")
|
|
|
|
),
|
2024-10-31 20:59:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-10 23:40:43 +00:00
|
|
|
pub struct StringMatcher(pub Box<dyn Fn(String) -> Option<Vec<(String, String)>>>);
|
|
|
|
|
|
|
|
impl PartialEq for StringMatcher {
|
|
|
|
fn eq(&self, _other: &StringMatcher) -> bool {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Clone for StringMatcher {
|
|
|
|
fn clone(&self) -> StringMatcher {
|
|
|
|
unreachable!()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for StringMatcher {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
write!(f, "string matcher")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
|
|
|
// Nil,
|
|
|
|
// Boolean(bool),
|
|
|
|
// Number(f64),
|
|
|
|
// 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(&'static str, Box<Spanned<Self>>),
|
|
|
|
// Dict(Vec<Spanned<Self>>),
|
|
|
|
// }
|
|
|
|
|
|
|
|
// impl fmt::Display for Pattern {
|
|
|
|
// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
|
// match self {
|
|
|
|
// Pattern::Nil => write!(f, "nil"),
|
|
|
|
// Pattern::Boolean(b) => write!(f, "{}", b),
|
|
|
|
// Pattern::Number(n) => write!(f, "{}", n),
|
|
|
|
// Pattern::String(s) => write!(f, "{}", s),
|
|
|
|
// Pattern::Keyword(k) => write!(f, ":{}", k),
|
|
|
|
// Pattern::Word(w) => write!(f, "{}", w),
|
|
|
|
// Pattern::As(w, t) => write!(f, "{} as {}", w, t),
|
|
|
|
// Pattern::Splattern(p) => write!(f, "...{}", p.0),
|
|
|
|
// Pattern::Placeholder => write!(f, "_"),
|
|
|
|
// Pattern::Tuple(t) => write!(
|
|
|
|
// f,
|
|
|
|
// "({})",
|
|
|
|
// t.iter()
|
|
|
|
// .map(|x| x.0.to_string())
|
|
|
|
// .collect::<Vec<_>>()
|
|
|
|
// .join(", ")
|
|
|
|
// ),
|
|
|
|
// Pattern::List(l) => write!(
|
|
|
|
// f,
|
|
|
|
// "({})",
|
|
|
|
// l.iter()
|
|
|
|
// .map(|x| x.0.to_string())
|
|
|
|
// .collect::<Vec<_>>()
|
|
|
|
// .join(", ")
|
|
|
|
// ),
|
|
|
|
// Pattern::Dict(entries) => write!(
|
|
|
|
// f,
|
|
|
|
// "#{{{}}}",
|
|
|
|
// entries
|
|
|
|
// .iter()
|
|
|
|
// .map(|(pair, _)| pair.to_string())
|
|
|
|
// .collect::<Vec<_>>()
|
|
|
|
// .join(", ")
|
|
|
|
// ),
|
|
|
|
// Pattern::Pair(key, value) => write!(f, ":{} {}", key, value.0),
|
|
|
|
// Pattern::Interpolated(strprts, _) => write!(
|
|
|
|
// f,
|
|
|
|
// "interpolated: \"{}\"",
|
|
|
|
// strprts
|
|
|
|
// .iter()
|
|
|
|
// .map(|part| part.0.to_string())
|
|
|
|
// .collect::<Vec<_>>()
|
|
|
|
// .join("")
|
|
|
|
// ),
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
2024-12-04 23:30:03 +00:00
|
|
|
fn is_word_char(c: char) -> bool {
|
|
|
|
if c.is_ascii_alphanumeric() {
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
matches!(c, '_' | '/' | '?' | '!')
|
|
|
|
}
|
|
|
|
|
2024-12-08 04:56:19 +00:00
|
|
|
fn parse_string(s: &'static str, span: SimpleSpan) -> Result<Vec<Spanned<StringPart>>, String> {
|
2024-12-04 23:30:03 +00:00
|
|
|
let mut parts = vec![];
|
|
|
|
let mut current_part = String::new();
|
|
|
|
let mut start = span.start;
|
|
|
|
let mut is_word = false;
|
|
|
|
|
|
|
|
let mut chars = s.char_indices();
|
|
|
|
while let Some((i, char)) = chars.next() {
|
|
|
|
match char {
|
|
|
|
'{' => {
|
|
|
|
if is_word {
|
|
|
|
return Err("interpolations must only contain words".to_string());
|
|
|
|
};
|
|
|
|
match chars.next() {
|
|
|
|
None => return Err("unclosed brace".to_string()),
|
|
|
|
Some((_, '{')) => current_part.push('{'),
|
|
|
|
Some((i, c)) => {
|
|
|
|
if !current_part.is_empty() {
|
|
|
|
parts.push((
|
|
|
|
StringPart::Data(current_part),
|
|
|
|
SimpleSpan::new(start, start + i),
|
|
|
|
));
|
|
|
|
};
|
|
|
|
current_part = String::new();
|
|
|
|
start = i;
|
|
|
|
is_word = true;
|
|
|
|
if c.is_ascii_lowercase() {
|
|
|
|
current_part.push(c);
|
|
|
|
} else {
|
|
|
|
return Err("interpolations must only contain words".to_string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
'}' => {
|
|
|
|
if is_word {
|
|
|
|
parts.push((
|
2024-12-08 04:56:19 +00:00
|
|
|
StringPart::Word(current_part.clone()),
|
2024-12-04 23:30:03 +00:00
|
|
|
SimpleSpan::new(start, start + i),
|
|
|
|
));
|
|
|
|
current_part = String::new();
|
|
|
|
start = i;
|
|
|
|
is_word = false;
|
|
|
|
} else {
|
|
|
|
match chars.next() {
|
|
|
|
None => return Err("unclosed brace".to_string()),
|
|
|
|
Some((_, c)) => current_part.push(c),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
if is_word {
|
|
|
|
if is_word_char(char) {
|
|
|
|
current_part.push(char)
|
|
|
|
} else {
|
|
|
|
return Err("interpolations must only contain words".to_string());
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
current_part.push(char)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-08 04:56:19 +00:00
|
|
|
if current_part == s {
|
|
|
|
parts.push((
|
|
|
|
StringPart::Inline(current_part),
|
|
|
|
SimpleSpan::new(start, span.end),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
2024-12-04 23:30:03 +00:00
|
|
|
Ok(parts)
|
2024-12-04 20:03:09 +00:00
|
|
|
}
|
|
|
|
|
2024-12-08 04:56:19 +00:00
|
|
|
pub fn compile_string_pattern(parts: Vec<Spanned<StringPart>>) -> StringMatcher {
|
2024-12-07 23:26:25 +00:00
|
|
|
StringMatcher(Box::new(move |scrutinee| {
|
|
|
|
let mut last_match = 0;
|
|
|
|
let mut parts_iter = parts.iter();
|
|
|
|
let mut matches = vec![];
|
|
|
|
while let Some((part, _)) = parts_iter.next() {
|
|
|
|
match part {
|
|
|
|
StringPart::Data(string) => match scrutinee.find(string.as_str()) {
|
|
|
|
Some(i) => {
|
|
|
|
// if i = 0, we're at the beginning
|
|
|
|
if i == 0 && last_match == 0 {
|
|
|
|
last_match = i + string.len();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// in theory, we only hit this branch if the first part is Data
|
|
|
|
unreachable!("internal Ludus error: bad string pattern")
|
|
|
|
}
|
|
|
|
None => return None,
|
|
|
|
},
|
|
|
|
StringPart::Word(word) => {
|
|
|
|
let to_test = scrutinee.get(last_match..scrutinee.len()).unwrap();
|
|
|
|
match parts_iter.next() {
|
|
|
|
None => matches.push((word.clone(), to_test.to_string())),
|
|
|
|
Some(part) => {
|
|
|
|
let (StringPart::Data(part), _) = part else {
|
|
|
|
unreachable!("internal Ludus error: bad string pattern")
|
|
|
|
};
|
|
|
|
match to_test.find(part) {
|
|
|
|
None => return None,
|
|
|
|
Some(i) => {
|
2024-12-08 04:56:19 +00:00
|
|
|
matches.push((
|
|
|
|
word.clone(),
|
|
|
|
to_test.get(last_match..i).unwrap().to_string(),
|
|
|
|
));
|
2024-12-07 23:26:25 +00:00
|
|
|
last_match = i + part.len();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => unreachable!("internal Ludus error"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some(matches)
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2024-12-08 04:56:19 +00:00
|
|
|
pub fn parser<I>(
|
|
|
|
) -> impl Parser<'static, I, Spanned<Ast>, extra::Err<Rich<'static, Token, Span>>> + Clone
|
2024-10-31 20:59:26 +00:00
|
|
|
where
|
2024-12-08 04:56:19 +00:00
|
|
|
I: ValueInput<'static, Token = Token, Span = Span>,
|
2024-10-31 20:59:26 +00:00
|
|
|
{
|
2024-12-10 23:40:43 +00:00
|
|
|
use Ast::*;
|
|
|
|
|
2024-10-31 20:59:26 +00:00
|
|
|
let mut expr = Recursive::declare();
|
|
|
|
|
|
|
|
let mut pattern = Recursive::declare();
|
|
|
|
|
|
|
|
let mut simple = Recursive::declare();
|
|
|
|
|
|
|
|
let mut nonbinding = Recursive::declare();
|
|
|
|
|
|
|
|
let separators = recursive(|separators| {
|
|
|
|
just(Token::Punctuation(","))
|
|
|
|
.or(just(Token::Punctuation("\n")))
|
|
|
|
.then(separators.clone().repeated())
|
|
|
|
});
|
|
|
|
|
|
|
|
let terminators = recursive(|terminators| {
|
|
|
|
just(Token::Punctuation(";"))
|
|
|
|
.or(just(Token::Punctuation("\n")))
|
|
|
|
.then(terminators.clone().repeated())
|
|
|
|
});
|
|
|
|
|
|
|
|
let placeholder_pattern =
|
2024-12-10 23:40:43 +00:00
|
|
|
select! {Token::Punctuation("_") => PlaceholderPattern}.map_with(|p, e| (p, e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-12-10 23:40:43 +00:00
|
|
|
let word_pattern = select! { Token::Word(w) => WordPattern(w) }.map_with(|w, e| (w, e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
|
|
|
let atom_pattern = select! {
|
2024-12-10 23:40:43 +00:00
|
|
|
Token::Nil => NilPattern,
|
|
|
|
Token::Boolean(b) => BooleanPattern(b),
|
|
|
|
Token::Number(n) => NumberPattern(n),
|
|
|
|
Token::Keyword(k) => KeywordPattern(k),
|
2024-10-31 20:59:26 +00:00
|
|
|
}
|
|
|
|
.map_with(|a, e| (a, e.span()));
|
|
|
|
|
2024-12-07 23:26:25 +00:00
|
|
|
let string_pattern = select! {Token::String(s) => s}.try_map_with(|s, e| {
|
|
|
|
let parsed = parse_string(s, e.span());
|
|
|
|
match parsed {
|
|
|
|
Ok(parts) => match parts[0] {
|
2024-12-10 23:40:43 +00:00
|
|
|
(StringPart::Inline(_), _) => Ok((StringPattern(s), e.span())),
|
2024-12-07 23:26:25 +00:00
|
|
|
_ => Ok((
|
2024-12-10 23:40:43 +00:00
|
|
|
InterpolatedPattern(parts.clone(), compile_string_pattern(parts)),
|
2024-12-07 23:26:25 +00:00
|
|
|
e.span(),
|
|
|
|
)),
|
|
|
|
},
|
|
|
|
Err(msg) => Err(Rich::custom(e.span(), msg)),
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-11-18 18:25:54 +00:00
|
|
|
let bare_splat = just(Token::Punctuation("...")).map_with(|_, e| {
|
|
|
|
(
|
2024-12-10 23:40:43 +00:00
|
|
|
Splattern(Box::new((PlaceholderPattern, e.span()))),
|
2024-11-18 18:25:54 +00:00
|
|
|
e.span(),
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
2024-11-22 00:54:50 +00:00
|
|
|
let splattable = word_pattern.or(placeholder_pattern);
|
2024-11-18 18:25:54 +00:00
|
|
|
|
|
|
|
let patt_splat = just(Token::Punctuation("..."))
|
|
|
|
.ignore_then(splattable)
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|x, e| (Splattern(Box::new(x)), e.span()));
|
2024-11-18 18:25:54 +00:00
|
|
|
|
|
|
|
let splattern = patt_splat.or(bare_splat);
|
|
|
|
|
2024-10-31 20:59:26 +00:00
|
|
|
let tuple_pattern = pattern
|
|
|
|
.clone()
|
2024-11-18 18:25:54 +00:00
|
|
|
.or(splattern.clone())
|
2024-10-31 20:59:26 +00:00
|
|
|
.separated_by(separators.clone())
|
|
|
|
.allow_leading()
|
|
|
|
.allow_trailing()
|
|
|
|
.collect()
|
|
|
|
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|tuple, e| (TuplePattern(tuple), e.span()))
|
2024-10-31 20:59:26 +00:00
|
|
|
.labelled("tuple pattern");
|
|
|
|
|
|
|
|
let list_pattern = pattern
|
|
|
|
.clone()
|
2024-11-18 18:25:54 +00:00
|
|
|
.or(splattern.clone())
|
2024-10-31 20:59:26 +00:00
|
|
|
.separated_by(separators.clone())
|
|
|
|
.allow_leading()
|
|
|
|
.allow_trailing()
|
|
|
|
.collect()
|
|
|
|
.delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]")))
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|list, e| (ListPattern(list), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-11-01 03:53:48 +00:00
|
|
|
let pair_pattern = select! {Token::Keyword(k) => k}
|
2024-10-31 20:59:26 +00:00
|
|
|
.then(pattern.clone())
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|(key, patt), e| (PairPattern(key, Box::new(patt)), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
|
|
|
let shorthand_pattern = select! {Token::Word(w) => w}.map_with(|w, e| {
|
|
|
|
(
|
2024-12-10 23:40:43 +00:00
|
|
|
PairPattern(w, Box::new((WordPattern(w), e.span()))),
|
2024-10-31 20:59:26 +00:00
|
|
|
e.span(),
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
let dict_pattern = pair_pattern
|
|
|
|
.or(shorthand_pattern)
|
2024-11-21 01:10:17 +00:00
|
|
|
.or(splattern.clone())
|
2024-10-31 20:59:26 +00:00
|
|
|
.separated_by(separators.clone())
|
|
|
|
.allow_leading()
|
|
|
|
.allow_trailing()
|
|
|
|
.collect()
|
|
|
|
.delimited_by(
|
|
|
|
just(Token::Punctuation("#{")),
|
|
|
|
just(Token::Punctuation("}")),
|
|
|
|
)
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|dict, e| (DictPattern(dict), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-12-10 23:40:43 +00:00
|
|
|
let keyword = select! {Token::Keyword(k) => Keyword(k),}.map_with(|k, e| (k, e.span()));
|
2024-11-09 19:10:08 +00:00
|
|
|
|
|
|
|
let as_pattern = select! {Token::Word(w) => w}
|
|
|
|
.then_ignore(just(Token::Reserved("as")))
|
|
|
|
.then(select! {Token::Keyword(k) => k})
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|(w, t), e| (AsPattern(w, t), e.span()));
|
2024-11-09 19:10:08 +00:00
|
|
|
|
2024-10-31 20:59:26 +00:00
|
|
|
pattern.define(
|
|
|
|
atom_pattern
|
2024-12-07 23:26:25 +00:00
|
|
|
.or(string_pattern)
|
2024-11-09 19:10:08 +00:00
|
|
|
.or(as_pattern)
|
2024-10-31 20:59:26 +00:00
|
|
|
.or(word_pattern)
|
|
|
|
.or(placeholder_pattern)
|
|
|
|
.or(tuple_pattern.clone())
|
|
|
|
.or(list_pattern)
|
|
|
|
.or(dict_pattern)
|
|
|
|
.labelled("pattern"),
|
|
|
|
);
|
|
|
|
|
|
|
|
let placeholder =
|
2024-12-10 23:40:43 +00:00
|
|
|
select! {Token::Punctuation("_") => Placeholder}.map_with(|p, e| (p, e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-12-10 23:40:43 +00:00
|
|
|
let word = select! { Token::Word(w) => Word(w) }
|
2024-10-31 20:59:26 +00:00
|
|
|
.map_with(|w, e| (w, e.span()))
|
|
|
|
.labelled("word");
|
|
|
|
|
|
|
|
let value = select! {
|
2024-12-10 23:40:43 +00:00
|
|
|
Token::Nil => Nil,
|
|
|
|
Token::Boolean(b) => Boolean(b),
|
|
|
|
Token::Number(n) => Number(n),
|
2024-10-31 20:59:26 +00:00
|
|
|
}
|
|
|
|
.map_with(|v, e| (v, e.span()));
|
|
|
|
|
2024-12-04 23:30:03 +00:00
|
|
|
let string = select! {Token::String(s) => s}.try_map_with(|s, e| {
|
|
|
|
let parsed = parse_string(s, e.span());
|
|
|
|
match parsed {
|
|
|
|
Ok(parts) => match parts[0] {
|
2024-12-10 23:40:43 +00:00
|
|
|
(StringPart::Inline(_), _) => Ok((String(s), e.span())),
|
|
|
|
_ => Ok((Interpolated(parts), e.span())),
|
2024-12-04 23:30:03 +00:00
|
|
|
},
|
|
|
|
Err(msg) => Err(Rich::custom(e.span(), msg)),
|
|
|
|
}
|
|
|
|
});
|
2024-11-22 03:36:57 +00:00
|
|
|
|
2024-10-31 20:59:26 +00:00
|
|
|
let tuple = simple
|
|
|
|
.clone()
|
|
|
|
.separated_by(separators.clone())
|
|
|
|
.allow_leading()
|
|
|
|
.allow_trailing()
|
|
|
|
.collect()
|
|
|
|
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|tuple, e| (Tuple(tuple), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
|
|
|
let args = simple
|
|
|
|
.clone()
|
|
|
|
.or(placeholder)
|
|
|
|
.separated_by(separators.clone())
|
|
|
|
.allow_leading()
|
|
|
|
.allow_trailing()
|
|
|
|
.collect()
|
|
|
|
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|args, e| (Arguments(args), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-11-22 00:54:50 +00:00
|
|
|
let synth_root = word.or(keyword);
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-11-22 00:54:50 +00:00
|
|
|
let synth_term = keyword.or(args);
|
2024-10-31 20:59:26 +00:00
|
|
|
|
|
|
|
let synthetic = synth_root
|
|
|
|
.then(synth_term.clone())
|
|
|
|
.then(synth_term.clone().repeated().collect())
|
|
|
|
.map_with(|((root, first), rest), e| {
|
2024-12-10 23:40:43 +00:00
|
|
|
(Synthetic(Box::new(root), Box::new(first), rest), e.span())
|
2024-10-31 20:59:26 +00:00
|
|
|
});
|
|
|
|
|
2024-11-21 21:41:46 +00:00
|
|
|
let splat = just(Token::Punctuation("..."))
|
2024-11-22 00:54:50 +00:00
|
|
|
.ignore_then(word)
|
2024-11-21 21:41:46 +00:00
|
|
|
.map_with(|(w, _), e| {
|
|
|
|
(
|
2024-12-10 23:40:43 +00:00
|
|
|
Splat(if let Word(w) = w { w } else { unreachable!() }),
|
2024-11-21 21:41:46 +00:00
|
|
|
e.span(),
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
2024-10-31 20:59:26 +00:00
|
|
|
let list = simple
|
|
|
|
.clone()
|
2024-11-21 21:41:46 +00:00
|
|
|
.or(splat.clone())
|
2024-10-31 20:59:26 +00:00
|
|
|
.separated_by(separators.clone())
|
|
|
|
.allow_leading()
|
|
|
|
.allow_trailing()
|
|
|
|
.collect()
|
|
|
|
.delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]")))
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|list, e| (List(list), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-11-01 03:53:48 +00:00
|
|
|
let pair = select! {Token::Keyword(k) => k}
|
2024-10-31 20:59:26 +00:00
|
|
|
.then(simple.clone())
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|(key, value), e| (Pair(key, Box::new(value)), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-11-21 21:41:46 +00:00
|
|
|
let shorthand = select! {Token::Word(w) => w}
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|w, e| (Pair(w, Box::new((Word(w), e.span()))), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
|
|
|
let dict = pair
|
|
|
|
.or(shorthand)
|
2024-11-21 21:41:46 +00:00
|
|
|
.or(splat.clone())
|
2024-10-31 20:59:26 +00:00
|
|
|
.separated_by(separators.clone())
|
|
|
|
.allow_leading()
|
|
|
|
.allow_trailing()
|
|
|
|
.collect()
|
|
|
|
.delimited_by(
|
|
|
|
just(Token::Punctuation("#{")),
|
|
|
|
just(Token::Punctuation("}")),
|
|
|
|
)
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|dict, e| (Dict(dict), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-11-21 21:41:46 +00:00
|
|
|
let recur = just(Token::Reserved("recur"))
|
|
|
|
.ignore_then(tuple.clone())
|
|
|
|
.map_with(|args, e| {
|
2024-12-10 23:40:43 +00:00
|
|
|
let (Tuple(args), _) = args else {
|
2024-11-21 21:41:46 +00:00
|
|
|
unreachable!()
|
|
|
|
};
|
2024-12-10 23:40:43 +00:00
|
|
|
(Recur(args), e.span())
|
2024-11-21 21:41:46 +00:00
|
|
|
});
|
|
|
|
|
2024-10-31 20:59:26 +00:00
|
|
|
let block = expr
|
|
|
|
.clone()
|
|
|
|
.separated_by(terminators.clone())
|
|
|
|
.allow_leading()
|
|
|
|
.allow_trailing()
|
|
|
|
.collect()
|
|
|
|
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}")))
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|block, e| (Block(block), e.span()))
|
2024-10-31 20:59:26 +00:00
|
|
|
.recover_with(via_parser(nested_delimiters(
|
|
|
|
Token::Punctuation("{"),
|
|
|
|
Token::Punctuation("}"),
|
|
|
|
[
|
|
|
|
(Token::Punctuation("("), Token::Punctuation(")")),
|
|
|
|
(Token::Punctuation("["), Token::Punctuation("]")),
|
|
|
|
],
|
2024-12-10 23:40:43 +00:00
|
|
|
|span| (Error, span),
|
2024-10-31 20:59:26 +00:00
|
|
|
)));
|
|
|
|
|
|
|
|
let if_ = just(Token::Reserved("if"))
|
|
|
|
.ignore_then(simple.clone())
|
2024-12-09 04:33:02 +00:00
|
|
|
.then_ignore(terminators.clone().or_not())
|
2024-10-31 20:59:26 +00:00
|
|
|
.then_ignore(just(Token::Reserved("then")))
|
|
|
|
.then(expr.clone())
|
2024-12-09 04:33:02 +00:00
|
|
|
.then_ignore(terminators.clone().or_not())
|
2024-10-31 20:59:26 +00:00
|
|
|
.then_ignore(just(Token::Reserved("else")))
|
|
|
|
.then(expr.clone())
|
|
|
|
.map_with(|((condition, then_branch), else_branch), e| {
|
|
|
|
(
|
2024-12-10 23:40:43 +00:00
|
|
|
If(
|
2024-10-31 20:59:26 +00:00
|
|
|
Box::new(condition),
|
|
|
|
Box::new(then_branch),
|
|
|
|
Box::new(else_branch),
|
|
|
|
),
|
|
|
|
e.span(),
|
|
|
|
)
|
|
|
|
});
|
|
|
|
|
|
|
|
let when_clause = simple
|
|
|
|
.clone()
|
|
|
|
.then_ignore(just(Token::Punctuation("->")))
|
|
|
|
.then(expr.clone())
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|(cond, body), e| (WhenClause(Box::new(cond), Box::new(body)), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
|
|
|
let when = just(Token::Reserved("when"))
|
|
|
|
.ignore_then(
|
|
|
|
when_clause
|
|
|
|
.separated_by(terminators.clone())
|
|
|
|
.allow_trailing()
|
|
|
|
.allow_leading()
|
|
|
|
.collect()
|
|
|
|
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}"))),
|
|
|
|
)
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|clauses, e| (When(clauses), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-11-21 01:10:17 +00:00
|
|
|
let guarded_clause = pattern
|
|
|
|
.clone()
|
|
|
|
.then_ignore(just(Token::Reserved("if")))
|
|
|
|
.then(simple.clone())
|
|
|
|
.then_ignore(just(Token::Punctuation("->")))
|
|
|
|
.then(expr.clone())
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|((patt, guard), body), e| {
|
|
|
|
(
|
|
|
|
MatchClause(Box::new(patt), Box::new(Some(guard)), Box::new(body)),
|
|
|
|
e.span(),
|
|
|
|
)
|
2024-11-21 01:10:17 +00:00
|
|
|
});
|
|
|
|
|
2024-10-31 20:59:26 +00:00
|
|
|
let match_clause = pattern
|
|
|
|
.clone()
|
|
|
|
.then_ignore(just(Token::Punctuation("->")))
|
|
|
|
.then(expr.clone())
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|(patt, body), e| {
|
|
|
|
(
|
|
|
|
MatchClause(Box::new(patt), Box::new(None), Box::new(body)),
|
|
|
|
e.span(),
|
|
|
|
)
|
2024-11-09 19:10:08 +00:00
|
|
|
});
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-12-10 23:40:43 +00:00
|
|
|
let r#match = just(Token::Reserved("match"))
|
2024-10-31 20:59:26 +00:00
|
|
|
.ignore_then(simple.clone())
|
|
|
|
.then_ignore(just(Token::Reserved("with")))
|
|
|
|
.then(
|
|
|
|
match_clause
|
|
|
|
.clone()
|
2024-11-21 01:10:17 +00:00
|
|
|
.or(guarded_clause)
|
2024-10-31 20:59:26 +00:00
|
|
|
.separated_by(terminators.clone())
|
|
|
|
.allow_leading()
|
|
|
|
.allow_trailing()
|
|
|
|
.collect()
|
|
|
|
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}"))),
|
|
|
|
)
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|(expr, clauses), e| (Match(Box::new(expr), clauses), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-12-10 23:40:43 +00:00
|
|
|
let conditional = when.or(if_).or(r#match);
|
2024-10-31 20:59:26 +00:00
|
|
|
|
|
|
|
let panic = just(Token::Reserved("panic!"))
|
|
|
|
.ignore_then(nonbinding.clone())
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|expr, e| (Panic(Box::new(expr)), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
|
|
|
let do_ = just(Token::Reserved("do"))
|
|
|
|
.ignore_then(
|
|
|
|
nonbinding
|
|
|
|
.clone()
|
|
|
|
.separated_by(
|
|
|
|
just(Token::Punctuation(">")).then(just(Token::Punctuation("\n")).repeated()),
|
|
|
|
)
|
|
|
|
.collect(),
|
|
|
|
)
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|exprs, e| (Do(exprs), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
|
|
|
let repeat = just(Token::Reserved("repeat"))
|
|
|
|
.ignore_then(simple.clone())
|
|
|
|
.then(block.clone())
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|(count, body), e| (Repeat(Box::new(count), Box::new(body)), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-11-21 01:10:17 +00:00
|
|
|
let fn_guarded = tuple_pattern
|
|
|
|
.clone()
|
|
|
|
.then_ignore(just(Token::Reserved("if")))
|
|
|
|
.then(simple.clone())
|
|
|
|
.then_ignore(just(Token::Punctuation("->")))
|
|
|
|
.then(nonbinding.clone())
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|((patt, guard), body), e| {
|
|
|
|
(
|
|
|
|
MatchClause(Box::new(patt), Box::new(Some(guard)), Box::new(body)),
|
|
|
|
e.span(),
|
|
|
|
)
|
2024-11-21 01:10:17 +00:00
|
|
|
})
|
|
|
|
.labelled("function clause");
|
|
|
|
|
2024-11-21 21:41:46 +00:00
|
|
|
let fn_unguarded = tuple_pattern
|
2024-10-31 20:59:26 +00:00
|
|
|
.clone()
|
|
|
|
.then_ignore(just(Token::Punctuation("->")))
|
|
|
|
.then(nonbinding.clone())
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|(patt, body), e| {
|
|
|
|
(
|
|
|
|
MatchClause(Box::new(patt), Box::new(None), Box::new(body)),
|
|
|
|
e.span(),
|
|
|
|
)
|
2024-11-09 19:10:08 +00:00
|
|
|
})
|
2024-10-31 20:59:26 +00:00
|
|
|
.labelled("function clause");
|
|
|
|
|
2024-11-21 21:41:46 +00:00
|
|
|
let fn_clause = fn_guarded.clone().or(fn_unguarded.clone());
|
|
|
|
|
2024-10-31 20:59:26 +00:00
|
|
|
let lambda = just(Token::Reserved("fn"))
|
2024-11-21 21:41:46 +00:00
|
|
|
.ignore_then(fn_unguarded.clone())
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|clause, e| (Fn("anonymous", vec![clause], None), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
2024-11-22 03:36:57 +00:00
|
|
|
let fn_clauses = fn_clause
|
2024-11-21 21:41:46 +00:00
|
|
|
.clone()
|
|
|
|
.separated_by(terminators.clone())
|
|
|
|
.allow_leading()
|
|
|
|
.allow_trailing()
|
2024-11-22 03:36:57 +00:00
|
|
|
.collect();
|
|
|
|
|
|
|
|
let loop_multiclause = fn_clauses
|
|
|
|
.clone()
|
2024-11-21 21:41:46 +00:00
|
|
|
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}")));
|
|
|
|
|
2024-11-21 22:10:50 +00:00
|
|
|
let fn_single_clause = fn_clause.clone().map_with(|c, _| vec![c]);
|
2024-11-21 21:41:46 +00:00
|
|
|
|
|
|
|
let r#loop = just(Token::Reserved("loop"))
|
|
|
|
.ignore_then(tuple.clone())
|
|
|
|
.then_ignore(just(Token::Reserved("with")))
|
2024-11-22 03:36:57 +00:00
|
|
|
.then(loop_multiclause.clone().or(fn_single_clause.clone()))
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|(init, body), e| (Loop(Box::new(init), body), e.span()));
|
2024-11-21 21:41:46 +00:00
|
|
|
|
2024-12-09 04:33:02 +00:00
|
|
|
simple.define(
|
|
|
|
synthetic
|
|
|
|
.or(recur)
|
|
|
|
.or(word)
|
|
|
|
.or(keyword)
|
|
|
|
.or(value)
|
|
|
|
.or(tuple.clone())
|
|
|
|
.or(list)
|
|
|
|
.or(dict)
|
|
|
|
.or(string)
|
|
|
|
.or(lambda.clone())
|
|
|
|
.labelled("simple expression"),
|
|
|
|
);
|
|
|
|
|
2024-10-31 20:59:26 +00:00
|
|
|
nonbinding.define(
|
|
|
|
simple
|
|
|
|
.clone()
|
|
|
|
.or(conditional)
|
|
|
|
.or(block)
|
|
|
|
.or(panic)
|
|
|
|
.or(do_)
|
|
|
|
.or(repeat)
|
2024-11-21 21:41:46 +00:00
|
|
|
.or(r#loop)
|
2024-10-31 20:59:26 +00:00
|
|
|
.labelled("nonbinding expression"),
|
|
|
|
);
|
|
|
|
|
|
|
|
let let_ = just(Token::Reserved("let"))
|
|
|
|
.ignore_then(pattern.clone())
|
|
|
|
.then_ignore(just(Token::Punctuation("=")))
|
|
|
|
.then(nonbinding.clone())
|
|
|
|
.map_with(|(pattern, expression), e| {
|
2024-12-10 23:40:43 +00:00
|
|
|
(Let(Box::new(pattern), Box::new(expression)), e.span())
|
2024-10-31 20:59:26 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
let box_ = just(Token::Reserved("box"))
|
2024-11-22 00:54:50 +00:00
|
|
|
.ignore_then(word)
|
2024-10-31 20:59:26 +00:00
|
|
|
.then_ignore(just(Token::Punctuation("=")))
|
|
|
|
.then(nonbinding.clone())
|
|
|
|
.map_with(|(word, expr), e| {
|
2024-12-10 23:40:43 +00:00
|
|
|
let name = if let Word(w) = word.0 {
|
2024-10-31 20:59:26 +00:00
|
|
|
w
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
};
|
2024-12-10 23:40:43 +00:00
|
|
|
(LBox(name, Box::new(expr)), e.span())
|
2024-10-31 20:59:26 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
let fn_decl = just(Token::Reserved("fn"))
|
2024-11-22 00:54:50 +00:00
|
|
|
.ignore_then(word)
|
2024-10-31 20:59:26 +00:00
|
|
|
.map_with(|(word, _), e| {
|
2024-12-10 23:40:43 +00:00
|
|
|
let name = if let Word(w) = word {
|
2024-10-31 20:59:26 +00:00
|
|
|
w
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
};
|
2024-12-10 23:40:43 +00:00
|
|
|
(FnDeclaration(name), e.span())
|
2024-10-31 20:59:26 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
let fn_named = just(Token::Reserved("fn"))
|
2024-11-22 00:54:50 +00:00
|
|
|
.ignore_then(word)
|
2024-11-21 21:41:46 +00:00
|
|
|
.then(fn_unguarded.clone())
|
2024-10-31 20:59:26 +00:00
|
|
|
.map_with(|(word, clause), e| {
|
2024-12-10 23:40:43 +00:00
|
|
|
let name = if let Word(word) = word.0 {
|
2024-10-31 20:59:26 +00:00
|
|
|
word
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
};
|
2024-12-10 23:40:43 +00:00
|
|
|
(Fn(name, vec![clause], None), e.span())
|
2024-10-31 20:59:26 +00:00
|
|
|
});
|
|
|
|
|
2024-11-22 03:36:57 +00:00
|
|
|
let docstr = select! {Token::String(s) => s};
|
|
|
|
|
|
|
|
let fn_multiclause = separators
|
|
|
|
.clone()
|
|
|
|
.or_not()
|
|
|
|
.ignore_then(docstr.or_not())
|
|
|
|
.then(fn_clauses.clone())
|
|
|
|
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}")))
|
|
|
|
.map_with(|(docstr, clauses), e| (docstr, clauses, e.span()));
|
|
|
|
|
2024-10-31 20:59:26 +00:00
|
|
|
let fn_compound = just(Token::Reserved("fn"))
|
2024-11-22 00:54:50 +00:00
|
|
|
.ignore_then(word)
|
2024-11-22 03:36:57 +00:00
|
|
|
.then(fn_multiclause)
|
|
|
|
.map_with(|(word, (docstr, clauses, _)), e| {
|
2024-12-10 23:40:43 +00:00
|
|
|
let name = if let Word(word) = word.0 {
|
2024-10-31 20:59:26 +00:00
|
|
|
word
|
|
|
|
} else {
|
|
|
|
unreachable!()
|
|
|
|
};
|
2024-12-10 23:40:43 +00:00
|
|
|
(Fn(name, clauses, docstr), e.span())
|
2024-10-31 20:59:26 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
let fn_ = fn_named.or(fn_compound).or(fn_decl);
|
|
|
|
|
|
|
|
let binding = let_.or(box_).or(fn_);
|
|
|
|
|
|
|
|
expr.define(binding.or(nonbinding));
|
|
|
|
|
|
|
|
let script = expr
|
|
|
|
.separated_by(terminators.clone())
|
|
|
|
.allow_trailing()
|
|
|
|
.allow_leading()
|
|
|
|
.collect()
|
2024-12-10 23:40:43 +00:00
|
|
|
.map_with(|exprs, e| (Block(exprs), e.span()));
|
2024-10-31 20:59:26 +00:00
|
|
|
|
|
|
|
script
|
|
|
|
}
|