460 lines
15 KiB
Rust
460 lines
15 KiB
Rust
|
use crate::parser::StringMatcher;
|
||
|
use crate::spans::*;
|
||
|
use std::fmt;
|
||
|
|
||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||
|
pub enum StringPart {
|
||
|
Data(String),
|
||
|
Word(String),
|
||
|
Inline(String),
|
||
|
}
|
||
|
|
||
|
impl fmt::Display for StringPart {
|
||
|
fn fmt(self: &StringPart, f: &mut fmt::Formatter) -> fmt::Result {
|
||
|
let rep = match self {
|
||
|
StringPart::Word(s) => format!("{{{s}}}"),
|
||
|
StringPart::Data(s) => s.to_string(),
|
||
|
StringPart::Inline(s) => s.to_string(),
|
||
|
};
|
||
|
write!(f, "{}", rep)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#[derive(Clone, Debug, PartialEq)]
|
||
|
pub enum Ast {
|
||
|
// a special Error node
|
||
|
// may come in handy?
|
||
|
Error,
|
||
|
|
||
|
And,
|
||
|
Or,
|
||
|
|
||
|
// expression nodes
|
||
|
Placeholder,
|
||
|
Nil,
|
||
|
Boolean(bool),
|
||
|
Number(f64),
|
||
|
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>>),
|
||
|
Tuple(Vec<Spanned<Self>>),
|
||
|
Arguments(Vec<Spanned<Self>>),
|
||
|
List(Vec<Spanned<Self>>),
|
||
|
Dict(Vec<Spanned<Self>>),
|
||
|
Let(Box<Spanned<Self>>, Box<Spanned<Self>>),
|
||
|
LBox(&'static str, Box<Spanned<Self>>),
|
||
|
Synthetic(Box<Spanned<Self>>, Box<Spanned<Self>>, Vec<Spanned<Self>>),
|
||
|
When(Vec<Spanned<Self>>),
|
||
|
WhenClause(Box<Spanned<Self>>, Box<Spanned<Self>>),
|
||
|
Match(Box<Spanned<Self>>, Vec<Spanned<Self>>),
|
||
|
Receive(Vec<Spanned<Self>>),
|
||
|
MatchClause(
|
||
|
Box<Spanned<Self>>,
|
||
|
Box<Option<Spanned<Self>>>,
|
||
|
Box<Spanned<Self>>,
|
||
|
),
|
||
|
Fn(&'static str, Box<Spanned<Ast>>, Option<&'static str>),
|
||
|
FnBody(Vec<Spanned<Ast>>),
|
||
|
FnDeclaration(&'static str),
|
||
|
Panic(Box<Spanned<Self>>),
|
||
|
Do(Vec<Spanned<Self>>),
|
||
|
Repeat(Box<Spanned<Self>>, Box<Spanned<Self>>),
|
||
|
Splat(&'static str),
|
||
|
Pair(&'static str, Box<Spanned<Self>>),
|
||
|
Loop(Box<Spanned<Self>>, Vec<Spanned<Self>>),
|
||
|
Recur(Vec<Spanned<Self>>),
|
||
|
|
||
|
// pattern nodes
|
||
|
NilPattern,
|
||
|
BooleanPattern(bool),
|
||
|
NumberPattern(f64),
|
||
|
StringPattern(&'static str),
|
||
|
InterpolatedPattern(Vec<Spanned<StringPart>>),
|
||
|
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>>),
|
||
|
}
|
||
|
|
||
|
impl Ast {
|
||
|
pub fn show(&self) -> String {
|
||
|
use Ast::*;
|
||
|
match self {
|
||
|
And => "and".to_string(),
|
||
|
Or => "or".to_string(),
|
||
|
Error => unreachable!(),
|
||
|
Nil | NilPattern => "nil".to_string(),
|
||
|
String(s) | StringPattern(s) => format!("\"{s}\""),
|
||
|
Interpolated(strs) | InterpolatedPattern(strs) => {
|
||
|
let mut out = "".to_string();
|
||
|
out = format!("\"{out}");
|
||
|
for (part, _) in strs {
|
||
|
out = format!("{out}{part}");
|
||
|
}
|
||
|
format!("{out}\"")
|
||
|
}
|
||
|
Boolean(b) | BooleanPattern(b) => b.to_string(),
|
||
|
Number(n) | NumberPattern(n) => n.to_string(),
|
||
|
Keyword(k) | KeywordPattern(k) => format!(":{k}"),
|
||
|
Word(w) | WordPattern(w) => w.to_string(),
|
||
|
Block(lines) => {
|
||
|
let mut out = "{\n".to_string();
|
||
|
for (line, _) in lines {
|
||
|
out = format!("{out}\n {}", line.show());
|
||
|
}
|
||
|
format!("{out}\n}}")
|
||
|
}
|
||
|
If(cond, then, r#else) => format!(
|
||
|
"if {}\n then {}\n else {}",
|
||
|
cond.0.show(),
|
||
|
then.0.show(),
|
||
|
r#else.0.show()
|
||
|
),
|
||
|
Let(pattern, expression) => {
|
||
|
format!("let {} = {}", pattern.0.show(), expression.0.show())
|
||
|
}
|
||
|
Dict(entries) | DictPattern(entries) => {
|
||
|
format!(
|
||
|
"#{{{}}}",
|
||
|
entries
|
||
|
.iter()
|
||
|
.map(|(pair, _)| pair.show())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join(", ")
|
||
|
)
|
||
|
}
|
||
|
List(members) | ListPattern(members) => format!(
|
||
|
"[{}]",
|
||
|
members
|
||
|
.iter()
|
||
|
.map(|(member, _)| member.show())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join(", ")
|
||
|
),
|
||
|
Arguments(members) => format!(
|
||
|
"({})",
|
||
|
members
|
||
|
.iter()
|
||
|
.map(|(member, _)| member.show())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join(", ")
|
||
|
),
|
||
|
Tuple(members) | TuplePattern(members) => format!(
|
||
|
"({})",
|
||
|
members
|
||
|
.iter()
|
||
|
.map(|(member, _)| member.show())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join(", ")
|
||
|
),
|
||
|
Synthetic(root, first, rest) => format!(
|
||
|
"{} {} {}",
|
||
|
root.0.show(),
|
||
|
first.0.show(),
|
||
|
rest.iter()
|
||
|
.map(|(term, _)| term.show())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join(" ")
|
||
|
),
|
||
|
When(clauses) => format!(
|
||
|
"when {{\n {}\n}}",
|
||
|
clauses
|
||
|
.iter()
|
||
|
.map(|(clause, _)| clause.show())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join("\n ")
|
||
|
),
|
||
|
Placeholder | PlaceholderPattern => "_".to_string(),
|
||
|
LBox(name, rhs) => format!("box {name} = {}", rhs.0.show()),
|
||
|
Match(scrutinee, clauses) => format!(
|
||
|
"match {} with {{\n {}\n}}",
|
||
|
scrutinee.0.show(),
|
||
|
clauses
|
||
|
.iter()
|
||
|
.map(|(clause, _)| clause.show())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join("\n ")
|
||
|
),
|
||
|
FnBody(clauses) => clauses
|
||
|
.iter()
|
||
|
.map(|(clause, _)| clause.show())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join("\n "),
|
||
|
Fn(name, body, doc) => {
|
||
|
let mut out = format!("fn {name} {{\n");
|
||
|
if let Some(doc) = doc {
|
||
|
out = format!("{out} {doc}\n");
|
||
|
}
|
||
|
format!("{out} {}\n}}", body.0.show())
|
||
|
}
|
||
|
FnDeclaration(name) => format!("fn {name}"),
|
||
|
Panic(expr) => format!("panic! {}", expr.0.show()),
|
||
|
Do(terms) => {
|
||
|
format!(
|
||
|
"do {}",
|
||
|
terms
|
||
|
.iter()
|
||
|
.map(|(term, _)| term.show())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join(" > ")
|
||
|
)
|
||
|
}
|
||
|
Repeat(times, body) => format!("repeat {} {{\n{}\n}}", times.0.show(), body.0.show()),
|
||
|
Splat(word) => format!("...{}", word),
|
||
|
Splattern(pattern) => format!("...{}", pattern.0.show()),
|
||
|
AsPattern(word, type_keyword) => format!("{word} as :{type_keyword}"),
|
||
|
Pair(key, value) | PairPattern(key, value) => format!(":{key} {}", value.0.show()),
|
||
|
Loop(init, body) => format!(
|
||
|
"loop {} with {{\n {}\n}}",
|
||
|
init.0.show(),
|
||
|
body.iter()
|
||
|
.map(|(clause, _)| clause.show())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join("\n ")
|
||
|
),
|
||
|
Recur(args) => format!(
|
||
|
"recur ({})",
|
||
|
args.iter()
|
||
|
.map(|(arg, _)| arg.show())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join(", ")
|
||
|
),
|
||
|
MatchClause(pattern, guard, body) => {
|
||
|
let mut out = pattern.0.show();
|
||
|
if let Some(guard) = guard.as_ref() {
|
||
|
out = format!("{out} if {}", guard.0.show());
|
||
|
}
|
||
|
format!("{out} -> {}", body.0.show())
|
||
|
}
|
||
|
WhenClause(cond, body) => format!("{} -> {}", cond.0.show(), body.0.show()),
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
impl fmt::Display for Ast {
|
||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||
|
use Ast::*;
|
||
|
match self {
|
||
|
And => write!(f, "And"),
|
||
|
Or => write!(f, "Or"),
|
||
|
Error => write!(f, "Error"),
|
||
|
Nil => write!(f, "nil"),
|
||
|
String(s) => write!(f, "String: \"{}\"", s),
|
||
|
Interpolated(strs) => {
|
||
|
write!(
|
||
|
f,
|
||
|
"Interpolated: \"{}\"",
|
||
|
strs.iter()
|
||
|
.map(|(s, _)| s.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join("")
|
||
|
)
|
||
|
}
|
||
|
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!(
|
||
|
f,
|
||
|
"Block: <{}>",
|
||
|
b.iter()
|
||
|
.map(|(line, _)| line.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join("\n")
|
||
|
),
|
||
|
If(cond, then_branch, else_branch) => write!(
|
||
|
f,
|
||
|
"If: {} Then: {} Else: {}",
|
||
|
cond.0, then_branch.0, else_branch.0
|
||
|
),
|
||
|
Let(pattern, expression) => {
|
||
|
write!(f, "Let: {} = {}", pattern.0, expression.0)
|
||
|
}
|
||
|
Dict(entries) => write!(
|
||
|
f,
|
||
|
"#{{{}}}",
|
||
|
entries
|
||
|
.iter()
|
||
|
.map(|pair| pair.0.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join(", ")
|
||
|
),
|
||
|
List(l) => write!(
|
||
|
f,
|
||
|
"List: [{}]",
|
||
|
l.iter()
|
||
|
.map(|(line, _)| line.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join("\n")
|
||
|
),
|
||
|
Arguments(a) => write!(
|
||
|
f,
|
||
|
"Arguments: ({})",
|
||
|
a.iter()
|
||
|
.map(|(line, _)| line.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join("\n")
|
||
|
),
|
||
|
Tuple(t) => write!(
|
||
|
f,
|
||
|
"Tuple: ({})",
|
||
|
t.iter()
|
||
|
.map(|(line, _)| line.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join("\n")
|
||
|
),
|
||
|
Synthetic(root, first, rest) => write!(
|
||
|
f,
|
||
|
"Synth: [{}, {}, {}]",
|
||
|
root.0,
|
||
|
first.0,
|
||
|
rest.iter()
|
||
|
.map(|(term, _)| term.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join("\n")
|
||
|
),
|
||
|
When(clauses) => write!(
|
||
|
f,
|
||
|
"When: [{}]",
|
||
|
clauses
|
||
|
.iter()
|
||
|
.map(|clause| clause.0.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join("\n")
|
||
|
),
|
||
|
Placeholder => write!(f, "Placeholder"),
|
||
|
LBox(_name, _rhs) => todo!(),
|
||
|
Match(value, clauses) => {
|
||
|
write!(
|
||
|
f,
|
||
|
"match: {} with {}",
|
||
|
&value.0.to_string(),
|
||
|
clauses
|
||
|
.iter()
|
||
|
.map(|clause| clause.0.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join("\n")
|
||
|
)
|
||
|
}
|
||
|
FnBody(clauses) => {
|
||
|
write!(
|
||
|
f,
|
||
|
"{}",
|
||
|
clauses
|
||
|
.iter()
|
||
|
.map(|clause| clause.0.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join("\n")
|
||
|
)
|
||
|
}
|
||
|
Fn(name, body, ..) => {
|
||
|
write!(f, "fn: {name}\n{}", body.0)
|
||
|
}
|
||
|
FnDeclaration(_name) => todo!(),
|
||
|
Panic(_expr) => todo!(),
|
||
|
Do(terms) => {
|
||
|
write!(
|
||
|
f,
|
||
|
"do: {}",
|
||
|
terms
|
||
|
.iter()
|
||
|
.map(|(term, _)| term.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join(" > ")
|
||
|
)
|
||
|
}
|
||
|
Repeat(_times, _body) => todo!(),
|
||
|
Splat(word) => {
|
||
|
write!(f, "splat: {}", word)
|
||
|
}
|
||
|
Pair(k, v) => {
|
||
|
write!(f, "pair: {} {}", k, v.0)
|
||
|
}
|
||
|
Loop(init, body) => {
|
||
|
write!(
|
||
|
f,
|
||
|
"loop: {} with {}",
|
||
|
init.0,
|
||
|
body.iter()
|
||
|
.map(|clause| clause.0.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join("\n")
|
||
|
)
|
||
|
}
|
||
|
Recur(args) => {
|
||
|
write!(
|
||
|
f,
|
||
|
"recur: {}",
|
||
|
args.iter()
|
||
|
.map(|(arg, _)| arg.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join(", ")
|
||
|
)
|
||
|
}
|
||
|
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)
|
||
|
}
|
||
|
|
||
|
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!(
|
||
|
f,
|
||
|
"({})",
|
||
|
t.iter()
|
||
|
.map(|x| x.0.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join(", ")
|
||
|
),
|
||
|
ListPattern(l) => write!(
|
||
|
f,
|
||
|
"({})",
|
||
|
l.iter()
|
||
|
.map(|x| x.0.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join(", ")
|
||
|
),
|
||
|
DictPattern(entries) => write!(
|
||
|
f,
|
||
|
"#{{{}}}",
|
||
|
entries
|
||
|
.iter()
|
||
|
.map(|(pair, _)| pair.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join(", ")
|
||
|
),
|
||
|
PairPattern(key, value) => write!(f, ":{} {}", key, value.0),
|
||
|
InterpolatedPattern(strprts) => write!(
|
||
|
f,
|
||
|
"interpolated: \"{}\"",
|
||
|
strprts
|
||
|
.iter()
|
||
|
.map(|part| part.0.to_string())
|
||
|
.collect::<Vec<_>>()
|
||
|
.join("")
|
||
|
),
|
||
|
}
|
||
|
}
|
||
|
}
|