[fine] Implement the wildcard pattern

This commit is contained in:
John Doty 2024-02-04 19:36:47 -08:00
parent e0721d09fc
commit 65ec2d4cca
5 changed files with 104 additions and 25 deletions

View file

@ -629,6 +629,18 @@ fn compile_is_expression(c: &mut Compiler, tree: &Tree) -> Option<()> {
fn compile_pattern(c: &mut Compiler, t: TreeRef) -> Option<()> {
let tree = &c.syntax[t];
// Let's *try* to generate good code in the presence of a wildcard pattern....
let is_wildcard = tree
.child_tree_of_kind(c.syntax, TreeKind::WildcardPattern)
.is_some();
let type_expr = tree.child_tree_of_kind(c.syntax, TreeKind::TypeExpression);
let and_index = tree.children.iter().position(|c| match c {
Child::Token(t) => t.kind == TokenKind::And,
_ => false,
});
// If you have a binding, dup and store now, it is in scope.
if let Some(binding) = tree.child_tree_of_kind(c.syntax, TreeKind::VariableBinding) {
if let Some(variable) = binding.nth_token(0) {
@ -644,31 +656,51 @@ fn compile_pattern(c: &mut Compiler, t: TreeRef) -> Option<()> {
ice!(c, t, "is cannot make a non-local, non-variable declaration")
};
c.push(Instruction::Dup);
// If we aren't a wildcard or we have an attached predicate then
// we will need the value on the stack, otherwise we can discard
// it.
if and_index.is_some() || !is_wildcard {
c.push(Instruction::Dup);
}
c.push(Instruction::StoreLocal(*index));
}
}
let type_expr = tree.child_tree_of_kind(c.syntax, TreeKind::TypeExpression)?;
compile_type_expr_eq(c, type_expr.nth_tree(0)?);
let and_index = tree.children.iter().position(|c| match c {
Child::Token(t) => t.kind == TokenKind::And,
_ => false,
});
if !is_wildcard {
let type_expr = type_expr?;
compile_type_expr_eq(c, type_expr.nth_tree(0)?);
}
if let Some(and_index) = and_index {
// This is the tail end of an "AND" expression.
let jump_true_index = c.push(Instruction::JumpTrue(0));
let jump_end_index = if is_wildcard {
// If the pattern was a wildcard then don't bother with this jump
// nonsense; we know the pattern matched, all we need to do is
// evaluate the predicate.
None
} else {
// Otherwise test the pattern to see if it passed; if it did then
// we need to run the predicate. (This is the back half of an AND
// expression.)
let jump_true_index = c.push(Instruction::JumpTrue(0));
c.push(Instruction::PushFalse);
let jump_end_index = c.push(Instruction::Jump(0));
c.push(Instruction::PushFalse);
let jump_end_index = c.push(Instruction::Jump(0));
c.patch(jump_true_index, |i| Instruction::JumpTrue(i));
c.patch(jump_true_index, |i| Instruction::JumpTrue(i));
Some(jump_end_index)
};
compile_expression(c, tree.nth_tree(and_index + 1)?);
c.patch(jump_end_index, |i| Instruction::Jump(i));
};
// If we wound up with a jump what needs patching, patch it.
if let Some(jump_end_index) = jump_end_index {
c.patch(jump_end_index, |i| Instruction::Jump(i));
}
} else if is_wildcard {
// If there was no predicate *and* the pattern was a wildcard then
// I'll just need to push true here.
c.push(Instruction::PushTrue);
}
OK
}