c-next 0.1.70 → 0.1.72

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/package.json +1 -1
  2. package/src/lib/__tests__/parseCHeader.mocked.test.ts +69 -54
  3. package/src/lib/parseCHeader.ts +56 -23
  4. package/src/lib/parseWithSymbols.ts +195 -53
  5. package/src/transpiler/Transpiler.ts +180 -63
  6. package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +1 -2
  7. package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +1 -2
  8. package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +51 -2
  9. package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +18 -12
  10. package/src/transpiler/logic/analysis/__tests__/InitializationAnalyzer.test.ts +9 -9
  11. package/src/transpiler/logic/analysis/__tests__/runAnalyzers.test.ts +5 -5
  12. package/src/transpiler/logic/symbols/SymbolTable.ts +729 -265
  13. package/src/transpiler/logic/symbols/SymbolUtils.ts +2 -2
  14. package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +415 -751
  15. package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +573 -0
  16. package/src/transpiler/logic/symbols/c/__tests__/testHelpers.ts +20 -0
  17. package/src/transpiler/logic/symbols/c/collectors/EnumCollector.ts +82 -0
  18. package/src/transpiler/logic/symbols/c/collectors/FunctionCollector.ts +106 -0
  19. package/src/transpiler/logic/symbols/c/collectors/StructCollector.ts +173 -0
  20. package/src/transpiler/logic/symbols/c/collectors/TypedefCollector.ts +35 -0
  21. package/src/transpiler/logic/symbols/c/collectors/VariableCollector.ts +80 -0
  22. package/src/transpiler/logic/symbols/c/index.ts +333 -0
  23. package/src/transpiler/logic/symbols/c/utils/DeclaratorUtils.ts +269 -0
  24. package/src/transpiler/logic/symbols/cnext/__tests__/BitmapCollector.test.ts +50 -11
  25. package/src/transpiler/logic/symbols/cnext/__tests__/CNextResolver.integration.test.ts +45 -34
  26. package/src/transpiler/logic/symbols/cnext/__tests__/EnumCollector.test.ts +30 -13
  27. package/src/transpiler/logic/symbols/cnext/__tests__/FunctionCollector.test.ts +279 -64
  28. package/src/transpiler/logic/symbols/cnext/__tests__/RegisterCollector.test.ts +60 -13
  29. package/src/transpiler/logic/symbols/cnext/__tests__/ScopeCollector.test.ts +40 -37
  30. package/src/transpiler/logic/symbols/cnext/__tests__/StructCollector.test.ts +131 -45
  31. package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolInfoAdapter.test.ts +223 -139
  32. package/src/transpiler/logic/symbols/cnext/__tests__/VariableCollector.test.ts +79 -25
  33. package/src/transpiler/logic/symbols/cnext/__tests__/testUtils.ts +53 -0
  34. package/src/transpiler/logic/symbols/cnext/adapters/TSymbolInfoAdapter.ts +83 -43
  35. package/src/transpiler/logic/symbols/cnext/collectors/BitmapCollector.ts +14 -13
  36. package/src/transpiler/logic/symbols/cnext/collectors/EnumCollector.ts +11 -10
  37. package/src/transpiler/logic/symbols/cnext/collectors/FunctionCollector.ts +83 -34
  38. package/src/transpiler/logic/symbols/cnext/collectors/RegisterCollector.ts +22 -18
  39. package/src/transpiler/logic/symbols/cnext/collectors/ScopeCollector.ts +53 -35
  40. package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +30 -23
  41. package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +18 -19
  42. package/src/transpiler/logic/symbols/cnext/index.ts +36 -14
  43. package/src/transpiler/logic/symbols/cnext/types/IScopeCollectorResult.ts +2 -2
  44. package/src/transpiler/logic/symbols/cnext/utils/SymbolNameUtils.ts +27 -0
  45. package/src/transpiler/logic/symbols/cpp/__tests__/CppResolver.integration.test.ts +270 -0
  46. package/src/transpiler/logic/symbols/cpp/__tests__/testHelpers.ts +20 -0
  47. package/src/transpiler/logic/symbols/cpp/collectors/ClassCollector.ts +317 -0
  48. package/src/transpiler/logic/symbols/cpp/collectors/EnumCollector.ts +71 -0
  49. package/src/transpiler/logic/symbols/cpp/collectors/FunctionCollector.ts +155 -0
  50. package/src/transpiler/logic/symbols/cpp/collectors/NamespaceCollector.ts +65 -0
  51. package/src/transpiler/logic/symbols/cpp/collectors/TypeAliasCollector.ts +46 -0
  52. package/src/transpiler/logic/symbols/cpp/collectors/VariableCollector.ts +54 -0
  53. package/src/transpiler/logic/symbols/cpp/index.ts +366 -0
  54. package/src/transpiler/logic/symbols/cpp/utils/DeclaratorUtils.ts +248 -0
  55. package/src/transpiler/logic/symbols/shared/IExtractedParameter.ts +18 -0
  56. package/src/transpiler/logic/symbols/shared/ParameterExtractorUtils.ts +73 -0
  57. package/src/transpiler/output/codegen/CodeGenerator.ts +268 -1674
  58. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +7 -1
  59. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +2 -1
  60. package/src/transpiler/output/codegen/assignment/handlers/AssignmentHandlerUtils.ts +7 -1
  61. package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +6 -2
  62. package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +2 -1
  63. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +21 -8
  64. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopedRegisterGenerator.ts +3 -2
  65. package/src/transpiler/output/codegen/generators/expressions/CallExprUtils.ts +9 -3
  66. package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +3 -4
  67. package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprUtils.test.ts +4 -8
  68. package/src/transpiler/output/codegen/helpers/ArgumentGenerator.ts +236 -0
  69. package/src/transpiler/output/codegen/helpers/CppConstructorHelper.ts +3 -3
  70. package/src/transpiler/output/codegen/helpers/FunctionContextManager.ts +435 -0
  71. package/src/transpiler/output/codegen/helpers/StringOperationsHelper.ts +203 -0
  72. package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +8 -12
  73. package/src/transpiler/output/codegen/helpers/TypeRegistrationEngine.ts +520 -0
  74. package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +735 -0
  75. package/src/transpiler/output/codegen/helpers/VariableDeclarationFormatter.ts +1 -1
  76. package/src/transpiler/output/codegen/helpers/__tests__/ArgumentGenerator.test.ts +521 -0
  77. package/src/transpiler/output/codegen/helpers/__tests__/CppConstructorHelper.test.ts +4 -5
  78. package/src/transpiler/output/codegen/helpers/__tests__/FunctionContextManager.test.ts +983 -0
  79. package/src/transpiler/output/codegen/helpers/__tests__/StringOperationsHelper.test.ts +269 -0
  80. package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +31 -32
  81. package/src/transpiler/output/codegen/helpers/__tests__/TypeRegistrationEngine.test.ts +186 -0
  82. package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclHelper.test.ts +460 -0
  83. package/src/transpiler/output/codegen/helpers/types/IArgumentGeneratorCallbacks.ts +32 -0
  84. package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +5 -1
  85. package/src/transpiler/output/codegen/types/IFunctionContextCallbacks.ts +12 -0
  86. package/src/transpiler/output/codegen/types/IVariableFormatInput.ts +1 -1
  87. package/src/transpiler/output/codegen/utils/QualifiedNameGenerator.ts +114 -0
  88. package/src/transpiler/output/codegen/utils/__tests__/QualifiedNameGenerator.test.ts +183 -0
  89. package/src/transpiler/output/headers/BaseHeaderGenerator.ts +4 -4
  90. package/src/transpiler/output/headers/ExternalTypeHeaderBuilder.ts +7 -7
  91. package/src/transpiler/output/headers/HeaderGenerator.ts +9 -7
  92. package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +19 -20
  93. package/src/transpiler/output/headers/__tests__/BaseHeaderGenerator.test.ts +15 -18
  94. package/src/transpiler/output/headers/__tests__/CHeaderGenerator.test.ts +63 -64
  95. package/src/transpiler/output/headers/__tests__/CppHeaderGenerator.test.ts +36 -32
  96. package/src/transpiler/output/headers/__tests__/ExternalTypeHeaderBuilder.test.ts +26 -26
  97. package/src/transpiler/output/headers/__tests__/HeaderGenerator.test.ts +87 -59
  98. package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +57 -58
  99. package/src/transpiler/output/headers/adapters/HeaderSymbolAdapter.ts +222 -0
  100. package/src/transpiler/output/headers/adapters/__tests__/HeaderSymbolAdapter.test.ts +538 -0
  101. package/src/transpiler/output/headers/types/IGroupedSymbols.ts +8 -8
  102. package/src/transpiler/output/headers/types/IHeaderSymbol.ts +62 -0
  103. package/src/transpiler/state/CodeGenState.ts +20 -33
  104. package/src/transpiler/state/SymbolRegistry.ts +181 -0
  105. package/src/transpiler/{types → state}/TranspilerState.ts +1 -1
  106. package/src/transpiler/state/__tests__/CodeGenState.test.ts +67 -59
  107. package/src/transpiler/state/__tests__/SymbolRegistry.test.ts +249 -0
  108. package/src/transpiler/{types → state}/__tests__/TranspilerState.test.ts +1 -1
  109. package/src/transpiler/types/ICachedFileEntry.ts +1 -1
  110. package/src/transpiler/types/IConflict.ts +14 -0
  111. package/src/transpiler/types/IPipelineInput.ts +0 -3
  112. package/src/transpiler/types/ISerializedSymbol.ts +11 -0
  113. package/src/transpiler/types/TPrimitiveKind.ts +20 -0
  114. package/src/transpiler/types/TType.ts +103 -0
  115. package/src/transpiler/types/TVisibility.ts +6 -0
  116. package/src/transpiler/types/symbol-kinds/TSymbolKind.ts +10 -0
  117. package/src/transpiler/types/symbol-kinds/TSymbolKindC.ts +12 -0
  118. package/src/transpiler/types/symbol-kinds/TSymbolKindCNext.ts +16 -0
  119. package/src/transpiler/types/symbol-kinds/TSymbolKindCpp.ts +14 -0
  120. package/src/transpiler/types/symbols/IBaseSymbol.ts +31 -0
  121. package/src/transpiler/{logic/symbols/types → types/symbols}/IBitmapFieldInfo.ts +2 -2
  122. package/src/transpiler/types/symbols/IBitmapSymbol.ts +21 -0
  123. package/src/transpiler/{logic/symbols/types → types/symbols}/IEnumSymbol.ts +5 -6
  124. package/src/transpiler/types/symbols/IFieldInfo.ts +26 -0
  125. package/src/transpiler/types/symbols/IFunctionSymbol.ts +30 -0
  126. package/src/transpiler/types/symbols/IParameterInfo.ts +26 -0
  127. package/src/transpiler/{logic/symbols/types → types/symbols}/IRegisterMemberInfo.ts +4 -4
  128. package/src/transpiler/types/symbols/IRegisterSymbol.ts +18 -0
  129. package/src/transpiler/types/symbols/IScopeSymbol.ts +32 -0
  130. package/src/transpiler/{logic/symbols/types → types/symbols}/IStructFieldInfo.ts +2 -1
  131. package/src/transpiler/types/symbols/IStructSymbol.ts +15 -0
  132. package/src/transpiler/types/symbols/IVariableSymbol.ts +30 -0
  133. package/src/transpiler/types/symbols/SymbolGuards.ts +43 -0
  134. package/src/transpiler/types/symbols/TAnySymbol.ts +22 -0
  135. package/src/transpiler/types/symbols/TSymbol.ts +32 -0
  136. package/src/transpiler/types/symbols/__tests__/IBaseSymbol.test.ts +56 -0
  137. package/src/transpiler/types/symbols/__tests__/SymbolGuards.test.ts +57 -0
  138. package/src/transpiler/types/symbols/c/ICBaseSymbol.ts +28 -0
  139. package/src/transpiler/types/symbols/c/ICEnumMemberSymbol.ts +17 -0
  140. package/src/transpiler/types/symbols/c/ICEnumSymbol.ts +17 -0
  141. package/src/transpiler/types/symbols/c/ICFieldInfo.ts +16 -0
  142. package/src/transpiler/types/symbols/c/ICFunctionSymbol.ts +21 -0
  143. package/src/transpiler/types/symbols/c/ICParameterInfo.ts +19 -0
  144. package/src/transpiler/types/symbols/c/ICStructSymbol.ts +21 -0
  145. package/src/transpiler/types/symbols/c/ICTypedefSymbol.ts +14 -0
  146. package/src/transpiler/types/symbols/c/ICVariableSymbol.ts +26 -0
  147. package/src/transpiler/types/symbols/c/TCSymbol.ts +26 -0
  148. package/src/transpiler/types/symbols/cpp/ICppBaseSymbol.ts +31 -0
  149. package/src/transpiler/types/symbols/cpp/ICppClassSymbol.ts +15 -0
  150. package/src/transpiler/types/symbols/cpp/ICppEnumMemberSymbol.ts +14 -0
  151. package/src/transpiler/types/symbols/cpp/ICppEnumSymbol.ts +14 -0
  152. package/src/transpiler/types/symbols/cpp/ICppFieldInfo.ts +16 -0
  153. package/src/transpiler/types/symbols/cpp/ICppFunctionSymbol.ts +21 -0
  154. package/src/transpiler/types/symbols/cpp/ICppNamespaceSymbol.ts +11 -0
  155. package/src/transpiler/types/symbols/cpp/ICppParameterInfo.ts +19 -0
  156. package/src/transpiler/types/symbols/cpp/ICppStructSymbol.ts +16 -0
  157. package/src/transpiler/types/symbols/cpp/ICppTypeAliasSymbol.ts +14 -0
  158. package/src/transpiler/types/symbols/cpp/ICppVariableSymbol.ts +23 -0
  159. package/src/transpiler/types/symbols/cpp/TCppSymbol.ts +30 -0
  160. package/src/utils/CppNamespaceUtils.ts +3 -4
  161. package/src/utils/FunctionUtils.ts +92 -0
  162. package/src/utils/ParameterUtils.ts +55 -0
  163. package/src/utils/PrimitiveKindUtils.ts +33 -0
  164. package/src/utils/ScopeUtils.ts +105 -0
  165. package/src/utils/TTypeUtils.ts +159 -0
  166. package/src/utils/TypeResolver.ts +132 -0
  167. package/src/utils/__tests__/CppNamespaceUtils.test.ts +92 -99
  168. package/src/utils/__tests__/FunctionUtils.test.ts +284 -0
  169. package/src/utils/__tests__/ParameterUtils.test.ts +174 -0
  170. package/src/utils/__tests__/PrimitiveKindUtils.test.ts +59 -0
  171. package/src/utils/__tests__/ScopeUtils.test.ts +53 -0
  172. package/src/utils/__tests__/TTypeUtils.test.ts +245 -0
  173. package/src/utils/__tests__/TypeResolver.test.ts +332 -0
  174. package/src/utils/cache/CacheManager.ts +91 -50
  175. package/src/utils/cache/__tests__/CacheManager.test.ts +180 -114
  176. package/src/transpiler/logic/symbols/AutoConstUpdater.ts +0 -93
  177. package/src/transpiler/logic/symbols/CSymbolCollector.ts +0 -648
  178. package/src/transpiler/logic/symbols/CppSymbolCollector.ts +0 -874
  179. package/src/transpiler/logic/symbols/SymbolCollectorContext.ts +0 -68
  180. package/src/transpiler/logic/symbols/__tests__/AutoConstUpdater.test.ts +0 -418
  181. package/src/transpiler/logic/symbols/__tests__/CSymbolCollector.test.ts +0 -685
  182. package/src/transpiler/logic/symbols/__tests__/CppSymbolCollector.test.ts +0 -1146
  183. package/src/transpiler/logic/symbols/__tests__/SymbolCollectorContext.test.ts +0 -290
  184. package/src/transpiler/logic/symbols/__tests__/cTestHelpers.ts +0 -43
  185. package/src/transpiler/logic/symbols/__tests__/cppTestHelpers.ts +0 -40
  186. package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolAdapter.test.ts +0 -595
  187. package/src/transpiler/logic/symbols/cnext/adapters/TSymbolAdapter.ts +0 -345
  188. package/src/transpiler/logic/symbols/types/IBaseSymbol.ts +0 -27
  189. package/src/transpiler/logic/symbols/types/IBitmapSymbol.ts +0 -23
  190. package/src/transpiler/logic/symbols/types/ICollectorContext.ts +0 -19
  191. package/src/transpiler/logic/symbols/types/IConflict.ts +0 -20
  192. package/src/transpiler/logic/symbols/types/IFieldInfo.ts +0 -18
  193. package/src/transpiler/logic/symbols/types/IFunctionSymbol.ts +0 -25
  194. package/src/transpiler/logic/symbols/types/IParameterInfo.ts +0 -24
  195. package/src/transpiler/logic/symbols/types/IRegisterSymbol.ts +0 -20
  196. package/src/transpiler/logic/symbols/types/IScopeSymbol.ts +0 -19
  197. package/src/transpiler/logic/symbols/types/IStructSymbol.ts +0 -16
  198. package/src/transpiler/logic/symbols/types/IVariableSymbol.ts +0 -30
  199. package/src/transpiler/logic/symbols/types/TSymbol.ts +0 -36
  200. package/src/transpiler/logic/symbols/types/__tests__/SymbolGuards.test.ts +0 -244
  201. package/src/transpiler/logic/symbols/types/typeGuards.ts +0 -44
  202. package/src/utils/types/ESymbolKind.ts +0 -19
  203. package/src/utils/types/ISymbol.ts +0 -64
  204. /package/src/transpiler/{types → constants}/BITMAP_BACKING_TYPE.ts +0 -0
  205. /package/src/transpiler/{types → constants}/BITMAP_SIZE.ts +0 -0
