c-next 0.2.16 → 0.2.18

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 (118) hide show
  1. package/README.md +18 -2
  2. package/dist/index.js +8897 -6260
  3. package/dist/index.js.map +4 -4
  4. package/grammar/CNext.g4 +12 -0
  5. package/package.json +4 -2
  6. package/src/transpiler/Transpiler.ts +376 -48
  7. package/src/transpiler/__tests__/DualCodePaths.test.ts +1 -1
  8. package/src/transpiler/__tests__/compileCommandsDiscovery.integration.test.ts +94 -0
  9. package/src/transpiler/__tests__/externalSymbolRecovery.integration.test.ts +215 -0
  10. package/src/transpiler/logic/__tests__/detectAssemblySyntax.test.ts +116 -0
  11. package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +65 -10
  12. package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +186 -14
  13. package/src/transpiler/logic/analysis/MixedTypeCategoryAnalyzer.ts +408 -0
  14. package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +16 -97
  15. package/src/transpiler/logic/analysis/ReturnPathAnalyzer.ts +171 -0
  16. package/src/transpiler/logic/analysis/SignedShiftAnalyzer.ts +124 -12
  17. package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +200 -0
  18. package/src/transpiler/logic/analysis/__tests__/InitializationAnalyzer.test.ts +386 -1
  19. package/src/transpiler/logic/analysis/__tests__/MixedTypeCategoryAnalyzer.test.ts +346 -0
  20. package/src/transpiler/logic/analysis/__tests__/ReturnPathAnalyzer.test.ts +232 -0
  21. package/src/transpiler/logic/analysis/__tests__/SignedShiftAnalyzer.test.ts +211 -0
  22. package/src/transpiler/logic/analysis/runAnalyzers.ts +23 -2
  23. package/src/transpiler/logic/analysis/types/IMixedTypeCategoryError.ts +17 -0
  24. package/src/transpiler/logic/analysis/types/IReturnPathError.ts +12 -0
  25. package/src/transpiler/logic/detectAssemblySyntax.ts +80 -0
  26. package/src/transpiler/logic/parser/grammar/CNext.interp +4 -1
  27. package/src/transpiler/logic/parser/grammar/CNext.tokens +169 -167
  28. package/src/transpiler/logic/parser/grammar/CNextLexer.interp +4 -1
  29. package/src/transpiler/logic/parser/grammar/CNextLexer.tokens +169 -167
  30. package/src/transpiler/logic/parser/grammar/CNextLexer.ts +545 -541
  31. package/src/transpiler/logic/parser/grammar/CNextListener.ts +11 -0
  32. package/src/transpiler/logic/parser/grammar/CNextParser.ts +1318 -1178
  33. package/src/transpiler/logic/parser/grammar/CNextVisitor.ts +7 -0
  34. package/src/transpiler/logic/preprocessor/CompileCommandsReader.ts +332 -0
  35. package/src/transpiler/logic/preprocessor/ExternalDeclarationOracle.ts +202 -0
  36. package/src/transpiler/logic/preprocessor/Preprocessor.ts +24 -6
  37. package/src/transpiler/logic/preprocessor/ToolchainDetector.ts +42 -1
  38. package/src/transpiler/logic/preprocessor/__tests__/CompileCommandsReader.test.ts +216 -0
  39. package/src/transpiler/logic/preprocessor/__tests__/ExternalDeclarationOracle.test.ts +153 -0
  40. package/src/transpiler/logic/preprocessor/__tests__/Preprocessor.test.ts +43 -18
  41. package/src/transpiler/logic/preprocessor/__tests__/ToolchainDetector.crossCompiler.test.ts +75 -0
  42. package/src/transpiler/logic/preprocessor/__tests__/fixtures/oracle/dependent.h +7 -0
  43. package/src/transpiler/logic/preprocessor/__tests__/fixtures/oracle/predecessor.h +5 -0
  44. package/src/transpiler/logic/preprocessor/types/ICompileCommandsResult.ts +14 -0
  45. package/src/transpiler/logic/preprocessor/types/IPreprocessOptions.ts +17 -0
  46. package/src/transpiler/logic/symbols/SymbolTable.ts +62 -2
  47. package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +55 -4
  48. package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +15 -2
  49. package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +64 -50
  50. package/src/transpiler/output/MisraSuppressionUtils.ts +52 -0
  51. package/src/transpiler/output/__tests__/MisraSuppressionUtils.test.ts +67 -0
  52. package/src/transpiler/output/codegen/CodeGenerator.ts +196 -98
  53. package/src/transpiler/output/codegen/TypeResolver.ts +148 -0
  54. package/src/transpiler/output/codegen/TypeValidator.ts +179 -81
  55. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +165 -17
  56. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +163 -35
  57. package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +2 -2
  58. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +93 -0
  59. package/src/transpiler/output/codegen/__tests__/TypeValidator.alwaysTrueLoop.test.ts +91 -0
  60. package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +97 -14
  61. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +13 -0
  62. package/src/transpiler/output/codegen/assignment/AssignmentKind.ts +1 -1
  63. package/src/transpiler/output/codegen/assignment/handlers/AccessPatternHandlers.ts +20 -12
  64. package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +424 -22
  65. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +31 -18
  66. package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +7 -8
  67. package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +6 -8
  68. package/src/transpiler/output/codegen/assignment/handlers/RegisterUtils.ts +12 -10
  69. package/src/transpiler/output/codegen/assignment/handlers/SimpleHandler.ts +3 -7
  70. package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +7 -9
  71. package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +12 -10
  72. package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +479 -11
  73. package/src/transpiler/output/codegen/generators/IOrchestrator.ts +3 -0
  74. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +26 -7
  75. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +86 -0
  76. package/src/transpiler/output/codegen/generators/expressions/BinaryExprGenerator.ts +43 -24
  77. package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +76 -58
  78. package/src/transpiler/output/codegen/generators/expressions/ExpressionGenerator.ts +9 -2
  79. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +26 -13
  80. package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +44 -0
  81. package/src/transpiler/output/codegen/generators/expressions/__tests__/ExpressionGenerator.test.ts +82 -1
  82. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +129 -1
  83. package/src/transpiler/output/codegen/generators/statements/ControlFlowGenerator.ts +64 -8
  84. package/src/transpiler/output/codegen/generators/statements/__tests__/ControlFlowGenerator.test.ts +8 -5
  85. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +30 -2
  86. package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +17 -3
  87. package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +17 -4
  88. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +240 -42
  89. package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +0 -21
  90. package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +60 -39
  91. package/src/transpiler/output/codegen/helpers/TypeRegistrationEngine.ts +170 -36
  92. package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +37 -39
  93. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +19 -0
  94. package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +117 -0
  95. package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +94 -2
  96. package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +322 -9
  97. package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +0 -64
  98. package/src/transpiler/output/codegen/helpers/__tests__/TypeRegistrationEngine.test.ts +101 -0
  99. package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclHelper.test.ts +29 -5
  100. package/src/transpiler/output/codegen/subscript/SubscriptClassifier.ts +30 -11
  101. package/src/transpiler/output/codegen/subscript/TSubscriptKind.ts +1 -1
  102. package/src/transpiler/output/codegen/subscript/__tests__/SubscriptClassifier.test.ts +38 -6
  103. package/src/transpiler/output/codegen/types/ICallbackTypeInfo.ts +2 -1
  104. package/src/transpiler/output/codegen/types/IParameterInput.ts +7 -0
  105. package/src/transpiler/output/headers/BaseHeaderGenerator.ts +8 -0
  106. package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +140 -24
  107. package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +280 -0
  108. package/src/transpiler/output/headers/generators/IHeaderTypeInput.ts +13 -0
  109. package/src/transpiler/output/headers/generators/generateStructHeader.ts +48 -28
  110. package/src/transpiler/state/CodeGenState.ts +91 -22
  111. package/src/transpiler/state/__tests__/CodeGenState.test.ts +253 -11
  112. package/src/transpiler/types/ICachedFileEntry.ts +7 -0
  113. package/src/utils/LiteralUtils.ts +23 -0
  114. package/src/utils/__tests__/LiteralUtils.test.ts +101 -0
  115. package/src/utils/cache/CacheManager.ts +13 -2
  116. package/src/utils/cache/__tests__/CacheManager.test.ts +18 -1
  117. package/src/utils/constants/TypeConstants.ts +13 -0
  118. package/src/utils/types/IParameterSymbol.ts +1 -0
