Browse Source

cranelift-isle: Save variable names for later use (#5221)

It's nice to be able to report these names after sema analysis completes
so rule authors can recognize which names they used.

This isn't used anywhere yet, but I'm planning to use it during codegen,
and the rule-verification folks wanted something like this for debugging
output.
pull/5244/head
Jamey Sharp 2 years ago
committed by GitHub
parent
commit
54998715ea
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 68
      cranelift/isle/isle/src/sema.rs

68
cranelift/isle/isle/src/sema.rs

@ -429,12 +429,25 @@ pub struct Rule {
/// The right-hand side expression that this rule evaluates upon successful
/// match.
pub rhs: Expr,
/// Variable names used in this rule, indexed by [VarId].
pub vars: Vec<BoundVar>,
/// The priority of this rule, defaulted to 0 if it was missing in the source.
pub prio: i64,
/// The source position where this rule is defined.
pub pos: Pos,
}
/// A name bound in a pattern or let-expression.
#[derive(Clone, Debug)]
pub struct BoundVar {
/// The identifier used for this variable within the scope of the current [Rule].
pub id: VarId,
/// The variable's name.
pub name: Sym,
/// The type of the value this variable is bound to.
pub ty: TypeId,
}
/// An `if-let` clause with a subpattern match on an expr after the
/// main LHS matches.
#[derive(Clone, Debug)]
@ -1082,17 +1095,22 @@ impl TypeEnv {
}
}
#[derive(Clone, Debug)]
#[derive(Clone, Debug, Default)]
struct Bindings {
next_var: usize,
vars: Vec<BoundVar>,
seen: Vec<BoundVar>,
}
#[derive(Clone, Debug)]
struct BoundVar {
name: Sym,
id: VarId,
ty: TypeId,
impl Bindings {
fn add_var(&mut self, name: Sym, ty: TypeId) -> VarId {
let id = VarId(self.seen.len());
log!("binding var {:?} as {:?} with type {:?}", name.0, id, ty);
self.seen.push(BoundVar { id, name, ty });
id
}
fn lookup(&self, name: Sym) -> Option<&BoundVar> {
self.seen.iter().rev().find(|binding| binding.name == name)
}
}
impl TermEnv {
@ -1623,10 +1641,7 @@ impl TermEnv {
match def {
&ast::Def::Rule(ref rule) => {
let pos = rule.pos;
let mut bindings = Bindings {
next_var: 0,
vars: vec![],
};
let mut bindings = Bindings::default();
let rule_term = match rule.pattern.root_term() {
Some(name) => {
@ -1692,6 +1707,7 @@ impl TermEnv {
lhs,
iflets,
rhs,
vars: bindings.seen,
prio: rule.prio.unwrap_or(0),
pos,
});
@ -1878,18 +1894,14 @@ impl TermEnv {
)?;
let name = tyenv.intern_mut(var);
if bindings.vars.iter().any(|bv| bv.name == name) {
if bindings.lookup(name).is_some() {
tyenv.report_error(
pos,
format!("Re-bound variable name in LHS pattern: '{}'", var.0),
);
// Try to keep going.
}
let id = VarId(bindings.next_var);
bindings.next_var += 1;
log!("binding var {:?}", var.0);
bindings.vars.push(BoundVar { name, id, ty });
let id = bindings.add_var(name, ty);
Some((Pattern::BindPattern(ty, id, Box::new(subpat)), ty))
}
&ast::Pattern::Var { ref var, pos } => {
@ -1899,7 +1911,7 @@ impl TermEnv {
// `BindPattern` with a wildcard subpattern to capture
// at this location.
let name = tyenv.intern_mut(var);
match bindings.vars.iter().rev().find(|bv| bv.name == name) {
match bindings.lookup(name) {
None => {
let ty = match expected_ty {
Some(ty) => ty,
@ -1911,10 +1923,7 @@ impl TermEnv {
return None;
}
};
let id = VarId(bindings.next_var);
bindings.next_var += 1;
log!("binding var {:?}", var.0);
bindings.vars.push(BoundVar { name, id, ty });
let id = bindings.add_var(name, ty);
Some((
Pattern::BindPattern(ty, id, Box::new(Pattern::Wildcard(ty))),
ty,
@ -2123,7 +2132,7 @@ impl TermEnv {
None => {
// Maybe this was actually a variable binding and the user has placed
// parens around it by mistake? (See #4775.)
if bindings.vars.iter().any(|b| b.name == name) {
if bindings.lookup(name).is_some() {
tyenv.report_error(
pos,
format!(
@ -2215,7 +2224,7 @@ impl TermEnv {
&ast::Expr::Var { ref name, pos } => {
let sym = tyenv.intern_mut(name);
// Look through bindings, innermost (most recent) first.
let bv = match bindings.vars.iter().rev().find(|b| b.name == sym) {
let bv = match bindings.lookup(sym) {
None => {
tyenv.report_error(pos, format!("Unknown variable '{}'", name.0));
return None;
@ -2295,7 +2304,7 @@ impl TermEnv {
ref body,
pos,
} => {
let orig_binding_len = bindings.vars.len();
let orig_binding_len = bindings.seen.len();
// For each new binding...
let mut let_defs = vec![];
@ -2335,10 +2344,7 @@ impl TermEnv {
)));
// Bind the var with the given type.
let id = VarId(bindings.next_var);
bindings.next_var += 1;
bindings.vars.push(BoundVar { name, id, ty: tid });
let id = bindings.add_var(name, tid);
let_defs.push((id, tid, val));
}
@ -2347,7 +2353,7 @@ impl TermEnv {
let body_ty = body.ty();
// Pop the bindings.
bindings.vars.truncate(orig_binding_len);
bindings.seen.truncate(orig_binding_len);
Some(Expr::Let {
ty: body_ty,

Loading…
Cancel
Save