c-next 0.1.69 → 0.1.71

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 (247) 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 +173 -60
  6. package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +240 -205
  7. package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +1 -2
  8. package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +742 -0
  9. package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +102 -15
  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/{output/codegen → logic/analysis}/helpers/AssignmentTargetExtractor.ts +1 -1
  13. package/src/transpiler/{output/codegen → logic/analysis}/helpers/ChildStatementCollector.ts +1 -1
  14. package/src/transpiler/{output/codegen → logic/analysis}/helpers/StatementExpressionCollector.ts +1 -1
  15. package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/AssignmentTargetExtractor.test.ts +2 -2
  16. package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/ChildStatementCollector.test.ts +2 -2
  17. package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/StatementExpressionCollector.test.ts +2 -2
  18. package/src/transpiler/logic/symbols/SymbolTable.ts +676 -258
  19. package/src/transpiler/logic/symbols/SymbolUtils.ts +2 -2
  20. package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +290 -782
  21. package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +573 -0
  22. package/src/transpiler/logic/symbols/c/__tests__/testHelpers.ts +20 -0
  23. package/src/transpiler/logic/symbols/c/collectors/EnumCollector.ts +82 -0
  24. package/src/transpiler/logic/symbols/c/collectors/FunctionCollector.ts +106 -0
  25. package/src/transpiler/logic/symbols/c/collectors/StructCollector.ts +173 -0
  26. package/src/transpiler/logic/symbols/c/collectors/TypedefCollector.ts +35 -0
  27. package/src/transpiler/logic/symbols/c/collectors/VariableCollector.ts +80 -0
  28. package/src/transpiler/logic/symbols/c/index.ts +333 -0
  29. package/src/transpiler/logic/symbols/c/utils/DeclaratorUtils.ts +269 -0
  30. package/src/transpiler/logic/symbols/cnext/__tests__/BitmapCollector.test.ts +50 -11
  31. package/src/transpiler/logic/symbols/cnext/__tests__/CNextResolver.integration.test.ts +45 -34
  32. package/src/transpiler/logic/symbols/cnext/__tests__/EnumCollector.test.ts +30 -13
  33. package/src/transpiler/logic/symbols/cnext/__tests__/FunctionCollector.test.ts +279 -64
  34. package/src/transpiler/logic/symbols/cnext/__tests__/RegisterCollector.test.ts +60 -13
  35. package/src/transpiler/logic/symbols/cnext/__tests__/ScopeCollector.test.ts +40 -37
  36. package/src/transpiler/logic/symbols/cnext/__tests__/StructCollector.test.ts +131 -45
  37. package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolInfoAdapter.test.ts +223 -139
  38. package/src/transpiler/logic/symbols/cnext/__tests__/VariableCollector.test.ts +79 -25
  39. package/src/transpiler/logic/symbols/cnext/__tests__/testUtils.ts +53 -0
  40. package/src/transpiler/logic/symbols/cnext/adapters/TSymbolInfoAdapter.ts +83 -43
  41. package/src/transpiler/logic/symbols/cnext/collectors/BitmapCollector.ts +14 -13
  42. package/src/transpiler/logic/symbols/cnext/collectors/EnumCollector.ts +11 -10
  43. package/src/transpiler/logic/symbols/cnext/collectors/FunctionCollector.ts +83 -34
  44. package/src/transpiler/logic/symbols/cnext/collectors/RegisterCollector.ts +22 -18
  45. package/src/transpiler/logic/symbols/cnext/collectors/ScopeCollector.ts +53 -35
  46. package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +30 -23
  47. package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +18 -19
  48. package/src/transpiler/logic/symbols/cnext/index.ts +36 -14
  49. package/src/transpiler/logic/symbols/cnext/types/IScopeCollectorResult.ts +2 -2
  50. package/src/transpiler/logic/symbols/cnext/utils/SymbolNameUtils.ts +27 -0
  51. package/src/transpiler/logic/symbols/cpp/__tests__/CppResolver.integration.test.ts +270 -0
  52. package/src/transpiler/logic/symbols/cpp/__tests__/testHelpers.ts +20 -0
  53. package/src/transpiler/logic/symbols/cpp/collectors/ClassCollector.ts +317 -0
  54. package/src/transpiler/logic/symbols/cpp/collectors/EnumCollector.ts +71 -0
  55. package/src/transpiler/logic/symbols/cpp/collectors/FunctionCollector.ts +155 -0
  56. package/src/transpiler/logic/symbols/cpp/collectors/NamespaceCollector.ts +65 -0
  57. package/src/transpiler/logic/symbols/cpp/collectors/TypeAliasCollector.ts +46 -0
  58. package/src/transpiler/logic/symbols/cpp/collectors/VariableCollector.ts +54 -0
  59. package/src/transpiler/logic/symbols/cpp/index.ts +366 -0
  60. package/src/transpiler/logic/symbols/cpp/utils/DeclaratorUtils.ts +248 -0
  61. package/src/transpiler/logic/symbols/shared/IExtractedParameter.ts +18 -0
  62. package/src/transpiler/logic/symbols/shared/ParameterExtractorUtils.ts +73 -0
  63. package/src/transpiler/output/codegen/CodeGenerator.ts +310 -2288
  64. package/src/transpiler/output/codegen/TypeRegistrationUtils.ts +4 -6
  65. package/src/transpiler/output/codegen/TypeResolver.ts +2 -2
  66. package/src/transpiler/output/codegen/TypeValidator.ts +5 -5
  67. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +7 -1
  68. package/src/transpiler/output/codegen/__tests__/TypeRegistrationUtils.test.ts +36 -51
  69. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +20 -17
  70. package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +3 -3
  71. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +1 -1
  72. package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +1 -1
  73. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +1 -1
  74. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +9 -9
  75. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +12 -12
  76. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +13 -12
  77. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +23 -17
  78. package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +2 -2
  79. package/src/transpiler/output/codegen/assignment/handlers/AssignmentHandlerUtils.ts +7 -1
  80. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +3 -3
  81. package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +9 -5
  82. package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +2 -1
  83. package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +4 -4
  84. package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +5 -5
  85. package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +23 -25
  86. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +20 -36
  87. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +18 -18
  88. package/src/transpiler/output/codegen/assignment/handlers/__tests__/SpecialHandlers.test.ts +42 -32
  89. package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +5 -4
  90. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +21 -8
  91. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopedRegisterGenerator.ts +3 -2
  92. package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +14 -6
  93. package/src/transpiler/output/codegen/generators/expressions/CallExprUtils.ts +9 -3
  94. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +19 -16
  95. package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +24 -8
  96. package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprUtils.test.ts +4 -8
  97. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +15 -2
  98. package/src/transpiler/output/codegen/helpers/ArgumentGenerator.ts +236 -0
  99. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +2 -1
  100. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +2 -2
  101. package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +3 -3
  102. package/src/transpiler/output/codegen/helpers/CppConstructorHelper.ts +3 -3
  103. package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +1 -1
  104. package/src/transpiler/output/codegen/helpers/FunctionContextManager.ts +435 -0
  105. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +2 -2
  106. package/src/transpiler/output/codegen/helpers/StringOperationsHelper.ts +203 -0
  107. package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +8 -12
  108. package/src/transpiler/output/codegen/helpers/TypeRegistrationEngine.ts +520 -0
  109. package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +735 -0
  110. package/src/transpiler/output/codegen/helpers/VariableDeclarationFormatter.ts +1 -1
  111. package/src/transpiler/output/codegen/helpers/__tests__/ArgumentGenerator.test.ts +521 -0
  112. package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +1 -1
  113. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +7 -7
  114. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +7 -7
  115. package/src/transpiler/output/codegen/helpers/__tests__/CppConstructorHelper.test.ts +4 -5
  116. package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +2 -2
  117. package/src/transpiler/output/codegen/helpers/__tests__/FunctionContextManager.test.ts +983 -0
  118. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +4 -4
  119. package/src/transpiler/output/codegen/helpers/__tests__/StringOperationsHelper.test.ts +269 -0
  120. package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +31 -32
  121. package/src/transpiler/output/codegen/helpers/__tests__/TypeRegistrationEngine.test.ts +186 -0
  122. package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclHelper.test.ts +460 -0
  123. package/src/transpiler/output/codegen/helpers/types/IArgumentGeneratorCallbacks.ts +32 -0
  124. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +7 -3
  125. package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +5 -5
  126. package/src/transpiler/output/codegen/types/IFunctionContextCallbacks.ts +12 -0
  127. package/src/transpiler/output/codegen/types/IVariableFormatInput.ts +1 -1
  128. package/src/transpiler/output/codegen/utils/QualifiedNameGenerator.ts +114 -0
  129. package/src/transpiler/output/codegen/utils/__tests__/QualifiedNameGenerator.test.ts +183 -0
  130. package/src/transpiler/output/headers/BaseHeaderGenerator.ts +4 -4
  131. package/src/transpiler/output/headers/ExternalTypeHeaderBuilder.ts +7 -7
  132. package/src/transpiler/output/headers/HeaderGenerator.ts +9 -7
  133. package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +19 -20
  134. package/src/transpiler/output/headers/__tests__/BaseHeaderGenerator.test.ts +15 -18
  135. package/src/transpiler/output/headers/__tests__/CHeaderGenerator.test.ts +63 -64
  136. package/src/transpiler/output/headers/__tests__/CppHeaderGenerator.test.ts +36 -32
  137. package/src/transpiler/output/headers/__tests__/ExternalTypeHeaderBuilder.test.ts +26 -26
  138. package/src/transpiler/output/headers/__tests__/HeaderGenerator.test.ts +87 -59
  139. package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +57 -58
  140. package/src/transpiler/output/headers/adapters/HeaderSymbolAdapter.ts +222 -0
  141. package/src/transpiler/output/headers/adapters/__tests__/HeaderSymbolAdapter.test.ts +538 -0
  142. package/src/transpiler/output/headers/types/IGroupedSymbols.ts +8 -8
  143. package/src/transpiler/output/headers/types/IHeaderSymbol.ts +62 -0
  144. package/src/transpiler/state/CodeGenState.ts +109 -4
  145. package/src/transpiler/state/SymbolRegistry.ts +181 -0
  146. package/src/transpiler/{types → state}/TranspilerState.ts +1 -1
  147. package/src/transpiler/state/__tests__/CodeGenState.test.ts +277 -1
  148. package/src/transpiler/state/__tests__/SymbolRegistry.test.ts +249 -0
  149. package/src/transpiler/{types → state}/__tests__/TranspilerState.test.ts +1 -1
  150. package/src/transpiler/types/ICachedFileEntry.ts +1 -1
  151. package/src/transpiler/types/IConflict.ts +14 -0
  152. package/src/transpiler/types/ISerializedSymbol.ts +11 -0
  153. package/src/transpiler/types/TPrimitiveKind.ts +20 -0
  154. package/src/transpiler/types/TType.ts +103 -0
  155. package/src/transpiler/types/TVisibility.ts +6 -0
  156. package/src/transpiler/types/symbol-kinds/TSymbolKind.ts +10 -0
  157. package/src/transpiler/types/symbol-kinds/TSymbolKindC.ts +12 -0
  158. package/src/transpiler/types/symbol-kinds/TSymbolKindCNext.ts +16 -0
  159. package/src/transpiler/types/symbol-kinds/TSymbolKindCpp.ts +14 -0
  160. package/src/transpiler/types/symbols/IBaseSymbol.ts +31 -0
  161. package/src/transpiler/{logic/symbols/types → types/symbols}/IBitmapFieldInfo.ts +2 -2
  162. package/src/transpiler/types/symbols/IBitmapSymbol.ts +21 -0
  163. package/src/transpiler/{logic/symbols/types → types/symbols}/IEnumSymbol.ts +5 -6
  164. package/src/transpiler/types/symbols/IFieldInfo.ts +26 -0
  165. package/src/transpiler/types/symbols/IFunctionSymbol.ts +30 -0
  166. package/src/transpiler/types/symbols/IParameterInfo.ts +26 -0
  167. package/src/transpiler/{logic/symbols/types → types/symbols}/IRegisterMemberInfo.ts +4 -4
  168. package/src/transpiler/types/symbols/IRegisterSymbol.ts +18 -0
  169. package/src/transpiler/types/symbols/IScopeSymbol.ts +32 -0
  170. package/src/transpiler/{logic/symbols/types → types/symbols}/IStructFieldInfo.ts +2 -1
  171. package/src/transpiler/types/symbols/IStructSymbol.ts +15 -0
  172. package/src/transpiler/types/symbols/IVariableSymbol.ts +30 -0
  173. package/src/transpiler/types/symbols/SymbolGuards.ts +43 -0
  174. package/src/transpiler/types/symbols/TAnySymbol.ts +22 -0
  175. package/src/transpiler/types/symbols/TSymbol.ts +32 -0
  176. package/src/transpiler/types/symbols/__tests__/IBaseSymbol.test.ts +56 -0
  177. package/src/transpiler/types/symbols/__tests__/SymbolGuards.test.ts +57 -0
  178. package/src/transpiler/types/symbols/c/ICBaseSymbol.ts +28 -0
  179. package/src/transpiler/types/symbols/c/ICEnumMemberSymbol.ts +17 -0
  180. package/src/transpiler/types/symbols/c/ICEnumSymbol.ts +17 -0
  181. package/src/transpiler/types/symbols/c/ICFieldInfo.ts +16 -0
  182. package/src/transpiler/types/symbols/c/ICFunctionSymbol.ts +21 -0
  183. package/src/transpiler/types/symbols/c/ICParameterInfo.ts +19 -0
  184. package/src/transpiler/types/symbols/c/ICStructSymbol.ts +21 -0
  185. package/src/transpiler/types/symbols/c/ICTypedefSymbol.ts +14 -0
  186. package/src/transpiler/types/symbols/c/ICVariableSymbol.ts +26 -0
  187. package/src/transpiler/types/symbols/c/TCSymbol.ts +26 -0
  188. package/src/transpiler/types/symbols/cpp/ICppBaseSymbol.ts +31 -0
  189. package/src/transpiler/types/symbols/cpp/ICppClassSymbol.ts +15 -0
  190. package/src/transpiler/types/symbols/cpp/ICppEnumMemberSymbol.ts +14 -0
  191. package/src/transpiler/types/symbols/cpp/ICppEnumSymbol.ts +14 -0
  192. package/src/transpiler/types/symbols/cpp/ICppFieldInfo.ts +16 -0
  193. package/src/transpiler/types/symbols/cpp/ICppFunctionSymbol.ts +21 -0
  194. package/src/transpiler/types/symbols/cpp/ICppNamespaceSymbol.ts +11 -0
  195. package/src/transpiler/types/symbols/cpp/ICppParameterInfo.ts +19 -0
  196. package/src/transpiler/types/symbols/cpp/ICppStructSymbol.ts +16 -0
  197. package/src/transpiler/types/symbols/cpp/ICppTypeAliasSymbol.ts +14 -0
  198. package/src/transpiler/types/symbols/cpp/ICppVariableSymbol.ts +23 -0
  199. package/src/transpiler/types/symbols/cpp/TCppSymbol.ts +30 -0
  200. package/src/utils/CppNamespaceUtils.ts +3 -4
  201. package/src/utils/FunctionUtils.ts +92 -0
  202. package/src/utils/ParameterUtils.ts +55 -0
  203. package/src/utils/PrimitiveKindUtils.ts +33 -0
  204. package/src/utils/ScopeUtils.ts +105 -0
  205. package/src/utils/TTypeUtils.ts +159 -0
  206. package/src/utils/TypeResolver.ts +132 -0
  207. package/src/utils/__tests__/CppNamespaceUtils.test.ts +92 -99
  208. package/src/utils/__tests__/FunctionUtils.test.ts +284 -0
  209. package/src/utils/__tests__/ParameterUtils.test.ts +174 -0
  210. package/src/utils/__tests__/PrimitiveKindUtils.test.ts +59 -0
  211. package/src/utils/__tests__/ScopeUtils.test.ts +53 -0
  212. package/src/utils/__tests__/TTypeUtils.test.ts +245 -0
  213. package/src/utils/__tests__/TypeResolver.test.ts +332 -0
  214. package/src/utils/cache/CacheManager.ts +91 -50
  215. package/src/utils/cache/__tests__/CacheManager.test.ts +180 -114
  216. package/src/transpiler/logic/symbols/AutoConstUpdater.ts +0 -93
  217. package/src/transpiler/logic/symbols/CSymbolCollector.ts +0 -648
  218. package/src/transpiler/logic/symbols/CppSymbolCollector.ts +0 -874
  219. package/src/transpiler/logic/symbols/SymbolCollectorContext.ts +0 -68
  220. package/src/transpiler/logic/symbols/__tests__/AutoConstUpdater.test.ts +0 -418
  221. package/src/transpiler/logic/symbols/__tests__/CSymbolCollector.test.ts +0 -685
  222. package/src/transpiler/logic/symbols/__tests__/CppSymbolCollector.test.ts +0 -1146
  223. package/src/transpiler/logic/symbols/__tests__/SymbolCollectorContext.test.ts +0 -290
  224. package/src/transpiler/logic/symbols/__tests__/cTestHelpers.ts +0 -43
  225. package/src/transpiler/logic/symbols/__tests__/cppTestHelpers.ts +0 -40
  226. package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolAdapter.test.ts +0 -595
  227. package/src/transpiler/logic/symbols/cnext/adapters/TSymbolAdapter.ts +0 -345
  228. package/src/transpiler/logic/symbols/types/IBaseSymbol.ts +0 -27
  229. package/src/transpiler/logic/symbols/types/IBitmapSymbol.ts +0 -23
  230. package/src/transpiler/logic/symbols/types/ICollectorContext.ts +0 -19
  231. package/src/transpiler/logic/symbols/types/IConflict.ts +0 -20
  232. package/src/transpiler/logic/symbols/types/IFieldInfo.ts +0 -18
  233. package/src/transpiler/logic/symbols/types/IFunctionSymbol.ts +0 -25
  234. package/src/transpiler/logic/symbols/types/IParameterInfo.ts +0 -24
  235. package/src/transpiler/logic/symbols/types/IRegisterSymbol.ts +0 -20
  236. package/src/transpiler/logic/symbols/types/IScopeSymbol.ts +0 -19
  237. package/src/transpiler/logic/symbols/types/IStructSymbol.ts +0 -16
  238. package/src/transpiler/logic/symbols/types/IVariableSymbol.ts +0 -30
  239. package/src/transpiler/logic/symbols/types/TSymbol.ts +0 -36
  240. package/src/transpiler/logic/symbols/types/__tests__/SymbolGuards.test.ts +0 -244
  241. package/src/transpiler/logic/symbols/types/typeGuards.ts +0 -44
  242. package/src/utils/types/ESymbolKind.ts +0 -19
  243. package/src/utils/types/ISymbol.ts +0 -64
  244. /package/src/transpiler/{types → constants}/BITMAP_BACKING_TYPE.ts +0 -0
  245. /package/src/transpiler/{types → constants}/BITMAP_SIZE.ts +0 -0
  246. /package/src/transpiler/{output/codegen → logic/analysis}/helpers/TransitiveModificationPropagator.ts +0 -0
  247. /package/src/transpiler/{output/codegen → logic/analysis}/helpers/__tests__/TransitiveModificationPropagator.test.ts +0 -0
