## Summary Extracted binding management into dedicated BindingContext struct, completing step 4 of 7 in the Context Box refactoring plan. ## Changes - NEW: src/mir/builder/binding_context.rs (BindingContext struct + helpers) - Modified 7 files to use binding_ctx (SSOT pattern with legacy sync) - Added comprehensive unit tests for BindingContext ## Extracted Fields - binding_map: BTreeMap<String, BindingId> → binding_ctx.binding_map ## Benefits - Clear separation: BindingId mapping isolated from MirBuilder - Better testability: BindingContext can be tested independently - Consistent pattern: Same SSOT + legacy sync approach as previous steps ## Tests - cargo test --release --lib: 1008/1008 passed - phase135_trim_mir_verify.sh: PASS - Backward compatibility: 100% maintained (deprecated fields synced) ## Progress Phase 136 Context Extraction: 4/7 complete (57%) - ✅ Step 1: TypeContext - ✅ Step 2: CoreContext - ✅ Step 3: ScopeContext - ✅ Step 4: BindingContext (this commit) - ⏳ Step 5: VariableContext - ⏳ Step 6: MetadataContext - ⏳ Step 7: RegionContext 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
138 lines
4.2 KiB
Rust
138 lines
4.2 KiB
Rust
//! Phase 136 follow-up (Step 4/7): BindingContext extraction
|
|
//!
|
|
//! Consolidates variable binding management:
|
|
//! - binding_map: String -> BindingId mapping (parallel to variable_map)
|
|
//! - BindingId allocation (via CoreContext.next_binding())
|
|
//! - Scope restoration logic (stored in ScopeContext frames)
|
|
//!
|
|
//! ## Relationship with other contexts:
|
|
//! - **CoreContext**: Allocates BindingId via next_binding()
|
|
//! - **ScopeContext**: Manages lexical scope frames with restore_binding data
|
|
//! - **TypeContext**: Independent (type tracking vs binding tracking)
|
|
//!
|
|
//! ## Design:
|
|
//! - BindingId tracks variable binding identity (survives SSA renaming)
|
|
//! - Parallel to ValueId (variable_map), but for binding semantics
|
|
//! - Restored on scope exit (see LexicalScopeFrame.restore_binding)
|
|
//!
|
|
//! Phase 74: BindingId system introduction
|
|
//! Phase 136 Step 4/7: Extraction into dedicated context
|
|
|
|
use crate::mir::BindingId;
|
|
use std::collections::BTreeMap;
|
|
|
|
/// Phase 136 Step 4/7: Binding context for variable binding management
|
|
///
|
|
/// Manages the mapping from variable names to their BindingId.
|
|
/// Parallel to `variable_map` (String -> ValueId), but tracks binding identity.
|
|
///
|
|
/// ## Key responsibilities:
|
|
/// - Maintain current binding_map (String -> BindingId)
|
|
/// - Provide lookup/insertion/removal operations
|
|
/// - Work with ScopeContext for scope-based restoration
|
|
///
|
|
/// ## Implementation note:
|
|
/// - Uses BTreeMap for deterministic iteration (Phase 25.1 consistency)
|
|
/// - BindingId allocation is delegated to CoreContext.next_binding()
|
|
#[derive(Debug, Clone)]
|
|
pub struct BindingContext {
|
|
/// Phase 74: BindingId mapping for lexical variable bindings
|
|
/// Maps variable names to their current BindingId.
|
|
/// Parallel to `variable_map` (String -> ValueId), but tracks binding identity.
|
|
/// Restored on lexical scope exit (see ScopeContext restore_binding).
|
|
pub(super) binding_map: BTreeMap<String, BindingId>,
|
|
}
|
|
|
|
impl Default for BindingContext {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl BindingContext {
|
|
/// Create a new BindingContext
|
|
pub fn new() -> Self {
|
|
Self {
|
|
binding_map: BTreeMap::new(),
|
|
}
|
|
}
|
|
|
|
/// Lookup a variable's BindingId
|
|
pub fn lookup(&self, name: &str) -> Option<BindingId> {
|
|
self.binding_map.get(name).copied()
|
|
}
|
|
|
|
/// Insert a variable binding
|
|
pub fn insert(&mut self, name: String, binding_id: BindingId) {
|
|
self.binding_map.insert(name, binding_id);
|
|
}
|
|
|
|
/// Remove a variable binding
|
|
pub fn remove(&mut self, name: &str) -> Option<BindingId> {
|
|
self.binding_map.remove(name)
|
|
}
|
|
|
|
/// Get immutable reference to the binding map (for BindingMapProvider)
|
|
pub fn binding_map(&self) -> &BTreeMap<String, BindingId> {
|
|
&self.binding_map
|
|
}
|
|
|
|
/// Check if a variable has a binding
|
|
pub fn contains(&self, name: &str) -> bool {
|
|
self.binding_map.contains_key(name)
|
|
}
|
|
|
|
/// Get the number of bindings
|
|
pub fn len(&self) -> usize {
|
|
self.binding_map.len()
|
|
}
|
|
|
|
/// Check if there are no bindings
|
|
pub fn is_empty(&self) -> bool {
|
|
self.binding_map.is_empty()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_binding_context_basic() {
|
|
let mut ctx = BindingContext::new();
|
|
assert!(ctx.is_empty());
|
|
assert_eq!(ctx.len(), 0);
|
|
|
|
let bid = BindingId::new(0);
|
|
ctx.insert("x".to_string(), bid);
|
|
assert_eq!(ctx.lookup("x"), Some(bid));
|
|
assert_eq!(ctx.len(), 1);
|
|
assert!(!ctx.is_empty());
|
|
|
|
ctx.remove("x");
|
|
assert_eq!(ctx.lookup("x"), None);
|
|
assert!(ctx.is_empty());
|
|
}
|
|
|
|
#[test]
|
|
fn test_binding_context_contains() {
|
|
let mut ctx = BindingContext::new();
|
|
assert!(!ctx.contains("x"));
|
|
|
|
ctx.insert("x".to_string(), BindingId::new(0));
|
|
assert!(ctx.contains("x"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_binding_map_access() {
|
|
let mut ctx = BindingContext::new();
|
|
ctx.insert("a".to_string(), BindingId::new(1));
|
|
ctx.insert("b".to_string(), BindingId::new(2));
|
|
|
|
let map = ctx.binding_map();
|
|
assert_eq!(map.len(), 2);
|
|
assert_eq!(map.get("a"), Some(&BindingId::new(1)));
|
|
assert_eq!(map.get("b"), Some(&BindingId::new(2)));
|
|
}
|
|
}
|