c-next 0.2.6 → 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 (37) hide show
  1. package/dist/index.js +387 -433
  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/PassByValueAnalyzer.ts +1 -12
  9. package/src/transpiler/logic/analysis/SignedShiftAnalyzer.ts +239 -0
  10. package/src/transpiler/logic/analysis/__tests__/SignedShiftAnalyzer.test.ts +414 -0
  11. package/src/transpiler/logic/analysis/__tests__/StructFieldAnalyzer.test.ts +15 -75
  12. package/src/transpiler/logic/analysis/__tests__/runAnalyzers.test.ts +3 -15
  13. package/src/transpiler/logic/analysis/runAnalyzers.ts +11 -2
  14. package/src/transpiler/logic/analysis/types/ISignedShiftError.ts +15 -0
  15. package/src/transpiler/logic/symbols/SymbolUtils.ts +4 -1
  16. package/src/transpiler/logic/symbols/__tests__/SymbolUtils.test.ts +10 -11
  17. package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +4 -4
  18. package/src/transpiler/logic/symbols/cpp/__tests__/CppResolver.integration.test.ts +4 -4
  19. package/src/transpiler/output/codegen/CodeGenerator.ts +12 -4
  20. package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +3 -3
  21. package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +26 -26
  22. package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +12 -11
  23. package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +21 -21
  24. package/src/transpiler/output/codegen/generators/expressions/AccessExprGenerator.ts +7 -326
  25. package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +14 -275
  26. package/src/transpiler/output/codegen/generators/expressions/UnaryExprGenerator.ts +13 -1
  27. package/src/transpiler/output/codegen/generators/expressions/__tests__/AccessExprGenerator.test.ts +0 -573
  28. package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +8 -439
  29. package/src/transpiler/output/codegen/generators/expressions/__tests__/UnaryExprGenerator.test.ts +196 -0
  30. package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +7 -2
  31. package/src/transpiler/output/codegen/helpers/TypedefParamParser.ts +34 -0
  32. package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +48 -0
  33. package/src/transpiler/output/codegen/helpers/__tests__/TypedefParamParser.test.ts +88 -0
  34. package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +15 -2
  35. package/src/transpiler/output/headers/__tests__/BaseHeaderGenerator.test.ts +87 -0
  36. package/src/utils/ExpressionUtils.ts +51 -0
  37. 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.6",
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) => {
@@ -115928,7 +115895,7 @@ var handleGlobalPrefix = (memberName, tracking, input, state, orchestrator) => {
115928
115895
  }
115929
115896
  return true;
115930
115897
  };
