c-next 0.1.70 → 0.1.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/package.json +1 -1
  2. package/src/lib/__tests__/parseCHeader.mocked.test.ts +69 -54
  3. package/src/lib/parseCHeader.ts +56 -23
  4. package/src/lib/parseWithSymbols.ts +195 -53
  5. package/src/transpiler/Transpiler.ts +180 -63
  6. package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +1 -2
  7. package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +1 -2
  8. package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +51 -2
  9. package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +18 -12
  10. package/src/transpiler/logic/analysis/__tests__/InitializationAnalyzer.test.ts +9 -9
  11. package/src/transpiler/logic/analysis/__tests__/runAnalyzers.test.ts +5 -5
  12. package/src/transpiler/logic/symbols/SymbolTable.ts +729 -265
  13. package/src/transpiler/logic/symbols/SymbolUtils.ts +2 -2
  14. package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +415 -751
  15. package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +573 -0
  16. package/src/transpiler/logic/symbols/c/__tests__/testHelpers.ts +20 -0
  17. package/src/transpiler/logic/symbols/c/collectors/EnumCollector.ts +82 -0
  18. package/src/transpiler/logic/symbols/c/collectors/FunctionCollector.ts +106 -0
  19. package/src/transpiler/logic/symbols/c/collectors/StructCollector.ts +173 -0
  20. package/src/transpiler/logic/symbols/c/collectors/TypedefCollector.ts +35 -0
  21. package/src/transpiler/logic/symbols/c/collectors/VariableCollector.ts +80 -0
  22. package/src/transpiler/logic/symbols/c/index.ts +333 -0
  23. package/src/transpiler/logic/symbols/c/utils/DeclaratorUtils.ts +269 -0
  24. package/src/transpiler/logic/symbols/cnext/__tests__/BitmapCollector.test.ts +50 -11
  25. package/src/transpiler/logic/symbols/cnext/__tests__/CNextResolver.integration.test.ts +45 -34
  26. package/src/transpiler/logic/symbols/cnext/__tests__/EnumCollector.test.ts +30 -13
  27. package/src/transpiler/logic/symbols/cnext/__tests__/FunctionCollector.test.ts +279 -64
  28. package/src/transpiler/logic/symbols/cnext/__tests__/RegisterCollector.test.ts +60 -13
  29. package/src/transpiler/logic/symbols/cnext/__tests__/ScopeCollector.test.ts +40 -37
  30. package/src/transpiler/logic/symbols/cnext/__tests__/StructCollector.test.ts +131 -45
  31. package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolInfoAdapter.test.ts +223 -139
  32. package/src/transpiler/logic/symbols/cnext/__tests__/VariableCollector.test.ts +79 -25
  33. package/src/transpiler/logic/symbols/cnext/__tests__/testUtils.ts +53 -0
  34. package/src/transpiler/logic/symbols/cnext/adapters/TSymbolInfoAdapter.ts +83 -43
  35. package/src/transpiler/logic/symbols/cnext/collectors/BitmapCollector.ts +14 -13
  36. package/src/transpiler/logic/symbols/cnext/collectors/EnumCollector.ts +11 -10
  37. package/src/transpiler/logic/symbols/cnext/collectors/FunctionCollector.ts +83 -34
  38. package/src/transpiler/logic/symbols/cnext/collectors/RegisterCollector.ts +22 -18
  39. package/src/transpiler/logic/symbols/cnext/collectors/ScopeCollector.ts +53 -35
  40. package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +30 -23
  41. package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +18 -19
  42. package/src/transpiler/logic/symbols/cnext/index.ts +36 -14
  43. package/src/transpiler/logic/symbols/cnext/types/IScopeCollectorResult.ts +2 -2
  44. package/src/transpiler/logic/symbols/cnext/utils/SymbolNameUtils.ts +27 -0
  45. package/src/transpiler/logic/symbols/cpp/__tests__/CppResolver.integration.test.ts +270 -0
  46. package/src/transpiler/logic/symbols/cpp/__tests__/testHelpers.ts +20 -0
  47. package/src/transpiler/logic/symbols/cpp/collectors/ClassCollector.ts +317 -0
  48. package/src/transpiler/logic/symbols/cpp/collectors/EnumCollector.ts +71 -0
  49. package/src/transpiler/logic/symbols/cpp/collectors/FunctionCollector.ts +155 -0
  50. package/src/transpiler/logic/symbols/cpp/collectors/NamespaceCollector.ts +65 -0
  51. package/src/transpiler/logic/symbols/cpp/collectors/TypeAliasCollector.ts +46 -0
  52. package/src/transpiler/logic/symbols/cpp/collectors/VariableCollector.ts +54 -0
  53. package/src/transpiler/logic/symbols/cpp/index.ts +366 -0
  54. package/src/transpiler/logic/symbols/cpp/utils/DeclaratorUtils.ts +248 -0
  55. package/src/transpiler/logic/symbols/shared/IExtractedParameter.ts +18 -0
  56. package/src/transpiler/logic/symbols/shared/ParameterExtractorUtils.ts +73 -0
  57. package/src/transpiler/output/codegen/CodeGenerator.ts +268 -1674
  58. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +7 -1
  59. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +2 -1
  60. package/src/transpiler/output/codegen/assignment/handlers/AssignmentHandlerUtils.ts +7 -1
  61. package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +6 -2
  62. package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +2 -1
  63. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +21 -8
  64. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopedRegisterGenerator.ts +3 -2
  65. package/src/transpiler/output/codegen/generators/expressions/CallExprUtils.ts +9 -3
  66. package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +3 -4
  67. package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprUtils.test.ts +4 -8
  68. package/src/transpiler/output/codegen/helpers/ArgumentGenerator.ts +236 -0
  69. package/src/transpiler/output/codegen/helpers/CppConstructorHelper.ts +3 -3
  70. package/src/transpiler/output/codegen/helpers/FunctionContextManager.ts +435 -0
  71. package/src/transpiler/output/codegen/helpers/StringOperationsHelper.ts +203 -0
  72. package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +8 -12
  73. package/src/transpiler/output/codegen/helpers/TypeRegistrationEngine.ts +520 -0
  74. package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +735 -0
  75. package/src/transpiler/output/codegen/helpers/VariableDeclarationFormatter.ts +1 -1
  76. package/src/transpiler/output/codegen/helpers/__tests__/ArgumentGenerator.test.ts +521 -0
  77. package/src/transpiler/output/codegen/helpers/__tests__/CppConstructorHelper.test.ts +4 -5
  78. package/src/transpiler/output/codegen/helpers/__tests__/FunctionContextManager.test.ts +983 -0
  79. package/src/transpiler/output/codegen/helpers/__tests__/StringOperationsHelper.test.ts +269 -0
  80. package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +31 -32
  81. package/src/transpiler/output/codegen/helpers/__tests__/TypeRegistrationEngine.test.ts +186 -0
  82. package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclHelper.test.ts +460 -0
  83. package/src/transpiler/output/codegen/helpers/types/IArgumentGeneratorCallbacks.ts +32 -0
  84. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +5 -1
  85. package/src/transpiler/output/codegen/types/IFunctionContextCallbacks.ts +12 -0
  86. package/src/transpiler/output/codegen/types/IVariableFormatInput.ts +1 -1
  87. package/src/transpiler/output/codegen/utils/QualifiedNameGenerator.ts +114 -0
  88. package/src/transpiler/output/codegen/utils/__tests__/QualifiedNameGenerator.test.ts +183 -0
  89. package/src/transpiler/output/headers/BaseHeaderGenerator.ts +4 -4
  90. package/src/transpiler/output/headers/ExternalTypeHeaderBuilder.ts +7 -7
  91. package/src/transpiler/output/headers/HeaderGenerator.ts +9 -7
  92. package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +19 -20
  93. package/src/transpiler/output/headers/__tests__/BaseHeaderGenerator.test.ts +15 -18
  94. package/src/transpiler/output/headers/__tests__/CHeaderGenerator.test.ts +63 -64
  95. package/src/transpiler/output/headers/__tests__/CppHeaderGenerator.test.ts +36 -32
  96. package/src/transpiler/output/headers/__tests__/ExternalTypeHeaderBuilder.test.ts +26 -26
  97. package/src/transpiler/output/headers/__tests__/HeaderGenerator.test.ts +87 -59
  98. package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +57 -58
  99. package/src/transpiler/output/headers/adapters/HeaderSymbolAdapter.ts +222 -0
  100. package/src/transpiler/output/headers/adapters/__tests__/HeaderSymbolAdapter.test.ts +538 -0
  101. package/src/transpiler/output/headers/types/IGroupedSymbols.ts +8 -8
  102. package/src/transpiler/output/headers/types/IHeaderSymbol.ts +62 -0
  103. package/src/transpiler/state/CodeGenState.ts +20 -33
  104. package/src/transpiler/state/SymbolRegistry.ts +181 -0
  105. package/src/transpiler/{types → state}/TranspilerState.ts +1 -1
  106. package/src/transpiler/state/__tests__/CodeGenState.test.ts +67 -59
  107. package/src/transpiler/state/__tests__/SymbolRegistry.test.ts +249 -0
  108. package/src/transpiler/{types → state}/__tests__/TranspilerState.test.ts +1 -1
  109. package/src/transpiler/types/ICachedFileEntry.ts +1 -1
  110. package/src/transpiler/types/IConflict.ts +14 -0
  111. package/src/transpiler/types/IPipelineInput.ts +0 -3
  112. package/src/transpiler/types/ISerializedSymbol.ts +11 -0
  113. package/src/transpiler/types/TPrimitiveKind.ts +20 -0
  114. package/src/transpiler/types/TType.ts +103 -0
  115. package/src/transpiler/types/TVisibility.ts +6 -0
  116. package/src/transpiler/types/symbol-kinds/TSymbolKind.ts +10 -0
  117. package/src/transpiler/types/symbol-kinds/TSymbolKindC.ts +12 -0
  118. package/src/transpiler/types/symbol-kinds/TSymbolKindCNext.ts +16 -0
  119. package/src/transpiler/types/symbol-kinds/TSymbolKindCpp.ts +14 -0
  120. package/src/transpiler/types/symbols/IBaseSymbol.ts +31 -0
  121. package/src/transpiler/{logic/symbols/types → types/symbols}/IBitmapFieldInfo.ts +2 -2
  122. package/src/transpiler/types/symbols/IBitmapSymbol.ts +21 -0
  123. package/src/transpiler/{logic/symbols/types → types/symbols}/IEnumSymbol.ts +5 -6
  124. package/src/transpiler/types/symbols/IFieldInfo.ts +26 -0
  125. package/src/transpiler/types/symbols/IFunctionSymbol.ts +30 -0
  126. package/src/transpiler/types/symbols/IParameterInfo.ts +26 -0
  127. package/src/transpiler/{logic/symbols/types → types/symbols}/IRegisterMemberInfo.ts +4 -4
  128. package/src/transpiler/types/symbols/IRegisterSymbol.ts +18 -0
  129. package/src/transpiler/types/symbols/IScopeSymbol.ts +32 -0
  130. package/src/transpiler/{logic/symbols/types → types/symbols}/IStructFieldInfo.ts +2 -1
  131. package/src/transpiler/types/symbols/IStructSymbol.ts +15 -0
  132. package/src/transpiler/types/symbols/IVariableSymbol.ts +30 -0
  133. package/src/transpiler/types/symbols/SymbolGuards.ts +43 -0
  134. package/src/transpiler/types/symbols/TAnySymbol.ts +22 -0
  135. package/src/transpiler/types/symbols/TSymbol.ts +32 -0
  136. package/src/transpiler/types/symbols/__tests__/IBaseSymbol.test.ts +56 -0
  137. package/src/transpiler/types/symbols/__tests__/SymbolGuards.test.ts +57 -0
  138. package/src/transpiler/types/symbols/c/ICBaseSymbol.ts +28 -0
  139. package/src/transpiler/types/symbols/c/ICEnumMemberSymbol.ts +17 -0
  140. package/src/transpiler/types/symbols/c/ICEnumSymbol.ts +17 -0
  141. package/src/transpiler/types/symbols/c/ICFieldInfo.ts +16 -0
  142. package/src/transpiler/types/symbols/c/ICFunctionSymbol.ts +21 -0
  143. package/src/transpiler/types/symbols/c/ICParameterInfo.ts +19 -0
  144. package/src/transpiler/types/symbols/c/ICStructSymbol.ts +21 -0
  145. package/src/transpiler/types/symbols/c/ICTypedefSymbol.ts +14 -0
  146. package/src/transpiler/types/symbols/c/ICVariableSymbol.ts +26 -0
  147. package/src/transpiler/types/symbols/c/TCSymbol.ts +26 -0
  148. package/src/transpiler/types/symbols/cpp/ICppBaseSymbol.ts +31 -0
  149. package/src/transpiler/types/symbols/cpp/ICppClassSymbol.ts +15 -0
  150. package/src/transpiler/types/symbols/cpp/ICppEnumMemberSymbol.ts +14 -0
  151. package/src/transpiler/types/symbols/cpp/ICppEnumSymbol.ts +14 -0
  152. package/src/transpiler/types/symbols/cpp/ICppFieldInfo.ts +16 -0
  153. package/src/transpiler/types/symbols/cpp/ICppFunctionSymbol.ts +21 -0
  154. package/src/transpiler/types/symbols/cpp/ICppNamespaceSymbol.ts +11 -0
  155. package/src/transpiler/types/symbols/cpp/ICppParameterInfo.ts +19 -0
  156. package/src/transpiler/types/symbols/cpp/ICppStructSymbol.ts +16 -0
  157. package/src/transpiler/types/symbols/cpp/ICppTypeAliasSymbol.ts +14 -0
  158. package/src/transpiler/types/symbols/cpp/ICppVariableSymbol.ts +23 -0
  159. package/src/transpiler/types/symbols/cpp/TCppSymbol.ts +30 -0
  160. package/src/utils/CppNamespaceUtils.ts +3 -4
  161. package/src/utils/FunctionUtils.ts +92 -0
  162. package/src/utils/ParameterUtils.ts +55 -0
  163. package/src/utils/PrimitiveKindUtils.ts +33 -0
  164. package/src/utils/ScopeUtils.ts +105 -0
  165. package/src/utils/TTypeUtils.ts +159 -0
  166. package/src/utils/TypeResolver.ts +132 -0
  167. package/src/utils/__tests__/CppNamespaceUtils.test.ts +92 -99
  168. package/src/utils/__tests__/FunctionUtils.test.ts +284 -0
  169. package/src/utils/__tests__/ParameterUtils.test.ts +174 -0
  170. package/src/utils/__tests__/PrimitiveKindUtils.test.ts +59 -0
  171. package/src/utils/__tests__/ScopeUtils.test.ts +53 -0
  172. package/src/utils/__tests__/TTypeUtils.test.ts +245 -0
  173. package/src/utils/__tests__/TypeResolver.test.ts +332 -0
  174. package/src/utils/cache/CacheManager.ts +91 -50
  175. package/src/utils/cache/__tests__/CacheManager.test.ts +180 -114
  176. package/src/transpiler/logic/symbols/AutoConstUpdater.ts +0 -93
  177. package/src/transpiler/logic/symbols/CSymbolCollector.ts +0 -648
  178. package/src/transpiler/logic/symbols/CppSymbolCollector.ts +0 -874
  179. package/src/transpiler/logic/symbols/SymbolCollectorContext.ts +0 -68
  180. package/src/transpiler/logic/symbols/__tests__/AutoConstUpdater.test.ts +0 -418
  181. package/src/transpiler/logic/symbols/__tests__/CSymbolCollector.test.ts +0 -685
  182. package/src/transpiler/logic/symbols/__tests__/CppSymbolCollector.test.ts +0 -1146
  183. package/src/transpiler/logic/symbols/__tests__/SymbolCollectorContext.test.ts +0 -290
  184. package/src/transpiler/logic/symbols/__tests__/cTestHelpers.ts +0 -43
  185. package/src/transpiler/logic/symbols/__tests__/cppTestHelpers.ts +0 -40
  186. package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolAdapter.test.ts +0 -595
  187. package/src/transpiler/logic/symbols/cnext/adapters/TSymbolAdapter.ts +0 -345
  188. package/src/transpiler/logic/symbols/types/IBaseSymbol.ts +0 -27
  189. package/src/transpiler/logic/symbols/types/IBitmapSymbol.ts +0 -23
  190. package/src/transpiler/logic/symbols/types/ICollectorContext.ts +0 -19
  191. package/src/transpiler/logic/symbols/types/IConflict.ts +0 -20
  192. package/src/transpiler/logic/symbols/types/IFieldInfo.ts +0 -18
  193. package/src/transpiler/logic/symbols/types/IFunctionSymbol.ts +0 -25
  194. package/src/transpiler/logic/symbols/types/IParameterInfo.ts +0 -24
  195. package/src/transpiler/logic/symbols/types/IRegisterSymbol.ts +0 -20
  196. package/src/transpiler/logic/symbols/types/IScopeSymbol.ts +0 -19
  197. package/src/transpiler/logic/symbols/types/IStructSymbol.ts +0 -16
  198. package/src/transpiler/logic/symbols/types/IVariableSymbol.ts +0 -30
  199. package/src/transpiler/logic/symbols/types/TSymbol.ts +0 -36
  200. package/src/transpiler/logic/symbols/types/__tests__/SymbolGuards.test.ts +0 -244
  201. package/src/transpiler/logic/symbols/types/typeGuards.ts +0 -44
  202. package/src/utils/types/ESymbolKind.ts +0 -19
  203. package/src/utils/types/ISymbol.ts +0 -64
  204. /package/src/transpiler/{types → constants}/BITMAP_BACKING_TYPE.ts +0 -0
  205. /package/src/transpiler/{types → constants}/BITMAP_SIZE.ts +0 -0