@@ -148,6 +148,7 @@ import EnumTypeResolver from "./resolution/EnumTypeResolver";
148
148
  import ScopeResolver from "./resolution/ScopeResolver";
149
149
  // Issue #797: Centralized C-style name generation
150
150
  import QualifiedNameGenerator from "./utils/QualifiedNameGenerator";
151
+ import MisraSuppressionUtils from "../MisraSuppressionUtils";
151
152
 
152
153
  const {
153
154
  generateOverflowHelpers: helperGenerateOverflowHelpers,
@@ -299,6 +300,10 @@ export default class CodeGenerator implements IOrchestrator {
299
300
  controlFlowGenerators.generateDoWhile,
300
301
  );
301
302
  this.registry.registerStatement("for", controlFlowGenerators.generateFor);
303
+ this.registry.registerStatement(
304
+ "forever",
305
+ controlFlowGenerators.generateForever,
306
+ );
302
307
  this.registry.registerStatement("switch", switchGenerators.generateSwitch);
303
308
  this.registry.registerStatement("critical", generateCriticalStatement);
304
309
 
@@ -726,6 +731,7 @@ export default class CodeGenerator implements IOrchestrator {
726
731
  * Part of IOrchestrator interface.
727
732
  * ADR-045: Used to detect string comparisons and generate strcmp().
728
733
  * Issue #137: Extended to handle array element access (e.g., names[0])
734
+ * Issue #1030: Extended to handle struct member access (e.g., person.name)
729
735
  */
730
736
  isStringExpression(ctx: Parser.RelationalExpressionContext): boolean {
731
737
  const text = ctx.getText();
@@ -743,6 +749,11 @@ export default class CodeGenerator implements IOrchestrator {
743
749
  }
744
750
  }
745
751
 
752
+ // Issue #1030: Check for struct member access (e.g., person.name)
753
+ if (this._isStructMemberStringExpression(text)) {
754
+ return true;
755
+ }
756
+
746
757
  // Issue #137: Check for array element access (e.g., names[0], arr[i])
747
758
  return this._isArrayAccessStringExpression(text);
748
759
  }
@@ -800,6 +811,59 @@ export default class CodeGenerator implements IOrchestrator {
800
811
  );
801
812
  }