@@ -6,8 +6,8 @@
6
6
  import { CommonTokenStream, ParserRuleContext } from "antlr4ng";
7
7
  import * as Parser from "../../logic/parser/grammar/CNextParser";
8
8
 
9
- import ESymbolKind from "../../../utils/types/ESymbolKind";
10
9
  import CommentExtractor from "../../logic/analysis/CommentExtractor";
10
+ import TypeRegistrationEngine from "./helpers/TypeRegistrationEngine";
11
11
  import CommentFormatter from "./CommentFormatter";
12
12
  import IncludeDiscovery from "../../data/IncludeDiscovery";
13
13
  import IComment from "../../types/IComment";
@@ -17,12 +17,10 @@ import TYPE_LIMITS from "./types/TYPE_LIMITS";
17
17
  // Issue #60: BITMAP_SIZE and BITMAP_BACKING_TYPE moved to SymbolCollector
18
18
  import TTypeInfo from "./types/TTypeInfo";
19
19
  import TParameterInfo from "./types/TParameterInfo";
20
- import TOverflowBehavior from "./types/TOverflowBehavior";
21
20
  import ICodeGeneratorOptions from "./types/ICodeGeneratorOptions";
22
21
  import TypeResolver from "./TypeResolver";
23
22
  import ICodeGenSymbols from "../../types/ICodeGenSymbols";
24
23
  import TypeValidator from "./TypeValidator";
25
- import TypeRegistrationUtils from "./TypeRegistrationUtils";
26
24
  import IOrchestrator from "./generators/IOrchestrator";
27
25
  import IGeneratorInput from "./generators/IGeneratorInput";
28
26
  import IGeneratorState from "./generators/IGeneratorState";
@@ -81,11 +79,13 @@ import MemberChainAnalyzer from "./analysis/MemberChainAnalyzer";
81
79
  // Issue #644: Float bit write helper for shadow variable pattern
82
80
  import FloatBitHelper from "./helpers/FloatBitHelper";
83
81
  // Issue #644: String declaration helper for bounded/array/concat strings
84
- import StringDeclHelper from "./helpers/StringDeclHelper";
82
+ // Note: StringDeclHelper is now used via VariableDeclHelper
83
+ // Issue #794: Argument generation helper for ADR-006 semantics
84
+ import ArgumentGenerator from "./helpers/ArgumentGenerator";
85
85
  // Issue #644: Enum assignment validator for type-safe enum assignments
86
86
  import EnumAssignmentValidator from "./helpers/EnumAssignmentValidator";
87
87
  // Issue #644: Array initialization helper for size inference and fill-all
88
- import ArrayInitHelper from "./helpers/ArrayInitHelper";
88
+ // Note: ArrayInitHelper is now used via VariableDeclHelper
89
89
  // Issue #644: Assignment expected type resolution helper
90
90
  import AssignmentExpectedTypeResolver from "./helpers/AssignmentExpectedTypeResolver";
91
91
  // PR #715: C++ member conversion helper for improved testability
@@ -102,7 +102,11 @@ import SymbolLookupHelper from "./helpers/SymbolLookupHelper";
102
102
  // Issue #644: Assignment validation coordinator helper
103
103
  import AssignmentValidator from "./helpers/AssignmentValidator";
104
104
  // Issue #696: Variable modifier extraction helper
105
- import VariableModifierBuilder from "./helpers/VariableModifierBuilder";
105
+ // Note: VariableModifierBuilder is now used via VariableDeclHelper
106
+ // Issue #792: Variable declaration helper
107
+ import VariableDeclHelper from "./helpers/VariableDeclHelper";
108
+ // String operation detection and extraction
109
+ import StringOperationsHelper from "./helpers/StringOperationsHelper";
106
110
  // PR #681: Extracted separator and dereference resolution utilities
107
111
  import MemberSeparatorResolver from "./helpers/MemberSeparatorResolver";
108
112
  import ParameterDereferenceResolver from "./helpers/ParameterDereferenceResolver";
@@ -120,20 +124,19 @@ import CodegenParserUtils from "./utils/CodegenParserUtils";
120
124
  import IMemberSeparatorDeps from "./types/IMemberSeparatorDeps";
121
125
  import IParameterDereferenceDeps from "./types/IParameterDereferenceDeps";
122
126
  import ISeparatorContext from "./types/ISeparatorContext";
123
- // Issue #566: Statement expression collection for const inference
124
- import StatementExpressionCollector from "./helpers/StatementExpressionCollector";
125
- // Issue #269: Transitive modification propagation for const inference
126
- import TransitiveModificationPropagator from "./helpers/TransitiveModificationPropagator";
127
- // Issue #566: Child statement/block collection for const inference
128
- import ChildStatementCollector from "./helpers/ChildStatementCollector";
129
- // SonarCloud S3776: Assignment target extraction for walkStatementForModifications
130
- import AssignmentTargetExtractor from "./helpers/AssignmentTargetExtractor";
127
+ // Issue #269: Transitive modification propagation for const inference (used by analyzeModificationsOnly)
128
+ import TransitiveModificationPropagator from "../../logic/analysis/helpers/TransitiveModificationPropagator";
131
129
  // Phase 3: Type generation helper for improved testability
132
130
  import TypeGenerationHelper from "./helpers/TypeGenerationHelper";
133
131
  // Phase 5: Cast validation helper for improved testability
134
132
  import CastValidator from "./helpers/CastValidator";
133
+ // Issue #793: Function context lifecycle and parameter processing helper
134
+ import FunctionContextManager from "./helpers/FunctionContextManager";
135
+ import IFunctionContextCallbacks from "./types/IFunctionContextCallbacks";
135
136
  // Global state for code generation (simplifies debugging, eliminates DI complexity)
136
137
  import CodeGenState from "../../state/CodeGenState";
138
+ // Issue #269: Pass-by-value analysis extracted from CodeGenerator
139
+ import PassByValueAnalyzer from "../../logic/analysis/PassByValueAnalyzer";
137
140
  // Unified parameter generation (Phase 1)
138
141
  import ParameterInputAdapter from "./helpers/ParameterInputAdapter";
139
142
  import ParameterSignatureBuilder from "./helpers/ParameterSignatureBuilder";
@@ -141,6 +144,8 @@ import ParameterSignatureBuilder from "./helpers/ParameterSignatureBuilder";
141
144
  import SizeofResolver from "./resolution/SizeofResolver";
142
145
  import EnumTypeResolver from "./resolution/EnumTypeResolver";
143
146
  import ScopeResolver from "./resolution/ScopeResolver";
147
+ // Issue #797: Centralized C-style name generation
148
+ import QualifiedNameGenerator from "./utils/QualifiedNameGenerator";
144
149
 
