Compare commits
2 Commits
759fc63cae
...
db52bc2687
Author | SHA1 | Date | |
---|---|---|---|
|
db52bc2687 | ||
|
a175ee7a41 |
|
@ -1218,8 +1218,11 @@ fn self {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send {
|
fn send {
|
||||||
"Sends a message to the specified process."
|
"Sends a message to the specified process and returns the message."
|
||||||
(pid as :keyword, msg) -> base :process (:send, pid, msg)
|
(pid as :keyword, msg) -> {
|
||||||
|
base :process (:send, pid, msg)
|
||||||
|
msg
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn spawn! {
|
fn spawn! {
|
||||||
|
@ -1245,21 +1248,11 @@ fn link! {
|
||||||
(pid1 as :keyword, pid2 as :keyword, :enforce) -> base :process (:link_enforce, pid1, pid2)
|
(pid1 as :keyword, pid2 as :keyword, :enforce) -> base :process (:link_enforce, pid1, pid2)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn msgs {
|
|
||||||
"Returns the entire contents of the current process as a list. Leaves all messages in the process mailbox."
|
|
||||||
() -> base :process (:msgs)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush! {
|
fn flush! {
|
||||||
"Clears the current process's mailbox."
|
"Clears the current process's mailbox and returns all the messages."
|
||||||
() -> base :process (:flush)
|
() -> base :process (:flush)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn flush_i! {
|
|
||||||
"Flushes the message at the indicated index in the current process's mailbox."
|
|
||||||
(i as :number) -> base :process (:flush_i, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sleep! {
|
fn sleep! {
|
||||||
"Puts the current process to sleep for at least the specified number of milliseconds."
|
"Puts the current process to sleep for at least the specified number of milliseconds."
|
||||||
(ms as :number) -> base :process (:sleep, ms)
|
(ms as :number) -> base :process (:sleep, ms)
|
||||||
|
|
|
@ -969,7 +969,8 @@ match (nil) with {
|
||||||
|
|
||||||
In particular, function arities need to be changed, flushes need to be inserted, anonymous lambdas need to be created (which can't be multi-clause), etc.
|
In particular, function arities need to be changed, flushes need to be inserted, anonymous lambdas need to be created (which can't be multi-clause), etc.
|
||||||
|
|
||||||
* [ ] There was another bug that I was going to write down and fix, but I forgot what it was. Something with processes.
|
~* [ ] There was another bug that I was going to write down and fix, but I forgot what it was. Something with processes.~
|
||||||
|
* [ ] I remembered: I got some weird behaviour when `MAX_REDUCTIONS` was set to 100; I've increased it to 1000, but now need to test what happens when we yield because of reductions.
|
||||||
|
|
||||||
* [ ] Also: the `butlast` bug is still outstanding: `base :slice` causes a panic in that function, but not the call to the Ludus function. Still have to investigate that one.
|
* [ ] Also: the `butlast` bug is still outstanding: `base :slice` causes a panic in that function, but not the call to the Ludus function. Still have to investigate that one.
|
||||||
|
|
||||||
|
|
459
src/ast.rs
Normal file
459
src/ast.rs
Normal file
|
@ -0,0 +1,459 @@
|
||||||
|
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("")
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
|
use crate::ast::{Ast, StringPart};
|
||||||
use crate::chunk::{Chunk, StrPattern};
|
use crate::chunk::{Chunk, StrPattern};
|
||||||
use crate::op::Op;
|
use crate::op::Op;
|
||||||
use crate::parser::Ast;
|
|
||||||
use crate::parser::StringPart;
|
|
||||||
use crate::spans::Spanned;
|
use crate::spans::Spanned;
|
||||||
use crate::value::*;
|
use crate::value::*;
|
||||||
use chumsky::prelude::SimpleSpan;
|
use chumsky::prelude::SimpleSpan;
|
||||||
|
|
|
@ -56,7 +56,9 @@ pub fn lexer(
|
||||||
"nil" => Token::Nil,
|
"nil" => Token::Nil,
|
||||||
// todo: hard code these as type constructors
|
// todo: hard code these as type constructors
|
||||||
"as" | "box" | "do" | "else" | "fn" | "if" | "let" | "loop" | "match" | "panic!"
|
"as" | "box" | "do" | "else" | "fn" | "if" | "let" | "loop" | "match" | "panic!"
|
||||||
| "recur" | "repeat" | "then" | "when" | "with" | "or" | "and" => Token::Reserved(word),
|
| "recur" | "repeat" | "then" | "when" | "with" | "or" | "and" | "receive" => {
|
||||||
|
Token::Reserved(word)
|
||||||
|
}
|
||||||
_ => Token::Word(word),
|
_ => Token::Word(word),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,9 @@ const DEBUG_SCRIPT_RUN: bool = false;
|
||||||
const DEBUG_PRELUDE_COMPILE: bool = false;
|
const DEBUG_PRELUDE_COMPILE: bool = false;
|
||||||
const DEBUG_PRELUDE_RUN: bool = false;
|
const DEBUG_PRELUDE_RUN: bool = false;
|
||||||
|
|
||||||
|
mod ast;
|
||||||
|
use crate::ast::Ast;
|
||||||
|
|
||||||
mod base;
|
mod base;
|
||||||
|
|
||||||
mod world;
|
mod world;
|
||||||
|
@ -19,7 +22,7 @@ mod lexer;
|
||||||
use crate::lexer::lexer;
|
use crate::lexer::lexer;
|
||||||
|
|
||||||
mod parser;
|
mod parser;
|
||||||
use crate::parser::{parser, Ast};
|
use crate::parser::parser;
|
||||||
|
|
||||||
mod validator;
|
mod validator;
|
||||||
use crate::validator::Validator;
|
use crate::validator::Validator;
|
||||||
|
|
530
src/parser.rs
530
src/parser.rs
|
@ -2,467 +2,13 @@
|
||||||
// TODO: remove StringMatcher cruft
|
// TODO: remove StringMatcher cruft
|
||||||
// TODO: good error messages?
|
// TODO: good error messages?
|
||||||
|
|
||||||
|
use crate::ast::{Ast, StringPart};
|
||||||
use crate::lexer::*;
|
use crate::lexer::*;
|
||||||
use crate::spans::*;
|
use crate::spans::*;
|
||||||
use chumsky::{input::ValueInput, prelude::*, recursive::Recursive};
|
use chumsky::{input::ValueInput, prelude::*, recursive::Recursive};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
pub struct StringMatcher();
|
||||||
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>>),
|
|
||||||
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>>, 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>>),
|
|
||||||
}
|
|
||||||
|
|
||||||
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("")
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
||||||
|
@ -576,54 +122,6 @@ fn parse_string(s: &'static str, span: SimpleSpan) -> Result<Vec<Spanned<StringP
|
||||||
Ok(parts)
|
Ok(parts)
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
|
||||||
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) => {
|
|
||||||
matches.push((
|
|
||||||
word.clone(),
|
|
||||||
to_test.get(last_match..i).unwrap().to_string(),
|
|
||||||
));
|
|
||||||
last_match = i + part.len();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unreachable!("internal Ludus error"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some(matches)
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parser<I>(
|
pub fn parser<I>(
|
||||||
) -> impl Parser<'static, I, Spanned<Ast>, extra::Err<Rich<'static, Token, Span>>> + Clone
|
) -> impl Parser<'static, I, Spanned<Ast>, extra::Err<Rich<'static, Token, Span>>> + Clone
|
||||||
where
|
where
|
||||||
|
@ -669,10 +167,7 @@ where
|
||||||
match parsed {
|
match parsed {
|
||||||
Ok(parts) => match parts[0] {
|
Ok(parts) => match parts[0] {
|
||||||
(StringPart::Inline(_), _) => Ok((StringPattern(s), e.span())),
|
(StringPart::Inline(_), _) => Ok((StringPattern(s), e.span())),
|
||||||
_ => Ok((
|
_ => Ok((InterpolatedPattern(parts.clone()), e.span())),
|
||||||
InterpolatedPattern(parts.clone(), compile_string_pattern(parts)),
|
|
||||||
e.span(),
|
|
||||||
)),
|
|
||||||
},
|
},
|
||||||
Err(msg) => Err(Rich::custom(e.span(), msg)),
|
Err(msg) => Err(Rich::custom(e.span(), msg)),
|
||||||
}
|
}
|
||||||
|
@ -882,7 +377,7 @@ where
|
||||||
|span| (Error, span),
|
|span| (Error, span),
|
||||||
)));
|
)));
|
||||||
|
|
||||||
let if_ = just(Token::Reserved("if"))
|
let r#if = just(Token::Reserved("if"))
|
||||||
.ignore_then(simple.clone())
|
.ignore_then(simple.clone())
|
||||||
.then_ignore(terminators.clone().or_not())
|
.then_ignore(terminators.clone().or_not())
|
||||||
.then_ignore(just(Token::Reserved("then")))
|
.then_ignore(just(Token::Reserved("then")))
|
||||||
|
@ -948,7 +443,7 @@ where
|
||||||
.then(
|
.then(
|
||||||
match_clause
|
match_clause
|
||||||
.clone()
|
.clone()
|
||||||
.or(guarded_clause)
|
.or(guarded_clause.clone())
|
||||||
.separated_by(terminators.clone())
|
.separated_by(terminators.clone())
|
||||||
.allow_leading()
|
.allow_leading()
|
||||||
.allow_trailing()
|
.allow_trailing()
|
||||||
|
@ -957,7 +452,20 @@ where
|
||||||
)
|
)
|
||||||
.map_with(|(expr, clauses), e| (Match(Box::new(expr), clauses), e.span()));
|
.map_with(|(expr, clauses), e| (Match(Box::new(expr), clauses), e.span()));
|
||||||
|
|
||||||
let conditional = when.or(if_).or(r#match);
|
let receive = just(Token::Reserved("receive"))
|
||||||
|
.ignore_then(
|
||||||
|
match_clause
|
||||||
|
.clone()
|
||||||
|
.or(guarded_clause)
|
||||||
|
.separated_by(terminators.clone())
|
||||||
|
.allow_leading()
|
||||||
|
.allow_trailing()
|
||||||
|
.collect()
|
||||||
|
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}"))),
|
||||||
|
)
|
||||||
|
.map_with(|clauses, e| (Receive(clauses), e.span()));
|
||||||
|
|
||||||
|
let conditional = when.or(r#if).or(r#match).or(receive);
|
||||||
|
|
||||||
let panic = just(Token::Reserved("panic!"))
|
let panic = just(Token::Reserved("panic!"))
|
||||||
.ignore_then(nonbinding.clone())
|
.ignore_then(nonbinding.clone())
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
// * [ ] ensure loops have fixed arity (no splats)
|
// * [ ] ensure loops have fixed arity (no splats)
|
||||||
// * [ ] ensure fn pattern splats are always highest (and same) arity
|
// * [ ] ensure fn pattern splats are always highest (and same) arity
|
||||||
|
|
||||||
use crate::parser::*;
|
use crate::ast::{Ast, StringPart};
|
||||||
use crate::spans::{Span, Spanned};
|
use crate::spans::{Span, Spanned};
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
use crate::ast::Ast;
|
||||||
use crate::base::BaseFn;
|
use crate::base::BaseFn;
|
||||||
use crate::chunk::Chunk;
|
use crate::chunk::Chunk;
|
||||||
use crate::op::Op;
|
use crate::op::Op;
|
||||||
use crate::parser::Ast;
|
|
||||||
use crate::spans::Spanned;
|
use crate::spans::Spanned;
|
||||||
use crate::value::{LFn, Value};
|
use crate::value::{LFn, Value};
|
||||||
use crate::world::Zoo;
|
use crate::world::Zoo;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user