802
813
 
814
+ /**
815
+ * Check if struct member access expression evaluates to a string.
816
+ * Issue #1030: Handles patterns like person.name, config.key
817
+ */
818
+ private _isStructMemberStringExpression(text: string): boolean {
819
+ // Pattern: identifier.identifier (simple member access)
820
+ // Must not end with a property that returns a number
821
+ if (
822
+ text.endsWith(".char_count") ||
823
+ text.endsWith(".capacity") ||
824
+ text.endsWith(".size") ||
825
+ text.endsWith(".length") ||
826
+ text.endsWith(".bit_length") ||
827
+ text.endsWith(".byte_length") ||
828
+ text.endsWith(".element_count")
829
+ ) {
830
+ return false;
831
+ }
832
+
833
+ // Match simple struct.member pattern
834
+ const memberMatch = /^([a-zA-Z_]\w*)\.([a-zA-Z_]\w*)$/.exec(text);
835
+ if (!memberMatch) {
836
+ return false;
837
+ }
838
+
839
+ const [, varName, fieldName] = memberMatch;
840
+
841
+ // Get the struct variable's type
842
+ const typeInfo = CodeGenState.getVariableTypeInfo(varName);
843
+ if (!typeInfo) {
844
+ return false;
845
+ }
846
+
847
+ // Get the struct type name - it might be directly the baseType
848
+ // or we might need to look it up by the variable's type
849
+ const structTypeName = typeInfo.baseType;
850
+ if (!structTypeName) {
851
+ return false;
852
+ }
853
+
854
+ // Look up the field type from the struct
855
+ const fieldType = CodeGenState.getStructFieldType(
856
+ structTypeName,
857
+ fieldName,
858
+ );
859
+ if (!fieldType) {
860
+ return false;
861
+ }
862
+
863
+ // Check if the field is a string type (e.g., "string<64>")
864
+ return fieldType.startsWith("string");
865
+ }
866
+
803
867
  /**
804
868
  * Get type of additive expression.
805
869
  * Part of IOrchestrator interface - delegates to private implementation.
@@ -998,6 +1062,8 @@ export default class CodeGenerator implements IOrchestrator {
998
1062
  result = this.generateDoWhile(ctx.doWhileStatement()!);
999
1063
  } else if (ctx.forStatement()) {
1000
1064
  result = this.generateFor(ctx.forStatement()!);
1065
+ } else if (ctx.foreverStatement()) {
1066
+ result = this.generateForever(ctx.foreverStatement()!);
1001
1067
  } else if (ctx.switchStatement()) {
1002
1068
  result = this.generateSwitch(ctx.switchStatement()!);
1003
1069
  } else if (ctx.returnStatement()) {
@@ -1063,6 +1129,14 @@ export default class CodeGenerator implements IOrchestrator {
1063
1129
  TypeValidator.validateConditionIsBoolean(ctx, conditionType);
1064
1130
  }
1065
1131
 
1132
+ /**
1133
+ * ADR-113 / #1075: reject an always-true literal loop condition (E0707).
1134
+ * Part of IOrchestrator interface.
1135
+ */
1136
+ validateLoopConditionNotAlwaysTrue(ctx: Parser.ExpressionContext): void {
1137
+ TypeValidator.validateLoopConditionNotAlwaysTrue(ctx);
1138
+ }
1139
+
1066
1140
  /**
1067
1141
  * Issue #254: Validate no function calls in condition (E0702).
1068
1142
  * Part of IOrchestrator interface (ADR-053 A3).
@@ -1105,8 +1179,6 @@ export default class CodeGenerator implements IOrchestrator {
1105
1179
 
1106
1180
  // Issue #779: Resolve bare scope member identifiers before postfix chain processing
1107
1181
  // This ensures scope members get their prefix even with array/member access.
1108
- // Skip parameters - they don't need scope resolution and shouldn't be dereferenced
1109
- // when used with array indexing (buf[idx] is valid C for pointer params).
1110
1182
  // Also skip known registers - they should be handled by the postfix chain builder
1111
1183
  // to enable proper register validation (requiring global. when shadowed).
1112
1184
  let resolvedIdentifier = identifier ?? "";
@@ -1115,7 +1187,24 @@ export default class CodeGenerator implements IOrchestrator {
1115
1187
  const isLocalVariable = CodeGenState.localVariables.has(identifier);
1116
1188
  const isKnownRegister =
1117
1189
  CodeGenState.symbols?.knownRegisters.has(identifier);
1118
- if (!isParameter && !isLocalVariable && !isKnownRegister) {
1190
+ // Issue #1100: Parameters with postfix ops (array/bit subscript, member
1191
+ // access) must resolve through the same dereference logic as a bare
1192
+ // parameter reference (ParameterDereferenceResolver), not skip it.
1193
+ // For array/struct/string/etc. parameters this is a no-op (they're
1194
+ // already pointer-like, matching the prior behavior verbatim — e.g.
1195
+ // `buf[idx]` stays `buf[idx]`). For a scalar parameter that became a
1196
+ // pointer because it's modified elsewhere in the function, a bit
1197
+ // access (`v[4] <- true`) now correctly dereferences to `(*v)[4]`
1198
+ // (which AssignmentContextBuilder reduces to base identifier `(*v)`)
1199
+ // instead of assigning through the raw pointer.
1200
+ if (isParameter) {
1201
+ const paramInfo = CodeGenState.currentParameters.get(identifier)!;
1202
+ resolvedIdentifier = ParameterDereferenceResolver.resolve(
1203
+ identifier,
1204
+ paramInfo,
1205
+ this._buildParameterDereferenceDeps(),
1206
+ );
1207
+ } else if (!isLocalVariable && !isKnownRegister) {
1119
1208
  const resolved = TypeValidator.resolveBareIdentifier(
1120
1209
  identifier,
1121
1210
  false, // not local
@@ -1311,9 +1400,10 @@ export default class CodeGenerator implements IOrchestrator {
1311
1400
  * ADR-017: Handle enum types by initializing to first member
1312
1401
  */