@@ -1,14 +1,27 @@
1
1
  /**
2
2
  * Unified Symbol Table
3
3
  * Stores symbols from all source languages and detects conflicts
4
+ *
5
+ * ADR-055 Phase 7: Fully typed symbol storage using discriminated unions.
6
+ * - TSymbol: C-Next symbols (rich type system with TType)
7
+ * - TCSymbol: C header symbols (string types)
8
+ * - TCppSymbol: C++ header symbols (string types)
4
9
  */
5
10
 
6
- import ISymbol from "../../../utils/types/ISymbol";
7
11
  import ESourceLanguage from "../../../utils/types/ESourceLanguage";
8
- import ESymbolKind from "../../../utils/types/ESymbolKind";
9
12
  import LiteralUtils from "../../../utils/LiteralUtils";
10
- import IConflict from "./types/IConflict";
11
- import IStructFieldInfo from "./types/IStructFieldInfo";
13
+ import IConflict from "../../types/IConflict";
14
+ import IStructFieldInfo from "../../types/symbols/IStructFieldInfo";
15
+ import TSymbol from "../../types/symbols/TSymbol";
16
+ import TCSymbol from "../../types/symbols/c/TCSymbol";
17
+ import TCppSymbol from "../../types/symbols/cpp/TCppSymbol";
18
+ import TAnySymbol from "../../types/symbols/TAnySymbol";
19
+ import IStructSymbol from "../../types/symbols/IStructSymbol";
20
+ import IEnumSymbol from "../../types/symbols/IEnumSymbol";
21
+ import IFunctionSymbol from "../../types/symbols/IFunctionSymbol";
22
+ import IVariableSymbol from "../../types/symbols/IVariableSymbol";
23
+ import TypeResolver from "../../../utils/TypeResolver";
24
+ import SymbolNameUtils from "./cnext/utils/SymbolNameUtils";
12
25
 