@@ -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";
@@ -126,6 +130,9 @@ import TransitiveModificationPropagator from "../../logic/analysis/helpers/Trans
126
130
  import TypeGenerationHelper from "./helpers/TypeGenerationHelper";
127
131
  // Phase 5: Cast validation helper for improved testability
128
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";
129
136
  // Global state for code generation (simplifies debugging, eliminates DI complexity)
130
137
  import CodeGenState from "../../state/CodeGenState";
131
138
  // Issue #269: Pass-by-value analysis extracted from CodeGenerator
@@ -137,6 +144,8 @@ import ParameterSignatureBuilder from "./helpers/ParameterSignatureBuilder";
137
144
  import SizeofResolver from "./resolution/SizeofResolver";
138
145
  import EnumTypeResolver from "./resolution/EnumTypeResolver";
139
146
  import ScopeResolver from "./resolution/ScopeResolver";
147
+ // Issue #797: Centralized C-style name generation
148
+ import QualifiedNameGenerator from "./utils/QualifiedNameGenerator";
140
149
 
141
150
  const {
142
151
  generateOverflowHelpers: helperGenerateOverflowHelpers,
@@ -860,13 +869,20 @@ export default class CodeGenerator implements IOrchestrator {
860
869
 
861
870
  /**
862
871
  * Generate function argument with pass-by-reference handling.
863
- * Part of IOrchestrator interface - delegates to private implementation.
872
+ * Part of IOrchestrator interface - delegates to ArgumentGenerator.
864
873
  */
865
874
  generateFunctionArg(
866
875
  ctx: Parser.ExpressionContext,
867
876
  targetParamBaseType?: string,
868
877
  ): string {
869
- 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
+ });
870
886
  }
871
887
 
872
888
  /**
@@ -1356,21 +1372,7 @@ export default class CodeGenerator implements IOrchestrator {
1356
1372
 
1357
1373
  /** Get the capacity of a string expression */
1358
1374
  getStringExprCapacity(exprCode: string): number | null {
1359
- // String literal - capacity equals content length
1360
- if (exprCode.startsWith('"') && exprCode.endsWith('"')) {
1361
- return StringUtils.literalLength(exprCode);
1362
- }
1363
-
1364
- // Variable - check type registry
1365
- const identifierRegex = /^[a-zA-Z_]\w*$/;
1366
- if (identifierRegex.test(exprCode)) {
1367
- const typeInfo = CodeGenState.getVariableTypeInfo(exprCode);
1368
- if (typeInfo?.isString && typeInfo.stringCapacity !== undefined) {
1369
- return typeInfo.stringCapacity;
1370
- }
1371
- }
1372
-
1373
- return null;
1375
+ return StringOperationsHelper.getStringExprCapacity(exprCode);
1374
1376
  }
1375
1377
 
1376
1378
  // === Parameter Management (IOrchestrator A4) ===