115931
- var handleThisScopeLength = (memberName, tracking, input, state, orchestrator) => {
115898
+ var handleThisScopeLength = (memberName, tracking, _input, state, orchestrator) => {
115932
115899
  if (tracking.result !== "__THIS_SCOPE__" || memberName !== "length") {
115933
115900
  return false;
115934
115901
  }
@@ -116017,19 +115984,9 @@ var tryExplicitLengthProperty = (memberName, tracking, rootIdentifier, input, st
116017
115984
  };
116018
115985
  var tryPropertyAccess = (memberName, tracking, rootIdentifier, input, state, orchestrator, effects) => {
116019
115986
  if (memberName === "length") {
116020
- const ctx = createExplicitLengthContext(tracking, rootIdentifier);
116021
- const lengthResult = generateLengthProperty2(
116022
- ctx,
116023
- input,
116024
- state,
116025
- orchestrator,
116026
- 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)`
116027
115989
  );
116028
- if (lengthResult !== null) {
116029
- applyPropertyResult(tracking, lengthResult);
116030
- return true;
116031
- }
116032
- return false;
116033
115990
  }
116034
115991
  const explicitProps = /* @__PURE__ */ new Set([
116035
115992
  "bit_length",
@@ -116074,129 +116031,6 @@ var tryPropertyAccess = (memberName, tracking, rootIdentifier, input, state, orc
116074
116031
  }
116075
116032
  return false;
116076
116033
  };
116077
- var generateLengthProperty2 = (ctx, input, state, orchestrator, effects) => {
116078
- if (state.mainArgsName && ctx.rootIdentifier === state.mainArgsName) {
116079
- return "argc";
116080
- }
116081
- if (ctx.previousStructType && ctx.previousMemberName) {
116082
- const fieldInfo = orchestrator.getStructFieldInfo(
116083
- ctx.previousStructType,
116084
- ctx.previousMemberName
116085
- );
116086
- if (fieldInfo) {
116087
- return generateStructFieldLength(
116088
- ctx.result,
116089
- fieldInfo,
116090
- ctx.subscriptDepth,
116091
- input,
116092
- orchestrator,
116093
- effects
116094
- );
116095
- }
116096
- }
116097
- const typeInfo = ctx.resolvedIdentifier ? CodeGenState.getVariableTypeInfo(ctx.resolvedIdentifier) : void 0;
116098
- if (!typeInfo) {
116099
- return `/* .length: unknown type for ${ctx.result} */0`;
116100
- }
116101
- return generateTypeInfoLength(
116102
- ctx.result,
116103
- typeInfo,
116104
- ctx.subscriptDepth,
116105
- ctx.resolvedIdentifier,
116106
- input,
116107
- state,
116108
- effects
116109
- );
116110
- };
116111
- var generateStructFieldLength = (result, fieldInfo, subscriptDepth, input, orchestrator, effects) => {
116112
- const memberType = fieldInfo.type;
116113
- const dimensions = fieldInfo.dimensions;
116114
- const isStringField = TypeCheckUtils_default.isString(memberType);
116115
- if (dimensions?.length && dimensions.length > 1 && isStringField) {
116116
- if (subscriptDepth === 0) {
116117
- return String(dimensions[0]);
116118
- } else {
116119
- effects.push({ type: "include", header: "string" });
116120
- return `strlen(${result})`;
116121
- }
116122
- } else if (dimensions?.length === 1 && isStringField) {
116123
- effects.push({ type: "include", header: "string" });
116124
- return `strlen(${result})`;
116125
- } else if (dimensions?.length && dimensions.length > 0 && subscriptDepth < dimensions.length) {
116126
- return String(dimensions[subscriptDepth]);
116127
- } else if (dimensions?.length && dimensions.length > 0 && subscriptDepth >= dimensions.length) {
116128
- return getTypeBitWidth2(memberType, input);
116129
- } else {
116130
- return getTypeBitWidth2(memberType, input);
116131
- }
116132
- };
116133
- var generateTypeInfoLength = (result, typeInfo, subscriptDepth, resolvedIdentifier, input, state, effects) => {
116134
- if (typeInfo.isString) {
116135
- return generateStringLength(
116136
- result,
116137
- typeInfo,
116138
- subscriptDepth,
116139
- resolvedIdentifier,
116140
- state
116141
- );
116142
- }
116143
- if (typeInfo.isEnum && !typeInfo.isArray) {
116144
- return "32";
116145
- }
116146
- if (!typeInfo.isArray) {
116147
- return String(typeInfo.bitWidth || 0);
116148
- }
116149
- const dims = typeInfo.arrayDimensions;
116150
- if (!dims || dims.length === 0) {
116151
- return `/* .length unknown for ${resolvedIdentifier} */0`;
116152
- }
116153
- if (subscriptDepth < dims.length) {
116154
- return String(dims[subscriptDepth]);
116155
- }
116156
- return generateElementTypeLength(result, typeInfo, input, effects);
116157
- };
116158
- var generateStringLength = (result, typeInfo, subscriptDepth, resolvedIdentifier, state) => {
116159
- const dims = typeInfo.arrayDimensions;
116160
- if (dims && dims.length > 1) {
116161
- return subscriptDepth === 0 ? String(dims[0]) : `strlen(${result})`;
116162
- }
116163
- if (subscriptDepth > 0) {
116164
- return `strlen(${result})`;
116165
- }
116166
- if (resolvedIdentifier && state.lengthCache?.has(resolvedIdentifier)) {
116167
- return state.lengthCache.get(resolvedIdentifier);
116168
- }
116169
- return resolvedIdentifier ? `strlen(${resolvedIdentifier})` : `strlen(${result})`;
116170
- };
116171
- var generateElementTypeLength = (result, typeInfo, input, effects) => {
116172
- if (typeInfo.isEnum) {
116173
- return "32";
116174
- }
116175
- if (TypeCheckUtils_default.isString(typeInfo.baseType) || typeInfo.isString) {
116176
- effects.push({ type: "include", header: "string" });
116177
- return `strlen(${result})`;
116178
- }
116179
- let elementBitWidth = TYPE_WIDTH_default[typeInfo.baseType] || 0;
116180
- if (elementBitWidth === 0 && typeInfo.isBitmap && typeInfo.bitmapTypeName) {
116181
- elementBitWidth = input.symbols.bitmapBitWidth.get(typeInfo.bitmapTypeName) || 0;
116182
- }
116183
- if (elementBitWidth > 0) {
116184
- return String(elementBitWidth);
116185
- }
116186
- return `/* .length: unsupported element type ${typeInfo.baseType} */0`;
116187
- };
116188
- var getTypeBitWidth2 = (typeName, input) => {
116189
- let bitWidth = TYPE_WIDTH_default[typeName] || C_TYPE_WIDTH_default[typeName] || 0;
116190
- if (bitWidth === 0 && input.symbolTable) {
116191
- const enumWidth = input.symbolTable.getEnumBitWidth(typeName);
116192
- if (enumWidth) bitWidth = enumWidth;
116193
- }
116194
- if (bitWidth > 0) {
116195
- return String(bitWidth);
116196
- } else {
116197
- return `/* .length: unsupported type ${typeName} */0`;
116198
- }
116199
- };
116200
116034
  var getNumericBitWidth = (typeName, input) => {
116201
116035
  let bitWidth = TYPE_WIDTH_default[typeName] ?? C_TYPE_WIDTH_default[typeName] ?? 0;
116202
116036
  if (bitWidth === 0 && input.symbolTable) {
@@ -116472,11 +116306,10 @@ var generateCharCountProperty = (ctx, input, state, orchestrator, effects) => {
116472
116306
  );
116473
116307
  }
116474
116308
  effects.push({ type: "include", header: "string" });
116475
- if (ctx.resolvedIdentifier && state.lengthCache?.has(ctx.resolvedIdentifier)) {
116309
+ if (ctx.subscriptDepth === 0 && ctx.resolvedIdentifier && state.lengthCache?.has(ctx.resolvedIdentifier)) {
116476
116310
  return state.lengthCache.get(ctx.resolvedIdentifier);
116477
116311
  }
116478
- const target = ctx.resolvedIdentifier ?? ctx.result;
116479
- return `strlen(${target})`;
116312
+ return `strlen(${ctx.result})`;
116480
116313
  };
116481
116314
  var initializeMemberOutput = (ctx) => ({
116482
116315
  result: ctx.result,
@@ -122371,7 +122204,7 @@ var AssignmentContextBuilder_default = buildAssignmentContext;
122371
122204
  // src/transpiler/output/codegen/analysis/StringLengthCounter.ts
122372
122205
  var StringLengthCounter = class _StringLengthCounter {
122373
122206
  /**
122374
- * Count .length accesses in an expression.
122207
+ * Count .char_count accesses in an expression.
122375
122208
  */
122376
122209
  static countExpression(ctx) {
122377
122210
  const counts = /* @__PURE__ */ new Map();
@@ -122379,7 +122212,7 @@ var StringLengthCounter = class _StringLengthCounter {
122379
122212
  return counts;
122380
122213
  }
122381
122214
  /**
122382
- * Count .length accesses in a block.
122215
+ * Count .char_count accesses in a block.
122383
122216
  */
122384
122217
  static countBlock(ctx) {
122385
122218
  const counts = /* @__PURE__ */ new Map();
@@ -122389,7 +122222,7 @@ var StringLengthCounter = class _StringLengthCounter {
122389
122222
  return counts;
122390
122223
  }
122391
122224
  /**
122392
- * Count .length accesses in a block, adding to existing counts.
122225
+ * Count .char_count accesses in a block, adding to existing counts.
122393
122226
  */
122394
122227
  static countBlockInto(ctx, counts) {
122395
122228
  for (const stmt of ctx.statement()) {
@@ -122397,7 +122230,7 @@ var StringLengthCounter = class _StringLengthCounter {
122397
122230
  }
122398
122231
  }
122399
122232
  /**
122400
- * Walk an expression tree, counting .length accesses.
122233
+ * Walk an expression tree, counting .char_count accesses.
122401
122234
  * Uses generic traversal - only postfix expressions need special handling.
122402
122235
  */
122403
122236
  static walkExpression(ctx, counts) {
@@ -122472,7 +122305,7 @@ var StringLengthCounter = class _StringLengthCounter {
122472
122305
  }
122473
122306
  }
122474
122307
  /**
122475
- * Walk a postfix expression - this is where we detect .length accesses.
122308
+ * Walk a postfix expression - this is where we detect .char_count accesses.
122476
122309
  */
122477
122310
  static walkPostfixExpr(ctx, counts) {
122478
122311
  const primary = ctx.primaryExpression();
@@ -122481,7 +122314,7 @@ var StringLengthCounter = class _StringLengthCounter {
122481
122314
  if (primaryId && ops.length > 0) {
122482
122315
  for (const op of ops) {
122483
122316
  const memberName = op.IDENTIFIER()?.getText();
122484
- if (memberName === "length") {
122317
+ if (memberName === "char_count") {
122485
122318
  const typeInfo = CodeGenState.getVariableTypeInfo(primaryId);
122486
122319
  if (typeInfo?.isString) {
122487
122320
  const currentCount = counts.get(primaryId) || 0;
@@ -122498,7 +122331,7 @@ var StringLengthCounter = class _StringLengthCounter {
122498
122331
  }
122499
122332
  }
122500
122333
  /**
122501
- * Walk a statement, counting .length accesses.
122334
+ * Walk a statement, counting .char_count accesses.
122502
122335
  */
122503
122336
  static walkStatement(ctx, counts) {
122504
122337
  if (ctx.assignmentStatement()) {
@@ -122530,95 +122363,6 @@ var StringLengthCounter = class _StringLengthCounter {
122530
122363
  };
122531
122364
  var StringLengthCounter_default = StringLengthCounter;
122532
122365
 
122533
- // src/transpiler/output/codegen/helpers/CppModeHelper.ts
122534
- var CppModeHelper = class {
122535
- /**
122536
- * Get address-of expression for struct parameter passing.
122537
- * C mode: `&expr` (pass pointer to struct)
122538
- * C++ mode: `expr` (pass reference directly)
122539
- *
122540
- * @param expr - The expression to potentially wrap
122541
- * @returns The expression with address-of operator in C mode
122542
- */
122543
- static maybeAddressOf(expr) {
122544
- return CodeGenState.cppMode ? expr : `&${expr}`;
122545
- }
122546
- /**
122547
- * Get dereference expression for struct parameter access.
122548
- * C mode: `(*expr)` (dereference pointer)
122549
- * C++ mode: `expr` (reference can be used directly)
122550
- *
122551
- * @param expr - The expression to potentially dereference
122552
- * @returns The expression with dereference in C mode
122553
- */
122554
- static maybeDereference(expr) {
122555
- return CodeGenState.cppMode ? expr : `(*${expr})`;
122556
- }
122557
- /**
122558
- * Get the type modifier for struct parameter declarations.
122559
- * C mode: `*` (pointer type)
122560
- * C++ mode: `&` (reference type)
122561
- *
122562
- * @returns The type modifier character
122563
- */
122564
- static refOrPtr() {
122565
- return CodeGenState.cppMode ? "&" : "*";
122566
- }
122567
- /**
122568
- * Get the member access separator for struct parameters.
122569
- * C mode: `->` (pointer member access)
122570
- * C++ mode: `.` (reference member access)
122571
- *
122572
- * @returns The member access separator
122573
- */
122574
- static memberSeparator() {
122575
- return CodeGenState.cppMode ? "." : "->";
122576
- }
122577
- /**
122578
- * Get NULL literal for the current mode.
122579
- * C mode: `NULL`
122580
- * C++ mode: `nullptr`
122581
- *
122582
- * @returns The null pointer literal
122583
- */
122584
- static nullLiteral() {
122585
- return CodeGenState.cppMode ? "nullptr" : "NULL";
122586
- }
122587
- /**
122588
- * Generate a cast expression for the current mode.
122589
- * C mode: `(type)expr`
122590
- * C++ mode: `static_cast<type>(expr)`
122591
- *
122592
- * @param type - The target type
122593
- * @param expr - The expression to cast
122594
- * @returns The cast expression
122595
- */
122596
- static cast(type, expr) {
122597
- return CodeGenState.cppMode ? `static_cast<${type}>(${expr})` : `(${type})${expr}`;
122598
- }
122599
- /**
122600
- * Generate a reinterpret cast expression for the current mode.
122601
- * C mode: `(type)expr`
122602
- * C++ mode: `reinterpret_cast<type>(expr)`
122603
- *
122604
- * @param type - The target type
122605
- * @param expr - The expression to cast
122606
- * @returns The cast expression
122607
- */
122608
- static reinterpretCast(type, expr) {
122609
- return CodeGenState.cppMode ? `reinterpret_cast<${type}>(${expr})` : `(${type})${expr}`;
122610
- }
122611
- /**
122612
- * Check if we're in C++ mode.
122613
- *
122614
- * @returns True if generating C++ code
122615
- */
122616
- static isCppMode() {
122617
- return CodeGenState.cppMode;
122618
- }
122619
- };
122620
- var CppModeHelper_default = CppModeHelper;
122621
-
122622
122366
  // src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts
122623
122367
  var MemberChainAnalyzer = class _MemberChainAnalyzer {
122624
122368
  /**
@@ -125648,6 +125392,33 @@ var TypedefParamParser = class _TypedefParamParser {
125648
125392
  static shouldBeConst(typedefType, paramIndex) {
125649
125393
  return _TypedefParamParser.getParamAt(typedefType, paramIndex)?.isConst ?? null;
125650
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
+ }
125651
125422
  };
125652
125423
  var TypedefParamParser_default = TypedefParamParser;
125653
125424
 
@@ -126419,7 +126190,7 @@ var PassByValueAnalyzer = class _PassByValueAnalyzer {
126419
126190
  * Used by both function call tracking and subscript access tracking.
126420
126191
  */
126421
126192
  static walkOrExpression(orExpr, handler) {
126422
- 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);
126423
126194
  }
126424
126195
  /**
126425
126196
  * Walk an orExpression tree for function calls.
@@ -126774,6 +126545,7 @@ var ParameterInputAdapter = class {
126774
126545
  isPassByReference: false
126775
126546
  };
126776
126547
  }
126548
+ const isCallbackPointer = param.isCallbackPointer ?? false;
126777
126549
  return {
126778
126550
  name: param.name,
126779
126551
  baseType: param.type,
@@ -126783,8 +126555,10 @@ var ParameterInputAdapter = class {
126783
126555
  isArray: false,
126784
126556
  isCallback: false,
126785
126557
  isString: false,
126786
- isPassByValue: deps.isPassByValue,
126787
- 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
126788
126562
  };
126789
126563
  }
126790
126564
  /**
@@ -127594,7 +127368,7 @@ var CodeGenerator = class _CodeGenerator {
127594
127368
  if (!arrayAccessMatch) {
127595
127369
  return false;
127596
127370
  }
127597
- 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")) {
127598
127372
  return false;
127599
127373
  }
127600
127374
  const arrayName = arrayAccessMatch[1];
@@ -128654,7 +128428,8 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
128654
128428
  );
128655
128429
  if (symbols.hasPublicSymbols() && CodeGenState.sourcePath) {
128656
128430
  const pathToUse = options?.sourceRelativePath || CodeGenState.sourcePath.replace(/^.*[\\/]/, "");
128657
- const headerName = pathToUse.replace(/\.cnx$|\.cnext$/, ".h");
128431
+ const ext = CodeGenState.cppMode ? ".hpp" : ".h";
128432
+ const headerName = pathToUse.replace(/\.cnx$|\.cnext$/, ext);
128658
128433
  output.push(`#include "${headerName}"`, "");
128659
128434
  CodeGenState.selfIncludeAdded = true;
128660
128435
  }
@@ -131102,10 +130877,15 @@ var HeaderGeneratorUtils = class _HeaderGeneratorUtils {
131102
130877
  }
131103
130878
  if (options.userIncludes && options.userIncludes.length > 0) {
131104
130879
  for (const include of options.userIncludes) {
131105
- lines.push(include);
130880
+ const transformedInclude = options.cppMode ? include.replace(/\.h"/, '.hpp"').replace(/\.h>/, ".hpp>") : include;
130881
+ lines.push(transformedInclude);
131106
130882
  }
131107
130883
  }
131108
- 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
+ );
131109
130889
  for (const directive of headersToInclude) {
131110
130890
  if (!userIncludeSet.has(directive)) {
131111
130891
  lines.push(directive);
@@ -132919,7 +132699,7 @@ var TSymbolInfoAdapter = class _TSymbolInfoAdapter {
132919
132699
  var TSymbolInfoAdapter_default = TSymbolInfoAdapter;
132920
132700
 
132921
132701
  // src/transpiler/logic/symbols/SymbolUtils.ts
132922
- var RESERVED_FIELD_NAMES = /* @__PURE__ */ new Set(["length"]);
132702
+ var RESERVED_FIELD_NAMES = /* @__PURE__ */ new Set([]);
132923
132703
  function parseArrayDimensions2(text) {
132924
132704
  const dimensions = [];
132925
132705
  const arrayMatches = text.match(/\[(\d+)\]/g);
@@ -138040,6 +137820,162 @@ var ArrayIndexTypeAnalyzer = class {
138040
137820
  };
138041
137821
  var ArrayIndexTypeAnalyzer_default = ArrayIndexTypeAnalyzer;
138042
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
+
138043
137979
  // src/transpiler/logic/analysis/runAnalyzers.ts
138044
137980
  function collectErrors(analyzerErrors, target, formatMessage) {
138045
137981
  const formatter = formatMessage ?? ((e) => e.message);
@@ -138097,6 +138033,10 @@ function runAnalyzers(tree, tokenStream, options) {
138097
138033
  if (collectErrors(indexTypeAnalyzer.analyze(tree), errors, formatWithCode)) {
138098
138034
  return errors;
138099
138035
  }
138036
+ const signedShiftAnalyzer = new SignedShiftAnalyzer_default();
138037
+ if (collectErrors(signedShiftAnalyzer.analyze(tree), errors, formatWithCode)) {
138038
+ return errors;
138039
+ }
138100
138040
  const commentExtractor = new CommentExtractor_default(tokenStream);
138101
138041
  collectErrors(
138102
138042
  commentExtractor.validate(),
@@ -139192,7 +139132,8 @@ var Transpiler = class {
139192
139132
  const headerContent = this.generateHeaderForFile(file);
139193
139133
  if (headerContent) {
139194
139134
  const headerPath = this.pathResolver.getHeaderOutputPath(
139195
- file.discoveredFile
139135
+ file.discoveredFile,
139136
+ this.cppDetected
139196
139137
  );
139197
139138
  this.fs.writeFile(headerPath, headerContent);
139198
139139
  result.outputFiles.push(headerPath);
@@ -139595,7 +139536,8 @@ var Transpiler = class {
139595
139536
  if (exportedSymbols.length === 0) {
139596
139537
  return null;
139597
139538
  }
139598
- const headerName = basename5(sourcePath).replace(/\.cnx$|\.cnext$/, ".h");
139539
+ const ext = this.cppDetected ? ".hpp" : ".h";
139540
+ const headerName = basename5(sourcePath).replace(/\.cnx$|\.cnext$/, ext);
139599
139541
  const typeInput = this.state.getSymbolInfo(sourcePath);
139600
139542
  const passByValueParams = this.state.getPassByValueParams(sourcePath) ?? /* @__PURE__ */ new Map();
139601
139543
  const userIncludes = this.state.getUserIncludes(sourcePath);
@@ -139665,19 +139607,31 @@ var Transpiler = class {
139665
139607
  convertToHeaderSymbols(symbols, unmodifiedParams, knownEnums) {
139666
139608
  return symbols.map((symbol) => {
139667
139609
  const headerSymbol = HeaderSymbolAdapter_default.fromTSymbol(symbol);
139668
- if (symbol.kind === "function" && headerSymbol.parameters && headerSymbol.parameters.length > 0) {
139669
- const unmodified = unmodifiedParams.get(headerSymbol.name);
139670
- if (unmodified) {
139671
- const updatedParams = headerSymbol.parameters.map((param) => {
139672
- const isPointerParam = !param.isConst && !param.isArray && param.type !== "f32" && param.type !== "f64" && param.type !== "ISR" && !knownEnums.has(param.type ?? "");
139673
- const isArrayParam = param.isArray && !param.isConst;
139674
- if ((isPointerParam || isArrayParam) && unmodified.has(param.name)) {
139675
- return { ...param, isAutoConst: true };
139676
- }
139677
- return param;
139678
- });
139679
- return { ...headerSymbol, parameters: updatedParams };
139680
- }
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 };
139681
139635
  }
139682
139636
  return headerSymbol;
139683
139637
  });