tuple splatterns now work
This commit is contained in:
parent
3957e9c14a
commit
0acad8b312
24
src/main.rs
24
src/main.rs
|
@ -55,28 +55,8 @@ use crate::base::*;
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let src = "
|
let src = "
|
||||||
fn fancy_add {
|
let (x, y, ...z) = (1, 2, 3)
|
||||||
() -> 0
|
z
|
||||||
(n as :number) -> n
|
|
||||||
(x as :number, y as :number) -> add (x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fancy_sub {
|
|
||||||
() -> 0
|
|
||||||
(n as :number) -> n
|
|
||||||
(x as :number, y as :number) -> sub (x, y)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fib {
|
|
||||||
(1) -> 1
|
|
||||||
(2) -> 1
|
|
||||||
(n) -> fancy_add(
|
|
||||||
fib (fancy_sub (n, 1))
|
|
||||||
fib (fancy_sub (n, 2))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fib (30)
|
|
||||||
";
|
";
|
||||||
let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
|
let (tokens, lex_errs) = lexer().parse(src).into_output_errors();
|
||||||
if lex_errs.len() > 0 {
|
if lex_errs.len() > 0 {
|
||||||
|
|
|
@ -211,6 +211,7 @@ pub enum Pattern<'src> {
|
||||||
Keyword(&'src str),
|
Keyword(&'src str),
|
||||||
Word(&'src str),
|
Word(&'src str),
|
||||||
As(&'src str, &'src str),
|
As(&'src str, &'src str),
|
||||||
|
Splattern(Box<Spanned<Self>>),
|
||||||
Placeholder,
|
Placeholder,
|
||||||
Tuple(Vec<Spanned<Self>>),
|
Tuple(Vec<Spanned<Self>>),
|
||||||
List(Vec<Spanned<Self>>),
|
List(Vec<Spanned<Self>>),
|
||||||
|
@ -229,6 +230,7 @@ impl<'src> fmt::Display for Pattern<'src> {
|
||||||
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.to_string()),
|
||||||
Pattern::Placeholder => write!(f, "_"),
|
Pattern::Placeholder => write!(f, "_"),
|
||||||
Pattern::Tuple(t) => write!(
|
Pattern::Tuple(t) => write!(
|
||||||
f,
|
f,
|
||||||
|
@ -300,8 +302,24 @@ where
|
||||||
}
|
}
|
||||||
.map_with(|a, e| (a, e.span()));
|
.map_with(|a, e| (a, e.span()));
|
||||||
|
|
||||||
|
let bare_splat = just(Token::Punctuation("...")).map_with(|_, e| {
|
||||||
|
(
|
||||||
|
Pattern::Splattern(Box::new((Pattern::Placeholder, e.span()))),
|
||||||
|
e.span(),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
let splattable = word_pattern.clone().or(placeholder_pattern.clone());
|
||||||
|
|
||||||
|
let patt_splat = just(Token::Punctuation("..."))
|
||||||
|
.ignore_then(splattable)
|
||||||
|
.map_with(|x, e| (Pattern::Splattern(Box::new(x)), e.span()));
|
||||||
|
|
||||||
|
let splattern = patt_splat.or(bare_splat);
|
||||||
|
|
||||||
let tuple_pattern = pattern
|
let tuple_pattern = pattern
|
||||||
.clone()
|
.clone()
|
||||||
|
.or(splattern.clone())
|
||||||
.separated_by(separators.clone())
|
.separated_by(separators.clone())
|
||||||
.allow_leading()
|
.allow_leading()
|
||||||
.allow_trailing()
|
.allow_trailing()
|
||||||
|
@ -312,6 +330,7 @@ where
|
||||||
|
|
||||||
let list_pattern = pattern
|
let list_pattern = pattern
|
||||||
.clone()
|
.clone()
|
||||||
|
.or(splattern.clone())
|
||||||
.separated_by(separators.clone())
|
.separated_by(separators.clone())
|
||||||
.allow_leading()
|
.allow_leading()
|
||||||
.allow_trailing()
|
.allow_trailing()
|
||||||
|
|
30
src/vm.rs
30
src/vm.rs
|
@ -79,16 +79,32 @@ pub fn match_pattern<'src, 'a>(
|
||||||
}
|
}
|
||||||
// todo: add splats to these match clauses
|
// todo: add splats to these match clauses
|
||||||
(Pattern::Tuple(x), Value::Tuple(y)) => {
|
(Pattern::Tuple(x), Value::Tuple(y)) => {
|
||||||
if x.len() != y.len() {
|
let has_splat = x.iter().any(|patt| {
|
||||||
|
if let (Pattern::Splattern(_), _) = patt {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if x.len() > y.len() || (!has_splat && x.len() != y.len()) {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
let to = ctx.len();
|
let to = ctx.len();
|
||||||
for i in 0..x.len() {
|
for i in 0..x.len() {
|
||||||
if let None = match_pattern(&x[i].0, &y[i], ctx) {
|
if let Pattern::Splattern(patt) = &x[i].0 {
|
||||||
while ctx.len() > to {
|
let mut list = Vector::new();
|
||||||
ctx.pop();
|
for i in i..y.len() {
|
||||||
|
list.push_back(y[i].clone())
|
||||||
|
}
|
||||||
|
let list = Value::List(list);
|
||||||
|
match_pattern(&(*patt).0, &list, ctx);
|
||||||
|
} else {
|
||||||
|
if let None = match_pattern(&x[i].0, &y[i], ctx) {
|
||||||
|
while ctx.len() > to {
|
||||||
|
ctx.pop();
|
||||||
|
}
|
||||||
|
return None;
|
||||||
}
|
}
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(ctx)
|
Some(ctx)
|
||||||
|
@ -260,7 +276,9 @@ pub fn eval<'src, 'a>(
|
||||||
let val = if let Some((_, value)) = ctx.iter().rev().find(|(name, _)| w == name) {
|
let val = if let Some((_, value)) = ctx.iter().rev().find(|(name, _)| w == name) {
|
||||||
value.clone()
|
value.clone()
|
||||||
} else {
|
} else {
|
||||||
unreachable!()
|
return Err(LudusError {
|
||||||
|
msg: format!("unbound name {w}"),
|
||||||
|
});
|
||||||
};
|
};
|
||||||
Ok(val)
|
Ok(val)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user