start moving Patterns into Ast

This commit is contained in:
Scott Richmond 2024-12-10 18:40:43 -05:00
parent dde9ac4bff
commit cab1b3f173
3 changed files with 292 additions and 224 deletions

View File

@ -441,7 +441,7 @@ impl<'src> Context<'src> {
self.ast = parent; self.ast = parent;
Ok(Value::Dict(dict)) Ok(Value::Dict(dict))
} }
Ast::Box(name, expr) => { Ast::LBox(name, expr) => {
let parent = self.ast; let parent = self.ast;
self.ast = &expr.0; self.ast = &expr.0;
let val = self.eval()?; let val = self.eval()?;

View File

@ -4,34 +4,34 @@ use chumsky::{input::ValueInput, prelude::*, recursive::Recursive};
use std::fmt; use std::fmt;
use struct_scalpel::Dissectible; use struct_scalpel::Dissectible;
#[derive(Clone, Debug, PartialEq)] // #[derive(Clone, Debug, PartialEq)]
pub struct WhenClause { // pub struct WhenClause {
pub cond: Spanned<Ast>, // pub cond: Spanned<Ast>,
pub body: Spanned<Ast>, // pub body: Spanned<Ast>,
} // }
impl fmt::Display for WhenClause { // impl fmt::Display for WhenClause {
fn fmt(self: &WhenClause, f: &mut fmt::Formatter) -> fmt::Result { // fn fmt(self: &WhenClause, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "cond: {}, body: {}", self.cond.0, self.body.0) // write!(f, "cond: {}, body: {}", self.cond.0, self.body.0)
} // }
} // }
#[derive(Clone, Debug, PartialEq)] // #[derive(Clone, Debug, PartialEq)]
pub struct MatchClause { // pub struct MatchClause {
pub patt: Spanned<Pattern>, // pub patt: Spanned<Pattern>,
pub guard: Option<Spanned<Ast>>, // pub guard: Option<Spanned<Ast>>,
pub body: Spanned<Ast>, // pub body: Spanned<Ast>,
} // }
impl fmt::Display for MatchClause { // impl fmt::Display for MatchClause {
fn fmt(self: &MatchClause, f: &mut fmt::Formatter) -> fmt::Result { // fn fmt(self: &MatchClause, f: &mut fmt::Formatter) -> fmt::Result {
write!( // write!(
f, // f,
"pattern: {}, guard: {:?} body: {}", // "pattern: {}, guard: {:?} body: {}",
self.patt.0, self.guard, self.body.0 // self.patt.0, self.guard, self.body.0
) // )
} // }
} // }
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
pub enum StringPart { pub enum StringPart {
@ -53,7 +53,11 @@ impl fmt::Display for StringPart {
#[derive(Clone, Debug, PartialEq, Dissectible)] #[derive(Clone, Debug, PartialEq, Dissectible)]
pub enum Ast { pub enum Ast {
// a special Error node
// may come in handy?
Error, Error,
// expression nodes
Placeholder, Placeholder,
Nil, Nil,
Boolean(bool), Boolean(bool),
@ -68,29 +72,52 @@ pub enum Ast {
Arguments(Vec<Spanned<Self>>), Arguments(Vec<Spanned<Self>>),
List(Vec<Spanned<Self>>), List(Vec<Spanned<Self>>),
Dict(Vec<Spanned<Self>>), Dict(Vec<Spanned<Self>>),
Let(Box<Spanned<Pattern>>, Box<Spanned<Self>>), Let(Box<Spanned<Self>>, Box<Spanned<Self>>),
Box(&'static str, Box<Spanned<Self>>), LBox(&'static str, Box<Spanned<Self>>),
Synthetic(Box<Spanned<Self>>, Box<Spanned<Self>>, Vec<Spanned<Self>>), Synthetic(Box<Spanned<Self>>, Box<Spanned<Self>>, Vec<Spanned<Self>>),
When(Vec<Spanned<WhenClause>>), When(Vec<Spanned<Self>>),
Match(Box<Spanned<Self>>, Vec<MatchClause>), WhenClause(Box<Spanned<Self>>, Box<Spanned<Self>>),
Fn(&'static str, Vec<MatchClause>, Option<&'static str>), 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>),
FnDeclaration(&'static str), FnDeclaration(&'static str),
Panic(Box<Spanned<Self>>), Panic(Box<Spanned<Self>>),
Do(Vec<Spanned<Self>>), Do(Vec<Spanned<Self>>),
Repeat(Box<Spanned<Self>>, Box<Spanned<Self>>), Repeat(Box<Spanned<Self>>, Box<Spanned<Self>>),
Splat(&'static str), Splat(&'static str),
Pair(&'static str, Box<Spanned<Self>>), Pair(&'static str, Box<Spanned<Self>>),
Loop(Box<Spanned<Self>>, Vec<MatchClause>), Loop(Box<Spanned<Self>>, Vec<Spanned<Self>>),
Recur(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 fmt::Display for Ast { impl fmt::Display for Ast {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use Ast::*;
match self { match self {
Ast::Error => write!(f, "Error"), Error => write!(f, "Error"),
Ast::Nil => write!(f, "nil"), Nil => write!(f, "nil"),
Ast::String(s) => write!(f, "String: \"{}\"", s), String(s) => write!(f, "String: \"{}\"", s),
Ast::Interpolated(strs) => { Interpolated(strs) => {
write!( write!(
f, f,
"Interpolated: \"{}\"", "Interpolated: \"{}\"",
@ -100,11 +127,11 @@ impl fmt::Display for Ast {
.join("") .join("")
) )
} }
Ast::Boolean(b) => write!(f, "Boolean: {}", b), Boolean(b) => write!(f, "Boolean: {}", b),
Ast::Number(n) => write!(f, "Number: {}", n), Number(n) => write!(f, "Number: {}", n),
Ast::Keyword(k) => write!(f, "Keyword: :{}", k), Keyword(k) => write!(f, "Keyword: :{}", k),
Ast::Word(w) => write!(f, "Word: {}", w), Word(w) => write!(f, "Word: {}", w),
Ast::Block(b) => write!( Block(b) => write!(
f, f,
"Block: <{}>", "Block: <{}>",
b.iter() b.iter()
@ -112,15 +139,15 @@ impl fmt::Display for Ast {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n") .join("\n")
), ),
Ast::If(cond, then_branch, else_branch) => write!( If(cond, then_branch, else_branch) => write!(
f, f,
"If: {} Then: {} Else: {}", "If: {} Then: {} Else: {}",
cond.0, then_branch.0, else_branch.0 cond.0, then_branch.0, else_branch.0
), ),
Ast::Let(pattern, expression) => { Let(pattern, expression) => {
write!(f, "Let: {} = {}", pattern.0, expression.0) write!(f, "Let: {} = {}", pattern.0, expression.0)
} }
Ast::Dict(entries) => write!( Dict(entries) => write!(
f, f,
"#{{{}}}", "#{{{}}}",
entries entries
@ -129,7 +156,7 @@ impl fmt::Display for Ast {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join(", ") .join(", ")
), ),
Ast::List(l) => write!( List(l) => write!(
f, f,
"List: [{}]", "List: [{}]",
l.iter() l.iter()
@ -137,7 +164,7 @@ impl fmt::Display for Ast {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n") .join("\n")
), ),
Ast::Tuple(t) | Ast::Arguments(t) => write!( Tuple(t) | Ast::Arguments(t) => write!(
f, f,
"Tuple: ({})", "Tuple: ({})",
t.iter() t.iter()
@ -145,7 +172,7 @@ impl fmt::Display for Ast {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n") .join("\n")
), ),
Ast::Synthetic(root, first, rest) => write!( Synthetic(root, first, rest) => write!(
f, f,
"Synth: [{}, {}, {}]", "Synth: [{}, {}, {}]",
root.0, root.0,
@ -155,7 +182,7 @@ impl fmt::Display for Ast {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n") .join("\n")
), ),
Ast::When(clauses) => write!( When(clauses) => write!(
f, f,
"When: [{}]", "When: [{}]",
clauses clauses
@ -164,35 +191,35 @@ impl fmt::Display for Ast {
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n") .join("\n")
), ),
Ast::Placeholder => todo!(), Placeholder => todo!(),
Ast::Box(_name, _rhs) => todo!(), LBox(_name, _rhs) => todo!(),
Ast::Match(value, clauses) => { Match(value, clauses) => {
write!( write!(
f, f,
"match: {} with {}", "match: {} with {}",
&value.0.to_string(), &value.0.to_string(),
clauses clauses
.iter() .iter()
.map(|clause| clause.to_string()) .map(|clause| clause.0.to_string())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n") .join("\n")
) )
} }
Ast::Fn(name, clauses, _) => { Fn(name, clauses, _) => {
write!( write!(
f, f,
"fn: {}\n{}", "fn: {}\n{}",
name, name,
clauses clauses
.iter() .iter()
.map(|clause| clause.to_string()) .map(|clause| clause.0.to_string())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n") .join("\n")
) )
} }
Ast::FnDeclaration(_name) => todo!(), FnDeclaration(_name) => todo!(),
Ast::Panic(_expr) => todo!(), Panic(_expr) => todo!(),
Ast::Do(terms) => { Do(terms) => {
write!( write!(
f, f,
"do: {}", "do: {}",
@ -203,25 +230,25 @@ impl fmt::Display for Ast {
.join(" > ") .join(" > ")
) )
} }
Ast::Repeat(_times, _body) => todo!(), Repeat(_times, _body) => todo!(),
Ast::Splat(word) => { Splat(word) => {
write!(f, "splat: {}", word) write!(f, "splat: {}", word)
} }
Ast::Pair(k, v) => { Pair(k, v) => {
write!(f, "pair: {} {}", k, v.0) write!(f, "pair: {} {}", k, v.0)
} }
Ast::Loop(init, body) => { Loop(init, body) => {
write!( write!(
f, f,
"loop: {} with {}", "loop: {} with {}",
init.0, init.0,
body.iter() body.iter()
.map(|clause| clause.to_string()) .map(|clause| clause.0.to_string())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n") .join("\n")
) )
} }
Ast::Recur(args) => { Recur(args) => {
write!( write!(
f, f,
"recur: {}", "recur: {}",
@ -231,19 +258,62 @@ impl fmt::Display for Ast {
.join(", ") .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)
} }
}
#[derive(Clone, Debug, PartialEq)] NilPattern => write!(f, "nil"),
pub struct PairPattern { BooleanPattern(b) => write!(f, "{}", b),
pub key: &'static str, NumberPattern(n) => write!(f, "{}", n),
pub patt: Spanned<Pattern>, StringPattern(s) => write!(f, "{}", s),
} KeywordPattern(k) => write!(f, ":{}", k),
WordPattern(w) => write!(f, "{}", w),
impl fmt::Display for PairPattern { AsPattern(w, t) => write!(f, "{} as {}", w, t),
fn fmt(self: &PairPattern, f: &mut fmt::Formatter) -> fmt::Result { Splattern(p) => write!(f, "...{}", p.0),
write!(f, "pair pattern: {}: {}", self.key, self.patt.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("")
),
}
} }
} }
@ -273,74 +343,74 @@ impl fmt::Debug for StringMatcher {
} }
} }
#[derive(Clone, Debug, PartialEq)] // #[derive(Clone, Debug, PartialEq)]
pub enum Pattern { // pub enum Pattern {
Nil, // Nil,
Boolean(bool), // Boolean(bool),
Number(f64), // Number(f64),
String(&'static str), // String(&'static str),
Interpolated(Vec<Spanned<StringPart>>, StringMatcher), // Interpolated(Vec<Spanned<StringPart>>, StringMatcher),
Keyword(&'static str), // Keyword(&'static str),
Word(&'static str), // Word(&'static str),
As(&'static str, &'static str), // As(&'static str, &'static str),
Splattern(Box<Spanned<Self>>), // Splattern(Box<Spanned<Self>>),
Placeholder, // Placeholder,
Tuple(Vec<Spanned<Self>>), // Tuple(Vec<Spanned<Self>>),
List(Vec<Spanned<Self>>), // List(Vec<Spanned<Self>>),
Pair(&'static str, Box<Spanned<Self>>), // Pair(&'static str, Box<Spanned<Self>>),
Dict(Vec<Spanned<Self>>), // Dict(Vec<Spanned<Self>>),
} // }
impl fmt::Display for Pattern { // impl fmt::Display for Pattern {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { // match self {
Pattern::Nil => write!(f, "nil"), // Pattern::Nil => write!(f, "nil"),
Pattern::Boolean(b) => write!(f, "{}", b), // Pattern::Boolean(b) => write!(f, "{}", b),
Pattern::Number(n) => write!(f, "{}", n), // Pattern::Number(n) => write!(f, "{}", n),
Pattern::String(s) => write!(f, "{}", s), // Pattern::String(s) => write!(f, "{}", s),
Pattern::Keyword(k) => write!(f, ":{}", k), // Pattern::Keyword(k) => write!(f, ":{}", k),
Pattern::Word(w) => write!(f, "{}", w), // Pattern::Word(w) => write!(f, "{}", w),
Pattern::As(w, t) => write!(f, "{} as {}", w, t), // Pattern::As(w, t) => write!(f, "{} as {}", w, t),
Pattern::Splattern(p) => write!(f, "...{}", p.0), // Pattern::Splattern(p) => write!(f, "...{}", p.0),
Pattern::Placeholder => write!(f, "_"), // Pattern::Placeholder => write!(f, "_"),
Pattern::Tuple(t) => write!( // Pattern::Tuple(t) => write!(
f, // f,
"({})", // "({})",
t.iter() // t.iter()
.map(|x| x.0.to_string()) // .map(|x| x.0.to_string())
.collect::<Vec<_>>() // .collect::<Vec<_>>()
.join(", ") // .join(", ")
), // ),
Pattern::List(l) => write!( // Pattern::List(l) => write!(
f, // f,
"({})", // "({})",
l.iter() // l.iter()
.map(|x| x.0.to_string()) // .map(|x| x.0.to_string())
.collect::<Vec<_>>() // .collect::<Vec<_>>()
.join(", ") // .join(", ")
), // ),
Pattern::Dict(entries) => write!( // Pattern::Dict(entries) => write!(
f, // f,
"#{{{}}}", // "#{{{}}}",
entries // entries
.iter() // .iter()
.map(|(pair, _)| pair.to_string()) // .map(|(pair, _)| pair.to_string())
.collect::<Vec<_>>() // .collect::<Vec<_>>()
.join(", ") // .join(", ")
), // ),
Pattern::Pair(key, value) => write!(f, ":{} {}", key, value.0), // Pattern::Pair(key, value) => write!(f, ":{} {}", key, value.0),
Pattern::Interpolated(strprts, _) => write!( // Pattern::Interpolated(strprts, _) => write!(
f, // f,
"interpolated: \"{}\"", // "interpolated: \"{}\"",
strprts // strprts
.iter() // .iter()
.map(|part| part.0.to_string()) // .map(|part| part.0.to_string())
.collect::<Vec<_>>() // .collect::<Vec<_>>()
.join("") // .join("")
), // ),
} // }
} // }
} // }
fn is_word_char(c: char) -> bool { fn is_word_char(c: char) -> bool {
if c.is_ascii_alphanumeric() { if c.is_ascii_alphanumeric() {
@ -476,6 +546,8 @@ pub fn parser<I>(
where where
I: ValueInput<'static, Token = Token, Span = Span>, I: ValueInput<'static, Token = Token, Span = Span>,
{ {
use Ast::*;
let mut expr = Recursive::declare(); let mut expr = Recursive::declare();
let mut pattern = Recursive::declare(); let mut pattern = Recursive::declare();
@ -497,16 +569,15 @@ where
}); });
let placeholder_pattern = let placeholder_pattern =
select! {Token::Punctuation("_") => Pattern::Placeholder}.map_with(|p, e| (p, e.span())); select! {Token::Punctuation("_") => PlaceholderPattern}.map_with(|p, e| (p, e.span()));
let word_pattern = let word_pattern = select! { Token::Word(w) => WordPattern(w) }.map_with(|w, e| (w, e.span()));
select! { Token::Word(w) => Pattern::Word(w) }.map_with(|w, e| (w, e.span()));
let atom_pattern = select! { let atom_pattern = select! {
Token::Nil => Pattern::Nil, Token::Nil => NilPattern,
Token::Boolean(b) => Pattern::Boolean(b), Token::Boolean(b) => BooleanPattern(b),
Token::Number(n) => Pattern::Number(n), Token::Number(n) => NumberPattern(n),
Token::Keyword(k) => Pattern::Keyword(k), Token::Keyword(k) => KeywordPattern(k),
} }
.map_with(|a, e| (a, e.span())); .map_with(|a, e| (a, e.span()));
@ -514,9 +585,9 @@ where
let parsed = parse_string(s, e.span()); let parsed = parse_string(s, e.span());
match parsed { match parsed {
Ok(parts) => match parts[0] { Ok(parts) => match parts[0] {
(StringPart::Inline(_), _) => Ok((Pattern::String(s), e.span())), (StringPart::Inline(_), _) => Ok((StringPattern(s), e.span())),
_ => Ok(( _ => Ok((
Pattern::Interpolated(parts.clone(), compile_string_pattern(parts)), InterpolatedPattern(parts.clone(), compile_string_pattern(parts)),
e.span(), e.span(),
)), )),
}, },
@ -526,7 +597,7 @@ where
let bare_splat = just(Token::Punctuation("...")).map_with(|_, e| { let bare_splat = just(Token::Punctuation("...")).map_with(|_, e| {
( (
Pattern::Splattern(Box::new((Pattern::Placeholder, e.span()))), Splattern(Box::new((PlaceholderPattern, e.span()))),
e.span(), e.span(),
) )
}); });
@ -535,7 +606,7 @@ where
let patt_splat = just(Token::Punctuation("...")) let patt_splat = just(Token::Punctuation("..."))
.ignore_then(splattable) .ignore_then(splattable)
.map_with(|x, e| (Pattern::Splattern(Box::new(x)), e.span())); .map_with(|x, e| (Splattern(Box::new(x)), e.span()));
let splattern = patt_splat.or(bare_splat); let splattern = patt_splat.or(bare_splat);
@ -547,7 +618,7 @@ where
.allow_trailing() .allow_trailing()
.collect() .collect()
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")"))) .delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
.map_with(|tuple, e| (Pattern::Tuple(tuple), e.span())) .map_with(|tuple, e| (TuplePattern(tuple), e.span()))
.labelled("tuple pattern"); .labelled("tuple pattern");
let list_pattern = pattern let list_pattern = pattern
@ -558,15 +629,15 @@ where
.allow_trailing() .allow_trailing()
.collect() .collect()
.delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]"))) .delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]")))
.map_with(|list, e| (Pattern::List(list), e.span())); .map_with(|list, e| (ListPattern(list), e.span()));
let pair_pattern = select! {Token::Keyword(k) => k} let pair_pattern = select! {Token::Keyword(k) => k}
.then(pattern.clone()) .then(pattern.clone())
.map_with(|(key, patt), e| (Pattern::Pair(key, Box::new(patt)), e.span())); .map_with(|(key, patt), e| (PairPattern(key, Box::new(patt)), e.span()));
let shorthand_pattern = select! {Token::Word(w) => w}.map_with(|w, e| { let shorthand_pattern = select! {Token::Word(w) => w}.map_with(|w, e| {
( (
Pattern::Pair(w, Box::new((Pattern::Word(w), e.span()))), PairPattern(w, Box::new((WordPattern(w), e.span()))),
e.span(), e.span(),
) )
}); });
@ -582,14 +653,14 @@ where
just(Token::Punctuation("#{")), just(Token::Punctuation("#{")),
just(Token::Punctuation("}")), just(Token::Punctuation("}")),
) )
.map_with(|dict, e| (Pattern::Dict(dict), e.span())); .map_with(|dict, e| (DictPattern(dict), e.span()));
let keyword = select! {Token::Keyword(k) => Ast::Keyword(k),}.map_with(|k, e| (k, e.span())); let keyword = select! {Token::Keyword(k) => Keyword(k),}.map_with(|k, e| (k, e.span()));
let as_pattern = select! {Token::Word(w) => w} let as_pattern = select! {Token::Word(w) => w}
.then_ignore(just(Token::Reserved("as"))) .then_ignore(just(Token::Reserved("as")))
.then(select! {Token::Keyword(k) => k}) .then(select! {Token::Keyword(k) => k})
.map_with(|(w, t), e| (Pattern::As(w, t), e.span())); .map_with(|(w, t), e| (AsPattern(w, t), e.span()));
pattern.define( pattern.define(
atom_pattern atom_pattern
@ -604,16 +675,16 @@ where
); );
let placeholder = let placeholder =
select! {Token::Punctuation("_") => Ast::Placeholder}.map_with(|p, e| (p, e.span())); select! {Token::Punctuation("_") => Placeholder}.map_with(|p, e| (p, e.span()));
let word = select! { Token::Word(w) => Ast::Word(w) } let word = select! { Token::Word(w) => Word(w) }
.map_with(|w, e| (w, e.span())) .map_with(|w, e| (w, e.span()))
.labelled("word"); .labelled("word");
let value = select! { let value = select! {
Token::Nil => Ast::Nil, Token::Nil => Nil,
Token::Boolean(b) => Ast::Boolean(b), Token::Boolean(b) => Boolean(b),
Token::Number(n) => Ast::Number(n), Token::Number(n) => Number(n),
} }
.map_with(|v, e| (v, e.span())); .map_with(|v, e| (v, e.span()));
@ -621,8 +692,8 @@ where
let parsed = parse_string(s, e.span()); let parsed = parse_string(s, e.span());
match parsed { match parsed {
Ok(parts) => match parts[0] { Ok(parts) => match parts[0] {
(StringPart::Inline(_), _) => Ok((Ast::String(s), e.span())), (StringPart::Inline(_), _) => Ok((String(s), e.span())),
_ => Ok((Ast::Interpolated(parts), e.span())), _ => Ok((Interpolated(parts), e.span())),
}, },
Err(msg) => Err(Rich::custom(e.span(), msg)), Err(msg) => Err(Rich::custom(e.span(), msg)),
} }
@ -635,7 +706,7 @@ where
.allow_trailing() .allow_trailing()
.collect() .collect()
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")"))) .delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
.map_with(|tuple, e| (Ast::Tuple(tuple), e.span())); .map_with(|tuple, e| (Tuple(tuple), e.span()));
let args = simple let args = simple
.clone() .clone()
@ -645,7 +716,7 @@ where
.allow_trailing() .allow_trailing()
.collect() .collect()
.delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")"))) .delimited_by(just(Token::Punctuation("(")), just(Token::Punctuation(")")))
.map_with(|args, e| (Ast::Arguments(args), e.span())); .map_with(|args, e| (Arguments(args), e.span()));
let synth_root = word.or(keyword); let synth_root = word.or(keyword);
@ -655,21 +726,14 @@ where
.then(synth_term.clone()) .then(synth_term.clone())
.then(synth_term.clone().repeated().collect()) .then(synth_term.clone().repeated().collect())
.map_with(|((root, first), rest), e| { .map_with(|((root, first), rest), e| {
( (Synthetic(Box::new(root), Box::new(first), rest), e.span())
Ast::Synthetic(Box::new(root), Box::new(first), rest),
e.span(),
)
}); });
let splat = just(Token::Punctuation("...")) let splat = just(Token::Punctuation("..."))
.ignore_then(word) .ignore_then(word)
.map_with(|(w, _), e| { .map_with(|(w, _), e| {
( (
Ast::Splat(if let Ast::Word(w) = w { Splat(if let Word(w) = w { w } else { unreachable!() }),
w
} else {
unreachable!()
}),
e.span(), e.span(),
) )
}); });
@ -682,14 +746,14 @@ where
.allow_trailing() .allow_trailing()
.collect() .collect()
.delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]"))) .delimited_by(just(Token::Punctuation("[")), just(Token::Punctuation("]")))
.map_with(|list, e| (Ast::List(list), e.span())); .map_with(|list, e| (List(list), e.span()));
let pair = select! {Token::Keyword(k) => k} let pair = select! {Token::Keyword(k) => k}
.then(simple.clone()) .then(simple.clone())
.map_with(|(key, value), e| (Ast::Pair(key, Box::new(value)), e.span())); .map_with(|(key, value), e| (Pair(key, Box::new(value)), e.span()));
let shorthand = select! {Token::Word(w) => w} let shorthand = select! {Token::Word(w) => w}
.map_with(|w, e| (Ast::Pair(w, Box::new((Ast::Word(w), e.span()))), e.span())); .map_with(|w, e| (Pair(w, Box::new((Word(w), e.span()))), e.span()));
let dict = pair let dict = pair
.or(shorthand) .or(shorthand)
@ -702,15 +766,15 @@ where
just(Token::Punctuation("#{")), just(Token::Punctuation("#{")),
just(Token::Punctuation("}")), just(Token::Punctuation("}")),
) )
.map_with(|dict, e| (Ast::Dict(dict), e.span())); .map_with(|dict, e| (Dict(dict), e.span()));
let recur = just(Token::Reserved("recur")) let recur = just(Token::Reserved("recur"))
.ignore_then(tuple.clone()) .ignore_then(tuple.clone())
.map_with(|args, e| { .map_with(|args, e| {
let (Ast::Tuple(args), _) = args else { let (Tuple(args), _) = args else {
unreachable!() unreachable!()
}; };
(Ast::Recur(args), e.span()) (Recur(args), e.span())
}); });
let block = expr let block = expr
@ -720,7 +784,7 @@ where
.allow_trailing() .allow_trailing()
.collect() .collect()
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}"))) .delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}")))
.map_with(|block, e| (Ast::Block(block), e.span())) .map_with(|block, e| (Block(block), e.span()))
.recover_with(via_parser(nested_delimiters( .recover_with(via_parser(nested_delimiters(
Token::Punctuation("{"), Token::Punctuation("{"),
Token::Punctuation("}"), Token::Punctuation("}"),
@ -728,7 +792,7 @@ where
(Token::Punctuation("("), Token::Punctuation(")")), (Token::Punctuation("("), Token::Punctuation(")")),
(Token::Punctuation("["), Token::Punctuation("]")), (Token::Punctuation("["), Token::Punctuation("]")),
], ],
|span| (Ast::Error, span), |span| (Error, span),
))); )));
let if_ = just(Token::Reserved("if")) let if_ = just(Token::Reserved("if"))
@ -741,7 +805,7 @@ where
.then(expr.clone()) .then(expr.clone())
.map_with(|((condition, then_branch), else_branch), e| { .map_with(|((condition, then_branch), else_branch), e| {
( (
Ast::If( If(
Box::new(condition), Box::new(condition),
Box::new(then_branch), Box::new(then_branch),
Box::new(else_branch), Box::new(else_branch),
@ -754,7 +818,7 @@ where
.clone() .clone()
.then_ignore(just(Token::Punctuation("->"))) .then_ignore(just(Token::Punctuation("->")))
.then(expr.clone()) .then(expr.clone())
.map_with(|(cond, body), e| (WhenClause { cond, body }, e.span())); .map_with(|(cond, body), e| (WhenClause(Box::new(cond), Box::new(body)), e.span()));
let when = just(Token::Reserved("when")) let when = just(Token::Reserved("when"))
.ignore_then( .ignore_then(
@ -765,7 +829,7 @@ where
.collect() .collect()
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}"))), .delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}"))),
) )
.map_with(|clauses, e| (Ast::When(clauses), e.span())); .map_with(|clauses, e| (When(clauses), e.span()));
let guarded_clause = pattern let guarded_clause = pattern
.clone() .clone()
@ -773,23 +837,25 @@ where
.then(simple.clone()) .then(simple.clone())
.then_ignore(just(Token::Punctuation("->"))) .then_ignore(just(Token::Punctuation("->")))
.then(expr.clone()) .then(expr.clone())
.map_with(|((patt, guard), body), _| MatchClause { .map_with(|((patt, guard), body), e| {
patt, (
guard: Some(guard), MatchClause(Box::new(patt), Box::new(Some(guard)), Box::new(body)),
body, e.span(),
)
}); });
let match_clause = pattern let match_clause = pattern
.clone() .clone()
.then_ignore(just(Token::Punctuation("->"))) .then_ignore(just(Token::Punctuation("->")))
.then(expr.clone()) .then(expr.clone())
.map_with(|(patt, body), _| MatchClause { .map_with(|(patt, body), e| {
patt, (
guard: None, MatchClause(Box::new(patt), Box::new(None), Box::new(body)),
body, e.span(),
)
}); });
let match_ = just(Token::Reserved("match")) let r#match = just(Token::Reserved("match"))
.ignore_then(simple.clone()) .ignore_then(simple.clone())
.then_ignore(just(Token::Reserved("with"))) .then_ignore(just(Token::Reserved("with")))
.then( .then(
@ -802,13 +868,13 @@ where
.collect() .collect()
.delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}"))), .delimited_by(just(Token::Punctuation("{")), just(Token::Punctuation("}"))),
) )
.map_with(|(expr, clauses), e| (Ast::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(match_); let conditional = when.or(if_).or(r#match);
let panic = just(Token::Reserved("panic!")) let panic = just(Token::Reserved("panic!"))
.ignore_then(nonbinding.clone()) .ignore_then(nonbinding.clone())
.map_with(|expr, e| (Ast::Panic(Box::new(expr)), e.span())); .map_with(|expr, e| (Panic(Box::new(expr)), e.span()));
let do_ = just(Token::Reserved("do")) let do_ = just(Token::Reserved("do"))
.ignore_then( .ignore_then(
@ -819,12 +885,12 @@ where
) )
.collect(), .collect(),
) )
.map_with(|exprs, e| (Ast::Do(exprs), e.span())); .map_with(|exprs, e| (Do(exprs), e.span()));
let repeat = just(Token::Reserved("repeat")) let repeat = just(Token::Reserved("repeat"))
.ignore_then(simple.clone()) .ignore_then(simple.clone())
.then(block.clone()) .then(block.clone())
.map_with(|(count, body), e| (Ast::Repeat(Box::new(count), Box::new(body)), e.span())); .map_with(|(count, body), e| (Repeat(Box::new(count), Box::new(body)), e.span()));
let fn_guarded = tuple_pattern let fn_guarded = tuple_pattern
.clone() .clone()
@ -832,10 +898,11 @@ where
.then(simple.clone()) .then(simple.clone())
.then_ignore(just(Token::Punctuation("->"))) .then_ignore(just(Token::Punctuation("->")))
.then(nonbinding.clone()) .then(nonbinding.clone())
.map_with(|((patt, guard), body), _| MatchClause { .map_with(|((patt, guard), body), e| {
patt, (
body, MatchClause(Box::new(patt), Box::new(Some(guard)), Box::new(body)),
guard: Some(guard), e.span(),
)
}) })
.labelled("function clause"); .labelled("function clause");
@ -843,10 +910,11 @@ where
.clone() .clone()
.then_ignore(just(Token::Punctuation("->"))) .then_ignore(just(Token::Punctuation("->")))
.then(nonbinding.clone()) .then(nonbinding.clone())
.map_with(|(patt, body), _| MatchClause { .map_with(|(patt, body), e| {
patt, (
body, MatchClause(Box::new(patt), Box::new(None), Box::new(body)),
guard: None, e.span(),
)
}) })
.labelled("function clause"); .labelled("function clause");
@ -854,7 +922,7 @@ where
let lambda = just(Token::Reserved("fn")) let lambda = just(Token::Reserved("fn"))
.ignore_then(fn_unguarded.clone()) .ignore_then(fn_unguarded.clone())
.map_with(|clause, e| (Ast::Fn("anonymous", vec![clause], None), e.span())); .map_with(|clause, e| (Fn("anonymous", vec![clause], None), e.span()));
let fn_clauses = fn_clause let fn_clauses = fn_clause
.clone() .clone()
@ -873,7 +941,7 @@ where
.ignore_then(tuple.clone()) .ignore_then(tuple.clone())
.then_ignore(just(Token::Reserved("with"))) .then_ignore(just(Token::Reserved("with")))
.then(loop_multiclause.clone().or(fn_single_clause.clone())) .then(loop_multiclause.clone().or(fn_single_clause.clone()))
.map_with(|(init, body), e| (Ast::Loop(Box::new(init), body), e.span())); .map_with(|(init, body), e| (Loop(Box::new(init), body), e.span()));
simple.define( simple.define(
synthetic synthetic
@ -906,7 +974,7 @@ where
.then_ignore(just(Token::Punctuation("="))) .then_ignore(just(Token::Punctuation("=")))
.then(nonbinding.clone()) .then(nonbinding.clone())
.map_with(|(pattern, expression), e| { .map_with(|(pattern, expression), e| {
(Ast::Let(Box::new(pattern), Box::new(expression)), e.span()) (Let(Box::new(pattern), Box::new(expression)), e.span())
}); });
let box_ = just(Token::Reserved("box")) let box_ = just(Token::Reserved("box"))
@ -914,35 +982,35 @@ where
.then_ignore(just(Token::Punctuation("="))) .then_ignore(just(Token::Punctuation("=")))
.then(nonbinding.clone()) .then(nonbinding.clone())
.map_with(|(word, expr), e| { .map_with(|(word, expr), e| {
let name = if let Ast::Word(w) = word.0 { let name = if let Word(w) = word.0 {
w w
} else { } else {
unreachable!() unreachable!()
}; };
(Ast::Box(name, Box::new(expr)), e.span()) (LBox(name, Box::new(expr)), e.span())
}); });
let fn_decl = just(Token::Reserved("fn")) let fn_decl = just(Token::Reserved("fn"))
.ignore_then(word) .ignore_then(word)
.map_with(|(word, _), e| { .map_with(|(word, _), e| {
let name = if let Ast::Word(w) = word { let name = if let Word(w) = word {
w w
} else { } else {
unreachable!() unreachable!()
}; };
(Ast::FnDeclaration(name), e.span()) (FnDeclaration(name), e.span())
}); });
let fn_named = just(Token::Reserved("fn")) let fn_named = just(Token::Reserved("fn"))
.ignore_then(word) .ignore_then(word)
.then(fn_unguarded.clone()) .then(fn_unguarded.clone())
.map_with(|(word, clause), e| { .map_with(|(word, clause), e| {
let name = if let Ast::Word(word) = word.0 { let name = if let Word(word) = word.0 {
word word
} else { } else {
unreachable!() unreachable!()
}; };
(Ast::Fn(name, vec![clause], None), e.span()) (Fn(name, vec![clause], None), e.span())
}); });
let docstr = select! {Token::String(s) => s}; let docstr = select! {Token::String(s) => s};
@ -959,12 +1027,12 @@ where
.ignore_then(word) .ignore_then(word)
.then(fn_multiclause) .then(fn_multiclause)
.map_with(|(word, (docstr, clauses, _)), e| { .map_with(|(word, (docstr, clauses, _)), e| {
let name = if let Ast::Word(word) = word.0 { let name = if let Word(word) = word.0 {
word word
} else { } else {
unreachable!() unreachable!()
}; };
(Ast::Fn(name, clauses, docstr), e.span()) (Fn(name, clauses, docstr), e.span())
}); });
let fn_ = fn_named.or(fn_compound).or(fn_decl); let fn_ = fn_named.or(fn_compound).or(fn_decl);
@ -978,7 +1046,7 @@ where
.allow_trailing() .allow_trailing()
.allow_leading() .allow_leading()
.collect() .collect()
.map_with(|exprs, e| (Ast::Block(exprs), e.span())); .map_with(|exprs, e| (Block(exprs), e.span()));
script script
} }

View File

@ -315,7 +315,7 @@ impl<'a> Validator<'a> {
// binding forms // binding forms
// TODO: set up errors to include original binding // TODO: set up errors to include original binding
Ast::Box(name, boxed) => { Ast::LBox(name, boxed) => {
if self.bound(name).is_some() { if self.bound(name).is_some() {
self.err(format!("box name `{name}` is already bound")); self.err(format!("box name `{name}` is already bound"));
} else { } else {