///|
fn Program::resolve(self : Program) -> Unit {
self.collapse_transparent_scopes()
for index in 0..= 0 {
reference.symbol
} else {
self.find_binding(scope, reference.name)
}
let symbol = if binding >= 0 { self.symbol_root(binding) } else { binding }
if symbol >= 0 {
let resolved = self.symbols[symbol]
self.symbols[symbol] = { ..resolved, use_count: resolved.use_count + 1, }
}
self.references[index] = { ..reference, scope, symbol, }
}
}
///|
fn Program::collapse_transparent_scopes(self : Program) -> Unit {
// Parent scopes are allocated before children. Collapse provisional scopes
// in one forward pass, avoiding repeated reparenting of nested expressions.
for index in 0..= 0 &&
self.scopes[scope.parent].kind == scope_transparent else {
continue
}
self.scopes[index] = { ..scope, parent: self.scopes[scope.parent].parent, }
}
}
///|
fn Program::reference_scope(self : Program, scope : Int) -> Int {
guard self.scopes[scope].kind == scope_transparent else { return scope }
self.scopes[scope].parent
}
///|
fn Program::find_binding(self : Program, start_scope : Int, name : Int) -> Int {
for scope = start_scope {
guard scope >= 0 else { break -1 }
let environment = self.scopes[scope]
if self.scope_members[scope].get(name) is Some(binding) {
break binding
}
// Ordinary functions introduce arguments; arrows inherit it.
guard name != name_arguments || environment.kind != scope_parameters else {
break -1
}
continue environment.parent
}
}