c-next 0.2.9 → 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 (60) hide show
  1. package/dist/index.js +814 -206
  2. package/dist/index.js.map +4 -4
  3. package/package.json +1 -1
  4. package/src/transpiler/Transpiler.ts +97 -7
  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/analysis/ArrayIndexTypeAnalyzer.ts +12 -1
  8. package/src/transpiler/logic/analysis/__tests__/ArrayIndexTypeAnalyzer.test.ts +172 -0
  9. package/src/transpiler/logic/symbols/SymbolTable.ts +84 -0
  10. package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +43 -0
  11. package/src/transpiler/logic/symbols/__tests__/TransitiveEnumCollector.test.ts +1 -0
  12. package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +98 -1
  13. package/src/transpiler/logic/symbols/c/collectors/FunctionCollector.ts +23 -5
  14. package/src/transpiler/logic/symbols/c/collectors/StructCollector.ts +69 -2
  15. package/src/transpiler/logic/symbols/c/index.ts +85 -30
  16. package/src/transpiler/logic/symbols/c/utils/DeclaratorUtils.ts +18 -0
  17. package/src/transpiler/logic/symbols/cnext/__tests__/TSymbolInfoAdapter.test.ts +90 -0
  18. package/src/transpiler/logic/symbols/cnext/adapters/TSymbolInfoAdapter.ts +40 -39
  19. package/src/transpiler/output/codegen/CodeGenerator.ts +23 -1
  20. package/src/transpiler/output/codegen/TypeResolver.ts +14 -0
  21. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +19 -14
  22. package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +7 -7
  23. package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +1 -0
  24. package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +27 -4
  25. package/src/transpiler/output/codegen/assignment/AssignmentKind.ts +6 -0
  26. package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +73 -0
  27. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +4 -0
  28. package/src/transpiler/output/codegen/assignment/handlers/SimpleHandler.ts +92 -0
  29. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +5 -2
  30. package/src/transpiler/output/codegen/assignment/handlers/__tests__/handlerTestUtils.ts +1 -0
  31. package/src/transpiler/output/codegen/generators/IOrchestrator.ts +14 -0
  32. package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +17 -2
  33. package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +49 -0
  34. package/src/transpiler/output/codegen/generators/expressions/AccessExprGenerator.ts +17 -5
  35. package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +5 -0
  36. package/src/transpiler/output/codegen/generators/expressions/LiteralGenerator.ts +16 -0
  37. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +41 -5
  38. package/src/transpiler/output/codegen/generators/expressions/UnaryExprGenerator.ts +25 -1
  39. package/src/transpiler/output/codegen/generators/statements/AtomicGenerator.ts +2 -17
  40. package/src/transpiler/output/codegen/helpers/ArrayAccessHelper.ts +3 -0
  41. package/src/transpiler/output/codegen/helpers/BitRangeHelper.ts +19 -3
  42. package/src/transpiler/output/codegen/helpers/NarrowingCastHelper.ts +191 -0
  43. package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +35 -4
  44. package/src/transpiler/output/codegen/helpers/__tests__/ArrayAccessHelper.test.ts +131 -1
  45. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +1 -0
  46. package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +1 -0
  47. package/src/transpiler/output/codegen/helpers/__tests__/BitRangeHelper.test.ts +53 -2
  48. package/src/transpiler/output/codegen/helpers/__tests__/FunctionContextManager.test.ts +1 -0
  49. package/src/transpiler/output/codegen/helpers/__tests__/NarrowingCastHelper.test.ts +159 -0
  50. package/src/transpiler/output/codegen/helpers/__tests__/TypeRegistrationEngine.test.ts +1 -0
  51. package/src/transpiler/output/codegen/types/COMPOUND_TO_BINARY.ts +21 -0
  52. package/src/transpiler/output/codegen/types/IArrayAccessInfo.ts +2 -0
  53. package/src/transpiler/state/CodeGenState.ts +49 -0
  54. package/src/transpiler/state/__tests__/CodeGenState.test.ts +53 -0
  55. package/src/transpiler/state/__tests__/TranspilerState.test.ts +1 -0
  56. package/src/transpiler/types/ICachedFileEntry.ts +2 -0
  57. package/src/transpiler/types/ICodeGenSymbols.ts +8 -0
  58. package/src/utils/BitUtils.ts +33 -4
  59. package/src/utils/cache/CacheManager.ts +9 -1
  60. 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.9",
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
  };
