c-next 0.2.5 → 0.2.7

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 (57) hide show
  1. package/dist/index.js +617 -474
  2. package/dist/index.js.map +4 -4
  3. package/package.json +1 -1
  4. package/src/transpiler/Transpiler.ts +50 -29
  5. package/src/transpiler/__tests__/Transpiler.coverage.test.ts +2 -1
  6. package/src/transpiler/data/PathResolver.ts +10 -6
  7. package/src/transpiler/data/__tests__/PathResolver.test.ts +32 -0
  8. package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +82 -7
  9. package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +1 -12
  10. package/src/transpiler/logic/analysis/SignedShiftAnalyzer.ts +239 -0
  11. package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +92 -0
  12. package/src/transpiler/logic/analysis/__tests__/SignedShiftAnalyzer.test.ts +414 -0
  13. package/src/transpiler/logic/analysis/__tests__/StructFieldAnalyzer.test.ts +15 -75
  14. package/src/transpiler/logic/analysis/__tests__/runAnalyzers.test.ts +3 -15
  15. package/src/transpiler/logic/analysis/runAnalyzers.ts +11 -2
  16. package/src/transpiler/logic/analysis/types/ISignedShiftError.ts +15 -0
  17. package/src/transpiler/logic/symbols/SymbolUtils.ts +4 -1
  18. package/src/transpiler/logic/symbols/__tests__/SymbolUtils.test.ts +10 -11
  19. package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +27 -4
  20. package/src/transpiler/logic/symbols/c/collectors/FunctionCollector.ts +11 -5
  21. package/src/transpiler/logic/symbols/cpp/__tests__/CppResolver.integration.test.ts +4 -4
  22. package/src/transpiler/output/codegen/CodeGenerator.ts +169 -11
  23. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +132 -3
  24. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +56 -31
  25. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +12 -11
  26. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +21 -21
  27. package/src/transpiler/output/codegen/assignment/handlers/AccessPatternHandlers.ts +2 -2
  28. package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +2 -2
  29. package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +2 -2
  30. package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +4 -4
  31. package/src/transpiler/output/codegen/assignment/handlers/__tests__/AccessPatternHandlers.test.ts +4 -4
  32. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +8 -8
  33. package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +5 -5
  34. package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterHandlers.test.ts +4 -4
  35. package/src/transpiler/output/codegen/generators/expressions/AccessExprGenerator.ts +7 -326
  36. package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +8 -1
  37. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +14 -275
  38. package/src/transpiler/output/codegen/generators/expressions/UnaryExprGenerator.ts +13 -1
  39. package/src/transpiler/output/codegen/generators/expressions/__tests__/AccessExprGenerator.test.ts +0 -573
  40. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +8 -439
  41. package/src/transpiler/output/codegen/generators/expressions/__tests__/UnaryExprGenerator.test.ts +196 -0
  42. package/src/transpiler/output/codegen/helpers/ArgumentGenerator.ts +5 -0
  43. package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +7 -2
  44. package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +8 -1
  45. package/src/transpiler/output/codegen/helpers/TypedefParamParser.ts +34 -0
  46. package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +11 -0
  47. package/src/transpiler/output/codegen/helpers/VariableModifierBuilder.ts +16 -1
  48. package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +48 -0
  49. package/src/transpiler/output/codegen/helpers/__tests__/TypedefParamParser.test.ts +88 -0
  50. package/src/transpiler/output/codegen/helpers/__tests__/VariableModifierBuilder.test.ts +34 -2
  51. package/src/transpiler/output/codegen/types/TTypeInfo.ts +1 -0
  52. package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +15 -2
  53. package/src/transpiler/output/headers/__tests__/BaseHeaderGenerator.test.ts +87 -0
  54. package/src/utils/BitUtils.ts +17 -13
  55. package/src/utils/ExpressionUtils.ts +51 -0
  56. package/src/utils/__tests__/BitUtils.test.ts +56 -56
  57. package/src/utils/types/IParameterSymbol.ts +2 -0
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.5",
13
+ version: "0.2.7",
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",
@@ -770,18 +770,20 @@ var PathResolver = class {
770
770
  return join(dirname(file.path), outputName);
771
771
  }
772
772
  /**
773
- * Get output path for a header file (.h)
773
+ * Get output path for a header file (.h or .hpp)
774
774
  * Uses headerOutDir if specified, otherwise falls back to outDir
775
775
  *
776
776
  * @param file - The discovered file to get header path for
777
+ * @param cppMode - If true, output .hpp; otherwise .h (Issue #933)
777
778
  * @returns The full header output path
778
779
  */