@@ -1429,25 +1431,20 @@ export default class CodeGenerator implements IOrchestrator {
1429
1431
 
1430
1432
  // === Function Body Management (A4) ===
1431
1433
 
1434
+ /**
1435
+ * Enter function body - clears local variables and sets inFunctionBody flag.
1436
+ * Issue #793: Delegates to FunctionContextManager.
1437
+ */
1432
1438
  enterFunctionBody(): void {
1433
- CodeGenState.localVariables.clear();
1434
- CodeGenState.floatBitShadows.clear();
1435
- CodeGenState.floatShadowCurrent.clear();
1436
- // Issue #558: modifiedParameters tracking removed - uses analysis-phase results
1437
- CodeGenState.inFunctionBody = true;
1438
- // Sync with CodeGenState
1439
- CodeGenState.enterFunctionBody();
1439
+ FunctionContextManager.enterFunctionBody();
1440
1440
  }
1441
1441
 
1442
+ /**
1443
+ * Exit function body - clears local variables and inFunctionBody flag.
1444
+ * Issue #793: Delegates to FunctionContextManager.
1445
+ */
1442
1446
  exitFunctionBody(): void {
1443
- CodeGenState.inFunctionBody = false;
1444
- CodeGenState.localVariables.clear();
1445
- CodeGenState.floatBitShadows.clear();
1446
- CodeGenState.floatShadowCurrent.clear();
1447
- CodeGenState.mainArgsName = null;
1448
- // Sync with CodeGenState
1449
- CodeGenState.exitFunctionBody();
1450
- CodeGenState.mainArgsName = null;
1447
+ FunctionContextManager.exitFunctionBody();
1451
1448
  }
1452
1449
 
1453
1450
  setMainArgsName(name: string | null): void {
@@ -2167,19 +2164,18 @@ export default class CodeGenerator implements IOrchestrator {
2167
2164
  }
2168
2165
 
2169
2166
  // Issue #461: Initialize constValues from symbol table
2167
+ // Only C-Next TSymbols have initialValue property
2170
2168
  CodeGenState.constValues = new Map();
2171
2169
  if (CodeGenState.symbolTable) {
2172
- for (const symbol of CodeGenState.symbolTable.getAllSymbols()) {
2170
+ for (const symbol of CodeGenState.symbolTable.getAllTSymbols()) {
2173
2171
  if (
2174
- symbol.kind === ESymbolKind.Variable &&
2172
+ symbol.kind === "variable" &&
2175
2173
  symbol.isConst &&
2176
2174
  symbol.initialValue !== undefined
2177
2175
  ) {
2178
2176
  const value = LiteralUtils.parseIntegerLiteral(symbol.initialValue);
2179
2177
  if (value !== undefined) {
2180
2178
  CodeGenState.constValues.set(symbol.name, value);
2181
- // Also populate CodeGenState
2182
- CodeGenState.constValues.set(symbol.name, value);
2183
2179
  }
2184
2180
  }
2185
2181
  }
@@ -2487,7 +2483,10 @@ export default class CodeGenerator implements IOrchestrator {
2487
2483
  const funcDecl = member.functionDeclaration()!;
2488
2484
  const funcName = funcDecl.IDENTIFIER().getText();
2489
2485
  // Track fully qualified function name: Scope_function
2490
- const fullName = `${scopeName}_${funcName}`;
2486
+ const fullName = QualifiedNameGenerator.forFunctionStrings(
2487
+ scopeName,
2488
+ funcName,
2489
+ );
2491
2490
  CodeGenState.knownFunctions.add(fullName);
2492
2491
  // ADR-013: Track function signature for const checking
2493
2492
  const sig = this.extractFunctionSignature(
@@ -2552,66 +2551,11 @@ export default class CodeGenerator implements IOrchestrator {
2552
2551
  * SonarCloud S3776: Refactored to use helper methods.
2553
2552
  */
2554
2553
  private registerAllVariableTypes(tree: Parser.ProgramContext): void {
2555
- for (const decl of tree.declaration()) {
2556
- // Register global variable types
2557
- if (decl.variableDeclaration()) {
2558
- this.registerGlobalVariableType(decl.variableDeclaration()!);
2559
- }
2560
-
2561
- // Register scope member variable types
2562
- if (decl.scopeDeclaration()) {
2563
- this.registerScopeMemberTypes(decl.scopeDeclaration()!);
2564
- }
2565
-
2566
- // Note: Function parameters are registered per-function during generation
2567
- // since they're scoped to the function body
2568
- }
2569
- }
2570
-
2571
- /**
2572
- * Register a global variable type and track const values.
2573
- * SonarCloud S3776: Extracted from registerAllVariableTypes().
2574
- */
2575
- private registerGlobalVariableType(
2576
- varDecl: Parser.VariableDeclarationContext,
2577
- ): void {
2578
- this.trackVariableType(varDecl);
2579
-
2580
- // Bug #8: Track const values for array size resolution at file scope
2581
- if (varDecl.constModifier() && varDecl.expression()) {
2582
- const constName = varDecl.IDENTIFIER().getText();
2583
- const constValue = this.tryEvaluateConstant(varDecl.expression()!);
2584
- if (constValue !== undefined) {
2585
- CodeGenState.constValues.set(constName, constValue);
2586
- }
2587
- }
2588
- }
2589
-
2590
- /**
2591
- * Register scope member variable types.
2592
- * SonarCloud S3776: Extracted from registerAllVariableTypes().
2593
- */
2594
- private registerScopeMemberTypes(
2595
- scopeDecl: Parser.ScopeDeclarationContext,
2596
- ): void {
2597
- const scopeName = scopeDecl.IDENTIFIER().getText();
2598
-
2599
- // Set currentScope so that this.Type references resolve correctly
2600
- const savedScope = CodeGenState.currentScope;
2601
- this.setCurrentScope(scopeName);
2602
-
2603
- for (const member of scopeDecl.scopeMember()) {
2604
- if (member.variableDeclaration()) {
2605
- const varDecl = member.variableDeclaration()!;
2606
- const varName = varDecl.IDENTIFIER().getText();
2607
- const fullName = `${scopeName}_${varName}`;
2608
- // Register with mangled name (Scope_variable)
2609
- this.trackVariableTypeWithName(varDecl, fullName);
2610
- }
2611
- }
2612
-
2613
- // Restore previous scope
2614
- 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
+ });
2615
2559
  }
2616
2560
 
2617
2561
  // Issue #60: collectEnum and collectBitmap methods removed - now in SymbolCollector
@@ -2640,830 +2584,163 @@ export default class CodeGenerator implements IOrchestrator {
2640
2584
  }
2641
2585
 
2642
2586
  /**
2643
- * ADR-036: Try to evaluate an expression as a compile-time constant.
2644
- * Returns the numeric value if constant, undefined if not evaluable.
2645
- * Bug #8: Extended to resolve const variable references for file-scope array sizes.
2646
- * Issue #644: Delegates to ArrayDimensionParser for consolidated implementation.
2647
- */
2648
- // Issue #63: checkArrayBounds moved to TypeValidator
2649
-
2650
- /**
2651
- * Evaluate array dimensions from ArrayDimensionContext[] to number[].
2652
- * Used for bitmap array registration.
2653
- * Issue #644: Delegates to ArrayDimensionParser for consolidated implementation.
2654
- */
2655
- private _evaluateArrayDimensions(
2656
- arrayDim: Parser.ArrayDimensionContext[] | null,
2657
- ): number[] | undefined {
2658
- return ArrayDimensionParser.parseAllDimensions(arrayDim, {
2659
- constValues: CodeGenState.constValues,
2660
- typeWidths: TYPE_WIDTH,
2661
- isKnownStruct: (name) => this.isKnownStruct(name),
2662
- });
2663
- }
2664
-
2665
- /**
2666
- * Try to register a type as enum or bitmap. Returns true if handled.
2667
- * Extracted to reduce duplication across type contexts (ADR-017, ADR-034).
2668
- */
2669
- private _tryRegisterEnumOrBitmapType(
2670
- name: string,
2671
- baseType: string,
2672
- isConst: boolean,
2673
- arrayDim: Parser.ArrayDimensionContext[] | null,
2674
- overflowBehavior: TOverflowBehavior,
2675
- isAtomic: boolean,
2676
- ): boolean {
2677
- // Common options for type registration
2678
- const registrationOptions = {
2679
- name,
2680
- baseType,
2681
- isConst,
2682
- overflowBehavior,
2683
- isAtomic,
2684
- };
2685
-
2686
- // ADR-017: Check if this is an enum type
2687
- if (
2688
- TypeRegistrationUtils.tryRegisterEnumType(
2689
- CodeGenState.symbols!,
2690
- registrationOptions,
2691
- )
2692
- ) {
2693
- return true;
2694
- }
2695
-
2696
- // ADR-034: Check if this is a bitmap type
2697
- const bitmapDimensions = this._evaluateArrayDimensions(arrayDim);
2698
- if (
2699
- TypeRegistrationUtils.tryRegisterBitmapType(
2700
- CodeGenState.symbols!,
2701
- registrationOptions,
2702
- bitmapDimensions,
2703
- )
2704
- ) {
2705
- return true;
2706
- }
2707
-
2708
- return false;
2709
- }
2710
-
2711
- /**
2712
- * Extract type info from a variable declaration and register it.
2713
- * Delegates to trackVariableTypeWithName using the variable's identifier.
2587
+ * Issue #322: Check if a type name is a user-defined struct
2588
+ * Part of IOrchestrator interface.
2714
2589
  */
2715
- private trackVariableType(varDecl: Parser.VariableDeclarationContext): void {
2716
- const name = varDecl.IDENTIFIER().getText();
2717
- this.trackVariableTypeWithName(varDecl, name);
2590
+ isStructType(typeName: string): boolean {
2591
+ return TypeResolver.isStructType(typeName);
2718
2592
  }
2719
2593
 
2720
- // =========================================================================
2721
- // Type Registration Helpers - Extracted to reduce cognitive complexity
2722
- // =========================================================================
2723
-
2724
2594
  /**
2725
- * Extract array dimensions from ArrayDimensionContext array (simple parseInt version)
2726
- * Used for string array dimensions where const evaluation is not needed.
2727
- * Issue #644: Delegates to ArrayDimensionParser for consolidated implementation.
2595
+ * Set up parameter tracking for a function.
2596
+ * Issue #793: Delegates to FunctionContextManager.
2728
2597
  */
2729
- private extractArrayDimensionsSimple(
2730
- arrayDim: Parser.ArrayDimensionContext[] | null,
2731
- ): number[] {
2732
- return ArrayDimensionParser.parseSimpleDimensions(arrayDim);
2598
+ private _setParameters(params: Parser.ParameterListContext | null): void {
2599
+ FunctionContextManager.processParameterList(
2600
+ params,
2601
+ this._getFunctionContextCallbacks(),
2602
+ );
2733
2603
  }
2734
2604
 
2735
2605
  /**
2736
- * Register a string type in the type registry
2737
- * Returns true if registration was successful
2606
+ * Clear parameter tracking when leaving a function.
2607
+ * Issue #793: Delegates to FunctionContextManager.
2738
2608
  */
2739
- private tryRegisterStringType(
2740
- registryName: string,
2741
- typeCtx: Parser.TypeContext,
2742
- arrayDim: Parser.ArrayDimensionContext[] | null,
2743
- isConst: boolean,
2744
- overflowBehavior: TOverflowBehavior,
2745
- isAtomic: boolean,
2746
- ): boolean {
2747
- const stringCtx = typeCtx.stringType();
2748
- if (!stringCtx) {
2749
- return false;
2750
- }
2751
-
2752
- const intLiteral = stringCtx.INTEGER_LITERAL();
2753
- if (!intLiteral) {
2754
- return false;
2755
- }
2756
-
2757
- const capacity = Number.parseInt(intLiteral.getText(), 10);
2758
- this.requireInclude("string");
2759
- const stringDim = capacity + 1;
2760
-
2761
- // Check if there are additional array dimensions (e.g., [4] in string<64> arr[4])
2762
- const additionalDims = this.extractArrayDimensionsSimple(arrayDim);
2763
- const allDims =
2764
- additionalDims.length > 0 ? [...additionalDims, stringDim] : [stringDim];
2765
-
2766
- CodeGenState.setVariableTypeInfo(registryName, {
2767
- baseType: "char",
2768
- bitWidth: 8,
2769
- isArray: true,
2770
- arrayDimensions: allDims,
2771
- isConst,
2772
- isString: true,
2773
- stringCapacity: capacity,
2774
- overflowBehavior,
2775
- isAtomic,
2776
- });
2777
- return true;
2609
+ private _clearParameters(): void {
2610
+ FunctionContextManager.clearParameters();
2778
2611
  }
2779
2612
 
2780
2613
  /**
2781
- * Resolve base type name from a type context
2782
- * Handles scoped, global, qualified, and user types
2614
+ * ADR-013: Extract function signature from parameter list
2783
2615
  */
2784
- private resolveBaseTypeFromContext(
2785
- typeCtx: Parser.TypeContext,
2786
- ): string | null {
2787
- if (typeCtx.primitiveType()) {
2788
- return typeCtx.primitiveType()!.getText();
2789
- }
2790
-
2791
- if (typeCtx.scopedType()) {
2792
- // ADR-016: Handle this.Type for scoped types (e.g., this.State -> Motor_State)
2793
- const typeName = typeCtx.scopedType()!.IDENTIFIER().getText();
2794
- return CodeGenState.currentScope
2795
- ? `${CodeGenState.currentScope}_${typeName}`
2796
- : typeName;
2797
- }
2798
-
2799
- if (typeCtx.globalType()) {
2800
- // Issue #478: Handle global.Type for global types inside scope
2801
- return typeCtx.globalType()!.IDENTIFIER().getText();
2802
- }
2803
-
2804
- if (typeCtx.qualifiedType()) {
2805
- // ADR-016: Handle Scope.Type from outside scope
2806
- // Issue #388: Also handles C++ namespace types
2807
- const identifiers = typeCtx.qualifiedType()!.IDENTIFIER();
2808
- const identifierNames = identifiers.map((id) => id.getText());
2809
- return this.resolveQualifiedType(identifierNames);
2810
- }
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
+ }> = [];
2811
2626
 
2812
- if (typeCtx.userType()) {
2813
- return typeCtx.userType()!.getText();
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
+ }
2814
2639
  }
2815
2640
 
2816
- return null;
2641
+ return { name, parameters };
2817
2642
  }
2818
2643
 
2819
2644
  /**
2820
- * Track variable type with a specific name (for namespace/class members)
2821
- * This allows tracking with mangled names for proper scope resolution
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
2822
2647
  */
2823
- private trackVariableTypeWithName(
2824
- varDecl: Parser.VariableDeclarationContext,
2825
- registryName: string,
2648
+ private registerCallbackType(
2649
+ name: string,
2650
+ funcDecl: Parser.FunctionDeclarationContext,
2826
2651
  ): void {
2827
- const typeCtx = varDecl.type();
2828
- const arrayDim = varDecl.arrayDimension();
2829
- const isConst = varDecl.constModifier() !== null;
2830
-
2831
- // ADR-044: Extract overflow modifier (clamp is default)
2832
- const overflowMod = varDecl.overflowModifier();
2833
- const overflowBehavior: TOverflowBehavior =
2834
- overflowMod?.getText() === "wrap" ? "wrap" : "clamp";
2835
-
2836
- // ADR-049: Extract atomic modifier
2837
- const isAtomic = varDecl.atomicModifier() !== null;
2838
-
2839
- // ADR-045: Handle bounded string type first (special case)
2840
- if (
2841
- this.tryRegisterStringType(
2842
- registryName,
2843
- typeCtx,
2844
- arrayDim,
2845
- isConst,
2846
- overflowBehavior,
2847
- isAtomic,
2848
- )
2849
- ) {
2850
- return;
2851
- }
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
+ }> = [];
2852
2661
 
2853
- // Handle array type syntax: u8[10]
2854
- if (typeCtx.arrayType()) {
2855
- this._registerArrayTypeVariable(
2856
- registryName,
2857
- typeCtx.arrayType()!,
2858
- arrayDim,
2859
- isConst,
2860
- overflowBehavior,
2861
- isAtomic,
2862
- );
2863
- return;
2864
- }
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;
2865
2670
 
2866
- // Resolve base type from context (handles scoped, global, qualified, user types)
2867
- const baseType = this.resolveBaseTypeFromContext(typeCtx);
2868
- if (!baseType) {
2869
- return;
2870
- }
2671
+ // ADR-029: Check if parameter type is itself a callback type
2672
+ const isCallbackParam = CodeGenState.callbackTypes.has(typeName);
2871
2673
 
2872
- // ADR-017/ADR-034: Check if enum or bitmap type (reuse existing helper)
2873
- if (
2874
- this._tryRegisterEnumOrBitmapType(
2875
- registryName,
2876
- baseType,
2877
- isConst,
2878
- arrayDim,
2879
- overflowBehavior,
2880
- isAtomic,
2881
- )
2882
- ) {
2883
- return;
2884
- }
2674
+ let paramType: string;
2675
+ let isPointer: boolean;
2885
2676
 
2886
- // Standard type registration
2887
- this._registerStandardType(
2888
- registryName,
2889
- baseType,
2890
- arrayDim,
2891
- isConst,
2892
- overflowBehavior,
2893
- isAtomic,
2894
- );
2895
- }
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
+ }
2896
2687
 
2897
- /**
2898
- * Register an array type variable (u8[10] syntax)
2899
- */
2900
- private _registerArrayTypeVariable(
2901
- registryName: string,
2902
- arrayTypeCtx: Parser.ArrayTypeContext,
2903
- arrayDim: Parser.ArrayDimensionContext[] | null,
2904
- isConst: boolean,
2905
- overflowBehavior: TOverflowBehavior,
2906
- isAtomic: boolean,
2907
- ): void {
2908
- let baseType = "";
2909
- let bitWidth = 0;
2910
-
2911
- if (arrayTypeCtx.primitiveType()) {
2912
- baseType = arrayTypeCtx.primitiveType()!.getText();
2913
- bitWidth = TYPE_WIDTH[baseType] || 0;
2914
- } else if (arrayTypeCtx.userType()) {
2915
- // Handle user types (structs, enums, bitmaps)
2916
- baseType = arrayTypeCtx.userType()!.getText();
2917
-
2918
- const combinedArrayDim = arrayDim ?? [];
2919
-
2920
- // Check if this is an enum or bitmap type and delegate to proper registration
2921
- if (
2922
- this._tryRegisterEnumOrBitmapType(
2923
- registryName,
2924
- baseType,
2925
- isConst,
2926
- combinedArrayDim,
2927
- overflowBehavior,
2928
- isAtomic,
2929
- )
2930
- ) {
2931
- // Enum/bitmap was registered, but we need to update with arrayType dimension
2932
- const existingInfo = CodeGenState.getVariableTypeInfo(registryName);
2933
- if (existingInfo) {
2934
- const arrayTypeDim =
2935
- this._parseArrayTypeDimensionFromCtx(arrayTypeCtx);
2936
- const allDims = arrayTypeDim
2937
- ? [arrayTypeDim, ...(existingInfo.arrayDimensions ?? [])]
2938
- : existingInfo.arrayDimensions;
2939
- CodeGenState.setVariableTypeInfo(registryName, {
2940
- ...existingInfo,
2941
- isArray: true,
2942
- arrayDimensions: allDims,
2943
- });
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 = "";
2944
2702
  }
2945
- return;
2703
+ parameters.push({
2704
+ name: paramName,
2705
+ type: paramType,
2706
+ isConst,
2707
+ isPointer,
2708
+ isArray,
2709
+ arrayDims,
2710
+ });
2946
2711
  }
2947
-
2948
- // Not an enum/bitmap - register as regular user type (struct)
2949
- // bitWidth already initialized to 0, no reassignment needed
2950
- }
2951
-
2952
- if (!baseType) {
2953
- return;
2954
2712
  }
2955
2713
 
2956
- const arrayDimensions = this._collectArrayDimensions(
2957
- arrayTypeCtx,
2958
- arrayDim,
2959
- );
2960
-
2961
- CodeGenState.setVariableTypeInfo(registryName, {
2962
- baseType,
2963
- bitWidth,
2964
- isArray: true,
2965
- arrayDimensions: arrayDimensions.length > 0 ? arrayDimensions : undefined,
2966
- isConst,
2967
- overflowBehavior,
2968
- isAtomic,
2714
+ CodeGenState.callbackTypes.set(name, {
2715
+ functionName: name,
2716
+ returnType,
2717
+ parameters,
2718
+ typedefName: `${name}_fp`,
2969
2719
  });
2970
2720
  }
2971
2721
 
2972
2722
  /**
2973
- * Parse array dimension from arrayType context.
2723
+ * ADR-029: Check if a function is used as a callback type (field type in a struct)
2974
2724
  */
2975
- private _parseArrayTypeDimensionFromCtx(
2976
- arrayTypeCtx: Parser.ArrayTypeContext,
2977
- ): number | undefined {
2978
- // Get first dimension for backwards compatibility
2979
- const dims = arrayTypeCtx.arrayTypeDimension();
2980
- if (dims.length === 0) {
2981
- return undefined;
2982
- }
2983
- const sizeExpr = dims[0].expression();
2984
- if (!sizeExpr) {
2985
- return undefined;
2986
- }
2987
- const size = Number.parseInt(sizeExpr.getText(), 10);
2988
- return Number.isNaN(size) ? undefined : size;
2989
- }
2725
+ // Issue #63: validateCallbackAssignment, callbackSignaturesMatch, isConstValue,
2726
+ // and validateBareIdentifierInScope moved to TypeValidator
2990
2727
 
2728
+ // EnumTypeResolver now handles: _getEnumTypeFromThisEnum, _getEnumTypeFromGlobalEnum,
2729
+ // _getEnumTypeFromThisVariable, _getEnumTypeFromScopedEnum, _getEnumTypeFromMemberAccess,
2730
+ // _getExpressionEnumType, _getFunctionCallEnumType
2991
2731
  /**
2992
- * Collect array dimensions from array type and additional dimensions
2732
+ * ADR-017: Check if an expression represents an integer literal or numeric type.
2733
+ * Used to detect comparisons between enums and integers.
2993
2734
  */
2994
- private _collectArrayDimensions(
2995
- arrayTypeCtx: Parser.ArrayTypeContext,
2996
- arrayDim: Parser.ArrayDimensionContext[] | null,
2997
- ): number[] {
2998
- const arrayDimensions: number[] = [];
2999
-
3000
- // Get all dimensions from array type syntax (supports multi-dimensional)
3001
- for (const dim of arrayTypeCtx.arrayTypeDimension()) {
3002
- const sizeExpr = dim.expression();
3003
- if (sizeExpr) {
3004
- const size = Number.parseInt(sizeExpr.getText(), 10);
3005
- if (!Number.isNaN(size)) {
3006
- arrayDimensions.push(size);
3007
- }
3008
- }
3009
- }
3010
-
3011
- // Add additional dimensions using const evaluation
3012
- const additionalDims = this._evaluateArrayDimensions(arrayDim);
3013
- if (additionalDims) {
3014
- arrayDimensions.push(...additionalDims);
3015
- }
3016
-
3017
- return arrayDimensions;
2735
+ private _isIntegerExpression(
2736
+ ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
2737
+ ): boolean {
2738
+ return EnumAssignmentValidator.isIntegerExpression(ctx);
3018
2739
  }
3019
2740
 
3020
2741
  /**
3021
- * Register a standard (non-array-syntax, non-special) type
3022
- */
3023
- private _registerStandardType(
3024
- registryName: string,
3025
- baseType: string,
3026
- arrayDim: Parser.ArrayDimensionContext[] | null,
3027
- isConst: boolean,
3028
- overflowBehavior: TOverflowBehavior,
3029
- isAtomic: boolean,
3030
- ): void {
3031
- const bitWidth = TYPE_WIDTH[baseType] || 0;
3032
- // Issue #665: Check array syntax presence first, then try to resolve dimensions
3033
- // This matches the pattern in trackVariableType() - unresolved dimensions (e.g., enum
3034
- // members like EIndex.COUNT) should still mark the variable as an array
3035
- const isArray = arrayDim !== null && arrayDim.length > 0;
3036
- const arrayDimensions = isArray
3037
- ? this._evaluateArrayDimensions(arrayDim)
3038
- : undefined;
3039
-
3040
- CodeGenState.setVariableTypeInfo(registryName, {
3041
- baseType,
3042
- bitWidth,
3043
- isArray,
3044
- arrayDimensions: isArray ? arrayDimensions : undefined,
3045
- isConst,
3046
- overflowBehavior,
3047
- isAtomic,
3048
- });
3049
- }
3050
-
3051
- /**
3052
- * Issue #322: Check if a type name is a user-defined struct
3053
- * Part of IOrchestrator interface.
3054
- */
3055
- isStructType(typeName: string): boolean {
3056
- return TypeResolver.isStructType(typeName);
3057
- }
3058
-
3059
- /**
3060
- * Set up parameter tracking for a function
3061
- */
3062
- private _setParameters(params: Parser.ParameterListContext | null): void {
3063
- CodeGenState.currentParameters.clear();
3064
- CodeGenState.currentParameters.clear();
3065
- if (!params) return;
3066
-
3067
- for (const param of params.parameter()) {
3068
- this._processParameter(param);
3069
- }
3070
- }
3071
-
3072
- /**
3073
- * Process a single parameter declaration
3074
- */
3075
- private _processParameter(param: Parser.ParameterContext): void {
3076
- const name = param.IDENTIFIER().getText();
3077
- // Check both C-Next style (u8[8] param) and legacy style (u8 param[8])
3078
- const isArray =
3079
- param.arrayDimension().length > 0 || param.type().arrayType() !== null;
3080
- const isConst = param.constModifier() !== null;
3081
- const typeCtx = param.type();
3082
-
3083
- // Resolve type information
3084
- const typeInfo = this._resolveParameterTypeInfo(typeCtx);
3085
-
3086
- // Register in currentParameters
3087
- const paramInfo = {
3088
- name,
3089
- baseType: typeInfo.typeName,
3090
- isArray,
3091
- isStruct: typeInfo.isStruct,
3092
- isConst,
3093
- isCallback: typeInfo.isCallback,
3094
- isString: typeInfo.isString,
3095
- };
3096
- CodeGenState.currentParameters.set(name, paramInfo);
3097
-
3098
- // Register in typeRegistry
3099
- this._registerParameterType(name, typeInfo, param, isArray, isConst);
3100
- }
3101
-
3102
- /**
3103
- * Resolve type name and flags from a type context
3104
- */
3105
- private _resolveParameterTypeInfo(typeCtx: Parser.TypeContext): {
3106
- typeName: string;
3107
- isStruct: boolean;
3108
- isCallback: boolean;
3109
- isString: boolean;
3110
- } {
3111
- if (typeCtx.primitiveType()) {
3112
- return {
3113
- typeName: typeCtx.primitiveType()!.getText(),
3114
- isStruct: false,
3115
- isCallback: false,
3116
- isString: false,
3117
- };
3118
- }
3119
-
3120
- if (typeCtx.userType()) {
3121
- const typeName = typeCtx.userType()!.getText();
3122
- return {
3123
- typeName,
3124
- isStruct: this.isStructType(typeName),
3125
- isCallback: CodeGenState.callbackTypes.has(typeName),
3126
- isString: false,
3127
- };
3128
- }
3129
-
3130
- if (typeCtx.qualifiedType()) {
3131
- const identifierNames = typeCtx
3132
- .qualifiedType()!
3133
- .IDENTIFIER()
3134
- .map((id) => id.getText());
3135
- const typeName = this.resolveQualifiedType(identifierNames);
3136
- return {
3137
- typeName,
3138
- isStruct: this.isStructType(typeName),
3139
- isCallback: false,
3140
- isString: false,
3141
- };
3142
- }
3143
-
3144
- if (typeCtx.scopedType()) {
3145
- const localTypeName = typeCtx.scopedType()!.IDENTIFIER().getText();
3146
- const typeName = CodeGenState.currentScope
3147
- ? `${CodeGenState.currentScope}_${localTypeName}`
3148
- : localTypeName;
3149
- return {
3150
- typeName,
3151
- isStruct: this.isStructType(typeName),
3152
- isCallback: false,
3153
- isString: false,
3154
- };
3155
- }
3156
-
3157
- if (typeCtx.globalType()) {
3158
- const typeName = typeCtx.globalType()!.IDENTIFIER().getText();
3159
- return {
3160
- typeName,
3161
- isStruct: this.isStructType(typeName),
3162
- isCallback: false,
3163
- isString: false,
3164
- };
3165
- }
3166
-
3167
- if (typeCtx.stringType()) {
3168
- return {
3169
- typeName: "string",
3170
- isStruct: false,
3171
- isCallback: false,
3172
- isString: true,
3173
- };
3174
- }
3175
-
3176
- // Handle C-Next style array type (u8[8] param) - extract base type
3177
- if (typeCtx.arrayType()) {
3178
- const arrayTypeCtx = typeCtx.arrayType()!;
3179
- if (arrayTypeCtx.primitiveType()) {
3180
- return {
3181
- typeName: arrayTypeCtx.primitiveType()!.getText(),
3182
- isStruct: false,
3183
- isCallback: false,
3184
- isString: false,
3185
- };
3186
- }
3187
- if (arrayTypeCtx.userType()) {
3188
- const typeName = arrayTypeCtx.userType()!.getText();
3189
- return {
3190
- typeName,
3191
- isStruct: this.isStructType(typeName),
3192
- isCallback: CodeGenState.callbackTypes.has(typeName),
3193
- isString: false,
3194
- };
3195
- }
3196
- // Handle string array type (string<32>[5] param)
3197
- if (arrayTypeCtx.stringType()) {
3198
- const stringCtx = arrayTypeCtx.stringType()!;
3199
- return {
3200
- typeName: stringCtx.getText(), // "string<32>"
3201
- isStruct: false,
3202
- isCallback: false,
3203
- isString: true,
3204
- };
3205
- }
3206
- }
3207
-
3208
- // Fallback
3209
- return {
3210
- typeName: typeCtx.getText(),
3211
- isStruct: false,
3212
- isCallback: false,
3213
- isString: false,
3214
- };
3215
- }
3216
-
3217
- /**
3218
- * Extract array dimensions from parameter (C-style or C-Next style).
3219
- */
3220
- private _extractParamArrayDimensions(
3221
- param: Parser.ParameterContext,
3222
- typeCtx: Parser.TypeContext,
3223
- isArray: boolean,
3224
- ): number[] {
3225
- if (!isArray) return [];
3226
-
3227
- // Try C-style first (param.arrayDimension())
3228
- if (param.arrayDimension().length > 0) {
3229
- return ArrayDimensionParser.parseForParameters(param.arrayDimension());
3230
- }
3231
-
3232
- // C-Next style: get dimensions from arrayType
3233
- const arrayTypeCtx = typeCtx.arrayType();
3234
- if (!arrayTypeCtx) return [];
3235
-
3236
- const dimensions: number[] = [];
3237
- for (const dim of arrayTypeCtx.arrayTypeDimension()) {
3238
- const expr = dim.expression();
3239
- if (!expr) continue;
3240
- const size = Number.parseInt(expr.getText(), 10);
3241
- if (!Number.isNaN(size)) {
3242
- dimensions.push(size);
3243
- }
3244
- }
3245
- return dimensions;
3246
- }
3247
-
3248
- /**
3249
- * Register a parameter in the type registry
3250
- */
3251
- private _registerParameterType(
3252
- name: string,
3253
- typeInfo: { typeName: string; isString: boolean },
3254
- param: Parser.ParameterContext,
3255
- isArray: boolean,
3256
- isConst: boolean,
3257
- ): void {
3258
- const { typeName, isString } = typeInfo;
3259
- const typeCtx = param.type();
3260
-
3261
- const isEnum = CodeGenState.symbols!.knownEnums.has(typeName);
3262
- const isBitmap = CodeGenState.symbols!.knownBitmaps.has(typeName);
3263
-
3264
- // Extract array dimensions
3265
- const arrayDimensions = this._extractParamArrayDimensions(
3266
- param,
3267
- typeCtx,
3268
- isArray,
3269
- );
3270
-
3271
- // Add string capacity dimension if applicable
3272
- const stringCapacity = this._getStringCapacity(typeCtx, isString);
3273
- if (isArray && stringCapacity !== undefined) {
3274
- arrayDimensions.push(stringCapacity + 1);
3275
- }
3276
-
3277
- const registeredType = {
3278
- baseType: typeName,
3279
- bitWidth: isBitmap
3280
- ? CodeGenState.symbols!.bitmapBitWidth.get(typeName) || 0
3281
- : TYPE_WIDTH[typeName] || 0,
3282
- isArray,
3283
- arrayDimensions: arrayDimensions.length > 0 ? arrayDimensions : undefined,
3284
- isConst,
3285
- isEnum,
3286
- enumTypeName: isEnum ? typeName : undefined,
3287
- isBitmap,
3288
- bitmapTypeName: isBitmap ? typeName : undefined,
3289
- isString,
3290
- stringCapacity,
3291
- isParameter: true,
3292
- };
3293
- CodeGenState.setVariableTypeInfo(name, registeredType);
3294
- }
3295
-
3296
- /**
3297
- * Extract string capacity from a string type context
3298
- */
3299
- private _getStringCapacity(
3300
- typeCtx: Parser.TypeContext,
3301
- isString: boolean,
3302
- ): number | undefined {
3303
- if (!isString) return undefined;
3304
-
3305
- // Check direct stringType (e.g., string<32> param)
3306
- if (typeCtx.stringType()) {
3307
- const intLiteral = typeCtx.stringType()!.INTEGER_LITERAL();
3308
- if (intLiteral) {
3309
- return Number.parseInt(intLiteral.getText(), 10);
3310
- }
3311
- }
3312
-
3313
- // Check arrayType with stringType (e.g., string<32>[5] param)
3314
- if (typeCtx.arrayType()?.stringType()) {
3315
- const intLiteral = typeCtx.arrayType()!.stringType()!.INTEGER_LITERAL();
3316
- if (intLiteral) {
3317
- return Number.parseInt(intLiteral.getText(), 10);
3318
- }
3319
- }
3320
-
3321
- return undefined;
3322
- }
3323
-
3324
- /**
3325
- * Clear parameter tracking when leaving a function
3326
- */
3327
- private _clearParameters(): void {
3328
- // ADR-025: Remove parameter types from typeRegistry
3329
- for (const name of CodeGenState.currentParameters.keys()) {
3330
- CodeGenState.deleteVariableTypeInfo(name);
3331
- }
3332
- CodeGenState.currentParameters.clear();
3333
- CodeGenState.localArrays.clear();
3334
- }
3335
-
3336
- /**
3337
- * ADR-013: Extract function signature from parameter list
3338
- */
3339
- private extractFunctionSignature(
3340
- name: string,
3341
- params: Parser.ParameterListContext | null,
3342
- ): FunctionSignature {
3343
- const parameters: Array<{
3344
- name: string;
3345
- baseType: string;
3346
- isConst: boolean;
3347
- isArray: boolean;
3348
- }> = [];
3349
-
3350
- if (params) {
3351
- for (const param of params.parameter()) {
3352
- const paramName = param.IDENTIFIER().getText();
3353
- const isConst = param.constModifier() !== null;
3354
- // arrayDimension() returns an array (due to grammar's *), so check length
3355
- // Also check C-Next style array type (e.g., u8[8] param)
3356
- const isArray =
3357
- param.arrayDimension().length > 0 ||
3358
- param.type().arrayType() !== null;
3359
- const baseType = this.getTypeName(param.type());
3360
- parameters.push({ name: paramName, baseType, isConst, isArray });
3361
- }
3362
- }
3363
-
3364
- return { name, parameters };
3365
- }
3366
-
3367
- /**
3368
- * ADR-029: Register a function as a callback type
3369
- * The function name becomes both a callable function and a type for callback fields
3370
- */
3371
- private registerCallbackType(
3372
- name: string,
3373
- funcDecl: Parser.FunctionDeclarationContext,
3374
- ): void {
3375
- const returnType = this.generateType(funcDecl.type());
3376
- const parameters: Array<{
3377
- name: string;
3378
- type: string;
3379
- isConst: boolean;
3380
- isPointer: boolean;
3381
- isArray: boolean;
3382
- arrayDims: string;
3383
- }> = [];
3384
-
3385
- if (funcDecl.parameterList()) {
3386
- for (const param of funcDecl.parameterList()!.parameter()) {
3387
- const paramName = param.IDENTIFIER().getText();
3388
- const typeName = this.getTypeName(param.type());
3389
- const isConst = param.constModifier() !== null;
3390
- const dims = param.arrayDimension();
3391
- const arrayTypeCtx = param.type().arrayType();
3392
- const isArray = dims.length > 0 || arrayTypeCtx !== null;
3393
-
3394
- // ADR-029: Check if parameter type is itself a callback type
3395
- const isCallbackParam = CodeGenState.callbackTypes.has(typeName);
3396
-
3397
- let paramType: string;
3398
- let isPointer: boolean;
3399
-
3400
- if (isCallbackParam) {
3401
- // Use the callback typedef name
3402
- const cbInfo = CodeGenState.callbackTypes.get(typeName)!;
3403
- paramType = cbInfo.typedefName;
3404
- isPointer = false; // Function pointers are already pointers
3405
- } else {
3406
- paramType = this.generateType(param.type());
3407
- // ADR-006: Non-array parameters become pointers
3408
- isPointer = !isArray;
3409
- }
3410
-
3411
- let arrayDims: string;
3412
- if (dims.length > 0) {
3413
- arrayDims = dims.map((d) => this.generateArrayDimension(d)).join("");
3414
- } else if (arrayTypeCtx) {
3415
- // Generate all dimensions from arrayType (supports multi-dimensional)
3416
- arrayDims = arrayTypeCtx
3417
- .arrayTypeDimension()
3418
- .map((d) => {
3419
- const expr = d.expression();
3420
- return expr ? `[${this.generateExpression(expr)}]` : "[]";
3421
- })
3422
- .join("");
3423
- } else {
3424
- arrayDims = "";
3425
- }
3426
- parameters.push({
3427
- name: paramName,
3428
- type: paramType,
3429
- isConst,
3430
- isPointer,
3431
- isArray,
3432
- arrayDims,
3433
- });
3434
- }
3435
- }
3436
-
3437
- CodeGenState.callbackTypes.set(name, {
3438
- functionName: name,
3439
- returnType,
3440
- parameters,
3441
- typedefName: `${name}_fp`,
3442
- });
3443
- }
3444
-
3445
- /**
3446
- * ADR-029: Check if a function is used as a callback type (field type in a struct)
3447
- */
3448
- // Issue #63: validateCallbackAssignment, callbackSignaturesMatch, isConstValue,
3449
- // and validateBareIdentifierInScope moved to TypeValidator
3450
-
3451
- // EnumTypeResolver now handles: _getEnumTypeFromThisEnum, _getEnumTypeFromGlobalEnum,
3452
- // _getEnumTypeFromThisVariable, _getEnumTypeFromScopedEnum, _getEnumTypeFromMemberAccess,
3453
- // _getExpressionEnumType, _getFunctionCallEnumType
3454
- /**
3455
- * ADR-017: Check if an expression represents an integer literal or numeric type.
3456
- * Used to detect comparisons between enums and integers.
3457
- */
3458
- private _isIntegerExpression(
3459
- ctx: Parser.ExpressionContext | Parser.RelationalExpressionContext,
3460
- ): boolean {
3461
- return EnumAssignmentValidator.isIntegerExpression(ctx);
3462
- }
3463
-
3464
- /**
3465
- * ADR-045: Check if an expression is a string concatenation (contains + with string operands).
3466
- * Returns the operand expressions if it is, null otherwise.
2742
+ * ADR-045: Check if an expression is a string concatenation.
2743
+ * Delegates to StringOperationsHelper.
3467
2744
  */
3468
2745
  private _getStringConcatOperands(ctx: Parser.ExpressionContext): {
3469
2746
  left: string;
@@ -3471,53 +2748,12 @@ export default class CodeGenerator implements IOrchestrator {
3471
2748
  leftCapacity: number;
3472
2749
  rightCapacity: number;
3473
2750
  } | null {
3474
- // Navigate to the additive expression level using ExpressionUnwrapper
3475
- // Issue #707: Deduplicated expression tree navigation
3476
- const add = ExpressionUnwrapper.getAdditiveExpression(ctx);
3477
- if (!add) return null;
3478
- const multExprs = add.multiplicativeExpression();
3479
-
3480
- // Need exactly 2 operands for simple concatenation
3481
- if (multExprs.length !== 2) return null;
3482
-
3483
- // Check if this is addition (not subtraction)
3484
- const text = add.getText();
3485
- if (text.includes("-")) return null;
3486
-
3487
- // Get the operand texts
3488
- const leftText = multExprs[0].getText();
3489
- const rightText = multExprs[1].getText();
3490
-
3491
- // Check if at least one operand is a string
3492
- const leftCapacity = this.getStringExprCapacity(leftText);
3493
- const rightCapacity = this.getStringExprCapacity(rightText);
3494
-
3495
- if (leftCapacity === null && rightCapacity === null) {
3496
- return null; // Neither is a string
3497
- }
3498
-
3499
- // If one is null, it's not a valid string concatenation
3500
- if (leftCapacity === null || rightCapacity === null) {
3501
- return null;
3502
- }
3503
-
3504
- return {
3505
- left: leftText,
3506
- right: rightText,
3507
- leftCapacity,
3508
- rightCapacity,
3509
- };
2751
+ return StringOperationsHelper.getStringConcatOperands(ctx);
3510
2752
  }
3511
2753
 
3512
2754
  /**
3513
- * ADR-045: Get the capacity of a string expression.
3514
- * For string literals, capacity is the literal length.
3515
- * For string variables, capacity is from the type registry.
3516
- */
3517
- /**
3518
- * ADR-045: Check if an expression is a substring extraction (string[start, length]).
3519
- * Returns the source string, start, length, and source capacity if it is.
3520
- * Issue #707: Uses ExpressionUnwrapper for tree navigation.
2755
+ * ADR-045: Check if an expression is a substring extraction.
2756
+ * Delegates to StringOperationsHelper.
3521
2757
  */
3522
2758
  private _getSubstringOperands(ctx: Parser.ExpressionContext): {
3523
2759
  source: string;
@@ -3525,51 +2761,9 @@ export default class CodeGenerator implements IOrchestrator {
3525
2761
  length: string;
3526
2762
  sourceCapacity: number;
3527
2763
  } | null {
3528
- // Navigate to the postfix expression level using shared utility
3529
- const postfix = ExpressionUnwrapper.getPostfixExpression(ctx);
3530
- if (!postfix) return null;
3531
-
3532
- const primary = postfix.primaryExpression();
3533
- const ops = postfix.postfixOp();
3534
-
3535
- // Need exactly one postfix operation (the [start, length])
3536
- if (ops.length !== 1) return null;
3537
-
3538
- const op = ops[0];
3539
- const exprs = op.expression();
3540
-
3541
- // Get the source variable name first
3542
- const sourceId = primary.IDENTIFIER();
3543
- if (!sourceId) return null;
3544
-
3545
- const sourceName = sourceId.getText();
3546
-
3547
- // Check if source is a string type
3548
- const typeInfo = CodeGenState.getVariableTypeInfo(sourceName);
3549
- if (!typeInfo?.isString || typeInfo.stringCapacity === undefined) {
3550
- return null;
3551
- }
3552
-
3553
- // Issue #140: Handle both [start, length] pattern (2 expressions)
3554
- // and single-character access [index] pattern (1 expression, treated as [index, 1])
3555
- if (exprs.length === 2) {
3556
- return {
3557
- source: sourceName,
3558
- start: this.generateExpression(exprs[0]),
3559
- length: this.generateExpression(exprs[1]),
3560
- sourceCapacity: typeInfo.stringCapacity,
3561
- };
3562
- } else if (exprs.length === 1) {
3563
- // Single-character access: source[i] is sugar for source[i, 1]
3564
- return {
3565
- source: sourceName,
3566
- start: this.generateExpression(exprs[0]),
3567
- length: "1",
3568
- sourceCapacity: typeInfo.stringCapacity,
3569
- };
3570
- }
3571
-
3572
- return null;
2764
+ return StringOperationsHelper.getSubstringOperands(ctx, {
2765
+ generateExpression: (exprCtx) => this.generateExpression(exprCtx),
2766
+ });
3573
2767
  }
3574
2768
 
3575
2769
  // ========================================================================
@@ -3794,226 +2988,47 @@ export default class CodeGenerator implements IOrchestrator {
3794
2988
  const postfix = ExpressionUnwrapper.getPostfixExpression(ctx);
3795
2989
  if (!postfix) return "not-array";
3796
2990
 
3797
- const ops = postfix.postfixOp();
3798
- if (ops.length === 0) return "not-array";
3799
-
3800
- // Last operator must be member access (.identifier)
3801
- const lastOp = ops.at(-1)!;
3802
- const memberName = lastOp.IDENTIFIER()?.getText();
3803
- if (!memberName) return "not-array";
3804
-
3805
- // Get the base identifier to find the struct type
3806
- const primary = postfix.primaryExpression();
3807
- if (!primary) return "not-array";
3808
- const baseId = primary.IDENTIFIER()?.getText();
3809
- if (!baseId) return "not-array";
3810
-
3811
- // Look up the struct type from either:
3812
- // 1. Local variable: typeRegistry.get(baseId).baseType
3813
- // 2. Parameter: currentParameters.get(baseId).baseType
3814
- let structType: string | undefined;
3815
-
3816
- const typeInfo = CodeGenState.getVariableTypeInfo(baseId);
3817
- if (typeInfo) {
3818
- structType = typeInfo.baseType;
3819
- } else {
3820
- const paramInfo = CodeGenState.currentParameters.get(baseId);
3821
- if (paramInfo) {
3822
- structType = paramInfo.baseType;
3823
- }
3824
- }
3825
-
3826
- if (!structType) return "not-array";
3827
-
3828
- // Check if this struct member is an array
3829
- const memberInfo = this.getMemberTypeInfo(structType, memberName);
3830
-
3831
- // Issue #355: If memberInfo is undefined, we don't have struct field info
3832
- // This could mean the header wasn't parsed - return "unknown" for defensive generation
3833
- if (!memberInfo) {
3834
- return "unknown";
3835
- }
3836
-
3837
- return memberInfo.isArray ? "array" : "not-array";
3838
- }
3839
-
3840
- /**
3841
- * Generate a function argument with proper ADR-006 semantics.
3842
- * - Local variables get & (address-of)
3843
- * - Member access (cursor.x) gets & (address-of)
3844
- * - Array access (arr[i]) gets & (address-of)
3845
- * - Parameters are passed as-is (already pointers)
3846
- * - Arrays are passed as-is (naturally decay to pointers)
3847
- * - Literals use compound literals for pointer params: &(type){value}
3848
- * - Complex expressions are passed as-is
3849
- */
3850
- private _generateFunctionArg(
3851
- ctx: Parser.ExpressionContext,
3852
- targetParamBaseType?: string,
3853
- ): string {
3854
- const id = CodegenParserUtils.getSimpleIdentifier(ctx);
3855
- if (id) {
3856
- return this._handleIdentifierArg(id);
3857
- }
3858
-
3859
- const lvalueType = this.getLvalueType(ctx);
3860
- if (lvalueType) {
3861
- return this._handleLvalueArg(ctx, lvalueType, targetParamBaseType);
3862
- }
3863
-
3864
- return this._handleRvalueArg(ctx, targetParamBaseType);
3865
- }
3866
-
3867
- /**
3868
- * Handle simple identifier argument (parameter, local array, scope member, or variable)
3869
- */
3870
- private _handleIdentifierArg(id: string): string {
3871
- // Parameters are already pointers
3872
- if (CodeGenState.currentParameters.get(id)) {
3873
- return id;
3874
- }
3875
-
3876
- // Local arrays decay to pointers
3877
- if (CodeGenState.localArrays.has(id)) {
3878
- return id;
3879
- }
3880
-
3881
- // Global arrays also decay to pointers (check typeRegistry)
3882
- // But NOT strings - strings need & (they're char arrays but passed by reference)
3883
- const typeInfo = CodeGenState.getVariableTypeInfo(id);
3884
- if (typeInfo?.isArray && !typeInfo.isString) {
3885
- return id;
3886
- }
3887
-
3888
- // Scope member - may need prefixing
3889
- if (CodeGenState.currentScope) {
3890
- const members = CodeGenState.getScopeMembers(CodeGenState.currentScope);
3891
- if (members?.has(id)) {
3892
- const scopedName = `${CodeGenState.currentScope}_${id}`;
3893
- return CppModeHelper.maybeAddressOf(scopedName);
3894
- }
3895
- }
3896
-
3897
- // Local variable - add & (except in C++ mode)
3898
- return CppModeHelper.maybeAddressOf(id);
3899
- }
3900
-
3901
- /**
3902
- * Handle lvalue argument (member access or array access)
3903
- */
3904
- private _handleLvalueArg(
3905
- ctx: Parser.ExpressionContext,
3906
- lvalueType: string,
3907
- targetParamBaseType?: string,
3908
- ): string {
3909
- // Member access to array field - arrays decay to pointers
3910
- if (lvalueType === "member") {
3911
- const memberResult = this._handleMemberAccessArg(
3912
- ctx,
3913
- targetParamBaseType,
3914
- );
3915
- if (memberResult) return memberResult;
3916
- }
3917
-
3918
- // Generate expression with address-of
3919
- const generatedExpr = this.generateExpression(ctx);
3920
- const expr = CppModeHelper.maybeAddressOf(generatedExpr);
3921
-
3922
- // String subscript access may need cast
3923
- if (lvalueType === "array") {
3924
- return this._maybeCastStringSubscript(ctx, expr, targetParamBaseType);
3925
- }
3926
-
3927
- return expr;
3928
- }
3929
-
3930
- /**
3931
- * Handle member access argument - may need special handling for arrays or C++ conversions
3932
- */
3933
- private _handleMemberAccessArg(
3934
- ctx: Parser.ExpressionContext,
3935
- targetParamBaseType?: string,
3936
- ): string | null {
3937
- const arrayStatus = this.getMemberAccessArrayStatus(ctx);
3938
-
3939
- // Array member - no address-of needed
3940
- if (arrayStatus === "array") {
3941
- return this.generateExpression(ctx);
3942
- }
3943
-
3944
- // C++ mode may need temp variable for type conversion
3945
- if (
3946
- arrayStatus === "not-array" &&
3947
- this.needsCppMemberConversion(ctx, targetParamBaseType)
3948
- ) {
3949
- return this._createCppMemberConversionTemp(ctx, targetParamBaseType!);
3950
- }
3951
-
3952
- return null; // Fall through to default lvalue handling
3953
- }
3954
-
3955
- /**
3956
- * Create temp variable for C++ member conversion
3957
- */
3958
- private _createCppMemberConversionTemp(
3959
- ctx: Parser.ExpressionContext,
3960
- targetParamBaseType: string,
3961
- ): string {
3962
- const cType = TYPE_MAP[targetParamBaseType] || "uint8_t";
3963
- const value = this.generateExpression(ctx);
3964
- const tempName = `_cnx_tmp_${CodeGenState.tempVarCounter++}`;
3965
- const castExpr = CppModeHelper.cast(cType, value);
3966
- CodeGenState.pendingTempDeclarations.push(
3967
- `${cType} ${tempName} = ${castExpr};`,
3968
- );
3969
- return CppModeHelper.maybeAddressOf(tempName);
3970
- }
3971
-
3972
- /**
3973
- * Maybe cast string subscript access for integer pointer parameters
3974
- */
3975
- private _maybeCastStringSubscript(
3976
- ctx: Parser.ExpressionContext,
3977
- expr: string,
3978
- targetParamBaseType?: string,
3979
- ): string {
3980
- if (!targetParamBaseType || !this.isStringSubscriptAccess(ctx)) {
3981
- return expr;
3982
- }
2991
+ const ops = postfix.postfixOp();
2992
+ if (ops.length === 0) return "not-array";
3983
2993
 
3984
- const cType = TYPE_MAP[targetParamBaseType];
3985
- if (cType && !["float", "double", "bool", "void"].includes(cType)) {
3986
- return CppModeHelper.reinterpretCast(`${cType}*`, expr);
3987
- }
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";
3988
2998
 
3989
- return expr;
3990
- }
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";
3991
3004
 
3992
- /**
3993
- * Handle rvalue argument (literals or complex expressions)
3994
- */
3995
- private _handleRvalueArg(
3996
- ctx: Parser.ExpressionContext,
3997
- targetParamBaseType?: string,
3998
- ): string {
3999
- if (!targetParamBaseType) {
4000
- return this.generateExpression(ctx);
4001
- }
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;
4002
3009
 
4003
- const cType = TYPE_MAP[targetParamBaseType];
4004
- if (!cType || cType === "void") {
4005
- 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
+ }
4006
3018
  }
4007
3019
 
4008
- const value = this.generateExpression(ctx);
3020
+ if (!structType) return "not-array";
3021
+
3022
+ // Check if this struct member is an array
3023
+ const memberInfo = this.getMemberTypeInfo(structType, memberName);
4009
3024
 
4010
- // C++ mode: rvalues can bind to const T&
4011
- if (CodeGenState.cppMode) {
4012
- 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";
4013
3029
  }
4014
3030
 
4015
- // C mode: Use compound literal syntax
4016
- return `&(${cType}){${value}}`;
3031
+ return memberInfo.isArray ? "array" : "not-array";
4017
3032
  }
4018
3033
 
4019
3034
  // ========================================================================
@@ -4136,7 +3151,7 @@ export default class CodeGenerator implements IOrchestrator {
4136
3151
  ): void {
4137
3152
  const type = this.generateType(varDecl.type());
4138
3153
  const varName = varDecl.IDENTIFIER().getText();
4139
- const fullName = `${scopeName}_${varName}`;
3154
+ const fullName = QualifiedNameGenerator.forMember(scopeName, varName);
4140
3155
  const prefix = isPrivate ? "static " : "";
4141
3156
 
4142
3157
  const arrayDims = varDecl.arrayDimension();
@@ -4147,7 +3162,10 @@ export default class CodeGenerator implements IOrchestrator {
4147
3162
 
4148
3163
  // Handle arrayType dimension (C-Next style: u8[16] data)
4149
3164
  if (hasArrayTypeSyntax) {
4150
- decl += this._getArrayTypeDimension(varDecl.type());
3165
+ decl += VariableDeclHelper.getArrayTypeDimension(varDecl.type(), {
3166
+ tryEvaluateConstant: (exprCtx) => this.tryEvaluateConstant(exprCtx),
3167
+ generateExpression: (exprCtx) => this.generateExpression(exprCtx),
3168
+ });
4151
3169
  }
4152
3170
 
4153
3171
  // Handle arrayDimension (C-style or additional dimensions)
@@ -4189,7 +3207,10 @@ export default class CodeGenerator implements IOrchestrator {
4189
3207
  ): void {
4190
3208
  const returnType = this.generateType(funcDecl.type());
4191
3209
  const funcName = funcDecl.IDENTIFIER().getText();
4192
- const fullName = `${scopeName}_${funcName}`;
3210
+ const fullName = QualifiedNameGenerator.forFunctionStrings(
3211
+ scopeName,
3212
+ funcName,
3213
+ );
4193
3214
  const prefix = isPrivate ? "static " : "";
4194
3215
 
4195
3216
  // Issue #269: Set current function name for pass-by-value lookup
@@ -4584,32 +3605,34 @@ export default class CodeGenerator implements IOrchestrator {
4584
3605
  }
4585
3606
 
4586
3607
  /**
4587
- * Set up context for function generation
3608
+ * Set up context for function generation.
3609
+ * Issue #793: Delegates to FunctionContextManager.
4588
3610
  */
4589
3611
  private _setupFunctionContext(
4590
3612
  name: string,
4591
3613
  ctx: Parser.FunctionDeclarationContext,
4592
3614
  ): void {
4593
- // Issue #269: Set current function name for pass-by-value lookup
4594
- const fullFuncName = CodeGenState.currentScope
4595
- ? `${CodeGenState.currentScope}_${name}`
4596
- : name;
4597
- CodeGenState.currentFunctionName = fullFuncName;
4598
- // Issue #477: Set return type for enum inference in return statements
4599
- CodeGenState.currentFunctionReturnType = ctx.type().getText();
4600
-
4601
- // Track parameters for ADR-006 pointer semantics
4602
- this._setParameters(ctx.parameterList() ?? null);
3615
+ FunctionContextManager.setupFunctionContext(
3616
+ name,
3617
+ ctx,
3618
+ this._getFunctionContextCallbacks(),
3619
+ );
3620
+ }
4603
3621
 
4604
- // ADR-016: Clear local variables and mark that we're in a function body
4605
- CodeGenState.localVariables.clear();
4606
- CodeGenState.floatBitShadows.clear();
4607
- CodeGenState.floatShadowCurrent.clear();
4608
- 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
+ };
4609
3631
  }
4610
3632
 
4611
3633
  /**
4612
- * Resolve return type and initial params for function
3634
+ * Resolve return type and initial params for function.
3635
+ * Issue #793: Delegates to FunctionContextManager.
4613
3636
  */
4614
3637
  private _resolveReturnTypeAndParams(
4615
3638
  name: string,
@@ -4617,33 +3640,20 @@ export default class CodeGenerator implements IOrchestrator {
4617
3640
  isMainWithArgs: boolean,
4618
3641
  ctx: Parser.FunctionDeclarationContext,
4619
3642
  ): { actualReturnType: string; initialParams: string } {
4620
- if (isMainWithArgs) {
4621
- // Special case: main(u8 args[][]) -> int main(int argc, char *argv[])
4622
- const argsParam = ctx.parameterList()!.parameter()[0];
4623
- CodeGenState.mainArgsName = argsParam.IDENTIFIER().getText();
4624
- return {
4625
- actualReturnType: "int",
4626
- initialParams: "int argc, char *argv[]",
4627
- };
4628
- }
4629
-
4630
- // For main() without args, always use int return type for C++ compatibility
4631
- const actualReturnType = name === "main" ? "int" : returnType;
4632
- return { actualReturnType, initialParams: "" };
3643
+ return FunctionContextManager.resolveReturnTypeAndParams(
3644
+ name,
3645
+ returnType,
3646
+ isMainWithArgs,
3647
+ ctx,
3648
+ );
4633
3649
  }
4634
3650
 
4635
3651
  /**
4636
- * Clean up context after function generation
3652
+ * Clean up context after function generation.
3653
+ * Issue #793: Delegates to FunctionContextManager.
4637
3654
  */
4638
3655
  private _cleanupFunctionContext(): void {
4639
- CodeGenState.inFunctionBody = false;
4640
- CodeGenState.localVariables.clear();
4641
- CodeGenState.floatBitShadows.clear();
4642
- CodeGenState.floatShadowCurrent.clear();
4643
- CodeGenState.mainArgsName = null;
4644
- CodeGenState.currentFunctionName = null;
4645
- CodeGenState.currentFunctionReturnType = null;
4646
- this._clearParameters();
3656
+ FunctionContextManager.cleanupFunctionContext();
4647
3657
  }
4648
3658
 
4649
3659
  /**
@@ -4766,74 +3776,27 @@ export default class CodeGenerator implements IOrchestrator {
4766
3776
  // ========================================================================
4767
3777
 
4768
3778
  private generateVariableDecl(ctx: Parser.VariableDeclarationContext): string {
4769
- // Issue #375: Check for C++ constructor syntax - early return
4770
- const constructorArgList = ctx.constructorArgumentList();
4771
- if (constructorArgList) {
4772
- return this._generateConstructorDecl(ctx, constructorArgList);
4773
- }
4774
-
4775
- // Issue #696: Use helper for modifier extraction and validation
4776
- const modifiers = VariableModifierBuilder.build(
4777
- ctx,
4778
- CodeGenState.inFunctionBody,
4779
- );
4780
-
4781
- const name = ctx.IDENTIFIER().getText();
4782
- const typeCtx = ctx.type();
4783
-
4784
- // Reject C-style array declarations (u16 arr[8]) - require C-Next style (u16[8] arr)
4785
- this._validateArrayDeclarationSyntax(ctx, typeCtx, name);
4786
-
4787
- const type = this._inferVariableType(ctx, name);
4788
-
4789
- // Track local variable metadata
4790
- this._trackLocalVariable(ctx, name);
4791
-
4792
- // ADR-045: Handle bounded string type specially - early return
4793
- const stringResult = StringDeclHelper.generateStringDecl(
4794
- typeCtx,
4795
- name,
4796
- ctx.expression() ?? null,
4797
- ctx.arrayDimension(),
4798
- modifiers,
4799
- ctx.constModifier() !== null,
4800
- {
4801
- generateExpression: (exprCtx) => this.generateExpression(exprCtx),
4802
- generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
4803
- getStringConcatOperands: (concatCtx) =>
4804
- this._getStringConcatOperands(concatCtx),
4805
- getSubstringOperands: (substrCtx) =>
4806
- this._getSubstringOperands(substrCtx),
4807
- getStringExprCapacity: (exprCode) =>
4808
- this.getStringExprCapacity(exprCode),
4809
- requireStringInclude: () => this.requireInclude("string"),
4810
- },
4811
- );
4812
- if (stringResult.handled) {
4813
- return stringResult.code;
4814
- }
4815
-
4816
- // Build base declaration
4817
- const modifierPrefix = VariableModifierBuilder.toPrefix(modifiers);
4818
- let decl = `${modifierPrefix}${type} ${name}`;
4819
-
4820
- // Handle array declarations - early return if array init handled
4821
- const arrayResult = this._handleArrayDeclaration(ctx, typeCtx, name, decl);
4822
- if (arrayResult.handled) {
4823
- return arrayResult.code;
4824
- }
4825
- decl = arrayResult.decl;
4826
-
4827
- // Handle initialization
4828
- decl = this._generateVariableInitializer(
4829
- ctx,
4830
- typeCtx,
4831
- decl,
4832
- arrayResult.isArray,
4833
- );
4834
-
4835
- // Handle pending C++ class field assignments
4836
- 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
+ });
4837
3800
  }
4838
3801
 
4839
3802
  /**
@@ -4870,7 +3833,11 @@ export default class CodeGenerator implements IOrchestrator {
4870
3833
  return;
4871
3834
  }
4872
3835
 
4873
- 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
+ });
4874
3841
  CodeGenState.localVariables.add(name);
4875
3842
 
4876
3843
  // Bug #8: Track local const values for array size and bit index resolution
@@ -4882,383 +3849,10 @@ export default class CodeGenerator implements IOrchestrator {
4882
3849
  }
4883
3850
  }
4884
3851
 
4885
- /**
4886
- * Issue #696: Handle array declaration with dimension parsing and init.
4887
- * Bug fix: Also handles C-Next style arrayType syntax (u16[8] myArray).
4888
- */
4889
- private _handleArrayDeclaration(
4890
- ctx: Parser.VariableDeclarationContext,
4891
- typeCtx: Parser.TypeContext,
4892
- name: string,
4893
- decl: string,
4894
- ): { handled: boolean; code: string; decl: string; isArray: boolean } {
4895
- const arrayDims = ctx.arrayDimension();
4896
- const hasArrayTypeSyntax = typeCtx.arrayType() !== null;
4897
- const isArray = arrayDims.length > 0 || hasArrayTypeSyntax;
4898
-
4899
- if (!isArray) {
4900
- return { handled: false, code: "", decl, isArray: false };
4901
- }
4902
-
4903
- // Generate dimension string from arrayType syntax (u16[8] myArray)
4904
- const arrayTypeDimStr = this._getArrayTypeDimension(typeCtx);
4905
-
4906
- const hasEmptyArrayDim = arrayDims.some((dim) => !dim.expression());
4907
- const declaredSize =
4908
- this._parseArrayTypeDimension(typeCtx) ??
4909
- this._parseFirstArrayDimension(arrayDims);
4910
-
4911
- // ADR-035: Handle array initializers with size inference
4912
- if (ctx.expression()) {
4913
- const arrayInitResult = ArrayInitHelper.processArrayInit(
4914
- name,
4915
- typeCtx,
4916
- ctx.expression()!,
4917
- arrayDims,
4918
- hasEmptyArrayDim,
4919
- declaredSize,
4920
- {
4921
- generateExpression: (exprCtx) => this.generateExpression(exprCtx),
4922
- getTypeName: (typeCtxParam) => this.getTypeName(typeCtxParam),
4923
- generateArrayDimensions: (dims) => this.generateArrayDimensions(dims),
4924
- },
4925
- );
4926
- if (arrayInitResult) {
4927
- // Track as local array for type resolution
4928
- CodeGenState.localArrays.add(name);
4929
- // Include arrayType dimension before arrayDimension dimensions
4930
- const fullDimSuffix = arrayTypeDimStr + arrayInitResult.dimensionSuffix;
4931
- return {
4932
- handled: true,
4933
- code: `${decl}${fullDimSuffix} = ${arrayInitResult.initValue};`,
4934
- decl,
4935
- isArray: true,
4936
- };
4937
- }
4938
- }
4939
-
4940
- // Generate dimensions: arrayType dimension first, then arrayDimension dimensions
4941
- const newDecl =
4942
- decl + arrayTypeDimStr + this.generateArrayDimensions(arrayDims);
4943
- CodeGenState.localArrays.add(name);
4944
-
4945
- return { handled: false, code: "", decl: newDecl, isArray: true };
4946
- }
4947
-
4948
- /**
4949
- * Get array dimension string from arrayType syntax (u16[8] -> "[8]", u16[4][4] -> "[4][4]").
4950
- * Evaluates const expressions to their numeric values for C compatibility.
4951
- */
4952
- private _getArrayTypeDimension(typeCtx: Parser.TypeContext): string {
4953
- if (!typeCtx.arrayType()) {
4954
- return "";
4955
- }
4956
- const dims = typeCtx.arrayType()!.arrayTypeDimension();
4957
- let result = "";
4958
- for (const dim of dims) {
4959
- const sizeExpr = dim.expression();
4960
- if (!sizeExpr) {
4961
- result += "[]";
4962
- continue;
4963
- }
4964
- // Try to evaluate as constant first (required for C file-scope arrays)
4965
- // Fall back to expression text for macros, enums, etc.
4966
- const dimValue =
4967
- this.tryEvaluateConstant(sizeExpr) ?? this.generateExpression(sizeExpr);
4968
- result += `[${dimValue}]`;
4969
- }
4970
- return result;
4971
- }
4972
-
4973
- /**
4974
- * Parse first array dimension from arrayType syntax for size validation.
4975
- */
4976
- private _parseArrayTypeDimension(typeCtx: Parser.TypeContext): number | null {
4977
- if (!typeCtx.arrayType()) {
4978
- return null;
4979
- }
4980
- const dims = typeCtx.arrayType()!.arrayTypeDimension();
4981
- if (dims.length === 0) {
4982
- return null;
4983
- }
4984
- const sizeExpr = dims[0].expression();
4985
- if (!sizeExpr) {
4986
- return null;
4987
- }
4988
- const sizeText = sizeExpr.getText();
4989
- const digitRegex = /^\d+$/;
4990
- if (digitRegex.exec(sizeText)) {
4991
- return Number.parseInt(sizeText, 10);
4992
- }
4993
- return null;
4994
- }
4995
-
4996
- /**
4997
- * Issue #696: Parse first array dimension for validation.
4998
- */
4999
- private _parseFirstArrayDimension(
5000
- arrayDims: Parser.ArrayDimensionContext[],
5001
- ): number | null {
5002
- if (arrayDims.length === 0 || !arrayDims[0].expression()) {
5003
- return null;
5004
- }
5005
- const sizeText = arrayDims[0].expression()!.getText();
5006
- if (/^\d+$/.exec(sizeText)) {
5007
- return Number.parseInt(sizeText, 10);
5008
- }
5009
- return null;
5010
- }
5011
-
5012
- /**
5013
- * Validate array declaration syntax - reject C-style, require C-Next style.
5014
- * C-style: u16 arr[8] (all dimensions after identifier) - REJECTED
5015
- * C-Next style: u16[8] arr (first dimension in type) - REQUIRED
5016
- * Multi-dim C-Next: u16[4] arr[2] (first in type, rest after) - ALLOWED
5017
- * Exceptions (grammar limitations):
5018
- * - Empty dimensions for size inference: u8 arr[] <- [...]
5019
- * - Qualified types: SeaDash.Parse.Result arr[3] (no arrayType support)
5020
- * - Scoped/global types: this.Type arr[3], global.Type arr[3]
5021
- * - String types: string<N> arr[3]
5022
- */
5023
- private _validateArrayDeclarationSyntax(
5024
- ctx: Parser.VariableDeclarationContext,
5025
- typeCtx: Parser.TypeContext,
5026
- name: string,
5027
- ): void {
5028
- const arrayDims = ctx.arrayDimension();
5029
- if (arrayDims.length === 0) {
5030
- return; // Not an array declaration
5031
- }
5032
-
5033
- // If type already has arrayType, additional dimensions are allowed (multi-dim)
5034
- if (typeCtx.arrayType()) {
5035
- return; // Valid C-Next style: u16[4] arr[2] → uint16_t arr[4][2]
5036
- }
5037
-
5038
- // Allow empty first dimension for size inference: u8 arr[] <- [1, 2, 3]
5039
- // The grammar doesn't support u8[] arr syntax, so this is the only way
5040
- if (arrayDims.length === 1 && !arrayDims[0].expression()) {
5041
- return; // Size inference pattern allowed
5042
- }
5043
-
5044
- // Allow C-style for multi-dimensional arrays: u8 matrix[4][4]
5045
- // The arrayType grammar only supports single dimension, so multi-dim needs C-style
5046
- if (arrayDims.length > 1) {
5047
- return; // Multi-dimensional arrays need C-style
5048
- }
5049
-
5050
- // Allow C-style for types that don't support arrayType syntax:
5051
- // - Qualified types (Scope.Type, Namespace::Type)
5052
- // - Scoped types (this.Type)
5053
- // - Global types (global.Type)
5054
- // - String types (string<N>)
5055
- // - Bitmap types (code generator doesn't yet handle arrayType for bitmaps)
5056
- if (
5057
- typeCtx.qualifiedType() ||
5058
- typeCtx.scopedType() ||
5059
- typeCtx.globalType() ||
5060
- typeCtx.stringType()
5061
- ) {
5062
- return; // Grammar limitation - these can't use arrayType
5063
- }
5064
-
5065
- // C-style array declaration detected - reject with helpful error
5066
- const baseType = this._extractBaseTypeName(typeCtx);
5067
- const dimensions = arrayDims
5068
- .map((dim) => `[${dim.expression()?.getText() ?? ""}]`)
5069
- .join("");
5070
- const line = ctx.start?.line ?? 0;
5071
- const col = ctx.start?.column ?? 0;
5072
-
5073
- throw new Error(
5074
- `${line}:${col} C-style array declaration is not allowed. ` +
5075
- `Use '${baseType}${dimensions} ${name}' instead of '${baseType} ${name}${dimensions}'`,
5076
- );
5077
- }
5078
-
5079
- /**
5080
- * Extract base type name from type context for error messages.
5081
- */
5082
- private _extractBaseTypeName(typeCtx: Parser.TypeContext): string {
5083
- if (typeCtx.primitiveType()) {
5084
- return typeCtx.primitiveType()!.getText();
5085
- }
5086
- if (typeCtx.userType()) {
5087
- return typeCtx.userType()!.getText();
5088
- }
5089
- if (typeCtx.arrayType()) {
5090
- const arrCtx = typeCtx.arrayType()!;
5091
- if (arrCtx.primitiveType()) {
5092
- return arrCtx.primitiveType()!.getText();
5093
- }
5094
- if (arrCtx.userType()) {
5095
- return arrCtx.userType()!.getText();
5096
- }
5097
- }
5098
- return typeCtx.getText();
5099
- }
5100
-
5101
- /**
5102
- * Issue #696: Generate variable initializer with validation.
5103
- */
5104
- private _generateVariableInitializer(
5105
- ctx: Parser.VariableDeclarationContext,
5106
- typeCtx: Parser.TypeContext,
5107
- decl: string,
5108
- isArray: boolean,
5109
- ): string {
5110
- if (!ctx.expression()) {
5111
- // ADR-015: Zero initialization for uninitialized variables
5112
- return `${decl} = ${this.getZeroInitializer(typeCtx, isArray)}`;
5113
- }
5114
-
5115
- const typeName = this.getTypeName(typeCtx);
5116
- const savedExpectedType = CodeGenState.expectedType;
5117
- CodeGenState.expectedType = typeName;
5118
-
5119
- // ADR-017: Validate enum type for initialization
5120
- EnumAssignmentValidator.validateEnumAssignment(typeName, ctx.expression()!);
5121
-
5122
- // ADR-024: Validate integer literals and type conversions
5123
- this._validateIntegerInitializer(ctx, typeName);
5124
-
5125
- const result = `${decl} = ${this.generateExpression(ctx.expression()!)}`;
5126
- CodeGenState.expectedType = savedExpectedType;
5127
-
5128
- return result;
5129
- }
5130
-
5131
- /**
5132
- * Issue #696: Validate integer initializer using helper.
5133
- */
5134
- private _validateIntegerInitializer(
5135
- ctx: Parser.VariableDeclarationContext,
5136
- typeName: string,
5137
- ): void {
5138
- if (!this._isIntegerType(typeName)) {
5139
- return;
5140
- }
5141
-
5142
- const exprText = ctx.expression()!.getText().trim();
5143
- const line = ctx.start?.line ?? 0;
5144
- const col = ctx.start?.column ?? 0;
5145
- const isLiteral = LiteralUtils.parseIntegerLiteral(exprText) !== undefined;
5146
-
5147
- try {
5148
- if (isLiteral) {
5149
- // Direct literal - validate it fits in the target type
5150
- this._validateLiteralFitsType(exprText, typeName);
5151
- } else {
5152
- // Not a literal - check for narrowing/sign conversions
5153
- const sourceType = this.getExpressionType(ctx.expression()!);
5154
- this._validateTypeConversion(typeName, sourceType);
5155
- }
5156
- } catch (validationError) {
5157
- const msg =
5158
- validationError instanceof Error
5159
- ? validationError.message
5160
- : String(validationError);
5161
- throw new Error(`${line}:${col} ${msg}`, { cause: validationError });
5162
- }
5163
- }
5164
-
5165
- /**
5166
- * Issue #696: Handle pending C++ class field assignments.
5167
- */
5168
- private _finalizeCppClassAssignments(
5169
- _ctx: Parser.VariableDeclarationContext,
5170
- typeCtx: Parser.TypeContext,
5171
- name: string,
5172
- decl: string,
5173
- ): string {
5174
- if (CodeGenState.pendingCppClassAssignments.length === 0) {
5175
- return `${decl};`;
5176
- }
5177
-
5178
- if (CodeGenState.inFunctionBody) {
5179
- const assignments = CodeGenState.pendingCppClassAssignments
5180
- .map((a) => `${name}.${a}`)
5181
- .join("\n");
5182
- CodeGenState.pendingCppClassAssignments = [];
5183
- return `${decl};\n${assignments}`;
5184
- }
5185
-
5186
- // At global scope, we can't emit assignment statements.
5187
- CodeGenState.pendingCppClassAssignments = [];
5188
- throw new Error(
5189
- `Error: C++ class '${this.getTypeName(typeCtx)}' with constructor cannot use struct initializer ` +
5190
- `syntax at global scope. Use constructor syntax or initialize fields separately.`,
5191
- );
5192
- }
5193
-
5194
- /**
5195
- * Issue #375: Generate C++ constructor-style declaration
5196
- * Validates that all arguments are const variables.
5197
- * Example: `Adafruit_MAX31856 thermocouple(pinConst);` -> `Adafruit_MAX31856 thermocouple(pinConst);`
5198
- */
5199
- private _generateConstructorDecl(
5200
- ctx: Parser.VariableDeclarationContext,
5201
- argListCtx: Parser.ConstructorArgumentListContext,
5202
- ): string {
5203
- const type = this.generateType(ctx.type());
5204
- const name = ctx.IDENTIFIER().getText();
5205
- const line = ctx.start?.line ?? 0;
5206
-
5207
- // Collect and validate all arguments
5208
- const argIdentifiers = argListCtx.IDENTIFIER();
5209
- const resolvedArgs: string[] = [];
5210
-
5211
- for (const argNode of argIdentifiers) {
5212
- const argName = argNode.getText();
5213
-
5214
- // Check if it exists in type registry
5215
- const typeInfo = CodeGenState.getVariableTypeInfo(argName);
5216
-
5217
- // Also check scoped variables if inside a scope
5218
- let scopedArgName = argName;
5219
- let scopedTypeInfo = typeInfo;
5220
- if (!typeInfo && CodeGenState.currentScope) {
5221
- scopedArgName = `${CodeGenState.currentScope}_${argName}`;
5222
- scopedTypeInfo = CodeGenState.getVariableTypeInfo(scopedArgName);
5223
- }
5224
-
5225
- if (!typeInfo && !scopedTypeInfo) {
5226
- throw new Error(
5227
- `Error at line ${line}: Constructor argument '${argName}' is not declared`,
5228
- );
5229
- }
5230
-
5231
- const finalTypeInfo = typeInfo ?? scopedTypeInfo!;
5232
- const finalArgName = typeInfo ? argName : scopedArgName;
5233
-
5234
- // Check if it's const
5235
- if (!finalTypeInfo.isConst) {
5236
- throw new Error(
5237
- `Error at line ${line}: Constructor argument '${argName}' must be const. ` +
5238
- `C++ constructors in C-Next only accept const variables.`,
5239
- );
5240
- }
5241
-
5242
- resolvedArgs.push(finalArgName);
5243
- }
5244
-
5245
- // Track the variable in type registry (as an external C++ type)
5246
- CodeGenState.setVariableTypeInfo(name, {
5247
- baseType: type,
5248
- bitWidth: 0, // Unknown for C++ types
5249
- isArray: false,
5250
- arrayDimensions: [],
5251
- isConst: false,
5252
- isExternalCppType: true,
5253
- });
5254
-
5255
- // Track as local variable if inside function body
5256
- if (CodeGenState.inFunctionBody) {
5257
- CodeGenState.localVariables.add(name);
5258
- }
5259
-
5260
- return `${type} ${name}(${resolvedArgs.join(", ")});`;
5261
- }
3852
+ // Issue #792: Methods _handleArrayDeclaration, _getArrayTypeDimension, _parseArrayTypeDimension,
3853
+ // _parseFirstArrayDimension, _validateArrayDeclarationSyntax, _extractBaseTypeName,
3854
+ // _generateVariableInitializer, _validateIntegerInitializer, _finalizeCppClassAssignments,
3855
+ // and _generateConstructorDecl have been extracted to VariableDeclHelper.ts
5262
3856
 
5263
3857
  /**
5264
3858
  * Get zero initializer for array types.