Refactor: Use new NodeKind and clean up Binder definitions
The Binder and related types have been refactored to use the new `NodeKind` enum instead of the previous `BoundKind`. This commit updates all references to use the new structure, ensuring consistency across the compiler's AST representation. Key changes include: - Replacing `BoundKind` with `NodeKind` in the Binder's `bind` and `visit` methods. - Updating pattern matching and field access to reflect the new enum variants (e.g., `NodeKind::Def` instead of `BoundKind::Define`). - Adjusting identifier bindings to use the new `IdentifierBinding` enum. - Reflecting changes in `DefBinding`, `AssignBinding`, and `LambdaBinding` structures. - Ensuring all newly created nodes use `NodeKind` and the appropriate metadata.
This commit is contained in:
+219
-182
@@ -1,182 +1,219 @@
|
||||
use crate::ast::compiler::bound_nodes::{Address, AnalyzedNode, BoundKind, GlobalIdx, VirtualId};
|
||||
use crate::ast::types::{Identity, Value};
|
||||
use crate::ast::vm::Closure;
|
||||
use std::collections::HashSet;
|
||||
|
||||
// --- PathTracker ---
|
||||
#[derive(Default)]
|
||||
pub struct PathTracker {
|
||||
pub inlining_depth: usize,
|
||||
pub inlining_stack: HashSet<GlobalIdx>,
|
||||
pub identity_stack: HashSet<Identity>,
|
||||
}
|
||||
|
||||
impl PathTracker {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn enter_lambda(&mut self, identity: &Identity) -> bool {
|
||||
if self.identity_stack.contains(identity) {
|
||||
return false;
|
||||
}
|
||||
self.identity_stack.insert(identity.clone());
|
||||
true
|
||||
}
|
||||
|
||||
pub fn exit_lambda(&mut self, identity: &Identity) {
|
||||
self.identity_stack.remove(identity);
|
||||
}
|
||||
}
|
||||
|
||||
// --- UsageInfo ---
|
||||
#[derive(Default)]
|
||||
pub struct UsageInfo {
|
||||
pub used: HashSet<Address<VirtualId>>,
|
||||
pub assigned: HashSet<Address<VirtualId>>,
|
||||
pub used_identities: HashSet<Identity>,
|
||||
}
|
||||
|
||||
impl UsageInfo {
|
||||
pub fn is_assigned(&self, addr: &Address<VirtualId>) -> bool {
|
||||
self.assigned.contains(addr)
|
||||
}
|
||||
|
||||
pub fn is_used(&self, addr: &Address<VirtualId>) -> bool {
|
||||
self.used.contains(addr)
|
||||
}
|
||||
|
||||
pub fn collect(&mut self, node: &AnalyzedNode) {
|
||||
match &node.kind {
|
||||
BoundKind::Destructure { pattern, value } => {
|
||||
self.collect_pattern(pattern);
|
||||
self.collect(value);
|
||||
}
|
||||
BoundKind::Constant(v) => {
|
||||
if let Value::Object(obj) = v
|
||||
&& let Some(closure) = obj.as_any().downcast_ref::<Closure>()
|
||||
{
|
||||
self.used_identities
|
||||
.insert(closure.function_node.identity.clone());
|
||||
self.collect(&closure.function_node);
|
||||
}
|
||||
}
|
||||
BoundKind::Get { addr, .. } => {
|
||||
self.used.insert(*addr);
|
||||
}
|
||||
BoundKind::Set { addr, value } => {
|
||||
self.assigned.insert(*addr);
|
||||
self.collect(value);
|
||||
}
|
||||
BoundKind::GetField { rec, .. } => {
|
||||
self.collect(rec);
|
||||
}
|
||||
BoundKind::Lambda {
|
||||
params,
|
||||
body,
|
||||
upvalues,
|
||||
..
|
||||
} => {
|
||||
self.used_identities.insert(node.identity.clone());
|
||||
|
||||
let mut inner_info = UsageInfo::default();
|
||||
inner_info.collect(params);
|
||||
inner_info.collect(body);
|
||||
|
||||
// Propagate globals and identities
|
||||
for addr in &inner_info.used {
|
||||
if let Address::Global(_) = addr {
|
||||
self.used.insert(*addr);
|
||||
}
|
||||
}
|
||||
for addr in &inner_info.assigned {
|
||||
if let Address::Global(_) = addr {
|
||||
self.assigned.insert(*addr);
|
||||
}
|
||||
}
|
||||
self.used_identities.extend(inner_info.used_identities);
|
||||
|
||||
// Map used upvalues to parent scope
|
||||
for addr in &inner_info.used {
|
||||
if let Address::Upvalue(idx) = addr
|
||||
&& let Some(parent_addr) = upvalues.get(idx.0 as usize)
|
||||
{
|
||||
self.used.insert(*parent_addr);
|
||||
}
|
||||
}
|
||||
// Map assigned upvalues to parent scope
|
||||
for addr in &inner_info.assigned {
|
||||
if let Address::Upvalue(idx) = addr
|
||||
&& let Some(parent_addr) = upvalues.get(idx.0 as usize)
|
||||
{
|
||||
self.assigned.insert(*parent_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
BoundKind::Block { exprs } => {
|
||||
for e in exprs {
|
||||
self.collect(e);
|
||||
}
|
||||
}
|
||||
BoundKind::If {
|
||||
cond,
|
||||
then_br,
|
||||
else_br,
|
||||
} => {
|
||||
self.collect(cond);
|
||||
self.collect(then_br);
|
||||
if let Some(e) = else_br {
|
||||
self.collect(e);
|
||||
}
|
||||
}
|
||||
BoundKind::Call { callee, args } => {
|
||||
self.collect(callee);
|
||||
self.collect(args);
|
||||
}
|
||||
BoundKind::Tuple { elements } => {
|
||||
for e in elements {
|
||||
self.collect(e);
|
||||
}
|
||||
}
|
||||
BoundKind::Record { values, .. } => {
|
||||
for v in values {
|
||||
self.collect(v);
|
||||
}
|
||||
}
|
||||
BoundKind::Define { value, .. } => {
|
||||
self.collect(value);
|
||||
}
|
||||
BoundKind::Expansion { bound_expanded, .. } => {
|
||||
self.collect(bound_expanded);
|
||||
}
|
||||
BoundKind::Again { args } => {
|
||||
self.collect(args);
|
||||
}
|
||||
BoundKind::Pipe { inputs, lambda, .. } => {
|
||||
for input in inputs {
|
||||
self.collect(input);
|
||||
}
|
||||
self.collect(lambda);
|
||||
}
|
||||
BoundKind::Nop
|
||||
| BoundKind::FieldAccessor(_)
|
||||
| BoundKind::Extension(_)
|
||||
| BoundKind::Error => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn collect_pattern(&mut self, node: &AnalyzedNode) {
|
||||
match &node.kind {
|
||||
BoundKind::Define { .. } => {}
|
||||
BoundKind::Set { addr, .. } => {
|
||||
self.assigned.insert(*addr);
|
||||
}
|
||||
BoundKind::Tuple { elements } => {
|
||||
for el in elements {
|
||||
self.collect_pattern(el);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
use crate::ast::compiler::bound_nodes::{
|
||||
Address, AnalyzedNode, GlobalIdx, IdentifierBinding,
|
||||
NodeKind, VirtualId,
|
||||
};
|
||||
use crate::ast::types::{Identity, Value};
|
||||
use crate::ast::vm::Closure;
|
||||
use std::collections::HashSet;
|
||||
|
||||
// --- PathTracker ---
|
||||
#[derive(Default)]
|
||||
pub struct PathTracker {
|
||||
pub inlining_depth: usize,
|
||||
pub inlining_stack: HashSet<GlobalIdx>,
|
||||
pub identity_stack: HashSet<Identity>,
|
||||
}
|
||||
|
||||
impl PathTracker {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
pub fn enter_lambda(&mut self, identity: &Identity) -> bool {
|
||||
if self.identity_stack.contains(identity) {
|
||||
return false;
|
||||
}
|
||||
self.identity_stack.insert(identity.clone());
|
||||
true
|
||||
}
|
||||
|
||||
pub fn exit_lambda(&mut self, identity: &Identity) {
|
||||
self.identity_stack.remove(identity);
|
||||
}
|
||||
}
|
||||
|
||||
// --- UsageInfo ---
|
||||
#[derive(Default)]
|
||||
pub struct UsageInfo {
|
||||
pub used: HashSet<Address<VirtualId>>,
|
||||
pub assigned: HashSet<Address<VirtualId>>,
|
||||
pub used_identities: HashSet<Identity>,
|
||||
}
|
||||
|
||||
impl UsageInfo {
|
||||
pub fn is_assigned(&self, addr: &Address<VirtualId>) -> bool {
|
||||
self.assigned.contains(addr)
|
||||
}
|
||||
|
||||
pub fn is_used(&self, addr: &Address<VirtualId>) -> bool {
|
||||
self.used.contains(addr)
|
||||
}
|
||||
|
||||
pub fn collect(&mut self, node: &AnalyzedNode) {
|
||||
match &node.kind {
|
||||
NodeKind::Def { pattern, value, .. } => {
|
||||
self.collect_pattern(pattern);
|
||||
self.collect(value);
|
||||
}
|
||||
NodeKind::Constant(v) => {
|
||||
if let Value::Object(obj) = v
|
||||
&& let Some(closure) = obj.as_any().downcast_ref::<Closure>()
|
||||
{
|
||||
self.used_identities
|
||||
.insert(closure.function_node.identity.clone());
|
||||
self.collect(&closure.function_node);
|
||||
}
|
||||
}
|
||||
NodeKind::Identifier { binding, .. } => {
|
||||
let addr = match binding {
|
||||
IdentifierBinding::Reference(addr) => *addr,
|
||||
IdentifierBinding::Declaration { addr, .. } => *addr,
|
||||
};
|
||||
self.used.insert(addr);
|
||||
}
|
||||
NodeKind::Assign { target, value, info, .. } => {
|
||||
if let Some(addr) = info.addr {
|
||||
self.assigned.insert(addr);
|
||||
} else {
|
||||
// Destructuring assign: collect assigned addresses from target pattern
|
||||
self.collect_assigned_from_target(target);
|
||||
}
|
||||
self.collect(value);
|
||||
}
|
||||
NodeKind::GetField { rec, .. } => {
|
||||
self.collect(rec);
|
||||
}
|
||||
NodeKind::Lambda {
|
||||
params,
|
||||
body,
|
||||
info: lambda_info,
|
||||
} => {
|
||||
self.used_identities.insert(node.identity.clone());
|
||||
|
||||
let mut inner_info = UsageInfo::default();
|
||||
inner_info.collect(params);
|
||||
inner_info.collect(body);
|
||||
|
||||
// Propagate globals and identities
|
||||
for addr in &inner_info.used {
|
||||
if let Address::Global(_) = addr {
|
||||
self.used.insert(*addr);
|
||||
}
|
||||
}
|
||||
for addr in &inner_info.assigned {
|
||||
if let Address::Global(_) = addr {
|
||||
self.assigned.insert(*addr);
|
||||
}
|
||||
}
|
||||
self.used_identities.extend(inner_info.used_identities);
|
||||
|
||||
// Map used upvalues to parent scope
|
||||
for addr in &inner_info.used {
|
||||
if let Address::Upvalue(idx) = addr
|
||||
&& let Some(parent_addr) = lambda_info.upvalues.get(idx.0 as usize)
|
||||
{
|
||||
self.used.insert(*parent_addr);
|
||||
}
|
||||
}
|
||||
// Map assigned upvalues to parent scope
|
||||
for addr in &inner_info.assigned {
|
||||
if let Address::Upvalue(idx) = addr
|
||||
&& let Some(parent_addr) = lambda_info.upvalues.get(idx.0 as usize)
|
||||
{
|
||||
self.assigned.insert(*parent_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
NodeKind::Block { exprs } => {
|
||||
for e in exprs {
|
||||
self.collect(e);
|
||||
}
|
||||
}
|
||||
NodeKind::If {
|
||||
cond,
|
||||
then_br,
|
||||
else_br,
|
||||
} => {
|
||||
self.collect(cond);
|
||||
self.collect(then_br);
|
||||
if let Some(e) = else_br {
|
||||
self.collect(e);
|
||||
}
|
||||
}
|
||||
NodeKind::Call { callee, args } => {
|
||||
self.collect(callee);
|
||||
self.collect(args);
|
||||
}
|
||||
NodeKind::Tuple { elements } => {
|
||||
for e in elements {
|
||||
self.collect(e);
|
||||
}
|
||||
}
|
||||
NodeKind::Record { fields, .. } => {
|
||||
for (_, v) in fields {
|
||||
self.collect(v);
|
||||
}
|
||||
}
|
||||
NodeKind::Expansion { expanded, .. } => {
|
||||
self.collect(expanded);
|
||||
}
|
||||
NodeKind::Again { args } => {
|
||||
self.collect(args);
|
||||
}
|
||||
NodeKind::Pipe { inputs, lambda, .. } => {
|
||||
for input in inputs {
|
||||
self.collect(input);
|
||||
}
|
||||
self.collect(lambda);
|
||||
}
|
||||
NodeKind::Nop
|
||||
| NodeKind::FieldAccessor(_)
|
||||
| NodeKind::Extension(_)
|
||||
| NodeKind::Error => {}
|
||||
// Syntax-only variants that should not appear in AnalyzedPhase
|
||||
NodeKind::MacroDecl { .. }
|
||||
| NodeKind::Template(_)
|
||||
| NodeKind::Placeholder(_)
|
||||
| NodeKind::Splice(_) => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn collect_pattern(&mut self, node: &AnalyzedNode) {
|
||||
match &node.kind {
|
||||
NodeKind::Identifier {
|
||||
binding: IdentifierBinding::Declaration { .. },
|
||||
..
|
||||
} => {}
|
||||
NodeKind::Def { .. } => {}
|
||||
NodeKind::Assign { info, .. } => {
|
||||
if let Some(addr) = info.addr {
|
||||
self.assigned.insert(addr);
|
||||
}
|
||||
}
|
||||
NodeKind::Tuple { elements } => {
|
||||
for el in elements {
|
||||
self.collect_pattern(el);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn collect_assigned_from_target(&mut self, node: &AnalyzedNode) {
|
||||
match &node.kind {
|
||||
NodeKind::Identifier { binding, .. } => {
|
||||
let addr = match binding {
|
||||
IdentifierBinding::Reference(addr)
|
||||
| IdentifierBinding::Declaration { addr, .. } => *addr,
|
||||
};
|
||||
self.assigned.insert(addr);
|
||||
}
|
||||
NodeKind::Tuple { elements } => {
|
||||
for el in elements {
|
||||
self.collect_assigned_from_target(el);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user