779
- getHeaderOutputPath(file) {
780
+ getHeaderOutputPath(file, cppMode = false) {
781
+ const ext = cppMode ? ".hpp" : ".h";
780
782
  const headerDir = this.config.headerOutDir || this.config.outDir;
781
783
  const relativePath = this.getRelativePathFromInputs(file.path);
782
784
  if (relativePath) {
783
785
  const strippedPath = this.stripBasePath(relativePath);
784
- const outputRelative = strippedPath.replace(/\.cnx$|\.cnext$/, ".h");
786
+ const outputRelative = strippedPath.replace(/\.cnx$|\.cnext$/, ext);
785
787
  const outputPath = join(headerDir, outputRelative);
786
788
  const outputDir = dirname(outputPath);
787
789
  if (!this.fs.exists(outputDir)) {
@@ -794,7 +796,7 @@ var PathResolver = class {
794
796
  const relativeFromCwd = relative(cwd, file.path);
795
797
  if (relativeFromCwd && !relativeFromCwd.startsWith("..")) {
796
798
  const strippedPath = this.stripBasePath(relativeFromCwd);
797
- const outputRelative = strippedPath.replace(/\.cnx$|\.cnext$/, ".h");
799
+ const outputRelative = strippedPath.replace(/\.cnx$|\.cnext$/, ext);
798
800
  const outputPath2 = join(this.config.headerOutDir, outputRelative);
799
801
  const outputDir = dirname(outputPath2);
800
802
  if (!this.fs.exists(outputDir)) {
@@ -802,14 +804,14 @@ var PathResolver = class {
802
804
  }
803
805
  return outputPath2;
804
806
  }
805
- const headerName2 = basename2(file.path).replace(/\.cnx$|\.cnext$/, ".h");
807
+ const headerName2 = basename2(file.path).replace(/\.cnx$|\.cnext$/, ext);
806
808
  const outputPath = join(this.config.headerOutDir, headerName2);
807
809
  if (!this.fs.exists(this.config.headerOutDir)) {
808
810
  this.fs.mkdir(this.config.headerOutDir, { recursive: true });
809
811
  }
810
812
  return outputPath;
811
813
  }
812
- const headerName = basename2(file.path).replace(/\.cnx$|\.cnext$/, ".h");
814
+ const headerName = basename2(file.path).replace(/\.cnx$|\.cnext$/, ext);
813
815
  return join(dirname(file.path), headerName);
814
816
  }
815
817
  /**
@@ -113466,6 +113468,38 @@ var ExpressionUtils = class _ExpressionUtils {
113466
113468
  const identifier = primary.IDENTIFIER();
113467
113469
  return identifier?.getText() ?? null;
113468
113470
  }
113471
+ /**
113472
+ * Collect all additive expressions from a ternary expression.
113473
+ *
113474
+ * Uses flatMap chains to traverse the expression grammar efficiently.
113475
+ * Useful for analyzers that need to examine operands at the additive level.
113476
+ *
113477
+ * @param ctx - The ternary expression context
113478
+ * @returns Array of all additive expression contexts in the tree
113479
+ */
113480
+ static collectAdditiveExpressions(ctx) {
113481
+ return _ExpressionUtils.collectAdditiveFromOrExprs(ctx.orExpression());
113482
+ }
113483
+ /**
113484
+ * Collect additive expressions from an array of orExpression contexts.
113485
+ *
113486
+ * Internal helper that performs the actual flatMap traversal.
113487
+ */
113488
+ static collectAdditiveFromOrExprs(orExprs) {
113489
+ return orExprs.flatMap((or) => or.andExpression()).flatMap((and) => and.equalityExpression()).flatMap((eq) => eq.relationalExpression()).flatMap((rel) => rel.bitwiseOrExpression()).flatMap((bor) => bor.bitwiseXorExpression()).flatMap((bxor) => bxor.bitwiseAndExpression()).flatMap((band) => band.shiftExpression()).flatMap((shift) => shift.additiveExpression());
113490
+ }
113491
+ /**
113492
+ * Collect all unary expressions from an orExpression context.
113493
+ *
113494
+ * Traverses through the entire expression hierarchy to find all unary expressions.
113495
+ * Useful for analyzers that need to examine leaf operands.
113496
+ *
113497
+ * @param orExpr - The orExpression context
113498
+ * @returns Array of all unary expression contexts in the tree
113499
+ */
113500
+ static collectUnaryFromOrExpr(orExpr) {
113501
+ return _ExpressionUtils.collectAdditiveFromOrExprs([orExpr]).flatMap((add) => add.multiplicativeExpression()).flatMap((mul) => mul.unaryExpression());
113502
+ }
113469
113503
  /**
113470
113504
  * ADR-023: Check if an expression contains a function call anywhere in its tree.
113471
113505
  *
@@ -114776,6 +114810,95 @@ var binaryExprGenerators = {
114776
114810
  };
114777
114811
  var BinaryExprGenerator_default = binaryExprGenerators;
114778
114812
 
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
+
114779
114902
  // src/transpiler/output/codegen/generators/expressions/UnaryExprGenerator.ts
114780
114903
  var generateUnaryExpr = (node, _input, _state, orchestrator) => {
114781
114904
  if (node.postfixExpression()) {
@@ -114788,7 +114911,16 @@ var generateUnaryExpr = (node, _input, _state, orchestrator) => {
114788
114911
  const text = node.getText();
114789
114912
  if (text.startsWith("!")) return { code: `!${inner}`, effects: [] };
114790
114913
  if (text.startsWith("-")) return { code: `-${inner}`, effects: [] };
114791
- if (text.startsWith("~")) return { code: `~${inner}`, effects: [] };
114914
+ if (text.startsWith("~")) {
114915
+ const innerType = TypeResolver_default2.getUnaryExpressionType(
114916
+ node.unaryExpression()
114917
+ );
114918
+ if (innerType && TypeResolver_default2.isUnsignedType(innerType)) {
114919
+ const cType = TYPE_MAP_default[innerType] ?? innerType;
114920
+ return { code: CppModeHelper_default.cast(cType, `~${inner}`), effects: [] };
114921
+ }
114922
+ return { code: `~${inner}`, effects: [] };
114923
+ }
114792
114924
  if (text.startsWith("&")) return { code: `&${inner}`, effects: [] };
114793
114925
  return { code: inner, effects: [] };
114794
114926
  };
@@ -114828,170 +114960,6 @@ var expressionGenerators = {
114828
114960
  var ExpressionGenerator_default = expressionGenerators;
114829
114961
 
114830
114962
  // src/transpiler/output/codegen/generators/expressions/AccessExprGenerator.ts
114831
- var TYPE_WIDTH2 = {
114832
- u8: 8,
114833
- u16: 16,
114834
- u32: 32,
114835
- u64: 64,
114836
- i8: 8,
114837
- i16: 16,
114838
- i32: 32,
114839
- i64: 64,
114840
- f32: 32,
114841
- f64: 64,
114842
- bool: 1
114843
- };
114844
- var C_TYPE_WIDTH = {
114845
- uint8_t: 8,
114846
- uint16_t: 16,
114847
- uint32_t: 32,
114848
- uint64_t: 64,
114849
- int8_t: 8,
114850
- int16_t: 16,
114851
- int32_t: 32,
114852
- int64_t: 64,
114853
- float: 32,
114854
- double: 64
114855
- };
114856
- function getTypeBitWidth(typeName) {
114857
- return TYPE_WIDTH2[typeName] || C_TYPE_WIDTH[typeName] || 0;
114858
- }
114859
- function makeStrlenResult(expr, skipContinue) {
114860
- return {
114861
- code: `strlen(${expr})`,
114862
- effects: [{ type: "include", header: "string" }],
114863
- skipContinue
114864
- };
114865
- }
114866
- function makeBitWidthResult(typeName, skipContinue, isElement = false) {
114867
- const bitWidth = getTypeBitWidth(typeName);
114868
- if (bitWidth > 0) {
114869
- return { code: String(bitWidth), effects: [], skipContinue };
114870
- }
114871
- const typeLabel = isElement ? "element type" : "type";
114872
- return {
114873
- code: `/* .length: unsupported ${typeLabel} ${typeName} */0`,
114874
- effects: [],
114875
- skipContinue
114876
- };
114877
- }
114878
- function handleStructMemberLength(ctx) {
114879
- if (!ctx.previousStructType || !ctx.previousMemberName) {
114880
- return null;
114881
- }
114882
- const fieldInfo = ctx.getStructFieldInfo(
114883
- ctx.previousStructType,
114884
- ctx.previousMemberName
114885
- );
114886
- if (!fieldInfo) {
114887
- return null;
114888
- }
114889
- const { type: memberType, dimensions } = fieldInfo;
114890
- const isStringField = memberType.startsWith("string<");
114891
- if (dimensions && dimensions.length > 1 && isStringField) {
114892
- if (ctx.subscriptDepth === 0) {
114893
- return { code: String(dimensions[0]), effects: [], skipContinue: true };
114894
- }
114895
- return makeStrlenResult(ctx.result, true);
114896
- }
114897
- if (dimensions?.length === 1 && isStringField) {
114898
- return makeStrlenResult(ctx.result, true);
114899
- }
114900
- if (dimensions && dimensions.length > 0 && ctx.subscriptDepth < dimensions.length) {
114901
- return {
114902
- code: String(dimensions[ctx.subscriptDepth]),
114903
- effects: [],
114904
- skipContinue: true
114905
- };
114906
- }
114907
- if (dimensions && dimensions.length > 0 && ctx.subscriptDepth >= dimensions.length) {
114908
- return makeBitWidthResult(memberType, true, true);
114909
- }
114910
- return makeBitWidthResult(memberType, true, false);
114911
- }
114912
- function handleStringLength(ctx, typeInfo) {
114913
- if (typeInfo.arrayDimensions && typeInfo.arrayDimensions.length > 1) {
114914
- if (ctx.subscriptDepth === 0) {
114915
- return {
114916
- code: String(typeInfo.arrayDimensions[0]),
114917
- effects: [],
114918
- skipContinue: false
114919
- };
114920
- }
114921
- return makeStrlenResult(ctx.result, false);
114922
- }
114923
- if (ctx.currentIdentifier && ctx.lengthCache?.has(ctx.currentIdentifier)) {
114924
- return {
114925
- code: ctx.lengthCache.get(ctx.currentIdentifier),
114926
- effects: [],
114927
- skipContinue: false
114928
- };
114929
- }
114930
- const target = ctx.currentIdentifier ?? ctx.result;
114931
- return makeStrlenResult(target, false);
114932
- }
114933
- function handleFullySubscriptedArrayLength(ctx, typeInfo) {
114934
- if (typeInfo.isEnum) {
114935
- return { code: "32", effects: [], skipContinue: false };
114936
- }
114937
- if (typeInfo.baseType.startsWith("string<") || typeInfo.isString) {
114938
- return makeStrlenResult(ctx.result, false);
114939
- }
114940
- let elementBitWidth = getTypeBitWidth(typeInfo.baseType);
114941
- if (elementBitWidth === 0 && typeInfo.isBitmap && typeInfo.bitmapTypeName && ctx.getBitmapBitWidth) {
114942
- elementBitWidth = ctx.getBitmapBitWidth(typeInfo.bitmapTypeName) || 0;
114943
- }
114944
- if (elementBitWidth > 0) {
114945
- return { code: String(elementBitWidth), effects: [], skipContinue: false };
114946
- }
114947
- return {
114948
- code: `/* .length: unsupported element type ${typeInfo.baseType} */0`,
114949
- effects: [],
114950
- skipContinue: false
114951
- };
114952
- }
114953
- var generateLengthProperty = (ctx) => {
114954
- if (ctx.mainArgsName && ctx.primaryId === ctx.mainArgsName) {
114955
- return { code: "argc", effects: [], skipContinue: false };
114956
- }
114957
- const structResult = handleStructMemberLength(ctx);
114958
- if (structResult) {
114959
- return structResult;
114960
- }
114961
- const typeInfo = ctx.typeInfo;
114962
- if (!typeInfo) {
114963
- return {
114964
- code: `/* .length: unknown type for ${ctx.result} */0`,
114965
- effects: [],
114966
- skipContinue: false
114967
- };
114968
- }
114969
- if (typeInfo.isString) {
114970
- return handleStringLength(ctx, typeInfo);
114971
- }
114972
- const hasDimensions = typeInfo.isArray && typeInfo.arrayDimensions && typeInfo.arrayDimensions.length > 0;
114973
- if (hasDimensions && ctx.subscriptDepth < typeInfo.arrayDimensions.length) {
114974
- return {
114975
- code: String(typeInfo.arrayDimensions[ctx.subscriptDepth]),
114976
- effects: [],
114977
- skipContinue: false
114978
- };
114979
- }
114980
- if (hasDimensions && ctx.subscriptDepth >= typeInfo.arrayDimensions.length) {
114981
- return handleFullySubscriptedArrayLength(ctx, typeInfo);
114982
- }
114983
- if (typeInfo.isArray) {
114984
- return {
114985
- code: `/* .length unknown for ${ctx.currentIdentifier} */0`,
114986
- effects: [],
114987
- skipContinue: false
114988
- };
114989
- }
114990
- if (typeInfo.isEnum) {
114991
- return { code: "32", effects: [], skipContinue: false };
114992
- }
114993
- return { code: String(typeInfo.bitWidth), effects: [], skipContinue: false };
114994
- };
114995
114963
  var generateCapacityProperty = (typeInfo) => {
114996
114964
  if (typeInfo?.isString && typeInfo.stringCapacity !== void 0) {
114997
114965
  return { code: String(typeInfo.stringCapacity), effects: [] };
@@ -115016,7 +114984,6 @@ var generateBitmapFieldAccess = (result, fieldInfo) => {
115016
114984
  }
115017
114985
  };
115018
114986
  var accessGenerators = {
115019
- generateLengthProperty,
115020
114987
  generateCapacityProperty,
115021
114988
  generateSizeProperty,
115022
114989
  generateBitmapFieldAccess
@@ -115104,7 +115071,7 @@ var CallExprUtils = class _CallExprUtils {
115104
115071
  var CallExprUtils_default = CallExprUtils;
115105
115072
 
115106
115073
  // src/transpiler/output/codegen/types/C_TYPE_WIDTH.ts
115107
- var C_TYPE_WIDTH2 = {
115074
+ var C_TYPE_WIDTH = {
115108
115075
  uint8_t: 8,
115109
115076
  int8_t: 8,
115110
115077
  uint16_t: 16,
@@ -115132,7 +115099,7 @@ var C_TYPE_WIDTH2 = {
115132
115099
  "long long": 64,
115133
115100
  "unsigned long long": 64
115134
115101
  };
115135
- var C_TYPE_WIDTH_default = C_TYPE_WIDTH2;
115102
+ var C_TYPE_WIDTH_default = C_TYPE_WIDTH;
115136
115103
 
115137
115104
  // src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts
115138
115105
  var wrapWithCppEnumCast = (argCode, argExpr, targetParamBaseType, orchestrator) => {
@@ -115165,13 +115132,17 @@ var _generateCFunctionArg = (e, targetParam, input, orchestrator) => {
115165
115132
  return wrapWithCppEnumCast(argCode, e, targetParam?.baseType, orchestrator);
115166
115133
  }
115167
115134
  let argType = orchestrator.getExpressionType(e);
115135
+ let isPointerVariable = false;
115136
+ const typeInfo = CodeGenState.getVariableTypeInfo(argCode);
115168
115137
  if (!argType && !argCode.startsWith("&")) {
115169
- const typeInfo = CodeGenState.getVariableTypeInfo(argCode);
115170
115138
  if (typeInfo) {
115171
115139
  argType = typeInfo.baseType;
115172
115140
  }
115173
115141
  }
115174
- const needsAddressOf = argType && !argType.endsWith("*") && !argCode.startsWith("&") && !targetParam.isArray && (orchestrator.isStructType(argType) || _parameterExpectsAddressOf(targetParam.baseType, argType, orchestrator));
115142
+ if (typeInfo?.isPointer) {
115143
+ isPointerVariable = true;
115144
+ }
115145
+ const needsAddressOf = argType && !argType.endsWith("*") && !argCode.startsWith("&") && !targetParam.isArray && !isPointerVariable && (orchestrator.isStructType(argType) || _parameterExpectsAddressOf(targetParam.baseType, argType, orchestrator));
115175
115146
  if (needsAddressOf) {
115176
115147
  argCode = `&${argCode}`;
115177
115148
  }
@@ -115924,7 +115895,7 @@ var handleGlobalPrefix = (memberName, tracking, input, state, orchestrator) => {
115924
115895
  }
115925
115896
  return true;
115926
115897
  };
115927
- var handleThisScopeLength = (memberName, tracking, input, state, orchestrator) => {
115898
+ var handleThisScopeLength = (memberName, tracking, _input, state, orchestrator) => {
115928
115899
  if (tracking.result !== "__THIS_SCOPE__" || memberName !== "length") {
115929
115900
  return false;
115930
115901
  }
@@ -116013,19 +115984,9 @@ var tryExplicitLengthProperty = (memberName, tracking, rootIdentifier, input, st
116013
115984
  };
116014
115985
  var tryPropertyAccess = (memberName, tracking, rootIdentifier, input, state, orchestrator, effects) => {
116015
115986
  if (memberName === "length") {
116016
- const ctx = createExplicitLengthContext(tracking, rootIdentifier);
116017
- const lengthResult = generateLengthProperty2(
116018
- ctx,
116019
- input,
116020
- state,
116021
- orchestrator,
116022
- effects
115987
+ throw new Error(
115988
+ `Error: '.length' on '${tracking.result}' is deprecated. Use explicit properties: .bit_length (bit width), .byte_length (byte size), .element_count (array size), or .char_count (string length)`
116023
115989
  );
116024
- if (lengthResult !== null) {
116025
- applyPropertyResult(tracking, lengthResult);
116026
- return true;
116027
- }
116028
- return false;
116029
115990
  }
116030
115991
  const explicitProps = /* @__PURE__ */ new Set([
116031
115992
  "bit_length",
@@ -116070,129 +116031,6 @@ var tryPropertyAccess = (memberName, tracking, rootIdentifier, input, state, orc
116070
116031
  }
116071
116032
  return false;
116072
116033
  };
116073
- var generateLengthProperty2 = (ctx, input, state, orchestrator, effects) => {
116074
- if (state.mainArgsName && ctx.rootIdentifier === state.mainArgsName) {
116075
- return "argc";
116076
- }
116077
- if (ctx.previousStructType && ctx.previousMemberName) {
116078
- const fieldInfo = orchestrator.getStructFieldInfo(
116079
- ctx.previousStructType,
116080
- ctx.previousMemberName
116081
- );
116082
- if (fieldInfo) {
116083
- return generateStructFieldLength(
116084
- ctx.result,
116085
- fieldInfo,
116086
- ctx.subscriptDepth,
116087
- input,
116088
- orchestrator,
116089
- effects
116090
- );
116091
- }
116092
- }
116093
- const typeInfo = ctx.resolvedIdentifier ? CodeGenState.getVariableTypeInfo(ctx.resolvedIdentifier) : void 0;
116094
- if (!typeInfo) {
116095
- return `/* .length: unknown type for ${ctx.result} */0`;
116096
- }
116097
- return generateTypeInfoLength(
116098
- ctx.result,
116099
- typeInfo,
116100
- ctx.subscriptDepth,
116101
- ctx.resolvedIdentifier,
116102
- input,
116103
- state,
116104
- effects
116105
- );
116106
- };
116107
- var generateStructFieldLength = (result, fieldInfo, subscriptDepth, input, orchestrator, effects) => {
116108
- const memberType = fieldInfo.type;
116109
- const dimensions = fieldInfo.dimensions;
116110
- const isStringField = TypeCheckUtils_default.isString(memberType);
116111
- if (dimensions?.length && dimensions.length > 1 && isStringField) {
116112
- if (subscriptDepth === 0) {
116113
- return String(dimensions[0]);
116114
- } else {
116115
- effects.push({ type: "include", header: "string" });
116116
- return `strlen(${result})`;
116117
- }
116118
- } else if (dimensions?.length === 1 && isStringField) {
116119
- effects.push({ type: "include", header: "string" });
116120
- return `strlen(${result})`;
116121
- } else if (dimensions?.length && dimensions.length > 0 && subscriptDepth < dimensions.length) {
116122
- return String(dimensions[subscriptDepth]);
116123
- } else if (dimensions?.length && dimensions.length > 0 && subscriptDepth >= dimensions.length) {
116124
- return getTypeBitWidth2(memberType, input);
116125
- } else {
116126
- return getTypeBitWidth2(memberType, input);
116127
- }
116128
- };
116129
- var generateTypeInfoLength = (result, typeInfo, subscriptDepth, resolvedIdentifier, input, state, effects) => {
116130
- if (typeInfo.isString) {
116131
- return generateStringLength(
116132
- result,
116133
- typeInfo,
116134
- subscriptDepth,
116135
- resolvedIdentifier,
116136
- state
116137
- );
116138
- }
116139
- if (typeInfo.isEnum && !typeInfo.isArray) {
116140
- return "32";
116141
- }
116142
- if (!typeInfo.isArray) {
116143
- return String(typeInfo.bitWidth || 0);
116144
- }
116145
- const dims = typeInfo.arrayDimensions;
116146
- if (!dims || dims.length === 0) {
116147
- return `/* .length unknown for ${resolvedIdentifier} */0`;
116148
- }
116149
- if (subscriptDepth < dims.length) {
116150
- return String(dims[subscriptDepth]);
116151
- }
116152
- return generateElementTypeLength(result, typeInfo, input, effects);
116153
- };
116154
- var generateStringLength = (result, typeInfo, subscriptDepth, resolvedIdentifier, state) => {
116155
- const dims = typeInfo.arrayDimensions;
116156
- if (dims && dims.length > 1) {
116157
- return subscriptDepth === 0 ? String(dims[0]) : `strlen(${result})`;
116158
- }
116159
- if (subscriptDepth > 0) {
116160
- return `strlen(${result})`;
116161
- }
116162
- if (resolvedIdentifier && state.lengthCache?.has(resolvedIdentifier)) {
116163
- return state.lengthCache.get(resolvedIdentifier);
116164
- }
116165
- return resolvedIdentifier ? `strlen(${resolvedIdentifier})` : `strlen(${result})`;
116166
- };
116167
- var generateElementTypeLength = (result, typeInfo, input, effects) => {
116168
- if (typeInfo.isEnum) {
116169
- return "32";
116170
- }
116171
- if (TypeCheckUtils_default.isString(typeInfo.baseType) || typeInfo.isString) {
116172
- effects.push({ type: "include", header: "string" });
116173
- return `strlen(${result})`;
116174
- }
116175
- let elementBitWidth = TYPE_WIDTH_default[typeInfo.baseType] || 0;
116176
- if (elementBitWidth === 0 && typeInfo.isBitmap && typeInfo.bitmapTypeName) {
116177
- elementBitWidth = input.symbols.bitmapBitWidth.get(typeInfo.bitmapTypeName) || 0;
116178
- }
116179
- if (elementBitWidth > 0) {
116180
- return String(elementBitWidth);
116181
- }
116182
- return `/* .length: unsupported element type ${typeInfo.baseType} */0`;
116183
- };
116184
- var getTypeBitWidth2 = (typeName, input) => {
116185
- let bitWidth = TYPE_WIDTH_default[typeName] || C_TYPE_WIDTH_default[typeName] || 0;
116186
- if (bitWidth === 0 && input.symbolTable) {
116187
- const enumWidth = input.symbolTable.getEnumBitWidth(typeName);
116188
- if (enumWidth) bitWidth = enumWidth;
116189
- }
116190
- if (bitWidth > 0) {
116191
- return String(bitWidth);
116192
- } else {
116193
- return `/* .length: unsupported type ${typeName} */0`;
116194
- }
116195
- };
116196
116034
  var getNumericBitWidth = (typeName, input) => {
116197
116035
  let bitWidth = TYPE_WIDTH_default[typeName] ?? C_TYPE_WIDTH_default[typeName] ?? 0;
116198
116036
  if (bitWidth === 0 && input.symbolTable) {
@@ -116468,11 +116306,10 @@ var generateCharCountProperty = (ctx, input, state, orchestrator, effects) => {
116468
116306
  );
116469
116307
  }
116470
116308
  effects.push({ type: "include", header: "string" });
116471
- if (ctx.resolvedIdentifier && state.lengthCache?.has(ctx.resolvedIdentifier)) {
116309
+ if (ctx.subscriptDepth === 0 && ctx.resolvedIdentifier && state.lengthCache?.has(ctx.resolvedIdentifier)) {
116472
116310
  return state.lengthCache.get(ctx.resolvedIdentifier);
116473
116311
  }
116474
- const target = ctx.resolvedIdentifier ?? ctx.result;
116475
- return `strlen(${target})`;
116312
+ return `strlen(${ctx.result})`;
116476
116313
  };
116477
116314
  var initializeMemberOutput = (ctx) => ({
116478
116315
  result: ctx.result,
@@ -116861,15 +116698,18 @@ var VariableModifierBuilder = class {
116861
116698
  *
116862
116699
  * @param ctx - Parser context with modifier methods
116863
116700
  * @param inFunctionBody - Whether we're inside a function body (affects extern)
116701
+ * @param hasInitializer - Whether the variable has an initializer (affects extern in C mode)
116702
+ * @param cppMode - Whether we're generating C++ code (affects extern behavior)
116864
116703
  * @returns Modifier strings ready for use in generated code
116865
116704
  * @throws Error if both atomic and volatile are specified
116866
116705
  */
116867
- static build(ctx, inFunctionBody) {
116706
+ static build(ctx, inFunctionBody, hasInitializer = false, cppMode = false) {
116868
116707
  const hasConst = ctx.constModifier?.() ?? false;
116869
116708
  const constMod = hasConst ? "const " : "";
116870
116709
  const atomicMod = ctx.atomicModifier() ? "volatile " : "";
116871
116710
  const volatileMod = ctx.volatileModifier() ? "volatile " : "";
116872
- const externMod = hasConst && !inFunctionBody ? "extern " : "";
116711
+ const needsExtern = hasConst && !inFunctionBody && (cppMode || !hasInitializer);
116712
+ const externMod = needsExtern ? "extern " : "";
116873
116713
  if (ctx.atomicModifier() && ctx.volatileModifier()) {
116874
116714
  const line = ctx.start?.line ?? 0;
116875
116715
  throw new Error(
@@ -118057,16 +117897,17 @@ var ScopeGenerator_default = generateScope;
118057
117897
  // src/utils/BitUtils.ts
118058
117898
  var BitUtils = class _BitUtils {
118059
117899
  /**
118060
- * Convert a boolean expression to an integer (0 or 1).
117900
+ * Convert a boolean expression to an unsigned integer (0U or 1U).
118061
117901
  * Handles literal "true"/"false" and generates ternary for expressions.
117902
+ * Uses unsigned literals for MISRA C:2012 Rule 10.1 compliance.
118062
117903
  *
118063
117904
  * @param expr - The expression to convert
118064
- * @returns C code string representing the integer value
117905
+ * @returns C code string representing the unsigned integer value
118065
117906
  */
118066
117907
  static boolToInt(expr) {
118067
- if (expr === "true") return "1";
118068
- if (expr === "false") return "0";
118069
- return `(${expr} ? 1 : 0)`;
117908
+ if (expr === "true") return "1U";
117909
+ if (expr === "false") return "0U";
117910
+ return `(${expr} ? 1U : 0U)`;
118070
117911
  }
118071
117912
  /**
118072
117913
  * Generate a bit mask for the given width.
@@ -118123,24 +117964,26 @@ var BitUtils = class _BitUtils {
118123
117964
  }
118124
117965
  }
118125
117966
  /**
118126
- * Return the appropriate "1" literal for a given type.
118127
- * Uses "1ULL" for 64-bit types to avoid undefined behavior on large shifts.
117967
+ * Return the appropriate unsigned "1" literal for a given type.
117968
+ * Uses "1ULL" for 64-bit types, "1U" for others.
117969
+ * MISRA C:2012 Rule 10.1 requires unsigned operands for bitwise operations.
118128
117970
  *
118129
117971
  * @param typeName - The C-Next type name (e.g., "u64", "i32")
118130
- * @returns "1ULL" for 64-bit types, "1" otherwise
117972
+ * @returns "1ULL" for 64-bit types, "1U" otherwise
118131
117973
  */
118132
117974
  static oneForType(typeName) {
118133
- return typeName === "u64" || typeName === "i64" ? "1ULL" : "1";
117975
+ return typeName === "u64" || typeName === "i64" ? "1ULL" : "1U";
118134
117976
  }
118135
117977
  /**
118136
- * Format a number as an uppercase hex string (e.g., 255 -> "0xFF").
117978
+ * Format a number as an unsigned uppercase hex string (e.g., 255 -> "0xFFU").
118137
117979
  * Used for generating hex mask literals in generated C code.
117980
+ * Includes U suffix for MISRA C:2012 Rule 10.1 compliance.
118138
117981
  *
118139
117982
  * @param value - The numeric value to format
118140
- * @returns Hex string like "0xFF" or "0x1F"
117983
+ * @returns Hex string like "0xFFU" or "0x1FU"
118141
117984
  */
118142
117985
  static formatHex(value) {
118143
- return `0x${value.toString(16).toUpperCase()}`;
117986
+ return `0x${value.toString(16).toUpperCase()}U`;
118144
117987
  }
118145
117988
  /**
118146
117989
  * Generate code to read a single bit from a value.
@@ -118186,7 +118029,7 @@ var BitUtils = class _BitUtils {
118186
118029
  static singleBitWrite(target, offset, value, targetType) {
118187
118030
  const intValue = _BitUtils.boolToInt(value);
118188
118031
  const is64Bit = targetType === "u64" || targetType === "i64";
118189
- const one = is64Bit ? "1ULL" : "1";
118032
+ const one = is64Bit ? "1ULL" : "1U";
118190
118033
  const valueShift = is64Bit ? `((uint64_t)${intValue} << ${offset})` : `(${intValue} << ${offset})`;
118191
118034
  return `${target} = (${target} & ~(${one} << ${offset})) | ${valueShift};`;
118192
118035
  }
@@ -120870,7 +120713,7 @@ function getBitmapFieldInfo(bitmapType, fieldName, ctx) {
120870
120713
  function generateBitmapWrite(target, fieldInfo, value) {
120871
120714
  const { maskHex } = calculateMask(fieldInfo.width);
120872
120715
  if (fieldInfo.width === 1) {
120873
- return `${target} = (${target} & ~(1 << ${fieldInfo.offset})) | (${BitUtils_default.boolToInt(value)} << ${fieldInfo.offset});`;
120716
+ return `${target} = (${target} & ~(1U << ${fieldInfo.offset})) | (${BitUtils_default.boolToInt(value)} << ${fieldInfo.offset});`;
120874
120717
  } else {
120875
120718
  return `${target} = (${target} & ~(${maskHex} << ${fieldInfo.offset})) | ((${value} & ${maskHex}) << ${fieldInfo.offset});`;
120876
120719
  }
@@ -121123,9 +120966,9 @@ function handleRegisterBit(ctx) {
121123
120966
  bitIndex,
121124
120967
  true
121125
120968
  );
121126
- return `${fullName} = (1 << ${bitIndex});`;
120969
+ return `${fullName} = (1U << ${bitIndex});`;
121127
120970
  }
121128
- return `${fullName} = (${fullName} & ~(1 << ${bitIndex})) | (${BitUtils_default.boolToInt(ctx.generatedValue)} << ${bitIndex});`;
120971
+ return `${fullName} = (${fullName} & ~(1U << ${bitIndex})) | (${BitUtils_default.boolToInt(ctx.generatedValue)} << ${bitIndex});`;
121129
120972
  }
121130
120973
  function handleRegisterBitRange(ctx) {
121131
120974
  AssignmentHandlerUtils_default.validateNoCompoundForBitAccess(
@@ -121191,9 +121034,9 @@ function handleScopedRegisterBit(ctx) {
121191
121034
  bitIndex,
121192
121035
  true
121193
121036
  );
121194
- return `${regName} = (1 << ${bitIndex});`;
121037
+ return `${regName} = (1U << ${bitIndex});`;
121195
121038
  }
121196
- return `${regName} = (${regName} & ~(1 << ${bitIndex})) | (${BitUtils_default.boolToInt(ctx.generatedValue)} << ${bitIndex});`;
121039
+ return `${regName} = (${regName} & ~(1U << ${bitIndex})) | (${BitUtils_default.boolToInt(ctx.generatedValue)} << ${bitIndex});`;
121197
121040
  }
121198
121041
  function handleScopedRegisterBitRange(ctx) {
121199
121042
  AssignmentHandlerUtils_default.validateScopeContext(CodeGenState.currentScope);
@@ -121439,7 +121282,7 @@ function handleStructMemberBit(ctx) {
121439
121282
  validateNotCompound2(ctx);
121440
121283
  const target = gen6().generateAssignmentTarget(ctx.targetCtx);
121441
121284
  const bitIndex = gen6().generateExpression(ctx.subscripts.at(-1));
121442
- const one = "1";
121285
+ const one = "1U";
121443
121286
  const intValue = BitUtils_default.boolToInt(ctx.generatedValue);
121444
121287
  return `${target} = (${target} & ~(${one} << ${bitIndex})) | (${intValue} << ${bitIndex});`;
121445
121288
  }
@@ -121687,9 +121530,9 @@ function handleGlobalRegisterBit(ctx) {
121687
121530
  `Cannot assign false to write-only register bit ${regName}[${bitIndex}]. Use the corresponding CLEAR register to clear bits.`
121688
121531
  );
121689
121532
  }
121690
- return `${regName} = (1 << ${bitIndex});`;
121533
+ return `${regName} = (1U << ${bitIndex});`;
121691
121534
  }
121692
- return `${regName} = (${regName} & ~(1 << ${bitIndex})) | (${BitUtils_default.boolToInt(ctx.generatedValue)} << ${bitIndex});`;
121535
+ return `${regName} = (${regName} & ~(1U << ${bitIndex})) | (${BitUtils_default.boolToInt(ctx.generatedValue)} << ${bitIndex});`;
121693
121536
  }
121694
121537
  function handleMemberChain(ctx) {
121695
121538
  const bitAnalysis = gen9().analyzeMemberChainForBitAccess(ctx.targetCtx);
@@ -122361,7 +122204,7 @@ var AssignmentContextBuilder_default = buildAssignmentContext;
122361
122204
  // src/transpiler/output/codegen/analysis/StringLengthCounter.ts
122362
122205
  var StringLengthCounter = class _StringLengthCounter {
122363
122206
  /**
122364
- * Count .length accesses in an expression.
122207
+ * Count .char_count accesses in an expression.
122365
122208
  */
122366
122209
  static countExpression(ctx) {
122367
122210
  const counts = /* @__PURE__ */ new Map();
@@ -122369,7 +122212,7 @@ var StringLengthCounter = class _StringLengthCounter {
122369
122212
  return counts;
122370
122213
  }
122371
122214
  /**
122372
- * Count .length accesses in a block.
122215
+ * Count .char_count accesses in a block.
122373
122216
  */
122374
122217
  static countBlock(ctx) {
122375
122218
  const counts = /* @__PURE__ */ new Map();
@@ -122379,7 +122222,7 @@ var StringLengthCounter = class _StringLengthCounter {
122379
122222
  return counts;
122380
122223
  }
122381
122224
  /**
122382
- * Count .length accesses in a block, adding to existing counts.
122225
+ * Count .char_count accesses in a block, adding to existing counts.
122383
122226
  */
122384
122227
  static countBlockInto(ctx, counts) {
122385
122228
  for (const stmt of ctx.statement()) {
@@ -122387,7 +122230,7 @@ var StringLengthCounter = class _StringLengthCounter {
122387
122230
  }
122388
122231
  }
122389
122232
  /**
122390
- * Walk an expression tree, counting .length accesses.
122233
+ * Walk an expression tree, counting .char_count accesses.
122391
122234
  * Uses generic traversal - only postfix expressions need special handling.
122392
122235
  */
122393
122236
  static walkExpression(ctx, counts) {
@@ -122462,7 +122305,7 @@ var StringLengthCounter = class _StringLengthCounter {
122462
122305
  }
122463
122306
  }
122464
122307
  /**
122465
- * Walk a postfix expression - this is where we detect .length accesses.
122308
+ * Walk a postfix expression - this is where we detect .char_count accesses.
122466
122309
  */
122467
122310
  static walkPostfixExpr(ctx, counts) {
122468
122311
  const primary = ctx.primaryExpression();
@@ -122471,7 +122314,7 @@ var StringLengthCounter = class _StringLengthCounter {
122471
122314
  if (primaryId && ops.length > 0) {
122472
122315
  for (const op of ops) {
122473
122316
  const memberName = op.IDENTIFIER()?.getText();
122474
- if (memberName === "length") {
122317
+ if (memberName === "char_count") {
122475
122318
  const typeInfo = CodeGenState.getVariableTypeInfo(primaryId);
122476
122319
  if (typeInfo?.isString) {
122477
122320
  const currentCount = counts.get(primaryId) || 0;
@@ -122488,7 +122331,7 @@ var StringLengthCounter = class _StringLengthCounter {
122488
122331
  }
122489
122332
  }
122490
122333
  /**
122491
- * Walk a statement, counting .length accesses.
122334
+ * Walk a statement, counting .char_count accesses.
122492
122335
  */
122493
122336
  static walkStatement(ctx, counts) {
122494
122337
  if (ctx.assignmentStatement()) {
@@ -122520,95 +122363,6 @@ var StringLengthCounter = class _StringLengthCounter {
122520
122363
  };
122521
122364
  var StringLengthCounter_default = StringLengthCounter;
122522
122365
 
122523
- // src/transpiler/output/codegen/helpers/CppModeHelper.ts
122524
- var CppModeHelper = class {
122525
- /**
122526
- * Get address-of expression for struct parameter passing.
122527
- * C mode: `&expr` (pass pointer to struct)
122528
- * C++ mode: `expr` (pass reference directly)
122529
- *
122530
- * @param expr - The expression to potentially wrap
122531
- * @returns The expression with address-of operator in C mode
122532
- */
122533
- static maybeAddressOf(expr) {
122534
- return CodeGenState.cppMode ? expr : `&${expr}`;
122535
- }
122536
- /**
122537
- * Get dereference expression for struct parameter access.
122538
- * C mode: `(*expr)` (dereference pointer)
122539
- * C++ mode: `expr` (reference can be used directly)
122540
- *
122541
- * @param expr - The expression to potentially dereference
122542
- * @returns The expression with dereference in C mode
122543
- */
122544
- static maybeDereference(expr) {
122545
- return CodeGenState.cppMode ? expr : `(*${expr})`;
122546
- }
122547
- /**
122548
- * Get the type modifier for struct parameter declarations.
122549
- * C mode: `*` (pointer type)
122550
- * C++ mode: `&` (reference type)
122551
- *
122552
- * @returns The type modifier character
122553
- */
122554
- static refOrPtr() {
122555
- return CodeGenState.cppMode ? "&" : "*";
122556
- }
122557
- /**
122558
- * Get the member access separator for struct parameters.
122559
- * C mode: `->` (pointer member access)
122560
- * C++ mode: `.` (reference member access)
122561
- *
122562
- * @returns The member access separator
122563
- */
122564
- static memberSeparator() {
122565
- return CodeGenState.cppMode ? "." : "->";
122566
- }
122567
- /**
122568
- * Get NULL literal for the current mode.
122569
- * C mode: `NULL`
122570
- * C++ mode: `nullptr`
122571
- *
122572
- * @returns The null pointer literal
122573
- */
122574
- static nullLiteral() {
122575
- return CodeGenState.cppMode ? "nullptr" : "NULL";
122576
- }
122577
- /**
122578
- * Generate a cast expression for the current mode.
122579
- * C mode: `(type)expr`
122580
- * C++ mode: `static_cast<type>(expr)`
122581
- *
122582
- * @param type - The target type
122583
- * @param expr - The expression to cast
122584
- * @returns The cast expression
122585
- */
122586
- static cast(type, expr) {
122587
- return CodeGenState.cppMode ? `static_cast<${type}>(${expr})` : `(${type})${expr}`;
122588
- }
122589
- /**
122590
- * Generate a reinterpret cast expression for the current mode.
122591
- * C mode: `(type)expr`
122592
- * C++ mode: `reinterpret_cast<type>(expr)`
122593
- *
122594
- * @param type - The target type
122595
- * @param expr - The expression to cast
122596
- * @returns The cast expression
122597
- */
122598
- static reinterpretCast(type, expr) {
122599
- return CodeGenState.cppMode ? `reinterpret_cast<${type}>(${expr})` : `(${type})${expr}`;
122600
- }
122601
- /**
122602
- * Check if we're in C++ mode.
122603
- *
122604
- * @returns True if generating C++ code
122605
- */
122606
- static isCppMode() {
122607
- return CodeGenState.cppMode;
122608
- }
122609
- };
122610
- var CppModeHelper_default = CppModeHelper;
122611
-
122612
122366
  // src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts
122613
122367
  var MemberChainAnalyzer = class _MemberChainAnalyzer {
122614
122368
  /**
@@ -122839,6 +122593,9 @@ var ArgumentGenerator = class _ArgumentGenerator {
122839
122593
  if (typeInfo?.isArray && !typeInfo.isString) {
122840
122594
  return id;
122841
122595
  }
122596
+ if (typeInfo?.isPointer) {
122597
+ return id;
122598
+ }
122842
122599
  if (CodeGenState.currentScope) {
122843
122600
  const members = CodeGenState.getScopeMembers(CodeGenState.currentScope);
122844
122601
  if (members?.has(id)) {
@@ -124105,7 +123862,11 @@ var StringDeclHelper = class _StringDeclHelper {
124105
123862
  initValue,
124106
123863
  arrayDims
124107
123864
  );
124108
- return { code: `${decl} = ${finalInitValue};`, handled: true };
123865
+ const suppression = "// cppcheck-suppress misra-c2012-9.3\n// cppcheck-suppress misra-c2012-9.4\n";
123866
+ return {
123867
+ code: `${suppression}${decl} = ${finalInitValue};`,
123868
+ handled: true
123869
+ };
124109
123870
  }
124110
123871
  /**
124111
123872
  * Handle size inference for empty array dimension.
@@ -124581,15 +124342,21 @@ ${assignments}`;
124581
124342
  { generateType: callbacks.generateType }
124582
124343
  );
124583
124344
  }
124345
+ const hasInitializer = ctx.expression() !== null;
124584
124346
  const modifiers = VariableModifierBuilder_default.build(
124585
124347
  ctx,
124586
- CodeGenState.inFunctionBody
124348
+ CodeGenState.inFunctionBody,
124349
+ hasInitializer,
124350
+ CodeGenState.cppMode
124587
124351
  );
124588
124352
  const name = ctx.IDENTIFIER().getText();
124589
124353
  const typeCtx = ctx.type();
124590
124354
  _VariableDeclHelper.validateArrayDeclarationSyntax(ctx, typeCtx, name);
124591
124355
  const type = callbacks.inferVariableType(ctx, name);
124592
124356
  callbacks.trackLocalVariable(ctx, name);
124357
+ if (type.endsWith("*")) {
124358
+ callbacks.markVariableAsPointer(name);
124359
+ }
124593
124360
  const stringResult = StringDeclHelper_default.generateStringDecl(
124594
124361
  typeCtx,
124595
124362
  name,
@@ -125625,6 +125392,33 @@ var TypedefParamParser = class _TypedefParamParser {
125625
125392
  static shouldBeConst(typedefType, paramIndex) {
125626
125393
  return _TypedefParamParser.getParamAt(typedefType, paramIndex)?.isConst ?? null;
125627
125394
  }
125395
+ /**
125396
+ * Resolve callback pointer/const overrides onto an array of IParameterSymbol.
125397
+ *
125398
+ * Issue #914: This is the single point where callback typedef info is applied
125399
+ * to parameters — used by both .c and .h generation paths via IParameterSymbol.
125400
+ *
125401
+ * @param params - The original parameter symbols
125402
+ * @param callbackTypedefType - The typedef type string (e.g., "void (*)(widget_t *, const rect_t *)")
125403
+ * @returns New array with isCallbackPointer/isCallbackConst resolved
125404
+ */
125405
+ static resolveCallbackParams(params, callbackTypedefType) {
125406
+ return params.map((param, index) => {
125407
+ const shouldBePointer = _TypedefParamParser.shouldBePointer(
125408
+ callbackTypedefType,
125409
+ index
125410
+ );
125411
+ const shouldBeConst = _TypedefParamParser.shouldBeConst(
125412
+ callbackTypedefType,
125413
+ index
125414
+ );
125415
+ return {
125416
+ ...param,
125417
+ isCallbackPointer: shouldBePointer ?? void 0,
125418
+ isCallbackConst: shouldBeConst ?? void 0
125419
+ };
125420
+ });
125421
+ }
125628
125422
  };
125629
125423
  var TypedefParamParser_default = TypedefParamParser;
125630
125424
 
@@ -126396,7 +126190,7 @@ var PassByValueAnalyzer = class _PassByValueAnalyzer {
126396
126190
  * Used by both function call tracking and subscript access tracking.
126397
126191
  */
126398
126192
  static walkOrExpression(orExpr, handler) {
126399
- orExpr.andExpression().flatMap((and) => and.equalityExpression()).flatMap((eq) => eq.relationalExpression()).flatMap((rel) => rel.bitwiseOrExpression()).flatMap((bor) => bor.bitwiseXorExpression()).flatMap((bxor) => bxor.bitwiseAndExpression()).flatMap((band) => band.shiftExpression()).flatMap((shift) => shift.additiveExpression()).flatMap((add) => add.multiplicativeExpression()).flatMap((mul) => mul.unaryExpression()).forEach(handler);
126193
+ ExpressionUtils_default.collectUnaryFromOrExpr(orExpr).forEach(handler);
126400
126194
  }
126401
126195
  /**
126402
126196
  * Walk an orExpression tree for function calls.
@@ -126751,6 +126545,7 @@ var ParameterInputAdapter = class {
126751
126545
  isPassByReference: false
126752
126546
  };
126753
126547
  }
126548
+ const isCallbackPointer = param.isCallbackPointer ?? false;
126754
126549
  return {
126755
126550
  name: param.name,
126756
126551
  baseType: param.type,
@@ -126760,8 +126555,10 @@ var ParameterInputAdapter = class {
126760
126555
  isArray: false,
126761
126556
  isCallback: false,
126762
126557
  isString: false,
126763
- isPassByValue: deps.isPassByValue,
126764
- isPassByReference: !deps.isPassByValue
126558
+ isPassByValue: isCallbackPointer ? false : deps.isPassByValue,
126559
+ isPassByReference: isCallbackPointer ? true : !deps.isPassByValue,
126560
+ forcePointerSyntax: isCallbackPointer || void 0,
126561
+ forceConst: param.isCallbackConst || void 0
126765
126562
  };
126766
126563
  }
126767
126564
  /**
@@ -127571,7 +127368,7 @@ var CodeGenerator = class _CodeGenerator {
127571
127368
  if (!arrayAccessMatch) {
127572
127369
  return false;
127573
127370
  }
127574
- if (text.endsWith(".length") || text.endsWith(".capacity") || text.endsWith(".size")) {
127371
+ if (text.endsWith(".length") || text.endsWith(".capacity") || text.endsWith(".size") || text.endsWith(".bit_length") || text.endsWith(".byte_length") || text.endsWith(".element_count") || text.endsWith(".char_count")) {
127575
127372
  return false;
127576
127373
  }
127577
127374
  const arrayName = arrayAccessMatch[1];
@@ -128631,7 +128428,8 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
128631
128428
  );
128632
128429
  if (symbols.hasPublicSymbols() && CodeGenState.sourcePath) {
128633
128430
  const pathToUse = options?.sourceRelativePath || CodeGenState.sourcePath.replace(/^.*[\\/]/, "");
128634
- const headerName = pathToUse.replace(/\.cnx$|\.cnext$/, ".h");
128431
+ const ext = CodeGenState.cppMode ? ".hpp" : ".h";
128432
+ const headerName = pathToUse.replace(/\.cnx$|\.cnext$/, ext);
128635
128433
  output.push(`#include "${headerName}"`, "");
128636
128434
  CodeGenState.selfIncludeAdded = true;
128637
128435
  }
@@ -129771,6 +129569,7 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
129771
129569
  getExpressionType: (exprCtx) => this.getExpressionType(exprCtx),
129772
129570
  inferVariableType: (varCtx, name) => this._inferVariableType(varCtx, name),
129773
129571
  trackLocalVariable: (varCtx, name) => this._trackLocalVariable(varCtx, name),
129572
+ markVariableAsPointer: (name) => this._markVariableAsPointer(name),
129774
129573
  getStringConcatOperands: (concatCtx) => this._getStringConcatOperands(concatCtx),
129775
129574
  getSubstringOperands: (substrCtx) => this._getSubstringOperands(substrCtx),
129776
129575
  getStringExprCapacity: (exprCode) => this.getStringExprCapacity(exprCode),
@@ -129779,20 +129578,116 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
129779
129578
  }
129780
129579
  /**
129781
129580
  * Issue #696: Infer variable type, handling nullable C pointer types.
129581
+ * Issue #895 Bug B: Infer pointer type from C function return type.
129782
129582
  */
129783
129583
  _inferVariableType(ctx, name) {
129784
- let type = this.generateType(ctx.type());
129785
- if (!name.startsWith("c_") || !ctx.expression()) {
129584
+ const type = this.generateType(ctx.type());
129585
+ if (!ctx.expression()) {
129786
129586
  return type;
129787
129587
  }
129788
- const exprText = ctx.expression().getText();
129789
- for (const funcName of NullCheckAnalyzer_default.getStructPointerFunctions()) {
129790
- if (exprText.includes(`${funcName}(`)) {
129791
- return `${type}*`;
129588
+ const pointerType = this._inferPointerTypeFromFunctionCall(
129589
+ ctx.expression(),
129590
+ type
129591
+ );
129592
+ if (pointerType) {
129593
+ return pointerType;
129594
+ }
129595
+ if (name.startsWith("c_")) {
129596
+ const exprText = ctx.expression().getText();
129597
+ for (const funcName of NullCheckAnalyzer_default.getStructPointerFunctions()) {
129598
+ if (exprText.includes(`${funcName}(`)) {
129599
+ return `${type}*`;
129600
+ }
129792
129601
  }
129793
129602
  }
129794
129603
  return type;
129795
129604
  }
129605
+ /**
129606
+ * Issue #895 Bug B: Infer pointer type from C function return type.
129607
+ * If initializer is a call to a C function that returns T*, and declared
129608
+ * type is T, return T* instead of T.
129609
+ */
129610
+ _inferPointerTypeFromFunctionCall(expr, declaredType) {
129611
+ const funcName = this._extractCFunctionName(expr);
129612
+ if (!funcName) {
129613
+ return null;
129614
+ }
129615
+ const cFunc = CodeGenState.symbolTable?.getCSymbol(funcName);
129616
+ if (cFunc?.kind !== "function") {
129617
+ return null;
129618
+ }
129619
+ const returnType = cFunc.type;
129620
+ if (!returnType.endsWith("*")) {
129621
+ return null;
129622
+ }
129623
+ const returnBaseType = returnType.replace(/\s*\*\s*$/, "").trim();
129624
+ if (returnBaseType === declaredType) {
129625
+ return `${declaredType}*`;
129626
+ }
129627
+ return null;
129628
+ }
129629
+ /**
129630
+ * Extract C function name from expression patterns.
129631
+ * Handles both:
129632
+ * - global.funcName(...) - explicit global access
129633
+ * - funcName(...) - direct call (if funcName is a known C function)
129634
+ * Returns null if expression doesn't match these patterns.
129635
+ */
129636
+ _extractCFunctionName(expr) {
129637
+ const postfix = ExpressionUnwrapper_default.getPostfixExpression(expr);
129638
+ if (!postfix) {
129639
+ return null;
129640
+ }
129641
+ const primary = postfix.primaryExpression();
129642
+ const ops = postfix.postfixOp();
129643
+ if (primary.GLOBAL()) {
129644
+ return this._extractGlobalPatternFuncName(ops);
129645
+ }
129646
+ const identifier = primary.IDENTIFIER();
129647
+ if (identifier) {
129648
+ return this._extractDirectCallFuncName(identifier.getText(), ops);
129649
+ }
129650
+ return null;
129651
+ }
129652
+ /**
129653
+ * Extract function name from global.funcName(...) pattern.
129654
+ */
129655
+ _extractGlobalPatternFuncName(ops) {
129656
+ if (ops.length < 2) {
129657
+ return null;
129658
+ }
129659
+ const memberOp = ops[0];
129660
+ if (!memberOp.IDENTIFIER()) {
129661
+ return null;
129662
+ }
129663
+ const callOp = ops[1];
129664
+ if (!this._isCallOp(callOp)) {
129665
+ return null;
129666
+ }
129667
+ return memberOp.IDENTIFIER().getText();
129668
+ }
129669
+ /**
129670
+ * Extract function name from direct funcName(...) call if it's a C function.
129671
+ */
129672
+ _extractDirectCallFuncName(funcName, ops) {
129673
+ if (ops.length < 1) {
129674
+ return null;
129675
+ }
129676
+ if (!this._isCallOp(ops[0])) {
129677
+ return null;
129678
+ }
129679
+ const cFunc = CodeGenState.symbolTable?.getCSymbol(funcName);
129680
+ if (cFunc?.kind === "function") {
129681
+ return funcName;
129682
+ }
129683
+ return null;
129684
+ }
129685
+ /**
129686
+ * Check if a postfix op is a function call.
129687
+ */
129688
+ _isCallOp(op) {
129689
+ return Boolean(op.argumentList() || op.getText().startsWith("("));
129690
+ }
129796
129691
  /**
129797
129692
  * Issue #696: Track local variable for type registry and const values.
129798
129693
  */
@@ -129813,6 +129708,20 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
129813
129708
  }
129814
129709
  }
129815
129710
  }
129711
+ /**
129712
+ * Issue #895 Bug B: Mark variable as a pointer in the type registry.
129713
+ * Called when type inference detects that a variable should be a pointer
129714
+ * (e.g., initialized from a C function returning T*).
129715
+ */
129716
+ _markVariableAsPointer(name) {
129717
+ const typeInfo = CodeGenState.getVariableTypeInfo(name);
129718
+ if (typeInfo) {
129719
+ CodeGenState.setVariableTypeInfo(name, {
129720
+ ...typeInfo,
129721
+ isPointer: true
129722
+ });
129723
+ }
129724
+ }
129816
129725
  // Issue #792: Methods _handleArrayDeclaration, _getArrayTypeDimension, _parseArrayTypeDimension,
129817
129726
  // _parseFirstArrayDimension, _validateArrayDeclarationSyntax, _extractBaseTypeName,
129818
129727
  // _generateVariableInitializer, _validateIntegerInitializer, _finalizeCppClassAssignments,
@@ -130968,10 +130877,15 @@ var HeaderGeneratorUtils = class _HeaderGeneratorUtils {
130968
130877
  }
130969
130878
  if (options.userIncludes && options.userIncludes.length > 0) {
130970
130879
  for (const include of options.userIncludes) {
130971
- lines.push(include);
130880
+ const transformedInclude = options.cppMode ? include.replace(/\.h"/, '.hpp"').replace(/\.h>/, ".hpp>") : include;
130881
+ lines.push(transformedInclude);
130972
130882
  }
130973
130883
  }
130974
- const userIncludeSet = new Set(options.userIncludes ?? []);
130884
+ const userIncludeSet = new Set(
130885
+ options.userIncludes?.map(
130886
+ (inc) => options.cppMode ? inc.replace(/\.h"/, '.hpp"').replace(/\.h>/, ".hpp>") : inc
130887
+ ) ?? []
130888
+ );
130975
130889
  for (const directive of headersToInclude) {
130976
130890
  if (!userIncludeSet.has(directive)) {
130977
130891
  lines.push(directive);
@@ -132785,7 +132699,7 @@ var TSymbolInfoAdapter = class _TSymbolInfoAdapter {
132785
132699
  var TSymbolInfoAdapter_default = TSymbolInfoAdapter;
132786
132700
 
132787
132701
  // src/transpiler/logic/symbols/SymbolUtils.ts
132788
- var RESERVED_FIELD_NAMES = /* @__PURE__ */ new Set(["length"]);
132702
+ var RESERVED_FIELD_NAMES = /* @__PURE__ */ new Set([]);
132789
132703
  function parseArrayDimensions2(text) {
132790
132704
  const dimensions = [];
132791
132705
  const arrayMatches = text.match(/\[(\d+)\]/g);
@@ -133389,6 +133303,8 @@ var FunctionCollector2 = class _FunctionCollector {
133389
133303
  const parameters = _FunctionCollector._mapParameters(
133390
133304
  DeclaratorUtils_default.extractFunctionParameters(declarator)
133391
133305
  );
133306
+ const hasPointer = declarator.pointer() !== null;
133307
+ const returnType = hasPointer ? `${baseType}*` : baseType;
133392
133308
  return {
133393
133309
  kind: "function",
133394
133310
  name,
@@ -133396,7 +133312,7 @@ var FunctionCollector2 = class _FunctionCollector {
133396
133312
  sourceLine: line,
133397
133313
  sourceLanguage: ESourceLanguage_default.C,
133398
133314
  isExported: !isExtern,
133399
- type: baseType,
133315
+ type: returnType,
133400
133316
  parameters: parameters.length > 0 ? parameters : void 0,
133401
133317
  isDeclaration: true
133402
133318
  };
@@ -137085,6 +137001,8 @@ var FunctionCallAnalyzer = class {
137085
137001
  if (sym?.kind !== "type") return false;
137086
137002
  return "type" in sym && typeof sym.type === "string" && sym.type.includes("(*)");
137087
137003
  }
137004
+ /** Current scope name during callback assignment scanning */
137005
+ scanCurrentScope = null;
137088
137006
  /**
137089
137007
  * Detect functions assigned to C function pointer typedefs.
137090
137008
  * When `PointCallback cb <- my_handler;` is found and PointCallback
@@ -137093,11 +137011,45 @@ var FunctionCallAnalyzer = class {
137093
137011
  collectCallbackCompatibleFunctions(tree) {
137094
137012
  for (const decl of tree.declaration()) {
137095
137013
  const funcDecl = decl.functionDeclaration();
137096
- if (!funcDecl) continue;
137097
- const block = funcDecl.block();
137098
- if (!block) continue;
137099
- this.scanBlockForCallbackAssignments(block);
137014
+ if (funcDecl) {
137015
+ this.scanStandaloneFunctionForCallbacks(funcDecl);
137016
+ continue;
137017
+ }
137018
+ const scopeDecl = decl.scopeDeclaration();
137019
+ if (scopeDecl) {
137020
+ this.scanScopeForCallbacks(scopeDecl);
137021
+ }
137022
+ }
137023
+ }
137024
+ /**
137025
+ * Scan a standalone function declaration for callback assignments.
137026
+ */
137027
+ scanStandaloneFunctionForCallbacks(funcDecl) {
137028
+ const block = funcDecl.block();
137029
+ if (!block) return;
137030
+ this.scanCurrentScope = null;
137031
+ this.scanBlockForCallbackAssignments(block);
137032
+ }
137033
+ /**
137034
+ * Scan all member functions in a scope for callback assignments (Issue #895).
137035
+ */
137036
+ scanScopeForCallbacks(scopeDecl) {
137037
+ const scopeName = scopeDecl.IDENTIFIER().getText();
137038
+ for (const member of scopeDecl.scopeMember()) {
137039
+ this.scanScopeMemberForCallbacks(member, scopeName);
137100
137040
  }
137041
+ this.scanCurrentScope = null;
137042
+ }
137043
+ /**
137044
+ * Scan a single scope member for callback assignments.
137045
+ */
137046
+ scanScopeMemberForCallbacks(member, scopeName) {
137047
+ const memberFunc = member.functionDeclaration();
137048
+ if (!memberFunc) return;
137049
+ const block = memberFunc.block();
137050
+ if (!block) return;
137051
+ this.scanCurrentScope = scopeName;
137052
+ this.scanBlockForCallbackAssignments(block);
137101
137053
  }
137102
137054
  /**
137103
137055
  * Recursively scan all statements in a block for callback typedef assignments.
@@ -137182,13 +137134,30 @@ var FunctionCallAnalyzer = class {
137182
137134
  }
137183
137135
  /**
137184
137136
  * Extract a function reference from an expression context.
137185
- * Matches bare identifiers (e.g., "my_handler") and qualified scope
137186
- * names (e.g., "MyScope.handler").
137137
+ * Matches:
137138
+ * - Bare identifiers: "my_handler"
137139
+ * - Qualified scope names: "MyScope.handler"
137140
+ * - Self-scope reference: "this.handler" (resolved using scanCurrentScope)
137141
+ * - Global scope reference: "global.ScopeName.handler"
137187
137142
  * Returns null if the expression is not a function reference.
137188
137143
  */
137189
137144
  extractFunctionReference(expr) {
137190
137145
  const text = expr.getText();
137191
- if (/^\w+(\.\w+)?$/.test(text)) {
137146
+ const thisPattern = /^this\.(\w+)$/;
137147
+ const thisMatch = thisPattern.exec(text);
137148
+ if (thisMatch) {
137149
+ if (!this.scanCurrentScope) {
137150
+ return null;
137151
+ }
137152
+ return this.scanCurrentScope + "." + thisMatch[1];
137153
+ }
137154
+ const globalPattern = /^global\.(\w+)\.(\w+)$/;
137155
+ const globalMatch = globalPattern.exec(text);
137156
+ if (globalMatch) {
137157
+ return globalMatch[1] + "." + globalMatch[2];
137158
+ }
137159
+ const simplePattern = /^\w+(\.\w+)?$/;
137160
+ if (simplePattern.test(text)) {
137192
137161
  return text;
137193
137162
  }
137194
137163
  return null;
@@ -137851,6 +137820,162 @@ var ArrayIndexTypeAnalyzer = class {
137851
137820
  };
137852
137821
  var ArrayIndexTypeAnalyzer_default = ArrayIndexTypeAnalyzer;
137853
137822
 
137823
+ // src/transpiler/logic/analysis/SignedShiftAnalyzer.ts
137824
+ import { ParseTreeWalker as ParseTreeWalker9 } from "antlr4ng";
137825
+ var SignedVariableCollector = class extends CNextListener {
137826
+ signedVars = /* @__PURE__ */ new Set();
137827
+ getSignedVars() {
137828
+ return this.signedVars;
137829
+ }
137830
+ /**
137831
+ * Track a typed identifier if it has a signed type
137832
+ */
137833
+ trackIfSigned(typeCtx, identifier) {
137834
+ if (!typeCtx) return;
137835
+ const typeName = typeCtx.getText();
137836
+ if (!TypeConstants_default.SIGNED_TYPES.includes(typeName)) return;
137837
+ if (!identifier) return;
137838
+ this.signedVars.add(identifier.getText());
137839
+ }
137840
+ /**
137841
+ * Track variable declarations with signed types
137842
+ */
137843
+ enterVariableDeclaration = (ctx) => {
137844
+ this.trackIfSigned(ctx.type(), ctx.IDENTIFIER());
137845
+ };
137846
+ /**
137847
+ * Track function parameters with signed types
137848
+ */
137849
+ enterParameter = (ctx) => {
137850
+ this.trackIfSigned(ctx.type(), ctx.IDENTIFIER());
137851
+ };
137852
+ /**
137853
+ * Track for-loop variable declarations with signed types
137854
+ */
137855
+ enterForVarDecl = (ctx) => {
137856
+ this.trackIfSigned(ctx.type(), ctx.IDENTIFIER());
137857
+ };
137858
+ };
137859
+ var SignedShiftListener = class extends CNextListener {
137860
+ analyzer;
137861
+ // eslint-disable-next-line @typescript-eslint/lines-between-class-members
137862
+ signedVars;
137863
+ constructor(analyzer, signedVars) {
137864
+ super();
137865
+ this.analyzer = analyzer;
137866
+ this.signedVars = signedVars;
137867
+ }
137868
+ /**
137869
+ * Check shift expressions for signed operands
137870
+ * shiftExpression: additiveExpression (('<<' | '>>') additiveExpression)*
137871
+ */
137872
+ enterShiftExpression = (ctx) => {
137873
+ const operands = ctx.additiveExpression();
137874
+ if (operands.length < 2) return;
137875
+ for (let i = 0; i < operands.length - 1; i++) {
137876
+ const operatorToken = ctx.getChild(i * 2 + 1);
137877
+ if (!operatorToken) continue;
137878
+ const operator = operatorToken.getText();
137879
+ if (operator !== "<<" && operator !== ">>") continue;
137880
+ const leftOperand = operands[i];
137881
+ if (this.isSignedOperand(leftOperand)) {
137882
+ const { line, column } = ParserUtils_default.getPosition(leftOperand);
137883
+ this.analyzer.addError(line, column, operator);
137884
+ }
137885
+ }
137886
+ };
137887
+ /**
137888
+ * Check if an additive expression contains a signed type operand
137889
+ */
137890
+ isSignedOperand(ctx) {
137891
+ const multExprs = ctx.multiplicativeExpression();
137892
+ for (const multExpr of multExprs) {
137893
+ const unaryExprs = multExpr.unaryExpression();
137894
+ for (const unaryExpr of unaryExprs) {
137895
+ if (this.isSignedUnaryExpression(unaryExpr)) {
137896
+ return true;
137897
+ }
137898
+ }
137899
+ }
137900
+ return false;
137901
+ }
137902
+ /**
137903
+ * Check if a unary expression is a signed type
137904
+ */
137905
+ isSignedUnaryExpression(ctx) {
137906
+ if (ctx.MINUS()) {
137907
+ const nestedUnary = ctx.unaryExpression();
137908
+ if (nestedUnary) {
137909
+ const nestedPostfix = nestedUnary.postfixExpression();
137910
+ if (nestedPostfix) {
137911
+ const nestedPrimary = nestedPostfix.primaryExpression();
137912
+ if (nestedPrimary?.literal()) {
137913
+ return true;
137914
+ }
137915
+ }
137916
+ return this.isSignedUnaryExpression(nestedUnary);
137917
+ }
137918
+ return false;
137919
+ }
137920
+ const postfixExpr = ctx.postfixExpression();
137921
+ if (!postfixExpr) return false;
137922
+ const primaryExpr = postfixExpr.primaryExpression();
137923
+ if (!primaryExpr) return false;
137924
+ const parenExpr = primaryExpr.expression();
137925
+ if (parenExpr) {
137926
+ return this.isSignedExpression(parenExpr);
137927
+ }
137928
+ const identifier = primaryExpr.IDENTIFIER();
137929
+ if (identifier) {
137930
+ return this.signedVars.has(identifier.getText());
137931
+ }
137932
+ return false;
137933
+ }
137934
+ /**
137935
+ * Check if a full expression contains signed operands
137936
+ */
137937
+ isSignedExpression(ctx) {
137938
+ const ternary = ctx.ternaryExpression();
137939
+ if (!ternary) return false;
137940
+ const additiveExprs = ExpressionUtils_default.collectAdditiveExpressions(ternary);
137941
+ return additiveExprs.some((addExpr) => this.isSignedOperand(addExpr));
137942
+ }
137943
+ };
137944
+ var SignedShiftAnalyzer = class {
137945
+ errors = [];
137946
+ /**
137947
+ * Analyze the parse tree for signed shift operations
137948
+ */
137949
+ analyze(tree) {
137950
+ this.errors = [];
137951
+ const collector = new SignedVariableCollector();
137952
+ ParseTreeWalker9.DEFAULT.walk(collector, tree);
137953
+ const signedVars = collector.getSignedVars();
137954
+ const listener = new SignedShiftListener(this, signedVars);
137955
+ ParseTreeWalker9.DEFAULT.walk(listener, tree);
137956
+ return this.errors;
137957
+ }
137958
+ /**
137959
+ * Add a signed shift error
137960
+ */
137961
+ addError(line, column, operator) {
137962
+ this.errors.push({
137963
+ code: "E0805",
137964
+ line,
137965
+ column,
137966
+ message: `Shift operator '${operator}' not allowed on signed integer types`,
137967
+ helpText: "Shift operations on signed integers have undefined (<<) or implementation-defined (>>) behavior. Use unsigned types (u8, u16, u32, u64) for bit manipulation."
137968
+ });
137969
+ }
137970
+ /**
137971
+ * Get all detected errors
137972
+ */
137973
+ getErrors() {
137974
+ return this.errors;
137975
+ }
137976
+ };
137977
+ var SignedShiftAnalyzer_default = SignedShiftAnalyzer;
137978
+
137854
137979
  // src/transpiler/logic/analysis/runAnalyzers.ts
137855
137980
  function collectErrors(analyzerErrors, target, formatMessage) {
137856
137981
  const formatter = formatMessage ?? ((e) => e.message);
@@ -137908,6 +138033,10 @@ function runAnalyzers(tree, tokenStream, options) {
137908
138033
  if (collectErrors(indexTypeAnalyzer.analyze(tree), errors, formatWithCode)) {
137909
138034
  return errors;
137910
138035
  }
138036
+ const signedShiftAnalyzer = new SignedShiftAnalyzer_default();
138037
+ if (collectErrors(signedShiftAnalyzer.analyze(tree), errors, formatWithCode)) {
138038
+ return errors;
138039
+ }
137911
138040
  const commentExtractor = new CommentExtractor_default(tokenStream);
137912
138041
  collectErrors(
137913
138042
  commentExtractor.validate(),
@@ -139003,7 +139132,8 @@ var Transpiler = class {
139003
139132
  const headerContent = this.generateHeaderForFile(file);
139004
139133
  if (headerContent) {
139005
139134
  const headerPath = this.pathResolver.getHeaderOutputPath(
139006
- file.discoveredFile
139135
+ file.discoveredFile,
139136
+ this.cppDetected
139007
139137
  );
139008
139138
  this.fs.writeFile(headerPath, headerContent);
139009
139139
  result.outputFiles.push(headerPath);
@@ -139406,7 +139536,8 @@ var Transpiler = class {
139406
139536
  if (exportedSymbols.length === 0) {
139407
139537
  return null;
139408
139538
  }
139409
- const headerName = basename5(sourcePath).replace(/\.cnx$|\.cnext$/, ".h");
139539
+ const ext = this.cppDetected ? ".hpp" : ".h";
139540
+ const headerName = basename5(sourcePath).replace(/\.cnx$|\.cnext$/, ext);
139410
139541
  const typeInput = this.state.getSymbolInfo(sourcePath);
139411
139542
  const passByValueParams = this.state.getPassByValueParams(sourcePath) ?? /* @__PURE__ */ new Map();
139412
139543
  const userIncludes = this.state.getUserIncludes(sourcePath);
@@ -139476,19 +139607,31 @@ var Transpiler = class {
139476
139607
  convertToHeaderSymbols(symbols, unmodifiedParams, knownEnums) {
139477
139608
  return symbols.map((symbol) => {
139478
139609
  const headerSymbol = HeaderSymbolAdapter_default.fromTSymbol(symbol);
139479
- if (symbol.kind === "function" && headerSymbol.parameters && headerSymbol.parameters.length > 0) {
139480
- const unmodified = unmodifiedParams.get(headerSymbol.name);
139481
- if (unmodified) {
139482
- const updatedParams = headerSymbol.parameters.map((param) => {
139483
- const isPointerParam = !param.isConst && !param.isArray && param.type !== "f32" && param.type !== "f64" && param.type !== "ISR" && !knownEnums.has(param.type ?? "");
139484
- const isArrayParam = param.isArray && !param.isConst;
139485
- if ((isPointerParam || isArrayParam) && unmodified.has(param.name)) {
139486
- return { ...param, isAutoConst: true };
139487
- }
139488
- return param;
139489
- });
139490
- return { ...headerSymbol, parameters: updatedParams };
139491
- }
139610
+ if (symbol.kind !== "function" || !headerSymbol.parameters || headerSymbol.parameters.length === 0) {
139611
+ return headerSymbol;
139612
+ }
139613
+ const typedefName = CodeGenState.callbackCompatibleFunctions.get(
139614
+ headerSymbol.name
139615
+ );
139616
+ const callbackTypedefType = typedefName ? CodeGenState.getTypedefType(typedefName) : void 0;
139617
+ if (callbackTypedefType) {
139618
+ const updatedParams = TypedefParamParser_default.resolveCallbackParams(
139619
+ headerSymbol.parameters,
139620
+ callbackTypedefType
139621
+ );
139622
+ return { ...headerSymbol, parameters: updatedParams };
139623
+ }
139624
+ const unmodified = unmodifiedParams.get(headerSymbol.name);
139625
+ if (unmodified) {
139626
+ const updatedParams = headerSymbol.parameters.map((param) => {
139627
+ const isPointerParam = !param.isConst && !param.isArray && param.type !== "f32" && param.type !== "f64" && param.type !== "ISR" && !knownEnums.has(param.type ?? "");
139628
+ const isArrayParam = param.isArray && !param.isConst;
139629
+ if ((isPointerParam || isArrayParam) && unmodified.has(param.name)) {
139630
+ return { ...param, isAutoConst: true };
139631
+ }
139632
+ return param;
139633
+ });
139634
+ return { ...headerSymbol, parameters: updatedParams };
139492
139635
  }
139493
139636
  return headerSymbol;
139494
139637
  });