@@ -110871,6 +110945,16 @@ var CodeGenState = class {
110871
110945
  /** Issue #473: IRQ wrappers for critical sections */
110872
110946
  static needsIrqWrappers = false;
110873
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
+ // ===========================================================================
110874
110958
  // C++ MODE STATE (Issue #250)
110875
110959
  // ===========================================================================
110876
110960
  /** Use temp vars instead of compound literals */
@@ -110954,6 +111038,7 @@ var CodeGenState = class {
110954
111038
  this.tempVarCounter = 0;
110955
111039
  this.pendingCppClassAssignments = [];
110956
111040
  this.selfIncludeAdded = false;
111041
+ this.opaqueScopeVariables = /* @__PURE__ */ new Set();
110957
111042
  this.sourcePath = null;
110958
111043
  this.includeDirs = [];
110959
111044
  this.inputs = [];
@@ -111043,6 +111128,14 @@ var CodeGenState = class {
111043
111128
  static isKnownRegister(name) {
111044
111129
  return this.symbols?.knownRegisters.has(name) ?? false;
111045
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
+ }
111046
111139
  /**
111047
111140
  * Get type info for a variable.
111048
111141
  * Checks local typeRegistry first, then falls back to SymbolTable
@@ -111482,6 +111575,28 @@ var CodeGenState = class {
111482
111575
  return this.floatShadowCurrent.has(name);
111483
111576
  }
111484
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
+ // ===========================================================================
111485
111600
  // C++ MODE HELPERS
111486
111601
  // ===========================================================================
111487
111602
  /**
@@ -113191,6 +113306,12 @@ var TypeResolver2 = class _TypeResolver {
113191
113306
  if (floatMatch) {
113192
113307
  return "f" + floatMatch[1];
113193
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
+ }
113194
113315
  return null;
113195
113316
  }
113196
113317
  /**
@@ -114450,6 +114571,229 @@ var GeneratorRegistry = class {
114450
114571
  }
114451
114572
  };
114452
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
+
114453
114797
  // src/transpiler/output/codegen/generators/expressions/LiteralGenerator.ts
114454
114798
  var UNSIGNED_64_TYPES = /* @__PURE__ */ new Set(["u64", "uint64_t"]);
114455
114799
  var UNSIGNED_TYPES3 = /* @__PURE__ */ new Set([
@@ -114490,6 +114834,18 @@ var generateLiteral = (node, _input, state, _orchestrator) => {
114490
114834
  effects.push({ type: "include", header: "stdbool" });
114491
114835
  return { code: literalText, effects };
114492
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
+ }
114493
114849
  if (/[fF]32$/.test(literalText)) {
114494
114850
  literalText = literalText.replace(/[fF]32$/, "f");
114495
114851
  return { code: literalText, effects };
@@ -114851,96 +115207,9 @@ var binaryExprGenerators = {
114851
115207
  };
114852
115208
  var BinaryExprGenerator_default = binaryExprGenerators;
114853
115209
 
114854
- // src/transpiler/output/codegen/helpers/CppModeHelper.ts
114855
- var CppModeHelper = class {
114856
- /**
114857
- * Get address-of expression for struct parameter passing.
114858
- * C mode: `&expr` (pass pointer to struct)
114859
- * C++ mode: `expr` (pass reference directly)
114860
- *
114861
- * @param expr - The expression to potentially wrap
114862
- * @returns The expression with address-of operator in C mode
114863
- */
114864
- static maybeAddressOf(expr) {
114865
- return CodeGenState.cppMode ? expr : `&${expr}`;
114866
- }
114867
- /**
114868
- * Get dereference expression for struct parameter access.
114869
- * C mode: `(*expr)` (dereference pointer)
114870
- * C++ mode: `expr` (reference can be used directly)
114871
- *
114872
- * @param expr - The expression to potentially dereference
114873
- * @returns The expression with dereference in C mode
114874
- */
114875
- static maybeDereference(expr) {
114876
- return CodeGenState.cppMode ? expr : `(*${expr})`;
114877
- }
114878
- /**
114879
- * Get the type modifier for struct parameter declarations.
114880
- * C mode: `*` (pointer type)
114881
- * C++ mode: `&` (reference type)
114882
- *
114883
- * @returns The type modifier character
114884
- */
114885
- static refOrPtr() {
114886
- return CodeGenState.cppMode ? "&" : "*";
114887
- }
114888
- /**
114889
- * Get the member access separator for struct parameters.
114890
- * C mode: `->` (pointer member access)
114891
- * C++ mode: `.` (reference member access)
114892
- *
114893
- * @returns The member access separator
114894
- */
114895
- static memberSeparator() {
114896
- return CodeGenState.cppMode ? "." : "->";
114897
- }
114898
- /**
114899
- * Get NULL literal for the current mode.
114900
- * C mode: `NULL`
114901
- * C++ mode: `nullptr`
114902
- *
114903
- * @returns The null pointer literal
114904
- */
114905
- static nullLiteral() {
114906
- return CodeGenState.cppMode ? "nullptr" : "NULL";
114907
- }
114908
- /**
114909
- * Generate a cast expression for the current mode.
114910
- * C mode: `(type)expr`
114911
- * C++ mode: `static_cast<type>(expr)`
114912
- *
114913
- * @param type - The target type
114914
- * @param expr - The expression to cast
114915
- * @returns The cast expression
114916
- */
114917
- static cast(type, expr) {
114918
- return CodeGenState.cppMode ? `static_cast<${type}>(${expr})` : `(${type})${expr}`;
114919
- }
114920
- /**
114921
- * Generate a reinterpret cast expression for the current mode.
114922
- * C mode: `(type)expr`
114923
- * C++ mode: `reinterpret_cast<type>(expr)`
114924
- *
114925
- * @param type - The target type
114926
- * @param expr - The expression to cast
114927
- * @returns The cast expression
114928
- */
114929
- static reinterpretCast(type, expr) {
114930
- return CodeGenState.cppMode ? `reinterpret_cast<${type}>(${expr})` : `(${type})${expr}`;
114931
- }
114932
- /**
114933
- * Check if we're in C++ mode.
114934
- *
114935
- * @returns True if generating C++ code
114936
- */
114937
- static isCppMode() {
114938
- return CodeGenState.cppMode;
114939
- }
114940
- };
114941
- var CppModeHelper_default = CppModeHelper;
114942
-
114943
115210
  // src/transpiler/output/codegen/generators/expressions/UnaryExprGenerator.ts
115211
+ var INT32_MIN_LITERAL = "2147483648";
115212
+ var INT64_MIN_LITERAL = "9223372036854775808";
114944
115213
  var generateUnaryExpr = (node, _input, _state, orchestrator) => {
114945
115214
  if (node.postfixExpression()) {
114946
115215
  return {
@@ -114951,7 +115220,18 @@ var generateUnaryExpr = (node, _input, _state, orchestrator) => {
114951
115220
  const inner = orchestrator.generateUnaryExpr(node.unaryExpression());
114952
115221
  const text = node.getText();
114953
115222
  if (text.startsWith("!")) return { code: `!${inner}`, effects: [] };
114954
- 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
+ }
114955
115235
  if (text.startsWith("~")) {
114956
115236
  const innerType = TypeResolver_default2.getUnaryExpressionType(
114957
115237
  node.unaryExpression()
@@ -115014,15 +115294,18 @@ var generateSizeProperty = (typeInfo) => {
115014
115294
  throw new Error(`Error: .size is only available on string types`);
115015
115295
  };
115016
115296
  var generateBitmapFieldAccess = (result, fieldInfo) => {
115297
+ let expr;
115017
115298
  if (fieldInfo.width === 1) {
115018
- return { code: `((${result} >> ${fieldInfo.offset}) & 1)`, effects: [] };
115299
+ expr = `((${result} >> ${fieldInfo.offset}) & 1)`;
115019
115300
  } else {
115020
115301
  const mask = (1 << fieldInfo.width) - 1;
115021
- return {
115022
- code: `((${result} >> ${fieldInfo.offset}) & 0x${mask.toString(16).toUpperCase()})`,
115023
- effects: []
115024
- };
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);
115025
115307
  }
115308
+ return { code: expr, effects: [] };
115026
115309
  };
115027
115310
  var accessGenerators = {
115028
115311
  generateCapacityProperty,
@@ -115199,7 +115482,8 @@ var _generateCFunctionArg = (e, targetParam, input, orchestrator) => {
115199
115482
  if (typeInfo?.isPointer) {
115200
115483
  isPointerVariable = true;
115201
115484
  }
115202
- const needsAddressOf = argType && !argType.endsWith("*") && !argCode.startsWith("&") && !targetParam.isArray && !isPointerVariable && (orchestrator.isStructType(argType) || _parameterExpectsAddressOf(targetParam.baseType, argType, 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));
115203
115487
  const finalArgCode = needsAddressOf ? `&${argCode}` : argCode;
115204
115488
  return wrapWithCppEnumCast(
115205
115489
  finalArgCode,
@@ -115337,7 +115621,7 @@ var trackPassThroughModifications = (funcName, argExprs, orchestrator) => {
115337
115621
  var CallExprGenerator_default = generateFunctionCall;
115338
115622
 
115339
115623
  // src/utils/TypeCheckUtils.ts
115340
- var INTEGER_TYPES2 = [
115624
+ var INTEGER_TYPES3 = [
115341
115625
  "u8",
115342
115626
  "u16",
115343
115627
  "u32",
@@ -115349,7 +115633,7 @@ var INTEGER_TYPES2 = [
115349
115633
  ];
115350
115634
  var UNSIGNED_TYPES4 = ["u8", "u16", "u32", "u64"];
115351
115635
  var SIGNED_TYPES3 = ["i8", "i16", "i32", "i64"];
115352
- var FLOAT_TYPES2 = ["f32", "f64"];
115636
+ var FLOAT_TYPES3 = ["f32", "f64"];
115353
115637
  var STANDARD_WIDTHS = [8, 16, 32];
115354
115638
  var TypeCheckUtils = class {
115355
115639
  /**
@@ -115359,7 +115643,7 @@ var TypeCheckUtils = class {
115359
115643
  * @returns true if it's u8, u16, u32, u64, i8, i16, i32, or i64
115360
115644
  */
115361
115645
  static isInteger(typeName) {
115362
- return INTEGER_TYPES2.includes(typeName);
115646
+ return INTEGER_TYPES3.includes(typeName);
115363
115647
  }
115364
115648
  /**
115365
115649
  * Check if a type name is an unsigned integer type.
@@ -115386,7 +115670,7 @@ var TypeCheckUtils = class {
115386
115670
  * @returns true if it's f32 or f64
115387
115671
  */
115388
115672
  static isFloat(typeName) {
115389
- return FLOAT_TYPES2.includes(typeName);
115673
+ return FLOAT_TYPES3.includes(typeName);
115390
115674
  }
115391
115675
  /**
115392
115676
  * Check if a type name is a string type (string<N>).
@@ -116618,7 +116902,12 @@ var handleSingleSubscript = (ctx, expr, input, orchestrator, output) => {
116618
116902
  const isRegisterAccess = checkRegisterAccess(ctx, input);
116619
116903
  const identifierTypeInfo = getIdentifierTypeInfo(ctx, input);
116620
116904
  if (isRegisterAccess) {
116621
- output.result = index === "0" || index === "0U" ? `((${ctx.result}) & 1)` : `((${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;
116622
116911
  return output;
116623
116912
  }
116624
116913
  if (ctx.currentMemberIsArray) {
@@ -116632,7 +116921,12 @@ var handleSingleSubscript = (ctx, expr, input, orchestrator, output) => {
116632
116921
  }
116633
116922
  const isPrimitiveIntMember = ctx.currentStructType && TypeCheckUtils_default.isInteger(ctx.currentStructType);
116634
116923
  if (isPrimitiveIntMember) {
116635
- output.result = index === "0" || index === "0U" ? `((${ctx.result}) & 1)` : `((${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;
116636
116930
  output.currentStructType = void 0;
116637
116931
  return output;
116638
116932
  }
@@ -116691,7 +116985,12 @@ var handleDefaultSubscript = (ctx, index, typeInfo, output) => {
116691
116985
  isRegisterAccess: false
116692
116986
  });
116693
116987
  if (subscriptKind === "bit_single") {
116694
- output.result = index === "0" || index === "0U" ? `((${ctx.result}) & 1)` : `((${ctx.result} >> ${index}) & 1)`;
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;
116695
116994
  } else {
116696
116995
  output.result = `${ctx.result}[${index}]`;
116697
116996
  }
@@ -116718,10 +117017,24 @@ var handleBitRangeSubscript = (ctx, exprs, input, state, orchestrator, effects,
116718
117017
  );
116719
117018
  } else {
116720
117019
  const mask = orchestrator.generateBitMask(width);
117020
+ let expr;
116721
117021
  if (start === "0" || start === "0U") {
116722
- output.result = `((${ctx.result}) & ${mask})`;
117022
+ expr = `((${ctx.result}) & ${mask})`;
116723
117023
  } else {
116724
- 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;
116725
117038
  }
116726
117039
  }
116727
117040
  return output;
@@ -117031,6 +117344,21 @@ var generateCriticalStatement = (node, _input, _state, orchestrator) => {
117031
117344
  };
117032
117345
  var CriticalGenerator_default = generateCriticalStatement;
117033
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
+
117034
117362
  // src/transpiler/output/codegen/generators/statements/AtomicGenerator.ts
117035
117363
  var TYPE_MAP2 = {
117036
117364
  u8: "uint8_t",
@@ -117058,18 +117386,6 @@ var STREX_MAP = {
117058
117386
  u32: "__STREXW",
117059
117387
  i32: "__STREXW"
117060
117388
  };
117061
- var SIMPLE_OP_MAP = {
117062
- "+=": "+",
117063
- "-=": "-",
117064
- "*=": "*",
117065
- "/=": "/",
117066
- "%=": "%",
117067
- "&=": "&",
117068
- "|=": "|",
117069
- "^=": "^",
117070
- "<<=": "<<",
117071
- ">>=": ">>"
117072
- };
117073
117389
  var CLAMP_OP_MAP = {
117074
117390
  "+=": "add",
117075
117391
  "-=": "sub",
@@ -117083,7 +117399,7 @@ function getClampHelperOp(cOp, typeInfo) {
117083
117399
  }
117084
117400
  function generateInnerAtomicOp(cOp, value, typeInfo) {
117085
117401
  const effects = [];
117086
- const simpleOp = SIMPLE_OP_MAP[cOp] || "+";
117402
+ const simpleOp = COMPOUND_TO_BINARY_default[cOp] || "+";
117087
117403
  const helperOp = getClampHelperOp(cOp, typeInfo);
117088
117404
  if (helperOp) {
117089
117405
  effects.push({
@@ -117748,8 +118064,13 @@ function generateRegularVariable(varDecl, varName, scopeName, isPrivate, orchest
117748
118064
  const arrayDims = varDecl.arrayDimension();
117749
118065
  const arrayTypeCtx = varDecl.type().arrayType?.() ?? null;
117750
118066
  const isArray = arrayDims.length > 0 || arrayTypeCtx !== null;
117751
- const type = orchestrator.generateType(varDecl.type());
118067
+ let type = orchestrator.generateType(varDecl.type());
117752
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
+ }
117753
118074
  const constPrefix = isConst ? "const " : "";
117754
118075
  const prefix = isPrivate ? "static " : "";
117755
118076
  let decl = `${prefix}${constPrefix}${type} ${fullName}`;
@@ -117761,7 +118082,11 @@ function generateRegularVariable(varDecl, varName, scopeName, isPrivate, orchest
117761
118082
  decl += orchestrator.generateArrayDimensions(arrayDims);
117762
118083
  }
117763
118084
  decl += ArrayDimensionUtils_default.generateStringCapacityDim(varDecl.type());
117764
- decl += generateInitializer(varDecl, isArray, orchestrator);
118085
+ if (isOpaque) {
118086
+ decl += " = NULL";
118087
+ } else {
118088
+ decl += generateInitializer(varDecl, isArray, orchestrator);
118089
+ }
117765
118090
  return decl + ";";
117766
118091
  }
117767
118092
  function generateScopeFunction(funcDecl, scopeName, isPrivate, orchestrator) {
@@ -117973,6 +118298,7 @@ function generateScopedStructInline(node, scopeName, _input, orchestrator) {
117973
118298
  var ScopeGenerator_default = generateScope;
117974
118299
 
117975
118300
  // src/utils/BitUtils.ts
118301
+ var NARROW_TYPES = /* @__PURE__ */ new Set(["u8", "u16", "i8", "i16"]);
117976
118302
  var BitUtils = class _BitUtils {
117977
118303
  /**
117978
118304
  * Convert a boolean expression to an unsigned integer (0U or 1U).
@@ -118063,6 +118389,21 @@ var BitUtils = class _BitUtils {
118063
118389
  static formatHex(value) {
118064
118390
  return `0x${value.toString(16).toUpperCase()}U`;
118065
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
+ }
118066
118407
  /**
118067
118408
  * Generate code to read a single bit from a value.
118068
118409
  * Pattern: ((target >> offset) & 1)
@@ -118109,7 +118450,8 @@ var BitUtils = class _BitUtils {
118109
118450
  const is64Bit = targetType === "u64" || targetType === "i64";
118110
118451
  const one = is64Bit ? "1ULL" : "1U";
118111
118452
  const valueShift = is64Bit ? `((uint64_t)${intValue} << ${offset})` : `(${intValue} << ${offset})`;
118112
- return `${target} = (${target} & ~(${one} << ${offset})) | ${valueShift};`;
118453
+ const rhs = `(${target} & ~(${one} << ${offset})) | ${valueShift}`;
118454
+ return `${target} = ${_BitUtils.wrapNarrowCast(rhs, targetType)};`;
118113
118455
  }
118114
118456
  /**
118115
118457
  * Generate read-modify-write code for multi-bit assignment.
@@ -118124,7 +118466,8 @@ var BitUtils = class _BitUtils {
118124
118466
  */
118125
118467
  static multiBitWrite(target, offset, width, value, targetType) {
118126
118468
  const mask = _BitUtils.generateMask(width, targetType);
118127
- return `${target} = (${target} & ~(${mask} << ${offset})) | ((${value} & ${mask}) << ${offset});`;
118469
+ const rhs = `(${target} & ~(${mask} << ${offset})) | ((${value} & ${mask}) << ${offset})`;
118470
+ return `${target} = ${_BitUtils.wrapNarrowCast(rhs, targetType)};`;
118128
118471
  }
118129
118472
  /**
118130
118473
  * Generate write-only register code for single bit assignment.
@@ -118140,7 +118483,8 @@ var BitUtils = class _BitUtils {
118140
118483
  static writeOnlySingleBit(target, offset, value, targetType) {
118141
118484
  const intValue = _BitUtils.boolToInt(value);
118142
118485
  const castPrefix = targetType === "u64" || targetType === "i64" ? "(uint64_t)" : "";
118143
- return `${target} = (${castPrefix}${intValue} << ${offset});`;
118486
+ const rhs = `(${castPrefix}${intValue} << ${offset})`;
118487
+ return `${target} = ${_BitUtils.wrapNarrowCast(rhs, targetType)};`;
118144
118488
  }
118145
118489
  /**
118146
118490
  * Generate write-only register code for multi-bit assignment.
@@ -118156,7 +118500,8 @@ var BitUtils = class _BitUtils {
118156
118500
  */
118157
118501
  static writeOnlyMultiBit(target, offset, width, value, targetType) {
118158
118502
  const mask = _BitUtils.generateMask(width, targetType);
118159
- return `${target} = ((${value} & ${mask}) << ${offset});`;
118503
+ const rhs = `((${value} & ${mask}) << ${offset})`;
118504
+ return `${target} = ${_BitUtils.wrapNarrowCast(rhs, targetType)};`;
118160
118505
  }
118161
118506
  };
118162
118507
  var BitUtils_default = BitUtils;
@@ -120717,8 +121062,10 @@ var AssignmentKind = /* @__PURE__ */ ((AssignmentKind2) => {
120717
121062
  AssignmentKind2[AssignmentKind2["GLOBAL_REGISTER_BIT"] = 28] = "GLOBAL_REGISTER_BIT";
120718
121063
  AssignmentKind2[AssignmentKind2["THIS_MEMBER"] = 29] = "THIS_MEMBER";
120719
121064
  AssignmentKind2[AssignmentKind2["THIS_ARRAY"] = 30] = "THIS_ARRAY";
120720
- AssignmentKind2[AssignmentKind2["MEMBER_CHAIN"] = 31] = "MEMBER_CHAIN";
120721
- 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";
120722
121069
  return AssignmentKind2;
120723
121070
  })(AssignmentKind || {});
120724
121071
  var AssignmentKind_default = AssignmentKind;
@@ -120760,8 +121107,55 @@ var handlers_default = AssignmentHandlerRegistry;
120760
121107
  function gen() {
120761
121108
  return CodeGenState.generator;
120762
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
+ }
120763
121149
  function handleSimpleAssignment(ctx) {
120764
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
+ }
120765
121159
  return `${target} ${ctx.cOp} ${ctx.generatedValue};`;
120766
121160
  }
120767
121161
  var SimpleHandler_default = handleSimpleAssignment;
@@ -121414,6 +121808,8 @@ function handleStructChainBitRange(ctx) {
121414
121808
  var bitAccessHandlers = [
121415
121809
  [AssignmentKind_default.INTEGER_BIT, handleIntegerBit],
121416
121810
  [AssignmentKind_default.INTEGER_BIT_RANGE, handleIntegerBitRange],
121811
+ [AssignmentKind_default.THIS_BIT, handleIntegerBit],
121812
+ [AssignmentKind_default.THIS_BIT_RANGE, handleIntegerBitRange],
121417
121813
  [AssignmentKind_default.STRUCT_MEMBER_BIT, handleStructMemberBit],
121418
121814
  [AssignmentKind_default.ARRAY_ELEMENT_BIT, handleArrayElementBit],
121419
121815
  [AssignmentKind_default.STRUCT_CHAIN_BIT_RANGE, handleStructChainBitRange]
@@ -121965,14 +122361,28 @@ var AssignmentClassifier = class _AssignmentClassifier {
121965
122361
  return AssignmentKind_default.THIS_MEMBER;
121966
122362
  }
121967
122363
  /**
121968
- * 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.
121969
122366
  */
121970
122367
  static classifyThisWithArrayAccess(ctx, scopedRegName) {
121971
122368
  if (CodeGenState.symbols.knownRegisters.has(scopedRegName)) {
121972
122369
  const hasBitRange = ctx.postfixOps.some((op) => op.COMMA() !== null);
121973
122370
  return hasBitRange ? AssignmentKind_default.SCOPED_REGISTER_BIT_RANGE : AssignmentKind_default.SCOPED_REGISTER_BIT;
121974
122371
  }
121975
- 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
+ }
121976
122386
  }
121977
122387
  /**
121978
122388
  * Classify simple array/bit access (no prefix, no member access).
@@ -122045,7 +122455,8 @@ var AssignmentClassifier = class _AssignmentClassifier {
122045
122455
  if (isGlobalAtomic) {
122046
122456
  return AssignmentKind_default.ATOMIC_RMW;
122047
122457
  }
122048
- 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)) {
122049
122460
  return AssignmentKind_default.OVERFLOW_CLAMP;
122050
122461
  }
122051
122462
  return null;
@@ -124446,10 +124857,20 @@ ${assignments}`;
124446
124857
  _VariableDeclHelper.validateIntegerInitializer(ctx, typeName, {
124447
124858
  getExpressionType: callbacks.getExpressionType
124448
124859
  });
124449
- return CodeGenState.withExpectedType(
124450
- typeName,
124451
- () => `${decl} = ${callbacks.generateExpression(ctx.expression())}`
124452
- );
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
+ });
124453
124874
  }
124454
124875
  // ========================================================================
124455
124876
  // Tier 4: Orchestrators (main entry points)
@@ -125310,7 +125731,7 @@ var TypeGenerationHelper_default = TypeGenerationHelper;
125310
125731
  var SIGNED_INTEGERS = /* @__PURE__ */ new Set(["i8", "i16", "i32", "i64"]);
125311
125732
  var UNSIGNED_INTEGERS = /* @__PURE__ */ new Set(["u8", "u16", "u32", "u64"]);
125312
125733
  var ALL_INTEGERS = /* @__PURE__ */ new Set([...SIGNED_INTEGERS, ...UNSIGNED_INTEGERS]);
125313
- var FLOAT_TYPES3 = /* @__PURE__ */ new Set(["f32", "f64"]);
125734
+ var FLOAT_TYPES4 = /* @__PURE__ */ new Set(["f32", "f64"]);
125314
125735
  var CastValidator = class _CastValidator {
125315
125736
  /**
125316
125737
  * Check if a type is an integer type.
@@ -125322,7 +125743,7 @@ var CastValidator = class _CastValidator {
125322
125743
  * Check if a type is a floating-point type.
125323
125744
  */
125324
125745
  static isFloatType(typeName) {
125325
- return FLOAT_TYPES3.has(typeName);
125746
+ return FLOAT_TYPES4.has(typeName);
125326
125747
  }
125327
125748
  /**
125328
125749
  * Check if a type is signed.
@@ -128368,6 +128789,22 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
128368
128789
  isFloatShadowCurrent(shadowName) {
128369
128790
  return CodeGenState.floatShadowCurrent.has(shadowName);
128370
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
+ }
128371
128808
  // ===========================================================================
128372
128809
  // End IOrchestrator Implementation
128373
128810
  // ===========================================================================
@@ -130334,7 +130771,9 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
130334
130771
  const minComparison = minValue === "0" ? `0.0${floatSuffix}` : `((${floatCastType})${minValue})`;
130335
130772
  const maxComparison = `((${floatCastType})${maxValue})`;
130336
130773
  const finalCast = CppModeHelper_default.cast(targetType, `(${expr})`);
130337
- 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})`;
130338
130777
  }
130339
130778
  /**
130340
130779
  * ADR-023: Generate sizeof expression
@@ -132527,6 +132966,7 @@ var TSymbolInfoAdapter = class _TSymbolInfoAdapter {
132527
132966
  const registerMemberCTypes = /* @__PURE__ */ new Map();
132528
132967
  const scopePrivateConstValues = /* @__PURE__ */ new Map();
132529
132968
  const functionReturnTypes = /* @__PURE__ */ new Map();
132969
+ const opaqueTypes = /* @__PURE__ */ new Set();
132530
132970
  for (const symbol of symbols) {
132531
132971
  switch (symbol.kind) {
132532
132972
  case "struct":
@@ -132614,6 +133054,8 @@ var TSymbolInfoAdapter = class _TSymbolInfoAdapter {
132614
133054
  scopePrivateConstValues,
132615
133055
  // Function return types
132616
133056
  functionReturnTypes,
133057
+ // Issue #948: Opaque types
133058
+ opaqueTypes,
132617
133059
  // Methods
132618
133060
  getSingleFunctionForVariable: (scopeName, varName) => _TSymbolInfoAdapter.getSingleFunctionForVariable(
132619
133061
  scopeVariableUsage,
@@ -132811,42 +133253,35 @@ var TSymbolInfoAdapter = class _TSymbolInfoAdapter {
132811
133253
  );
132812
133254
  }
132813
133255
  return {
132814
- // Type sets - knownEnums and knownScopes are merged
133256
+ ...base,
132815
133257
  knownScopes: mergedKnownScopes,
132816
- knownStructs: base.knownStructs,
132817
133258
  knownEnums: mergedKnownEnums,
132818
- knownBitmaps: base.knownBitmaps,
132819
- knownRegisters: base.knownRegisters,
132820
- // Scope info
132821
- scopeMembers: base.scopeMembers,
132822
- scopeMemberVisibility: base.scopeMemberVisibility,
132823
- scopeVariableUsage: base.scopeVariableUsage,
132824
- // Struct info
132825
- structFields: base.structFields,
132826
- structFieldArrays: base.structFieldArrays,
132827
- structFieldDimensions: base.structFieldDimensions,
132828
- // Enum info - merged
132829
133259
  enumMembers: mergedEnumMembers,
132830
- // Bitmap info
132831
- bitmapFields: base.bitmapFields,
132832
- bitmapBackingType: base.bitmapBackingType,
132833
- bitmapBitWidth: base.bitmapBitWidth,
132834
- // Register info
132835
- scopedRegisters: base.scopedRegisters,
132836
- registerMemberAccess: base.registerMemberAccess,
132837
- registerMemberTypes: base.registerMemberTypes,
132838
- registerBaseAddresses: base.registerBaseAddresses,
132839
- registerMemberOffsets: base.registerMemberOffsets,
132840
- registerMemberCTypes: base.registerMemberCTypes,
132841
- // Private const values
132842
- scopePrivateConstValues: base.scopePrivateConstValues,
132843
- // Function return types - merged
132844
- functionReturnTypes: mergedFunctionReturnTypes,
132845
- // Methods - delegate to base's implementation
132846
- getSingleFunctionForVariable: base.getSingleFunctionForVariable,
132847
- hasPublicSymbols: base.hasPublicSymbols
133260
+ functionReturnTypes: mergedFunctionReturnTypes
132848
133261
  };
132849
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
+ }
132850
133285
  };
132851
133286
  var TSymbolInfoAdapter_default = TSymbolInfoAdapter;
132852
133287
 
@@ -133233,6 +133668,18 @@ var DeclaratorUtils = class _DeclaratorUtils {
133233
133668
  }
133234
133669
  return void 0;
133235
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
+ }
133236
133683
  };
133237
133684
  var DeclaratorUtils_default = DeclaratorUtils;
133238
133685
 
@@ -133254,6 +133701,7 @@ var StructCollector2 = class _StructCollector {
133254
133701
  const name = identifier?.getText() || typedefName;
133255
133702
  if (!name) return null;
133256
133703
  const isUnion = structSpec.structOrUnion()?.getText() === "union";
133704
+ const hasBody = structSpec.structDeclarationList() !== null;
133257
133705
  const fields = _StructCollector.collectFields(
133258
133706
  structSpec,
133259
133707
  name,
@@ -133261,8 +133709,16 @@ var StructCollector2 = class _StructCollector {
133261
133709
  warnings
133262
133710
  );
133263
133711
  const needsStructKeyword = Boolean(identifier && !isTypedef);
133264
- if (symbolTable && needsStructKeyword) {
133265
- 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
+ );
133266
133722
  }
133267
133723
  return {
133268
133724
  kind: "struct",
@@ -133276,6 +133732,44 @@ var StructCollector2 = class _StructCollector {
133276
133732
  fields: fields.size > 0 ? fields : void 0
133277
133733
  };
133278
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
+ }
133279
133773
  /**
133280
133774
  * Collect fields from a struct/union definition.
133281
133775
  */
@@ -133412,6 +133906,15 @@ var FunctionCollector2 = class _FunctionCollector {
133412
133906
  isArray: p.isArray
133413
133907
  }));
133414
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
+ }
133415
133918
  /**
133416
133919
  * Collect a function symbol from a function definition.
133417
133920
  *
@@ -133425,7 +133928,11 @@ var FunctionCollector2 = class _FunctionCollector {
133425
133928
  if (!name) return null;
133426
133929
  const line = funcDef.start?.line ?? 0;
133427
133930
  const declSpecs = funcDef.declarationSpecifiers();
133428
- 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
+ );
133429
133936
  const parameters = _FunctionCollector._mapParameters(
133430
133937
  DeclaratorUtils_default.extractFunctionParameters(declarator)
133431
133938
  );
@@ -133455,8 +133962,10 @@ var FunctionCollector2 = class _FunctionCollector {
133455
133962
  const parameters = _FunctionCollector._mapParameters(
133456
133963
  DeclaratorUtils_default.extractFunctionParameters(declarator)
133457
133964
  );
133458
- const hasPointer = declarator.pointer() !== null;
133459
- const returnType = hasPointer ? `${baseType}*` : baseType;
133965
+ const returnType = _FunctionCollector._resolveReturnType(
133966
+ baseType,
133967
+ declarator
133968
+ );
133460
133969
  return {
133461
133970
  kind: "function",
133462
133971
  name,
@@ -133599,39 +134108,33 @@ var CResolver = class _CResolver {
133599
134108
  const line = decl.start?.line ?? 0;
133600
134109
  const isTypedef = DeclaratorUtils_default.hasStorageClass(declSpecs, "typedef");
133601
134110
  const isExtern = DeclaratorUtils_default.hasStorageClass(declSpecs, "extern");
134111
+ const ctx = {
134112
+ sourceFile,
134113
+ line,
134114
+ isTypedef,
134115
+ isExtern,
134116
+ symbols
134117
+ };
133602
134118
  const structSpec = DeclaratorUtils_default.findStructOrUnionSpecifier(declSpecs);
133603
134119
  if (structSpec) {
133604
- const typedefName = isTypedef ? DeclaratorUtils_default.extractTypedefNameFromSpecs(declSpecs) : void 0;
133605
- const structSymbol = StructCollector_default2.collect(
134120
+ _CResolver.collectStructSymbol(
133606
134121
  structSpec,
133607
- sourceFile,
133608
- line,
134122
+ decl,
134123
+ declSpecs,
134124
+ ctx,
133609
134125
  symbolTable,
133610
- typedefName,
133611
- isTypedef,
133612
134126
  warnings
133613
134127
  );
133614
- if (structSymbol) {
133615
- symbols.push(structSymbol);
133616
- }
133617
134128
  }
133618
134129
  const enumSpec = DeclaratorUtils_default.findEnumSpecifier(declSpecs);
133619
134130
  if (enumSpec) {
133620
- const enumResult = EnumCollector_default2.collect(enumSpec, sourceFile, line);
133621
- if (enumResult) {
133622
- symbols.push(enumResult.enum);
133623
- for (const member of enumResult.members) {
133624
- symbols.push(member);
133625
- }
133626
- }
134131
+ _CResolver.collectEnumSymbols(
134132
+ enumSpec,
134133
+ ctx.sourceFile,
134134
+ ctx.line,
134135
+ ctx.symbols
134136
+ );
133627
134137
  }
133628
- const ctx = {
133629
- sourceFile,
133630
- line,
133631
- isTypedef,
133632
- isExtern,
133633
- symbols
133634
- };
133635
134138
  const initDeclList = decl.initDeclaratorList();
133636
134139
  if (initDeclList) {
133637
134140
  const baseType = DeclaratorUtils_default.extractTypeFromDeclSpecs(declSpecs);
@@ -133645,6 +134148,49 @@ var CResolver = class _CResolver {
133645
134148
  );
133646
134149
  }
133647
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
+ }
133648
134194
  /**
133649
134195
  * Collect symbols from init declarator list.
133650
134196
  */
@@ -137838,6 +138384,9 @@ var IndexTypeListener = class extends CNextListener {
137838
138384
  if (TypeConstants_default.UNSIGNED_INDEX_TYPES.includes(resolvedType)) {
137839
138385
  continue;
137840
138386
  }
138387
+ if (CodeGenState.isKnownEnum(resolvedType)) {
138388
+ continue;
138389
+ }
137841
138390
  const { line, column } = ParserUtils_default.getPosition(ctx);
137842
138391
  this.analyzer.addError(line, column, "E0852", resolvedType);
137843
138392
  return;
@@ -137927,6 +138476,10 @@ var IndexTypeListener = class extends CNextListener {
137927
138476
  if (TypeConstants_default.SIGNED_TYPES.includes(currentType)) {
137928
138477
  return "bool";
137929
138478
  }
138479
+ const strippedType = currentType.replace(/\[[^\]]*\]$/, "");
138480
+ if (strippedType !== currentType) {
138481
+ return strippedType;
138482
+ }
137930
138483
  return currentType;
137931
138484
  }
137932
138485
  if (op.LPAREN()) {
@@ -138327,7 +138880,7 @@ var CacheKeyGenerator_default = CacheKeyGenerator;
138327
138880
 
138328
138881
  // src/utils/cache/CacheManager.ts
138329
138882
  var defaultFs7 = NodeFileSystem_default.instance;
138330
- var CACHE_VERSION = 4;
138883
+ var CACHE_VERSION = 5;
138331
138884
  var TRANSPILER_VERSION = package_default.version;
138332
138885
  var CacheManager = class {
138333
138886
  projectRoot;
@@ -138427,14 +138980,15 @@ var CacheManager = class {
138427
138980
  symbols,
138428
138981
  structFields,
138429
138982
  needsStructKeyword: cachedEntry.needsStructKeyword ?? [],
138430
- enumBitWidth
138983
+ enumBitWidth,
138984
+ opaqueTypes: cachedEntry.opaqueTypes ?? []
138431
138985
  };
138432
138986
  }
138433
138987
  /**
138434
138988
  * Store symbols and struct fields for a file
138435
138989
  * ADR-055 Phase 7: Takes ISerializedSymbol[] directly
138436
138990
  */
138437
- setSymbols(filePath, symbols, structFields, needsStructKeyword, enumBitWidth) {
138991
+ setSymbols(filePath, symbols, structFields, needsStructKeyword, enumBitWidth, opaqueTypes) {
138438
138992
  if (!this.cache) return;
138439
138993
  let cacheKey;
138440
138994
  try {
@@ -138462,7 +139016,8 @@ var CacheManager = class {
138462
139016
  symbols: serializedSymbols,
138463
139017
  structFields: serializedFields,
138464
139018
  needsStructKeyword,
138465
- enumBitWidth: serializedEnumBitWidth
139019
+ enumBitWidth: serializedEnumBitWidth,
139020
+ opaqueTypes
138466
139021
  };
138467
139022
  this.cache.setKey(filePath, entry);
138468
139023
  this.dirty = true;
@@ -138490,12 +139045,14 @@ var CacheManager = class {
138490
139045
  filePath,
138491
139046
  symbolTable
138492
139047
  );
139048
+ const opaqueTypes = symbolTable.getAllOpaqueTypes();
138493
139049
  this.setSymbols(
138494
139050
  filePath,
138495
139051
  symbols,
138496
139052
  structFields,
138497
139053
  needsStructKeyword,
138498
- enumBitWidth
139054
+ enumBitWidth,
139055
+ opaqueTypes
138499
139056
  );
138500
139057
  }
138501
139058
  /**
@@ -138938,7 +139495,7 @@ var Transpiler = class {
138938
139495
  * Stage 6: Generate headers (per-file)
138939
139496
  */
138940
139497
  async _executePipeline(input, result) {
138941
- this._collectAllHeaderSymbols(input.headerFiles, result);
139498
+ await this._collectAllHeaderSymbols(input.headerFiles, result);
138942
139499
  CodeGenState.buildExternalStructFields();
138943
139500
  if (!this._collectAllCNextSymbolsFromPipeline(input.cnextFiles, result)) {
138944
139501
  return;
@@ -139047,6 +139604,13 @@ var Transpiler = class {
139047
139604
  externalEnumSources
139048
139605
  );
139049
139606
  }
139607
+ const externalOpaqueTypes = CodeGenState.symbolTable.getAllOpaqueTypes();
139608
+ if (externalOpaqueTypes.length > 0) {
139609
+ symbolInfo = TSymbolInfoAdapter_default.mergeOpaqueTypes(
139610
+ symbolInfo,
139611
+ externalOpaqueTypes
139612
+ );
139613
+ }
139050
139614
  CodeGenState.symbols = symbolInfo;
139051
139615
  const analyzerErrors = runAnalyzers_default(tree, tokenStream);
139052
139616
  if (analyzerErrors.length > 0) {
@@ -139220,11 +139784,12 @@ var Transpiler = class {
139220
139784
  }
139221
139785
  /**
139222
139786
  * Stage 2: Collect symbols from all C/C++ headers
139787
+ * Issue #945: Made async for preprocessing support.
139223
139788
  */
139224
- _collectAllHeaderSymbols(headerFiles, result) {
139789
+ async _collectAllHeaderSymbols(headerFiles, result) {
139225
139790
  for (const file of headerFiles) {
139226
139791
  try {
139227
- this.doCollectHeaderSymbols(file);
139792
+ await this.doCollectHeaderSymbols(file);
139228
139793
  result.filesProcessed++;
139229
139794
  } catch (err) {
139230
139795
  this.warnings.push(`Failed to process header ${file.path}: ${err}`);
@@ -139503,15 +140068,16 @@ var Transpiler = class {
139503
140068
  /**
139504
140069
  * Stage 2: Collect symbols from a single C/C++ header
139505
140070
  * Issue #592: Recursive include processing moved to IncludeResolver.resolveHeadersTransitively()
140071
+ * Issue #945: Added preprocessing support for conditional compilation
139506
140072
  * SonarCloud S3776: Refactored to use helper methods for reduced complexity.
139507
140073
  */
139508
- doCollectHeaderSymbols(file) {
140074
+ async doCollectHeaderSymbols(file) {
139509
140075
  const absolutePath = resolve12(file.path);
139510
140076
  this.state.markHeaderProcessed(absolutePath);
139511
140077
  if (this.tryRestoreFromCache(file)) {
139512
140078
  return;
139513
140079
  }
139514
- const content = this.fs.readFile(file.path);
140080
+ const content = await this.getHeaderContent(file);
139515
140081
  this.parseHeaderFile(file, content);
139516
140082
  if (this.config.debugMode) {
139517
140083
  const symbols = CodeGenState.symbolTable.getSymbolsByFile(file.path);
@@ -139542,9 +140108,51 @@ var Transpiler = class {
139542
140108
  cached.needsStructKeyword
139543
140109
  );
139544
140110
  CodeGenState.symbolTable.restoreEnumBitWidths(cached.enumBitWidth);
140111
+ CodeGenState.symbolTable.restoreOpaqueTypes(cached.opaqueTypes);
139545
140112
  this.detectCppFromFileType(file);
139546
140113
  return true;
139547
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
+ }
139548
140156
  /**
139549
140157
  * Restore cached symbols to the symbol table.
139550
140158
  * ADR-055 Phase 7: Converts ISerializedSymbol[] from cache to typed symbols.