001package gudusoft.gsqlparser.ir.bound; 002 003import java.util.ArrayList; 004import java.util.Collections; 005import java.util.LinkedHashMap; 006import java.util.List; 007import java.util.Map; 008 009/** 010 * Aggregation root for the Bound IR phase output. 011 * <p> 012 * Contains all scopes, symbols, and references produced by the bound IR builder. 013 */ 014public class BoundProgram { 015 016 /** All scopes in the program (root scope first). */ 017 private final List<BoundScope> scopes; 018 019 /** Global routine symbol table indexed by routine ID (deterministic iteration order). */ 020 private final Map<String, BoundRoutineSymbol> routineIndex; 021 022 /** Multi-value index: uppercase routine name → list of routines with that name. */ 023 private final Map<String, List<BoundRoutineSymbol>> routinesByName; 024 025 /** All object references found during binding. */ 026 private final List<BoundObjectRef> allObjectRefs; 027 028 /** All column references found during binding. */ 029 private final List<BoundColumnRef> allColumnRefs; 030 031 /** All routine references found during binding. */ 032 private final List<BoundRoutineRef> allRoutineRefs; 033 034 public BoundProgram() { 035 this.scopes = new ArrayList<BoundScope>(); 036 this.routineIndex = new LinkedHashMap<String, BoundRoutineSymbol>(); 037 this.routinesByName = new LinkedHashMap<String, List<BoundRoutineSymbol>>(); 038 this.allObjectRefs = new ArrayList<BoundObjectRef>(); 039 this.allColumnRefs = new ArrayList<BoundColumnRef>(); 040 this.allRoutineRefs = new ArrayList<BoundRoutineRef>(); 041 } 042 043 public BoundProgram(List<BoundScope> scopes, 044 Map<String, BoundRoutineSymbol> routineIndex, 045 List<BoundObjectRef> allObjectRefs, 046 List<BoundColumnRef> allColumnRefs, 047 List<BoundRoutineRef> allRoutineRefs) { 048 this.scopes = scopes != null ? scopes : new ArrayList<BoundScope>(); 049 this.routineIndex = routineIndex != null 050 ? new LinkedHashMap<String, BoundRoutineSymbol>(routineIndex) 051 : new LinkedHashMap<String, BoundRoutineSymbol>(); 052 this.routinesByName = new LinkedHashMap<String, List<BoundRoutineSymbol>>(); 053 // Rebuild the by-name index from routineIndex 054 for (BoundRoutineSymbol sym : this.routineIndex.values()) { 055 addToNameIndex(sym); 056 } 057 this.allObjectRefs = allObjectRefs != null ? allObjectRefs : new ArrayList<BoundObjectRef>(); 058 this.allColumnRefs = allColumnRefs != null ? allColumnRefs : new ArrayList<BoundColumnRef>(); 059 this.allRoutineRefs = allRoutineRefs != null ? allRoutineRefs : new ArrayList<BoundRoutineRef>(); 060 } 061 062 public List<BoundScope> getScopes() { return scopes; } 063 public Map<String, BoundRoutineSymbol> getRoutineIndex() { 064 return Collections.unmodifiableMap(routineIndex); 065 } 066 public Map<String, List<BoundRoutineSymbol>> getRoutinesByName() { 067 return Collections.unmodifiableMap(routinesByName); 068 } 069 public List<BoundObjectRef> getAllObjectRefs() { return allObjectRefs; } 070 public List<BoundColumnRef> getAllColumnRefs() { return allColumnRefs; } 071 public List<BoundRoutineRef> getAllRoutineRefs() { return allRoutineRefs; } 072 073 public void addScope(BoundScope scope) { scopes.add(scope); } 074 075 public void registerRoutine(BoundRoutineSymbol routine) { 076 routineIndex.put(routine.getRoutineId(), routine); 077 addToNameIndex(routine); 078 } 079 080 private void addToNameIndex(BoundRoutineSymbol routine) { 081 String nameKey = routine.getRoutineName().toUpperCase(); 082 List<BoundRoutineSymbol> list = routinesByName.get(nameKey); 083 if (list == null) { 084 list = new ArrayList<BoundRoutineSymbol>(); 085 routinesByName.put(nameKey, list); 086 } 087 list.add(routine); 088 } 089 090 public void addObjectRef(BoundObjectRef ref) { allObjectRefs.add(ref); } 091 public void addColumnRef(BoundColumnRef ref) { allColumnRefs.add(ref); } 092 public void addRoutineRef(BoundRoutineRef ref) { allRoutineRefs.add(ref); } 093 094 /** 095 * Looks up a routine by its ID. 096 */ 097 public BoundRoutineSymbol lookupRoutine(String routineId) { 098 return routineIndex.get(routineId); 099 } 100 101 /** 102 * Replaces the entire routine ref list (used after post-resolution pass). 103 */ 104 public void replaceRoutineRefs(List<BoundRoutineRef> resolved) { 105 allRoutineRefs.clear(); 106 allRoutineRefs.addAll(resolved); 107 } 108 109 @Override 110 public String toString() { 111 return "BoundProgram{scopes=" + scopes.size() 112 + ", routines=" + routineIndex.size() 113 + ", objectRefs=" + allObjectRefs.size() 114 + ", columnRefs=" + allColumnRefs.size() 115 + ", routineRefs=" + allRoutineRefs.size() + "}"; 116 } 117}