c-next 0.2.8 → 0.2.10

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 (71) hide show
  1. package/dist/index.js +1019 -267
  2. package/dist/index.js.map +4 -4
  3. package/package.json +1 -1
  4. package/src/transpiler/Transpiler.ts +101 -8
  5. package/src/transpiler/__tests__/Transpiler.coverage.test.ts +170 -0
  6. package/src/transpiler/__tests__/needsConditionalPreprocessing.test.ts +246 -0
  7. package/src/transpiler/logic/IncludeExtractor.ts +12 -6
  8. package/src/transpiler/logic/__tests__/IncludeExtractor.test.ts +24 -0
  9. package/src/transpiler/logic/analysis/ArrayIndexTypeAnalyzer.ts +12 -1
  10. package/src/transpiler/logic/analysis/__tests__/ArrayIndexTypeAnalyzer.test.ts +172 -0
  11. package/src/transpiler/logic/symbols/SymbolTable.ts +84 -0
  12. package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +43 -0
  13. package/src/transpiler/logic/symbols/__tests__/TransitiveEnumCollector.test.ts +1 -0
  14. package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +98 -1
  15. package/src/transpiler/logic/symbols/c/collectors/FunctionCollector.ts +23 -5
  16. package/src/transpiler/logic/symbols/c/collectors/StructCollector.ts +69 -2
  17. package/src/transpiler/logic/symbols/c/index.ts +85 -30
  18. package/src/transpiler/logic/symbols/c/utils/DeclaratorUtils.ts +18 -0
  19. package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolInfoAdapter.test.ts +90 -0
  20. package/src/transpiler/logic/symbols/cnext/adapters/TSymbolInfoAdapter.ts +40 -39
  21. package/src/transpiler/output/codegen/CodeGenerator.ts +55 -25
  22. package/src/transpiler/output/codegen/TypeResolver.ts +14 -0
  23. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +3 -3
  24. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +35 -30
  25. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +7 -7
  26. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +1 -0
  27. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +27 -4
  28. package/src/transpiler/output/codegen/assignment/AssignmentKind.ts +6 -0
  29. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +73 -0
  30. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +4 -0
  31. package/src/transpiler/output/codegen/assignment/handlers/SimpleHandler.ts +92 -0
  32. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +5 -2
  33. package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +1 -0
  34. package/src/transpiler/output/codegen/generators/IOrchestrator.ts +14 -0
  35. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +25 -3
  36. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +49 -0
  37. package/src/transpiler/output/codegen/generators/expressions/AccessExprGenerator.ts +17 -5
  38. package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +26 -6
  39. package/src/transpiler/output/codegen/generators/expressions/LiteralGenerator.ts +31 -2
  40. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +72 -13
  41. package/src/transpiler/output/codegen/generators/expressions/UnaryExprGenerator.ts +25 -1
  42. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +2 -1
  43. package/src/transpiler/output/codegen/generators/statements/AtomicGenerator.ts +2 -17
  44. package/src/transpiler/output/codegen/generators/support/IncludeGenerator.ts +19 -7
  45. package/src/transpiler/output/codegen/generators/support/__tests__/IncludeGenerator.test.ts +68 -0
  46. package/src/transpiler/output/codegen/helpers/ArgumentGenerator.ts +14 -2
  47. package/src/transpiler/output/codegen/helpers/ArrayAccessHelper.ts +3 -0
  48. package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +3 -5
  49. package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +56 -8
  50. package/src/transpiler/output/codegen/helpers/BitRangeHelper.ts +19 -3
  51. package/src/transpiler/output/codegen/helpers/NarrowingCastHelper.ts +191 -0
  52. package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +35 -5
  53. package/src/transpiler/output/codegen/helpers/__tests__/ArrayAccessHelper.test.ts +131 -1
  54. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +61 -2
  55. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +1 -0
  56. package/src/transpiler/output/codegen/helpers/__tests__/BitRangeHelper.test.ts +53 -2
  57. package/src/transpiler/output/codegen/helpers/__tests__/FunctionContextManager.test.ts +1 -0
  58. package/src/transpiler/output/codegen/helpers/__tests__/NarrowingCastHelper.test.ts +159 -0
  59. package/src/transpiler/output/codegen/helpers/__tests__/TypeRegistrationEngine.test.ts +1 -0
  60. package/src/transpiler/output/codegen/types/COMPOUND_TO_BINARY.ts +21 -0
  61. package/src/transpiler/output/codegen/types/IArrayAccessInfo.ts +2 -0
  62. package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +14 -16
  63. package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +25 -0
  64. package/src/transpiler/state/CodeGenState.ts +89 -0
  65. package/src/transpiler/state/__tests__/CodeGenState.test.ts +53 -0
  66. package/src/transpiler/state/__tests__/TranspilerState.test.ts +1 -0
  67. package/src/transpiler/types/ICachedFileEntry.ts +2 -0
  68. package/src/transpiler/types/ICodeGenSymbols.ts +8 -0
  69. package/src/utils/BitUtils.ts +33 -4
  70. package/src/utils/cache/CacheManager.ts +9 -1
  71. package/src/utils/cache/__tests__/CacheManager.test.ts +1 -1
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import { hideBin } from "yargs/helpers";
10
10
  // package.json