1313
1402
  getZeroInitializer(typeCtx: Parser.TypeContext, isArray: boolean): string {
1314
- // Issue #379: Arrays need element type checking for C++ classes
1403
+ // Issue #379 / #1004: arrays zero-init with the aggregate brace ({} in
1404
+ // C++, {0} in C) regardless of element type.
1315
1405
  if (isArray) {
1316
- return this._getArrayZeroInitializer(typeCtx);
1406
+ return this._getAggregateZeroInitBrace();
1317
1407
  }
1318
1408
 
1319
1409
  // Handle named types (scoped, global, qualified, user)
@@ -1323,11 +1413,10 @@ export default class CodeGenerator implements IOrchestrator {
1323
1413
  if (CodeGenState.symbols!.knownEnums.has(resolved.name)) {
1324
1414
  return this._getEnumZeroValue(resolved.name, resolved.separator);
1325
1415
  }
1326
- // Check if C++ type needing {} (only for userType, not qualified/scoped/global)
1327
- if (resolved.checkCppType && this._needsEmptyBraceInit(resolved.name)) {
1328
- return "{}";
1329
- }
1330
- return "{0}";
1416
+ // Issue #1004: struct/class zero-init. C++ value-initialization ({})
1417
+ // works for every aggregate (including ones whose first field is an
1418
+ // enum, where {0} is an invalid int->enum narrowing); C uses {0}.
1419
+ return this._getAggregateZeroInitBrace();
1331
1420
  }
1332
1421
 
1333
1422
  // Issue #295: C++ template types use value initialization {}
@@ -1335,6 +1424,11 @@ export default class CodeGenerator implements IOrchestrator {
1335
1424
  return "{}";
1336
1425
  }
1337
1426
 
1427
+ // Issue #1019: string<N> types use empty string initializer
1428
+ if (typeCtx.stringType()) {
1429
+ return '""';
1430
+ }
1431
+
1338
1432
  // Primitive types use lookup map
1339
1433
  if (typeCtx.primitiveType()) {
1340
1434
  const primType = typeCtx.primitiveType()!.getText();
@@ -1490,9 +1584,9 @@ export default class CodeGenerator implements IOrchestrator {
1490
1584
  if (p.isArray) {
1491
1585
  // Array parameters: type name[]
1492
1586
  return `${constMod}${p.type} ${p.name}${p.arrayDims}`;
1493
- } else if (p.isPointer) {
1494
- // ADR-006: Non-array, non-callback parameters become pointers
1495
- // In C++ mode, use reference (&) instead of pointer (*)
1587
+ } else if (p.isStruct) {
1588
+ // ADR-006: Struct parameters become pointers (C) or references (C++)
1589
+ // Only struct types get pointer/reference semantics, not primitives
1496
1590
  const ptrOrRef = this.isCppMode() ? "&" : "*";
1497
1591
  return `${constMod}${p.type}${ptrOrRef}`;
1498
1592
  } else {
@@ -1776,7 +1870,17 @@ export default class CodeGenerator implements IOrchestrator {
1776
1870
  }
1777
1871
 
1778
1872
  if (ctx.IDENTIFIER()) {
1779
- return this._resolveIdentifierExpression(ctx.IDENTIFIER()!.getText());
1873
+ const id = ctx.IDENTIFIER()!.getText();
1874
+ // Issue #1011: break/continue are not part of C-Next - use structured conditions
1875
+ // ADR-026 (Status: Rejected) explicitly excludes break/continue from the language
1876
+ if (id === "break" || id === "continue") {
1877
+ const line = ctx.start?.line ?? 0;
1878
+ const col = ctx.start?.column ?? 0;
1879
+ throw new Error(
1880
+ `${line}:${col} error[E0703]: '${id}' is not supported in C-Next - use structured conditions instead`,
1881
+ );
1882
+ }
1883
+ return this._resolveIdentifierExpression(id);
1780
1884
  }
1781
1885
  if (ctx.literal()) {
1782
1886
  return this._generateLiteralExpression(ctx.literal()!);
@@ -2085,15 +2189,6 @@ export default class CodeGenerator implements IOrchestrator {
2085
2189
  return identifiers.join("_");
2086
2190
  }
2087
2191
 
2088
- /**
2089
- * Issue #304: Check if a type name is from a C++ header
2090
- * Used to determine whether to use {} or {0} for initialization.
2091
- * C++ types with constructors may fail with {0} but work with {}.
2092
- */
2093
- private isCppType(typeName: string): boolean {
2094
- return SymbolLookupHelper.isCppType(CodeGenState.symbolTable, typeName);
2095
- }
2096
-
2097
2192
  /**
2098
2193
  * Generate C code from a C-Next program
2099
2194
  * @param tree The parsed C-Next program
@@ -2297,7 +2392,14 @@ export default class CodeGenerator implements IOrchestrator {
2297
2392
  includePaths,
2298
2393
  );
2299
2394
 
2300
- output.push(this.transformIncludeDirective(includeDir.getText()));
2395
+ // Issue #850: Add MISRA suppression for banned headers
2396
+ const includeText = includeDir.getText();
2397
+ const suppression =
2398
+ MisraSuppressionUtils.getMisraSuppressionComment(includeText);
2399
+ if (suppression) {
2400
+ output.push(suppression);
2401
+ }
2402
+ output.push(this.transformIncludeDirective(includeText));
2301
2403
  }
2302
2404
 
2303
2405
  if (tree.includeDirective().length > 0) {
@@ -2689,6 +2791,7 @@ export default class CodeGenerator implements IOrchestrator {
2689
2791
  type: string;
2690
2792
  isConst: boolean;
2691
2793
  isPointer: boolean;
2794
+ isStruct: boolean;
2692
2795
  isArray: boolean;
2693
2796
  arrayDims: string;
2694
2797
  }> = [];
@@ -2704,6 +2807,8 @@ export default class CodeGenerator implements IOrchestrator {
2704
2807
 
2705
2808
  // ADR-029: Check if parameter type is itself a callback type
2706
2809
  const isCallbackParam = CodeGenState.callbackTypes.has(typeName);
2810
+ // ADR-006: Check if parameter type is a struct (for pointer/reference semantics)
2811
+ const isStruct = this.isStructType(typeName);
2707
2812
 
2708
2813
  let paramType: string;
2709
2814
  let isPointer: boolean;
@@ -2715,8 +2820,8 @@ export default class CodeGenerator implements IOrchestrator {
2715
2820
  isPointer = false; // Function pointers are already pointers
2716
2821
  } else {
2717
2822
  paramType = this.generateType(param.type());
2718
- // ADR-006: Non-array parameters become pointers
2719
- isPointer = !isArray;
2823
+ // ADR-006: Non-array struct parameters become pointers in C mode
2824
+ isPointer = !isArray && isStruct;
2720
2825
  }
2721
2826
 
2722
2827
  let arrayDims: string;
@@ -2739,6 +2844,7 @@ export default class CodeGenerator implements IOrchestrator {
2739
2844
  type: paramType,
2740
2845
  isConst,
2741
2846
  isPointer,
2847
+ isStruct,
2742
2848
  isArray,
2743
2849
  arrayDims,
2744
2850
  });
@@ -3211,7 +3317,7 @@ export default class CodeGenerator implements IOrchestrator {
3211
3317
  decl += this._getStringCapacityDimension(varDecl.type());
3212
3318
 
3213
3319
  if (varDecl.expression()) {
3214
- decl += ` = ${this.generateExpression(varDecl.expression()!)}`;
3320
+ decl += ` = ${CodeGenState.withDeclarationInit(() => this.generateExpression(varDecl.expression()!))}`;
3215
3321
  } else {
3216
3322
  // ADR-015: Zero initialization for uninitialized scope variables
3217
3323
  decl += ` = ${this.getZeroInitializer(varDecl.type(), isArray)}`;
@@ -3495,8 +3601,9 @@ export default class CodeGenerator implements IOrchestrator {
3495
3601
  );
3496
3602
 
3497
3603
  if (!fieldList) {
3498
- // Empty initializer: Point {} -> (Point){ 0 } or {} for C++ classes
3499
- return isCppClass ? "{}" : `(${castType}){ 0 }`;
3604
+ // Empty initializer: Point {} -> { 0 } in declaration context, (Point){ 0 } elsewhere
3605
+ if (isCppClass) return "{}";
3606
+ return CodeGenState.inDeclarationInit ? "{ 0 }" : `(${castType}){ 0 }`;
3500
3607
  }
3501
3608
 
3502
3609
  // Get field type info for nested initializers
@@ -3507,28 +3614,10 @@ export default class CodeGenerator implements IOrchestrator {
3507
3614
 
3508
3615
  const fields = fieldList.fieldInitializer().map((field) => {
3509
3616
  const fieldName = field.IDENTIFIER().getText();
3510
-
3511
- // Compute expected type for nested initializers
3512
- let fieldType: string | undefined;
3513
- if (structFieldTypes?.has(fieldName)) {
3514
- // Issue #502: Convert underscore format to correct output format
3515
- // C-Next struct fields may store C++ types with _ separator (e.g., SeaDash_Parse_ParseResult)
3516
- // but code generation needs :: for C++ types (e.g., SeaDash::Parse::ParseResult)
3517
- fieldType = structFieldTypes.get(fieldName)!;
3518
- if (fieldType.includes("_")) {
3519
- // Check if this looks like a qualified type (contains _) and convert
3520
- const parts = fieldType.split("_");
3521
- if (parts.length > 1 && this.isCppScopeSymbol(parts[0])) {
3522
- // It's a C++ namespaced type - convert _ to ::
3523
- fieldType = parts.join("::");
3524
- }
3525
- }
3526
- }
3527
-
3617
+ const fieldType = this._resolveFieldType(fieldName, structFieldTypes);
3528
3618
  const value = CodeGenState.withExpectedType(fieldType, () =>
3529
3619
  this.generateExpression(field.expression()),
3530
3620
  );
3531
-
3532
3621
  return { fieldName, value };
3533
3622
  });
3534
3623
 
@@ -3545,6 +3634,23 @@ export default class CodeGenerator implements IOrchestrator {
3545
3634
  // For C-Next/C structs, generate designated initializer
3546
3635
  const fieldInits = fields.map((f) => `.${f.fieldName} = ${f.value}`);
3547
3636
 
3637
+ return this.formatStructInitializer(typeName, castType, fieldInits);
3638
+ }
3639
+
3640
+ private formatStructInitializer(
3641
+ typeName: string,
3642
+ castType: string,
3643
+ fieldInits: string[],
3644
+ ): string {
3645
+ const initializer: string = `{ ${fieldInits.join(", ")} }`;
3646
+
3647
+ // In a declaration initializer context, use plain designated initializer — no type cast
3648
+ // prefix needed, and compound literals are not C99 constant expressions so they fail
3649
+ // at file scope on GCC < 13.
3650
+ if (CodeGenState.inDeclarationInit) {
3651
+ return initializer;
3652
+ }
3653
+
3548
3654
  // Issue #882: In C++ mode, anonymous structs/unions must use plain brace init.
3549
3655
  // Compound literals like (struct { ... }){ ... } create incompatible types in C++
3550
3656
  // because each struct { ... } definition creates a distinct nominal type.
@@ -3552,10 +3658,33 @@ export default class CodeGenerator implements IOrchestrator {
3552
3658
  CodeGenState.cppMode &&
3553
3659
  (typeName.startsWith("struct {") || typeName.startsWith("union {"))
3554
3660
  ) {
3555
- return `{ ${fieldInits.join(", ")} }`;
3661
+ return initializer;
3662
+ }
3663
+
3664
+ if (!CodeGenState.inFunctionBody) {
3665
+ return initializer;
3556
3666
  }
3557
3667
 
3558
- return `(${castType}){ ${fieldInits.join(", ")} }`;
3668
+ return `(${castType})${initializer}`;
3669
+ }
3670
+
3671
+ /**
3672
+ * Resolve the C type string for a named struct field, converting C++ underscore-separated
3673
+ * names to :: notation. Returns undefined if the field is not in the type map.
3674
+ * Issue #502: C-Next stores C++ types with _ separator; codegen needs ::.
3675
+ */
3676
+ private _resolveFieldType(
3677
+ fieldName: string,
3678
+ structFieldTypes: Map<string, string> | undefined,
3679
+ ): string | undefined {
3680
+ if (!structFieldTypes?.has(fieldName)) return undefined;
3681
+ const fieldType = structFieldTypes.get(fieldName)!;
3682
+ if (!fieldType.includes("_")) return fieldType;
3683
+ const parts = fieldType.split("_");
3684
+ if (parts.length > 1 && this.isCppScopeSymbol(parts[0])) {
3685
+ return parts.join("::");
3686
+ }
3687
+ return fieldType;
3559
3688
  }
3560
3689
 
3561
3690
  /**
@@ -3776,6 +3905,8 @@ export default class CodeGenerator implements IOrchestrator {
3776
3905
  forceConst,
3777
3906
  isTypedefStructType: (t) =>
3778
3907
  CodeGenState.symbolTable?.isTypedefStructType(t) ?? false,
3908
+ // Issue #995: Opaque handles should not get auto-const
3909
+ isOpaqueType: (t) => CodeGenState.isOpaqueType(t),
3779
3910
  });
3780
3911
 
3781
3912
  // Use shared builder with C/C++ mode
@@ -4102,31 +4233,13 @@ export default class CodeGenerator implements IOrchestrator {
4102
4233
  // and _generateConstructorDecl have been extracted to VariableDeclHelper.ts
4103
4234
 
4104
4235
  /**
4105
- * Get zero initializer for array types.
4106
- * Issue #379: C++ class arrays must use {} instead of {0}
4236
+ * Brace initializer that zero-initializes an aggregate (struct or array).
4237
+ * Issue #379 / #1004: C++ uses value-initialization ({}), which is valid for
4238
+ * any aggregate element type (POD, struct, class) including enum-first
4239
+ * structs where {0} is an invalid int->enum narrowing; C uses {0}.
4107
4240
  */
4108
- private _getArrayZeroInitializer(typeCtx: Parser.TypeContext): string {
4109
- // Check if element type is a C++ class or template type
4110
- if (typeCtx.userType()) {
4111
- const typeName = typeCtx.userType()!.getText();
4112
- if (this._needsEmptyBraceInit(typeName)) {
4113
- return "{}";
4114
- }
4115
- }
4116
- // Also check C-Next style array type (e.g., CppClass[4]) where
4117
- // the userType is nested inside arrayType.
4118
- if (typeCtx.arrayType()?.userType()) {
4119
- const typeName = typeCtx.arrayType()!.userType()!.getText();
4120
- if (this._needsEmptyBraceInit(typeName)) {
4121
- return "{}";
4122
- }
4123
- }
4124
- // Template types are always C++ classes
4125
- if (typeCtx.templateType()) {
4126
- return "{}";
4127
- }
4128
- // Default: POD arrays use {0}
4129
- return "{0}";
4241
+ private _getAggregateZeroInitBrace(): string {
4242
+ return CodeGenState.cppMode ? "{}" : "{0}";
4130
4243
  }
4131
4244
 
4132
4245
  /**
@@ -4158,20 +4271,19 @@ export default class CodeGenerator implements IOrchestrator {
4158
4271
 
4159
4272
  /**
4160
4273
  * Resolve full type name from any TypeContext variant.
4161
- * Returns { name, separator, checkCppType } or null if not a named type.
4274
+ * Returns { name, separator } or null if not a named type.
4162
4275
  * ADR-016: Handles scoped, global, qualified, and user types
4163
- * checkCppType: only true for userType (original behavior preserved)
4164
4276
  */
4165
4277
  private _resolveTypeNameFromContext(
4166
4278
  typeCtx: Parser.TypeContext,
4167
- ): { name: string; separator: string; checkCppType: boolean } | null {
4279
+ ): { name: string; separator: string } | null {
4168
4280
  // ADR-016: Check for scoped types (this.Type)
4169
4281
  if (typeCtx.scopedType()) {
4170
4282
  const localName = typeCtx.scopedType()!.IDENTIFIER().getText();
4171
4283
  const name = CodeGenState.currentScope
4172
4284
  ? `${CodeGenState.currentScope}_${localName}`
4173
4285
  : localName;
4174
- return { name, separator: "_", checkCppType: false };
4286
+ return { name, separator: "_" };
4175
4287
  }
4176
4288
 
4177
4289
  // Issue #478: Check for global types (global.Type)
@@ -4179,7 +4291,6 @@ export default class CodeGenerator implements IOrchestrator {
4179
4291
  return {
4180
4292
  name: typeCtx.globalType()!.IDENTIFIER().getText(),
4181
4293
  separator: "_",
4182
- checkCppType: false,
4183
4294
  };
4184
4295
  }
4185
4296
 
@@ -4189,7 +4300,7 @@ export default class CodeGenerator implements IOrchestrator {
4189
4300
  const parts = typeCtx.qualifiedType()!.IDENTIFIER();
4190
4301
  const name = this.resolveQualifiedType(parts.map((id) => id.getText()));
4191
4302
  const separator = name.includes("::") ? "::" : "_";
4192
- return { name, separator, checkCppType: false };
4303
+ return { name, separator };
4193
4304
  }
4194
4305
 
4195
4306
  // Check for user-defined types (structs/classes/enums)
@@ -4197,28 +4308,12 @@ export default class CodeGenerator implements IOrchestrator {
4197
4308
  return {
4198
4309
  name: typeCtx.userType()!.getText(),
4199
4310
  separator: "_",
4200
- checkCppType: true,
4201
4311
  };
4202
4312
  }
4203
4313
 
4204
4314
  return null;
4205
4315
  }
4206
4316
 
4207
- /**
4208
- * Check if a type needs empty brace initialization {}.
4209
- * Issue #304: C++ types with constructors may fail with {0}
4210
- * Issue #309: Unknown user types in C++ mode may have non-trivial constructors
4211
- */
4212
- private _needsEmptyBraceInit(typeName: string): boolean {
4213
- // C++ types (external libraries with constructors)
4214
- if (this.isCppType(typeName)) {
4215
- return true;
4216
- }
4217
- // In C++ mode, unknown user types may have non-trivial constructors
4218
- // Known structs (C-Next or C headers) are POD types where {0} works
4219
- return CodeGenState.cppMode && !this.isKnownStruct(typeName);
4220
- }
4221
-
4222
4317
  /**
4223
4318
  * Generate a safe bit mask expression.
4224
4319
  * Avoids undefined behavior when width >= 32 for 32-bit integers.
@@ -4461,6 +4556,10 @@ export default class CodeGenerator implements IOrchestrator {
4461
4556
  return this.invokeStatement("for", ctx);
4462
4557
  }
4463
4558
 
4559
+ private generateForever(ctx: Parser.ForeverStatementContext): string {
4560
+ return this.invokeStatement("forever", ctx);
4561
+ }
4562
+
4464
4563
  private generateReturn(ctx: Parser.ReturnStatementContext): string {
4465
4564
  return this.invokeStatement("return", ctx);
4466
4565
  }
@@ -4750,8 +4849,7 @@ export default class CodeGenerator implements IOrchestrator {
4750
4849
  // MISRA 10.3: Cast limit macros to target type (they have type 'int')
4751
4850
  const finalCast = CppModeHelper.cast(targetType, `(${expr})`);
4752
4851
  const castMax = CppModeHelper.cast(targetType, maxValue);
4753
- const castMin =
4754
- minValue === "0" ? "0" : CppModeHelper.cast(targetType, minValue);
4852
+ const castMin = CppModeHelper.cast(targetType, minValue);
4755
4853
  return `((${expr}) > ${maxComparison} ? ${castMax} : (${expr}) < ${minComparison} ? ${castMin} : ${finalCast})`;
4756
4854
  }
4757
4855