c-next 0.2.5 → 0.2.6
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.
- package/dist/index.js +231 -42
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
- package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +82 -7
- package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +92 -0
- package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +23 -0
- package/src/transpiler/logic/symbols/c/collectors/FunctionCollector.ts +11 -5
- package/src/transpiler/output/codegen/CodeGenerator.ts +157 -7
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +129 -0
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +30 -5
- package/src/transpiler/output/codegen/assignment/handlers/AccessPatternHandlers.ts +2 -2
- package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +2 -2
- package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +2 -2
- package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +4 -4
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/AccessPatternHandlers.test.ts +4 -4
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitAccessHandlers.test.ts +8 -8
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/BitmapHandlers.test.ts +5 -5
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/RegisterHandlers.test.ts +4 -4
- package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +8 -1
- package/src/transpiler/output/codegen/helpers/ArgumentGenerator.ts +5 -0
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +8 -1
- package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +11 -0
- package/src/transpiler/output/codegen/helpers/VariableModifierBuilder.ts +16 -1
- package/src/transpiler/output/codegen/helpers/__tests__/VariableModifierBuilder.test.ts +34 -2
- package/src/transpiler/output/codegen/types/TTypeInfo.ts +1 -0
- package/src/utils/BitUtils.ts +17 -13
- package/src/utils/__tests__/BitUtils.test.ts +56 -56
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.
|
|
13
|
+
version: "0.2.6",
|
|
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",
|
|
@@ -115165,13 +115165,17 @@ var _generateCFunctionArg = (e, targetParam, input, orchestrator) => {
|
|
|
115165
115165
|
return wrapWithCppEnumCast(argCode, e, targetParam?.baseType, orchestrator);
|
|
115166
115166
|
}
|
|
115167
115167
|
let argType = orchestrator.getExpressionType(e);
|
|
115168
|
+
let isPointerVariable = false;
|
|
115169
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(argCode);
|
|
115168
115170
|
if (!argType && !argCode.startsWith("&")) {
|
|
115169
|
-
const typeInfo = CodeGenState.getVariableTypeInfo(argCode);
|
|
115170
115171
|
if (typeInfo) {
|
|
115171
115172
|
argType = typeInfo.baseType;
|
|
115172
115173
|
}
|
|
115173
115174
|
}
|
|
115174
|
-
|
|
115175
|
+
if (typeInfo?.isPointer) {
|
|
115176
|
+
isPointerVariable = true;
|
|
115177
|
+
}
|
|
115178
|
+
const needsAddressOf = argType && !argType.endsWith("*") && !argCode.startsWith("&") && !targetParam.isArray && !isPointerVariable && (orchestrator.isStructType(argType) || _parameterExpectsAddressOf(targetParam.baseType, argType, orchestrator));
|
|
115175
115179
|
if (needsAddressOf) {
|
|
115176
115180
|
argCode = `&${argCode}`;
|
|
115177
115181
|
}
|
|
@@ -116861,15 +116865,18 @@ var VariableModifierBuilder = class {
|
|
|
116861
116865
|
*
|
|
116862
116866
|
* @param ctx - Parser context with modifier methods
|
|
116863
116867
|
* @param inFunctionBody - Whether we're inside a function body (affects extern)
|
|
116868
|
+
* @param hasInitializer - Whether the variable has an initializer (affects extern in C mode)
|
|
116869
|
+
* @param cppMode - Whether we're generating C++ code (affects extern behavior)
|
|
116864
116870
|
* @returns Modifier strings ready for use in generated code
|
|
116865
116871
|
* @throws Error if both atomic and volatile are specified
|
|
116866
116872
|
*/
|
|
116867
|
-
static build(ctx, inFunctionBody) {
|
|
116873
|
+
static build(ctx, inFunctionBody, hasInitializer = false, cppMode = false) {
|
|
116868
116874
|
const hasConst = ctx.constModifier?.() ?? false;
|
|
116869
116875
|
const constMod = hasConst ? "const " : "";
|
|
116870
116876
|
const atomicMod = ctx.atomicModifier() ? "volatile " : "";
|
|
116871
116877
|
const volatileMod = ctx.volatileModifier() ? "volatile " : "";
|
|
116872
|
-
const
|
|
116878
|
+
const needsExtern = hasConst && !inFunctionBody && (cppMode || !hasInitializer);
|
|
116879
|
+
const externMod = needsExtern ? "extern " : "";
|
|
116873
116880
|
if (ctx.atomicModifier() && ctx.volatileModifier()) {
|
|
116874
116881
|
const line = ctx.start?.line ?? 0;
|
|
116875
116882
|
throw new Error(
|
|
@@ -118057,16 +118064,17 @@ var ScopeGenerator_default = generateScope;
|
|
|
118057
118064
|
// src/utils/BitUtils.ts
|
|
118058
118065
|
var BitUtils = class _BitUtils {
|
|
118059
118066
|
/**
|
|
118060
|
-
* Convert a boolean expression to an integer (
|
|
118067
|
+
* Convert a boolean expression to an unsigned integer (0U or 1U).
|
|
118061
118068
|
* Handles literal "true"/"false" and generates ternary for expressions.
|
|
118069
|
+
* Uses unsigned literals for MISRA C:2012 Rule 10.1 compliance.
|
|
118062
118070
|
*
|
|
118063
118071
|
* @param expr - The expression to convert
|
|
118064
|
-
* @returns C code string representing the integer value
|
|
118072
|
+
* @returns C code string representing the unsigned integer value
|
|
118065
118073
|
*/
|
|
118066
118074
|
static boolToInt(expr) {
|
|
118067
|
-
if (expr === "true") return "
|
|
118068
|
-
if (expr === "false") return "
|
|
118069
|
-
return `(${expr} ?
|
|
118075
|
+
if (expr === "true") return "1U";
|
|
118076
|
+
if (expr === "false") return "0U";
|
|
118077
|
+
return `(${expr} ? 1U : 0U)`;
|
|
118070
118078
|
}
|
|
118071
118079
|
/**
|
|
118072
118080
|
* Generate a bit mask for the given width.
|
|
@@ -118123,24 +118131,26 @@ var BitUtils = class _BitUtils {
|
|
|
118123
118131
|
}
|
|
118124
118132
|
}
|
|
118125
118133
|
/**
|
|
118126
|
-
* Return the appropriate "1" literal for a given type.
|
|
118127
|
-
* Uses "1ULL" for 64-bit types
|
|
118134
|
+
* Return the appropriate unsigned "1" literal for a given type.
|
|
118135
|
+
* Uses "1ULL" for 64-bit types, "1U" for others.
|
|
118136
|
+
* MISRA C:2012 Rule 10.1 requires unsigned operands for bitwise operations.
|
|
118128
118137
|
*
|
|
118129
118138
|
* @param typeName - The C-Next type name (e.g., "u64", "i32")
|
|
118130
|
-
* @returns "1ULL" for 64-bit types, "
|
|
118139
|
+
* @returns "1ULL" for 64-bit types, "1U" otherwise
|
|
118131
118140
|
*/
|
|
118132
118141
|
static oneForType(typeName) {
|
|
118133
|
-
return typeName === "u64" || typeName === "i64" ? "1ULL" : "
|
|
118142
|
+
return typeName === "u64" || typeName === "i64" ? "1ULL" : "1U";
|
|
118134
118143
|
}
|
|
118135
118144
|
/**
|
|
118136
|
-
* Format a number as an uppercase hex string (e.g., 255 -> "
|
|
118145
|
+
* Format a number as an unsigned uppercase hex string (e.g., 255 -> "0xFFU").
|
|
118137
118146
|
* Used for generating hex mask literals in generated C code.
|
|
118147
|
+
* Includes U suffix for MISRA C:2012 Rule 10.1 compliance.
|
|
118138
118148
|
*
|
|
118139
118149
|
* @param value - The numeric value to format
|
|
118140
|
-
* @returns Hex string like "
|
|
118150
|
+
* @returns Hex string like "0xFFU" or "0x1FU"
|
|
118141
118151
|
*/
|
|
118142
118152
|
static formatHex(value) {
|
|
118143
|
-
return `0x${value.toString(16).toUpperCase()}`;
|
|
118153
|
+
return `0x${value.toString(16).toUpperCase()}U`;
|
|
118144
118154
|
}
|
|
118145
118155
|
/**
|
|
118146
118156
|
* Generate code to read a single bit from a value.
|
|
@@ -118186,7 +118196,7 @@ var BitUtils = class _BitUtils {
|
|
|
118186
118196
|
static singleBitWrite(target, offset, value, targetType) {
|
|
118187
118197
|
const intValue = _BitUtils.boolToInt(value);
|
|
118188
118198
|
const is64Bit = targetType === "u64" || targetType === "i64";
|
|
118189
|
-
const one = is64Bit ? "1ULL" : "
|
|
118199
|
+
const one = is64Bit ? "1ULL" : "1U";
|
|
118190
118200
|
const valueShift = is64Bit ? `((uint64_t)${intValue} << ${offset})` : `(${intValue} << ${offset})`;
|
|
118191
118201
|
return `${target} = (${target} & ~(${one} << ${offset})) | ${valueShift};`;
|
|
118192
118202
|
}
|
|
@@ -120870,7 +120880,7 @@ function getBitmapFieldInfo(bitmapType, fieldName, ctx) {
|
|
|
120870
120880
|
function generateBitmapWrite(target, fieldInfo, value) {
|
|
120871
120881
|
const { maskHex } = calculateMask(fieldInfo.width);
|
|
120872
120882
|
if (fieldInfo.width === 1) {
|
|
120873
|
-
return `${target} = (${target} & ~(
|
|
120883
|
+
return `${target} = (${target} & ~(1U << ${fieldInfo.offset})) | (${BitUtils_default.boolToInt(value)} << ${fieldInfo.offset});`;
|
|
120874
120884
|
} else {
|
|
120875
120885
|
return `${target} = (${target} & ~(${maskHex} << ${fieldInfo.offset})) | ((${value} & ${maskHex}) << ${fieldInfo.offset});`;
|
|
120876
120886
|
}
|
|
@@ -121123,9 +121133,9 @@ function handleRegisterBit(ctx) {
|
|
|
121123
121133
|
bitIndex,
|
|
121124
121134
|
true
|
|
121125
121135
|
);
|
|
121126
|
-
return `${fullName} = (
|
|
121136
|
+
return `${fullName} = (1U << ${bitIndex});`;
|
|
121127
121137
|
}
|
|
121128
|
-
return `${fullName} = (${fullName} & ~(
|
|
121138
|
+
return `${fullName} = (${fullName} & ~(1U << ${bitIndex})) | (${BitUtils_default.boolToInt(ctx.generatedValue)} << ${bitIndex});`;
|
|
121129
121139
|
}
|
|
121130
121140
|
function handleRegisterBitRange(ctx) {
|
|
121131
121141
|
AssignmentHandlerUtils_default.validateNoCompoundForBitAccess(
|
|
@@ -121191,9 +121201,9 @@ function handleScopedRegisterBit(ctx) {
|
|
|
121191
121201
|
bitIndex,
|
|
121192
121202
|
true
|
|
121193
121203
|
);
|
|
121194
|
-
return `${regName} = (
|
|
121204
|
+
return `${regName} = (1U << ${bitIndex});`;
|
|
121195
121205
|
}
|
|
121196
|
-
return `${regName} = (${regName} & ~(
|
|
121206
|
+
return `${regName} = (${regName} & ~(1U << ${bitIndex})) | (${BitUtils_default.boolToInt(ctx.generatedValue)} << ${bitIndex});`;
|
|
121197
121207
|
}
|
|
121198
121208
|
function handleScopedRegisterBitRange(ctx) {
|
|
121199
121209
|
AssignmentHandlerUtils_default.validateScopeContext(CodeGenState.currentScope);
|
|
@@ -121439,7 +121449,7 @@ function handleStructMemberBit(ctx) {
|
|
|
121439
121449
|
validateNotCompound2(ctx);
|
|
121440
121450
|
const target = gen6().generateAssignmentTarget(ctx.targetCtx);
|
|
121441
121451
|
const bitIndex = gen6().generateExpression(ctx.subscripts.at(-1));
|
|
121442
|
-
const one = "
|
|
121452
|
+
const one = "1U";
|
|
121443
121453
|
const intValue = BitUtils_default.boolToInt(ctx.generatedValue);
|
|
121444
121454
|
return `${target} = (${target} & ~(${one} << ${bitIndex})) | (${intValue} << ${bitIndex});`;
|
|
121445
121455
|
}
|
|
@@ -121687,9 +121697,9 @@ function handleGlobalRegisterBit(ctx) {
|
|
|
121687
121697
|
`Cannot assign false to write-only register bit ${regName}[${bitIndex}]. Use the corresponding CLEAR register to clear bits.`
|
|
121688
121698
|
);
|
|
121689
121699
|
}
|
|
121690
|
-
return `${regName} = (
|
|
121700
|
+
return `${regName} = (1U << ${bitIndex});`;
|
|
121691
121701
|
}
|
|
121692
|
-
return `${regName} = (${regName} & ~(
|
|
121702
|
+
return `${regName} = (${regName} & ~(1U << ${bitIndex})) | (${BitUtils_default.boolToInt(ctx.generatedValue)} << ${bitIndex});`;
|
|
121693
121703
|
}
|
|
121694
121704
|
function handleMemberChain(ctx) {
|
|
121695
121705
|
const bitAnalysis = gen9().analyzeMemberChainForBitAccess(ctx.targetCtx);
|
|
@@ -122839,6 +122849,9 @@ var ArgumentGenerator = class _ArgumentGenerator {
|
|
|
122839
122849
|
if (typeInfo?.isArray && !typeInfo.isString) {
|
|
122840
122850
|
return id;
|
|
122841
122851
|
}
|
|
122852
|
+
if (typeInfo?.isPointer) {
|
|
122853
|
+
return id;
|
|
122854
|
+
}
|
|
122842
122855
|
if (CodeGenState.currentScope) {
|
|
122843
122856
|
const members = CodeGenState.getScopeMembers(CodeGenState.currentScope);
|
|
122844
122857
|
if (members?.has(id)) {
|
|
@@ -124105,7 +124118,11 @@ var StringDeclHelper = class _StringDeclHelper {
|
|
|
124105
124118
|
initValue,
|
|
124106
124119
|
arrayDims
|
|
124107
124120
|
);
|
|
124108
|
-
|
|
124121
|
+
const suppression = "// cppcheck-suppress misra-c2012-9.3\n// cppcheck-suppress misra-c2012-9.4\n";
|
|
124122
|
+
return {
|
|
124123
|
+
code: `${suppression}${decl} = ${finalInitValue};`,
|
|
124124
|
+
handled: true
|
|
124125
|
+
};
|
|
124109
124126
|
}
|
|
124110
124127
|
/**
|
|
124111
124128
|
* Handle size inference for empty array dimension.
|
|
@@ -124581,15 +124598,21 @@ ${assignments}`;
|
|
|
124581
124598
|
{ generateType: callbacks.generateType }
|
|
124582
124599
|
);
|
|
124583
124600
|
}
|
|
124601
|
+
const hasInitializer = ctx.expression() !== null;
|
|
124584
124602
|
const modifiers = VariableModifierBuilder_default.build(
|
|
124585
124603
|
ctx,
|
|
124586
|
-
CodeGenState.inFunctionBody
|
|
124604
|
+
CodeGenState.inFunctionBody,
|
|
124605
|
+
hasInitializer,
|
|
124606
|
+
CodeGenState.cppMode
|
|
124587
124607
|
);
|
|
124588
124608
|
const name = ctx.IDENTIFIER().getText();
|
|
124589
124609
|
const typeCtx = ctx.type();
|
|
124590
124610
|
_VariableDeclHelper.validateArrayDeclarationSyntax(ctx, typeCtx, name);
|
|
124591
124611
|
const type = callbacks.inferVariableType(ctx, name);
|
|
124592
124612
|
callbacks.trackLocalVariable(ctx, name);
|
|
124613
|
+
if (type.endsWith("*")) {
|
|
124614
|
+
callbacks.markVariableAsPointer(name);
|
|
124615
|
+
}
|
|
124593
124616
|
const stringResult = StringDeclHelper_default.generateStringDecl(
|
|
124594
124617
|
typeCtx,
|
|
124595
124618
|
name,
|
|
@@ -129771,6 +129794,7 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
129771
129794
|
getExpressionType: (exprCtx) => this.getExpressionType(exprCtx),
|
|
129772
129795
|
inferVariableType: (varCtx, name) => this._inferVariableType(varCtx, name),
|
|
129773
129796
|
trackLocalVariable: (varCtx, name) => this._trackLocalVariable(varCtx, name),
|
|
129797
|
+
markVariableAsPointer: (name) => this._markVariableAsPointer(name),
|
|
129774
129798
|
getStringConcatOperands: (concatCtx) => this._getStringConcatOperands(concatCtx),
|
|
129775
129799
|
getSubstringOperands: (substrCtx) => this._getSubstringOperands(substrCtx),
|
|
129776
129800
|
getStringExprCapacity: (exprCode) => this.getStringExprCapacity(exprCode),
|
|
@@ -129779,20 +129803,116 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
129779
129803
|
}
|
|
129780
129804
|
/**
|
|
129781
129805
|
* Issue #696: Infer variable type, handling nullable C pointer types.
|
|
129806
|
+
* Issue #895 Bug B: Infer pointer type from C function return type.
|
|
129782
129807
|
*/
|
|
129783
129808
|
_inferVariableType(ctx, name) {
|
|
129784
|
-
|
|
129785
|
-
if (!
|
|
129809
|
+
const type = this.generateType(ctx.type());
|
|
129810
|
+
if (!ctx.expression()) {
|
|
129786
129811
|
return type;
|
|
129787
129812
|
}
|
|
129788
|
-
const
|
|
129789
|
-
|
|
129790
|
-
|
|
129791
|
-
|
|
129813
|
+
const pointerType = this._inferPointerTypeFromFunctionCall(
|
|
129814
|
+
ctx.expression(),
|
|
129815
|
+
type
|
|
129816
|
+
);
|
|
129817
|
+
if (pointerType) {
|
|
129818
|
+
return pointerType;
|
|
129819
|
+
}
|
|
129820
|
+
if (name.startsWith("c_")) {
|
|
129821
|
+
const exprText = ctx.expression().getText();
|
|
129822
|
+
for (const funcName of NullCheckAnalyzer_default.getStructPointerFunctions()) {
|
|
129823
|
+
if (exprText.includes(`${funcName}(`)) {
|
|
129824
|
+
return `${type}*`;
|
|
129825
|
+
}
|
|
129792
129826
|
}
|
|
129793
129827
|
}
|
|
129794
129828
|
return type;
|
|
129795
129829
|
}
|
|
129830
|
+
/**
|
|
129831
|
+
* Issue #895 Bug B: Infer pointer type from C function return type.
|
|
129832
|
+
* If initializer is a call to a C function that returns T*, and declared
|
|
129833
|
+
* type is T, return T* instead of T.
|
|
129834
|
+
*/
|
|
129835
|
+
_inferPointerTypeFromFunctionCall(expr, declaredType) {
|
|
129836
|
+
const funcName = this._extractCFunctionName(expr);
|
|
129837
|
+
if (!funcName) {
|
|
129838
|
+
return null;
|
|
129839
|
+
}
|
|
129840
|
+
const cFunc = CodeGenState.symbolTable?.getCSymbol(funcName);
|
|
129841
|
+
if (cFunc?.kind !== "function") {
|
|
129842
|
+
return null;
|
|
129843
|
+
}
|
|
129844
|
+
const returnType = cFunc.type;
|
|
129845
|
+
if (!returnType.endsWith("*")) {
|
|
129846
|
+
return null;
|
|
129847
|
+
}
|
|
129848
|
+
const returnBaseType = returnType.replace(/\s*\*\s*$/, "").trim();
|
|
129849
|
+
if (returnBaseType === declaredType) {
|
|
129850
|
+
return `${declaredType}*`;
|
|
129851
|
+
}
|
|
129852
|
+
return null;
|
|
129853
|
+
}
|
|
129854
|
+
/**
|
|
129855
|
+
* Extract C function name from expression patterns.
|
|
129856
|
+
* Handles both:
|
|
129857
|
+
* - global.funcName(...) - explicit global access
|
|
129858
|
+
* - funcName(...) - direct call (if funcName is a known C function)
|
|
129859
|
+
* Returns null if expression doesn't match these patterns.
|
|
129860
|
+
*/
|
|
129861
|
+
_extractCFunctionName(expr) {
|
|
129862
|
+
const postfix = ExpressionUnwrapper_default.getPostfixExpression(expr);
|
|
129863
|
+
if (!postfix) {
|
|
129864
|
+
return null;
|
|
129865
|
+
}
|
|
129866
|
+
const primary = postfix.primaryExpression();
|
|
129867
|
+
const ops = postfix.postfixOp();
|
|
129868
|
+
if (primary.GLOBAL()) {
|
|
129869
|
+
return this._extractGlobalPatternFuncName(ops);
|
|
129870
|
+
}
|
|
129871
|
+
const identifier = primary.IDENTIFIER();
|
|
129872
|
+
if (identifier) {
|
|
129873
|
+
return this._extractDirectCallFuncName(identifier.getText(), ops);
|
|
129874
|
+
}
|
|
129875
|
+
return null;
|
|
129876
|
+
}
|
|
129877
|
+
/**
|
|
129878
|
+
* Extract function name from global.funcName(...) pattern.
|
|
129879
|
+
*/
|
|
129880
|
+
_extractGlobalPatternFuncName(ops) {
|
|
129881
|
+
if (ops.length < 2) {
|
|
129882
|
+
return null;
|
|
129883
|
+
}
|
|
129884
|
+
const memberOp = ops[0];
|
|
129885
|
+
if (!memberOp.IDENTIFIER()) {
|
|
129886
|
+
return null;
|
|
129887
|
+
}
|
|
129888
|
+
const callOp = ops[1];
|
|
129889
|
+
if (!this._isCallOp(callOp)) {
|
|
129890
|
+
return null;
|
|
129891
|
+
}
|
|
129892
|
+
return memberOp.IDENTIFIER().getText();
|
|
129893
|
+
}
|
|
129894
|
+
/**
|
|
129895
|
+
* Extract function name from direct funcName(...) call if it's a C function.
|
|
129896
|
+
*/
|
|
129897
|
+
_extractDirectCallFuncName(funcName, ops) {
|
|
129898
|
+
if (ops.length < 1) {
|
|
129899
|
+
return null;
|
|
129900
|
+
}
|
|
129901
|
+
if (!this._isCallOp(ops[0])) {
|
|
129902
|
+
return null;
|
|
129903
|
+
}
|
|
129904
|
+
const cFunc = CodeGenState.symbolTable?.getCSymbol(funcName);
|
|
129905
|
+
if (cFunc?.kind === "function") {
|
|
129906
|
+
return funcName;
|
|
129907
|
+
}
|
|
129908
|
+
return null;
|
|
129909
|
+
}
|
|
129910
|
+
/**
|
|
129911
|
+
* Check if a postfix op is a function call.
|
|
129912
|
+
*/
|
|
129913
|
+
_isCallOp(op) {
|
|
129914
|
+
return Boolean(op.argumentList() || op.getText().startsWith("("));
|
|
129915
|
+
}
|
|
129796
129916
|
/**
|
|
129797
129917
|
* Issue #696: Track local variable for type registry and const values.
|
|
129798
129918
|
*/
|
|
@@ -129813,6 +129933,20 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
129813
129933
|
}
|
|
129814
129934
|
}
|
|
129815
129935
|
}
|
|
129936
|
+
/**
|
|
129937
|
+
* Issue #895 Bug B: Mark variable as a pointer in the type registry.
|
|
129938
|
+
* Called when type inference detects that a variable should be a pointer
|
|
129939
|
+
* (e.g., initialized from a C function returning T*).
|
|
129940
|
+
*/
|
|
129941
|
+
_markVariableAsPointer(name) {
|
|
129942
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(name);
|
|
129943
|
+
if (typeInfo) {
|
|
129944
|
+
CodeGenState.setVariableTypeInfo(name, {
|
|
129945
|
+
...typeInfo,
|
|
129946
|
+
isPointer: true
|
|
129947
|
+
});
|
|
129948
|
+
}
|
|
129949
|
+
}
|
|
129816
129950
|
// Issue #792: Methods _handleArrayDeclaration, _getArrayTypeDimension, _parseArrayTypeDimension,
|
|
129817
129951
|
// _parseFirstArrayDimension, _validateArrayDeclarationSyntax, _extractBaseTypeName,
|
|
129818
129952
|
// _generateVariableInitializer, _validateIntegerInitializer, _finalizeCppClassAssignments,
|
|
@@ -133389,6 +133523,8 @@ var FunctionCollector2 = class _FunctionCollector {
|
|
|
133389
133523
|
const parameters = _FunctionCollector._mapParameters(
|
|
133390
133524
|
DeclaratorUtils_default.extractFunctionParameters(declarator)
|
|
133391
133525
|
);
|
|
133526
|
+
const hasPointer = declarator.pointer() !== null;
|
|
133527
|
+
const returnType = hasPointer ? `${baseType}*` : baseType;
|
|
133392
133528
|
return {
|
|
133393
133529
|
kind: "function",
|
|
133394
133530
|
name,
|
|
@@ -133396,7 +133532,7 @@ var FunctionCollector2 = class _FunctionCollector {
|
|
|
133396
133532
|
sourceLine: line,
|
|
133397
133533
|
sourceLanguage: ESourceLanguage_default.C,
|
|
133398
133534
|
isExported: !isExtern,
|
|
133399
|
-
type:
|
|
133535
|
+
type: returnType,
|
|
133400
133536
|
parameters: parameters.length > 0 ? parameters : void 0,
|
|
133401
133537
|
isDeclaration: true
|
|
133402
133538
|
};
|
|
@@ -137085,6 +137221,8 @@ var FunctionCallAnalyzer = class {
|
|
|
137085
137221
|
if (sym?.kind !== "type") return false;
|
|
137086
137222
|
return "type" in sym && typeof sym.type === "string" && sym.type.includes("(*)");
|
|
137087
137223
|
}
|
|
137224
|
+
/** Current scope name during callback assignment scanning */
|
|
137225
|
+
scanCurrentScope = null;
|
|
137088
137226
|
/**
|
|
137089
137227
|
* Detect functions assigned to C function pointer typedefs.
|
|
137090
137228
|
* When `PointCallback cb <- my_handler;` is found and PointCallback
|
|
@@ -137093,12 +137231,46 @@ var FunctionCallAnalyzer = class {
|
|
|
137093
137231
|
collectCallbackCompatibleFunctions(tree) {
|
|
137094
137232
|
for (const decl of tree.declaration()) {
|
|
137095
137233
|
const funcDecl = decl.functionDeclaration();
|
|
137096
|
-
if (
|
|
137097
|
-
|
|
137098
|
-
|
|
137099
|
-
|
|
137234
|
+
if (funcDecl) {
|
|
137235
|
+
this.scanStandaloneFunctionForCallbacks(funcDecl);
|
|
137236
|
+
continue;
|
|
137237
|
+
}
|
|
137238
|
+
const scopeDecl = decl.scopeDeclaration();
|
|
137239
|
+
if (scopeDecl) {
|
|
137240
|
+
this.scanScopeForCallbacks(scopeDecl);
|
|
137241
|
+
}
|
|
137100
137242
|
}
|
|
137101
137243
|
}
|
|
137244
|
+
/**
|
|
137245
|
+
* Scan a standalone function declaration for callback assignments.
|
|
137246
|
+
*/
|
|
137247
|
+
scanStandaloneFunctionForCallbacks(funcDecl) {
|
|
137248
|
+
const block = funcDecl.block();
|
|
137249
|
+
if (!block) return;
|
|
137250
|
+
this.scanCurrentScope = null;
|
|
137251
|
+
this.scanBlockForCallbackAssignments(block);
|
|
137252
|
+
}
|
|
137253
|
+
/**
|
|
137254
|
+
* Scan all member functions in a scope for callback assignments (Issue #895).
|
|
137255
|
+
*/
|
|
137256
|
+
scanScopeForCallbacks(scopeDecl) {
|
|
137257
|
+
const scopeName = scopeDecl.IDENTIFIER().getText();
|
|
137258
|
+
for (const member of scopeDecl.scopeMember()) {
|
|
137259
|
+
this.scanScopeMemberForCallbacks(member, scopeName);
|
|
137260
|
+
}
|
|
137261
|
+
this.scanCurrentScope = null;
|
|
137262
|
+
}
|
|
137263
|
+
/**
|
|
137264
|
+
* Scan a single scope member for callback assignments.
|
|
137265
|
+
*/
|
|
137266
|
+
scanScopeMemberForCallbacks(member, scopeName) {
|
|
137267
|
+
const memberFunc = member.functionDeclaration();
|
|
137268
|
+
if (!memberFunc) return;
|
|
137269
|
+
const block = memberFunc.block();
|
|
137270
|
+
if (!block) return;
|
|
137271
|
+
this.scanCurrentScope = scopeName;
|
|
137272
|
+
this.scanBlockForCallbackAssignments(block);
|
|
137273
|
+
}
|
|
137102
137274
|
/**
|
|
137103
137275
|
* Recursively scan all statements in a block for callback typedef assignments.
|
|
137104
137276
|
*/
|
|
@@ -137182,13 +137354,30 @@ var FunctionCallAnalyzer = class {
|
|
|
137182
137354
|
}
|
|
137183
137355
|
/**
|
|
137184
137356
|
* Extract a function reference from an expression context.
|
|
137185
|
-
* Matches
|
|
137186
|
-
*
|
|
137357
|
+
* Matches:
|
|
137358
|
+
* - Bare identifiers: "my_handler"
|
|
137359
|
+
* - Qualified scope names: "MyScope.handler"
|
|
137360
|
+
* - Self-scope reference: "this.handler" (resolved using scanCurrentScope)
|
|
137361
|
+
* - Global scope reference: "global.ScopeName.handler"
|
|
137187
137362
|
* Returns null if the expression is not a function reference.
|
|
137188
137363
|
*/
|
|
137189
137364
|
extractFunctionReference(expr) {
|
|
137190
137365
|
const text = expr.getText();
|
|
137191
|
-
|
|
137366
|
+
const thisPattern = /^this\.(\w+)$/;
|
|
137367
|
+
const thisMatch = thisPattern.exec(text);
|
|
137368
|
+
if (thisMatch) {
|
|
137369
|
+
if (!this.scanCurrentScope) {
|
|
137370
|
+
return null;
|
|
137371
|
+
}
|
|
137372
|
+
return this.scanCurrentScope + "." + thisMatch[1];
|
|
137373
|
+
}
|
|
137374
|
+
const globalPattern = /^global\.(\w+)\.(\w+)$/;
|
|
137375
|
+
const globalMatch = globalPattern.exec(text);
|
|
137376
|
+
if (globalMatch) {
|
|
137377
|
+
return globalMatch[1] + "." + globalMatch[2];
|
|
137378
|
+
}
|
|
137379
|
+
const simplePattern = /^\w+(\.\w+)?$/;
|
|
137380
|
+
if (simplePattern.test(text)) {
|
|
137192
137381
|
return text;
|
|
137193
137382
|
}
|
|
137194
137383
|
return null;
|