11
11
  var package_default = {
12
12
  name: "c-next",
13
- version: "0.2.8",
13
+ version: "0.2.10",
14
14
  description: "A safer C for embedded systems development. Transpiles to clean, readable C.",
15
15
  packageManager: "npm@11.9.0",
16
16
  type: "module",
@@ -109966,6 +109966,18 @@ var SymbolTable = class {
109966
109966
  * In C, they must be referred to as 'struct Name', not just 'Name'
109967
109967
  */
109968
109968
  needsStructKeyword = /* @__PURE__ */ new Set();
109969
+ /**
109970
+ * Issue #948: Track typedef names that alias incomplete (forward-declared) struct types.
109971
+ * These are "opaque" types that can only be used as pointers.
109972
+ */
109973
+ opaqueTypes = /* @__PURE__ */ new Set();
109974
+ /**
109975
+ * Issue #948: Track struct tag -> typedef name relationships.
109976
+ * When a typedef declares an alias for a struct tag (e.g., typedef struct _foo foo_t),
109977
+ * we record structTagAliases["_foo"] = "foo_t". This allows us to unmark the typedef
109978
+ * as opaque when the full struct definition is later found.
109979
+ */
109980
+ structTagAliases = /* @__PURE__ */ new Map();
109969
109981
  /**
109970
109982
  * Issue #208: Track enum backing type bit widths
109971
109983
  * C++14 typed enums: enum Name : uint8_t { ... } have explicit bit widths
@@ -110594,6 +110606,66 @@ Rename the C-Next symbol to resolve.`
110594
110606
  }
110595
110607
  }
110596
110608
  // ========================================================================
110609
+ // Opaque Type Tracking (Issue #948)
110610
+ // ========================================================================
110611
+ /**
110612
+ * Issue #948: Mark a typedef as aliasing an opaque (forward-declared) struct type.
110613
+ * @param typeName Typedef name (e.g., "widget_t")
110614
+ */
110615
+ markOpaqueType(typeName) {
110616
+ this.opaqueTypes.add(typeName);
110617
+ }
110618
+ /**
110619
+ * Issue #948: Unmark a typedef when full struct definition is found.
110620
+ * Handles edge case: typedef before definition.
110621
+ * @param typeName Typedef name
110622
+ */
110623
+ unmarkOpaqueType(typeName) {
110624
+ this.opaqueTypes.delete(typeName);
110625
+ }
110626
+ /**
110627
+ * Issue #948: Check if a typedef aliases an opaque struct type.
110628
+ * @param typeName Typedef name
110629
+ * @returns true if the type is opaque (forward-declared)
110630
+ */
110631
+ isOpaqueType(typeName) {
110632
+ return this.opaqueTypes.has(typeName);
110633
+ }
110634
+ /**
110635
+ * Issue #948: Get all opaque type names for cache serialization.
110636
+ * @returns Array of opaque typedef names
110637
+ */
110638
+ getAllOpaqueTypes() {
110639
+ return Array.from(this.opaqueTypes);
110640
+ }
110641
+ /**
110642
+ * Issue #948: Restore opaque types from cache.
110643
+ * @param typeNames Array of opaque typedef names
110644
+ */
110645
+ restoreOpaqueTypes(typeNames) {
110646
+ for (const name of typeNames) {
110647
+ this.opaqueTypes.add(name);
110648
+ }
110649
+ }
110650
+ /**
110651
+ * Issue #948: Register a struct tag -> typedef name relationship.
110652
+ * Called when processing: typedef struct _foo foo_t;
110653
+ * This allows unmarking foo_t when struct _foo { ... } is later defined.
110654
+ * @param structTag The struct tag name (e.g., "_foo")
110655
+ * @param typedefName The typedef alias name (e.g., "foo_t")
110656
+ */
110657
+ registerStructTagAlias(structTag, typedefName) {
110658
+ this.structTagAliases.set(structTag, typedefName);
110659
+ }
110660
+ /**
110661
+ * Issue #948: Get the typedef alias for a struct tag, if any.
110662
+ * @param structTag The struct tag name
110663
+ * @returns The typedef alias name, or undefined if none registered
110664
+ */
110665
+ getStructTagAlias(structTag) {
110666
+ return this.structTagAliases.get(structTag);
110667
+ }
110668
+ // ========================================================================
110597
110669
  // Enum Bit Width Tracking
110598
110670
  // ========================================================================
110599
110671
  /**
@@ -110710,6 +110782,8 @@ Rename the C-Next symbol to resolve.`
110710
110782
  this.cppSymbolsByFile.clear();
110711
110783
  this.structFields.clear();
110712
110784
  this.needsStructKeyword.clear();
110785
+ this.opaqueTypes.clear();
110786
+ this.structTagAliases.clear();
110713
110787
  this.enumBitWidth.clear();
110714
110788
  }
110715
110789
  };
@@ -110828,6 +110902,13 @@ var CodeGenState = class {
110828
110902
  static inFunctionBody = false;
110829
110903
  /** Expected type for struct initializers and enum inference */
110830
110904
  static expectedType = null;
110905
+ /**
110906
+ * Suppress bare enum resolution even when expectedType is set.
110907
+ * Issue #872: MISRA 7.2 requires expectedType for U suffix on function args,
110908
+ * but bare enum resolution in function args was never allowed and changing
110909
+ * that would require ADR approval.
110910
+ */
110911
+ static suppressBareEnumResolution = false;
110831
110912
  /** Track args parameter name for main() translation */
110832
110913
  static mainArgsName = null;
110833
110914
  /** ADR-044: Current assignment context for overflow behavior */
@@ -110864,6 +110945,16 @@ var CodeGenState = class {
110864
110945
  /** Issue #473: IRQ wrappers for critical sections */
110865
110946
  static needsIrqWrappers = false;
110866
110947
  // ===========================================================================
110948
+ // OPAQUE TYPE SCOPE VARIABLES (Issue #948)
110949
+ // ===========================================================================
110950
+ /**
110951
+ * Tracks scope variables with opaque (forward-declared) struct types.
110952
+ * These are generated as pointers with NULL initialization and should
110953
+ * be passed directly (not with &) since they're already pointers.
110954
+ * Maps qualified name (e.g., "MyScope_widget") to true.
110955
+ */
110956
+ static opaqueScopeVariables = /* @__PURE__ */ new Set();
110957
+ // ===========================================================================
110867
110958
  // C++ MODE STATE (Issue #250)
110868
110959
  // ===========================================================================
110869
110960
  /** Use temp vars instead of compound literals */
@@ -110922,6 +111013,7 @@ var CodeGenState = class {
110922
111013
  this.indentLevel = 0;
110923
111014
  this.inFunctionBody = false;
110924
111015
  this.expectedType = null;
111016
+ this.suppressBareEnumResolution = false;
110925
111017
  this.mainArgsName = null;
110926
111018
  this.assignmentContext = {
110927
111019
  targetName: null,
@@ -110946,6 +111038,7 @@ var CodeGenState = class {
110946
111038
  this.tempVarCounter = 0;
110947
111039
  this.pendingCppClassAssignments = [];
110948
111040
  this.selfIncludeAdded = false;
111041
+ this.opaqueScopeVariables = /* @__PURE__ */ new Set();
110949
111042
  this.sourcePath = null;
110950
111043
  this.includeDirs = [];
110951
111044
  this.inputs = [];
@@ -110972,6 +111065,32 @@ var CodeGenState = class {
110972
111065
  this.floatBitShadows.clear();
110973
111066
  this.floatShadowCurrent.clear();
110974
111067
  }
111068
+ /**
111069
+ * Execute a function with a temporary expectedType, restoring on completion.
111070
+ * Issue #872: Extracted to eliminate duplicate save/restore pattern and add exception safety.
111071
+ *
111072
+ * @param type - The expected type to set (if falsy, no change is made)
111073
+ * @param fn - The function to execute
111074
+ * @param suppressEnumResolution - If true, suppress bare enum resolution (for MISRA-only contexts)
111075
+ * @returns The result of the function
111076
+ */
111077
+ static withExpectedType(type, fn, suppressEnumResolution = false) {
111078
+ if (!type) {
111079
+ return fn();
111080
+ }
111081
+ const savedType = this.expectedType;
111082
+ const savedSuppress = this.suppressBareEnumResolution;
111083
+ this.expectedType = type;
111084
+ if (suppressEnumResolution) {
111085
+ this.suppressBareEnumResolution = true;
111086
+ }
111087
+ try {
111088
+ return fn();
111089
+ } finally {
111090
+ this.expectedType = savedType;
111091
+ this.suppressBareEnumResolution = savedSuppress;
111092
+ }
111093
+ }
110975
111094
  // ===========================================================================
110976
111095
  // CONVENIENCE LOOKUP METHODS
110977
111096
  // ===========================================================================
@@ -111009,6 +111128,14 @@ var CodeGenState = class {
111009
111128
  static isKnownRegister(name) {
111010
111129
  return this.symbols?.knownRegisters.has(name) ?? false;
111011
111130
  }
111131
+ /**
111132
+ * Issue #948: Check if a type name is an opaque (forward-declared) struct type.
111133
+ * Opaque types are incomplete types that can only be used as pointers.
111134
+ * Example: `typedef struct _widget_t widget_t;` without a body makes `widget_t` opaque.
111135
+ */
111136
+ static isOpaqueType(typeName) {
111137
+ return this.symbols?.opaqueTypes.has(typeName) ?? false;
111138
+ }
111012
111139
  /**
111013
111140
  * Get type info for a variable.
111014
111141
  * Checks local typeRegistry first, then falls back to SymbolTable
@@ -111448,6 +111575,28 @@ var CodeGenState = class {
111448
111575
  return this.floatShadowCurrent.has(name);
111449
111576
  }
111450
111577
  // ===========================================================================
111578
+ // OPAQUE SCOPE VARIABLE HELPERS (Issue #948)
111579
+ // ===========================================================================
111580
+ /**
111581
+ * Mark a scope variable as having an opaque (forward-declared) struct type.
111582
+ * These are generated as pointers with NULL initialization.
111583
+ *
111584
+ * @param qualifiedName - The fully qualified variable name (e.g., "MyScope_widget")
111585
+ */
111586
+ static markOpaqueScopeVariable(qualifiedName) {
111587
+ this.opaqueScopeVariables.add(qualifiedName);
111588
+ }
111589
+ /**
111590
+ * Check if a scope variable has an opaque type (and is thus a pointer).
111591
+ * Used during access generation to determine if & prefix is needed.
111592
+ *
111593
+ * @param qualifiedName - The fully qualified variable name (e.g., "MyScope_widget")
111594
+ * @returns true if this is an opaque scope variable (already a pointer)
111595
+ */
111596
+ static isOpaqueScopeVariable(qualifiedName) {
111597
+ return this.opaqueScopeVariables.has(qualifiedName);
111598
+ }
111599
+ // ===========================================================================
111451
111600
  // C++ MODE HELPERS
111452
111601
  // ===========================================================================
111453
111602
  /**
@@ -113157,6 +113306,12 @@ var TypeResolver2 = class _TypeResolver {
113157
113306
  if (floatMatch) {
113158
113307
  return "f" + floatMatch[1];
113159
113308
  }
113309
+ if (/^\d+$/.test(text) || /^0[xXbBoO][\da-fA-F]+$/.test(text)) {
113310
+ return "int";
113311
+ }
113312
+ if (/^\d*\.\d+([eE][+-]?\d+)?$/.test(text) || /^\d+[eE][+-]?\d+$/.test(text)) {
113313
+ return "f64";
113314
+ }
113160
113315
  return null;
113161
113316
  }
113162
113317
  /**
@@ -114416,6 +114571,229 @@ var GeneratorRegistry = class {
114416
114571
  }
114417
114572
  };
114418
114573
 
114574
+ // src/transpiler/output/codegen/helpers/CppModeHelper.ts
114575
+ var CppModeHelper = class {
114576
+ /**
114577
+ * Get address-of expression for struct parameter passing.
114578
+ * C mode: `&expr` (pass pointer to struct)
114579
+ * C++ mode: `expr` (pass reference directly)
114580
+ *
114581
+ * @param expr - The expression to potentially wrap
114582
+ * @returns The expression with address-of operator in C mode
114583
+ */
114584
+ static maybeAddressOf(expr) {
114585
+ return CodeGenState.cppMode ? expr : `&${expr}`;
114586
+ }
114587
+ /**
114588
+ * Get dereference expression for struct parameter access.
114589
+ * C mode: `(*expr)` (dereference pointer)
114590
+ * C++ mode: `expr` (reference can be used directly)
114591
+ *
114592
+ * @param expr - The expression to potentially dereference
114593
+ * @returns The expression with dereference in C mode
114594
+ */
114595
+ static maybeDereference(expr) {
114596
+ return CodeGenState.cppMode ? expr : `(*${expr})`;
114597
+ }
114598
+ /**
114599
+ * Get the type modifier for struct parameter declarations.
114600
+ * C mode: `*` (pointer type)
114601
+ * C++ mode: `&` (reference type)
114602
+ *
114603
+ * @returns The type modifier character
114604
+ */
114605
+ static refOrPtr() {
114606
+ return CodeGenState.cppMode ? "&" : "*";
114607
+ }
114608
+ /**
114609
+ * Get the member access separator for struct parameters.
114610
+ * C mode: `->` (pointer member access)
114611
+ * C++ mode: `.` (reference member access)
114612
+ *
114613
+ * @returns The member access separator
114614
+ */
114615
+ static memberSeparator() {
114616
+ return CodeGenState.cppMode ? "." : "->";
114617
+ }
114618
+ /**
114619
+ * Get NULL literal for the current mode.
114620
+ * C mode: `NULL`
114621
+ * C++ mode: `nullptr`
114622
+ *
114623
+ * @returns The null pointer literal
114624
+ */
114625
+ static nullLiteral() {
114626
+ return CodeGenState.cppMode ? "nullptr" : "NULL";
114627
+ }
114628
+ /**
114629
+ * Generate a cast expression for the current mode.
114630
+ * C mode: `(type)expr`
114631
+ * C++ mode: `static_cast<type>(expr)`
114632
+ *
114633
+ * @param type - The target type
114634
+ * @param expr - The expression to cast
114635
+ * @returns The cast expression
114636
+ */
114637
+ static cast(type, expr) {
114638
+ return CodeGenState.cppMode ? `static_cast<${type}>(${expr})` : `(${type})${expr}`;
114639
+ }
114640
+ /**
114641
+ * Generate a reinterpret cast expression for the current mode.
114642
+ * C mode: `(type)expr`
114643
+ * C++ mode: `reinterpret_cast<type>(expr)`
114644
+ *
114645
+ * @param type - The target type
114646
+ * @param expr - The expression to cast
114647
+ * @returns The cast expression
114648
+ */
114649
+ static reinterpretCast(type, expr) {
114650
+ return CodeGenState.cppMode ? `reinterpret_cast<${type}>(${expr})` : `(${type})${expr}`;
114651
+ }
114652
+ /**
114653
+ * Check if we're in C++ mode.
114654
+ *
114655
+ * @returns True if generating C++ code
114656
+ */
114657
+ static isCppMode() {
114658
+ return CodeGenState.cppMode;
114659
+ }
114660
+ };
114661
+ var CppModeHelper_default = CppModeHelper;
114662
+
114663
+ // src/transpiler/output/codegen/helpers/NarrowingCastHelper.ts
114664
+ var EXTENDED_TYPE_WIDTH = {
114665
+ ...TYPE_WIDTH_default,
114666
+ int: 32
114667
+ // C's int after promotion
114668
+ };
114669
+ var PROMOTED_TO_INT = /* @__PURE__ */ new Set(["u8", "i8", "u16", "i16", "bool"]);
114670
+ var FLOAT_TYPES2 = /* @__PURE__ */ new Set(["f32", "f64", "float", "double"]);
114671
+ var INTEGER_TYPES2 = /* @__PURE__ */ new Set([
114672
+ "u8",
114673
+ "u16",
114674
+ "u32",
114675
+ "u64",
114676
+ "i8",
114677
+ "i16",
114678
+ "i32",
114679
+ "i64",
114680
+ "uint8_t",
114681
+ "uint16_t",
114682
+ "uint32_t",
114683
+ "uint64_t",
114684
+ "int8_t",
114685
+ "int16_t",
114686
+ "int32_t",
114687
+ "int64_t",
114688
+ "int"
114689
+ ]);
114690
+ var NarrowingCastHelper = class _NarrowingCastHelper {
114691
+ /**
114692
+ * Check if a cast is needed for MISRA 10.3 compliance.
114693
+ * Returns true if:
114694
+ * - Source is wider than target (narrowing)
114695
+ * - Source and target are different essential type categories
114696
+ *
114697
+ * @param sourceType - Type of the expression (C-Next type or "int" for promoted)
114698
+ * @param targetType - Type of the target variable (C-Next type)
114699
+ */
114700
+ static needsCast(sourceType, targetType) {
114701
+ if (sourceType === targetType) {
114702
+ return false;
114703
+ }
114704
+ if (targetType === "bool" && sourceType !== "bool") {
114705
+ return true;
114706
+ }
114707
+ const sourceWidth = EXTENDED_TYPE_WIDTH[sourceType];
114708
+ const targetWidth = EXTENDED_TYPE_WIDTH[targetType];
114709
+ if (sourceWidth === void 0 || targetWidth === void 0) {
114710
+ return false;
114711
+ }
114712
+ return sourceWidth > targetWidth;
114713
+ }
114714
+ /**
114715
+ * Wrap expression with cast if needed for MISRA 10.3 compliance.
114716
+ *
114717
+ * @param expr - The generated C expression
114718
+ * @param sourceType - Type of the expression (C-Next type or "int")
114719
+ * @param targetType - Type of the assignment target (C-Next type)
114720
+ * @returns Expression with cast wrapper if needed, or original expression
114721
+ */
114722
+ static wrap(expr, sourceType, targetType) {
114723
+ if (!_NarrowingCastHelper.needsCast(sourceType, targetType)) {
114724
+ return expr;
114725
+ }
114726
+ if (targetType === "bool") {
114727
+ return `((${expr}) != 0U)`;
114728
+ }
114729
+ const cType = TYPE_MAP_default[targetType] ?? targetType;
114730
+ return CppModeHelper_default.cast(cType, expr);
114731
+ }
114732
+ /**
114733
+ * Determine the result type of C integer promotion for a given type.
114734
+ *
114735
+ * In C, operations on types smaller than int are promoted:
114736
+ * - u8, i8, u16, i16, bool -> int (32-bit)
114737
+ * - u32, i32, u64, i64 -> no promotion (already >= int width)
114738
+ *
114739
+ * @param baseType - The C-Next type of the operand
114740
+ * @returns "int" for promoted types, or the original type
114741
+ */
114742
+ static getPromotedType(baseType) {
114743
+ if (PROMOTED_TO_INT.has(baseType)) {
114744
+ return "int";
114745
+ }
114746
+ return baseType;
114747
+ }
114748
+ /**
114749
+ * Check if a type is a floating-point type.
114750
+ */
114751
+ static isFloatType(typeName) {
114752
+ return FLOAT_TYPES2.has(typeName);
114753
+ }
114754
+ /**
114755
+ * Check if a type is an integer type.
114756
+ */
114757
+ static isIntegerType(typeName) {
114758
+ return INTEGER_TYPES2.has(typeName);
114759
+ }
114760
+ /**
114761
+ * Check if conversion between source and target is a cross-type-category conversion.
114762
+ * MISRA 10.3 requires explicit casts for different essential type categories.
114763
+ */
114764
+ static isCrossTypeCategoryConversion(sourceType, targetType) {
114765
+ const sourceIsFloat = _NarrowingCastHelper.isFloatType(sourceType);
114766
+ const targetIsFloat = _NarrowingCastHelper.isFloatType(targetType);
114767
+ const sourceIsInt = _NarrowingCastHelper.isIntegerType(sourceType);
114768
+ const targetIsInt = _NarrowingCastHelper.isIntegerType(targetType);
114769
+ return sourceIsFloat && targetIsInt || sourceIsInt && targetIsFloat;
114770
+ }
114771
+ /**
114772
+ * Get the appropriate C float type for a C-Next type.
114773
+ */
114774
+ static getCFloatType(typeName) {
114775
+ if (typeName === "f32" || typeName === "float") {
114776
+ return "float";
114777
+ }
114778
+ if (typeName === "f64" || typeName === "double") {
114779
+ return "double";
114780
+ }
114781
+ return "double";
114782
+ }
114783
+ /**
114784
+ * Wrap int-to-float conversion with explicit cast for MISRA 10.3.
114785
+ *
114786
+ * @param expr - The integer expression
114787
+ * @param targetType - The float target type (f32/f64)
114788
+ * @returns Expression with cast
114789
+ */
114790
+ static wrapIntToFloat(expr, targetType) {
114791
+ const floatType = _NarrowingCastHelper.getCFloatType(targetType);
114792
+ return CppModeHelper_default.cast(floatType, expr);
114793
+ }
114794
+ };
114795
+ var NarrowingCastHelper_default = NarrowingCastHelper;
114796
+
114419
114797
  // src/transpiler/output/codegen/generators/expressions/LiteralGenerator.ts
114420
114798
  var UNSIGNED_64_TYPES = /* @__PURE__ */ new Set(["u64", "uint64_t"]);
114421
114799
  var UNSIGNED_TYPES3 = /* @__PURE__ */ new Set([
@@ -114424,8 +114802,14 @@ var UNSIGNED_TYPES3 = /* @__PURE__ */ new Set([
114424
114802
  "u32",
114425
114803
  "uint8_t",
114426
114804
  "uint16_t",
114427
- "uint32_t"
114805
+ "uint32_t",
114806
+ "size_t"
114807
+ // Array indices (MISRA 7.2)
114428
114808
  ]);
114809
+ function resolveTypedef(typeName) {
114810
+ const underlyingType = CodeGenState.getTypedefType(typeName);
114811
+ return underlyingType ?? typeName;
114812
+ }
114429
114813
  function isNumericIntegerLiteral(text) {
114430
114814
  if (text.startsWith('"') || text.startsWith("'")) {
114431
114815
  return false;
@@ -114450,6 +114834,18 @@ var generateLiteral = (node, _input, state, _orchestrator) => {
114450
114834
  effects.push({ type: "include", header: "stdbool" });
114451
114835
  return { code: literalText, effects };
114452
114836
  }
114837
+ if (literalText.startsWith("'")) {
114838
+ const expectedType2 = state?.expectedType;
114839
+ if (expectedType2) {
114840
+ const wrappedCode = NarrowingCastHelper_default.wrap(
114841
+ literalText,
114842
+ "int",
114843
+ expectedType2
114844
+ );
114845
+ return { code: wrappedCode, effects };
114846
+ }
114847
+ return { code: literalText, effects };
114848
+ }
114453
114849
  if (/[fF]32$/.test(literalText)) {
114454
114850
  literalText = literalText.replace(/[fF]32$/, "f");
114455
114851
  return { code: literalText, effects };
@@ -114471,9 +114867,10 @@ var generateLiteral = (node, _input, state, _orchestrator) => {
114471
114867
  }
114472
114868
  const expectedType = state?.expectedType;
114473
114869
  if (expectedType && isNumericIntegerLiteral(literalText) && !hasUnsignedSuffix(literalText)) {
114474
- if (UNSIGNED_64_TYPES.has(expectedType)) {
114870
+ const resolvedType = resolveTypedef(expectedType);
114871
+ if (UNSIGNED_64_TYPES.has(resolvedType)) {
114475
114872
  literalText = literalText + "ULL";
114476
- } else if (UNSIGNED_TYPES3.has(expectedType)) {
114873
+ } else if (UNSIGNED_TYPES3.has(resolvedType)) {
114477
114874
  literalText = literalText + "U";
114478
114875
  }
114479
114876
  }
@@ -114810,96 +115207,9 @@ var binaryExprGenerators = {
114810
115207
  };
114811
115208
  var BinaryExprGenerator_default = binaryExprGenerators;
114812
115209
 
114813
- // src/transpiler/output/codegen/helpers/CppModeHelper.ts
114814
- var CppModeHelper = class {
114815
- /**
114816
- * Get address-of expression for struct parameter passing.
114817
- * C mode: `&expr` (pass pointer to struct)
114818
- * C++ mode: `expr` (pass reference directly)
114819
- *
114820
- * @param expr - The expression to potentially wrap
114821
- * @returns The expression with address-of operator in C mode
114822
- */
114823
- static maybeAddressOf(expr) {
114824
- return CodeGenState.cppMode ? expr : `&${expr}`;
114825
- }
114826
- /**
114827
- * Get dereference expression for struct parameter access.
114828
- * C mode: `(*expr)` (dereference pointer)
114829
- * C++ mode: `expr` (reference can be used directly)
114830
- *
114831
- * @param expr - The expression to potentially dereference
114832
- * @returns The expression with dereference in C mode
114833
- */
114834
- static maybeDereference(expr) {
114835
- return CodeGenState.cppMode ? expr : `(*${expr})`;
114836
- }
114837
- /**
114838
- * Get the type modifier for struct parameter declarations.
114839
- * C mode: `*` (pointer type)
114840
- * C++ mode: `&` (reference type)
114841
- *
114842
- * @returns The type modifier character
114843
- */
114844
- static refOrPtr() {
114845
- return CodeGenState.cppMode ? "&" : "*";
114846
- }
114847
- /**
114848
- * Get the member access separator for struct parameters.
114849
- * C mode: `->` (pointer member access)
114850
- * C++ mode: `.` (reference member access)
114851
- *
114852
- * @returns The member access separator
114853
- */
114854
- static memberSeparator() {
114855
- return CodeGenState.cppMode ? "." : "->";
114856
- }
114857
- /**
114858
- * Get NULL literal for the current mode.
114859
- * C mode: `NULL`
114860
- * C++ mode: `nullptr`
114861
- *
114862
- * @returns The null pointer literal
114863
- */
114864
- static nullLiteral() {
114865
- return CodeGenState.cppMode ? "nullptr" : "NULL";
114866
- }
114867
- /**
114868
- * Generate a cast expression for the current mode.
114869
- * C mode: `(type)expr`
114870
- * C++ mode: `static_cast<type>(expr)`
114871
- *
114872
- * @param type - The target type
114873
- * @param expr - The expression to cast
114874
- * @returns The cast expression
114875
- */
114876
- static cast(type, expr) {
114877
- return CodeGenState.cppMode ? `static_cast<${type}>(${expr})` : `(${type})${expr}`;
114878
- }
114879
- /**
114880
- * Generate a reinterpret cast expression for the current mode.
114881
- * C mode: `(type)expr`
114882
- * C++ mode: `reinterpret_cast<type>(expr)`
114883
- *
114884
- * @param type - The target type
114885
- * @param expr - The expression to cast
114886
- * @returns The cast expression
114887
- */
114888
- static reinterpretCast(type, expr) {
114889
- return CodeGenState.cppMode ? `reinterpret_cast<${type}>(${expr})` : `(${type})${expr}`;
114890
- }
114891
- /**
114892
- * Check if we're in C++ mode.
114893
- *
114894
- * @returns True if generating C++ code
114895
- */
114896
- static isCppMode() {
114897
- return CodeGenState.cppMode;
114898
- }
114899
- };
114900
- var CppModeHelper_default = CppModeHelper;
114901
-
114902
115210
  // src/transpiler/output/codegen/generators/expressions/UnaryExprGenerator.ts
115211
+ var INT32_MIN_LITERAL = "2147483648";
115212
+ var INT64_MIN_LITERAL = "9223372036854775808";
114903
115213
  var generateUnaryExpr = (node, _input, _state, orchestrator) => {
114904
115214
  if (node.postfixExpression()) {
114905
115215
  return {
@@ -114910,7 +115220,18 @@ var generateUnaryExpr = (node, _input, _state, orchestrator) => {
114910
115220
  const inner = orchestrator.generateUnaryExpr(node.unaryExpression());
114911
115221
  const text = node.getText();
114912
115222
  if (text.startsWith("!")) return { code: `!${inner}`, effects: [] };
114913
- if (text.startsWith("-")) return { code: `-${inner}`, effects: [] };
115223
+ if (text.startsWith("-")) {
115224
+ const effects = [];
115225
+ if (inner === INT32_MIN_LITERAL) {
115226
+ effects.push({ type: "include", header: "limits" });
115227
+ return { code: "(int32_t)INT32_MIN", effects };
115228
+ }
115229
+ if (inner === INT64_MIN_LITERAL || inner === INT64_MIN_LITERAL + "LL") {
115230
+ effects.push({ type: "include", header: "limits" });
115231
+ return { code: "(int64_t)INT64_MIN", effects };
115232
+ }
115233
+ return { code: `-${inner}`, effects };
115234
+ }
114914
115235
  if (text.startsWith("~")) {
114915
115236
  const innerType = TypeResolver_default2.getUnaryExpressionType(
114916
115237
  node.unaryExpression()
@@ -114973,15 +115294,18 @@ var generateSizeProperty = (typeInfo) => {
114973
115294
  throw new Error(`Error: .size is only available on string types`);
114974
115295
  };
114975
115296
  var generateBitmapFieldAccess = (result, fieldInfo) => {
115297
+ let expr;
114976
115298
  if (fieldInfo.width === 1) {
114977
- return { code: `((${result} >> ${fieldInfo.offset}) & 1)`, effects: [] };
115299
+ expr = `((${result} >> ${fieldInfo.offset}) & 1)`;
114978
115300
  } else {
114979
115301
  const mask = (1 << fieldInfo.width) - 1;
114980
- return {
114981
- code: `((${result} >> ${fieldInfo.offset}) & 0x${mask.toString(16).toUpperCase()})`,
114982
- effects: []
114983
- };
115302
+ expr = `((${result} >> ${fieldInfo.offset}) & 0x${mask.toString(16).toUpperCase()})`;
115303
+ }
115304
+ const targetType = CodeGenState.expectedType;
115305
+ if (targetType) {
115306
+ expr = NarrowingCastHelper_default.wrap(expr, "int", targetType);
114984
115307
  }
115308
+ return { code: expr, effects: [] };
114985
115309
  };
114986
115310
  var accessGenerators = {
114987
115311
  generateCapacityProperty,
@@ -115138,7 +115462,12 @@ var _generateCFunctionArg = (e, targetParam, input, orchestrator) => {
115138
115462
  orchestrator
115139
115463
  );
115140
115464
  }
115141
- let argCode = orchestrator.generateExpression(e);
115465
+ const argCode = CodeGenState.withExpectedType(
115466
+ targetParam?.baseType,
115467
+ () => orchestrator.generateExpression(e),
115468
+ true
115469
+ // suppressEnumResolution
115470
+ );
115142
115471
  if (!targetParam?.baseType?.endsWith("*")) {
115143
115472
  return wrapWithCppEnumCast(argCode, e, targetParam?.baseType, orchestrator);
115144
115473
  }
@@ -115153,11 +115482,15 @@ var _generateCFunctionArg = (e, targetParam, input, orchestrator) => {
115153
115482
  if (typeInfo?.isPointer) {
115154
115483
  isPointerVariable = true;
115155
115484
  }
115156
- const needsAddressOf = argType && !argType.endsWith("*") && !argCode.startsWith("&") && !targetParam.isArray && !isPointerVariable && (orchestrator.isStructType(argType) || _parameterExpectsAddressOf(targetParam.baseType, argType, orchestrator));
115157
- if (needsAddressOf) {
115158
- argCode = `&${argCode}`;
115159
- }
115160
- return wrapWithCppEnumCast(argCode, e, targetParam?.baseType, orchestrator);
115485
+ const isOpaqueScopeVar = CodeGenState.isOpaqueScopeVariable(argCode);
115486
+ const needsAddressOf = argType && !argType.endsWith("*") && !argCode.startsWith("&") && !targetParam.isArray && !isPointerVariable && !isOpaqueScopeVar && (orchestrator.isStructType(argType) || _parameterExpectsAddressOf(targetParam.baseType, argType, orchestrator));
115487
+ const finalArgCode = needsAddressOf ? `&${argCode}` : argCode;
115488
+ return wrapWithCppEnumCast(
115489
+ finalArgCode,
115490
+ e,
115491
+ targetParam?.baseType,
115492
+ orchestrator
115493
+ );
115161
115494
  };
115162
115495
  var _shouldPassByValue = (funcExpr, idx, targetParam, isCrossFile, orchestrator) => {
115163
115496
  if (!targetParam) return false;
@@ -115204,7 +115537,12 @@ var generateFunctionCall = (funcExpr, argCtx, input, _state, orchestrator) => {
115204
115537
  resolved.isCrossFile,
115205
115538
  orchestrator
115206
115539
  )) {
115207
- const argCode = orchestrator.generateExpression(e);
115540
+ const argCode = CodeGenState.withExpectedType(
115541
+ targetParam?.baseType,
115542
+ () => orchestrator.generateExpression(e),
115543
+ true
115544
+ // suppressEnumResolution
115545
+ );
115208
115546
  return wrapWithCppEnumCast(
115209
115547
  argCode,
115210
115548
  e,
@@ -115283,7 +115621,7 @@ var trackPassThroughModifications = (funcName, argExprs, orchestrator) => {
115283
115621
  var CallExprGenerator_default = generateFunctionCall;
115284
115622
 
115285
115623
  // src/utils/TypeCheckUtils.ts
115286
- var INTEGER_TYPES2 = [
115624
+ var INTEGER_TYPES3 = [
115287
115625
  "u8",
115288
115626
  "u16",
115289
115627
  "u32",
@@ -115295,7 +115633,7 @@ var INTEGER_TYPES2 = [
115295
115633
  ];
115296
115634
  var UNSIGNED_TYPES4 = ["u8", "u16", "u32", "u64"];
115297
115635
  var SIGNED_TYPES3 = ["i8", "i16", "i32", "i64"];
115298
- var FLOAT_TYPES2 = ["f32", "f64"];
115636
+ var FLOAT_TYPES3 = ["f32", "f64"];
115299
115637
  var STANDARD_WIDTHS = [8, 16, 32];
115300
115638
  var TypeCheckUtils = class {
115301
115639
  /**
@@ -115305,7 +115643,7 @@ var TypeCheckUtils = class {
115305
115643
  * @returns true if it's u8, u16, u32, u64, i8, i16, i32, or i64
115306
115644
  */
115307
115645
  static isInteger(typeName) {
115308
- return INTEGER_TYPES2.includes(typeName);
115646
+ return INTEGER_TYPES3.includes(typeName);
115309
115647
  }
115310
115648
  /**
115311
115649
  * Check if a type name is an unsigned integer type.
@@ -115332,7 +115670,7 @@ var TypeCheckUtils = class {
115332
115670
  * @returns true if it's f32 or f64
115333
115671
  */
115334
115672
  static isFloat(typeName) {
115335
- return FLOAT_TYPES2.includes(typeName);
115673
+ return FLOAT_TYPES3.includes(typeName);
115336
115674
  }
115337
115675
  /**
115338
115676
  * Check if a type name is a string type (string<N>).
@@ -116556,12 +116894,20 @@ var generateSubscriptAccess = (ctx, input, state, orchestrator, effects) => {
116556
116894
  return output;
116557
116895
  };
116558
116896
  var handleSingleSubscript = (ctx, expr, input, orchestrator, output) => {
116559
- const index = orchestrator.generateExpression(expr);
116897
+ const index = CodeGenState.withExpectedType(
116898
+ "size_t",
116899
+ () => orchestrator.generateExpression(expr)
116900
+ );
116560
116901
  validateNotBitmapMember(ctx, input);
116561
116902
  const isRegisterAccess = checkRegisterAccess(ctx, input);
116562
116903
  const identifierTypeInfo = getIdentifierTypeInfo(ctx, input);
116563
116904
  if (isRegisterAccess) {
116564
- output.result = `((${ctx.result} >> ${index}) & 1)`;
116905
+ let expr2 = index === "0" || index === "0U" ? `((${ctx.result}) & 1)` : `((${ctx.result} >> ${index}) & 1)`;
116906
+ const targetType = CodeGenState.expectedType;
116907
+ if (targetType) {
116908
+ expr2 = NarrowingCastHelper_default.wrap(expr2, "int", targetType);
116909
+ }
116910
+ output.result = expr2;
116565
116911
  return output;
116566
116912
  }
116567
116913
  if (ctx.currentMemberIsArray) {
@@ -116575,7 +116921,12 @@ var handleSingleSubscript = (ctx, expr, input, orchestrator, output) => {
116575
116921
  }
116576
116922
  const isPrimitiveIntMember = ctx.currentStructType && TypeCheckUtils_default.isInteger(ctx.currentStructType);
116577
116923
  if (isPrimitiveIntMember) {
116578
- output.result = `((${ctx.result} >> ${index}) & 1)`;
116924
+ let expr2 = index === "0" || index === "0U" ? `((${ctx.result}) & 1)` : `((${ctx.result} >> ${index}) & 1)`;
116925
+ const targetType = CodeGenState.expectedType;
116926
+ if (targetType) {
116927
+ expr2 = NarrowingCastHelper_default.wrap(expr2, "int", targetType);
116928
+ }
116929
+ output.result = expr2;
116579
116930
  output.currentStructType = void 0;
116580
116931
  return output;
116581
116932
  }
@@ -116633,12 +116984,23 @@ var handleDefaultSubscript = (ctx, index, typeInfo, output) => {
116633
116984
  subscriptCount: 1,
116634
116985
  isRegisterAccess: false
116635
116986
  });
116636
- output.result = subscriptKind === "bit_single" ? `((${ctx.result} >> ${index}) & 1)` : `${ctx.result}[${index}]`;
116987
+ if (subscriptKind === "bit_single") {
116988
+ let expr = index === "0" || index === "0U" ? `((${ctx.result}) & 1)` : `((${ctx.result} >> ${index}) & 1)`;
116989
+ const targetType = CodeGenState.expectedType;
116990
+ if (targetType) {
116991
+ expr = NarrowingCastHelper_default.wrap(expr, "int", targetType);
116992
+ }
116993
+ output.result = expr;
116994
+ } else {
116995
+ output.result = `${ctx.result}[${index}]`;
116996
+ }
116637
116997
  return output;
116638
116998
  };
116639
116999
  var handleBitRangeSubscript = (ctx, exprs, input, state, orchestrator, effects, output) => {
116640
- const start = orchestrator.generateExpression(exprs[0]);
116641
- const width = orchestrator.generateExpression(exprs[1]);
117000
+ const [start, width] = CodeGenState.withExpectedType("size_t", () => [
117001
+ orchestrator.generateExpression(exprs[0]),
117002
+ orchestrator.generateExpression(exprs[1])
117003
+ ]);
116642
117004
  const isFloatType = ctx.primaryTypeInfo?.baseType === "f32" || ctx.primaryTypeInfo?.baseType === "f64";
116643
117005
  if (isFloatType && ctx.rootIdentifier) {
116644
117006
  output.result = handleFloatBitRange(
@@ -116655,10 +117017,24 @@ var handleBitRangeSubscript = (ctx, exprs, input, state, orchestrator, effects,
116655
117017
  );
116656
117018
  } else {
116657
117019
  const mask = orchestrator.generateBitMask(width);
116658
- if (start === "0") {
116659
- output.result = `((${ctx.result}) & ${mask})`;
117020
+ let expr;
117021
+ if (start === "0" || start === "0U") {
117022
+ expr = `((${ctx.result}) & ${mask})`;
116660
117023
  } else {
116661
- output.result = `((${ctx.result} >> ${start}) & ${mask})`;
117024
+ expr = `((${ctx.result} >> ${start}) & ${mask})`;
117025
+ }
117026
+ const targetType = CodeGenState.expectedType;
117027
+ if (targetType && ctx.primaryTypeInfo?.baseType) {
117028
+ const promotedSourceType = NarrowingCastHelper_default.getPromotedType(
117029
+ ctx.primaryTypeInfo.baseType
117030
+ );
117031
+ output.result = NarrowingCastHelper_default.wrap(
117032
+ expr,
117033
+ promotedSourceType,
117034
+ targetType
117035
+ );
117036
+ } else {
117037
+ output.result = expr;
116662
117038
  }
116663
117039
  }
116664
117040
  return output;
@@ -116690,7 +117066,7 @@ var handleFloatBitRange = (ctx, state, orchestrator, effects) => {
116690
117066
  if (!shadowIsCurrent) {
116691
117067
  orchestrator.addPendingTempDeclaration(`${shadowName}.f = ${ctx.result};`);
116692
117068
  }
116693
- if (ctx.start === "0") {
117069
+ if (ctx.start === "0" || ctx.start === "0U") {
116694
117070
  return `(${shadowName}.u & ${mask})`;
116695
117071
  }
116696
117072
  return `((${shadowName}.u >> ${ctx.start}) & ${mask})`;
@@ -116968,6 +117344,21 @@ var generateCriticalStatement = (node, _input, _state, orchestrator) => {
116968
117344
  };
116969
117345
  var CriticalGenerator_default = generateCriticalStatement;
116970
117346
 
117347
+ // src/transpiler/output/codegen/types/COMPOUND_TO_BINARY.ts
117348
+ var COMPOUND_TO_BINARY = {
117349
+ "+=": "+",
117350
+ "-=": "-",
117351
+ "*=": "*",
117352
+ "/=": "/",
117353
+ "%=": "%",
117354
+ "&=": "&",
117355
+ "|=": "|",
117356
+ "^=": "^",
117357
+ "<<=": "<<",
117358
+ ">>=": ">>"
117359
+ };
117360
+ var COMPOUND_TO_BINARY_default = COMPOUND_TO_BINARY;
117361
+
116971
117362
  // src/transpiler/output/codegen/generators/statements/AtomicGenerator.ts
116972
117363
  var TYPE_MAP2 = {
116973
117364
  u8: "uint8_t",
@@ -116995,18 +117386,6 @@ var STREX_MAP = {
116995
117386
  u32: "__STREXW",
116996
117387
  i32: "__STREXW"
116997
117388
  };
116998
- var SIMPLE_OP_MAP = {
116999
- "+=": "+",
117000
- "-=": "-",
117001
- "*=": "*",
117002
- "/=": "/",
117003
- "%=": "%",
117004
- "&=": "&",
117005
- "|=": "|",
117006
- "^=": "^",
117007
- "<<=": "<<",
117008
- ">>=": ">>"
117009
- };
117010
117389
  var CLAMP_OP_MAP = {
117011
117390
  "+=": "add",
117012
117391
  "-=": "sub",
@@ -117020,7 +117399,7 @@ function getClampHelperOp(cOp, typeInfo) {
117020
117399
  }
117021
117400
  function generateInnerAtomicOp(cOp, value, typeInfo) {
117022
117401
  const effects = [];
117023
- const simpleOp = SIMPLE_OP_MAP[cOp] || "+";
117402
+ const simpleOp = COMPOUND_TO_BINARY_default[cOp] || "+";
117024
117403
  const helperOp = getClampHelperOp(cOp, typeInfo);
117025
117404
  if (helperOp) {
117026
117405
  effects.push({
@@ -117612,7 +117991,11 @@ var FunctionGenerator_default = generateFunction;
117612
117991
  // src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts
117613
117992
  function generateInitializer(varDecl, isArray, orchestrator) {
117614
117993
  if (varDecl.expression()) {
117615
- return ` = ${orchestrator.generateExpression(varDecl.expression())}`;
117994
+ const typeName = orchestrator.generateType(varDecl.type());
117995
+ return CodeGenState.withExpectedType(
117996
+ typeName,
117997
+ () => ` = ${orchestrator.generateExpression(varDecl.expression())}`
117998
+ );
117616
117999
  }
117617
118000
  return ` = ${orchestrator.getZeroInitializer(varDecl.type(), isArray)}`;
117618
118001
  }
@@ -117681,8 +118064,13 @@ function generateRegularVariable(varDecl, varName, scopeName, isPrivate, orchest
117681
118064
  const arrayDims = varDecl.arrayDimension();
117682
118065
  const arrayTypeCtx = varDecl.type().arrayType?.() ?? null;
117683
118066
  const isArray = arrayDims.length > 0 || arrayTypeCtx !== null;
117684
- const type = orchestrator.generateType(varDecl.type());
118067
+ let type = orchestrator.generateType(varDecl.type());
117685
118068
  const fullName = QualifiedNameGenerator_default.forMember(scopeName, varName);
118069
+ const isOpaque = orchestrator.isOpaqueType(type);
118070
+ if (isOpaque) {
118071
+ type = `${type}*`;
118072
+ orchestrator.markOpaqueScopeVariable(fullName);
118073
+ }
117686
118074
  const constPrefix = isConst ? "const " : "";
117687
118075
  const prefix = isPrivate ? "static " : "";
117688
118076
  let decl = `${prefix}${constPrefix}${type} ${fullName}`;
@@ -117694,7 +118082,11 @@ function generateRegularVariable(varDecl, varName, scopeName, isPrivate, orchest
117694
118082
  decl += orchestrator.generateArrayDimensions(arrayDims);
117695
118083
  }
117696
118084
  decl += ArrayDimensionUtils_default.generateStringCapacityDim(varDecl.type());
117697
- decl += generateInitializer(varDecl, isArray, orchestrator);
118085
+ if (isOpaque) {
118086
+ decl += " = NULL";
118087
+ } else {
118088
+ decl += generateInitializer(varDecl, isArray, orchestrator);
118089
+ }
117698
118090
  return decl + ";";
117699
118091
  }
117700
118092
  function generateScopeFunction(funcDecl, scopeName, isPrivate, orchestrator) {
@@ -117906,6 +118298,7 @@ function generateScopedStructInline(node, scopeName, _input, orchestrator) {
117906
118298
  var ScopeGenerator_default = generateScope;
117907
118299
 
117908
118300
  // src/utils/BitUtils.ts
118301
+ var NARROW_TYPES = /* @__PURE__ */ new Set(["u8", "u16", "i8", "i16"]);
117909
118302
  var BitUtils = class _BitUtils {
117910
118303
  /**
117911
118304
  * Convert a boolean expression to an unsigned integer (0U or 1U).
@@ -117996,6 +118389,21 @@ var BitUtils = class _BitUtils {
117996
118389
  static formatHex(value) {
117997
118390
  return `0x${value.toString(16).toUpperCase()}U`;
117998
118391
  }
118392
+ /**
118393
+ * Wrap an expression with a cast for MISRA 10.3 compliance on narrow types.
118394
+ * Bit manipulation operations promote to int; this casts back to the target type.
118395
+ *
118396
+ * @param expr - The expression to potentially wrap
118397
+ * @param targetType - The C-Next type name (e.g., "u8", "u16")
118398
+ * @returns Expression wrapped with cast if narrow, or original expression
118399
+ */
118400
+ static wrapNarrowCast(expr, targetType) {
118401
+ if (!targetType || !NARROW_TYPES.has(targetType)) {
118402
+ return expr;
118403
+ }
118404
+ const cType = TYPE_MAP_default[targetType] ?? targetType;
118405
+ return `(${cType})(${expr})`;
118406
+ }
117999
118407
  /**
118000
118408
  * Generate code to read a single bit from a value.
118001
118409
  * Pattern: ((target >> offset) & 1)
@@ -118042,7 +118450,8 @@ var BitUtils = class _BitUtils {
118042
118450
  const is64Bit = targetType === "u64" || targetType === "i64";
118043
118451
  const one = is64Bit ? "1ULL" : "1U";
118044
118452
  const valueShift = is64Bit ? `((uint64_t)${intValue} << ${offset})` : `(${intValue} << ${offset})`;
118045
- return `${target} = (${target} & ~(${one} << ${offset})) | ${valueShift};`;
118453
+ const rhs = `(${target} & ~(${one} << ${offset})) | ${valueShift}`;
118454
+ return `${target} = ${_BitUtils.wrapNarrowCast(rhs, targetType)};`;
118046
118455
  }
118047
118456
  /**
118048
118457
  * Generate read-modify-write code for multi-bit assignment.
@@ -118057,7 +118466,8 @@ var BitUtils = class _BitUtils {
118057
118466
  */
118058
118467
  static multiBitWrite(target, offset, width, value, targetType) {
118059
118468
  const mask = _BitUtils.generateMask(width, targetType);
118060
- return `${target} = (${target} & ~(${mask} << ${offset})) | ((${value} & ${mask}) << ${offset});`;
118469
+ const rhs = `(${target} & ~(${mask} << ${offset})) | ((${value} & ${mask}) << ${offset})`;
118470
+ return `${target} = ${_BitUtils.wrapNarrowCast(rhs, targetType)};`;
118061
118471
  }
118062
118472
  /**
118063
118473
  * Generate write-only register code for single bit assignment.
@@ -118073,7 +118483,8 @@ var BitUtils = class _BitUtils {
118073
118483
  static writeOnlySingleBit(target, offset, value, targetType) {
118074
118484
  const intValue = _BitUtils.boolToInt(value);
118075
118485
  const castPrefix = targetType === "u64" || targetType === "i64" ? "(uint64_t)" : "";
118076
- return `${target} = (${castPrefix}${intValue} << ${offset});`;
118486
+ const rhs = `(${castPrefix}${intValue} << ${offset})`;
118487
+ return `${target} = ${_BitUtils.wrapNarrowCast(rhs, targetType)};`;
118077
118488
  }
118078
118489
  /**
118079
118490
  * Generate write-only register code for multi-bit assignment.
@@ -118089,7 +118500,8 @@ var BitUtils = class _BitUtils {
118089
118500
  */
118090
118501
  static writeOnlyMultiBit(target, offset, width, value, targetType) {
118091
118502
  const mask = _BitUtils.generateMask(width, targetType);
118092
- return `${target} = ((${value} & ${mask}) << ${offset});`;
118503
+ const rhs = `((${value} & ${mask}) << ${offset})`;
118504
+ return `${target} = ${_BitUtils.wrapNarrowCast(rhs, targetType)};`;
118093
118505
  }
118094
118506
  };
118095
118507
  var BitUtils_default = BitUtils;
@@ -118804,7 +119216,7 @@ var CnxFileResolver = class {
118804
119216
  var CnxFileResolver_default = CnxFileResolver;
118805
119217
 
118806
119218
  // src/transpiler/output/codegen/generators/support/IncludeGenerator.ts
118807
- var resolveAngleIncludePath = (filename, sourcePath, includeDirs, inputs) => {
119219
+ var resolveAngleIncludePath = (filename, sourcePath, includeDirs, inputs, cppMode) => {
118808
119220
  if (inputs.length === 0) {
118809
119221
  return null;
118810
119222
  }
@@ -118818,25 +119230,33 @@ var resolveAngleIncludePath = (filename, sourcePath, includeDirs, inputs) => {
118818
119230
  foundPath,
118819
119231
  inputs
118820
119232
  );
118821
- return relativePath ? relativePath.replace(/\.cnx$/, ".h") : null;
119233
+ const ext = cppMode ? ".hpp" : ".h";
119234
+ return relativePath ? relativePath.replace(/\.cnx$/, ext) : null;
118822
119235
  };
118823
119236
  var transformAngleInclude = (includeText, filename, options) => {
118824
- const { sourcePath, includeDirs = [], inputs = [] } = options;
119237
+ const {
119238
+ sourcePath,
119239
+ includeDirs = [],
119240
+ inputs = [],
119241
+ cppMode = false
119242
+ } = options;
118825
119243
  if (sourcePath) {
118826
119244
  const resolvedPath = resolveAngleIncludePath(
118827
119245
  filename,
118828
119246
  sourcePath,
118829
119247
  includeDirs,
118830
- inputs
119248
+ inputs,
119249
+ cppMode
118831
119250
  );
118832
119251
  if (resolvedPath) {
118833
119252
  return includeText.replace(`<${filename}.cnx>`, `<${resolvedPath}>`);
118834
119253
  }
118835
119254
  }
118836
- return includeText.replace(`<${filename}.cnx>`, `<${filename}.h>`);
119255
+ const ext = cppMode ? ".hpp" : ".h";
119256
+ return includeText.replace(`<${filename}.cnx>`, `<${filename}${ext}>`);
118837
119257
  };
118838
119258
  var transformQuoteInclude = (includeText, filepath, options) => {
118839
- const { sourcePath } = options;
119259
+ const { sourcePath, cppMode = false } = options;
118840
119260
  if (sourcePath) {
118841
119261
  const sourceDir = path.dirname(sourcePath);
118842
119262
  const cnxPath = path.resolve(sourceDir, `${filepath}.cnx`);
@@ -118848,7 +119268,8 @@ var transformQuoteInclude = (includeText, filepath, options) => {
118848
119268
  );
118849
119269
  }
118850
119270
  }
118851
- return includeText.replace(`"${filepath}.cnx"`, `"${filepath}.h"`);
119271
+ const ext = cppMode ? ".hpp" : ".h";
119272
+ return includeText.replace(`"${filepath}.cnx"`, `"${filepath}${ext}"`);
118852
119273
  };
118853
119274
  var transformIncludeDirective = (includeText, options) => {
118854
119275
  const angleMatch = /#\s*include\s*<([^>]+)\.cnx>/.exec(includeText);
@@ -120641,8 +121062,10 @@ var AssignmentKind = /* @__PURE__ */ ((AssignmentKind2) => {
120641
121062
  AssignmentKind2[AssignmentKind2["GLOBAL_REGISTER_BIT"] = 28] = "GLOBAL_REGISTER_BIT";
120642
121063
  AssignmentKind2[AssignmentKind2["THIS_MEMBER"] = 29] = "THIS_MEMBER";
120643
121064
  AssignmentKind2[AssignmentKind2["THIS_ARRAY"] = 30] = "THIS_ARRAY";
120644
- AssignmentKind2[AssignmentKind2["MEMBER_CHAIN"] = 31] = "MEMBER_CHAIN";
120645
- AssignmentKind2[AssignmentKind2["SIMPLE"] = 32] = "SIMPLE";
121065
+ AssignmentKind2[AssignmentKind2["THIS_BIT"] = 31] = "THIS_BIT";
121066
+ AssignmentKind2[AssignmentKind2["THIS_BIT_RANGE"] = 32] = "THIS_BIT_RANGE";
121067
+ AssignmentKind2[AssignmentKind2["MEMBER_CHAIN"] = 33] = "MEMBER_CHAIN";
121068
+ AssignmentKind2[AssignmentKind2["SIMPLE"] = 34] = "SIMPLE";
120646
121069
  return AssignmentKind2;
120647
121070
  })(AssignmentKind || {});
120648
121071
  var AssignmentKind_default = AssignmentKind;
@@ -120684,8 +121107,55 @@ var handlers_default = AssignmentHandlerRegistry;
120684
121107
  function gen() {
120685
121108
  return CodeGenState.generator;
120686
121109
  }
121110
+ function tryHandleCompoundNarrowingCast(ctx, target) {
121111
+ if (!ctx.isCompound || !ctx.firstIdTypeInfo) {
121112
+ return null;
121113
+ }
121114
+ const baseType = ctx.firstIdTypeInfo.baseType;
121115
+ const promotedType = NarrowingCastHelper_default.getPromotedType(baseType);
121116
+ if (promotedType !== "int" || baseType === "int") {
121117
+ return null;
121118
+ }
121119
+ const binaryOp = COMPOUND_TO_BINARY_default[ctx.cOp];
121120
+ if (!binaryOp) {
121121
+ return null;
121122
+ }
121123
+ const cType = TYPE_MAP_default[baseType] ?? baseType;
121124
+ const expr = `(${target} ${binaryOp} ${ctx.generatedValue})`;
121125
+ const castExpr = CppModeHelper_default.cast(cType, expr);
121126
+ return `${target} = ${castExpr};`;
121127
+ }
121128
+ function tryHandleIntToFloatConversion(ctx, target) {
121129
+ if (ctx.isCompound || !ctx.firstIdTypeInfo || !ctx.valueCtx) {
121130
+ return null;
121131
+ }
121132
+ const targetType = ctx.firstIdTypeInfo.baseType;
121133
+ const valueType = TypeResolver_default2.getExpressionType(ctx.valueCtx);
121134
+ if (!valueType) {
121135
+ return null;
121136
+ }
121137
+ if (!NarrowingCastHelper_default.isCrossTypeCategoryConversion(valueType, targetType)) {
121138
+ return null;
121139
+ }
121140
+ if (!NarrowingCastHelper_default.isIntegerType(valueType) || !NarrowingCastHelper_default.isFloatType(targetType)) {
121141
+ return null;
121142
+ }
121143
+ const castedValue = NarrowingCastHelper_default.wrapIntToFloat(
121144
+ ctx.generatedValue,
121145
+ targetType
121146
+ );
121147
+ return `${target} ${ctx.cOp} ${castedValue};`;
121148
+ }
120687
121149
  function handleSimpleAssignment(ctx) {
120688
121150
  const target = gen().generateAssignmentTarget(ctx.targetCtx);
121151
+ const compoundResult = tryHandleCompoundNarrowingCast(ctx, target);
121152
+ if (compoundResult) {
121153
+ return compoundResult;
121154
+ }
121155
+ const conversionResult = tryHandleIntToFloatConversion(ctx, target);
121156
+ if (conversionResult) {
121157
+ return conversionResult;
121158
+ }
120689
121159
  return `${target} ${ctx.cOp} ${ctx.generatedValue};`;
120690
121160
  }
120691
121161
  var SimpleHandler_default = handleSimpleAssignment;
@@ -121338,6 +121808,8 @@ function handleStructChainBitRange(ctx) {
121338
121808
  var bitAccessHandlers = [
121339
121809
  [AssignmentKind_default.INTEGER_BIT, handleIntegerBit],
121340
121810
  [AssignmentKind_default.INTEGER_BIT_RANGE, handleIntegerBitRange],
121811
+ [AssignmentKind_default.THIS_BIT, handleIntegerBit],
121812
+ [AssignmentKind_default.THIS_BIT_RANGE, handleIntegerBitRange],
121341
121813
  [AssignmentKind_default.STRUCT_MEMBER_BIT, handleStructMemberBit],
121342
121814
  [AssignmentKind_default.ARRAY_ELEMENT_BIT, handleArrayElementBit],
121343
121815
  [AssignmentKind_default.STRUCT_CHAIN_BIT_RANGE, handleStructChainBitRange]
@@ -121889,14 +122361,28 @@ var AssignmentClassifier = class _AssignmentClassifier {
121889
122361
  return AssignmentKind_default.THIS_MEMBER;
121890
122362
  }
121891
122363
  /**
121892
- * Classify this.reg[bit] / this.arr[i] patterns with array access.
122364
+ * Classify this.reg[bit] / this.arr[i] / this.flags[3] patterns with array access.
122365
+ * Issue #954: Uses SubscriptClassifier to distinguish array vs bit access.
121893
122366
  */
121894
122367
  static classifyThisWithArrayAccess(ctx, scopedRegName) {
121895
122368
  if (CodeGenState.symbols.knownRegisters.has(scopedRegName)) {
121896
122369
  const hasBitRange = ctx.postfixOps.some((op) => op.COMMA() !== null);
121897
122370
  return hasBitRange ? AssignmentKind_default.SCOPED_REGISTER_BIT_RANGE : AssignmentKind_default.SCOPED_REGISTER_BIT;
121898
122371
  }
121899
- return AssignmentKind_default.THIS_ARRAY;
122372
+ const typeInfo = CodeGenState.getVariableTypeInfo(scopedRegName);
122373
+ const subscriptKind = SubscriptClassifier_default.classify({
122374
+ typeInfo: typeInfo ?? null,
122375
+ subscriptCount: ctx.lastSubscriptExprCount,
122376
+ isRegisterAccess: false
122377
+ });
122378
+ switch (subscriptKind) {
122379
+ case "bit_single":
122380
+ return AssignmentKind_default.THIS_BIT;
122381
+ case "bit_range":
122382
+ return AssignmentKind_default.THIS_BIT_RANGE;
122383
+ default:
122384
+ return AssignmentKind_default.THIS_ARRAY;
122385
+ }
121900
122386
  }
121901
122387
  /**
121902
122388
  * Classify simple array/bit access (no prefix, no member access).
@@ -121969,7 +122455,8 @@ var AssignmentClassifier = class _AssignmentClassifier {
121969
122455
  if (isGlobalAtomic) {
121970
122456
  return AssignmentKind_default.ATOMIC_RMW;
121971
122457
  }
121972
- if (typeInfo.overflowBehavior === "clamp" && TypeCheckUtils_default.isInteger(typeInfo.baseType)) {
122458
+ const ARITHMETIC_COMPOUND_OPS = /* @__PURE__ */ new Set(["+=", "-=", "*="]);
122459
+ if (typeInfo.overflowBehavior === "clamp" && TypeCheckUtils_default.isInteger(typeInfo.baseType) && ARITHMETIC_COMPOUND_OPS.has(ctx.cOp)) {
121973
122460
  return AssignmentKind_default.OVERFLOW_CLAMP;
121974
122461
  }
121975
122462
  return null;
@@ -122618,6 +123105,7 @@ var ArgumentGenerator = class _ArgumentGenerator {
122618
123105
  }
122619
123106
  /**
122620
123107
  * Handle rvalue argument (literals or complex expressions).
123108
+ * Issue #872: Sets expectedType for MISRA 7.2 U suffix on unsigned literals.
122621
123109
  */
122622
123110
  static handleRvalueArg(ctx, targetParamBaseType, callbacks) {
122623
123111
  if (!targetParamBaseType) {
@@ -122625,9 +123113,19 @@ var ArgumentGenerator = class _ArgumentGenerator {
122625
123113
  }
122626
123114
  const cType = TYPE_MAP_default[targetParamBaseType];
122627
123115
  if (!cType || cType === "void") {
122628
- return callbacks.generateExpression(ctx);
123116
+ return CodeGenState.withExpectedType(
123117
+ targetParamBaseType,
123118
+ () => callbacks.generateExpression(ctx),
123119
+ true
123120
+ // suppressEnumResolution
123121
+ );
122629
123122
  }
122630
- const value = callbacks.generateExpression(ctx);
123123
+ const value = CodeGenState.withExpectedType(
123124
+ targetParamBaseType,
123125
+ () => callbacks.generateExpression(ctx),
123126
+ true
123127
+ // suppressEnumResolution
123128
+ );
122631
123129
  if (CodeGenState.cppMode) {
122632
123130
  return value;
122633
123131
  }
@@ -123046,6 +123544,14 @@ var AssignmentExpectedTypeResolver = class _AssignmentExpectedTypeResolver {
123046
123544
  identifiers
123047
123545
  );
123048
123546
  }
123547
+ if (identifiers.length === 1 && hasSubscript) {
123548
+ return _AssignmentExpectedTypeResolver.resolveForArrayElement(baseId);
123549
+ }
123550
+ if (identifiers.length >= 2 && hasSubscript) {
123551
+ return _AssignmentExpectedTypeResolver.resolveForMemberArrayElement(
123552
+ identifiers
123553
+ );
123554
+ }
123049
123555
  }
123050
123556
  return { expectedType: null, assignmentContext: null };
123051
123557
  }
@@ -123072,8 +123578,40 @@ var AssignmentExpectedTypeResolver = class _AssignmentExpectedTypeResolver {
123072
123578
  *
123073
123579
  * Issue #452: Enables type-aware resolution of unqualified enum members
123074
123580
  * for nested access (e.g., config.nested.field).
123581
+ *
123582
+ * Delegates to walkMemberChain shared implementation.
123075
123583
  */
123076
123584
  static resolveForMemberChain(identifiers) {
123585
+ return _AssignmentExpectedTypeResolver.walkMemberChain(identifiers);
123586
+ }
123587
+ /**
123588
+ * Resolve expected type for array element access.
123589
+ * Issue #872: arr[i] <- value needs baseType for MISRA 7.2 U suffix.
123590
+ */
123591
+ static resolveForArrayElement(id) {
123592
+ const typeInfo = CodeGenState.getVariableTypeInfo(id);
123593
+ if (!typeInfo?.isArray) {
123594
+ return { expectedType: null, assignmentContext: null };
123595
+ }
123596
+ return { expectedType: typeInfo.baseType, assignmentContext: null };
123597
+ }
123598
+ /**
123599
+ * Resolve expected type for member chain ending with array access.
123600
+ * Issue #872: struct.arr[i] <- value needs element type for MISRA 7.2.
123601
+ *
123602
+ * Delegates to walkMemberChain which handles both member chain and
123603
+ * member-array-element patterns identically (both return final field type).
123604
+ */
123605
+ static resolveForMemberArrayElement(identifiers) {
123606
+ return _AssignmentExpectedTypeResolver.walkMemberChain(identifiers);
123607
+ }
123608
+ /**
123609
+ * Walk a struct member chain to find the final field's type.
123610
+ * Shared implementation for both member chain and member-array-element patterns.
123611
+ *
123612
+ * Issue #831: Uses SymbolTable as single source of truth for struct fields.
123613
+ */
123614
+ static walkMemberChain(identifiers) {
123077
123615
  if (identifiers.length < 2) {
123078
123616
  return { expectedType: null, assignmentContext: null };
123079
123617
  }
@@ -123619,11 +124157,10 @@ var ArrayInitHelper = class _ArrayInitHelper {
123619
124157
  */
123620
124158
  static _generateArrayInitValue(typeCtx, expression, callbacks) {
123621
124159
  const typeName = callbacks.getTypeName(typeCtx);
123622
- const savedExpectedType = CodeGenState.expectedType;
123623
- CodeGenState.expectedType = typeName;
123624
- const initValue = callbacks.generateExpression(expression);
123625
- CodeGenState.expectedType = savedExpectedType;
123626
- return initValue;
124160
+ return CodeGenState.withExpectedType(
124161
+ typeName,
124162
+ () => callbacks.generateExpression(expression)
124163
+ );
123627
124164
  }
123628
124165
  /**
123629
124166
  * Check if the last expression was an array initializer
@@ -124316,15 +124853,24 @@ ${assignments}`;
124316
124853
  return `${decl} = ${callbacks.getZeroInitializer(typeCtx, isArray)}`;
124317
124854
  }
124318
124855
  const typeName = callbacks.getTypeName(typeCtx);
124319
- const savedExpectedType = CodeGenState.expectedType;
124320
- CodeGenState.expectedType = typeName;
124321
124856
  EnumAssignmentValidator_default.validateEnumAssignment(typeName, ctx.expression());
124322
124857
  _VariableDeclHelper.validateIntegerInitializer(ctx, typeName, {
124323
124858
  getExpressionType: callbacks.getExpressionType
124324
124859
  });
124325
- const result = `${decl} = ${callbacks.generateExpression(ctx.expression())}`;
124326
- CodeGenState.expectedType = savedExpectedType;
124327
- return result;
124860
+ return CodeGenState.withExpectedType(typeName, () => {
124861
+ let exprCode = callbacks.generateExpression(ctx.expression());
124862
+ const exprType = callbacks.getExpressionType(ctx.expression());
124863
+ if (exprType && NarrowingCastHelper_default.isCrossTypeCategoryConversion(exprType, typeName)) {
124864
+ if (NarrowingCastHelper_default.isIntegerType(exprType) && NarrowingCastHelper_default.isFloatType(typeName)) {
124865
+ exprCode = NarrowingCastHelper_default.wrapIntToFloat(exprCode, typeName);
124866
+ }
124867
+ if (NarrowingCastHelper_default.isFloatType(exprType) && NarrowingCastHelper_default.isIntegerType(typeName)) {
124868
+ const cType = TYPE_MAP_default[typeName] ?? typeName;
124869
+ exprCode = CppModeHelper_default.cast(cType, exprCode);
124870
+ }
124871
+ }
124872
+ return `${decl} = ${exprCode}`;
124873
+ });
124328
124874
  }
124329
124875
  // ========================================================================
124330
124876
  // Tier 4: Orchestrators (main entry points)
@@ -125185,7 +125731,7 @@ var TypeGenerationHelper_default = TypeGenerationHelper;
125185
125731
  var SIGNED_INTEGERS = /* @__PURE__ */ new Set(["i8", "i16", "i32", "i64"]);
125186
125732
  var UNSIGNED_INTEGERS = /* @__PURE__ */ new Set(["u8", "u16", "u32", "u64"]);
125187
125733
  var ALL_INTEGERS = /* @__PURE__ */ new Set([...SIGNED_INTEGERS, ...UNSIGNED_INTEGERS]);
125188
- var FLOAT_TYPES3 = /* @__PURE__ */ new Set(["f32", "f64"]);
125734
+ var FLOAT_TYPES4 = /* @__PURE__ */ new Set(["f32", "f64"]);
125189
125735
  var CastValidator = class _CastValidator {
125190
125736
  /**
125191
125737
  * Check if a type is an integer type.
@@ -125197,7 +125743,7 @@ var CastValidator = class _CastValidator {
125197
125743
  * Check if a type is a floating-point type.
125198
125744
  */
125199
125745
  static isFloatType(typeName) {
125200
- return FLOAT_TYPES3.has(typeName);
125746
+ return FLOAT_TYPES4.has(typeName);
125201
125747
  }
125202
125748
  /**
125203
125749
  * Check if a type is signed.
@@ -127245,13 +127791,16 @@ var CodeGenerator = class _CodeGenerator {
127245
127791
  /**
127246
127792
  * Issue #477: Generate expression with a specific expected type context.
127247
127793
  * Used by return statements to resolve unqualified enum values.
127794
+ * Note: Uses explicit save/restore (not withExpectedType) to support null values.
127248
127795
  */
127249
127796
  generateExpressionWithExpectedType(ctx, expectedType) {
127250
- const savedExpectedType = CodeGenState.expectedType;
127797
+ const saved = CodeGenState.expectedType;
127251
127798
  CodeGenState.expectedType = expectedType;
127252
- const result = this.generateExpression(ctx);
127253
- CodeGenState.expectedType = savedExpectedType;
127254
- return result;
127799
+ try {
127800
+ return this.generateExpression(ctx);
127801
+ } finally {
127802
+ CodeGenState.expectedType = saved;
127803
+ }
127255
127804
  }
127256
127805
  /**
127257
127806
  * Generate type translation (C-Next type -> C type).
@@ -128240,6 +128789,22 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
128240
128789
  isFloatShadowCurrent(shadowName) {
128241
128790
  return CodeGenState.floatShadowCurrent.has(shadowName);
128242
128791
  }
128792
+ /**
128793
+ * Issue #948: Check if a type is an opaque (forward-declared) struct type.
128794
+ * Opaque types can only be used as pointers (cannot be instantiated).
128795
+ * Part of IOrchestrator interface.
128796
+ */
128797
+ isOpaqueType(typeName) {
128798
+ return CodeGenState.isOpaqueType(typeName);
128799
+ }
128800
+ /**
128801
+ * Issue #948: Mark a scope variable as having an opaque type.
128802
+ * These variables are generated as pointers with NULL initialization.
128803
+ * Part of IOrchestrator interface.
128804
+ */
128805
+ markOpaqueScopeVariable(qualifiedName) {
128806
+ CodeGenState.markOpaqueScopeVariable(qualifiedName);
128807
+ }
128243
128808
  // ===========================================================================
128244
128809
  // End IOrchestrator Implementation
128245
128810
  // ===========================================================================
@@ -128596,15 +129161,17 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
128596
129161
  return DEFAULT_TARGET2;
128597
129162
  }
128598
129163
  /**
128599
- * ADR-010: Transform #include directives, converting .cnx to .h
129164
+ * ADR-010: Transform #include directives, converting .cnx to .h or .hpp
128600
129165
  * ADR-053 A5: Delegates to IncludeGenerator
128601
129166
  * Issue #349: Now passes includeDirs and inputs for angle-bracket resolution
129167
+ * Issue #941: Now passes cppMode for .hpp extension in C++ mode
128602
129168
  */
128603
129169
  transformIncludeDirective(includeText) {
128604
129170
  return includeTransformIncludeDirective(includeText, {
128605
129171
  sourcePath: CodeGenState.sourcePath,
128606
129172
  includeDirs: CodeGenState.includeDirs,
128607
- inputs: CodeGenState.inputs
129173
+ inputs: CodeGenState.inputs,
129174
+ cppMode: CodeGenState.cppMode
128608
129175
  });
128609
129176
  }
128610
129177
  // Issue #63: validateIncludeNotImplementationFile moved to TypeValidator
@@ -129342,19 +129909,20 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
129342
129909
  const structFieldTypes = CodeGenState.symbolTable?.getStructFieldTypes(typeName);
129343
129910
  const fields = fieldList.fieldInitializer().map((field) => {
129344
129911
  const fieldName = field.IDENTIFIER().getText();
129345
- const savedExpectedType = CodeGenState.expectedType;
129912
+ let fieldType;
129346
129913
  if (structFieldTypes?.has(fieldName)) {
129347
- let fieldType = structFieldTypes.get(fieldName);
129914
+ fieldType = structFieldTypes.get(fieldName);
129348
129915
  if (fieldType.includes("_")) {
129349
129916
  const parts = fieldType.split("_");
129350
129917
  if (parts.length > 1 && this.isCppScopeSymbol(parts[0])) {
129351
129918
  fieldType = parts.join("::");
129352
129919
  }
129353
129920
  }
129354
- CodeGenState.expectedType = fieldType;
129355
129921
  }
129356
- const value = this.generateExpression(field.expression());
129357
- CodeGenState.expectedType = savedExpectedType;
129922
+ const value = CodeGenState.withExpectedType(
129923
+ fieldType,
129924
+ () => this.generateExpression(field.expression())
129925
+ );
129358
129926
  return { fieldName, value };
129359
129927
  });
129360
129928
  if (isCppClass) {
@@ -129869,18 +130437,20 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
129869
130437
  // ADR-001: <- becomes = in C, with compound assignment operators
129870
130438
  generateAssignment(ctx) {
129871
130439
  const targetCtx = ctx.assignmentTarget();
129872
- const savedExpectedType = CodeGenState.expectedType;
129873
130440
  const savedAssignmentContext = { ...CodeGenState.assignmentContext };
129874
130441
  const resolved = AssignmentExpectedTypeResolver_default.resolve(targetCtx);
129875
- if (resolved.expectedType) {
129876
- CodeGenState.expectedType = resolved.expectedType;
129877
- }
129878
130442
  if (resolved.assignmentContext) {
129879
130443
  CodeGenState.assignmentContext = resolved.assignmentContext;
129880
130444
  }
129881
- const value = this.generateExpression(ctx.expression());
129882
- CodeGenState.expectedType = savedExpectedType;
129883
- CodeGenState.assignmentContext = savedAssignmentContext;
130445
+ let value;
130446
+ try {
130447
+ value = CodeGenState.withExpectedType(
130448
+ resolved.expectedType,
130449
+ () => this.generateExpression(ctx.expression())
130450
+ );
130451
+ } finally {
130452
+ CodeGenState.assignmentContext = savedAssignmentContext;
130453
+ }
129884
130454
  const operatorCtx = ctx.assignmentOperator();
129885
130455
  const cnextOp = operatorCtx.getText();
129886
130456
  const cOp = ASSIGNMENT_OPERATOR_MAP2[cnextOp] || "=";
@@ -130090,7 +130660,11 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
130090
130660
  * @returns The qualified enum member access, or null if not an enum member
130091
130661
  */
130092
130662
  _resolveUnqualifiedEnumMember(id) {
130093
- if (CodeGenState.expectedType && CodeGenState.symbols.knownEnums.has(CodeGenState.expectedType)) {
130663
+ if (CodeGenState.suppressBareEnumResolution) {
130664
+ } else if (
130665
+ // Type-aware resolution: check only the expected enum type
130666
+ CodeGenState.expectedType && CodeGenState.symbols.knownEnums.has(CodeGenState.expectedType)
130667
+ ) {
130094
130668
  const members = CodeGenState.symbols.enumMembers.get(
130095
130669
  CodeGenState.expectedType
130096
130670
  );
@@ -130197,7 +130771,9 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
130197
130771
  const minComparison = minValue === "0" ? `0.0${floatSuffix}` : `((${floatCastType})${minValue})`;
130198
130772
  const maxComparison = `((${floatCastType})${maxValue})`;
130199
130773
  const finalCast = CppModeHelper_default.cast(targetType, `(${expr})`);
130200
- return `((${expr}) > ${maxComparison} ? ${maxValue} : (${expr}) < ${minComparison} ? ${minValue} : ${finalCast})`;
130774
+ const castMax = CppModeHelper_default.cast(targetType, maxValue);
130775
+ const castMin = minValue === "0" ? "0" : CppModeHelper_default.cast(targetType, minValue);
130776
+ return `((${expr}) > ${maxComparison} ? ${castMax} : (${expr}) < ${minComparison} ? ${castMin} : ${finalCast})`;
130201
130777
  }
130202
130778
  /**
130203
130779
  * ADR-023: Generate sizeof expression
@@ -130888,15 +131464,16 @@ var HeaderGeneratorUtils = class _HeaderGeneratorUtils {
130888
131464
  }
130889
131465
  if (options.userIncludes && options.userIncludes.length > 0) {
130890
131466
  for (const include of options.userIncludes) {
130891
- const transformedInclude = options.cppMode ? include.replace(/\.h"/, '.hpp"').replace(/\.h>/, ".hpp>") : include;
130892
- lines.push(transformedInclude);
131467
+ lines.push(include);
131468
+ }
131469
+ }
131470
+ const userIncludeSet = new Set(options.userIncludes ?? []);
131471
+ if (options.cppMode && options.userIncludes) {
131472
+ for (const inc of options.userIncludes) {
131473
+ const hVersion = inc.replace(/\.hpp"/, '.h"').replace(/\.hpp>/, ".h>");
131474
+ userIncludeSet.add(hVersion);
130893
131475
  }
130894
131476
  }
130895
- const userIncludeSet = new Set(
130896
- options.userIncludes?.map(
130897
- (inc) => options.cppMode ? inc.replace(/\.h"/, '.hpp"').replace(/\.h>/, ".hpp>") : inc
130898
- ) ?? []
130899
- );
130900
131477
  for (const directive of headersToInclude) {
130901
131478
  if (!userIncludeSet.has(directive)) {
130902
131479
  lines.push(directive);
@@ -131274,18 +131851,21 @@ var IncludeExtractor = class {
131274
131851
  /**
131275
131852
  * Extract user includes from a parsed C-Next program.
131276
131853
  *
131277
- * Extracts #include directives for .cnx files and transforms them to .h includes.
131854
+ * Extracts #include directives for .cnx files and transforms them to .h or .hpp includes.
131855
+ * Issue #941: Uses .hpp extension when cppMode is true.
131278
131856
  * This enables cross-file type definitions in generated headers.
131279
131857
  *
131280
131858
  * @param tree The parsed C-Next program
131281
- * @returns Array of transformed include strings (e.g., '#include "types.h"')
131859
+ * @param cppMode Whether to use .hpp extension (C++ mode)
131860
+ * @returns Array of transformed include strings (e.g., '#include "types.h"' or '#include "types.hpp"')
131282
131861
  */
131283
- static collectUserIncludes(tree) {
131862
+ static collectUserIncludes(tree, cppMode = false) {
131284
131863
  const userIncludes = [];
131864
+ const ext = cppMode ? ".hpp" : ".h";
131285
131865
  for (const includeDir of tree.includeDirective()) {
131286
131866
  const includeText = includeDir.getText();
131287
131867
  if (includeText.includes(".cnx")) {
131288
- const transformedInclude = includeText.replace(/\.cnx"/, '.h"').replace(/\.cnx>/, ".h>");
131868
+ const transformedInclude = includeText.replace(/\.cnx"/, `${ext}"`).replace(/\.cnx>/, `${ext}>`);
131289
131869
  userIncludes.push(transformedInclude);
131290
131870
  }
131291
131871
  }
@@ -132386,6 +132966,7 @@ var TSymbolInfoAdapter = class _TSymbolInfoAdapter {
132386
132966
  const registerMemberCTypes = /* @__PURE__ */ new Map();
132387
132967
  const scopePrivateConstValues = /* @__PURE__ */ new Map();
132388
132968
  const functionReturnTypes = /* @__PURE__ */ new Map();
132969
+ const opaqueTypes = /* @__PURE__ */ new Set();
132389
132970
  for (const symbol of symbols) {
132390
132971
  switch (symbol.kind) {
132391
132972
  case "struct":
@@ -132473,6 +133054,8 @@ var TSymbolInfoAdapter = class _TSymbolInfoAdapter {
132473
133054
  scopePrivateConstValues,
132474
133055
  // Function return types
132475
133056
  functionReturnTypes,
133057
+ // Issue #948: Opaque types
133058
+ opaqueTypes,
132476
133059
  // Methods
132477
133060
  getSingleFunctionForVariable: (scopeName, varName) => _TSymbolInfoAdapter.getSingleFunctionForVariable(
132478
133061
  scopeVariableUsage,
@@ -132670,42 +133253,35 @@ var TSymbolInfoAdapter = class _TSymbolInfoAdapter {
132670
133253
  );
132671
133254
  }
132672
133255
  return {
132673
- // Type sets - knownEnums and knownScopes are merged
133256
+ ...base,
132674
133257
  knownScopes: mergedKnownScopes,
132675
- knownStructs: base.knownStructs,
132676
133258
  knownEnums: mergedKnownEnums,
132677
- knownBitmaps: base.knownBitmaps,
132678
- knownRegisters: base.knownRegisters,
132679
- // Scope info
132680
- scopeMembers: base.scopeMembers,
132681
- scopeMemberVisibility: base.scopeMemberVisibility,
132682
- scopeVariableUsage: base.scopeVariableUsage,
132683
- // Struct info
132684
- structFields: base.structFields,
132685
- structFieldArrays: base.structFieldArrays,
132686
- structFieldDimensions: base.structFieldDimensions,
132687
- // Enum info - merged
132688
133259
  enumMembers: mergedEnumMembers,
132689
- // Bitmap info
132690
- bitmapFields: base.bitmapFields,
132691
- bitmapBackingType: base.bitmapBackingType,
132692
- bitmapBitWidth: base.bitmapBitWidth,
132693
- // Register info
132694
- scopedRegisters: base.scopedRegisters,
132695
- registerMemberAccess: base.registerMemberAccess,
132696
- registerMemberTypes: base.registerMemberTypes,
132697
- registerBaseAddresses: base.registerBaseAddresses,
132698
- registerMemberOffsets: base.registerMemberOffsets,
132699
- registerMemberCTypes: base.registerMemberCTypes,
132700
- // Private const values
132701
- scopePrivateConstValues: base.scopePrivateConstValues,
132702
- // Function return types - merged
132703
- functionReturnTypes: mergedFunctionReturnTypes,
132704
- // Methods - delegate to base's implementation
132705
- getSingleFunctionForVariable: base.getSingleFunctionForVariable,
132706
- hasPublicSymbols: base.hasPublicSymbols
133260
+ functionReturnTypes: mergedFunctionReturnTypes
132707
133261
  };
132708
133262
  }
133263
+ /**
133264
+ * Issue #948: Merge opaque types from an external source (e.g., SymbolTable)
133265
+ * into an existing ICodeGenSymbols.
133266
+ *
133267
+ * Opaque types are forward-declared struct types (like `typedef struct _foo foo;`)
133268
+ * that come from C headers and need to be tracked for correct scope variable
133269
+ * generation (as pointers with NULL initialization).
133270
+ *
133271
+ * @param base The ICodeGenSymbols from the current file
133272
+ * @param externalOpaqueTypes Array of opaque type names from external sources
133273
+ * @returns New ICodeGenSymbols with merged opaque types
133274
+ */
133275
+ static mergeOpaqueTypes(base, externalOpaqueTypes) {
133276
+ if (externalOpaqueTypes.length === 0) {
133277
+ return base;
133278
+ }
133279
+ const mergedOpaqueTypes = new Set(base.opaqueTypes);
133280
+ for (const typeName of externalOpaqueTypes) {
133281
+ mergedOpaqueTypes.add(typeName);
133282
+ }
133283
+ return { ...base, opaqueTypes: mergedOpaqueTypes };
133284
+ }
132709
133285
  };
132710
133286
  var TSymbolInfoAdapter_default = TSymbolInfoAdapter;
132711
133287
 
@@ -133092,6 +133668,18 @@ var DeclaratorUtils = class _DeclaratorUtils {
133092
133668
  }
133093
133669
  return void 0;
133094
133670
  }
133671
+ /**
133672
+ * Extract the first declarator name from an init-declarator-list.
133673
+ * For "typedef struct _widget_t widget_t;", this returns "widget_t".
133674
+ * Used for Issue #948 opaque type detection.
133675
+ */
133676
+ static extractFirstDeclaratorName(initDeclList) {
133677
+ const initDeclarators = initDeclList.initDeclarator?.();
133678
+ if (!initDeclarators || initDeclarators.length === 0) return void 0;
133679
+ const firstDeclarator = initDeclarators[0].declarator?.();
133680
+ if (!firstDeclarator) return void 0;
133681
+ return _DeclaratorUtils.extractDeclaratorName(firstDeclarator) ?? void 0;
133682
+ }
133095
133683
  };
133096
133684
  var DeclaratorUtils_default = DeclaratorUtils;
133097
133685
 
@@ -133113,6 +133701,7 @@ var StructCollector2 = class _StructCollector {
133113
133701
  const name = identifier?.getText() || typedefName;
133114
133702
  if (!name) return null;
133115
133703
  const isUnion = structSpec.structOrUnion()?.getText() === "union";
133704
+ const hasBody = structSpec.structDeclarationList() !== null;
133116
133705
  const fields = _StructCollector.collectFields(
133117
133706
  structSpec,
133118
133707
  name,
@@ -133120,8 +133709,16 @@ var StructCollector2 = class _StructCollector {
133120
133709
  warnings
133121
133710
  );
133122
133711
  const needsStructKeyword = Boolean(identifier && !isTypedef);
133123
- if (symbolTable && needsStructKeyword) {
133124
- symbolTable.markNeedsStructKeyword(name);
133712
+ if (symbolTable) {
133713
+ _StructCollector.updateSymbolTable(
133714
+ symbolTable,
133715
+ name,
133716
+ needsStructKeyword,
133717
+ hasBody,
133718
+ isTypedef,
133719
+ typedefName,
133720
+ identifier?.getText()
133721
+ );
133125
133722
  }
133126
133723
  return {
133127
133724
  kind: "struct",
@@ -133135,6 +133732,44 @@ var StructCollector2 = class _StructCollector {
133135
133732
  fields: fields.size > 0 ? fields : void 0
133136
133733
  };
133137
133734
  }
133735
+ /**
133736
+ * Update symbol table with struct metadata.
133737
+ * Extracted to reduce cognitive complexity of collect().
133738
+ */
133739
+ static updateSymbolTable(symbolTable, name, needsStructKeyword, hasBody, isTypedef, typedefName, structTag) {
133740
+ if (needsStructKeyword) {
133741
+ symbolTable.markNeedsStructKeyword(name);
133742
+ }
133743
+ if (isTypedef && !hasBody && typedefName) {
133744
+ symbolTable.markOpaqueType(typedefName);
133745
+ if (structTag) {
133746
+ symbolTable.registerStructTagAlias(structTag, typedefName);
133747
+ }
133748
+ }
133749
+ if (hasBody) {
133750
+ _StructCollector.unmarkOpaqueTypesOnDefinition(
133751
+ symbolTable,
133752
+ structTag,
133753
+ typedefName
133754
+ );
133755
+ }
133756
+ }
133757
+ /**
133758
+ * Unmark opaque types when a full struct definition is encountered.
133759
+ * Handles: typedef struct _foo foo; struct _foo { ... };
133760
+ */
133761
+ static unmarkOpaqueTypesOnDefinition(symbolTable, structTag, typedefName) {
133762
+ if (structTag) {
133763
+ symbolTable.unmarkOpaqueType(structTag);
133764
+ const typedefAlias = symbolTable.getStructTagAlias(structTag);
133765
+ if (typedefAlias) {
133766
+ symbolTable.unmarkOpaqueType(typedefAlias);
133767
+ }
133768
+ }
133769
+ if (typedefName) {
133770
+ symbolTable.unmarkOpaqueType(typedefName);
133771
+ }
133772
+ }
133138
133773
  /**
133139
133774
  * Collect fields from a struct/union definition.
133140
133775
  */
@@ -133271,6 +133906,15 @@ var FunctionCollector2 = class _FunctionCollector {
133271
133906
  isArray: p.isArray
133272
133907
  }));
133273
133908
  }
133909
+ /**
133910
+ * Resolve return type, appending '*' if declarator has a pointer.
133911
+ * Issue #895 Bug B / Issue #945: C grammar puts pointer before directDeclarator
133912
+ * (e.g., `widget_t *func()` has declarator.pointer() !== null)
133913
+ */
133914
+ static _resolveReturnType(baseType, declarator) {
133915
+ const hasPointer = declarator.pointer() !== null;
133916
+ return hasPointer ? `${baseType}*` : baseType;
133917
+ }
133274
133918
  /**
133275
133919
  * Collect a function symbol from a function definition.
133276
133920
  *
@@ -133284,7 +133928,11 @@ var FunctionCollector2 = class _FunctionCollector {
133284
133928
  if (!name) return null;
133285
133929
  const line = funcDef.start?.line ?? 0;
133286
133930
  const declSpecs = funcDef.declarationSpecifiers();
133287
- const returnType = declSpecs ? DeclaratorUtils_default.extractTypeFromDeclSpecs(declSpecs) : "int";
133931
+ const baseType = declSpecs ? DeclaratorUtils_default.extractTypeFromDeclSpecs(declSpecs) : "int";
133932
+ const returnType = _FunctionCollector._resolveReturnType(
133933
+ baseType,
133934
+ declarator
133935
+ );
133288
133936
  const parameters = _FunctionCollector._mapParameters(
133289
133937
  DeclaratorUtils_default.extractFunctionParameters(declarator)
133290
133938
  );
@@ -133314,8 +133962,10 @@ var FunctionCollector2 = class _FunctionCollector {
133314
133962
  const parameters = _FunctionCollector._mapParameters(
133315
133963
  DeclaratorUtils_default.extractFunctionParameters(declarator)
133316
133964
  );
133317
- const hasPointer = declarator.pointer() !== null;
133318
- const returnType = hasPointer ? `${baseType}*` : baseType;
133965
+ const returnType = _FunctionCollector._resolveReturnType(
133966
+ baseType,
133967
+ declarator
133968
+ );
133319
133969
  return {
133320
133970
  kind: "function",
133321
133971
  name,
@@ -133458,39 +134108,33 @@ var CResolver = class _CResolver {
133458
134108
  const line = decl.start?.line ?? 0;
133459
134109
  const isTypedef = DeclaratorUtils_default.hasStorageClass(declSpecs, "typedef");
133460
134110
  const isExtern = DeclaratorUtils_default.hasStorageClass(declSpecs, "extern");
134111
+ const ctx = {
134112
+ sourceFile,
134113
+ line,
134114
+ isTypedef,
134115
+ isExtern,
134116
+ symbols
134117
+ };
133461
134118
  const structSpec = DeclaratorUtils_default.findStructOrUnionSpecifier(declSpecs);
133462
134119
  if (structSpec) {
133463
- const typedefName = isTypedef ? DeclaratorUtils_default.extractTypedefNameFromSpecs(declSpecs) : void 0;
133464
- const structSymbol = StructCollector_default2.collect(
134120
+ _CResolver.collectStructSymbol(
133465
134121
  structSpec,
133466
- sourceFile,
133467
- line,
134122
+ decl,
134123
+ declSpecs,
134124
+ ctx,
133468
134125
  symbolTable,
133469
- typedefName,
133470
- isTypedef,
133471
134126
  warnings
133472
134127
  );
133473
- if (structSymbol) {
133474
- symbols.push(structSymbol);
133475
- }
133476
134128
  }
133477
134129
  const enumSpec = DeclaratorUtils_default.findEnumSpecifier(declSpecs);
133478
134130
  if (enumSpec) {
133479
- const enumResult = EnumCollector_default2.collect(enumSpec, sourceFile, line);
133480
- if (enumResult) {
133481
- symbols.push(enumResult.enum);
133482
- for (const member of enumResult.members) {
133483
- symbols.push(member);
133484
- }
133485
- }
134131
+ _CResolver.collectEnumSymbols(
134132
+ enumSpec,
134133
+ ctx.sourceFile,
134134
+ ctx.line,
134135
+ ctx.symbols
134136
+ );
133486
134137
  }
133487
- const ctx = {
133488
- sourceFile,
133489
- line,
133490
- isTypedef,
133491
- isExtern,
133492
- symbols
133493
- };
133494
134138
  const initDeclList = decl.initDeclaratorList();
133495
134139
  if (initDeclList) {
133496
134140
  const baseType = DeclaratorUtils_default.extractTypeFromDeclSpecs(declSpecs);
@@ -133504,6 +134148,49 @@ var CResolver = class _CResolver {
133504
134148
  );
133505
134149
  }
133506
134150
  }
134151
+ /**
134152
+ * Collect struct symbol from a struct specifier.
134153
+ * Extracted to reduce cognitive complexity of collectDeclaration().
134154
+ */
134155
+ static collectStructSymbol(structSpec, decl, declSpecs, ctx, symbolTable, warnings) {
134156
+ const typedefName = ctx.isTypedef ? _CResolver.extractTypedefName(decl, declSpecs) : void 0;
134157
+ const structSymbol = StructCollector_default2.collect(
134158
+ structSpec,
134159
+ ctx.sourceFile,
134160
+ ctx.line,
134161
+ symbolTable,
134162
+ typedefName,
134163
+ ctx.isTypedef,
134164
+ warnings
134165
+ );
134166
+ if (structSymbol) {
134167
+ ctx.symbols.push(structSymbol);
134168
+ }
134169
+ }
134170
+ /**
134171
+ * Extract typedef name from declaration.
134172
+ * First try from init-declarator-list, then fall back to specifiers.
134173
+ */
134174
+ static extractTypedefName(decl, declSpecs) {
134175
+ const initDeclList = decl.initDeclaratorList();
134176
+ if (initDeclList) {
134177
+ const name = DeclaratorUtils_default.extractFirstDeclaratorName(initDeclList);
134178
+ if (name) return name;
134179
+ }
134180
+ return DeclaratorUtils_default.extractTypedefNameFromSpecs(declSpecs);
134181
+ }
134182
+ /**
134183
+ * Collect enum symbols from an enum specifier.
134184
+ * Extracted to reduce cognitive complexity of collectDeclaration().
134185
+ */
134186
+ static collectEnumSymbols(enumSpec, sourceFile, line, symbols) {
134187
+ const enumResult = EnumCollector_default2.collect(enumSpec, sourceFile, line);
134188
+ if (!enumResult) return;
134189
+ symbols.push(enumResult.enum);
134190
+ for (const member of enumResult.members) {
134191
+ symbols.push(member);
134192
+ }
134193
+ }
133507
134194
  /**
133508
134195
  * Collect symbols from init declarator list.
133509
134196
  */
@@ -137697,6 +138384,9 @@ var IndexTypeListener = class extends CNextListener {
137697
138384
  if (TypeConstants_default.UNSIGNED_INDEX_TYPES.includes(resolvedType)) {
137698
138385
  continue;
137699
138386
  }
138387
+ if (CodeGenState.isKnownEnum(resolvedType)) {
138388
+ continue;
138389
+ }
137700
138390
  const { line, column } = ParserUtils_default.getPosition(ctx);
137701
138391
  this.analyzer.addError(line, column, "E0852", resolvedType);
137702
138392
  return;
@@ -137786,6 +138476,10 @@ var IndexTypeListener = class extends CNextListener {
137786
138476
  if (TypeConstants_default.SIGNED_TYPES.includes(currentType)) {
137787
138477
  return "bool";
137788
138478
  }
138479
+ const strippedType = currentType.replace(/\[[^\]]*\]$/, "");
138480
+ if (strippedType !== currentType) {
138481
+ return strippedType;
138482
+ }
137789
138483
  return currentType;
137790
138484
  }
137791
138485
  if (op.LPAREN()) {
@@ -138186,7 +138880,7 @@ var CacheKeyGenerator_default = CacheKeyGenerator;
138186
138880
 
138187
138881
  // src/utils/cache/CacheManager.ts
138188
138882
  var defaultFs7 = NodeFileSystem_default.instance;
138189
- var CACHE_VERSION = 4;
138883
+ var CACHE_VERSION = 5;
138190
138884
  var TRANSPILER_VERSION = package_default.version;
138191
138885
  var CacheManager = class {
138192
138886
  projectRoot;
@@ -138286,14 +138980,15 @@ var CacheManager = class {
138286
138980
  symbols,
138287
138981
  structFields,
138288
138982
  needsStructKeyword: cachedEntry.needsStructKeyword ?? [],
138289
- enumBitWidth
138983
+ enumBitWidth,
138984
+ opaqueTypes: cachedEntry.opaqueTypes ?? []
138290
138985
  };
138291
138986
  }
138292
138987
  /**
138293
138988
  * Store symbols and struct fields for a file
138294
138989
  * ADR-055 Phase 7: Takes ISerializedSymbol[] directly
138295
138990
  */
138296
- setSymbols(filePath, symbols, structFields, needsStructKeyword, enumBitWidth) {
138991
+ setSymbols(filePath, symbols, structFields, needsStructKeyword, enumBitWidth, opaqueTypes) {
138297
138992
  if (!this.cache) return;
138298
138993
  let cacheKey;
138299
138994
  try {
@@ -138321,7 +139016,8 @@ var CacheManager = class {
138321
139016
  symbols: serializedSymbols,
138322
139017
  structFields: serializedFields,
138323
139018
  needsStructKeyword,
138324
- enumBitWidth: serializedEnumBitWidth
139019
+ enumBitWidth: serializedEnumBitWidth,
139020
+ opaqueTypes
138325
139021
  };
138326
139022
  this.cache.setKey(filePath, entry);
138327
139023
  this.dirty = true;
@@ -138349,12 +139045,14 @@ var CacheManager = class {
138349
139045
  filePath,
138350
139046
  symbolTable
138351
139047
  );
139048
+ const opaqueTypes = symbolTable.getAllOpaqueTypes();
138352
139049
  this.setSymbols(
138353
139050
  filePath,
138354
139051
  symbols,
138355
139052
  structFields,
138356
139053
  needsStructKeyword,
138357
- enumBitWidth
139054
+ enumBitWidth,
139055
+ opaqueTypes
138358
139056
  );
138359
139057
  }
138360
139058
  /**
@@ -138797,7 +139495,7 @@ var Transpiler = class {
138797
139495
  * Stage 6: Generate headers (per-file)
138798
139496
  */
138799
139497
  async _executePipeline(input, result) {
138800
- this._collectAllHeaderSymbols(input.headerFiles, result);
139498
+ await this._collectAllHeaderSymbols(input.headerFiles, result);
138801
139499
  CodeGenState.buildExternalStructFields();
138802
139500
  if (!this._collectAllCNextSymbolsFromPipeline(input.cnextFiles, result)) {
138803
139501
  return;
@@ -138906,6 +139604,13 @@ var Transpiler = class {
138906
139604
  externalEnumSources
138907
139605
  );
138908
139606
  }
139607
+ const externalOpaqueTypes = CodeGenState.symbolTable.getAllOpaqueTypes();
139608
+ if (externalOpaqueTypes.length > 0) {
139609
+ symbolInfo = TSymbolInfoAdapter_default.mergeOpaqueTypes(
139610
+ symbolInfo,
139611
+ externalOpaqueTypes
139612
+ );
139613
+ }
138909
139614
  CodeGenState.symbols = symbolInfo;
138910
139615
  const analyzerErrors = runAnalyzers_default(tree, tokenStream);
138911
139616
  if (analyzerErrors.length > 0) {
@@ -138923,7 +139628,10 @@ var Transpiler = class {
138923
139628
  cppMode: this.cppDetected,
138924
139629
  symbolInfo
138925
139630
  });
138926
- const userIncludes = IncludeExtractor_default.collectUserIncludes(tree);
139631
+ const userIncludes = IncludeExtractor_default.collectUserIncludes(
139632
+ tree,
139633
+ this.cppDetected
139634
+ );
138927
139635
  const passByValue = this.codeGenerator.getPassByValueParams();
138928
139636
  const passByValueCopy = MapUtils_default.deepCopyStringSetMap(passByValue);
138929
139637
  this.state.setSymbolInfo(sourcePath, symbolInfo);
@@ -139076,11 +139784,12 @@ var Transpiler = class {
139076
139784
  }
139077
139785
  /**
139078
139786
  * Stage 2: Collect symbols from all C/C++ headers
139787
+ * Issue #945: Made async for preprocessing support.
139079
139788
  */
139080
- _collectAllHeaderSymbols(headerFiles, result) {
139789
+ async _collectAllHeaderSymbols(headerFiles, result) {
139081
139790
  for (const file of headerFiles) {
139082
139791
  try {
139083
- this.doCollectHeaderSymbols(file);
139792
+ await this.doCollectHeaderSymbols(file);
139084
139793
  result.filesProcessed++;
139085
139794
  } catch (err) {
139086
139795
  this.warnings.push(`Failed to process header ${file.path}: ${err}`);
@@ -139359,15 +140068,16 @@ var Transpiler = class {
139359
140068
  /**
139360
140069
  * Stage 2: Collect symbols from a single C/C++ header
139361
140070
  * Issue #592: Recursive include processing moved to IncludeResolver.resolveHeadersTransitively()
140071
+ * Issue #945: Added preprocessing support for conditional compilation
139362
140072
  * SonarCloud S3776: Refactored to use helper methods for reduced complexity.
139363
140073
  */
139364
- doCollectHeaderSymbols(file) {
140074
+ async doCollectHeaderSymbols(file) {
139365
140075
  const absolutePath = resolve12(file.path);
139366
140076
  this.state.markHeaderProcessed(absolutePath);
139367
140077
  if (this.tryRestoreFromCache(file)) {
139368
140078
  return;
139369
140079
  }
139370
- const content = this.fs.readFile(file.path);
140080
+ const content = await this.getHeaderContent(file);
139371
140081
  this.parseHeaderFile(file, content);
139372
140082
  if (this.config.debugMode) {
139373
140083
  const symbols = CodeGenState.symbolTable.getSymbolsByFile(file.path);
@@ -139398,9 +140108,51 @@ var Transpiler = class {
139398
140108
  cached.needsStructKeyword
139399
140109
  );
139400
140110
  CodeGenState.symbolTable.restoreEnumBitWidths(cached.enumBitWidth);
140111
+ CodeGenState.symbolTable.restoreOpaqueTypes(cached.opaqueTypes);
139401
140112
  this.detectCppFromFileType(file);
139402
140113
  return true;
139403
140114
  }
140115
+ /**
140116
+ * Get header content, optionally preprocessed.
140117
+ * Issue #945: Evaluates #if/#ifdef directives using system preprocessor.
140118
+ *
140119
+ * Only preprocesses when necessary to avoid side effects from full expansion.
140120
+ * Preprocessing is needed when the file has conditional compilation patterns
140121
+ * like #if MACRO != 0 that require expression evaluation.
140122
+ */
140123
+ async getHeaderContent(file) {
140124
+ const rawContent = this.fs.readFile(file.path);
140125
+ if (this.config.preprocess === false) {
140126
+ return rawContent;
140127
+ }
140128
+ if (!this.preprocessor.isAvailable()) {
140129
+ return rawContent;
140130
+ }
140131
+ if (!this.needsConditionalPreprocessing(rawContent)) {
140132
+ return rawContent;
140133
+ }
140134
+ const result = await this.preprocessor.preprocess(file.path, {
140135
+ defines: this.config.defines,
140136
+ includePaths: this.config.includeDirs,
140137
+ keepLineDirectives: false
140138
+ // We don't need line mappings for symbol collection
140139
+ });
140140
+ if (!result.success) {
140141
+ this.warnings.push(
140142
+ `Preprocessing failed for ${file.path}: ${result.error}. Using raw content.`
140143
+ );
140144
+ return rawContent;
140145
+ }
140146
+ return result.content;
140147
+ }
140148
+ /**
140149
+ * Check if a header file needs conditional preprocessing.
140150
+ * Issue #945: Only preprocess files with #if expressions that need evaluation.
140151
+ */
140152
+ needsConditionalPreprocessing(content) {
140153
+ const ifExpressionPattern = /#(?:if|elif)\s+(?!defined\s*\()(?![01]\s*(?:$|\n|\/\*|\/\/))\w+/m;
140154
+ return ifExpressionPattern.test(content);
140155
+ }
139404
140156
  /**
139405
140157
  * Restore cached symbols to the symbol table.
139406
140158
  * ADR-055 Phase 7: Converts ISerializedSymbol[] from cache to typed symbols.