145
150
  const {
146
151
  generateOverflowHelpers: helperGenerateOverflowHelpers,
@@ -387,7 +392,7 @@ export default class CodeGenerator implements IOrchestrator {
387
392
  return {
388
393
  symbolTable: CodeGenState.symbolTable,
389
394
  symbols: CodeGenState.symbols,
390
- typeRegistry: CodeGenState.typeRegistry,
395
+ typeRegistry: CodeGenState.getTypeRegistryView(),
391
396
  functionSignatures: CodeGenState.functionSignatures,
392
397
  knownFunctions: CodeGenState.knownFunctions,
393
398
  knownStructs: CodeGenState.symbols?.knownStructs ?? new Set(),
@@ -451,7 +456,7 @@ export default class CodeGenerator implements IOrchestrator {
451
456
 
452
457
  // Type registration effects
453
458
  case "register-type":
454
- CodeGenState.typeRegistry.set(effect.name, effect.info);
459
+ CodeGenState.setVariableTypeInfo(effect.name, effect.info);
455
460
  break;
456
461
  case "register-local":
457
462
  CodeGenState.localVariables.add(effect.name);
@@ -727,7 +732,7 @@ export default class CodeGenerator implements IOrchestrator {
727
732
 
728
733
  // Check if it's a simple variable of string type
729
734
  if (/^[a-zA-Z_]\w*$/.exec(text)) {
730
- const typeInfo = CodeGenState.typeRegistry.get(text);
735
+ const typeInfo = CodeGenState.getVariableTypeInfo(text);
731
736
  if (typeInfo?.isString) {
732
737
  return true;
733
738
  }
@@ -759,7 +764,7 @@ export default class CodeGenerator implements IOrchestrator {
759
764
  }
760
765
 
761
766
  const arrayName = arrayAccessMatch[1];
762
- const typeInfo = CodeGenState.typeRegistry.get(arrayName);
767
+ const typeInfo = CodeGenState.getVariableTypeInfo(arrayName);
763
768
  if (!typeInfo) {
764
769
  return false;
765
770
  }
@@ -864,13 +869,20 @@ export default class CodeGenerator implements IOrchestrator {
864
869
 
865
870
  /**
866
871
  * Generate function argument with pass-by-reference handling.
867
- * Part of IOrchestrator interface - delegates to private implementation.
872
+ * Part of IOrchestrator interface - delegates to ArgumentGenerator.
868
873
  */
869
874
  generateFunctionArg(
870
875
  ctx: Parser.ExpressionContext,
871
876
  targetParamBaseType?: string,
872
877
  ): string {
873
- return this._generateFunctionArg(ctx, targetParamBaseType);
878
+ const simpleId = CodegenParserUtils.getSimpleIdentifier(ctx);
879
+ return ArgumentGenerator.generateArg(ctx, simpleId, targetParamBaseType, {
880
+ getLvalueType: (c) => this.getLvalueType(c),
881
+ getMemberAccessArrayStatus: (c) => this.getMemberAccessArrayStatus(c),
882
+ needsCppMemberConversion: (c, t) => this.needsCppMemberConversion(c, t),
883
+ isStringSubscriptAccess: (c) => this.isStringSubscriptAccess(c),
884
+ generateExpression: (c) => this.generateExpression(c),
885
+ });
874
886
  }
875
887
 
876
888
  /**
@@ -1360,21 +1372,7 @@ export default class CodeGenerator implements IOrchestrator {
1360
1372
 
1361
1373
  /** Get the capacity of a string expression */
1362
1374
  getStringExprCapacity(exprCode: string): number | null {
1363
- // String literal - capacity equals content length
1364
- if (exprCode.startsWith('"') && exprCode.endsWith('"')) {
1365
- return StringUtils.literalLength(exprCode);
1366
- }
1367
-
1368
- // Variable - check type registry
1369
- const identifierRegex = /^[a-zA-Z_]\w*$/;
1370
- if (identifierRegex.test(exprCode)) {
1371
- const typeInfo = CodeGenState.typeRegistry.get(exprCode);
1372
- if (typeInfo?.isString && typeInfo.stringCapacity !== undefined) {
1373
- return typeInfo.stringCapacity;
1374
- }
1375
- }
1376
-
1377
- return null;
1375
+ return StringOperationsHelper.getStringExprCapacity(exprCode);
1378
1376
  }
1379
1377
 
1380
1378
  // === Parameter Management (IOrchestrator A4) ===
@@ -1433,25 +1431,20 @@ export default class CodeGenerator implements IOrchestrator {
1433
1431
 
1434
1432
  // === Function Body Management (A4) ===
1435
1433
 
1434
+ /**
1435
+ * Enter function body - clears local variables and sets inFunctionBody flag.
1436
+ * Issue #793: Delegates to FunctionContextManager.
1437
+ */
1436
1438
  enterFunctionBody(): void {
1437
- CodeGenState.localVariables.clear();
1438
- CodeGenState.floatBitShadows.clear();
1439
- CodeGenState.floatShadowCurrent.clear();
1440
- // Issue #558: modifiedParameters tracking removed - uses analysis-phase results
1441
- CodeGenState.inFunctionBody = true;
1442
- // Sync with CodeGenState
1443
- CodeGenState.enterFunctionBody();
1439
+ FunctionContextManager.enterFunctionBody();
1444
1440
  }
1445
1441
 
1442
+ /**
1443
+ * Exit function body - clears local variables and inFunctionBody flag.
1444
+ * Issue #793: Delegates to FunctionContextManager.
1445
+ */
1446
1446
  exitFunctionBody(): void {
1447
- CodeGenState.inFunctionBody = false;
1448
- CodeGenState.localVariables.clear();
1449
- CodeGenState.floatBitShadows.clear();
1450
- CodeGenState.floatShadowCurrent.clear();
1451
- CodeGenState.mainArgsName = null;
1452
- // Sync with CodeGenState
1453
- CodeGenState.exitFunctionBody();
1454
- CodeGenState.mainArgsName = null;
1447
+ FunctionContextManager.exitFunctionBody();
1455
1448
  }
1456
1449
 
1457
1450
  setMainArgsName(name: string | null): void {
@@ -1604,7 +1597,7 @@ export default class CodeGenerator implements IOrchestrator {
1604
1597
  const injectedFuncs = new Set(crossFileModifications?.keys() ?? []);
1605
1598
 
1606
1599
  // Run modification analysis on the tree (adds to what was injected)
1607
- this.collectFunctionParametersAndModifications(tree);
1600
+ PassByValueAnalyzer.collectFunctionParametersAndModifications(tree);
1608
1601
 
1609
1602
  // Issue #565: Run transitive propagation with full context
1610
1603
  TransitiveModificationPropagator.propagate(
@@ -1951,7 +1944,7 @@ export default class CodeGenerator implements IOrchestrator {
1951
1944
  isKnownPrimitive: (typeName: string) => this._isKnownPrimitive(typeName),
1952
1945
  knownEnums: CodeGenState.symbols!.knownEnums,
1953
1946
  isParameterPassByValue: (funcName: string, paramName: string) =>
1954
- this._isParameterPassByValueByName(funcName, paramName),
1947
+ PassByValueAnalyzer.isParameterPassByValueByName(funcName, paramName),
1955
1948
  currentFunctionName: CodeGenState.currentFunctionName,
1956
1949
  maybeDereference: (id: string) => CppModeHelper.maybeDereference(id),
1957
1950
  };
@@ -2171,19 +2164,18 @@ export default class CodeGenerator implements IOrchestrator {
2171
2164
  }
2172
2165
 
2173
2166
  // Issue #461: Initialize constValues from symbol table
2167
+ // Only C-Next TSymbols have initialValue property
2174
2168
  CodeGenState.constValues = new Map();
2175
2169
  if (CodeGenState.symbolTable) {
2176
- for (const symbol of CodeGenState.symbolTable.getAllSymbols()) {
2170
+ for (const symbol of CodeGenState.symbolTable.getAllTSymbols()) {
2177
2171
  if (
2178
- symbol.kind === ESymbolKind.Variable &&
2172
+ symbol.kind === "variable" &&
2179
2173
  symbol.isConst &&
2180
2174
  symbol.initialValue !== undefined
2181
2175
  ) {
2182
2176
  const value = LiteralUtils.parseIntegerLiteral(symbol.initialValue);
2183
2177
  if (value !== undefined) {
2184
2178
  CodeGenState.constValues.set(symbol.name, value);
2185
- // Also populate CodeGenState
2186
- CodeGenState.constValues.set(symbol.name, value);
2187
2179
  }
2188
2180
  }
2189
2181
  }
@@ -2196,7 +2188,7 @@ export default class CodeGenerator implements IOrchestrator {
2196
2188
  private initializeHelperObjects(tree: Parser.ProgramContext): void {
2197
2189
  // Collect function/callback information
2198
2190
  this.collectFunctionsAndCallbacks(tree);
2199
- this.analyzePassByValue(tree);
2191
+ PassByValueAnalyzer.analyze(tree);
2200
2192
  }
2201
2193
 
2202
2194
  /**
@@ -2491,7 +2483,10 @@ export default class CodeGenerator implements IOrchestrator {
2491
2483
  const funcDecl = member.functionDeclaration()!;
2492
2484
  const funcName = funcDecl.IDENTIFIER().getText();
2493
2485
  // Track fully qualified function name: Scope_function
2494
- const fullName = `${scopeName}_${funcName}`;
2486
+ const fullName = QualifiedNameGenerator.forFunctionStrings(
2487
+ scopeName,
2488
+ funcName,
2489
+ );
2495
2490
  CodeGenState.knownFunctions.add(fullName);
2496
2491
  // ADR-013: Track function signature for const checking
2497
2492
  const sig = this.extractFunctionSignature(
@@ -2556,66 +2551,11 @@ export default class CodeGenerator implements IOrchestrator {
2556
2551
  * SonarCloud S3776: Refactored to use helper methods.
2557
2552
  */
2558
2553
  private registerAllVariableTypes(tree: Parser.ProgramContext): void {
2559
- for (const decl of tree.declaration()) {
2560
- // Register global variable types
2561
- if (decl.variableDeclaration()) {
2562
- this.registerGlobalVariableType(decl.variableDeclaration()!);
2563
- }
2564
-
2565
- // Register scope member variable types
2566
- if (decl.scopeDeclaration()) {
2567
- this.registerScopeMemberTypes(decl.scopeDeclaration()!);
2568
- }
2569
-
2570
- // Note: Function parameters are registered per-function during generation
2571
- // since they're scoped to the function body
2572
- }
2573
- }
2574
-
2575
- /**
2576
- * Register a global variable type and track const values.
2577
- * SonarCloud S3776: Extracted from registerAllVariableTypes().
2578
- */
2579
- private registerGlobalVariableType(
2580
- varDecl: Parser.VariableDeclarationContext,
2581
- ): void {
2582
- this.trackVariableType(varDecl);
2583
-
2584
- // Bug #8: Track const values for array size resolution at file scope
2585
- if (varDecl.constModifier() && varDecl.expression()) {
2586
- const constName = varDecl.IDENTIFIER().getText();
2587
- const constValue = this.tryEvaluateConstant(varDecl.expression()!);
2588
- if (constValue !== undefined) {
2589
- CodeGenState.constValues.set(constName, constValue);
2590
- }
2591
- }
2592
- }
2593
-
2594
- /**
2595
- * Register scope member variable types.
2596
- * SonarCloud S3776: Extracted from registerAllVariableTypes().
2597
- */
2598
- private registerScopeMemberTypes(
2599
- scopeDecl: Parser.ScopeDeclarationContext,
2600
- ): void {
2601
- const scopeName = scopeDecl.IDENTIFIER().getText();
2602
-
2603
- // Set currentScope so that this.Type references resolve correctly
2604
- const savedScope = CodeGenState.currentScope;
2605
- this.setCurrentScope(scopeName);
2606
-
2607
- for (const member of scopeDecl.scopeMember()) {
2608
- if (member.variableDeclaration()) {
2609
- const varDecl = member.variableDeclaration()!;
2610
- const varName = varDecl.IDENTIFIER().getText();
2611
- const fullName = `${scopeName}_${varName}`;
2612
- // Register with mangled name (Scope_variable)
2613
- this.trackVariableTypeWithName(varDecl, fullName);
2614
- }
2615
- }
2616
-
2617
- // Restore previous scope
2618
- this.setCurrentScope(savedScope);
2554
+ TypeRegistrationEngine.register(tree, {
2555
+ tryEvaluateConstant: (ctx) => this.tryEvaluateConstant(ctx),
2556
+ requireInclude: (header) => this.requireInclude(header),
2557
+ resolveQualifiedType: (ids) => this.resolveQualifiedType(ids),
2558
+ });
2619
2559
  }
2620
2560
 
2621
2561
  // Issue #60: collectEnum and collectBitmap methods removed - now in SymbolCollector
@@ -2623,1530 +2563,209 @@ export default class CodeGenerator implements IOrchestrator {
2623
2563
  // Issue #63: validateBitmapFieldLiteral moved to TypeValidator
2624
2564
  // Issue #60: evaluateConstantExpression method removed - now in SymbolCollector
2625
2565
 
2626
- // ========================================================================
2627
- // Issue #269: Pass-by-value analysis for small unmodified parameters
2628
- // ========================================================================
2566
+ // Issue #269: Pass-by-value analysis extracted to PassByValueAnalyzer
2629
2567
 
2630
2568
  /**
2631
- * Analyze all functions to determine which parameters should pass by value.
2632
- * This runs before code generation and populates passByValueParams.
2633
- * SonarCloud S3776: Refactored to use helper methods.
2569
+ * Issue #269: Check if a parameter should be passed by value (by index).
2570
+ * Part of IOrchestrator interface - used by CallExprGenerator.
2571
+ * Delegates to PassByValueAnalyzer.
2634
2572
  */
2635
- private analyzePassByValue(tree: Parser.ProgramContext): void {
2636
- // Reset analysis state
2637
- CodeGenState.modifiedParameters.clear();
2638
- CodeGenState.passByValueParams.clear();
2639
- CodeGenState.functionCallGraph.clear();
2640
- CodeGenState.functionParamLists.clear();
2641
-
2642
- // Phase 1: Collect function parameter lists and direct modifications
2643
- this.collectFunctionParametersAndModifications(tree);
2644
-
2645
- // Issue #558: Inject cross-file data before transitive propagation
2646
- this.injectCrossFileModifications();
2647
- this.injectCrossFileParamLists();
2648
-
2649
- // Phase 2: Fixed-point iteration for transitive modifications
2650
- TransitiveModificationPropagator.propagate(
2651
- CodeGenState.functionCallGraph,
2652
- CodeGenState.functionParamLists,
2653
- CodeGenState.modifiedParameters,
2654
- );
2655
-
2656
- // Phase 3: Determine which parameters can pass by value
2657
- this.computePassByValueParams();
2573
+ isParameterPassByValue(funcName: string, paramIndex: number): boolean {
2574
+ return PassByValueAnalyzer.isParameterPassByValue(funcName, paramIndex);
2658
2575
  }
2659
2576
 
2660
2577
  /**
2661
- * Inject cross-file modification data into modifiedParameters.
2662
- * SonarCloud S3776: Extracted from analyzePassByValue().
2578
+ * Issue #269: Get all pass-by-value parameters.
2579
+ * Returns a Map from function name to Set of parameter names that should be pass-by-value.
2580
+ * Used by HeaderGenerator to ensure header and implementation signatures match.
2663
2581
  */
2664
- private injectCrossFileModifications(): void {
2665
- if (!CodeGenState.pendingCrossFileModifications) return;
2666
-
2667
- for (const [
2668
- funcName,
2669
- params,
2670
- ] of CodeGenState.pendingCrossFileModifications) {
2671
- const existing = CodeGenState.modifiedParameters.get(funcName);
2672
- if (existing) {
2673
- for (const param of params) {
2674
- existing.add(param);
2675
- }
2676
- } else {
2677
- CodeGenState.modifiedParameters.set(funcName, new Set(params));
2678
- }
2679
- }
2680
- CodeGenState.pendingCrossFileModifications = null; // Clear after use
2582
+ getPassByValueParams(): ReadonlyMap<string, ReadonlySet<string>> {
2583
+ return CodeGenState.passByValueParams;
2681
2584
  }
2682
2585
 
2683
2586
  /**
2684
- * Inject cross-file parameter lists into functionParamLists.
2685
- * SonarCloud S3776: Extracted from analyzePassByValue().
2587
+ * Issue #322: Check if a type name is a user-defined struct
2588
+ * Part of IOrchestrator interface.
2686
2589
  */
2687
- private injectCrossFileParamLists(): void {
2688
- if (!CodeGenState.pendingCrossFileParamLists) return;
2689
-
2690
- for (const [funcName, params] of CodeGenState.pendingCrossFileParamLists) {
2691
- if (!CodeGenState.functionParamLists.has(funcName)) {
2692
- CodeGenState.functionParamLists.set(funcName, [...params]);
2693
- }
2694
- }
2695
- CodeGenState.pendingCrossFileParamLists = null; // Clear after use
2590
+ isStructType(typeName: string): boolean {
2591
+ return TypeResolver.isStructType(typeName);
2696
2592
  }
2697
2593
 
2698
2594
  /**
2699
- * Phase 1: Walk all functions to collect:
2700
- * - Parameter lists (for call graph resolution)
2701
- * - Direct modifications (param <- value)
2702
- * - Function calls where params are passed as arguments
2595
+ * Set up parameter tracking for a function.
2596
+ * Issue #793: Delegates to FunctionContextManager.
2703
2597
  */
2704
- private collectFunctionParametersAndModifications(
2705
- tree: Parser.ProgramContext,
2706
- ): void {
2707
- for (const decl of tree.declaration()) {
2708
- // Handle scope-level functions
2709
- if (decl.scopeDeclaration()) {
2710
- const scopeDecl = decl.scopeDeclaration()!;
2711
- const scopeName = scopeDecl.IDENTIFIER().getText();
2712
-
2713
- for (const member of scopeDecl.scopeMember()) {
2714
- if (member.functionDeclaration()) {
2715
- const funcDecl = member.functionDeclaration()!;
2716
- const funcName = funcDecl.IDENTIFIER().getText();
2717
- const fullName = `${scopeName}_${funcName}`;
2718
- this.analyzeFunctionForModifications(fullName, funcDecl);
2719
- }
2720
- }
2721
- }
2722
-
2723
- // Handle top-level functions
2724
- if (decl.functionDeclaration()) {
2725
- const funcDecl = decl.functionDeclaration()!;
2726
- const name = funcDecl.IDENTIFIER().getText();
2727
- this.analyzeFunctionForModifications(name, funcDecl);
2728
- }
2729
- }
2598
+ private _setParameters(params: Parser.ParameterListContext | null): void {
2599
+ FunctionContextManager.processParameterList(
2600
+ params,
2601
+ this._getFunctionContextCallbacks(),
2602
+ );
2730
2603
  }
2731
2604
 
2732
2605
  /**
2733
- * Analyze a single function for parameter modifications and call graph edges.
2606
+ * Clear parameter tracking when leaving a function.
2607
+ * Issue #793: Delegates to FunctionContextManager.
2734
2608
  */
2735
- private analyzeFunctionForModifications(
2736
- funcName: string,
2737
- funcDecl: Parser.FunctionDeclarationContext,
2738
- ): void {
2739
- // Collect parameter names
2740
- const paramNames: string[] = [];
2741
- const paramList = funcDecl.parameterList();
2742
- if (paramList) {
2743
- for (const param of paramList.parameter()) {
2744
- paramNames.push(param.IDENTIFIER().getText());
2745
- }
2746
- }
2747
- CodeGenState.functionParamLists.set(funcName, paramNames);
2748
-
2749
- // Initialize modified set
2750
- CodeGenState.modifiedParameters.set(funcName, new Set());
2751
- // Issue #579: Initialize subscript access tracking
2752
- CodeGenState.subscriptAccessedParameters.set(funcName, new Set());
2753
- CodeGenState.functionCallGraph.set(funcName, []);
2754
-
2755
- // Walk the function body to find modifications and calls
2756
- const block = funcDecl.block();
2757
- if (block) {
2758
- this.walkBlockForModifications(funcName, paramNames, block);
2759
- }
2609
+ private _clearParameters(): void {
2610
+ FunctionContextManager.clearParameters();
2760
2611
  }
2761
2612
 
2762
2613
  /**
2763
- * Walk a block to find parameter modifications and function calls.
2614
+ * ADR-013: Extract function signature from parameter list
2764
2615
  */
2765
- private walkBlockForModifications(
2766
- funcName: string,
2767
- paramNames: string[],
2768
- block: Parser.BlockContext,
2769
- ): void {
2770
- const paramSet = new Set(paramNames);
2616
+ private extractFunctionSignature(
2617
+ name: string,
2618
+ params: Parser.ParameterListContext | null,
2619
+ ): FunctionSignature {
2620
+ const parameters: Array<{
2621
+ name: string;
2622
+ baseType: string;
2623
+ isConst: boolean;
2624
+ isArray: boolean;
2625
+ }> = [];
2771
2626
 
2772
- for (const stmt of block.statement()) {
2773
- this.walkStatementForModifications(funcName, paramSet, stmt);
2627
+ if (params) {
2628
+ for (const param of params.parameter()) {
2629
+ const paramName = param.IDENTIFIER().getText();
2630
+ const isConst = param.constModifier() !== null;
2631
+ // arrayDimension() returns an array (due to grammar's *), so check length
2632
+ // Also check C-Next style array type (e.g., u8[8] param)
2633
+ const isArray =
2634
+ param.arrayDimension().length > 0 ||
2635
+ param.type().arrayType() !== null;
2636
+ const baseType = this.getTypeName(param.type());
2637
+ parameters.push({ name: paramName, baseType, isConst, isArray });
2638
+ }
2774
2639
  }
2640
+
2641
+ return { name, parameters };
2775
2642
  }
2776
2643
 
2777
2644
  /**
2778
- * Walk a statement recursively looking for modifications and calls.
2779
- * Issue #566: Refactored to use helper methods for expression and child collection.
2645
+ * ADR-029: Register a function as a callback type
2646
+ * The function name becomes both a callable function and a type for callback fields
2780
2647
  */
2781
- private walkStatementForModifications(
2782
- funcName: string,
2783
- paramSet: Set<string>,
2784
- stmt: Parser.StatementContext,
2648
+ private registerCallbackType(
2649
+ name: string,
2650
+ funcDecl: Parser.FunctionDeclarationContext,
2785
2651
  ): void {
2786
- // 1. Check for parameter modifications via assignment targets
2787
- if (stmt.assignmentStatement()) {
2788
- this.trackAssignmentModifications(funcName, paramSet, stmt);
2789
- }
2652
+ const returnType = this.generateType(funcDecl.type());
2653
+ const parameters: Array<{
2654
+ name: string;
2655
+ type: string;
2656
+ isConst: boolean;
2657
+ isPointer: boolean;
2658
+ isArray: boolean;
2659
+ arrayDims: string;
2660
+ }> = [];
2790
2661
 
2791
- // 2. Walk all expressions in this statement for function calls and subscript access
2792
- for (const expr of StatementExpressionCollector.collectAll(stmt)) {
2793
- this.walkExpressionForCalls(funcName, paramSet, expr);
2794
- // Issue #579: Also track subscript read access on parameters
2795
- this.walkExpressionForSubscriptAccess(funcName, paramSet, expr);
2796
- }
2662
+ if (funcDecl.parameterList()) {
2663
+ for (const param of funcDecl.parameterList()!.parameter()) {
2664
+ const paramName = param.IDENTIFIER().getText();
2665
+ const typeName = this.getTypeName(param.type());
2666
+ const isConst = param.constModifier() !== null;
2667
+ const dims = param.arrayDimension();
2668
+ const arrayTypeCtx = param.type().arrayType();
2669
+ const isArray = dims.length > 0 || arrayTypeCtx !== null;
2797
2670
 
2798
- // 3. Recurse into child statements and blocks
2799
- const { statements, blocks } = ChildStatementCollector.collectAll(stmt);
2800
- for (const childStmt of statements) {
2801
- this.walkStatementForModifications(funcName, paramSet, childStmt);
2802
- }
2803
- for (const block of blocks) {
2804
- this.walkBlockForModifications(funcName, [...paramSet], block);
2805
- }
2806
- }
2671
+ // ADR-029: Check if parameter type is itself a callback type
2672
+ const isCallbackParam = CodeGenState.callbackTypes.has(typeName);
2807
2673
 
2808
- /**
2809
- * Track assignment modifications for parameter const inference.
2810
- * SonarCloud S3776: Extracted from walkStatementForModifications().
2811
- */
2812
- private trackAssignmentModifications(
2813
- funcName: string,
2814
- paramSet: Set<string>,
2815
- stmt: Parser.StatementContext,
2816
- ): void {
2817
- const assign = stmt.assignmentStatement()!;
2818
- const target = assign.assignmentTarget();
2674
+ let paramType: string;
2675
+ let isPointer: boolean;
2819
2676
 
2820
- const { baseIdentifier, hasSingleIndexSubscript } =
2821
- AssignmentTargetExtractor.extract(target);
2677
+ if (isCallbackParam) {
2678
+ // Use the callback typedef name
2679
+ const cbInfo = CodeGenState.callbackTypes.get(typeName)!;
2680
+ paramType = cbInfo.typedefName;
2681
+ isPointer = false; // Function pointers are already pointers
2682
+ } else {
2683
+ paramType = this.generateType(param.type());
2684
+ // ADR-006: Non-array parameters become pointers
2685
+ isPointer = !isArray;
2686
+ }
2822
2687
 
2823
- // Issue #579: Track subscript access on parameters (for write path)
2824
- if (
2825
- hasSingleIndexSubscript &&
2826
- baseIdentifier &&
2827
- paramSet.has(baseIdentifier)
2828
- ) {
2829
- CodeGenState.subscriptAccessedParameters
2830
- .get(funcName)!
2831
- .add(baseIdentifier);
2688
+ let arrayDims: string;
2689
+ if (dims.length > 0) {
2690
+ arrayDims = dims.map((d) => this.generateArrayDimension(d)).join("");
2691
+ } else if (arrayTypeCtx) {
2692
+ // Generate all dimensions from arrayType (supports multi-dimensional)
2693
+ arrayDims = arrayTypeCtx
2694
+ .arrayTypeDimension()
2695
+ .map((d) => {
2696
+ const expr = d.expression();
2697
+ return expr ? `[${this.generateExpression(expr)}]` : "[]";
2698
+ })
2699
+ .join("");
2700
+ } else {
2701
+ arrayDims = "";
2702
+ }
2703
+ parameters.push({
2704
+ name: paramName,
2705
+ type: paramType,
2706
+ isConst,
2707
+ isPointer,
2708
+ isArray,
2709
+ arrayDims,
2710
+ });
2711
+ }
2832
2712
  }
2833
2713
 
2834
- // Track as modified parameter
2835
- if (baseIdentifier && paramSet.has(baseIdentifier)) {
2836
- CodeGenState.modifiedParameters.get(funcName)!.add(baseIdentifier);
2837
- }
2714
+ CodeGenState.callbackTypes.set(name, {
2715
+ functionName: name,
2716
+ returnType,
2717
+ parameters,
2718
+ typedefName: `${name}_fp`,
2719
+ });
2838
2720
  }
2839
2721
 
2840
2722
  /**
2841
- * Walk an expression tree to find function calls where parameters are passed.
2842
- * Uses recursive descent through the expression hierarchy.
2723
+ * ADR-029: Check if a function is used as a callback type (field type in a struct)
2843
2724
  */
2844
- private walkExpressionForCalls(
2845
- funcName: string,
2846
- paramSet: Set<string>,
2847
- expr: Parser.ExpressionContext,
2848
- ): void {
2849
- // Expression -> TernaryExpression -> OrExpression -> ... -> PostfixExpression
2850
- const ternary = expr.ternaryExpression();
2851
- if (ternary) {
2852
- // Walk all orExpression children
2853
- for (const orExpr of ternary.orExpression()) {
2854
- this.walkOrExpressionForCalls(funcName, paramSet, orExpr);
2855
- }
2856
- }
2857
- }
2725
+ // Issue #63: validateCallbackAssignment, callbackSignaturesMatch, isConstValue,
2726
+ // and validateBareIdentifierInScope moved to TypeValidator
2858
2727
 
2728
+ // EnumTypeResolver now handles: _getEnumTypeFromThisEnum, _getEnumTypeFromGlobalEnum,
2729
+ // _getEnumTypeFromThisVariable, _getEnumTypeFromScopedEnum, _getEnumTypeFromMemberAccess,
2730
+ // _getExpressionEnumType, _getFunctionCallEnumType
2859
2731
  /**
2860
- * Issue #579: Walk an expression tree to find subscript access on parameters.
2861
- * This tracks read access like `buf[i]` where buf is a parameter.
2862
- * Parameters with subscript access must become pointers.
2732
+ * ADR-017: Check if an expression represents an integer literal or numeric type.
2733
+ * Used to detect comparisons between enums and integers.
2863
2734
  */
2864
- private walkExpressionForSubscriptAccess(
2865
- funcName: string,
2866
- paramSet: Set<string>,
2867
- expr: Parser.ExpressionContext,
2868
- ): void {
2869
- const ternary = expr.ternaryExpression();
2870
- if (ternary) {
2871
- for (const orExpr of ternary.orExpression()) {
2872
- this.walkOrExpression(orExpr, (unaryExpr) => {
2873
- this.handleSubscriptAccess(funcName, paramSet, unaryExpr);
2874
- });
2875
- }
2876
- }
2735
+ private _isIntegerExpression(
2736
+ ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
2737
+ ): boolean {
2738
+ return EnumAssignmentValidator.isIntegerExpression(ctx);
2877
2739
  }
2878
2740
 
2879
2741
  /**
2880
- * Issue #579: Handle subscript access on a unary expression.
2881
- * Only tracks single-index subscript access (which could be array access).
2882
- * Two-index subscript (e.g., value[start, width]) is always bit extraction,
2883
- * so it doesn't require the parameter to become a pointer.
2742
+ * ADR-045: Check if an expression is a string concatenation.
2743
+ * Delegates to StringOperationsHelper.
2884
2744
  */
2885
- private handleSubscriptAccess(
2886
- funcName: string,
2887
- paramSet: Set<string>,
2888
- unaryExpr: Parser.UnaryExpressionContext,
2889
- ): void {
2890
- const postfixExpr = unaryExpr.postfixExpression();
2891
- if (!postfixExpr) return;
2892
-
2893
- const primary = postfixExpr.primaryExpression();
2894
- const ops = postfixExpr.postfixOp();
2895
-
2896
- // Check if primary is a parameter and there's subscript access
2897
- const primaryId = primary.IDENTIFIER()?.getText();
2898
- if (!primaryId || !paramSet.has(primaryId)) {
2899
- return;
2900
- }
2901
-
2902
- // Only track SINGLE-index subscript access (potential array access)
2903
- // Two-index subscript like value[0, 8] is bit extraction, not array access
2904
- const hasSingleIndexSubscript = ops.some(
2905
- (op) => op.expression().length === 1,
2906
- );
2907
- if (hasSingleIndexSubscript) {
2908
- CodeGenState.subscriptAccessedParameters.get(funcName)!.add(primaryId);
2909
- }
2745
+ private _getStringConcatOperands(ctx: Parser.ExpressionContext): {
2746
+ left: string;
2747
+ right: string;
2748
+ leftCapacity: number;
2749
+ rightCapacity: number;
2750
+ } | null {
2751
+ return StringOperationsHelper.getStringConcatOperands(ctx);
2910
2752
  }
2911
2753
 
2912
2754
  /**
2913
- * Generic walker for orExpression trees.
2914
- * Walks through the expression hierarchy and calls the handler for each unaryExpression.
2915
- * Used by both function call tracking and subscript access tracking.
2755
+ * ADR-045: Check if an expression is a substring extraction.
2756
+ * Delegates to StringOperationsHelper.
2916
2757
  */
2917
- private walkOrExpression(
2918
- orExpr: Parser.OrExpressionContext,
2919
- handler: (unaryExpr: Parser.UnaryExpressionContext) => void,
2920
- ): void {
2921
- orExpr
2922
- .andExpression()
2923
- .flatMap((and) => and.equalityExpression())
2924
- .flatMap((eq) => eq.relationalExpression())
2925
- .flatMap((rel) => rel.bitwiseOrExpression())
2926
- .flatMap((bor) => bor.bitwiseXorExpression())
2927
- .flatMap((bxor) => bxor.bitwiseAndExpression())
2928
- .flatMap((band) => band.shiftExpression())
2929
- .flatMap((shift) => shift.additiveExpression())
2930
- .flatMap((add) => add.multiplicativeExpression())
2931
- .flatMap((mul) => mul.unaryExpression())
2932
- .forEach(handler);
2933
- }
2934
-
2935
- /**
2936
- * Walk an orExpression tree for function calls.
2937
- */
2938
- private walkOrExpressionForCalls(
2939
- funcName: string,
2940
- paramSet: Set<string>,
2941
- orExpr: Parser.OrExpressionContext,
2942
- ): void {
2943
- this.walkOrExpression(orExpr, (unaryExpr) => {
2944
- this.walkUnaryExpressionForCalls(funcName, paramSet, unaryExpr);
2758
+ private _getSubstringOperands(ctx: Parser.ExpressionContext): {
2759
+ source: string;
2760
+ start: string;
2761
+ length: string;
2762
+ sourceCapacity: number;
2763
+ } | null {
2764
+ return StringOperationsHelper.getSubstringOperands(ctx, {
2765
+ generateExpression: (exprCtx) => this.generateExpression(exprCtx),
2945
2766
  });
2946
2767
  }
2947
2768
 
2948
- /**
2949
- * Walk a unaryExpression tree for function calls.
2950
- */
2951
- private walkUnaryExpressionForCalls(
2952
- funcName: string,
2953
- paramSet: Set<string>,
2954
- unaryExpr: Parser.UnaryExpressionContext,
2955
- ): void {
2956
- // Recurse into nested unary
2957
- if (unaryExpr.unaryExpression()) {
2958
- this.walkUnaryExpressionForCalls(
2959
- funcName,
2960
- paramSet,
2961
- unaryExpr.unaryExpression()!,
2962
- );
2963
- return;
2964
- }
2965
-
2966
- // Check postfix expression
2967
- const postfix = unaryExpr.postfixExpression();
2968
- if (postfix) {
2969
- this.walkPostfixExpressionForCalls(funcName, paramSet, postfix);
2970
- }
2971
- }
2972
-
2973
- /**
2974
- * Walk a postfixExpression for function calls.
2975
- * This is where function calls are found: primaryExpr followed by '(' args ')'
2976
- */
2977
- private walkPostfixExpressionForCalls(
2978
- funcName: string,
2979
- paramSet: Set<string>,
2980
- postfix: Parser.PostfixExpressionContext,
2981
- ): void {
2982
- const primary = postfix.primaryExpression();
2983
- const postfixOps = postfix.postfixOp();
2984
-
2985
- // Handle simple function calls: IDENTIFIER followed by '(' ... ')'
2986
- this.handleSimpleFunctionCall(funcName, paramSet, primary, postfixOps);
2987
-
2988
- // Issue #365: Handle scope-qualified calls: Scope.method(...) or global.Scope.method(...)
2989
- this.handleScopeQualifiedCalls(funcName, paramSet, primary, postfixOps);
2990
-
2991
- // Recurse into primary expression if it's a parenthesized expression
2992
- if (primary.expression()) {
2993
- this.walkExpressionForCalls(funcName, paramSet, primary.expression()!);
2994
- }
2995
-
2996
- // Walk arguments in any postfix function call ops (for nested calls)
2997
- this.walkPostfixOpsRecursively(funcName, paramSet, postfixOps);
2998
- }
2999
-
3000
- /**
3001
- * Handle simple function calls: IDENTIFIER followed by '(' ... ')'
3002
- */
3003
- private handleSimpleFunctionCall(
3004
- funcName: string,
3005
- paramSet: Set<string>,
3006
- primary: Parser.PrimaryExpressionContext,
3007
- postfixOps: Parser.PostfixOpContext[],
3008
- ): void {
3009
- if (!primary.IDENTIFIER() || postfixOps.length === 0) return;
3010
-
3011
- const firstOp = postfixOps[0];
3012
- if (!firstOp.LPAREN()) return;
3013
-
3014
- const calleeName = primary.IDENTIFIER()!.getText();
3015
- this.recordCallsFromArgList(funcName, paramSet, calleeName, firstOp);
3016
- }
3017
-
3018
- /**
3019
- * Handle scope-qualified calls: Scope.method(...) or global.Scope.method(...)
3020
- * Track member accesses to build the mangled callee name (e.g., Storage_load)
3021
- */
3022
- private handleScopeQualifiedCalls(
3023
- funcName: string,
3024
- paramSet: Set<string>,
3025
- primary: Parser.PrimaryExpressionContext,
3026
- postfixOps: Parser.PostfixOpContext[],
3027
- ): void {
3028
- if (postfixOps.length === 0) return;
3029
-
3030
- const memberNames = this.collectInitialMemberNames(funcName, primary);
3031
-
3032
- for (const op of postfixOps) {
3033
- if (op.IDENTIFIER()) {
3034
- memberNames.push(op.IDENTIFIER()!.getText());
3035
- } else if (op.LPAREN() && memberNames.length >= 1) {
3036
- const calleeName = memberNames.join("_");
3037
- this.recordCallsFromArgList(funcName, paramSet, calleeName, op);
3038
- memberNames.length = 0; // Reset for potential chained calls
3039
- } else if (op.expression().length > 0) {
3040
- memberNames.length = 0; // Array subscript breaks scope chain
3041
- }
3042
- }
3043
- }
3044
-
3045
- /**
3046
- * Collect initial member names from primary expression for scope resolution.
3047
- * Issue #561: When 'this' is used, resolve to the current scope name from funcName.
3048
- */
3049
- private collectInitialMemberNames(
3050
- funcName: string,
3051
- primary: Parser.PrimaryExpressionContext,
3052
- ): string[] {
3053
- const memberNames: string[] = [];
3054
- const primaryId = primary.IDENTIFIER()?.getText();
3055
-
3056
- if (primaryId && primaryId !== "global") {
3057
- memberNames.push(primaryId);
3058
- } else if (primary.THIS()) {
3059
- const scopeName = funcName.split("_")[0];
3060
- if (scopeName && scopeName !== funcName) {
3061
- memberNames.push(scopeName);
3062
- }
3063
- }
3064
- return memberNames;
3065
- }
3066
-
3067
- /**
3068
- * Record function calls to the call graph from an argument list.
3069
- * Also recurses into argument expressions.
3070
- */
3071
- private recordCallsFromArgList(
3072
- funcName: string,
3073
- paramSet: Set<string>,
3074
- calleeName: string,
3075
- op: Parser.PostfixOpContext,
3076
- ): void {
3077
- const argList = op.argumentList();
3078
- if (!argList) return;
3079
-
3080
- const args = argList.expression();
3081
- for (let i = 0; i < args.length; i++) {
3082
- const arg = args[i];
3083
- const argName = ExpressionUtils.extractIdentifier(arg);
3084
- if (argName && paramSet.has(argName)) {
3085
- CodeGenState.functionCallGraph.get(funcName)!.push({
3086
- callee: calleeName,
3087
- paramIndex: i,
3088
- argParamName: argName,
3089
- });
3090
- }
3091
- this.walkExpressionForCalls(funcName, paramSet, arg);
3092
- }
3093
- }
3094
-
3095
- /**
3096
- * Walk postfix ops recursively for nested calls and array subscripts.
3097
- */
3098
- private walkPostfixOpsRecursively(
3099
- funcName: string,
3100
- paramSet: Set<string>,
3101
- postfixOps: Parser.PostfixOpContext[],
3102
- ): void {
3103
- for (const op of postfixOps) {
3104
- if (op.argumentList()) {
3105
- for (const argExpr of op.argumentList()!.expression()) {
3106
- this.walkExpressionForCalls(funcName, paramSet, argExpr);
3107
- }
3108
- }
3109
- for (const expr of op.expression()) {
3110
- this.walkExpressionForCalls(funcName, paramSet, expr);
3111
- }
3112
- }
3113
- }
3114
-
3115
- /**
3116
- * Phase 3: Determine which parameters can pass by value.
3117
- * A parameter passes by value if:
3118
- * 1. It's a small primitive type (u8, i8, u16, i16, u32, i32, u64, i64, bool)
3119
- * 2. It's not modified (directly or transitively)
3120
- * 3. It's not an array, struct, string, or callback
3121
- */
3122
- private computePassByValueParams(): void {
3123
- const smallPrimitives = new Set([
3124
- "u8",
3125
- "i8",
3126
- "u16",
3127
- "i16",
3128
- "u32",
3129
- "i32",
3130
- "u64",
3131
- "i64",
3132
- "bool",
3133
- ]);
3134
-
3135
- for (const [funcName, paramNames] of CodeGenState.functionParamLists) {
3136
- const passByValue = new Set<string>();
3137
- const modified =
3138
- CodeGenState.modifiedParameters.get(funcName) ?? new Set();
3139
-
3140
- // Get function declaration to check parameter types
3141
- const funcSig = CodeGenState.functionSignatures.get(funcName);
3142
- if (funcSig) {
3143
- for (let i = 0; i < paramNames.length; i++) {
3144
- const paramName = paramNames[i];
3145
- const paramSig = funcSig.parameters[i];
3146
-
3147
- if (!paramSig) continue;
3148
-
3149
- // Check if eligible for pass-by-value:
3150
- // - Is a small primitive type
3151
- // - Not an array
3152
- // - Not modified
3153
- // - Not accessed via subscript (Issue #579)
3154
- const isSmallPrimitive = smallPrimitives.has(paramSig.baseType);
3155
- const isArray = paramSig.isArray ?? false;
3156
- const isModified = modified.has(paramName);
3157
- // Issue #579: Parameters with subscript access must become pointers
3158
- const hasSubscriptAccess =
3159
- CodeGenState.subscriptAccessedParameters
3160
- .get(funcName)
3161
- ?.has(paramName) ?? false;
3162
-
3163
- if (
3164
- isSmallPrimitive &&
3165
- !isArray &&
3166
- !isModified &&
3167
- !hasSubscriptAccess
3168
- ) {
3169
- passByValue.add(paramName);
3170
- }
3171
- }
3172
- }
3173
-
3174
- CodeGenState.passByValueParams.set(funcName, passByValue);
3175
- }
3176
- }
3177
-
3178
- /**
3179
- * Check if a parameter should be passed by value (by name).
3180
- * Used internally during code generation.
3181
- */
3182
- private _isParameterPassByValueByName(
3183
- funcName: string,
3184
- paramName: string,
3185
- ): boolean {
3186
- const passByValue = CodeGenState.passByValueParams.get(funcName);
3187
- return passByValue?.has(paramName) ?? false;
3188
- }
3189
-
3190
- /**
3191
- * Issue #269: Check if a parameter should be passed by value (by index).
3192
- * Part of IOrchestrator interface - used by CallExprGenerator.
3193
- */
3194
- isParameterPassByValue(funcName: string, paramIndex: number): boolean {
3195
- const paramList = CodeGenState.functionParamLists.get(funcName);
3196
- if (!paramList || paramIndex < 0 || paramIndex >= paramList.length) {
3197
- return false;
3198
- }
3199
- const paramName = paramList[paramIndex];
3200
- return this._isParameterPassByValueByName(funcName, paramName);
3201
- }
3202
-
3203
- /**
3204
- * Issue #269: Get all pass-by-value parameters.
3205
- * Returns a Map from function name to Set of parameter names that should be pass-by-value.
3206
- * Used by HeaderGenerator to ensure header and implementation signatures match.
3207
- */
3208
- getPassByValueParams(): ReadonlyMap<string, ReadonlySet<string>> {
3209
- return CodeGenState.passByValueParams;
3210
- }
3211
-
3212
- /**
3213
- * ADR-036: Try to evaluate an expression as a compile-time constant.
3214
- * Returns the numeric value if constant, undefined if not evaluable.
3215
- * Bug #8: Extended to resolve const variable references for file-scope array sizes.
3216
- * Issue #644: Delegates to ArrayDimensionParser for consolidated implementation.
3217
- */
3218
- // Issue #63: checkArrayBounds moved to TypeValidator
3219
-
3220
- /**
3221
- * Evaluate array dimensions from ArrayDimensionContext[] to number[].
3222
- * Used for bitmap array registration.
3223
- * Issue #644: Delegates to ArrayDimensionParser for consolidated implementation.
3224
- */
3225
- private _evaluateArrayDimensions(
3226
- arrayDim: Parser.ArrayDimensionContext[] | null,
3227
- ): number[] | undefined {
3228
- return ArrayDimensionParser.parseAllDimensions(arrayDim, {
3229
- constValues: CodeGenState.constValues,
3230
- typeWidths: TYPE_WIDTH,
3231
- isKnownStruct: (name) => this.isKnownStruct(name),
3232
- });
3233
- }
3234
-
3235
- /**
3236
- * Try to register a type as enum or bitmap. Returns true if handled.
3237
- * Extracted to reduce duplication across type contexts (ADR-017, ADR-034).
3238
- */
3239
- private _tryRegisterEnumOrBitmapType(
3240
- name: string,
3241
- baseType: string,
3242
- isConst: boolean,
3243
- arrayDim: Parser.ArrayDimensionContext[] | null,
3244
- overflowBehavior: TOverflowBehavior,
3245
- isAtomic: boolean,
3246
- ): boolean {
3247
- // Common options for type registration
3248
- const registrationOptions = {
3249
- name,
3250
- baseType,
3251
- isConst,
3252
- overflowBehavior,
3253
- isAtomic,
3254
- };
3255
-
3256
- // ADR-017: Check if this is an enum type
3257
- if (
3258
- TypeRegistrationUtils.tryRegisterEnumType(
3259
- CodeGenState.typeRegistry,
3260
- CodeGenState.symbols!,
3261
- registrationOptions,
3262
- )
3263
- ) {
3264
- return true;
3265
- }
3266
-
3267
- // ADR-034: Check if this is a bitmap type
3268
- const bitmapDimensions = this._evaluateArrayDimensions(arrayDim);
3269
- if (
3270
- TypeRegistrationUtils.tryRegisterBitmapType(
3271
- CodeGenState.typeRegistry,
3272
- CodeGenState.symbols!,
3273
- registrationOptions,
3274
- bitmapDimensions,
3275
- )
3276
- ) {
3277
- return true;
3278
- }
3279
-
3280
- return false;
3281
- }
3282
-
3283
- /**
3284
- * Extract type info from a variable declaration and register it.
3285
- * Delegates to trackVariableTypeWithName using the variable's identifier.
3286
- */
3287
- private trackVariableType(varDecl: Parser.VariableDeclarationContext): void {
3288
- const name = varDecl.IDENTIFIER().getText();
3289
- this.trackVariableTypeWithName(varDecl, name);
3290
- }
3291
-
3292
- // =========================================================================
3293
- // Type Registration Helpers - Extracted to reduce cognitive complexity
3294
- // =========================================================================
3295
-
3296
- /**
3297
- * Extract array dimensions from ArrayDimensionContext array (simple parseInt version)
3298
- * Used for string array dimensions where const evaluation is not needed.
3299
- * Issue #644: Delegates to ArrayDimensionParser for consolidated implementation.
3300
- */
3301
- private extractArrayDimensionsSimple(
3302
- arrayDim: Parser.ArrayDimensionContext[] | null,
3303
- ): number[] {
3304
- return ArrayDimensionParser.parseSimpleDimensions(arrayDim);
3305
- }
3306
-
3307
- /**
3308
- * Register a string type in the type registry
3309
- * Returns true if registration was successful
3310
- */
3311
- private tryRegisterStringType(
3312
- registryName: string,
3313
- typeCtx: Parser.TypeContext,
3314
- arrayDim: Parser.ArrayDimensionContext[] | null,
3315
- isConst: boolean,
3316
- overflowBehavior: TOverflowBehavior,
3317
- isAtomic: boolean,
3318
- ): boolean {
3319
- const stringCtx = typeCtx.stringType();
3320
- if (!stringCtx) {
3321
- return false;
3322
- }
3323
-
3324
- const intLiteral = stringCtx.INTEGER_LITERAL();
3325
- if (!intLiteral) {
3326
- return false;
3327
- }
3328
-
3329
- const capacity = Number.parseInt(intLiteral.getText(), 10);
3330
- this.requireInclude("string");
3331
- const stringDim = capacity + 1;
3332
-
3333
- // Check if there are additional array dimensions (e.g., [4] in string<64> arr[4])
3334
- const additionalDims = this.extractArrayDimensionsSimple(arrayDim);
3335
- const allDims =
3336
- additionalDims.length > 0 ? [...additionalDims, stringDim] : [stringDim];
3337
-
3338
- CodeGenState.typeRegistry.set(registryName, {
3339
- baseType: "char",
3340
- bitWidth: 8,
3341
- isArray: true,
3342
- arrayDimensions: allDims,
3343
- isConst,
3344
- isString: true,
3345
- stringCapacity: capacity,
3346
- overflowBehavior,
3347
- isAtomic,
3348
- });
3349
- return true;
3350
- }
3351
-
3352
- /**
3353
- * Resolve base type name from a type context
3354
- * Handles scoped, global, qualified, and user types
3355
- */
3356
- private resolveBaseTypeFromContext(
3357
- typeCtx: Parser.TypeContext,
3358
- ): string | null {
3359
- if (typeCtx.primitiveType()) {
3360
- return typeCtx.primitiveType()!.getText();
3361
- }
3362
-
3363
- if (typeCtx.scopedType()) {
3364
- // ADR-016: Handle this.Type for scoped types (e.g., this.State -> Motor_State)
3365
- const typeName = typeCtx.scopedType()!.IDENTIFIER().getText();
3366
- return CodeGenState.currentScope
3367
- ? `${CodeGenState.currentScope}_${typeName}`
3368
- : typeName;
3369
- }
3370
-
3371
- if (typeCtx.globalType()) {
3372
- // Issue #478: Handle global.Type for global types inside scope
3373
- return typeCtx.globalType()!.IDENTIFIER().getText();
3374
- }
3375
-
3376
- if (typeCtx.qualifiedType()) {
3377
- // ADR-016: Handle Scope.Type from outside scope
3378
- // Issue #388: Also handles C++ namespace types
3379
- const identifiers = typeCtx.qualifiedType()!.IDENTIFIER();
3380
- const identifierNames = identifiers.map((id) => id.getText());
3381
- return this.resolveQualifiedType(identifierNames);
3382
- }
3383
-
3384
- if (typeCtx.userType()) {
3385
- return typeCtx.userType()!.getText();
3386
- }
3387
-
3388
- return null;
3389
- }
3390
-
3391
- /**
3392
- * Track variable type with a specific name (for namespace/class members)
3393
- * This allows tracking with mangled names for proper scope resolution
3394
- */
3395
- private trackVariableTypeWithName(
3396
- varDecl: Parser.VariableDeclarationContext,
3397
- registryName: string,
3398
- ): void {
3399
- const typeCtx = varDecl.type();
3400
- const arrayDim = varDecl.arrayDimension();
3401
- const isConst = varDecl.constModifier() !== null;
3402
-
3403
- // ADR-044: Extract overflow modifier (clamp is default)
3404
- const overflowMod = varDecl.overflowModifier();
3405
- const overflowBehavior: TOverflowBehavior =
3406
- overflowMod?.getText() === "wrap" ? "wrap" : "clamp";
3407
-
3408
- // ADR-049: Extract atomic modifier
3409
- const isAtomic = varDecl.atomicModifier() !== null;
3410
-
3411
- // ADR-045: Handle bounded string type first (special case)
3412
- if (
3413
- this.tryRegisterStringType(
3414
- registryName,
3415
- typeCtx,
3416
- arrayDim,
3417
- isConst,
3418
- overflowBehavior,
3419
- isAtomic,
3420
- )
3421
- ) {
3422
- return;
3423
- }
3424
-
3425
- // Handle array type syntax: u8[10]
3426
- if (typeCtx.arrayType()) {
3427
- this._registerArrayTypeVariable(
3428
- registryName,
3429
- typeCtx.arrayType()!,
3430
- arrayDim,
3431
- isConst,
3432
- overflowBehavior,
3433
- isAtomic,
3434
- );
3435
- return;
3436
- }
3437
-
3438
- // Resolve base type from context (handles scoped, global, qualified, user types)
3439
- const baseType = this.resolveBaseTypeFromContext(typeCtx);
3440
- if (!baseType) {
3441
- return;
3442
- }
3443
-
3444
- // ADR-017/ADR-034: Check if enum or bitmap type (reuse existing helper)
3445
- if (
3446
- this._tryRegisterEnumOrBitmapType(
3447
- registryName,
3448
- baseType,
3449
- isConst,
3450
- arrayDim,
3451
- overflowBehavior,
3452
- isAtomic,
3453
- )
3454
- ) {
3455
- return;
3456
- }
3457
-
3458
- // Standard type registration
3459
- this._registerStandardType(
3460
- registryName,
3461
- baseType,
3462
- arrayDim,
3463
- isConst,
3464
- overflowBehavior,
3465
- isAtomic,
3466
- );
3467
- }
3468
-
3469
- /**
3470
- * Register an array type variable (u8[10] syntax)
3471
- */
3472
- private _registerArrayTypeVariable(
3473
- registryName: string,
3474
- arrayTypeCtx: Parser.ArrayTypeContext,
3475
- arrayDim: Parser.ArrayDimensionContext[] | null,
3476
- isConst: boolean,
3477
- overflowBehavior: TOverflowBehavior,
3478
- isAtomic: boolean,
3479
- ): void {
3480
- let baseType = "";
3481
- let bitWidth = 0;
3482
-
3483
- if (arrayTypeCtx.primitiveType()) {
3484
- baseType = arrayTypeCtx.primitiveType()!.getText();
3485
- bitWidth = TYPE_WIDTH[baseType] || 0;
3486
- } else if (arrayTypeCtx.userType()) {
3487
- // Handle user types (structs, enums, bitmaps)
3488
- baseType = arrayTypeCtx.userType()!.getText();
3489
-
3490
- const combinedArrayDim = arrayDim ?? [];
3491
-
3492
- // Check if this is an enum or bitmap type and delegate to proper registration
3493
- if (
3494
- this._tryRegisterEnumOrBitmapType(
3495
- registryName,
3496
- baseType,
3497
- isConst,
3498
- combinedArrayDim,
3499
- overflowBehavior,
3500
- isAtomic,
3501
- )
3502
- ) {
3503
- // Enum/bitmap was registered, but we need to update with arrayType dimension
3504
- const existingInfo = CodeGenState.typeRegistry.get(registryName);
3505
- if (existingInfo) {
3506
- const arrayTypeDim =
3507
- this._parseArrayTypeDimensionFromCtx(arrayTypeCtx);
3508
- const allDims = arrayTypeDim
3509
- ? [arrayTypeDim, ...(existingInfo.arrayDimensions ?? [])]
3510
- : existingInfo.arrayDimensions;
3511
- CodeGenState.typeRegistry.set(registryName, {
3512
- ...existingInfo,
3513
- isArray: true,
3514
- arrayDimensions: allDims,
3515
- });
3516
- }
3517
- return;
3518
- }
3519
-
3520
- // Not an enum/bitmap - register as regular user type (struct)
3521
- // bitWidth already initialized to 0, no reassignment needed
3522
- }
3523
-
3524
- if (!baseType) {
3525
- return;
3526
- }
3527
-
3528
- const arrayDimensions = this._collectArrayDimensions(
3529
- arrayTypeCtx,
3530
- arrayDim,
3531
- );
3532
-
3533
- CodeGenState.typeRegistry.set(registryName, {
3534
- baseType,
3535
- bitWidth,
3536
- isArray: true,
3537
- arrayDimensions: arrayDimensions.length > 0 ? arrayDimensions : undefined,
3538
- isConst,
3539
- overflowBehavior,
3540
- isAtomic,
3541
- });
3542
- }
3543
-
3544
- /**
3545
- * Parse array dimension from arrayType context.
3546
- */
3547
- private _parseArrayTypeDimensionFromCtx(
3548
- arrayTypeCtx: Parser.ArrayTypeContext,
3549
- ): number | undefined {
3550
- // Get first dimension for backwards compatibility
3551
- const dims = arrayTypeCtx.arrayTypeDimension();
3552
- if (dims.length === 0) {
3553
- return undefined;
3554
- }
3555
- const sizeExpr = dims[0].expression();
3556
- if (!sizeExpr) {
3557
- return undefined;
3558
- }
3559
- const size = Number.parseInt(sizeExpr.getText(), 10);
3560
- return Number.isNaN(size) ? undefined : size;
3561
- }
3562
-
3563
- /**
3564
- * Collect array dimensions from array type and additional dimensions
3565
- */
3566
- private _collectArrayDimensions(
3567
- arrayTypeCtx: Parser.ArrayTypeContext,
3568
- arrayDim: Parser.ArrayDimensionContext[] | null,
3569
- ): number[] {
3570
- const arrayDimensions: number[] = [];
3571
-
3572
- // Get all dimensions from array type syntax (supports multi-dimensional)
3573
- for (const dim of arrayTypeCtx.arrayTypeDimension()) {
3574
- const sizeExpr = dim.expression();
3575
- if (sizeExpr) {
3576
- const size = Number.parseInt(sizeExpr.getText(), 10);
3577
- if (!Number.isNaN(size)) {
3578
- arrayDimensions.push(size);
3579
- }
3580
- }
3581
- }
3582
-
3583
- // Add additional dimensions using const evaluation
3584
- const additionalDims = this._evaluateArrayDimensions(arrayDim);
3585
- if (additionalDims) {
3586
- arrayDimensions.push(...additionalDims);
3587
- }
3588
-
3589
- return arrayDimensions;
3590
- }
3591
-
3592
- /**
3593
- * Register a standard (non-array-syntax, non-special) type
3594
- */
3595
- private _registerStandardType(
3596
- registryName: string,
3597
- baseType: string,
3598
- arrayDim: Parser.ArrayDimensionContext[] | null,
3599
- isConst: boolean,
3600
- overflowBehavior: TOverflowBehavior,
3601
- isAtomic: boolean,
3602
- ): void {
3603
- const bitWidth = TYPE_WIDTH[baseType] || 0;
3604
- // Issue #665: Check array syntax presence first, then try to resolve dimensions
3605
- // This matches the pattern in trackVariableType() - unresolved dimensions (e.g., enum
3606
- // members like EIndex.COUNT) should still mark the variable as an array
3607
- const isArray = arrayDim !== null && arrayDim.length > 0;
3608
- const arrayDimensions = isArray
3609
- ? this._evaluateArrayDimensions(arrayDim)
3610
- : undefined;
3611
-
3612
- CodeGenState.typeRegistry.set(registryName, {
3613
- baseType,
3614
- bitWidth,
3615
- isArray,
3616
- arrayDimensions: isArray ? arrayDimensions : undefined,
3617
- isConst,
3618
- overflowBehavior,
3619
- isAtomic,
3620
- });
3621
- }
3622
-
3623
- /**
3624
- * Issue #322: Check if a type name is a user-defined struct
3625
- * Part of IOrchestrator interface.
3626
- */
3627
- isStructType(typeName: string): boolean {
3628
- return TypeResolver.isStructType(typeName);
3629
- }
3630
-
3631
- /**
3632
- * Set up parameter tracking for a function
3633
- */
3634
- private _setParameters(params: Parser.ParameterListContext | null): void {
3635
- CodeGenState.currentParameters.clear();
3636
- CodeGenState.currentParameters.clear();
3637
- if (!params) return;
3638
-
3639
- for (const param of params.parameter()) {
3640
- this._processParameter(param);
3641
- }
3642
- }
3643
-
3644
- /**
3645
- * Process a single parameter declaration
3646
- */
3647
- private _processParameter(param: Parser.ParameterContext): void {
3648
- const name = param.IDENTIFIER().getText();
3649
- // Check both C-Next style (u8[8] param) and legacy style (u8 param[8])
3650
- const isArray =
3651
- param.arrayDimension().length > 0 || param.type().arrayType() !== null;
3652
- const isConst = param.constModifier() !== null;
3653
- const typeCtx = param.type();
3654
-
3655
- // Resolve type information
3656
- const typeInfo = this._resolveParameterTypeInfo(typeCtx);
3657
-
3658
- // Register in currentParameters
3659
- const paramInfo = {
3660
- name,
3661
- baseType: typeInfo.typeName,
3662
- isArray,
3663
- isStruct: typeInfo.isStruct,
3664
- isConst,
3665
- isCallback: typeInfo.isCallback,
3666
- isString: typeInfo.isString,
3667
- };
3668
- CodeGenState.currentParameters.set(name, paramInfo);
3669
-
3670
- // Register in typeRegistry
3671
- this._registerParameterType(name, typeInfo, param, isArray, isConst);
3672
- }
3673
-
3674
- /**
3675
- * Resolve type name and flags from a type context
3676
- */
3677
- private _resolveParameterTypeInfo(typeCtx: Parser.TypeContext): {
3678
- typeName: string;
3679
- isStruct: boolean;
3680
- isCallback: boolean;
3681
- isString: boolean;
3682
- } {
3683
- if (typeCtx.primitiveType()) {
3684
- return {
3685
- typeName: typeCtx.primitiveType()!.getText(),
3686
- isStruct: false,
3687
- isCallback: false,
3688
- isString: false,
3689
- };
3690
- }
3691
-
3692
- if (typeCtx.userType()) {
3693
- const typeName = typeCtx.userType()!.getText();
3694
- return {
3695
- typeName,
3696
- isStruct: this.isStructType(typeName),
3697
- isCallback: CodeGenState.callbackTypes.has(typeName),
3698
- isString: false,
3699
- };
3700
- }
3701
-
3702
- if (typeCtx.qualifiedType()) {
3703
- const identifierNames = typeCtx
3704
- .qualifiedType()!
3705
- .IDENTIFIER()
3706
- .map((id) => id.getText());
3707
- const typeName = this.resolveQualifiedType(identifierNames);
3708
- return {
3709
- typeName,
3710
- isStruct: this.isStructType(typeName),
3711
- isCallback: false,
3712
- isString: false,
3713
- };
3714
- }
3715
-
3716
- if (typeCtx.scopedType()) {
3717
- const localTypeName = typeCtx.scopedType()!.IDENTIFIER().getText();
3718
- const typeName = CodeGenState.currentScope
3719
- ? `${CodeGenState.currentScope}_${localTypeName}`
3720
- : localTypeName;
3721
- return {
3722
- typeName,
3723
- isStruct: this.isStructType(typeName),
3724
- isCallback: false,
3725
- isString: false,
3726
- };
3727
- }
3728
-
3729
- if (typeCtx.globalType()) {
3730
- const typeName = typeCtx.globalType()!.IDENTIFIER().getText();
3731
- return {
3732
- typeName,
3733
- isStruct: this.isStructType(typeName),
3734
- isCallback: false,
3735
- isString: false,
3736
- };
3737
- }
3738
-
3739
- if (typeCtx.stringType()) {
3740
- return {
3741
- typeName: "string",
3742
- isStruct: false,
3743
- isCallback: false,
3744
- isString: true,
3745
- };
3746
- }
3747
-
3748
- // Handle C-Next style array type (u8[8] param) - extract base type
3749
- if (typeCtx.arrayType()) {
3750
- const arrayTypeCtx = typeCtx.arrayType()!;
3751
- if (arrayTypeCtx.primitiveType()) {
3752
- return {
3753
- typeName: arrayTypeCtx.primitiveType()!.getText(),
3754
- isStruct: false,
3755
- isCallback: false,
3756
- isString: false,
3757
- };
3758
- }
3759
- if (arrayTypeCtx.userType()) {
3760
- const typeName = arrayTypeCtx.userType()!.getText();
3761
- return {
3762
- typeName,
3763
- isStruct: this.isStructType(typeName),
3764
- isCallback: CodeGenState.callbackTypes.has(typeName),
3765
- isString: false,
3766
- };
3767
- }
3768
- // Handle string array type (string<32>[5] param)
3769
- if (arrayTypeCtx.stringType()) {
3770
- const stringCtx = arrayTypeCtx.stringType()!;
3771
- return {
3772
- typeName: stringCtx.getText(), // "string<32>"
3773
- isStruct: false,
3774
- isCallback: false,
3775
- isString: true,
3776
- };
3777
- }
3778
- }
3779
-
3780
- // Fallback
3781
- return {
3782
- typeName: typeCtx.getText(),
3783
- isStruct: false,
3784
- isCallback: false,
3785
- isString: false,
3786
- };
3787
- }
3788
-
3789
- /**
3790
- * Extract array dimensions from parameter (C-style or C-Next style).
3791
- */
3792
- private _extractParamArrayDimensions(
3793
- param: Parser.ParameterContext,
3794
- typeCtx: Parser.TypeContext,
3795
- isArray: boolean,
3796
- ): number[] {
3797
- if (!isArray) return [];
3798
-
3799
- // Try C-style first (param.arrayDimension())
3800
- if (param.arrayDimension().length > 0) {
3801
- return ArrayDimensionParser.parseForParameters(param.arrayDimension());
3802
- }
3803
-
3804
- // C-Next style: get dimensions from arrayType
3805
- const arrayTypeCtx = typeCtx.arrayType();
3806
- if (!arrayTypeCtx) return [];
3807
-
3808
- const dimensions: number[] = [];
3809
- for (const dim of arrayTypeCtx.arrayTypeDimension()) {
3810
- const expr = dim.expression();
3811
- if (!expr) continue;
3812
- const size = Number.parseInt(expr.getText(), 10);
3813
- if (!Number.isNaN(size)) {
3814
- dimensions.push(size);
3815
- }
3816
- }
3817
- return dimensions;
3818
- }
3819
-
3820
- /**
3821
- * Register a parameter in the type registry
3822
- */
3823
- private _registerParameterType(
3824
- name: string,
3825
- typeInfo: { typeName: string; isString: boolean },
3826
- param: Parser.ParameterContext,
3827
- isArray: boolean,
3828
- isConst: boolean,
3829
- ): void {
3830
- const { typeName, isString } = typeInfo;
3831
- const typeCtx = param.type();
3832
-
3833
- const isEnum = CodeGenState.symbols!.knownEnums.has(typeName);
3834
- const isBitmap = CodeGenState.symbols!.knownBitmaps.has(typeName);
3835
-
3836
- // Extract array dimensions
3837
- const arrayDimensions = this._extractParamArrayDimensions(
3838
- param,
3839
- typeCtx,
3840
- isArray,
3841
- );
3842
-
3843
- // Add string capacity dimension if applicable
3844
- const stringCapacity = this._getStringCapacity(typeCtx, isString);
3845
- if (isArray && stringCapacity !== undefined) {
3846
- arrayDimensions.push(stringCapacity + 1);
3847
- }
3848
-
3849
- const registeredType = {
3850
- baseType: typeName,
3851
- bitWidth: isBitmap
3852
- ? CodeGenState.symbols!.bitmapBitWidth.get(typeName) || 0
3853
- : TYPE_WIDTH[typeName] || 0,
3854
- isArray,
3855
- arrayDimensions: arrayDimensions.length > 0 ? arrayDimensions : undefined,
3856
- isConst,
3857
- isEnum,
3858
- enumTypeName: isEnum ? typeName : undefined,
3859
- isBitmap,
3860
- bitmapTypeName: isBitmap ? typeName : undefined,
3861
- isString,
3862
- stringCapacity,
3863
- isParameter: true,
3864
- };
3865
- CodeGenState.typeRegistry.set(name, registeredType);
3866
- }
3867
-
3868
- /**
3869
- * Extract string capacity from a string type context
3870
- */
3871
- private _getStringCapacity(
3872
- typeCtx: Parser.TypeContext,
3873
- isString: boolean,
3874
- ): number | undefined {
3875
- if (!isString) return undefined;
3876
-
3877
- // Check direct stringType (e.g., string<32> param)
3878
- if (typeCtx.stringType()) {
3879
- const intLiteral = typeCtx.stringType()!.INTEGER_LITERAL();
3880
- if (intLiteral) {
3881
- return Number.parseInt(intLiteral.getText(), 10);
3882
- }
3883
- }
3884
-
3885
- // Check arrayType with stringType (e.g., string<32>[5] param)
3886
- if (typeCtx.arrayType()?.stringType()) {
3887
- const intLiteral = typeCtx.arrayType()!.stringType()!.INTEGER_LITERAL();
3888
- if (intLiteral) {
3889
- return Number.parseInt(intLiteral.getText(), 10);
3890
- }
3891
- }
3892
-
3893
- return undefined;
3894
- }
3895
-
3896
- /**
3897
- * Clear parameter tracking when leaving a function
3898
- */
3899
- private _clearParameters(): void {
3900
- // ADR-025: Remove parameter types from typeRegistry
3901
- for (const name of CodeGenState.currentParameters.keys()) {
3902
- CodeGenState.typeRegistry.delete(name);
3903
- CodeGenState.typeRegistry.delete(name);
3904
- }
3905
- CodeGenState.currentParameters.clear();
3906
- CodeGenState.localArrays.clear();
3907
- CodeGenState.currentParameters.clear();
3908
- CodeGenState.localArrays.clear();
3909
- }
3910
-
3911
- /**
3912
- * ADR-013: Extract function signature from parameter list
3913
- */
3914
- private extractFunctionSignature(
3915
- name: string,
3916
- params: Parser.ParameterListContext | null,
3917
- ): FunctionSignature {
3918
- const parameters: Array<{
3919
- name: string;
3920
- baseType: string;
3921
- isConst: boolean;
3922
- isArray: boolean;
3923
- }> = [];
3924
-
3925
- if (params) {
3926
- for (const param of params.parameter()) {
3927
- const paramName = param.IDENTIFIER().getText();
3928
- const isConst = param.constModifier() !== null;
3929
- // arrayDimension() returns an array (due to grammar's *), so check length
3930
- // Also check C-Next style array type (e.g., u8[8] param)
3931
- const isArray =
3932
- param.arrayDimension().length > 0 ||
3933
- param.type().arrayType() !== null;
3934
- const baseType = this.getTypeName(param.type());
3935
- parameters.push({ name: paramName, baseType, isConst, isArray });
3936
- }
3937
- }
3938
-
3939
- return { name, parameters };
3940
- }
3941
-
3942
- /**
3943
- * ADR-029: Register a function as a callback type
3944
- * The function name becomes both a callable function and a type for callback fields
3945
- */
3946
- private registerCallbackType(
3947
- name: string,
3948
- funcDecl: Parser.FunctionDeclarationContext,
3949
- ): void {
3950
- const returnType = this.generateType(funcDecl.type());
3951
- const parameters: Array<{
3952
- name: string;
3953
- type: string;
3954
- isConst: boolean;
3955
- isPointer: boolean;
3956
- isArray: boolean;
3957
- arrayDims: string;
3958
- }> = [];
3959
-
3960
- if (funcDecl.parameterList()) {
3961
- for (const param of funcDecl.parameterList()!.parameter()) {
3962
- const paramName = param.IDENTIFIER().getText();
3963
- const typeName = this.getTypeName(param.type());
3964
- const isConst = param.constModifier() !== null;
3965
- const dims = param.arrayDimension();
3966
- const arrayTypeCtx = param.type().arrayType();
3967
- const isArray = dims.length > 0 || arrayTypeCtx !== null;
3968
-
3969
- // ADR-029: Check if parameter type is itself a callback type
3970
- const isCallbackParam = CodeGenState.callbackTypes.has(typeName);
3971
-
3972
- let paramType: string;
3973
- let isPointer: boolean;
3974
-
3975
- if (isCallbackParam) {
3976
- // Use the callback typedef name
3977
- const cbInfo = CodeGenState.callbackTypes.get(typeName)!;
3978
- paramType = cbInfo.typedefName;
3979
- isPointer = false; // Function pointers are already pointers
3980
- } else {
3981
- paramType = this.generateType(param.type());
3982
- // ADR-006: Non-array parameters become pointers
3983
- isPointer = !isArray;
3984
- }
3985
-
3986
- let arrayDims: string;
3987
- if (dims.length > 0) {
3988
- arrayDims = dims.map((d) => this.generateArrayDimension(d)).join("");
3989
- } else if (arrayTypeCtx) {
3990
- // Generate all dimensions from arrayType (supports multi-dimensional)
3991
- arrayDims = arrayTypeCtx
3992
- .arrayTypeDimension()
3993
- .map((d) => {
3994
- const expr = d.expression();
3995
- return expr ? `[${this.generateExpression(expr)}]` : "[]";
3996
- })
3997
- .join("");
3998
- } else {
3999
- arrayDims = "";
4000
- }
4001
- parameters.push({
4002
- name: paramName,
4003
- type: paramType,
4004
- isConst,
4005
- isPointer,
4006
- isArray,
4007
- arrayDims,
4008
- });
4009
- }
4010
- }
4011
-
4012
- CodeGenState.callbackTypes.set(name, {
4013
- functionName: name,
4014
- returnType,
4015
- parameters,
4016
- typedefName: `${name}_fp`,
4017
- });
4018
- }
4019
-
4020
- /**
4021
- * ADR-029: Check if a function is used as a callback type (field type in a struct)
4022
- */
4023
- // Issue #63: validateCallbackAssignment, callbackSignaturesMatch, isConstValue,
4024
- // and validateBareIdentifierInScope moved to TypeValidator
4025
-
4026
- // EnumTypeResolver now handles: _getEnumTypeFromThisEnum, _getEnumTypeFromGlobalEnum,
4027
- // _getEnumTypeFromThisVariable, _getEnumTypeFromScopedEnum, _getEnumTypeFromMemberAccess,
4028
- // _getExpressionEnumType, _getFunctionCallEnumType
4029
- /**
4030
- * ADR-017: Check if an expression represents an integer literal or numeric type.
4031
- * Used to detect comparisons between enums and integers.
4032
- */
4033
- private _isIntegerExpression(
4034
- ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
4035
- ): boolean {
4036
- return EnumAssignmentValidator.isIntegerExpression(ctx);
4037
- }
4038
-
4039
- /**
4040
- * ADR-045: Check if an expression is a string concatenation (contains + with string operands).
4041
- * Returns the operand expressions if it is, null otherwise.
4042
- */
4043
- private _getStringConcatOperands(ctx: Parser.ExpressionContext): {
4044
- left: string;
4045
- right: string;
4046
- leftCapacity: number;
4047
- rightCapacity: number;
4048
- } | null {
4049
- // Navigate to the additive expression level using ExpressionUnwrapper
4050
- // Issue #707: Deduplicated expression tree navigation
4051
- const add = ExpressionUnwrapper.getAdditiveExpression(ctx);
4052
- if (!add) return null;
4053
- const multExprs = add.multiplicativeExpression();
4054
-
4055
- // Need exactly 2 operands for simple concatenation
4056
- if (multExprs.length !== 2) return null;
4057
-
4058
- // Check if this is addition (not subtraction)
4059
- const text = add.getText();
4060
- if (text.includes("-")) return null;
4061
-
4062
- // Get the operand texts
4063
- const leftText = multExprs[0].getText();
4064
- const rightText = multExprs[1].getText();
4065
-
4066
- // Check if at least one operand is a string
4067
- const leftCapacity = this.getStringExprCapacity(leftText);
4068
- const rightCapacity = this.getStringExprCapacity(rightText);
4069
-
4070
- if (leftCapacity === null && rightCapacity === null) {
4071
- return null; // Neither is a string
4072
- }
4073
-
4074
- // If one is null, it's not a valid string concatenation
4075
- if (leftCapacity === null || rightCapacity === null) {
4076
- return null;
4077
- }
4078
-
4079
- return {
4080
- left: leftText,
4081
- right: rightText,
4082
- leftCapacity,
4083
- rightCapacity,
4084
- };
4085
- }
4086
-
4087
- /**
4088
- * ADR-045: Get the capacity of a string expression.
4089
- * For string literals, capacity is the literal length.
4090
- * For string variables, capacity is from the type registry.
4091
- */
4092
- /**
4093
- * ADR-045: Check if an expression is a substring extraction (string[start, length]).
4094
- * Returns the source string, start, length, and source capacity if it is.
4095
- * Issue #707: Uses ExpressionUnwrapper for tree navigation.
4096
- */
4097
- private _getSubstringOperands(ctx: Parser.ExpressionContext): {
4098
- source: string;
4099
- start: string;
4100
- length: string;
4101
- sourceCapacity: number;
4102
- } | null {
4103
- // Navigate to the postfix expression level using shared utility
4104
- const postfix = ExpressionUnwrapper.getPostfixExpression(ctx);
4105
- if (!postfix) return null;
4106
-
4107
- const primary = postfix.primaryExpression();
4108
- const ops = postfix.postfixOp();
4109
-
4110
- // Need exactly one postfix operation (the [start, length])
4111
- if (ops.length !== 1) return null;
4112
-
4113
- const op = ops[0];
4114
- const exprs = op.expression();
4115
-
4116
- // Get the source variable name first
4117
- const sourceId = primary.IDENTIFIER();
4118
- if (!sourceId) return null;
4119
-
4120
- const sourceName = sourceId.getText();
4121
-
4122
- // Check if source is a string type
4123
- const typeInfo = CodeGenState.typeRegistry.get(sourceName);
4124
- if (!typeInfo?.isString || typeInfo.stringCapacity === undefined) {
4125
- return null;
4126
- }
4127
-
4128
- // Issue #140: Handle both [start, length] pattern (2 expressions)
4129
- // and single-character access [index] pattern (1 expression, treated as [index, 1])
4130
- if (exprs.length === 2) {
4131
- return {
4132
- source: sourceName,
4133
- start: this.generateExpression(exprs[0]),
4134
- length: this.generateExpression(exprs[1]),
4135
- sourceCapacity: typeInfo.stringCapacity,
4136
- };
4137
- } else if (exprs.length === 1) {
4138
- // Single-character access: source[i] is sugar for source[i, 1]
4139
- return {
4140
- source: sourceName,
4141
- start: this.generateExpression(exprs[0]),
4142
- length: "1",
4143
- sourceCapacity: typeInfo.stringCapacity,
4144
- };
4145
- }
4146
-
4147
- return null;
4148
- }
4149
-
4150
2769
  // ========================================================================
4151
2770
  // ADR-024: Type Classification and Validation Helpers
4152
2771
  // ========================================================================
@@ -4307,7 +2926,7 @@ export default class CodeGenerator implements IOrchestrator {
4307
2926
  baseId: string,
4308
2927
  targetParamBaseType: string,
4309
2928
  ): boolean {
4310
- const typeInfo = CodeGenState.typeRegistry.get(baseId);
2929
+ const typeInfo = CodeGenState.getVariableTypeInfo(baseId);
4311
2930
  return CppMemberHelper.needsComplexMemberConversion(
4312
2931
  this._toPostfixOps(ops),
4313
2932
  typeInfo,
@@ -4334,7 +2953,7 @@ export default class CodeGenerator implements IOrchestrator {
4334
2953
  const baseId = primary.IDENTIFIER()?.getText();
4335
2954
  if (!baseId) return false;
4336
2955
 
4337
- const typeInfo = CodeGenState.typeRegistry.get(baseId);
2956
+ const typeInfo = CodeGenState.getVariableTypeInfo(baseId);
4338
2957
  const paramInfo = CodeGenState.currentParameters.get(baseId);
4339
2958
 
4340
2959
  return CppMemberHelper.isStringSubscriptPattern(
@@ -4370,225 +2989,46 @@ export default class CodeGenerator implements IOrchestrator {
4370
2989
  if (!postfix) return "not-array";
4371
2990
 
4372
2991
  const ops = postfix.postfixOp();
4373
- if (ops.length === 0) return "not-array";
4374
-
4375
- // Last operator must be member access (.identifier)
4376
- const lastOp = ops.at(-1)!;
4377
- const memberName = lastOp.IDENTIFIER()?.getText();
4378
- if (!memberName) return "not-array";
4379
-
4380
- // Get the base identifier to find the struct type
4381
- const primary = postfix.primaryExpression();
4382
- if (!primary) return "not-array";
4383
- const baseId = primary.IDENTIFIER()?.getText();
4384
- if (!baseId) return "not-array";
4385
-
4386
- // Look up the struct type from either:
4387
- // 1. Local variable: typeRegistry.get(baseId).baseType
4388
- // 2. Parameter: currentParameters.get(baseId).baseType
4389
- let structType: string | undefined;
4390
-
4391
- const typeInfo = CodeGenState.typeRegistry.get(baseId);
4392
- if (typeInfo) {
4393
- structType = typeInfo.baseType;
4394
- } else {
4395
- const paramInfo = CodeGenState.currentParameters.get(baseId);
4396
- if (paramInfo) {
4397
- structType = paramInfo.baseType;
4398
- }
4399
- }
4400
-
4401
- if (!structType) return "not-array";
4402
-
4403
- // Check if this struct member is an array
4404
- const memberInfo = this.getMemberTypeInfo(structType, memberName);
4405
-
4406
- // Issue #355: If memberInfo is undefined, we don't have struct field info
4407
- // This could mean the header wasn't parsed - return "unknown" for defensive generation
4408
- if (!memberInfo) {
4409
- return "unknown";
4410
- }
4411
-
4412
- return memberInfo.isArray ? "array" : "not-array";
4413
- }
4414
-
4415
- /**
4416
- * Generate a function argument with proper ADR-006 semantics.
4417
- * - Local variables get & (address-of)
4418
- * - Member access (cursor.x) gets & (address-of)
4419
- * - Array access (arr[i]) gets & (address-of)
4420
- * - Parameters are passed as-is (already pointers)
4421
- * - Arrays are passed as-is (naturally decay to pointers)
4422
- * - Literals use compound literals for pointer params: &(type){value}
4423
- * - Complex expressions are passed as-is
4424
- */
4425
- private _generateFunctionArg(
4426
- ctx: Parser.ExpressionContext,
4427
- targetParamBaseType?: string,
4428
- ): string {
4429
- const id = CodegenParserUtils.getSimpleIdentifier(ctx);
4430
- if (id) {
4431
- return this._handleIdentifierArg(id);
4432
- }
4433
-
4434
- const lvalueType = this.getLvalueType(ctx);
4435
- if (lvalueType) {
4436
- return this._handleLvalueArg(ctx, lvalueType, targetParamBaseType);
4437
- }
4438
-
4439
- return this._handleRvalueArg(ctx, targetParamBaseType);
4440
- }
4441
-
4442
- /**
4443
- * Handle simple identifier argument (parameter, local array, scope member, or variable)
4444
- */
4445
- private _handleIdentifierArg(id: string): string {
4446
- // Parameters are already pointers
4447
- if (CodeGenState.currentParameters.get(id)) {
4448
- return id;
4449
- }
4450
-
4451
- // Local arrays decay to pointers
4452
- if (CodeGenState.localArrays.has(id)) {
4453
- return id;
4454
- }
4455
-
4456
- // Global arrays also decay to pointers (check typeRegistry)
4457
- // But NOT strings - strings need & (they're char arrays but passed by reference)
4458
- const typeInfo = CodeGenState.typeRegistry.get(id);
4459
- if (typeInfo?.isArray && !typeInfo.isString) {
4460
- return id;
4461
- }
4462
-
4463
- // Scope member - may need prefixing
4464
- if (CodeGenState.currentScope) {
4465
- const members = CodeGenState.getScopeMembers(CodeGenState.currentScope);
4466
- if (members?.has(id)) {
4467
- const scopedName = `${CodeGenState.currentScope}_${id}`;
4468
- return CppModeHelper.maybeAddressOf(scopedName);
4469
- }
4470
- }
4471
-
4472
- // Local variable - add & (except in C++ mode)
4473
- return CppModeHelper.maybeAddressOf(id);
4474
- }
4475
-
4476
- /**
4477
- * Handle lvalue argument (member access or array access)
4478
- */
4479
- private _handleLvalueArg(
4480
- ctx: Parser.ExpressionContext,
4481
- lvalueType: string,
4482
- targetParamBaseType?: string,
4483
- ): string {
4484
- // Member access to array field - arrays decay to pointers
4485
- if (lvalueType === "member") {
4486
- const memberResult = this._handleMemberAccessArg(
4487
- ctx,
4488
- targetParamBaseType,
4489
- );
4490
- if (memberResult) return memberResult;
4491
- }
4492
-
4493
- // Generate expression with address-of
4494
- const generatedExpr = this.generateExpression(ctx);
4495
- const expr = CppModeHelper.maybeAddressOf(generatedExpr);
4496
-
4497
- // String subscript access may need cast
4498
- if (lvalueType === "array") {
4499
- return this._maybeCastStringSubscript(ctx, expr, targetParamBaseType);
4500
- }
4501
-
4502
- return expr;
4503
- }
4504
-
4505
- /**
4506
- * Handle member access argument - may need special handling for arrays or C++ conversions
4507
- */
4508
- private _handleMemberAccessArg(
4509
- ctx: Parser.ExpressionContext,
4510
- targetParamBaseType?: string,
4511
- ): string | null {
4512
- const arrayStatus = this.getMemberAccessArrayStatus(ctx);
4513
-
4514
- // Array member - no address-of needed
4515
- if (arrayStatus === "array") {
4516
- return this.generateExpression(ctx);
4517
- }
4518
-
4519
- // C++ mode may need temp variable for type conversion
4520
- if (
4521
- arrayStatus === "not-array" &&
4522
- this.needsCppMemberConversion(ctx, targetParamBaseType)
4523
- ) {
4524
- return this._createCppMemberConversionTemp(ctx, targetParamBaseType!);
4525
- }
4526
-
4527
- return null; // Fall through to default lvalue handling
4528
- }
4529
-
4530
- /**
4531
- * Create temp variable for C++ member conversion
4532
- */
4533
- private _createCppMemberConversionTemp(
4534
- ctx: Parser.ExpressionContext,
4535
- targetParamBaseType: string,
4536
- ): string {
4537
- const cType = TYPE_MAP[targetParamBaseType] || "uint8_t";
4538
- const value = this.generateExpression(ctx);
4539
- const tempName = `_cnx_tmp_${CodeGenState.tempVarCounter++}`;
4540
- const castExpr = CppModeHelper.cast(cType, value);
4541
- CodeGenState.pendingTempDeclarations.push(
4542
- `${cType} ${tempName} = ${castExpr};`,
4543
- );
4544
- return CppModeHelper.maybeAddressOf(tempName);
4545
- }
2992
+ if (ops.length === 0) return "not-array";
4546
2993
 
4547
- /**
4548
- * Maybe cast string subscript access for integer pointer parameters
4549
- */
4550
- private _maybeCastStringSubscript(
4551
- ctx: Parser.ExpressionContext,
4552
- expr: string,
4553
- targetParamBaseType?: string,
4554
- ): string {
4555
- if (!targetParamBaseType || !this.isStringSubscriptAccess(ctx)) {
4556
- return expr;
4557
- }
2994
+ // Last operator must be member access (.identifier)
2995
+ const lastOp = ops.at(-1)!;
2996
+ const memberName = lastOp.IDENTIFIER()?.getText();
2997
+ if (!memberName) return "not-array";
4558
2998
 
4559
- const cType = TYPE_MAP[targetParamBaseType];
4560
- if (cType && !["float", "double", "bool", "void"].includes(cType)) {
4561
- return CppModeHelper.reinterpretCast(`${cType}*`, expr);
4562
- }
2999
+ // Get the base identifier to find the struct type
3000
+ const primary = postfix.primaryExpression();
3001
+ if (!primary) return "not-array";
3002
+ const baseId = primary.IDENTIFIER()?.getText();
3003
+ if (!baseId) return "not-array";
4563
3004
 
4564
- return expr;
4565
- }
3005
+ // Look up the struct type from either:
3006
+ // 1. Local variable: typeRegistry.get(baseId).baseType
3007
+ // 2. Parameter: currentParameters.get(baseId).baseType
3008
+ let structType: string | undefined;
4566
3009
 
4567
- /**
4568
- * Handle rvalue argument (literals or complex expressions)
4569
- */
4570
- private _handleRvalueArg(
4571
- ctx: Parser.ExpressionContext,
4572
- targetParamBaseType?: string,
4573
- ): string {
4574
- if (!targetParamBaseType) {
4575
- return this.generateExpression(ctx);
3010
+ const typeInfo = CodeGenState.getVariableTypeInfo(baseId);
3011
+ if (typeInfo) {
3012
+ structType = typeInfo.baseType;
3013
+ } else {
3014
+ const paramInfo = CodeGenState.currentParameters.get(baseId);
3015
+ if (paramInfo) {
3016
+ structType = paramInfo.baseType;
3017
+ }
4576
3018
  }
4577
3019
 
4578
- const cType = TYPE_MAP[targetParamBaseType];
4579
- if (!cType || cType === "void") {
4580
- return this.generateExpression(ctx);
4581
- }
3020
+ if (!structType) return "not-array";
4582
3021
 
4583
- const value = this.generateExpression(ctx);
3022
+ // Check if this struct member is an array
3023
+ const memberInfo = this.getMemberTypeInfo(structType, memberName);
4584
3024
 
4585
- // C++ mode: rvalues can bind to const T&
4586
- if (CodeGenState.cppMode) {
4587
- return value;
3025
+ // Issue #355: If memberInfo is undefined, we don't have struct field info
3026
+ // This could mean the header wasn't parsed - return "unknown" for defensive generation
3027
+ if (!memberInfo) {
3028
+ return "unknown";
4588
3029
  }
4589
3030
 
4590
- // C mode: Use compound literal syntax
4591
- return `&(${cType}){${value}}`;
3031
+ return memberInfo.isArray ? "array" : "not-array";
4592
3032
  }
4593
3033
 
4594
3034
  // ========================================================================
@@ -4711,7 +3151,7 @@ export default class CodeGenerator implements IOrchestrator {
4711
3151
  ): void {
4712
3152
  const type = this.generateType(varDecl.type());
4713
3153
  const varName = varDecl.IDENTIFIER().getText();
4714
- const fullName = `${scopeName}_${varName}`;
3154
+ const fullName = QualifiedNameGenerator.forMember(scopeName, varName);
4715
3155
  const prefix = isPrivate ? "static " : "";
4716
3156
 
4717
3157
  const arrayDims = varDecl.arrayDimension();
@@ -4722,7 +3162,10 @@ export default class CodeGenerator implements IOrchestrator {
4722
3162
 
4723
3163
  // Handle arrayType dimension (C-Next style: u8[16] data)
4724
3164
  if (hasArrayTypeSyntax) {
4725
- decl += this._getArrayTypeDimension(varDecl.type());
3165
+ decl += VariableDeclHelper.getArrayTypeDimension(varDecl.type(), {
3166
+ tryEvaluateConstant: (exprCtx) => this.tryEvaluateConstant(exprCtx),
3167
+ generateExpression: (exprCtx) => this.generateExpression(exprCtx),
3168
+ });
4726
3169
  }
4727
3170
 
4728
3171
  // Handle arrayDimension (C-style or additional dimensions)
@@ -4764,7 +3207,10 @@ export default class CodeGenerator implements IOrchestrator {
4764
3207
  ): void {
4765
3208
  const returnType = this.generateType(funcDecl.type());
4766
3209
  const funcName = funcDecl.IDENTIFIER().getText();
4767
- const fullName = `${scopeName}_${funcName}`;
3210
+ const fullName = QualifiedNameGenerator.forFunctionStrings(
3211
+ scopeName,
3212
+ funcName,
3213
+ );
4768
3214
  const prefix = isPrivate ? "static " : "";
4769
3215
 
4770
3216
  // Issue #269: Set current function name for pass-by-value lookup
@@ -5159,32 +3605,34 @@ export default class CodeGenerator implements IOrchestrator {
5159
3605
  }
5160
3606
 
5161
3607
  /**
5162
- * Set up context for function generation
3608
+ * Set up context for function generation.
3609
+ * Issue #793: Delegates to FunctionContextManager.
5163
3610
  */
5164
3611
  private _setupFunctionContext(
5165
3612
  name: string,
5166
3613
  ctx: Parser.FunctionDeclarationContext,
5167
3614
  ): void {
5168
- // Issue #269: Set current function name for pass-by-value lookup
5169
- const fullFuncName = CodeGenState.currentScope
5170
- ? `${CodeGenState.currentScope}_${name}`
5171
- : name;
5172
- CodeGenState.currentFunctionName = fullFuncName;
5173
- // Issue #477: Set return type for enum inference in return statements
5174
- CodeGenState.currentFunctionReturnType = ctx.type().getText();
5175
-
5176
- // Track parameters for ADR-006 pointer semantics
5177
- this._setParameters(ctx.parameterList() ?? null);
3615
+ FunctionContextManager.setupFunctionContext(
3616
+ name,
3617
+ ctx,
3618
+ this._getFunctionContextCallbacks(),
3619
+ );
3620
+ }
5178
3621
 
5179
- // ADR-016: Clear local variables and mark that we're in a function body
5180
- CodeGenState.localVariables.clear();
5181
- CodeGenState.floatBitShadows.clear();
5182
- CodeGenState.floatShadowCurrent.clear();
5183
- CodeGenState.inFunctionBody = true;
3622
+ /**
3623
+ * Issue #793: Create callbacks for FunctionContextManager.
3624
+ */
3625
+ private _getFunctionContextCallbacks(): IFunctionContextCallbacks {
3626
+ return {
3627
+ isStructType: (typeName: string) => this.isStructType(typeName),
3628
+ resolveQualifiedType: (identifiers: string[]) =>
3629
+ this.resolveQualifiedType(identifiers),
3630
+ };
5184
3631
  }
5185
3632
 
5186
3633
  /**
5187
- * Resolve return type and initial params for function
3634
+ * Resolve return type and initial params for function.
3635
+ * Issue #793: Delegates to FunctionContextManager.
5188
3636
  */
5189
3637
  private _resolveReturnTypeAndParams(
5190
3638
  name: string,
@@ -5192,33 +3640,20 @@ export default class CodeGenerator implements IOrchestrator {
5192
3640
  isMainWithArgs: boolean,
5193
3641
  ctx: Parser.FunctionDeclarationContext,
5194
3642
  ): { actualReturnType: string; initialParams: string } {
5195
- if (isMainWithArgs) {
5196
- // Special case: main(u8 args[][]) -> int main(int argc, char *argv[])
5197
- const argsParam = ctx.parameterList()!.parameter()[0];
5198
- CodeGenState.mainArgsName = argsParam.IDENTIFIER().getText();
5199
- return {
5200
- actualReturnType: "int",
5201
- initialParams: "int argc, char *argv[]",
5202
- };
5203
- }
5204
-
5205
- // For main() without args, always use int return type for C++ compatibility
5206
- const actualReturnType = name === "main" ? "int" : returnType;
5207
- return { actualReturnType, initialParams: "" };
3643
+ return FunctionContextManager.resolveReturnTypeAndParams(
3644
+ name,
3645
+ returnType,
3646
+ isMainWithArgs,
3647
+ ctx,
3648
+ );
5208
3649
  }
5209
3650
 
5210
3651
  /**
5211
- * Clean up context after function generation
3652
+ * Clean up context after function generation.
3653
+ * Issue #793: Delegates to FunctionContextManager.
5212
3654
  */
5213
3655
  private _cleanupFunctionContext(): void {
5214
- CodeGenState.inFunctionBody = false;
5215
- CodeGenState.localVariables.clear();
5216
- CodeGenState.floatBitShadows.clear();
5217
- CodeGenState.floatShadowCurrent.clear();
5218
- CodeGenState.mainArgsName = null;
5219
- CodeGenState.currentFunctionName = null;
5220
- CodeGenState.currentFunctionReturnType = null;
5221
- this._clearParameters();
3656
+ FunctionContextManager.cleanupFunctionContext();
5222
3657
  }
5223
3658
 
5224
3659
  /**
@@ -5325,7 +3760,10 @@ export default class CodeGenerator implements IOrchestrator {
5325
3760
  // Small unmodified primitives
5326
3761
  if (
5327
3762
  CodeGenState.currentFunctionName &&
5328
- this._isParameterPassByValueByName(CodeGenState.currentFunctionName, name)
3763
+ PassByValueAnalyzer.isParameterPassByValueByName(
3764
+ CodeGenState.currentFunctionName,
3765
+ name,
3766
+ )
5329
3767
  ) {
5330
3768
  return true;
5331
3769
  }
@@ -5338,74 +3776,27 @@ export default class CodeGenerator implements IOrchestrator {
5338
3776
  // ========================================================================
5339
3777
 
5340
3778
  private generateVariableDecl(ctx: Parser.VariableDeclarationContext): string {
5341
- // Issue #375: Check for C++ constructor syntax - early return
5342
- const constructorArgList = ctx.constructorArgumentList();
5343
- if (constructorArgList) {
5344
- return this._generateConstructorDecl(ctx, constructorArgList);
5345
- }
5346
-
5347
- // Issue #696: Use helper for modifier extraction and validation
5348
- const modifiers = VariableModifierBuilder.build(
5349
- ctx,
5350
- CodeGenState.inFunctionBody,
5351
- );
5352
-
5353
- const name = ctx.IDENTIFIER().getText();
5354
- const typeCtx = ctx.type();
5355
-
5356
- // Reject C-style array declarations (u16 arr[8]) - require C-Next style (u16[8] arr)
5357
- this._validateArrayDeclarationSyntax(ctx, typeCtx, name);
5358
-
5359
- const type = this._inferVariableType(ctx, name);
5360
-
5361
- // Track local variable metadata
5362
- this._trackLocalVariable(ctx, name);
5363
-
5364
- // ADR-045: Handle bounded string type specially - early return
5365
- const stringResult = StringDeclHelper.generateStringDecl(
5366
- typeCtx,
5367
- name,
5368
- ctx.expression() ?? null,
5369
- ctx.arrayDimension(),
5370
- modifiers,
5371
- ctx.constModifier() !== null,
5372
- {
5373
- generateExpression: (exprCtx) => this.generateExpression(exprCtx),
5374
- generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
5375
- getStringConcatOperands: (concatCtx) =>
5376
- this._getStringConcatOperands(concatCtx),
5377
- getSubstringOperands: (substrCtx) =>
5378
- this._getSubstringOperands(substrCtx),
5379
- getStringExprCapacity: (exprCode) =>
5380
- this.getStringExprCapacity(exprCode),
5381
- requireStringInclude: () => this.requireInclude("string"),
5382
- },
5383
- );
5384
- if (stringResult.handled) {
5385
- return stringResult.code;
5386
- }
5387
-
5388
- // Build base declaration
5389
- const modifierPrefix = VariableModifierBuilder.toPrefix(modifiers);
5390
- let decl = `${modifierPrefix}${type} ${name}`;
5391
-
5392
- // Handle array declarations - early return if array init handled
5393
- const arrayResult = this._handleArrayDeclaration(ctx, typeCtx, name, decl);
5394
- if (arrayResult.handled) {
5395
- return arrayResult.code;
5396
- }
5397
- decl = arrayResult.decl;
5398
-
5399
- // Handle initialization
5400
- decl = this._generateVariableInitializer(
5401
- ctx,
5402
- typeCtx,
5403
- decl,
5404
- arrayResult.isArray,
5405
- );
5406
-
5407
- // Handle pending C++ class field assignments
5408
- return this._finalizeCppClassAssignments(ctx, typeCtx, name, decl);
3779
+ // Issue #792: Delegate to VariableDeclHelper
3780
+ return VariableDeclHelper.generateVariableDecl(ctx, {
3781
+ generateExpression: (exprCtx) => this.generateExpression(exprCtx),
3782
+ generateType: (typeCtx) => this.generateType(typeCtx),
3783
+ getTypeName: (typeCtx) => this.getTypeName(typeCtx),
3784
+ generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
3785
+ tryEvaluateConstant: (exprCtx) => this.tryEvaluateConstant(exprCtx),
3786
+ getZeroInitializer: (typeCtx, isArray) =>
3787
+ this.getZeroInitializer(typeCtx, isArray),
3788
+ getExpressionType: (exprCtx) => this.getExpressionType(exprCtx),
3789
+ inferVariableType: (varCtx, name) =>
3790
+ this._inferVariableType(varCtx, name),
3791
+ trackLocalVariable: (varCtx, name) =>
3792
+ this._trackLocalVariable(varCtx, name),
3793
+ getStringConcatOperands: (concatCtx) =>
3794
+ this._getStringConcatOperands(concatCtx),
3795
+ getSubstringOperands: (substrCtx) =>
3796
+ this._getSubstringOperands(substrCtx),
3797
+ getStringExprCapacity: (exprCode) => this.getStringExprCapacity(exprCode),
3798
+ requireStringInclude: () => this.requireInclude("string"),
3799
+ });
5409
3800
  }
5410
3801
 
5411
3802
  /**
@@ -5442,7 +3833,11 @@ export default class CodeGenerator implements IOrchestrator {
5442
3833
  return;
5443
3834
  }
5444
3835
 
5445
- this.trackVariableType(ctx);
3836
+ TypeRegistrationEngine.trackVariable(ctx, {
3837
+ tryEvaluateConstant: (expr) => this.tryEvaluateConstant(expr),
3838
+ requireInclude: (header) => this.requireInclude(header),
3839
+ resolveQualifiedType: (ids) => this.resolveQualifiedType(ids),
3840
+ });
5446
3841
  CodeGenState.localVariables.add(name);
5447
3842
 
5448
3843
  // Bug #8: Track local const values for array size and bit index resolution
@@ -5454,383 +3849,10 @@ export default class CodeGenerator implements IOrchestrator {
5454
3849
  }
5455
3850
  }
5456
3851
 
5457
- /**
5458
- * Issue #696: Handle array declaration with dimension parsing and init.
5459
- * Bug fix: Also handles C-Next style arrayType syntax (u16[8] myArray).
5460
- */
5461
- private _handleArrayDeclaration(
5462
- ctx: Parser.VariableDeclarationContext,
5463
- typeCtx: Parser.TypeContext,
5464
- name: string,
5465
- decl: string,
5466
- ): { handled: boolean; code: string; decl: string; isArray: boolean } {
5467
- const arrayDims = ctx.arrayDimension();
5468
- const hasArrayTypeSyntax = typeCtx.arrayType() !== null;
5469
- const isArray = arrayDims.length > 0 || hasArrayTypeSyntax;
5470
-
5471
- if (!isArray) {
5472
- return { handled: false, code: "", decl, isArray: false };
5473
- }
5474
-
5475
- // Generate dimension string from arrayType syntax (u16[8] myArray)
5476
- const arrayTypeDimStr = this._getArrayTypeDimension(typeCtx);
5477
-
5478
- const hasEmptyArrayDim = arrayDims.some((dim) => !dim.expression());
5479
- const declaredSize =
5480
- this._parseArrayTypeDimension(typeCtx) ??
5481
- this._parseFirstArrayDimension(arrayDims);
5482
-
5483
- // ADR-035: Handle array initializers with size inference
5484
- if (ctx.expression()) {
5485
- const arrayInitResult = ArrayInitHelper.processArrayInit(
5486
- name,
5487
- typeCtx,
5488
- ctx.expression()!,
5489
- arrayDims,
5490
- hasEmptyArrayDim,
5491
- declaredSize,
5492
- {
5493
- generateExpression: (exprCtx) => this.generateExpression(exprCtx),
5494
- getTypeName: (typeCtxParam) => this.getTypeName(typeCtxParam),
5495
- generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
5496
- },
5497
- );
5498
- if (arrayInitResult) {
5499
- // Track as local array for type resolution
5500
- CodeGenState.localArrays.add(name);
5501
- // Include arrayType dimension before arrayDimension dimensions
5502
- const fullDimSuffix = arrayTypeDimStr + arrayInitResult.dimensionSuffix;
5503
- return {
5504
- handled: true,
5505
- code: `${decl}${fullDimSuffix} = ${arrayInitResult.initValue};`,
5506
- decl,
5507
- isArray: true,
5508
- };
5509
- }
5510
- }
5511
-
5512
- // Generate dimensions: arrayType dimension first, then arrayDimension dimensions
5513
- const newDecl =
5514
- decl + arrayTypeDimStr + this.generateArrayDimensions(arrayDims);
5515
- CodeGenState.localArrays.add(name);
5516
-
5517
- return { handled: false, code: "", decl: newDecl, isArray: true };
5518
- }
5519
-
5520
- /**
5521
- * Get array dimension string from arrayType syntax (u16[8] -> "[8]", u16[4][4] -> "[4][4]").
5522
- * Evaluates const expressions to their numeric values for C compatibility.
5523
- */
5524
- private _getArrayTypeDimension(typeCtx: Parser.TypeContext): string {
5525
- if (!typeCtx.arrayType()) {
5526
- return "";
5527
- }
5528
- const dims = typeCtx.arrayType()!.arrayTypeDimension();
5529
- let result = "";
5530
- for (const dim of dims) {
5531
- const sizeExpr = dim.expression();
5532
- if (!sizeExpr) {
5533
- result += "[]";
5534
- continue;
5535
- }
5536
- // Try to evaluate as constant first (required for C file-scope arrays)
5537
- // Fall back to expression text for macros, enums, etc.
5538
- const dimValue =
5539
- this.tryEvaluateConstant(sizeExpr) ?? this.generateExpression(sizeExpr);
5540
- result += `[${dimValue}]`;
5541
- }
5542
- return result;
5543
- }
5544
-
5545
- /**
5546
- * Parse first array dimension from arrayType syntax for size validation.
5547
- */
5548
- private _parseArrayTypeDimension(typeCtx: Parser.TypeContext): number | null {
5549
- if (!typeCtx.arrayType()) {
5550
- return null;
5551
- }
5552
- const dims = typeCtx.arrayType()!.arrayTypeDimension();
5553
- if (dims.length === 0) {
5554
- return null;
5555
- }
5556
- const sizeExpr = dims[0].expression();
5557
- if (!sizeExpr) {
5558
- return null;
5559
- }
5560
- const sizeText = sizeExpr.getText();
5561
- const digitRegex = /^\d+$/;
5562
- if (digitRegex.exec(sizeText)) {
5563
- return Number.parseInt(sizeText, 10);
5564
- }
5565
- return null;
5566
- }
5567
-
5568
- /**
5569
- * Issue #696: Parse first array dimension for validation.
5570
- */
5571
- private _parseFirstArrayDimension(
5572
- arrayDims: Parser.ArrayDimensionContext[],
5573
- ): number | null {
5574
- if (arrayDims.length === 0 || !arrayDims[0].expression()) {
5575
- return null;
5576
- }
5577
- const sizeText = arrayDims[0].expression()!.getText();
5578
- if (/^\d+$/.exec(sizeText)) {
5579
- return Number.parseInt(sizeText, 10);
5580
- }
5581
- return null;
5582
- }
5583
-
5584
- /**
5585
- * Validate array declaration syntax - reject C-style, require C-Next style.
5586
- * C-style: u16 arr[8] (all dimensions after identifier) - REJECTED
5587
- * C-Next style: u16[8] arr (first dimension in type) - REQUIRED
5588
- * Multi-dim C-Next: u16[4] arr[2] (first in type, rest after) - ALLOWED
5589
- * Exceptions (grammar limitations):
5590
- * - Empty dimensions for size inference: u8 arr[] <- [...]
5591
- * - Qualified types: SeaDash.Parse.Result arr[3] (no arrayType support)
5592
- * - Scoped/global types: this.Type arr[3], global.Type arr[3]
5593
- * - String types: string<N> arr[3]
5594
- */
5595
- private _validateArrayDeclarationSyntax(
5596
- ctx: Parser.VariableDeclarationContext,
5597
- typeCtx: Parser.TypeContext,
5598
- name: string,
5599
- ): void {
5600
- const arrayDims = ctx.arrayDimension();
5601
- if (arrayDims.length === 0) {
5602
- return; // Not an array declaration
5603
- }
5604
-
5605
- // If type already has arrayType, additional dimensions are allowed (multi-dim)
5606
- if (typeCtx.arrayType()) {
5607
- return; // Valid C-Next style: u16[4] arr[2] → uint16_t arr[4][2]
5608
- }
5609
-
5610
- // Allow empty first dimension for size inference: u8 arr[] <- [1, 2, 3]
5611
- // The grammar doesn't support u8[] arr syntax, so this is the only way
5612
- if (arrayDims.length === 1 && !arrayDims[0].expression()) {
5613
- return; // Size inference pattern allowed
5614
- }
5615
-
5616
- // Allow C-style for multi-dimensional arrays: u8 matrix[4][4]
5617
- // The arrayType grammar only supports single dimension, so multi-dim needs C-style
5618
- if (arrayDims.length > 1) {
5619
- return; // Multi-dimensional arrays need C-style
5620
- }
5621
-
5622
- // Allow C-style for types that don't support arrayType syntax:
5623
- // - Qualified types (Scope.Type, Namespace::Type)
5624
- // - Scoped types (this.Type)
5625
- // - Global types (global.Type)
5626
- // - String types (string<N>)
5627
- // - Bitmap types (code generator doesn't yet handle arrayType for bitmaps)
5628
- if (
5629
- typeCtx.qualifiedType() ||
5630
- typeCtx.scopedType() ||
5631
- typeCtx.globalType() ||
5632
- typeCtx.stringType()
5633
- ) {
5634
- return; // Grammar limitation - these can't use arrayType
5635
- }
5636
-
5637
- // C-style array declaration detected - reject with helpful error
5638
- const baseType = this._extractBaseTypeName(typeCtx);
5639
- const dimensions = arrayDims
5640
- .map((dim) => `[${dim.expression()?.getText() ?? ""}]`)
5641
- .join("");
5642
- const line = ctx.start?.line ?? 0;
5643
- const col = ctx.start?.column ?? 0;
5644
-
5645
- throw new Error(
5646
- `${line}:${col} C-style array declaration is not allowed. ` +
5647
- `Use '${baseType}${dimensions} ${name}' instead of '${baseType} ${name}${dimensions}'`,
5648
- );
5649
- }
5650
-
5651
- /**
5652
- * Extract base type name from type context for error messages.
5653
- */
5654
- private _extractBaseTypeName(typeCtx: Parser.TypeContext): string {
5655
- if (typeCtx.primitiveType()) {
5656
- return typeCtx.primitiveType()!.getText();
5657
- }
5658
- if (typeCtx.userType()) {
5659
- return typeCtx.userType()!.getText();
5660
- }
5661
- if (typeCtx.arrayType()) {
5662
- const arrCtx = typeCtx.arrayType()!;
5663
- if (arrCtx.primitiveType()) {
5664
- return arrCtx.primitiveType()!.getText();
5665
- }
5666
- if (arrCtx.userType()) {
5667
- return arrCtx.userType()!.getText();
5668
- }
5669
- }
5670
- return typeCtx.getText();
5671
- }
5672
-
5673
- /**
5674
- * Issue #696: Generate variable initializer with validation.
5675
- */
5676
- private _generateVariableInitializer(
5677
- ctx: Parser.VariableDeclarationContext,
5678
- typeCtx: Parser.TypeContext,
5679
- decl: string,
5680
- isArray: boolean,
5681
- ): string {
5682
- if (!ctx.expression()) {
5683
- // ADR-015: Zero initialization for uninitialized variables
5684
- return `${decl} = ${this.getZeroInitializer(typeCtx, isArray)}`;
5685
- }
5686
-
5687
- const typeName = this.getTypeName(typeCtx);
5688
- const savedExpectedType = CodeGenState.expectedType;
5689
- CodeGenState.expectedType = typeName;
5690
-
5691
- // ADR-017: Validate enum type for initialization
5692
- EnumAssignmentValidator.validateEnumAssignment(typeName, ctx.expression()!);
5693
-
5694
- // ADR-024: Validate integer literals and type conversions
5695
- this._validateIntegerInitializer(ctx, typeName);
5696
-
5697
- const result = `${decl} = ${this.generateExpression(ctx.expression()!)}`;
5698
- CodeGenState.expectedType = savedExpectedType;
5699
-
5700
- return result;
5701
- }
5702
-
5703
- /**
5704
- * Issue #696: Validate integer initializer using helper.
5705
- */
5706
- private _validateIntegerInitializer(
5707
- ctx: Parser.VariableDeclarationContext,
5708
- typeName: string,
5709
- ): void {
5710
- if (!this._isIntegerType(typeName)) {
5711
- return;
5712
- }
5713
-
5714
- const exprText = ctx.expression()!.getText().trim();
5715
- const line = ctx.start?.line ?? 0;
5716
- const col = ctx.start?.column ?? 0;
5717
- const isLiteral = LiteralUtils.parseIntegerLiteral(exprText) !== undefined;
5718
-
5719
- try {
5720
- if (isLiteral) {
5721
- // Direct literal - validate it fits in the target type
5722
- this._validateLiteralFitsType(exprText, typeName);
5723
- } else {
5724
- // Not a literal - check for narrowing/sign conversions
5725
- const sourceType = this.getExpressionType(ctx.expression()!);
5726
- this._validateTypeConversion(typeName, sourceType);
5727
- }
5728
- } catch (validationError) {
5729
- const msg =
5730
- validationError instanceof Error
5731
- ? validationError.message
5732
- : String(validationError);
5733
- throw new Error(`${line}:${col} ${msg}`, { cause: validationError });
5734
- }
5735
- }
5736
-
5737
- /**
5738
- * Issue #696: Handle pending C++ class field assignments.
5739
- */
5740
- private _finalizeCppClassAssignments(
5741
- _ctx: Parser.VariableDeclarationContext,
5742
- typeCtx: Parser.TypeContext,
5743
- name: string,
5744
- decl: string,
5745
- ): string {
5746
- if (CodeGenState.pendingCppClassAssignments.length === 0) {
5747
- return `${decl};`;
5748
- }
5749
-
5750
- if (CodeGenState.inFunctionBody) {
5751
- const assignments = CodeGenState.pendingCppClassAssignments
5752
- .map((a) => `${name}.${a}`)
5753
- .join("\n");
5754
- CodeGenState.pendingCppClassAssignments = [];
5755
- return `${decl};\n${assignments}`;
5756
- }
5757
-
5758
- // At global scope, we can't emit assignment statements.
5759
- CodeGenState.pendingCppClassAssignments = [];
5760
- throw new Error(
5761
- `Error: C++ class '${this.getTypeName(typeCtx)}' with constructor cannot use struct initializer ` +
5762
- `syntax at global scope. Use constructor syntax or initialize fields separately.`,
5763
- );
5764
- }
5765
-
5766
- /**
5767
- * Issue #375: Generate C++ constructor-style declaration
5768
- * Validates that all arguments are const variables.
5769
- * Example: `Adafruit_MAX31856 thermocouple(pinConst);` -> `Adafruit_MAX31856 thermocouple(pinConst);`
5770
- */
5771
- private _generateConstructorDecl(
5772
- ctx: Parser.VariableDeclarationContext,
5773
- argListCtx: Parser.ConstructorArgumentListContext,
5774
- ): string {
5775
- const type = this.generateType(ctx.type());
5776
- const name = ctx.IDENTIFIER().getText();
5777
- const line = ctx.start?.line ?? 0;
5778
-
5779
- // Collect and validate all arguments
5780
- const argIdentifiers = argListCtx.IDENTIFIER();
5781
- const resolvedArgs: string[] = [];
5782
-
5783
- for (const argNode of argIdentifiers) {
5784
- const argName = argNode.getText();
5785
-
5786
- // Check if it exists in type registry
5787
- const typeInfo = CodeGenState.typeRegistry.get(argName);
5788
-
5789
- // Also check scoped variables if inside a scope
5790
- let scopedArgName = argName;
5791
- let scopedTypeInfo = typeInfo;
5792
- if (!typeInfo && CodeGenState.currentScope) {
5793
- scopedArgName = `${CodeGenState.currentScope}_${argName}`;
5794
- scopedTypeInfo = CodeGenState.typeRegistry.get(scopedArgName);
5795
- }
5796
-
5797
- if (!typeInfo && !scopedTypeInfo) {
5798
- throw new Error(
5799
- `Error at line ${line}: Constructor argument '${argName}' is not declared`,
5800
- );
5801
- }
5802
-
5803
- const finalTypeInfo = typeInfo ?? scopedTypeInfo!;
5804
- const finalArgName = typeInfo ? argName : scopedArgName;
5805
-
5806
- // Check if it's const
5807
- if (!finalTypeInfo.isConst) {
5808
- throw new Error(
5809
- `Error at line ${line}: Constructor argument '${argName}' must be const. ` +
5810
- `C++ constructors in C-Next only accept const variables.`,
5811
- );
5812
- }
5813
-
5814
- resolvedArgs.push(finalArgName);
5815
- }
5816
-
5817
- // Track the variable in type registry (as an external C++ type)
5818
- CodeGenState.typeRegistry.set(name, {
5819
- baseType: type,
5820
- bitWidth: 0, // Unknown for C++ types
5821
- isArray: false,
5822
- arrayDimensions: [],
5823
- isConst: false,
5824
- isExternalCppType: true,
5825
- });
5826
-
5827
- // Track as local variable if inside function body
5828
- if (CodeGenState.inFunctionBody) {
5829
- CodeGenState.localVariables.add(name);
5830
- }
5831
-
5832
- return `${type} ${name}(${resolvedArgs.join(", ")});`;
5833
- }
3852
+ // Issue #792: Methods _handleArrayDeclaration, _getArrayTypeDimension, _parseArrayTypeDimension,
3853
+ // _parseFirstArrayDimension, _validateArrayDeclarationSyntax, _extractBaseTypeName,
3854
+ // _generateVariableInitializer, _validateIntegerInitializer, _finalizeCppClassAssignments,
3855
+ // and _generateConstructorDecl have been extracted to VariableDeclHelper.ts
5834
3856
 
5835
3857
  /**
5836
3858
  * Get zero initializer for array types.
@@ -6055,7 +4077,7 @@ export default class CodeGenerator implements IOrchestrator {
6055
4077
  // ADR-109: Dispatch to assignment handlers
6056
4078
  // Build context, classify, and dispatch - all patterns handled by handlers
6057
4079
  const assignCtx = buildAssignmentContext(ctx, {
6058
- typeRegistry: CodeGenState.typeRegistry,
4080
+ typeRegistry: CodeGenState.getTypeRegistryView(),
6059
4081
  generateExpression: () => value,
6060
4082
  generateAssignmentTarget: (targetCtx) =>
6061
4083
  this.generateAssignmentTarget(targetCtx),