[fine] Implement the wildcard pattern
This commit is contained in:
parent
e0721d09fc
commit
65ec2d4cca
5 changed files with 104 additions and 25 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue