[fine] Starting on pattern matching, make patterns explicit

This commit is contained in:
John Doty 2024-02-04 07:47:16 -08:00
parent f00b9e22e7
commit deed9d9a45
4 changed files with 178 additions and 50 deletions

View file

@ -850,14 +850,29 @@ impl<'a> Semantics<'a> {
fn environment_of_is_expression(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef {
assert_eq!(tree.kind, TreeKind::IsExpression);
// The environment of an `is` expression is the environment produced by the pattern.
let Some(pattern) = tree.child_tree_of_kind(self.syntax_tree, TreeKind::Pattern) else {
// Should really have a pattern in there; otherwise there was a
// parse error, don't make more trouble.
return Environment::error();
};
self.environment_of_pattern(parent, pattern)
}
// NOTE: THIS IS CALLED DIRECTLY, NOT VIA `environment_of` TO AVOID CYCLES.
fn environment_of_pattern(&self, parent: EnvironmentRef, tree: &Tree) -> EnvironmentRef {
assert_eq!(tree.kind, TreeKind::Pattern);
let Some(binding) = tree.child_tree_of_kind(self.syntax_tree, TreeKind::VariableBinding)
else {
// No binding, no new environment.
return parent;
};
let Some(variable) = binding.nth_token(0) else {
return Environment::error();
};
let Some(type_expr) = binding.nth_tree(2) else {
let Some(type_expr) = tree.child_of_kind(self.syntax_tree, TreeKind::TypeExpression) else {
return Environment::error();
};
@ -866,7 +881,7 @@ impl<'a> Semantics<'a> {
let mut env = Environment::new(Some(parent), Location::Local);
env.insert(variable, type_expr);
return EnvironmentRef::new(env);
EnvironmentRef::new(env)
}
pub fn class_of(&self, t: TreeRef) -> ClassRef {
@ -1911,6 +1926,11 @@ pub fn check(s: &Semantics) {
TreeKind::IsExpression => check_is_expression(s, tree),
TreeKind::VariableBinding => check_variable_binding(s, tree),
TreeKind::Pattern => check_pattern(s, tree),
TreeKind::MatchArm => {}
TreeKind::MatchBody => {}
TreeKind::MatchExpression => {}
}
}
}
@ -2090,6 +2110,26 @@ fn check_is_expression(_s: &Semantics, _tree: &Tree) {
// TODO
}
fn check_pattern(s: &Semantics, tree: &Tree) {
// If there's an AND then it must produce a boolean.
let and_index = tree.children.iter().position(|c| match c {
Child::Token(t) => t.kind == TokenKind::And,
_ => false,
});
if let Some(and_index) = and_index {
if let Some(pred) = tree.nth_tree(and_index + 1) {
let predicate_type = s.type_of(pred);
if !s.can_convert(&predicate_type, &Type::Bool) {
// TODO: TEST
s.report_error_tree_ref(
pred,
format!("this predicate produces {predicate_type}, but must produce a boolean"),
)
}
}
}
}
fn check_variable_binding(_s: &Semantics, _tree: &Tree) {
// TODO
}