13
26
  /**
14
27
  * Central symbol table for cross-language interoperability
@@ -19,11 +32,39 @@ import IStructFieldInfo from "./types/IStructFieldInfo";
19
32
  * - OK: Function overloads in C++ (different signatures)
20
33
  */
21
34
  class SymbolTable {
22
- /** All symbols indexed by name */
23
- private readonly symbols: Map<string, ISymbol[]> = new Map();
35
+ // ========================================================================
36
+ // C-Next Symbol Storage (TSymbol)
37
+ // ========================================================================
38
+
39
+ /** All C-Next TSymbols indexed by name */
40
+ private readonly tSymbols: Map<string, TSymbol[]> = new Map();
41
+
42
+ /** C-Next TSymbols indexed by source file */
43
+ private readonly tSymbolsByFile: Map<string, TSymbol[]> = new Map();
44
+
45
+ // ========================================================================
46
+ // C Symbol Storage (TCSymbol)
47
+ // ========================================================================
48
+
49
+ /** All C symbols indexed by name */
50
+ private readonly cSymbols: Map<string, TCSymbol[]> = new Map();
51
+
52
+ /** C symbols indexed by source file */
53
+ private readonly cSymbolsByFile: Map<string, TCSymbol[]> = new Map();
54
+
55
+ // ========================================================================
56
+ // C++ Symbol Storage (TCppSymbol)
57
+ // ========================================================================
58
+
59
+ /** All C++ symbols indexed by name */
60
+ private readonly cppSymbols: Map<string, TCppSymbol[]> = new Map();
24
61
 
25
- /** Symbols indexed by source file */
26
- private readonly byFile: Map<string, ISymbol[]> = new Map();
62
+ /** C++ symbols indexed by source file */
63
+ private readonly cppSymbolsByFile: Map<string, TCppSymbol[]> = new Map();
64
+
65
+ // ========================================================================
66
+ // Auxiliary Data (shared across languages)
67
+ // ========================================================================
27
68
 
28
69
  /** Struct field information: struct name -> (field name -> field info) */
29
70
  private readonly structFields: Map<string, Map<string, IStructFieldInfo>> =
@@ -42,331 +83,466 @@ class SymbolTable {
42
83
  */
43
84
  private readonly enumBitWidth: Map<string, number> = new Map();
44
85
 
86
+ // ========================================================================
87
+ // C-Next Symbol Methods (TSymbol)
88
+ // ========================================================================
89
+
45
90
  /**
46
- * Add a symbol to the table
91
+ * Add a C-Next TSymbol to the table
47
92
  */
48
- addSymbol(symbol: ISymbol): void {
93
+ addTSymbol(symbol: TSymbol): void {
49
94
  // Add to name index
50
- const existing = this.symbols.get(symbol.name);
95
+ const existing = this.tSymbols.get(symbol.name);
51
96
  if (existing) {
52
97
  existing.push(symbol);
53
98
  } else {
54
- this.symbols.set(symbol.name, [symbol]);
99
+ this.tSymbols.set(symbol.name, [symbol]);
55
100
  }
56
101
 
57
102
  // Add to file index
58
- const fileSymbols = this.byFile.get(symbol.sourceFile);
103
+ const fileSymbols = this.tSymbolsByFile.get(symbol.sourceFile);
59
104
  if (fileSymbols) {
60
105
  fileSymbols.push(symbol);
61
106
  } else {
62
- this.byFile.set(symbol.sourceFile, [symbol]);
107
+ this.tSymbolsByFile.set(symbol.sourceFile, [symbol]);
108
+ }
109
+
110
+ // Auto-register struct fields for TypeResolver.getMemberTypeInfo()
111
+ if (symbol.kind === "struct") {
112
+ this.registerStructFields(symbol);
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Register struct fields in structFields map for cross-file type resolution.
118
+ * Called automatically when adding struct symbols.
119
+ */
120
+ private registerStructFields(struct: IStructSymbol): void {
121
+ const mangledName = SymbolNameUtils.getMangledName(struct);
122
+
123
+ for (const [fieldName, fieldInfo] of struct.fields) {
124
+ // Convert TType to string for structFields map
125
+ const typeString = TypeResolver.getTypeName(fieldInfo.type);
126
+
127
+ // Filter to only numeric dimensions (structFields doesn't support string dims)
128
+ const numericDims = fieldInfo.dimensions?.filter(
129
+ (d): d is number => typeof d === "number",
130
+ );
131
+
132
+ this.addStructField(
133
+ mangledName,
134
+ fieldName,
135
+ typeString,
136
+ numericDims && numericDims.length > 0 ? numericDims : undefined,
137
+ );
63
138
  }
64
139
  }
65
140
 
66
141
  /**
67
- * Add multiple symbols at once
142
+ * Add multiple C-Next TSymbols at once
68
143
  */
69
- addSymbols(symbols: ISymbol[]): void {
144
+ addTSymbols(symbols: TSymbol[]): void {
70
145
  for (const symbol of symbols) {
71
- this.addSymbol(symbol);
146
+ this.addTSymbol(symbol);
72
147
  }
73
148
  }
74
149
 
75
150
  /**
76
- * Get a symbol by name (returns first match, or undefined)
151
+ * Get a TSymbol by name (returns first match, or undefined)
77
152
  */
78
- getSymbol(name: string): ISymbol | undefined {
79
- const symbols = this.symbols.get(name);
153
+ getTSymbol(name: string): TSymbol | undefined {
154
+ const symbols = this.tSymbols.get(name);
80
155
  return symbols?.[0];
81
156
  }
82
157
 
83
158
  /**
84
- * Get all symbols with a given name (for overload detection)
159
+ * Get all TSymbols with a given name (for overload detection)
85
160
  */
86
- getOverloads(name: string): ISymbol[] {
87
- return this.symbols.get(name) ?? [];
161
+ getTOverloads(name: string): TSymbol[] {
162
+ return this.tSymbols.get(name) ?? [];
88
163
  }
89
164
 
90
165
  /**
91
- * Check if a symbol exists
166
+ * Get TSymbols by source file
92
167
  */
93
- hasSymbol(name: string): boolean {
94
- return this.symbols.has(name);
168
+ getTSymbolsByFile(file: string): TSymbol[] {
169
+ return this.tSymbolsByFile.get(file) ?? [];
95
170
  }
96
171
 
97
172
  /**
98
- * Check if a symbol has conflicts
173
+ * Get all TSymbols
99
174
  */
100
- hasConflict(name: string): boolean {
101
- const symbols = this.symbols.get(name);
102
- if (!symbols || symbols.length <= 1) {
103
- return false;
175
+ getAllTSymbols(): TSymbol[] {
176
+ const result: TSymbol[] = [];
177
+ for (const symbols of this.tSymbols.values()) {
178
+ result.push(...symbols);
104
179
  }
180
+ return result;
181
+ }
182
+
183
+ /**
184
+ * Get all struct symbols (type-safe filtering)
185
+ */
186
+ getStructSymbols(): IStructSymbol[] {
187
+ return this.getAllTSymbols().filter(
188
+ (s): s is IStructSymbol => s.kind === "struct",
189
+ );
190
+ }
105
191
 
106
- return this.detectConflict(symbols) !== null;
192
+ /**
193
+ * Get all enum symbols (type-safe filtering)
194
+ */
195
+ getEnumSymbols(): IEnumSymbol[] {
196
+ return this.getAllTSymbols().filter(
197
+ (s): s is IEnumSymbol => s.kind === "enum",
198
+ );
107
199
  }
108
200
 
109
201
  /**
110
- * Get all conflicts in the symbol table
111
- * Per user requirement: Strict errors for cross-language conflicts
202
+ * Get all function symbols (type-safe filtering)
112
203
  */
113
- getConflicts(): IConflict[] {
114
- const conflicts: IConflict[] = [];
204
+ getFunctionSymbols(): IFunctionSymbol[] {
205
+ return this.getAllTSymbols().filter(
206
+ (s): s is IFunctionSymbol => s.kind === "function",
207
+ );
208
+ }
115
209
 
116
- for (const [, symbols] of this.symbols) {
117
- if (symbols.length <= 1) continue;
210
+ /**
211
+ * Get all variable symbols (type-safe filtering)
212
+ */
213
+ getVariableSymbols(): IVariableSymbol[] {
214
+ return this.getAllTSymbols().filter(
215
+ (s): s is IVariableSymbol => s.kind === "variable",
216
+ );
217
+ }
118
218
 
119
- const conflict = this.detectConflict(symbols);
120
- if (conflict) {
121
- conflicts.push(conflict);
122
- }
219
+ /**
220
+ * Get struct field type directly from TSymbol storage.
221
+ * This method queries IStructSymbol.fields directly, eliminating the need
222
+ * for the separate structFields Map for C-Next symbols.
223
+ *
224
+ * @param structName Name of the struct
225
+ * @param fieldName Name of the field
226
+ * @returns Field type string or undefined if not found
227
+ */
228
+ getTStructFieldType(
229
+ structName: string,
230
+ fieldName: string,
231
+ ): string | undefined {
232
+ const struct = this.getTOverloads(structName).find(
233
+ (s): s is IStructSymbol => s.kind === "struct",
234
+ );
235
+ if (!struct) {
236
+ return undefined;
123
237
  }
124
-
125
- return conflicts;
238
+ const field = struct.fields.get(fieldName);
239
+ return field ? TypeResolver.getTypeName(field.type) : undefined;
126
240
  }
127
241
 
128
242
  /**
129
- * Get symbols by source file
243
+ * Check if a TSymbol exists by name
130
244
  */
131
- getSymbolsByFile(file: string): ISymbol[] {
132
- return this.byFile.get(file) ?? [];
245
+ hasTSymbol(name: string): boolean {
246
+ return this.tSymbols.has(name);
133
247
  }
134
248
 
135
249
  /**
136
- * Get symbols by source language
250
+ * Get TSymbol count
137
251
  */
138
- getSymbolsByLanguage(lang: ESourceLanguage): ISymbol[] {
139
- const result: ISymbol[] = [];
140
- for (const symbols of this.symbols.values()) {
141
- for (const symbol of symbols) {
142
- if (symbol.sourceLanguage === lang) {
143
- result.push(symbol);
144
- }
145
- }
252
+ getTSize(): number {
253
+ let count = 0;
254
+ for (const symbols of this.tSymbols.values()) {
255
+ count += symbols.length;
146
256
  }
147
- return result;
257
+ return count;
148
258
  }
149
259
 
260
+ // ========================================================================
261
+ // C Symbol Methods (TCSymbol)
262
+ // ========================================================================
263
+
150
264
  /**
151
- * Get all symbols
265
+ * Add a C symbol to the table
152
266
  */
153
- getAllSymbols(): ISymbol[] {
154
- const result: ISymbol[] = [];
155
- for (const symbols of this.symbols.values()) {
156
- result.push(...symbols);
267
+ addCSymbol(symbol: TCSymbol): void {
268
+ // Add to name index
269
+ const existing = this.cSymbols.get(symbol.name);
270
+ if (existing) {
271
+ existing.push(symbol);
272
+ } else {
273
+ this.cSymbols.set(symbol.name, [symbol]);
274
+ }
275
+
276
+ // Add to file index
277
+ const fileSymbols = this.cSymbolsByFile.get(symbol.sourceFile);
278
+ if (fileSymbols) {
279
+ fileSymbols.push(symbol);
280
+ } else {
281
+ this.cSymbolsByFile.set(symbol.sourceFile, [symbol]);
157
282
  }
158
- return result;
159
283
  }
160
284
 
161
285
  /**
162
- * Add struct field information
163
- * @param structName Name of the struct
164
- * @param fieldName Name of the field
165
- * @param fieldType Type of the field (e.g., "uint32_t")
166
- * @param arrayDimensions Optional array dimensions if field is an array
286
+ * Add multiple C symbols at once
167
287
  */
168
- addStructField(
169
- structName: string,
170
- fieldName: string,
171
- fieldType: string,
172
- arrayDimensions?: number[],
173
- ): void {
174
- let fields = this.structFields.get(structName);
175
- if (!fields) {
176
- fields = new Map();
177
- this.structFields.set(structName, fields);
288
+ addCSymbols(symbols: TCSymbol[]): void {
289
+ for (const symbol of symbols) {
290
+ this.addCSymbol(symbol);
178
291
  }
179
-
180
- fields.set(fieldName, {
181
- type: fieldType,
182
- arrayDimensions,
183
- });
184
292
  }
185
293
 
186
294
  /**
187
- * Get struct field type
188
- * @param structName Name of the struct
189
- * @param fieldName Name of the field
190
- * @returns Field type or undefined if not found
295
+ * Get a C symbol by name (returns first match, or undefined)
191
296
  */
192
- getStructFieldType(
193
- structName: string,
194
- fieldName: string,
195
- ): string | undefined {
196
- const fields = this.structFields.get(structName);
197
- return fields?.get(fieldName)?.type;
297
+ getCSymbol(name: string): TCSymbol | undefined {
298
+ const symbols = this.cSymbols.get(name);
299
+ return symbols?.[0];
198
300
  }
199
301
 
200
302
  /**
201
- * Get struct field info (type and array dimensions)
202
- * @param structName Name of the struct
203
- * @param fieldName Name of the field
204
- * @returns Field info or undefined if not found
303
+ * Get all C symbols with a given name
205
304
  */
206
- getStructFieldInfo(
207
- structName: string,
208
- fieldName: string,
209
- ): IStructFieldInfo | undefined {
210
- const fields = this.structFields.get(structName);
211
- return fields?.get(fieldName);
305
+ getCOverloads(name: string): TCSymbol[] {
306
+ return this.cSymbols.get(name) ?? [];
212
307
  }
213
308
 
214
309
  /**
215
- * Issue #196 Bug 3: Mark a struct as requiring 'struct' keyword in C
216
- * @param structName Name of the struct (e.g., "NamedPoint")
310
+ * Get C symbols by source file
217
311
  */
218
- markNeedsStructKeyword(structName: string): void {
219
- this.needsStructKeyword.add(structName);
312
+ getCSymbolsByFile(file: string): TCSymbol[] {
313
+ return this.cSymbolsByFile.get(file) ?? [];
220
314
  }
221
315
 
222
316
  /**
223
- * Issue #196 Bug 3: Check if a struct requires 'struct' keyword in C
224
- * @param structName Name of the struct
225
- * @returns true if the struct was defined as 'struct Name { ... }' without typedef
317
+ * Get all C symbols
226
318
  */
227
- checkNeedsStructKeyword(structName: string): boolean {
228
- return this.needsStructKeyword.has(structName);
319
+ getAllCSymbols(): TCSymbol[] {
320
+ const result: TCSymbol[] = [];
321
+ for (const symbols of this.cSymbols.values()) {
322
+ result.push(...symbols);
323
+ }
324
+ return result;
229
325
  }
230
326
 
327
+ // ========================================================================
328
+ // C++ Symbol Methods (TCppSymbol)
329
+ // ========================================================================
330
+
231
331
  /**
232
- * Issue #196 Bug 3: Get all struct names requiring 'struct' keyword
233
- * @returns Array of struct names
332
+ * Add a C++ symbol to the table
234
333
  */
235
- getAllNeedsStructKeyword(): string[] {
236
- return Array.from(this.needsStructKeyword);
334
+ addCppSymbol(symbol: TCppSymbol): void {
335
+ // Add to name index
336
+ const existing = this.cppSymbols.get(symbol.name);
337
+ if (existing) {
338
+ existing.push(symbol);
339
+ } else {
340
+ this.cppSymbols.set(symbol.name, [symbol]);
341
+ }
342
+
343
+ // Add to file index
344
+ const fileSymbols = this.cppSymbolsByFile.get(symbol.sourceFile);
345
+ if (fileSymbols) {
346
+ fileSymbols.push(symbol);
347
+ } else {
348
+ this.cppSymbolsByFile.set(symbol.sourceFile, [symbol]);
349
+ }
237
350
  }
238
351
 
239
352
  /**
240
- * Issue #196 Bug 3: Restore needsStructKeyword from cache
241
- * @param structNames Array of struct names requiring 'struct' keyword
353
+ * Add multiple C++ symbols at once
242
354
  */
243
- restoreNeedsStructKeyword(structNames: string[]): void {
244
- for (const name of structNames) {
245
- this.needsStructKeyword.add(name);
355
+ addCppSymbols(symbols: TCppSymbol[]): void {
356
+ for (const symbol of symbols) {
357
+ this.addCppSymbol(symbol);
246
358
  }
247
359
  }
248
360
 
249
361
  /**
250
- * Issue #208: Add enum bit width for a typed enum
251
- * @param enumName Name of the enum (e.g., "EPressureType")
252
- * @param bitWidth Bit width from backing type (e.g., 8 for uint8_t)
362
+ * Get a C++ symbol by name (returns first match, or undefined)
253
363
  */
254
- addEnumBitWidth(enumName: string, bitWidth: number): void {
255
- this.enumBitWidth.set(enumName, bitWidth);
364
+ getCppSymbol(name: string): TCppSymbol | undefined {
365
+ const symbols = this.cppSymbols.get(name);
366
+ return symbols?.[0];
256
367
  }
257
368
 
258
369
  /**
259
- * Issue #208: Get enum bit width for a typed enum
260
- * @param enumName Name of the enum
261
- * @returns Bit width or undefined if not a typed enum
370
+ * Get all C++ symbols with a given name
262
371
  */
263
- getEnumBitWidth(enumName: string): number | undefined {
264
- return this.enumBitWidth.get(enumName);
372
+ getCppOverloads(name: string): TCppSymbol[] {
373
+ return this.cppSymbols.get(name) ?? [];
265
374
  }
266
375
 
267
376
  /**
268
- * Issue #208: Get all enum bit widths for cache serialization
269
- * @returns Map of enum name -> bit width
377
+ * Get C++ symbols by source file
270
378
  */
271
- getAllEnumBitWidths(): Map<string, number> {
272
- return this.enumBitWidth;
379
+ getCppSymbolsByFile(file: string): TCppSymbol[] {
380
+ return this.cppSymbolsByFile.get(file) ?? [];
273
381
  }
274
382
 
275
383
  /**
276
- * Issue #208: Restore enum bit widths from cache
277
- * @param bitWidths Map of enum name -> bit width
384
+ * Get all C++ symbols
278
385
  */
279
- restoreEnumBitWidths(bitWidths: Map<string, number>): void {
280
- for (const [enumName, width] of bitWidths) {
281
- this.enumBitWidth.set(enumName, width);
386
+ getAllCppSymbols(): TCppSymbol[] {
387
+ const result: TCppSymbol[] = [];
388
+ for (const symbols of this.cppSymbols.values()) {
389
+ result.push(...symbols);
282
390
  }
391
+ return result;
283
392
  }
284
393
 
394
+ // ========================================================================
395
+ // Cross-Language Methods
396
+ // ========================================================================
397
+
285
398
  /**
286
- * Get all fields for a struct
287
- * @param structName Name of the struct
288
- * @returns Map of field names to field info, or undefined if struct not found
399
+ * Get all symbols across all languages
289
400
  */
290
- getStructFields(
291
- structName: string,
292
- ): Map<string, IStructFieldInfo> | undefined {
293
- return this.structFields.get(structName);
401
+ getAllSymbols(): TAnySymbol[] {
402
+ return [
403
+ ...this.getAllTSymbols(),
404
+ ...this.getAllCSymbols(),
405
+ ...this.getAllCppSymbols(),
406
+ ];
294
407
  }
295
408
 
296
409
  /**
297
- * Get all struct fields for cache serialization
298
- * @returns Map of struct name -> (field name -> field info)
410
+ * Get first symbol matching a name across all languages.
411
+ * Searches TSymbol, then C, then C++ collections.
412
+ * Used by ISymbolLookup interface for constructor detection.
299
413
  */
300
- getAllStructFields(): Map<string, Map<string, IStructFieldInfo>> {
301
- return this.structFields;
414
+ getSymbol(name: string): TAnySymbol | undefined {
415
+ return (
416
+ this.getTSymbol(name) ?? this.getCSymbol(name) ?? this.getCppSymbol(name)
417
+ );
302
418
  }
303
419
 
304
420
  /**
305
- * Restore struct fields from cache
306
- * Merges cached fields into the existing structFields map
307
- * @param fields Map of struct name -> (field name -> field info)
421
+ * Get all overloads for a name across all languages
308
422
  */
309
- restoreStructFields(
310
- fields: Map<string, Map<string, IStructFieldInfo>>,
311
- ): void {
312
- for (const [structName, fieldMap] of fields) {
313
- // Get or create the struct's field map
314
- let existingFields = this.structFields.get(structName);
315
- if (!existingFields) {
316
- existingFields = new Map();
317
- this.structFields.set(structName, existingFields);
318
- }
423
+ getOverloads(name: string): TAnySymbol[] {
424
+ return [
425
+ ...this.getTOverloads(name),
426
+ ...this.getCOverloads(name),
427
+ ...this.getCppOverloads(name),
428
+ ];
429
+ }
319
430
 
320
- // Merge fields
321
- for (const [fieldName, fieldInfo] of fieldMap) {
322
- existingFields.set(fieldName, fieldInfo);
323
- }
324
- }
431
+ /**
432
+ * Get symbols by source file across all languages
433
+ */
434
+ getSymbolsByFile(file: string): TAnySymbol[] {
435
+ return [
436
+ ...this.getTSymbolsByFile(file),
437
+ ...this.getCSymbolsByFile(file),
438
+ ...this.getCppSymbolsByFile(file),
439
+ ];
325
440
  }
326
441
 
327
442
  /**
328
- * Get struct names defined in a specific source file
329
- * @param file Source file path
330
- * @returns Array of struct names defined in that file
443
+ * Get symbols by source language
331
444
  */
332
- getStructNamesByFile(file: string): string[] {
333
- const fileSymbols = this.byFile.get(file) ?? [];
334
- // Issue #196: Include any symbol that has struct fields registered
335
- // The dual-parse strategy may register typedef'd anonymous structs as variables
336
- // (e.g., "typedef struct { ... } Rectangle;" -> Rectangle has kind=variable)
337
- // But the C parser still adds struct fields for it
338
- const symbolNames = fileSymbols.map((s) => s.name);
339
- return symbolNames.filter((name) => this.structFields.has(name));
445
+ getSymbolsByLanguage(lang: ESourceLanguage): TAnySymbol[] {
446
+ switch (lang) {
447
+ case ESourceLanguage.CNext:
448
+ return this.getAllTSymbols();
449
+ case ESourceLanguage.C:
450
+ return this.getAllCSymbols();
451
+ case ESourceLanguage.Cpp:
452
+ return this.getAllCppSymbols();
453
+ }
340
454
  }
341
455
 
342
456
  /**
343
- * Clear all symbols
457
+ * Check if a symbol exists in any language
344
458
  */
345
- clear(): void {
346
- this.symbols.clear();
347
- this.byFile.clear();
348
- this.structFields.clear();
349
- this.needsStructKeyword.clear();
350
- this.enumBitWidth.clear();
459
+ hasSymbol(name: string): boolean {
460
+ return (
461
+ this.tSymbols.has(name) ||
462
+ this.cSymbols.has(name) ||
463
+ this.cppSymbols.has(name)
464
+ );
351
465
  }
352
466
 
353
467
  /**
354
- * Get symbol count
468
+ * Get total symbol count
355
469
  */
356
470
  get size(): number {
471
+ return this.getTSize() + this.getCSize() + this.getCppSize();
472
+ }
473
+
474
+ /**
475
+ * Get C symbol count
476
+ */
477
+ getCSize(): number {
357
478
  let count = 0;
358
- for (const symbols of this.symbols.values()) {
479
+ for (const symbols of this.cSymbols.values()) {
359
480
  count += symbols.length;
360
481
  }
361
482
  return count;
362
483
  }
363
484
 
485
+ /**
486
+ * Get C++ symbol count
487
+ */
488
+ getCppSize(): number {
489
+ let count = 0;
490
+ for (const symbols of this.cppSymbols.values()) {
491
+ count += symbols.length;
492
+ }
493
+ return count;
494
+ }
495
+
496
+ // ========================================================================
497
+ // Conflict Detection
498
+ // ========================================================================
499
+
500
+ /**
501
+ * Check if a symbol has conflicts
502
+ */
503
+ hasConflict(name: string): boolean {
504
+ const allSymbols = this.getOverloads(name);
505
+ if (allSymbols.length <= 1) {
506
+ return false;
507
+ }
508
+
509
+ return this.detectConflict(allSymbols) !== null;
510
+ }
511
+
512
+ /**
513
+ * Get all conflicts in the symbol table
514
+ * Per user requirement: Strict errors for cross-language conflicts
515
+ */
516
+ getConflicts(): IConflict[] {
517
+ const conflicts: IConflict[] = [];
518
+ const allNames = new Set<string>();
519
+
520
+ // Collect all symbol names from all languages
521
+ for (const name of this.tSymbols.keys()) allNames.add(name);
522
+ for (const name of this.cSymbols.keys()) allNames.add(name);
523
+ for (const name of this.cppSymbols.keys()) allNames.add(name);
524
+
525
+ for (const name of allNames) {
526
+ const symbols = this.getOverloads(name);
527
+ if (symbols.length <= 1) continue;
528
+
529
+ const conflict = this.detectConflict(symbols);
530
+ if (conflict) {
531
+ conflicts.push(conflict);
532
+ }
533
+ }
534
+
535
+ return conflicts;
536
+ }
537
+
364
538
  /**
365
539
  * Detect if a set of symbols with the same name represents a conflict
366
540
  */
367
- private detectConflict(symbols: ISymbol[]): IConflict | null {
541
+ private detectConflict(symbols: TAnySymbol[]): IConflict | null {
368
542
  // Filter out pure declarations (extern in C) - they don't count as definitions
369
- const definitions = symbols.filter((s) => !s.isDeclaration);
543
+ const definitions = symbols.filter(
544
+ (s) => !("isDeclaration" in s && s.isDeclaration),
545
+ );
370
546
 
371
547
  if (definitions.length <= 1) {
372
548
  // 0 or 1 definitions = no conflict
@@ -374,47 +550,58 @@ class SymbolTable {
374
550
  }
375
551
 
376
552
  // Issue #221: Filter out function parameters from conflict detection
377
- // Function parameters have a parent (their containing function) but their name
378
- // is NOT qualified with the parent prefix (unlike scope-level variables like Math_counter).
379
- // Parameters with the same name in different functions are not conflicts.
553
+ // Function parameters have a parent but their name is NOT qualified with the parent prefix.
380
554
  const globalDefinitions = definitions.filter((def) => {
381
- // If no parent, it's a global symbol - keep it
382
- if (!def.parent) return true;
383
-
384
- // Variables with a parent need special handling
385
- if (def.kind === ESymbolKind.Variable) {
386
- // Scope-level variables have qualified names (e.g., "Math_counter" with parent "Math")
387
- // Function parameters have unqualified names (e.g., "x" with parent "Math_add")
388
- // If the name starts with parent_, it's a scope-level variable - keep it
389
- // If not, it's a function parameter - filter it out
390
- const isQualifiedName = def.name.startsWith(def.parent + "_");
391
- return isQualifiedName;
555
+ // C-Next variables with scope need special handling
556
+ if (
557
+ def.sourceLanguage === ESourceLanguage.CNext &&
558
+ def.kind === "variable"
559
+ ) {
560
+ // After sourceLanguage check, def is narrowed to TSymbol
561
+ // After kind check, def is narrowed to IVariableSymbol
562
+ // Global scope means no conflict filtering needed
563
+ if (def.scope.name === "") return true;
564
+ // Scope-level variables vs function parameters:
565
+ // We can't easily distinguish here, so keep all for now
566
+ return true;
567
+ }
568
+ // C/C++ symbols: check parent field
569
+ if ("parent" in def && def.parent) {
570
+ // Non-variable symbols with parents are kept
571
+ if (def.kind !== "variable") return true;
572
+ // Variables with parents might be function parameters - filter out
573
+ return false;
392
574
  }
393
-
394
- // Non-variable symbols with parents (functions, enums, etc.) are kept
395
575
  return true;
396
576
  });
397
577
 
398
578
  if (globalDefinitions.length <= 1) {
399
- // After filtering parameters, 0 or 1 definitions = no conflict
400
579
  return null;
401
580
  }
402
581
 
403
582
  // Check for C++ function overloads (different signatures are OK)
404
- const cppFunctions = definitions.filter(
405
- (s) => s.sourceLanguage === ESourceLanguage.Cpp && s.signature,
583
+ const cppFunctions = globalDefinitions.filter(
584
+ (s) =>
585
+ s.sourceLanguage === ESourceLanguage.Cpp &&
586
+ s.kind === "function" &&
587
+ "parameters" in s,
406
588
  );
407
- if (cppFunctions.length === definitions.length) {
408
- // All are C++ functions with signatures
409
- const uniqueSignatures = new Set(cppFunctions.map((s) => s.signature));
589
+ if (cppFunctions.length === globalDefinitions.length) {
590
+ // All are C++ functions with signatures - check for unique signatures
591
+ const signatures = cppFunctions.map((f) => {
592
+ if ("parameters" in f && f.parameters) {
593
+ const params = f.parameters as ReadonlyArray<{ type?: string }>;
594
+ return params.map((p) => p.type ?? "").join(",");
595
+ }
596
+ return "";
597
+ });
598
+ const uniqueSignatures = new Set(signatures);
410
599
  if (uniqueSignatures.size === cppFunctions.length) {
411
- // All signatures are unique = valid overload, no conflict
412
600
  return null;
413
601
  }
414
602
  }
415
603
 
416
604
  // Check for cross-language conflict (C-Next vs C or C++)
417
- // Issue #221: Use globalDefinitions for C-Next to exclude function parameters
418
605
  const cnextDefs = globalDefinitions.filter(
419
606
  (s) => s.sourceLanguage === ESourceLanguage.CNext,
420
607
  );
@@ -426,7 +613,6 @@ class SymbolTable {
426
613
  );
427
614
 
428
615
  if (cnextDefs.length > 0 && (cDefs.length > 0 || cppDefs.length > 0)) {
429
- // C-Next + C/C++ conflict = ERROR
430
616
  const locations = globalDefinitions.map(
431
617
  (s) =>
432
618
  `${s.sourceLanguage.toUpperCase()} (${s.sourceFile}:${s.sourceLine})`,
@@ -441,26 +627,261 @@ class SymbolTable {
441
627
  }
442
628
 
443
629
  // Multiple definitions in same language (excluding overloads) = ERROR
630
+ // Issue #817: Group by scope AND kind - symbols in different scopes don't conflict,
631
+ // and symbols with different kinds (variable vs scope) don't conflict either
444
632
  if (cnextDefs.length > 1) {
445
- const locations = cnextDefs.map((s) => `${s.sourceFile}:${s.sourceLine}`);
446
- return {
447
- symbolName: cnextDefs[0].name,
448
- definitions: cnextDefs,
449
- severity: "error",
450
- message: `Symbol conflict: '${cnextDefs[0].name}' is defined multiple times in C-Next:\n ${locations.join("\n ")}`,
451
- };
633
+ const byScopeAndKind = this.groupCNextSymbolsByScopeAndKind(cnextDefs);
634
+
635
+ // Check each scope+kind group for conflicts (multiple symbols in same scope with same kind)
636
+ for (const symbols of byScopeAndKind.values()) {
637
+ if (symbols.length > 1) {
638
+ const locations = symbols.map(
639
+ (s) => `${s.sourceFile}:${s.sourceLine}`,
640
+ );
641
+ const scopeName = symbols[0].scope.name;
642
+ const displayName =
643
+ scopeName === ""
644
+ ? symbols[0].name
645
+ : `${scopeName}.${symbols[0].name}`;
646
+ return {
647
+ symbolName: displayName,
648
+ definitions: symbols,
649
+ severity: "error",
650
+ message: `Symbol conflict: '${displayName}' is defined multiple times in C-Next:\n ${locations.join("\n ")}`,
651
+ };
652
+ }
653
+ }
452
654
  }
453
655
 
454
656
  // Same symbol in C and C++ - typically OK (same symbol)
455
- // But if they have different types, might be a warning
456
657
  if (cDefs.length > 0 && cppDefs.length > 0) {
457
- // For now, allow C/C++ to share symbols (common pattern)
458
658
  return null;
459
659
  }
460
660
 
461
661
  return null;
462
662
  }
463
663
 
664
+ /**
665
+ * Issue #817: Group C-Next symbols by scope name and kind.
666
+ *
667
+ * Symbols in different scopes don't conflict (Foo.enabled vs Bar.enabled
668
+ * generate Foo_enabled and Bar_enabled). Symbols with different kinds also
669
+ * don't conflict (variable LED vs scope LED are distinct).
670
+ *
671
+ * @param symbols C-Next symbols to group (must all be TSymbol)
672
+ * @returns Map from "scopeName:kind" key to array of symbols
673
+ */
674
+ private groupCNextSymbolsByScopeAndKind(
675
+ symbols: TAnySymbol[],
676
+ ): Map<string, TSymbol[]> {
677
+ const byScopeAndKind = new Map<string, TSymbol[]>();
678
+
679
+ for (const def of symbols) {
680
+ const tSymbol = def as TSymbol;
681
+ const scopeName = tSymbol.scope.name;
682
+ const key = `${scopeName}:${tSymbol.kind}`;
683
+ const existing = byScopeAndKind.get(key);
684
+ if (existing) {
685
+ existing.push(tSymbol);
686
+ } else {
687
+ byScopeAndKind.set(key, [tSymbol]);
688
+ }
689
+ }
690
+
691
+ return byScopeAndKind;
692
+ }
693
+
694
+ // ========================================================================
695
+ // Struct Field Information
696
+ // ========================================================================
697
+
698
+ /**
699
+ * Add struct field information
700
+ * @param structName Name of the struct
701
+ * @param fieldName Name of the field
702
+ * @param fieldType Type of the field (e.g., "uint32_t")
703
+ * @param arrayDimensions Optional array dimensions if field is an array
704
+ */
705
+ addStructField(
706
+ structName: string,
707
+ fieldName: string,
708
+ fieldType: string,
709
+ arrayDimensions?: number[],
710
+ ): void {
711
+ let fields = this.structFields.get(structName);
712
+ if (!fields) {
713
+ fields = new Map();
714
+ this.structFields.set(structName, fields);
715
+ }
716
+
717
+ fields.set(fieldName, {
718
+ type: fieldType,
719
+ arrayDimensions,
720
+ });
721
+ }
722
+
723
+ /**
724
+ * Get struct field type
725
+ * @param structName Name of the struct
726
+ * @param fieldName Name of the field
727
+ * @returns Field type or undefined if not found
728
+ */
729
+ getStructFieldType(
730
+ structName: string,
731
+ fieldName: string,
732
+ ): string | undefined {
733
+ const fields = this.structFields.get(structName);
734
+ return fields?.get(fieldName)?.type;
735
+ }
736
+
737
+ /**
738
+ * Get struct field info (type and array dimensions)
739
+ * @param structName Name of the struct
740
+ * @param fieldName Name of the field
741
+ * @returns Field info or undefined if not found
742
+ */
743
+ getStructFieldInfo(
744
+ structName: string,
745
+ fieldName: string,
746
+ ): IStructFieldInfo | undefined {
747
+ const fields = this.structFields.get(structName);
748
+ return fields?.get(fieldName);
749
+ }
750
+
751
+ /**
752
+ * Get all fields for a struct
753
+ * @param structName Name of the struct
754
+ * @returns Map of field names to field info, or undefined if struct not found
755
+ */
756
+ getStructFields(
757
+ structName: string,
758
+ ): Map<string, IStructFieldInfo> | undefined {
759
+ return this.structFields.get(structName);
760
+ }
761
+
762
+ /**
763
+ * Get all struct fields for cache serialization
764
+ * @returns Map of struct name -> (field name -> field info)
765
+ */
766
+ getAllStructFields(): Map<string, Map<string, IStructFieldInfo>> {
767
+ return this.structFields;
768
+ }
769
+
770
+ /**
771
+ * Restore struct fields from cache
772
+ * Merges cached fields into the existing structFields map
773
+ * @param fields Map of struct name -> (field name -> field info)
774
+ */
775
+ restoreStructFields(
776
+ fields: Map<string, Map<string, IStructFieldInfo>>,
777
+ ): void {
778
+ for (const [structName, fieldMap] of fields) {
779
+ let existingFields = this.structFields.get(structName);
780
+ if (!existingFields) {
781
+ existingFields = new Map();
782
+ this.structFields.set(structName, existingFields);
783
+ }
784
+
785
+ for (const [fieldName, fieldInfo] of fieldMap) {
786
+ existingFields.set(fieldName, fieldInfo);
787
+ }
788
+ }
789
+ }
790
+
791
+ /**
792
+ * Get struct names defined in a specific source file
793
+ * @param file Source file path
794
+ * @returns Array of struct names defined in that file
795
+ */
796
+ getStructNamesByFile(file: string): string[] {
797
+ const fileSymbols = this.getSymbolsByFile(file);
798
+ const symbolNames = fileSymbols.map((s) => s.name);
799
+ return symbolNames.filter((name) => this.structFields.has(name));
800
+ }
801
+
802
+ // ========================================================================
803
+ // Struct Keyword Tracking
804
+ // ========================================================================
805
+
806
+ /**
807
+ * Issue #196 Bug 3: Mark a struct as requiring 'struct' keyword in C
808
+ * @param structName Name of the struct (e.g., "NamedPoint")
809
+ */
810
+ markNeedsStructKeyword(structName: string): void {
811
+ this.needsStructKeyword.add(structName);
812
+ }
813
+
814
+ /**
815
+ * Issue #196 Bug 3: Check if a struct requires 'struct' keyword in C
816
+ * @param structName Name of the struct
817
+ * @returns true if the struct was defined as 'struct Name { ... }' without typedef
818
+ */
819
+ checkNeedsStructKeyword(structName: string): boolean {
820
+ return this.needsStructKeyword.has(structName);
821
+ }
822
+
823
+ /**
824
+ * Issue #196 Bug 3: Get all struct names requiring 'struct' keyword
825
+ * @returns Array of struct names
826
+ */
827
+ getAllNeedsStructKeyword(): string[] {
828
+ return Array.from(this.needsStructKeyword);
829
+ }
830
+
831
+ /**
832
+ * Issue #196 Bug 3: Restore needsStructKeyword from cache
833
+ * @param structNames Array of struct names requiring 'struct' keyword
834
+ */
835
+ restoreNeedsStructKeyword(structNames: string[]): void {
836
+ for (const name of structNames) {
837
+ this.needsStructKeyword.add(name);
838
+ }
839
+ }
840
+
841
+ // ========================================================================
842
+ // Enum Bit Width Tracking
843
+ // ========================================================================
844
+
845
+ /**
846
+ * Issue #208: Add enum bit width for a typed enum
847
+ * @param enumName Name of the enum (e.g., "EPressureType")
848
+ * @param bitWidth Bit width from backing type (e.g., 8 for uint8_t)
849
+ */
850
+ addEnumBitWidth(enumName: string, bitWidth: number): void {
851
+ this.enumBitWidth.set(enumName, bitWidth);
852
+ }
853
+
854
+ /**
855
+ * Issue #208: Get enum bit width for a typed enum
856
+ * @param enumName Name of the enum
857
+ * @returns Bit width or undefined if not a typed enum
858
+ */
859
+ getEnumBitWidth(enumName: string): number | undefined {
860
+ return this.enumBitWidth.get(enumName);
861
+ }
862
+
863
+ /**
864
+ * Issue #208: Get all enum bit widths for cache serialization
865
+ * @returns Map of enum name -> bit width
866
+ */
867
+ getAllEnumBitWidths(): Map<string, number> {
868
+ return this.enumBitWidth;
869
+ }
870
+
871
+ /**
872
+ * Issue #208: Restore enum bit widths from cache
873
+ * @param bitWidths Map of enum name -> bit width
874
+ */
875
+ restoreEnumBitWidths(bitWidths: Map<string, number>): void {
876
+ for (const [enumName, width] of bitWidths) {
877
+ this.enumBitWidth.set(enumName, width);
878
+ }
879
+ }
880
+
881
+ // ========================================================================
882
+ // External Array Dimension Resolution
883
+ // ========================================================================
884
+
464
885
  /**
465
886
  * Issue #461: Resolve external const array dimensions
466
887
  *
@@ -472,59 +893,102 @@ class SymbolTable {
472
893
  * external .cnx files that were not available during initial symbol collection.
473
894
  */
474
895
  resolveExternalArrayDimensions(): void {
475
- // Build a map of all const values from the symbol table
896
+ const constValues = this.buildConstValuesMap();
897
+ if (constValues.size === 0) {
898
+ return;
899
+ }
900
+ this.resolveArrayDimensionsWithConstants(constValues);
901
+ }
902
+
903
+ /**
904
+ * Build a map of const variable names to their integer values.
905
+ */
906
+ private buildConstValuesMap(): Map<string, number> {
476
907
  const constValues = new Map<string, number>();
477
- for (const symbol of this.getAllSymbols()) {
478
- if (
479
- symbol.kind === ESymbolKind.Variable &&
480
- symbol.isConst &&
481
- symbol.initialValue !== undefined
482
- ) {
483
- const value = LiteralUtils.parseIntegerLiteral(symbol.initialValue);
484
- if (value !== undefined) {
485
- constValues.set(symbol.name, value);
908
+ for (const symbol of this.getAllTSymbols()) {
909
+ if (symbol.kind === "variable" && symbol.isConst) {
910
+ // After kind check, symbol is narrowed to IVariableSymbol
911
+ if (symbol.initialValue !== undefined) {
912
+ const value = LiteralUtils.parseIntegerLiteral(symbol.initialValue);
913
+ if (value !== undefined) {
914
+ constValues.set(symbol.name, value);
915
+ }
486
916
  }
487
917
  }
488
918
  }
919
+ return constValues;
920
+ }
489
921
 
490
- // If no const values found, nothing to resolve
491
- if (constValues.size === 0) {
492
- return;
493
- }
494
-
495
- // Scan all variable symbols for unresolved array dimensions
496
- for (const symbol of this.getAllSymbols()) {
922
+ /**
923
+ * Resolve string array dimensions using const values lookup.
924
+ */
925
+ private resolveArrayDimensionsWithConstants(
926
+ constValues: Map<string, number>,
927
+ ): void {
928
+ for (const symbol of this.getAllTSymbols()) {
497
929
  if (
498
- symbol.kind === ESymbolKind.Variable &&
930
+ symbol.kind === "variable" &&
499
931
  symbol.isArray &&
500
932
  symbol.arrayDimensions
501
933
  ) {
502
- let modified = false;
503
- const resolvedDimensions = symbol.arrayDimensions.map((dim) => {
504
- // If dimension is numeric, keep it
505
- const numericValue = Number.parseInt(dim, 10);
506
- if (!Number.isNaN(numericValue)) {
507
- return dim;
508
- }
509
-
510
- // Try to resolve from const values
511
- const constValue = constValues.get(dim);
512
- if (constValue !== undefined) {
513
- modified = true;
514
- return String(constValue);
515
- }
516
-
517
- // Keep original (unresolved macro reference)
518
- return dim;
519
- });
934
+ // After kind check, symbol is narrowed to IVariableSymbol
935
+ this.resolveVariableArrayDimensions(symbol, constValues);
936
+ }
937
+ }
938
+ }
520
939
 
521
- if (modified) {
522
- // Update the symbol's array dimensions
523
- symbol.arrayDimensions = resolvedDimensions;
524
- }
940
+ /**
941
+ * Resolve array dimensions for a single variable symbol.
942
+ */
943
+ private resolveVariableArrayDimensions(
944
+ variable: IVariableSymbol,
945
+ constValues: Map<string, number>,
946
+ ): void {
947
+ let modified = false;
948
+ const resolvedDimensions = variable.arrayDimensions!.map((dim) => {
949
+ if (typeof dim === "number") {
950
+ return dim;
525
951
  }
952
+ const constValue = constValues.get(dim);
953
+ if (constValue !== undefined) {
954
+ modified = true;
955
+ return constValue;
956
+ }
957
+ return dim;
958
+ });
959
+
960
+ if (modified) {
961
+ // Mutate in place - symbol is already in storage, cloning would require
962
+ // updating all maps. The readonly typing prevents accidental mutations
963
+ // elsewhere; this controlled mutation is intentional during resolution.
964
+ (
965
+ variable as unknown as { arrayDimensions: (number | string)[] }
966
+ ).arrayDimensions = resolvedDimensions;
526
967
  }
527
968
  }
969
+
970
+ // ========================================================================
971
+ // Clear / Reset
972
+ // ========================================================================
973
+
974
+ /**
975
+ * Clear all symbols
976
+ */
977
+ clear(): void {
978
+ // C-Next
979
+ this.tSymbols.clear();
980
+ this.tSymbolsByFile.clear();
981
+ // C
982
+ this.cSymbols.clear();
983
+ this.cSymbolsByFile.clear();
984
+ // C++
985
+ this.cppSymbols.clear();
986
+ this.cppSymbolsByFile.clear();
987
+ // Auxiliary
988
+ this.structFields.clear();
989
+ this.needsStructKeyword.clear();
990
+ this.enumBitWidth.clear();
991
+ }
528
992
  }
529
993
 
530
994
  export default SymbolTable;