c-next 0.2.3 → 0.2.5
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/README.md +59 -57
- package/dist/index.js +859 -198
- package/dist/index.js.map +4 -4
- package/package.json +3 -1
- package/src/cli/Runner.ts +1 -1
- package/src/cli/__tests__/Runner.test.ts +8 -8
- package/src/cli/serve/ServeCommand.ts +29 -9
- package/src/transpiler/Transpiler.ts +105 -200
- package/src/transpiler/__tests__/DualCodePaths.test.ts +117 -68
- package/src/transpiler/__tests__/Transpiler.coverage.test.ts +87 -51
- package/src/transpiler/__tests__/Transpiler.test.ts +150 -48
- package/src/transpiler/__tests__/determineProjectRoot.test.ts +2 -2
- package/src/transpiler/data/IncludeResolver.ts +11 -3
- package/src/transpiler/data/__tests__/IncludeResolver.test.ts +2 -2
- package/src/transpiler/logic/analysis/ArrayIndexTypeAnalyzer.ts +346 -0
- package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +281 -14
- package/src/transpiler/logic/analysis/__tests__/ArrayIndexTypeAnalyzer.test.ts +545 -0
- package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +375 -0
- package/src/transpiler/logic/analysis/runAnalyzers.ts +9 -2
- package/src/transpiler/logic/analysis/types/IArrayIndexTypeError.ts +15 -0
- package/src/transpiler/logic/symbols/TransitiveEnumCollector.ts +1 -1
- package/src/transpiler/logic/symbols/c/__tests__/CResolver.integration.test.ts +18 -0
- package/src/transpiler/logic/symbols/c/index.ts +50 -1
- package/src/transpiler/output/codegen/CodeGenerator.ts +69 -15
- package/src/transpiler/output/codegen/TypeResolver.ts +1 -1
- package/src/transpiler/output/codegen/TypeValidator.ts +10 -7
- package/src/transpiler/output/codegen/__tests__/ExpressionWalker.test.ts +9 -3
- package/src/transpiler/output/codegen/__tests__/RequireInclude.test.ts +86 -23
- package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +3 -1
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +43 -29
- package/src/transpiler/output/codegen/generators/IOrchestrator.ts +5 -2
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +15 -3
- package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +1 -1
- package/src/transpiler/output/codegen/generators/statements/ControlFlowGenerator.ts +12 -3
- package/src/transpiler/output/codegen/generators/statements/__tests__/ControlFlowGenerator.test.ts +4 -4
- package/src/transpiler/output/codegen/helpers/FunctionContextManager.ts +64 -3
- package/src/transpiler/output/codegen/helpers/MemberSeparatorResolver.ts +28 -6
- package/src/transpiler/output/codegen/helpers/ParameterDereferenceResolver.ts +12 -0
- package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +30 -2
- package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +15 -7
- package/src/transpiler/output/codegen/helpers/StringOperationsHelper.ts +1 -1
- package/src/transpiler/output/codegen/helpers/TypedefParamParser.ts +220 -0
- package/src/transpiler/output/codegen/helpers/__tests__/FunctionContextManager.test.ts +5 -5
- package/src/transpiler/output/codegen/helpers/__tests__/MemberSeparatorResolver.test.ts +48 -36
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +37 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +63 -0
- package/src/transpiler/output/codegen/helpers/__tests__/TypedefParamParser.test.ts +209 -0
- package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +1 -1
- package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +1 -1
- package/src/transpiler/output/codegen/types/IParameterInput.ts +13 -0
- package/src/transpiler/output/codegen/types/ISeparatorContext.ts +7 -0
- package/src/transpiler/output/codegen/types/TParameterInfo.ts +12 -0
- package/src/transpiler/output/codegen/utils/CodegenParserUtils.ts +1 -1
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +5 -2
- package/src/transpiler/state/CodeGenState.ts +25 -0
- package/src/transpiler/types/IPipelineFile.ts +2 -2
- package/src/transpiler/types/IPipelineInput.ts +1 -1
- package/src/transpiler/types/TTranspileInput.ts +18 -0
- package/src/{transpiler/output/codegen/utils → utils}/ExpressionUnwrapper.ts +1 -1
- package/src/{transpiler/output/codegen/utils → utils}/__tests__/ExpressionUnwrapper.test.ts +2 -2
- package/src/utils/constants/TypeConstants.ts +22 -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.
|
|
13
|
+
version: "0.2.5",
|
|
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",
|
|
@@ -32,6 +32,8 @@ var package_default = {
|
|
|
32
32
|
"test:cli": "node scripts/test-cli.js",
|
|
33
33
|
"test:q": "tsx scripts/test.ts -q",
|
|
34
34
|
"test:update": "tsx scripts/test.ts --update",
|
|
35
|
+
"integration:transpile": "tsx scripts/test.ts --transpile-only",
|
|
36
|
+
"integration:execute": "tsx scripts/test.ts --execute-only",
|
|
35
37
|
analyze: "./scripts/static-analysis.sh",
|
|
36
38
|
clean: "rm -rf dist src/transpiler/logic/parser/grammar src/transpiler/logic/parser/c/grammar src/transpiler/logic/parser/cpp/grammar",
|
|
37
39
|
"prettier:check": "prettier --check .",
|
|
@@ -110764,6 +110766,12 @@ var CodeGenState = class {
|
|
|
110764
110766
|
static callbackTypes = /* @__PURE__ */ new Map();
|
|
110765
110767
|
/** Callback field types: "Struct.field" -> callbackTypeName */
|
|
110766
110768
|
static callbackFieldTypes = /* @__PURE__ */ new Map();
|
|
110769
|
+
/**
|
|
110770
|
+
* Functions that are assigned to C callback typedefs.
|
|
110771
|
+
* Maps function name -> typedef name (e.g., "my_flush" -> "flush_cb_t")
|
|
110772
|
+
* Issue #895: We need the typedef name to look up parameter types.
|
|
110773
|
+
*/
|
|
110774
|
+
static callbackCompatibleFunctions = /* @__PURE__ */ new Map();
|
|
110767
110775
|
// ===========================================================================
|
|
110768
110776
|
// PASS-BY-VALUE ANALYSIS (Issue #269)
|
|
110769
110777
|
// ===========================================================================
|
|
@@ -111131,6 +111139,20 @@ var CodeGenState = class {
|
|
|
111131
111139
|
static getCallbackType(name) {
|
|
111132
111140
|
return this.callbackTypes.get(name);
|
|
111133
111141
|
}
|
|
111142
|
+
/**
|
|
111143
|
+
* Issue #895: Get the typedef type string for a C typedef by name.
|
|
111144
|
+
* Used to look up function pointer typedef signatures for callback-compatible functions.
|
|
111145
|
+
*
|
|
111146
|
+
* @param typedefName - Name of the typedef (e.g., "flush_cb_t")
|
|
111147
|
+
* @returns The type string (e.g., "void (*)(widget_t *, const rect_t *, uint8_t *)") or undefined
|
|
111148
|
+
*/
|
|
111149
|
+
static getTypedefType(typedefName) {
|
|
111150
|
+
const symbol = this.symbolTable.getCSymbol(typedefName);
|
|
111151
|
+
if (symbol?.kind === "type") {
|
|
111152
|
+
return symbol.type;
|
|
111153
|
+
}
|
|
111154
|
+
return void 0;
|
|
111155
|
+
}
|
|
111134
111156
|
/**
|
|
111135
111157
|
* Check if a type name is a known C-Next function.
|
|
111136
111158
|
*/
|
|
@@ -112904,7 +112926,7 @@ var TYPE_RANGES = {
|
|
|
112904
112926
|
};
|
|
112905
112927
|
var TYPE_RANGES_default = TYPE_RANGES;
|
|
112906
112928
|
|
|
112907
|
-
// src/
|
|
112929
|
+
// src/utils/ExpressionUnwrapper.ts
|
|
112908
112930
|
var ExpressionUnwrapper = class {
|
|
112909
112931
|
/**
|
|
112910
112932
|
* Navigate from ExpressionContext to ShiftExpressionContext.
|
|
@@ -114074,14 +114096,14 @@ var TypeValidator = class _TypeValidator {
|
|
|
114074
114096
|
}
|
|
114075
114097
|
}
|
|
114076
114098
|
// ========================================================================
|
|
114077
|
-
//
|
|
114099
|
+
// Condition Boolean Validation (ADR-027, Issue #884)
|
|
114078
114100
|
// ========================================================================
|
|
114079
|
-
static
|
|
114101
|
+
static validateConditionIsBoolean(ctx, conditionType) {
|
|
114080
114102
|
const ternaryExpr = ctx.ternaryExpression();
|
|
114081
114103
|
const orExprs = ternaryExpr.orExpression();
|
|
114082
114104
|
if (orExprs.length !== 1) {
|
|
114083
114105
|
throw new Error(
|
|
114084
|
-
`Error E0701:
|
|
114106
|
+
`Error E0701: ${conditionType} condition must be a boolean expression, not a ternary (MISRA C:2012 Rule 14.4)`
|
|
114085
114107
|
);
|
|
114086
114108
|
}
|
|
114087
114109
|
const orExpr = orExprs[0];
|
|
@@ -114092,7 +114114,7 @@ var TypeValidator = class _TypeValidator {
|
|
|
114092
114114
|
const andExpr = orExpr.andExpression(0);
|
|
114093
114115
|
if (!andExpr) {
|
|
114094
114116
|
throw new Error(
|
|
114095
|
-
`Error E0701:
|
|
114117
|
+
`Error E0701: ${conditionType} condition must be a boolean expression (comparison or logical operation), not '${text}' (MISRA C:2012 Rule 14.4)`
|
|
114096
114118
|
);
|
|
114097
114119
|
}
|
|
114098
114120
|
if (andExpr.equalityExpression().length > 1) {
|
|
@@ -114101,7 +114123,7 @@ var TypeValidator = class _TypeValidator {
|
|
|
114101
114123
|
const equalityExpr = andExpr.equalityExpression(0);
|
|
114102
114124
|
if (!equalityExpr) {
|
|
114103
114125
|
throw new Error(
|
|
114104
|
-
`Error E0701:
|
|
114126
|
+
`Error E0701: ${conditionType} condition must be a boolean expression (comparison or logical operation), not '${text}' (MISRA C:2012 Rule 14.4)`
|
|
114105
114127
|
);
|
|
114106
114128
|
}
|
|
114107
114129
|
if (equalityExpr.relationalExpression().length > 1) {
|
|
@@ -114110,7 +114132,7 @@ var TypeValidator = class _TypeValidator {
|
|
|
114110
114132
|
const relationalExpr = equalityExpr.relationalExpression(0);
|
|
114111
114133
|
if (!relationalExpr) {
|
|
114112
114134
|
throw new Error(
|
|
114113
|
-
`Error E0701:
|
|
114135
|
+
`Error E0701: ${conditionType} condition must be a boolean expression (comparison or logical operation), not '${text}' (MISRA C:2012 Rule 14.4)`
|
|
114114
114136
|
);
|
|
114115
114137
|
}
|
|
114116
114138
|
if (relationalExpr.bitwiseOrExpression().length > 1) {
|
|
@@ -114121,7 +114143,7 @@ var TypeValidator = class _TypeValidator {
|
|
|
114121
114143
|
return;
|
|
114122
114144
|
}
|
|
114123
114145
|
throw new Error(
|
|
114124
|
-
`Error E0701:
|
|
114146
|
+
`Error E0701: ${conditionType} condition must be a boolean expression (comparison or logical operation), not '${text}' (MISRA C:2012 Rule 14.4)
|
|
114125
114147
|
help: use explicit comparison: ${text} > 0 or ${text} != 0`
|
|
114126
114148
|
);
|
|
114127
114149
|
}
|
|
@@ -115742,6 +115764,7 @@ var generatePostfixExpression = (ctx, input, state, orchestrator) => {
|
|
|
115742
115764
|
const rootIdentifier = primary.IDENTIFIER()?.getText();
|
|
115743
115765
|
const paramInfo = rootIdentifier ? state.currentParameters.get(rootIdentifier) : null;
|
|
115744
115766
|
const isStructParam = paramInfo?.isStruct ?? false;
|
|
115767
|
+
const forcePointerSemantics = paramInfo?.forcePointerSemantics ?? false;
|
|
115745
115768
|
const hasSubscriptOps = ops.some((op) => op.expression().length > 0);
|
|
115746
115769
|
const isNonArrayParamWithSubscript = paramInfo && !paramInfo.isArray && !paramInfo.isStruct && hasSubscriptOps;
|
|
115747
115770
|
let result;
|
|
@@ -115762,6 +115785,7 @@ var generatePostfixExpression = (ctx, input, state, orchestrator) => {
|
|
|
115762
115785
|
const postfixCtx = {
|
|
115763
115786
|
rootIdentifier,
|
|
115764
115787
|
isStructParam,
|
|
115788
|
+
forcePointerSemantics,
|
|
115765
115789
|
input,
|
|
115766
115790
|
state,
|
|
115767
115791
|
orchestrator,
|
|
@@ -115853,6 +115877,7 @@ var handleMemberOp = (memberName, tracking, ctx) => {
|
|
|
115853
115877
|
memberName,
|
|
115854
115878
|
rootIdentifier: ctx.rootIdentifier,
|
|
115855
115879
|
isStructParam: ctx.isStructParam,
|
|
115880
|
+
forcePointerSemantics: ctx.forcePointerSemantics,
|
|
115856
115881
|
isGlobalAccess: tracking.isGlobalAccess,
|
|
115857
115882
|
isCppAccessChain: tracking.isCppAccessChain,
|
|
115858
115883
|
currentStructType: tracking.currentStructType,
|
|
@@ -116587,7 +116612,7 @@ var tryStructParamAccess = (ctx, orchestrator) => {
|
|
|
116587
116612
|
if (!ctx.isStructParam || ctx.result !== ctx.rootIdentifier) {
|
|
116588
116613
|
return null;
|
|
116589
116614
|
}
|
|
116590
|
-
const structParamSep = memberAccessChain_default.getStructParamSeparator({
|
|
116615
|
+
const structParamSep = ctx.forcePointerSemantics ? "->" : memberAccessChain_default.getStructParamSeparator({
|
|
116591
116616
|
cppMode: orchestrator.isCppMode()
|
|
116592
116617
|
});
|
|
116593
116618
|
const output = initializeMemberOutput(ctx);
|
|
@@ -116940,6 +116965,7 @@ var generateIf = (node, _input, _state, orchestrator) => {
|
|
|
116940
116965
|
}
|
|
116941
116966
|
const cacheDecls = orchestrator.setupLengthCache(lengthCounts);
|
|
116942
116967
|
orchestrator.validateConditionNoFunctionCall(node.expression(), "if");
|
|
116968
|
+
orchestrator.validateConditionIsBoolean(node.expression(), "if");
|
|
116943
116969
|
const condition = orchestrator.generateExpression(node.expression());
|
|
116944
116970
|
const conditionTemps = orchestrator.flushPendingTempDeclarations();
|
|
116945
116971
|
const thenBranch = orchestrator.generateStatement(thenStmt);
|
|
@@ -116960,6 +116986,7 @@ var generateIf = (node, _input, _state, orchestrator) => {
|
|
|
116960
116986
|
var generateWhile = (node, _input, _state, orchestrator) => {
|
|
116961
116987
|
const effects = [];
|
|
116962
116988
|
orchestrator.validateConditionNoFunctionCall(node.expression(), "while");
|
|
116989
|
+
orchestrator.validateConditionIsBoolean(node.expression(), "while");
|
|
116963
116990
|
const condition = orchestrator.generateExpression(node.expression());
|
|
116964
116991
|
const conditionTemps = orchestrator.flushPendingTempDeclarations();
|
|
116965
116992
|
const body = orchestrator.generateStatement(node.statement());
|
|
@@ -116971,8 +116998,8 @@ var generateWhile = (node, _input, _state, orchestrator) => {
|
|
|
116971
116998
|
};
|
|
116972
116999
|
var generateDoWhile = (node, _input, _state, orchestrator) => {
|
|
116973
117000
|
const effects = [];
|
|
116974
|
-
orchestrator.validateDoWhileCondition(node.expression());
|
|
116975
117001
|
orchestrator.validateConditionNoFunctionCall(node.expression(), "do-while");
|
|
117002
|
+
orchestrator.validateConditionIsBoolean(node.expression(), "do-while");
|
|
116976
117003
|
const body = orchestrator.generateBlock(node.block());
|
|
116977
117004
|
const condition = orchestrator.generateExpression(node.expression());
|
|
116978
117005
|
const conditionTemps = orchestrator.flushPendingTempDeclarations();
|
|
@@ -117037,6 +117064,7 @@ var generateFor = (node, input, state, orchestrator) => {
|
|
|
117037
117064
|
let condition = "";
|
|
117038
117065
|
if (node.expression()) {
|
|
117039
117066
|
orchestrator.validateConditionNoFunctionCall(node.expression(), "for");
|
|
117067
|
+
orchestrator.validateConditionIsBoolean(node.expression(), "for");
|
|
117040
117068
|
condition = orchestrator.generateExpression(node.expression());
|
|
117041
117069
|
}
|
|
117042
117070
|
const conditionTemps = orchestrator.flushPendingTempDeclarations();
|
|
@@ -124789,7 +124817,16 @@ var MemberSeparatorResolver = class _MemberSeparatorResolver {
|
|
|
124789
124817
|
/**
|
|
124790
124818
|
* Build the separator context for a member access chain
|
|
124791
124819
|
*/
|
|
124792
|
-
static buildContext(
|
|
124820
|
+
static buildContext(input, deps) {
|
|
124821
|
+
const {
|
|
124822
|
+
firstId,
|
|
124823
|
+
hasGlobal,
|
|
124824
|
+
hasThis,
|
|
124825
|
+
currentScope,
|
|
124826
|
+
isStructParam,
|
|
124827
|
+
isCppAccess,
|
|
124828
|
+
forcePointerSemantics
|
|
124829
|
+
} = input;
|
|
124793
124830
|
const isCrossScope = hasGlobal && (deps.isKnownScope(firstId) || deps.isKnownRegister(firstId));
|
|
124794
124831
|
const scopedRegName = hasThis && currentScope ? `${currentScope}_${firstId}` : null;
|
|
124795
124832
|
const isScopedRegister = scopedRegName !== null && deps.isKnownRegister(scopedRegName);
|
|
@@ -124799,7 +124836,8 @@ var MemberSeparatorResolver = class _MemberSeparatorResolver {
|
|
|
124799
124836
|
isStructParam,
|
|
124800
124837
|
isCppAccess,
|
|
124801
124838
|
scopedRegName,
|
|
124802
|
-
isScopedRegister
|
|
124839
|
+
isScopedRegister,
|
|
124840
|
+
forcePointerSemantics
|
|
124803
124841
|
};
|
|
124804
124842
|
}
|
|
124805
124843
|
/**
|
|
@@ -124810,6 +124848,9 @@ var MemberSeparatorResolver = class _MemberSeparatorResolver {
|
|
|
124810
124848
|
return "::";
|
|
124811
124849
|
}
|
|
124812
124850
|
if (ctx.isStructParam) {
|
|
124851
|
+
if (ctx.forcePointerSemantics) {
|
|
124852
|
+
return "->";
|
|
124853
|
+
}
|
|
124813
124854
|
return deps.getStructParamSeparator();
|
|
124814
124855
|
}
|
|
124815
124856
|
if (ctx.isCrossScope) {
|
|
@@ -124870,6 +124911,9 @@ var ParameterDereferenceResolver = class _ParameterDereferenceResolver {
|
|
|
124870
124911
|
* Determine if a parameter should be passed by value (no dereference needed)
|
|
124871
124912
|
*/
|
|
124872
124913
|
static isPassByValue(paramInfo, deps) {
|
|
124914
|
+
if (paramInfo.isCallbackPointerPrimitive) {
|
|
124915
|
+
return false;
|
|
124916
|
+
}
|
|
124873
124917
|
if (paramInfo.isCallback) {
|
|
124874
124918
|
return true;
|
|
124875
124919
|
}
|
|
@@ -124908,6 +124952,9 @@ var ParameterDereferenceResolver = class _ParameterDereferenceResolver {
|
|
|
124908
124952
|
if (_ParameterDereferenceResolver.isPassByValue(paramInfo, deps)) {
|
|
124909
124953
|
return id;
|
|
124910
124954
|
}
|
|
124955
|
+
if (paramInfo.forcePointerSemantics) {
|
|
124956
|
+
return `(*${id})`;
|
|
124957
|
+
}
|
|
124911
124958
|
return deps.maybeDereference(id);
|
|
124912
124959
|
}
|
|
124913
124960
|
};
|
|
@@ -125450,6 +125497,137 @@ var CastValidator = class _CastValidator {
|
|
|
125450
125497
|
};
|
|
125451
125498
|
var CastValidator_default = CastValidator;
|
|
125452
125499
|
|
|
125500
|
+
// src/transpiler/output/codegen/helpers/TypedefParamParser.ts
|
|
125501
|
+
var TypedefParamParser = class _TypedefParamParser {
|
|
125502
|
+
/**
|
|
125503
|
+
* Parse a function pointer typedef type string.
|
|
125504
|
+
*
|
|
125505
|
+
* @param typedefType - The type string, e.g., "void (*)(widget_t *, const rect_t *, uint8_t *)"
|
|
125506
|
+
* @returns Parsed result with return type and parameters, or null if parsing fails
|
|
125507
|
+
*/
|
|
125508
|
+
static parse(typedefType) {
|
|
125509
|
+
const funcPtrIndex = typedefType.indexOf("(*)");
|
|
125510
|
+
if (funcPtrIndex === -1) {
|
|
125511
|
+
return null;
|
|
125512
|
+
}
|
|
125513
|
+
const returnType = typedefType.substring(0, funcPtrIndex).trim();
|
|
125514
|
+
const afterFuncPtr = typedefType.substring(funcPtrIndex + 3).trim();
|
|
125515
|
+
if (!afterFuncPtr.startsWith("(")) {
|
|
125516
|
+
return null;
|
|
125517
|
+
}
|
|
125518
|
+
const paramsStr = _TypedefParamParser.extractParenContent(afterFuncPtr);
|
|
125519
|
+
if (paramsStr === null) {
|
|
125520
|
+
return null;
|
|
125521
|
+
}
|
|
125522
|
+
if (!paramsStr || paramsStr === "void") {
|
|
125523
|
+
return { returnType, params: [] };
|
|
125524
|
+
}
|
|
125525
|
+
const paramStrings = _TypedefParamParser.splitParams(paramsStr);
|
|
125526
|
+
const params = paramStrings.map((p) => _TypedefParamParser.parseParam(p));
|
|
125527
|
+
return { returnType, params };
|
|
125528
|
+
}
|
|
125529
|
+
/**
|
|
125530
|
+
* Extract content between matching parentheses, handling arbitrary nesting.
|
|
125531
|
+
* @param str - String starting with '('
|
|
125532
|
+
* @returns Content between outer parens, or null if no match
|
|
125533
|
+
*/
|
|
125534
|
+
static extractParenContent(str) {
|
|
125535
|
+
if (!str.startsWith("(")) {
|
|
125536
|
+
return null;
|
|
125537
|
+
}
|
|
125538
|
+
let depth = 0;
|
|
125539
|
+
for (let i = 0; i < str.length; i++) {
|
|
125540
|
+
if (str[i] === "(") {
|
|
125541
|
+
depth++;
|
|
125542
|
+
} else if (str[i] === ")") {
|
|
125543
|
+
depth--;
|
|
125544
|
+
if (depth === 0) {
|
|
125545
|
+
return str.substring(1, i);
|
|
125546
|
+
}
|
|
125547
|
+
}
|
|
125548
|
+
}
|
|
125549
|
+
return null;
|
|
125550
|
+
}
|
|
125551
|
+
/**
|
|
125552
|
+
* Split parameter string by commas, respecting nested parentheses.
|
|
125553
|
+
*/
|
|
125554
|
+
static splitParams(paramsStr) {
|
|
125555
|
+
const params = [];
|
|
125556
|
+
let current = "";
|
|
125557
|
+
let depth = 0;
|
|
125558
|
+
for (const char of paramsStr) {
|
|
125559
|
+
if (char === "(") {
|
|
125560
|
+
depth++;
|
|
125561
|
+
current += char;
|
|
125562
|
+
} else if (char === ")") {
|
|
125563
|
+
depth--;
|
|
125564
|
+
current += char;
|
|
125565
|
+
} else if (char === "," && depth === 0) {
|
|
125566
|
+
params.push(current.trim());
|
|
125567
|
+
current = "";
|
|
125568
|
+
} else {
|
|
125569
|
+
current += char;
|
|
125570
|
+
}
|
|
125571
|
+
}
|
|
125572
|
+
if (current.trim()) {
|
|
125573
|
+
params.push(current.trim());
|
|
125574
|
+
}
|
|
125575
|
+
return params;
|
|
125576
|
+
}
|
|
125577
|
+
/**
|
|
125578
|
+
* Parse a single parameter type string.
|
|
125579
|
+
*/
|
|
125580
|
+
static parseParam(paramStr) {
|
|
125581
|
+
const trimmed = paramStr.trim();
|
|
125582
|
+
const isPointer = trimmed.includes("*");
|
|
125583
|
+
const isConst = /\bconst\b/.test(trimmed) || trimmed.startsWith("const");
|
|
125584
|
+
let baseType = trimmed.replaceAll(/\bconst\b/g, "").replace(/^const/, "").replaceAll("*", "").replaceAll(/\s+/g, " ").trim();
|
|
125585
|
+
if (baseType.includes(" ")) {
|
|
125586
|
+
baseType = baseType.replace(/\s+\w+$/, "");
|
|
125587
|
+
}
|
|
125588
|
+
if (baseType.startsWith("struct ")) {
|
|
125589
|
+
baseType = baseType.substring(7);
|
|
125590
|
+
}
|
|
125591
|
+
return {
|
|
125592
|
+
type: trimmed,
|
|
125593
|
+
isPointer,
|
|
125594
|
+
isConst,
|
|
125595
|
+
baseType
|
|
125596
|
+
};
|
|
125597
|
+
}
|
|
125598
|
+
/**
|
|
125599
|
+
* Get the parameter info at a given index, or null if not found.
|
|
125600
|
+
*/
|
|
125601
|
+
static getParamAt(typedefType, paramIndex) {
|
|
125602
|
+
const parsed = _TypedefParamParser.parse(typedefType);
|
|
125603
|
+
if (!parsed || paramIndex >= parsed.params.length) {
|
|
125604
|
+
return null;
|
|
125605
|
+
}
|
|
125606
|
+
return parsed.params[paramIndex];
|
|
125607
|
+
}
|
|
125608
|
+
/**
|
|
125609
|
+
* Check if a parameter at a given index should be a pointer based on the typedef.
|
|
125610
|
+
*
|
|
125611
|
+
* @param typedefType - The typedef type string
|
|
125612
|
+
* @param paramIndex - The parameter index (0-based)
|
|
125613
|
+
* @returns true if the param should be a pointer, false for value, null if unknown
|
|
125614
|
+
*/
|
|
125615
|
+
static shouldBePointer(typedefType, paramIndex) {
|
|
125616
|
+
return _TypedefParamParser.getParamAt(typedefType, paramIndex)?.isPointer ?? null;
|
|
125617
|
+
}
|
|
125618
|
+
/**
|
|
125619
|
+
* Check if a parameter at a given index should be const based on the typedef.
|
|
125620
|
+
*
|
|
125621
|
+
* @param typedefType - The typedef type string
|
|
125622
|
+
* @param paramIndex - The parameter index (0-based)
|
|
125623
|
+
* @returns true if the param should be const, false otherwise, null if unknown
|
|
125624
|
+
*/
|
|
125625
|
+
static shouldBeConst(typedefType, paramIndex) {
|
|
125626
|
+
return _TypedefParamParser.getParamAt(typedefType, paramIndex)?.isConst ?? null;
|
|
125627
|
+
}
|
|
125628
|
+
};
|
|
125629
|
+
var TypedefParamParser_default = TypedefParamParser;
|
|
125630
|
+
|
|
125453
125631
|
// src/transpiler/output/codegen/helpers/FunctionContextManager.ts
|
|
125454
125632
|
var FunctionContextManager = class _FunctionContextManager {
|
|
125455
125633
|
/**
|
|
@@ -125510,14 +125688,15 @@ var FunctionContextManager = class _FunctionContextManager {
|
|
|
125510
125688
|
static processParameterList(params, callbacks) {
|
|
125511
125689
|
CodeGenState.currentParameters.clear();
|
|
125512
125690
|
if (!params) return;
|
|
125513
|
-
|
|
125514
|
-
|
|
125691
|
+
const paramList = params.parameter();
|
|
125692
|
+
for (let i = 0; i < paramList.length; i++) {
|
|
125693
|
+
_FunctionContextManager.processParameter(paramList[i], callbacks, i);
|
|
125515
125694
|
}
|
|
125516
125695
|
}
|
|
125517
125696
|
/**
|
|
125518
125697
|
* Process a single parameter declaration.
|
|
125519
125698
|
*/
|
|
125520
|
-
static processParameter(param, callbacks) {
|
|
125699
|
+
static processParameter(param, callbacks, paramIndex) {
|
|
125521
125700
|
const name = param.IDENTIFIER().getText();
|
|
125522
125701
|
const isArray = param.arrayDimension().length > 0 || param.type().arrayType() !== null;
|
|
125523
125702
|
const isConst = param.constModifier() !== null;
|
|
@@ -125526,14 +125705,21 @@ var FunctionContextManager = class _FunctionContextManager {
|
|
|
125526
125705
|
typeCtx,
|
|
125527
125706
|
callbacks
|
|
125528
125707
|
);
|
|
125708
|
+
const callbackTypedefInfo = _FunctionContextManager.getCallbackTypedefParamInfo(paramIndex);
|
|
125709
|
+
const isCallbackPointerParam = callbackTypedefInfo?.shouldBePointer ?? false;
|
|
125710
|
+
const isStruct = callbackTypedefInfo ? isCallbackPointerParam && typeInfo.isStruct : typeInfo.isStruct;
|
|
125711
|
+
const isCallbackPointerPrimitive = isCallbackPointerParam && !typeInfo.isStruct && !isArray;
|
|
125529
125712
|
const paramInfo = {
|
|
125530
125713
|
name,
|
|
125531
125714
|
baseType: typeInfo.typeName,
|
|
125532
125715
|
isArray,
|
|
125533
|
-
isStruct
|
|
125716
|
+
isStruct,
|
|
125534
125717
|
isConst,
|
|
125535
125718
|
isCallback: typeInfo.isCallback,
|
|
125536
|
-
isString: typeInfo.isString
|
|
125719
|
+
isString: typeInfo.isString,
|
|
125720
|
+
isCallbackPointerPrimitive,
|
|
125721
|
+
// Issue #895: Callback-compatible params need pointer semantics even in C++ mode
|
|
125722
|
+
forcePointerSemantics: isCallbackPointerParam
|
|
125537
125723
|
};
|
|
125538
125724
|
CodeGenState.currentParameters.set(name, paramInfo);
|
|
125539
125725
|
_FunctionContextManager.registerParameterType(
|
|
@@ -125696,6 +125882,32 @@ var FunctionContextManager = class _FunctionContextManager {
|
|
|
125696
125882
|
}
|
|
125697
125883
|
return dimensions;
|
|
125698
125884
|
}
|
|
125885
|
+
/**
|
|
125886
|
+
* Issue #895: Get callback typedef parameter info from the C header.
|
|
125887
|
+
* Returns null if not callback-compatible or index is invalid.
|
|
125888
|
+
*/
|
|
125889
|
+
static getCallbackTypedefParamInfo(paramIndex) {
|
|
125890
|
+
if (CodeGenState.currentFunctionName === null) return null;
|
|
125891
|
+
const typedefName = CodeGenState.callbackCompatibleFunctions.get(
|
|
125892
|
+
CodeGenState.currentFunctionName
|
|
125893
|
+
);
|
|
125894
|
+
if (!typedefName) return null;
|
|
125895
|
+
const typedefType = CodeGenState.getTypedefType(typedefName);
|
|
125896
|
+
if (!typedefType) return null;
|
|
125897
|
+
const shouldBePointer = TypedefParamParser_default.shouldBePointer(
|
|
125898
|
+
typedefType,
|
|
125899
|
+
paramIndex
|
|
125900
|
+
);
|
|
125901
|
+
const shouldBeConst = TypedefParamParser_default.shouldBeConst(
|
|
125902
|
+
typedefType,
|
|
125903
|
+
paramIndex
|
|
125904
|
+
);
|
|
125905
|
+
if (shouldBePointer === null) return null;
|
|
125906
|
+
return {
|
|
125907
|
+
shouldBePointer,
|
|
125908
|
+
shouldBeConst: shouldBeConst ?? false
|
|
125909
|
+
};
|
|
125910
|
+
}
|
|
125699
125911
|
/**
|
|
125700
125912
|
* Extract string capacity from a string type context.
|
|
125701
125913
|
*/
|
|
@@ -126488,7 +126700,8 @@ var ParameterInputAdapter = class {
|
|
|
126488
126700
|
}
|
|
126489
126701
|
const isKnownStruct = deps.isKnownStruct(typeName);
|
|
126490
126702
|
const isKnownPrimitive = !!deps.typeMap[typeName];
|
|
126491
|
-
const isAutoConst = !deps.isModified && !isConst;
|
|
126703
|
+
const isAutoConst = !deps.isCallbackCompatible && !deps.isModified && !isConst;
|
|
126704
|
+
const isPassByReference = deps.forcePassByReference || isKnownStruct || isKnownPrimitive;
|
|
126492
126705
|
return {
|
|
126493
126706
|
name,
|
|
126494
126707
|
baseType: typeName,
|
|
@@ -126499,7 +126712,12 @@ var ParameterInputAdapter = class {
|
|
|
126499
126712
|
isCallback: false,
|
|
126500
126713
|
isString: false,
|
|
126501
126714
|
isPassByValue: deps.isPassByValue,
|
|
126502
|
-
isPassByReference
|
|
126715
|
+
isPassByReference,
|
|
126716
|
+
// Issue #895: Force pointer syntax in C++ mode for callback-compatible functions
|
|
126717
|
+
// because C callback typedefs expect pointers, not C++ references
|
|
126718
|
+
forcePointerSyntax: deps.forcePassByReference,
|
|
126719
|
+
// Issue #895: Preserve const from callback typedef signature
|
|
126720
|
+
forceConst: deps.forceConst
|
|
126503
126721
|
};
|
|
126504
126722
|
}
|
|
126505
126723
|
/**
|
|
@@ -126713,11 +126931,15 @@ var ParameterSignatureBuilder = class {
|
|
|
126713
126931
|
/**
|
|
126714
126932
|
* Build pass-by-reference parameter signature.
|
|
126715
126933
|
* C mode: const Point* p
|
|
126716
|
-
* C++ mode: const Point& p
|
|
126934
|
+
* C++ mode: const Point& p (unless forcePointerSyntax)
|
|
126935
|
+
*
|
|
126936
|
+
* Issue #895: When forcePointerSyntax is set, always use pointer syntax
|
|
126937
|
+
* because C callback typedefs expect pointers, not C++ references.
|
|
126717
126938
|
*/
|
|
126718
126939
|
static _buildRefParam(param, refSuffix) {
|
|
126719
126940
|
const constPrefix = this._getConstPrefix(param);
|
|
126720
|
-
|
|
126941
|
+
const actualSuffix = param.forcePointerSyntax ? "*" : refSuffix;
|
|
126942
|
+
return `${constPrefix}${param.mappedType}${actualSuffix} ${param.name}`;
|
|
126721
126943
|
}
|
|
126722
126944
|
/**
|
|
126723
126945
|
* Build unknown type parameter (pass by value, standard C semantics).
|
|
@@ -126727,13 +126949,15 @@ var ParameterSignatureBuilder = class {
|
|
|
126727
126949
|
return `${constMod}${param.mappedType} ${param.name}`;
|
|
126728
126950
|
}
|
|
126729
126951
|
/**
|
|
126730
|
-
* Get const prefix combining explicit const
|
|
126731
|
-
*
|
|
126952
|
+
* Get const prefix combining explicit const, auto-const, and forced const.
|
|
126953
|
+
* Priority: forceConst > isConst > isAutoConst
|
|
126954
|
+
* Issue #895: forceConst preserves const from callback typedef signature.
|
|
126732
126955
|
*/
|
|
126733
126956
|
static _getConstPrefix(param) {
|
|
126734
|
-
|
|
126735
|
-
|
|
126736
|
-
|
|
126957
|
+
if (param.forceConst || param.isConst || param.isAutoConst) {
|
|
126958
|
+
return "const ";
|
|
126959
|
+
}
|
|
126960
|
+
return "";
|
|
126737
126961
|
}
|
|
126738
126962
|
};
|
|
126739
126963
|
var ParameterSignatureBuilder_default = ParameterSignatureBuilder;
|
|
@@ -127561,11 +127785,11 @@ var CodeGenerator = class _CodeGenerator {
|
|
|
127561
127785
|
TypeValidator_default.validateSwitchStatement(ctx, switchExpr);
|
|
127562
127786
|
}
|
|
127563
127787
|
/**
|
|
127564
|
-
* Validate
|
|
127788
|
+
* Validate condition is a boolean expression (ADR-027, Issue #884).
|
|
127565
127789
|
* Part of IOrchestrator interface (ADR-053 A3).
|
|
127566
127790
|
*/
|
|
127567
|
-
|
|
127568
|
-
TypeValidator_default.
|
|
127791
|
+
validateConditionIsBoolean(ctx, conditionType) {
|
|
127792
|
+
TypeValidator_default.validateConditionIsBoolean(ctx, conditionType);
|
|
127569
127793
|
}
|
|
127570
127794
|
/**
|
|
127571
127795
|
* Issue #254: Validate no function calls in condition (E0702).
|
|
@@ -127709,7 +127933,7 @@ var CodeGenerator = class _CodeGenerator {
|
|
|
127709
127933
|
}
|
|
127710
127934
|
/** Generate parameter list for function signature */
|
|
127711
127935
|
generateParameterList(ctx) {
|
|
127712
|
-
return ctx.parameter().map((p) => this.generateParameter(p)).join(", ");
|
|
127936
|
+
return ctx.parameter().map((p, index) => this.generateParameter(p, index)).join(", ");
|
|
127713
127937
|
}
|
|
127714
127938
|
/** Get the raw type name without C conversion */
|
|
127715
127939
|
getTypeName(ctx) {
|
|
@@ -127951,8 +128175,8 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
127951
128175
|
}
|
|
127952
128176
|
/**
|
|
127953
128177
|
* Issue #561: Analyze modifications in a parse tree without full code generation.
|
|
127954
|
-
* Used by
|
|
127955
|
-
* for cross-file const inference
|
|
128178
|
+
* Used by the transpile() pipeline to collect modification info from includes
|
|
128179
|
+
* for cross-file const inference.
|
|
127956
128180
|
*
|
|
127957
128181
|
* Issue #565: Now accepts optional cross-file data for transitive propagation.
|
|
127958
128182
|
* When a file calls a function from an included file that modifies its param,
|
|
@@ -129333,6 +129557,9 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
129333
129557
|
return "{}";
|
|
129334
129558
|
}
|
|
129335
129559
|
const fieldInits = fields.map((f) => `.${f.fieldName} = ${f.value}`);
|
|
129560
|
+
if (CodeGenState.cppMode && (typeName.startsWith("struct {") || typeName.startsWith("union {"))) {
|
|
129561
|
+
return `{ ${fieldInits.join(", ")} }`;
|
|
129562
|
+
}
|
|
129336
129563
|
return `(${castType}){ ${fieldInits.join(", ")} }`;
|
|
129337
129564
|
}
|
|
129338
129565
|
/**
|
|
@@ -129452,13 +129679,17 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
129452
129679
|
const typedef = this.generateCallbackTypedef(name);
|
|
129453
129680
|
return typedef ? functionCode + typedef : functionCode;
|
|
129454
129681
|
}
|
|
129455
|
-
generateParameter(ctx) {
|
|
129682
|
+
generateParameter(ctx, paramIndex) {
|
|
129456
129683
|
const typeName = this.getTypeName(ctx.type());
|
|
129457
129684
|
const name = ctx.IDENTIFIER().getText();
|
|
129458
129685
|
this._validateCStyleArrayParam(ctx, typeName, name);
|
|
129459
129686
|
this._validateUnboundedArrayParam(ctx);
|
|
129460
129687
|
const isModified = this._isCurrentParameterModified(name);
|
|
129461
|
-
const
|
|
129688
|
+
const callbackInfo = paramIndex === void 0 ? null : FunctionContextManager_default.getCallbackTypedefParamInfo(paramIndex);
|
|
129689
|
+
const isPassByValue = callbackInfo ? !callbackInfo.shouldBePointer : this._isPassByValueType(typeName, name);
|
|
129690
|
+
const isCallbackCompatible = callbackInfo !== null;
|
|
129691
|
+
const forcePassByReference = callbackInfo?.shouldBePointer ?? false;
|
|
129692
|
+
const forceConst = callbackInfo?.shouldBeConst ?? false;
|
|
129462
129693
|
const input = ParameterInputAdapter_default.fromAST(ctx, {
|
|
129463
129694
|
getTypeName: (t) => this.getTypeName(t),
|
|
129464
129695
|
generateType: (t) => this.generateType(t),
|
|
@@ -129467,7 +129698,10 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
129467
129698
|
isKnownStruct: (t) => this.isKnownStruct(t),
|
|
129468
129699
|
typeMap: TYPE_MAP_default,
|
|
129469
129700
|
isModified,
|
|
129470
|
-
isPassByValue
|
|
129701
|
+
isPassByValue,
|
|
129702
|
+
isCallbackCompatible,
|
|
129703
|
+
forcePassByReference,
|
|
129704
|
+
forceConst
|
|
129471
129705
|
});
|
|
129472
129706
|
return ParameterSignatureBuilder_default.build(input, CppModeHelper_default.refOrPtr());
|
|
129473
129707
|
}
|
|
@@ -129516,6 +129750,11 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
129516
129750
|
)) {
|
|
129517
129751
|
return true;
|
|
129518
129752
|
}
|
|
129753
|
+
if (CodeGenState.currentFunctionName && CodeGenState.callbackCompatibleFunctions.has(
|
|
129754
|
+
CodeGenState.currentFunctionName
|
|
129755
|
+
) && this.isKnownStruct(typeName)) {
|
|
129756
|
+
return true;
|
|
129757
|
+
}
|
|
129519
129758
|
return false;
|
|
129520
129759
|
}
|
|
129521
129760
|
// ========================================================================
|
|
@@ -129800,14 +130039,18 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
129800
130039
|
const isStructParam = paramInfo?.isStruct ?? false;
|
|
129801
130040
|
const isCppAccess = hasGlobal && this.isCppScopeSymbol(firstId);
|
|
129802
130041
|
const separatorDeps = this._buildMemberSeparatorDeps();
|
|
130042
|
+
const forcePointerSemantics = paramInfo?.forcePointerSemantics ?? false;
|
|
129803
130043
|
const separatorCtx = MemberSeparatorResolver_default.buildContext(
|
|
129804
|
-
|
|
129805
|
-
|
|
129806
|
-
|
|
129807
|
-
|
|
129808
|
-
|
|
129809
|
-
|
|
129810
|
-
|
|
130044
|
+
{
|
|
130045
|
+
firstId,
|
|
130046
|
+
hasGlobal,
|
|
130047
|
+
hasThis,
|
|
130048
|
+
currentScope: CodeGenState.currentScope,
|
|
130049
|
+
isStructParam,
|
|
130050
|
+
isCppAccess,
|
|
130051
|
+
forcePointerSemantics
|
|
130052
|
+
},
|
|
130053
|
+
separatorDeps
|
|
129811
130054
|
);
|
|
129812
130055
|
return {
|
|
129813
130056
|
generateExpression: (expr) => this.generateExpression(expr),
|
|
@@ -130728,8 +130971,11 @@ var HeaderGeneratorUtils = class _HeaderGeneratorUtils {
|
|
|
130728
130971
|
lines.push(include);
|
|
130729
130972
|
}
|
|
130730
130973
|
}
|
|
130974
|
+
const userIncludeSet = new Set(options.userIncludes ?? []);
|
|
130731
130975
|
for (const directive of headersToInclude) {
|
|
130732
|
-
|
|
130976
|
+
if (!userIncludeSet.has(directive)) {
|
|
130977
|
+
lines.push(directive);
|
|
130978
|
+
}
|
|
130733
130979
|
}
|
|
130734
130980
|
const hasIncludes = options.includeSystemHeaders !== false || options.userIncludes && options.userIncludes.length > 0 || headersToInclude.size > 0;
|
|
130735
130981
|
if (hasIncludes) {
|
|
@@ -133342,8 +133588,9 @@ var CResolver = class _CResolver {
|
|
|
133342
133588
|
if (!name) continue;
|
|
133343
133589
|
const isFunction = DeclaratorUtils_default.declaratorIsFunction(declarator);
|
|
133344
133590
|
if (ctx.isTypedef) {
|
|
133591
|
+
const typedefType = _CResolver.isFunctionPointerDeclarator(declarator) ? `${baseType} (*)(${_CResolver.extractParamText(declarator)})` : baseType;
|
|
133345
133592
|
ctx.symbols.push(
|
|
133346
|
-
TypedefCollector_default.collect(name,
|
|
133593
|
+
TypedefCollector_default.collect(name, typedefType, ctx.sourceFile, ctx.line)
|
|
133347
133594
|
);
|
|
133348
133595
|
} else if (isFunction) {
|
|
133349
133596
|
ctx.symbols.push(
|
|
@@ -133446,6 +133693,36 @@ var CResolver = class _CResolver {
|
|
|
133446
133693
|
}
|
|
133447
133694
|
return typeParts.join(" ") || "int";
|
|
133448
133695
|
}
|
|
133696
|
+
/**
|
|
133697
|
+
* Check if a declarator represents a function pointer.
|
|
133698
|
+
* For `(*PointCallback)(Point p)`, the C grammar parses as:
|
|
133699
|
+
* declarator -> directDeclarator
|
|
133700
|
+
* directDeclarator -> directDeclarator '(' parameterTypeList ')'
|
|
133701
|
+
* inner directDeclarator -> '(' declarator ')'
|
|
133702
|
+
* inner declarator -> pointer directDeclarator -> * PointCallback
|
|
133703
|
+
*/
|
|
133704
|
+
static isFunctionPointerDeclarator(declarator) {
|
|
133705
|
+
const directDecl = declarator.directDeclarator?.();
|
|
133706
|
+
if (!directDecl) return false;
|
|
133707
|
+
const hasParams = directDecl.parameterTypeList?.() !== null || Boolean(directDecl.LeftParen?.());
|
|
133708
|
+
if (!hasParams) return false;
|
|
133709
|
+
const innerDirectDecl = directDecl.directDeclarator?.();
|
|
133710
|
+
if (!innerDirectDecl) return false;
|
|
133711
|
+
const nestedDecl = innerDirectDecl.declarator?.();
|
|
133712
|
+
if (!nestedDecl) return false;
|
|
133713
|
+
return Boolean(nestedDecl.pointer?.());
|
|
133714
|
+
}
|
|
133715
|
+
/**
|
|
133716
|
+
* Extract parameter text from a function pointer declarator.
|
|
133717
|
+
* Returns the text of the parameters from a function pointer like "(*Callback)(Point p)".
|
|
133718
|
+
*/
|
|
133719
|
+
static extractParamText(declarator) {
|
|
133720
|
+
const directDecl = declarator.directDeclarator?.();
|
|
133721
|
+
if (!directDecl) return "";
|
|
133722
|
+
const paramTypeList = directDecl.parameterTypeList?.();
|
|
133723
|
+
if (!paramTypeList) return "";
|
|
133724
|
+
return paramTypeList.getText();
|
|
133725
|
+
}
|
|
133449
133726
|
};
|
|
133450
133727
|
var c_default = CResolver;
|
|
133451
133728
|
|
|
@@ -135075,6 +135352,9 @@ var IncludeResolver = class _IncludeResolver {
|
|
|
135075
135352
|
}
|
|
135076
135353
|
if (file.type === EFileType_default.CNext) {
|
|
135077
135354
|
result.cnextIncludes.push(file);
|
|
135355
|
+
const headerPath = includeInfo.path.replace(/\.cnx$|\.cnext$/, ".h");
|
|
135356
|
+
const directive = includeInfo.isLocal ? `#include "${headerPath}"` : `#include <${headerPath}>`;
|
|
135357
|
+
result.headerIncludeDirectives.set(absolutePath, directive);
|
|
135078
135358
|
}
|
|
135079
135359
|
}
|
|
135080
135360
|
/**
|
|
@@ -135212,8 +135492,8 @@ var IncludeResolver = class _IncludeResolver {
|
|
|
135212
135492
|
/**
|
|
135213
135493
|
* Build search paths from a source file location
|
|
135214
135494
|
*
|
|
135215
|
-
* Consolidates the search path building logic used by
|
|
135216
|
-
*
|
|
135495
|
+
* Consolidates the search path building logic used by the unified
|
|
135496
|
+
* transpile() entry point.
|
|
135217
135497
|
*
|
|
135218
135498
|
* Search order (highest to lowest priority):
|
|
135219
135499
|
* 1. Source file's directory (for relative includes)
|
|
@@ -136548,16 +136828,20 @@ var FunctionCallListener = class extends CNextListener {
|
|
|
136548
136828
|
// ========================================================================
|
|
136549
136829
|
// ISR/Callback Variable Tracking (ADR-040)
|
|
136550
136830
|
// ========================================================================
|
|
136831
|
+
/**
|
|
136832
|
+
* Check if a type name represents a callable type (ISR, callback, or C function pointer typedef).
|
|
136833
|
+
*/
|
|
136834
|
+
isCallableType(typeName) {
|
|
136835
|
+
return typeName === "ISR" || this.analyzer.isCallbackType(typeName) || this.analyzer.isCFunctionPointerTypedef(typeName);
|
|
136836
|
+
}
|
|
136551
136837
|
/**
|
|
136552
136838
|
* Track ISR-typed variables from variable declarations
|
|
136553
136839
|
* e.g., `ISR handler <- myFunction;`
|
|
136554
136840
|
*/
|
|
136555
136841
|
enterVariableDeclaration = (ctx) => {
|
|
136556
|
-
const
|
|
136557
|
-
|
|
136558
|
-
|
|
136559
|
-
const varName = ctx.IDENTIFIER().getText();
|
|
136560
|
-
this.analyzer.defineCallableVariable(varName);
|
|
136842
|
+
const typeName = ctx.type().getText();
|
|
136843
|
+
if (this.isCallableType(typeName)) {
|
|
136844
|
+
this.analyzer.defineCallableVariable(ctx.IDENTIFIER().getText());
|
|
136561
136845
|
}
|
|
136562
136846
|
};
|
|
136563
136847
|
/**
|
|
@@ -136565,11 +136849,9 @@ var FunctionCallListener = class extends CNextListener {
|
|
|
136565
136849
|
* e.g., `void execute(ISR handler) { handler(); }`
|
|
136566
136850
|
*/
|
|
136567
136851
|
enterParameter = (ctx) => {
|
|
136568
|
-
const
|
|
136569
|
-
|
|
136570
|
-
|
|
136571
|
-
const paramName = ctx.IDENTIFIER().getText();
|
|
136572
|
-
this.analyzer.defineCallableVariable(paramName);
|
|
136852
|
+
const typeName = ctx.type().getText();
|
|
136853
|
+
if (this.isCallableType(typeName)) {
|
|
136854
|
+
this.analyzer.defineCallableVariable(ctx.IDENTIFIER().getText());
|
|
136573
136855
|
}
|
|
136574
136856
|
};
|
|
136575
136857
|
// ========================================================================
|
|
@@ -136708,6 +136990,7 @@ var FunctionCallAnalyzer = class {
|
|
|
136708
136990
|
this.collectIncludes(tree);
|
|
136709
136991
|
this.collectCallbackTypes(tree);
|
|
136710
136992
|
this.collectAllLocalFunctions(tree);
|
|
136993
|
+
this.collectCallbackCompatibleFunctions(tree);
|
|
136711
136994
|
const listener = new FunctionCallListener(this);
|
|
136712
136995
|
ParseTreeWalker5.DEFAULT.walk(listener, tree);
|
|
136713
136996
|
return this.errors;
|
|
@@ -136791,6 +137074,187 @@ var FunctionCallAnalyzer = class {
|
|
|
136791
137074
|
isCallbackType(name) {
|
|
136792
137075
|
return this.callbackTypes.has(name);
|
|
136793
137076
|
}
|
|
137077
|
+
/**
|
|
137078
|
+
* Check if a type name is a C function pointer typedef.
|
|
137079
|
+
* Looks up the type in the symbol table and checks if it's a typedef
|
|
137080
|
+
* whose underlying type contains "(*)" indicating a function pointer.
|
|
137081
|
+
*/
|
|
137082
|
+
isCFunctionPointerTypedef(typeName) {
|
|
137083
|
+
if (!this.symbolTable) return false;
|
|
137084
|
+
const sym = this.symbolTable.getCSymbol(typeName);
|
|
137085
|
+
if (sym?.kind !== "type") return false;
|
|
137086
|
+
return "type" in sym && typeof sym.type === "string" && sym.type.includes("(*)");
|
|
137087
|
+
}
|
|
137088
|
+
/**
|
|
137089
|
+
* Detect functions assigned to C function pointer typedefs.
|
|
137090
|
+
* When `PointCallback cb <- my_handler;` is found and PointCallback
|
|
137091
|
+
* is a C function pointer typedef, mark my_handler as callback-compatible.
|
|
137092
|
+
*/
|
|
137093
|
+
collectCallbackCompatibleFunctions(tree) {
|
|
137094
|
+
for (const decl of tree.declaration()) {
|
|
137095
|
+
const funcDecl = decl.functionDeclaration();
|
|
137096
|
+
if (!funcDecl) continue;
|
|
137097
|
+
const block = funcDecl.block();
|
|
137098
|
+
if (!block) continue;
|
|
137099
|
+
this.scanBlockForCallbackAssignments(block);
|
|
137100
|
+
}
|
|
137101
|
+
}
|
|
137102
|
+
/**
|
|
137103
|
+
* Recursively scan all statements in a block for callback typedef assignments.
|
|
137104
|
+
*/
|
|
137105
|
+
scanBlockForCallbackAssignments(block) {
|
|
137106
|
+
for (const stmt of block.statement()) {
|
|
137107
|
+
this.scanStatementForCallbackAssignments(stmt);
|
|
137108
|
+
}
|
|
137109
|
+
}
|
|
137110
|
+
/**
|
|
137111
|
+
* Scan a single statement for callback typedef assignments,
|
|
137112
|
+
* recursing into nested blocks (if/while/for/do-while/switch/critical).
|
|
137113
|
+
*/
|
|
137114
|
+
scanStatementForCallbackAssignments(stmt) {
|
|
137115
|
+
const varDecl = stmt.variableDeclaration();
|
|
137116
|
+
if (varDecl) {
|
|
137117
|
+
this.checkVarDeclForCallbackAssignment(varDecl);
|
|
137118
|
+
return;
|
|
137119
|
+
}
|
|
137120
|
+
const exprStmt = stmt.expressionStatement();
|
|
137121
|
+
if (exprStmt) {
|
|
137122
|
+
this.checkExpressionForCallbackArgs(exprStmt.expression());
|
|
137123
|
+
return;
|
|
137124
|
+
}
|
|
137125
|
+
const ifStmt = stmt.ifStatement();
|
|
137126
|
+
if (ifStmt) {
|
|
137127
|
+
for (const child of ifStmt.statement()) {
|
|
137128
|
+
this.scanStatementForCallbackAssignments(child);
|
|
137129
|
+
}
|
|
137130
|
+
return;
|
|
137131
|
+
}
|
|
137132
|
+
const whileStmt = stmt.whileStatement();
|
|
137133
|
+
if (whileStmt) {
|
|
137134
|
+
this.scanStatementForCallbackAssignments(whileStmt.statement());
|
|
137135
|
+
return;
|
|
137136
|
+
}
|
|
137137
|
+
const forStmt = stmt.forStatement();
|
|
137138
|
+
if (forStmt) {
|
|
137139
|
+
this.scanStatementForCallbackAssignments(forStmt.statement());
|
|
137140
|
+
return;
|
|
137141
|
+
}
|
|
137142
|
+
const doWhileStmt = stmt.doWhileStatement();
|
|
137143
|
+
if (doWhileStmt) {
|
|
137144
|
+
this.scanBlockForCallbackAssignments(doWhileStmt.block());
|
|
137145
|
+
return;
|
|
137146
|
+
}
|
|
137147
|
+
const switchStmt = stmt.switchStatement();
|
|
137148
|
+
if (switchStmt) {
|
|
137149
|
+
for (const caseCtx of switchStmt.switchCase()) {
|
|
137150
|
+
this.scanBlockForCallbackAssignments(caseCtx.block());
|
|
137151
|
+
}
|
|
137152
|
+
const defaultCtx = switchStmt.defaultCase();
|
|
137153
|
+
if (defaultCtx) {
|
|
137154
|
+
this.scanBlockForCallbackAssignments(defaultCtx.block());
|
|
137155
|
+
}
|
|
137156
|
+
return;
|
|
137157
|
+
}
|
|
137158
|
+
const criticalStmt = stmt.criticalStatement();
|
|
137159
|
+
if (criticalStmt) {
|
|
137160
|
+
this.scanBlockForCallbackAssignments(criticalStmt.block());
|
|
137161
|
+
return;
|
|
137162
|
+
}
|
|
137163
|
+
const nestedBlock = stmt.block();
|
|
137164
|
+
if (nestedBlock) {
|
|
137165
|
+
this.scanBlockForCallbackAssignments(nestedBlock);
|
|
137166
|
+
}
|
|
137167
|
+
}
|
|
137168
|
+
/**
|
|
137169
|
+
* Check if a variable declaration assigns a function to a C callback typedef.
|
|
137170
|
+
*/
|
|
137171
|
+
checkVarDeclForCallbackAssignment(varDecl) {
|
|
137172
|
+
const typeName = varDecl.type().getText();
|
|
137173
|
+
if (!this.isCFunctionPointerTypedef(typeName)) return;
|
|
137174
|
+
const expr = varDecl.expression();
|
|
137175
|
+
if (!expr) return;
|
|
137176
|
+
const funcRef = this.extractFunctionReference(expr);
|
|
137177
|
+
if (!funcRef) return;
|
|
137178
|
+
const lookupName = funcRef.includes(".") ? funcRef.replace(".", "_") : funcRef;
|
|
137179
|
+
if (this.allLocalFunctions.has(lookupName)) {
|
|
137180
|
+
CodeGenState.callbackCompatibleFunctions.set(lookupName, typeName);
|
|
137181
|
+
}
|
|
137182
|
+
}
|
|
137183
|
+
/**
|
|
137184
|
+
* 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").
|
|
137187
|
+
* Returns null if the expression is not a function reference.
|
|
137188
|
+
*/
|
|
137189
|
+
extractFunctionReference(expr) {
|
|
137190
|
+
const text = expr.getText();
|
|
137191
|
+
if (/^\w+(\.\w+)?$/.test(text)) {
|
|
137192
|
+
return text;
|
|
137193
|
+
}
|
|
137194
|
+
return null;
|
|
137195
|
+
}
|
|
137196
|
+
/**
|
|
137197
|
+
* Issue #895: Check expression for function calls that pass C-Next functions
|
|
137198
|
+
* to C function pointer parameters.
|
|
137199
|
+
*
|
|
137200
|
+
* Pattern: `global.widget_set_flush_cb(w, my_flush)`
|
|
137201
|
+
* Where widget_set_flush_cb's 2nd param is a C function pointer typedef.
|
|
137202
|
+
*/
|
|
137203
|
+
checkExpressionForCallbackArgs(expr) {
|
|
137204
|
+
const postfix = this.findPostfixExpression(expr);
|
|
137205
|
+
if (!postfix) return;
|
|
137206
|
+
const callInfo = this.extractCallInfo(postfix);
|
|
137207
|
+
if (!callInfo) return;
|
|
137208
|
+
const cFunc = this.symbolTable?.getCSymbol(callInfo.funcName);
|
|
137209
|
+
if (cFunc?.kind !== "function" || !cFunc.parameters) return;
|
|
137210
|
+
for (let i = 0; i < callInfo.args.length; i++) {
|
|
137211
|
+
const param = cFunc.parameters[i];
|
|
137212
|
+
if (!param) continue;
|
|
137213
|
+
if (!this.isCFunctionPointerTypedef(param.type)) continue;
|
|
137214
|
+
const funcRef = this.extractFunctionReference(callInfo.args[i]);
|
|
137215
|
+
if (!funcRef) continue;
|
|
137216
|
+
const lookupName = funcRef.includes(".") ? funcRef.replace(".", "_") : funcRef;
|
|
137217
|
+
if (this.allLocalFunctions.has(lookupName)) {
|
|
137218
|
+
CodeGenState.callbackCompatibleFunctions.set(lookupName, param.type);
|
|
137219
|
+
}
|
|
137220
|
+
}
|
|
137221
|
+
}
|
|
137222
|
+
/**
|
|
137223
|
+
* Find the postfix expression within an expression tree.
|
|
137224
|
+
* Uses ExpressionUnwrapper which validates that expression is "simple"
|
|
137225
|
+
* (single term at each level), returning null for complex expressions.
|
|
137226
|
+
*/
|
|
137227
|
+
findPostfixExpression(expr) {
|
|
137228
|
+
return ExpressionUnwrapper_default.getPostfixExpression(expr);
|
|
137229
|
+
}
|
|
137230
|
+
/**
|
|
137231
|
+
* Extract function name and arguments from a postfix expression.
|
|
137232
|
+
* Returns null if not a function call.
|
|
137233
|
+
*/
|
|
137234
|
+
extractCallInfo(postfix) {
|
|
137235
|
+
const primary = postfix.primaryExpression();
|
|
137236
|
+
const ops = postfix.postfixOp();
|
|
137237
|
+
const ident = primary.IDENTIFIER();
|
|
137238
|
+
const globalKw = primary.GLOBAL();
|
|
137239
|
+
if (!ident && !globalKw) {
|
|
137240
|
+
return null;
|
|
137241
|
+
}
|
|
137242
|
+
let funcName = ident ? ident.getText() : "";
|
|
137243
|
+
let argListOp = null;
|
|
137244
|
+
for (const op of ops) {
|
|
137245
|
+
if (op.IDENTIFIER()) {
|
|
137246
|
+
const member = op.IDENTIFIER().getText();
|
|
137247
|
+
funcName = funcName ? `${funcName}_${member}` : member;
|
|
137248
|
+
} else if (op.argumentList() || op.getText().startsWith("(")) {
|
|
137249
|
+
argListOp = op;
|
|
137250
|
+
break;
|
|
137251
|
+
}
|
|
137252
|
+
}
|
|
137253
|
+
if (!argListOp || !funcName) return null;
|
|
137254
|
+
const argList = argListOp.argumentList();
|
|
137255
|
+
const args = argList?.expression() ?? [];
|
|
137256
|
+
return { funcName, args };
|
|
137257
|
+
}
|
|
136794
137258
|
/**
|
|
136795
137259
|
* ADR-040: Register a variable that holds a callable (ISR or callback)
|
|
136796
137260
|
*/
|
|
@@ -137044,6 +137508,26 @@ var TypeConstants = class {
|
|
|
137044
137508
|
"float",
|
|
137045
137509
|
"double"
|
|
137046
137510
|
];
|
|
137511
|
+
/**
|
|
137512
|
+
* Unsigned integer types valid as array/bit subscript indexes.
|
|
137513
|
+
*
|
|
137514
|
+
* Used by:
|
|
137515
|
+
* - ArrayIndexTypeAnalyzer: validating subscript index types
|
|
137516
|
+
*/
|
|
137517
|
+
static UNSIGNED_INDEX_TYPES = [
|
|
137518
|
+
"u8",
|
|
137519
|
+
"u16",
|
|
137520
|
+
"u32",
|
|
137521
|
+
"u64",
|
|
137522
|
+
"bool"
|
|
137523
|
+
];
|
|
137524
|
+
/**
|
|
137525
|
+
* Signed integer types (rejected as subscript indexes).
|
|
137526
|
+
*
|
|
137527
|
+
* Used by:
|
|
137528
|
+
* - ArrayIndexTypeAnalyzer: detecting signed integer subscript indexes
|
|
137529
|
+
*/
|
|
137530
|
+
static SIGNED_TYPES = ["i8", "i16", "i32", "i64"];
|
|
137047
137531
|
};
|
|
137048
137532
|
var TypeConstants_default = TypeConstants;
|
|
137049
137533
|
|
|
@@ -137161,6 +137645,212 @@ var FloatModuloAnalyzer = class {
|
|
|
137161
137645
|
};
|
|
137162
137646
|
var FloatModuloAnalyzer_default = FloatModuloAnalyzer;
|
|
137163
137647
|
|
|
137648
|
+
// src/transpiler/logic/analysis/ArrayIndexTypeAnalyzer.ts
|
|
137649
|
+
import { ParseTreeWalker as ParseTreeWalker8 } from "antlr4ng";
|
|
137650
|
+
var VariableTypeCollector = class extends CNextListener {
|
|
137651
|
+
varTypes = /* @__PURE__ */ new Map();
|
|
137652
|
+
getVarTypes() {
|
|
137653
|
+
return this.varTypes;
|
|
137654
|
+
}
|
|
137655
|
+
trackType(typeCtx, identifier) {
|
|
137656
|
+
if (!typeCtx || !identifier) return;
|
|
137657
|
+
this.varTypes.set(identifier.getText(), typeCtx.getText());
|
|
137658
|
+
}
|
|
137659
|
+
enterVariableDeclaration = (ctx) => {
|
|
137660
|
+
this.trackType(ctx.type(), ctx.IDENTIFIER());
|
|
137661
|
+
};
|
|
137662
|
+
enterParameter = (ctx) => {
|
|
137663
|
+
this.trackType(ctx.type(), ctx.IDENTIFIER());
|
|
137664
|
+
};
|
|
137665
|
+
enterForVarDecl = (ctx) => {
|
|
137666
|
+
this.trackType(ctx.type(), ctx.IDENTIFIER());
|
|
137667
|
+
};
|
|
137668
|
+
};
|
|
137669
|
+
var IndexTypeListener = class extends CNextListener {
|
|
137670
|
+
analyzer;
|
|
137671
|
+
// eslint-disable-next-line @typescript-eslint/lines-between-class-members
|
|
137672
|
+
varTypes;
|
|
137673
|
+
constructor(analyzer, varTypes) {
|
|
137674
|
+
super();
|
|
137675
|
+
this.analyzer = analyzer;
|
|
137676
|
+
this.varTypes = varTypes;
|
|
137677
|
+
}
|
|
137678
|
+
/**
|
|
137679
|
+
* Check postfix operations in expressions (RHS: arr[idx], flags[bit])
|
|
137680
|
+
*/
|
|
137681
|
+
enterPostfixOp = (ctx) => {
|
|
137682
|
+
if (!ctx.LBRACKET()) return;
|
|
137683
|
+
const expressions = ctx.expression();
|
|
137684
|
+
for (const expr of expressions) {
|
|
137685
|
+
this.validateIndexExpression(expr);
|
|
137686
|
+
}
|
|
137687
|
+
};
|
|
137688
|
+
/**
|
|
137689
|
+
* Check postfix target operations in assignments (LHS: arr[idx] <- val)
|
|
137690
|
+
*/
|
|
137691
|
+
enterPostfixTargetOp = (ctx) => {
|
|
137692
|
+
if (!ctx.LBRACKET()) return;
|
|
137693
|
+
const expressions = ctx.expression();
|
|
137694
|
+
for (const expr of expressions) {
|
|
137695
|
+
this.validateIndexExpression(expr);
|
|
137696
|
+
}
|
|
137697
|
+
};
|
|
137698
|
+
/**
|
|
137699
|
+
* Validate that a subscript index expression uses an unsigned integer type.
|
|
137700
|
+
* Collects all leaf operands from the expression and checks each one.
|
|
137701
|
+
*/
|
|
137702
|
+
validateIndexExpression(ctx) {
|
|
137703
|
+
const operands = this.collectOperands(ctx);
|
|
137704
|
+
for (const operand of operands) {
|
|
137705
|
+
const resolvedType = this.resolveOperandType(operand);
|
|
137706
|
+
if (!resolvedType) continue;
|
|
137707
|
+
if (TypeConstants_default.SIGNED_TYPES.includes(resolvedType)) {
|
|
137708
|
+
const { line: line2, column: column2 } = ParserUtils_default.getPosition(ctx);
|
|
137709
|
+
this.analyzer.addError(line2, column2, "E0850", resolvedType);
|
|
137710
|
+
return;
|
|
137711
|
+
}
|
|
137712
|
+
if (resolvedType === "float literal" || TypeConstants_default.FLOAT_TYPES.includes(resolvedType)) {
|
|
137713
|
+
const { line: line2, column: column2 } = ParserUtils_default.getPosition(ctx);
|
|
137714
|
+
this.analyzer.addError(line2, column2, "E0851", resolvedType);
|
|
137715
|
+
return;
|
|
137716
|
+
}
|
|
137717
|
+
if (TypeConstants_default.UNSIGNED_INDEX_TYPES.includes(resolvedType)) {
|
|
137718
|
+
continue;
|
|
137719
|
+
}
|
|
137720
|
+
const { line, column } = ParserUtils_default.getPosition(ctx);
|
|
137721
|
+
this.analyzer.addError(line, column, "E0852", resolvedType);
|
|
137722
|
+
return;
|
|
137723
|
+
}
|
|
137724
|
+
}
|
|
137725
|
+
/**
|
|
137726
|
+
* Collect all leaf unary expression operands from an expression tree.
|
|
137727
|
+
* Handles binary operators at any level by flatMapping through the grammar hierarchy.
|
|
137728
|
+
*/
|
|
137729
|
+
collectOperands(ctx) {
|
|
137730
|
+
const ternary = ctx.ternaryExpression();
|
|
137731
|
+
if (!ternary) return [];
|
|
137732
|
+
const orExpressions = ternary.orExpression();
|
|
137733
|
+
if (orExpressions.length === 0) return [];
|
|
137734
|
+
const valueExpressions = orExpressions.length === 3 ? orExpressions.slice(1) : orExpressions;
|
|
137735
|
+
return valueExpressions.flatMap((o) => o.andExpression()).flatMap((a) => a.equalityExpression()).flatMap((e) => e.relationalExpression()).flatMap((r) => r.bitwiseOrExpression()).flatMap((bo) => bo.bitwiseXorExpression()).flatMap((bx) => bx.bitwiseAndExpression()).flatMap((ba) => ba.shiftExpression()).flatMap((s) => s.additiveExpression()).flatMap((a) => a.multiplicativeExpression()).flatMap((m) => m.unaryExpression());
|
|
137736
|
+
}
|
|
137737
|
+
/**
|
|
137738
|
+
* Resolve the type of a unary expression operand.
|
|
137739
|
+
* Uses local varTypes first, then falls back to CodeGenState for
|
|
137740
|
+
* struct fields, function return types, and enum detection.
|
|
137741
|
+
*
|
|
137742
|
+
* Returns null if the type cannot be resolved (pass-through).
|
|
137743
|
+
*/
|
|
137744
|
+
resolveOperandType(operand) {
|
|
137745
|
+
const postfixExpr = operand.postfixExpression();
|
|
137746
|
+
if (!postfixExpr) return null;
|
|
137747
|
+
const primaryExpr = postfixExpr.primaryExpression();
|
|
137748
|
+
if (!primaryExpr) return null;
|
|
137749
|
+
let currentType = this.resolveBaseType(primaryExpr);
|
|
137750
|
+
const postfixOps = postfixExpr.postfixOp();
|
|
137751
|
+
if (!currentType && postfixOps.length > 0) {
|
|
137752
|
+
const identifier = primaryExpr.IDENTIFIER();
|
|
137753
|
+
if (identifier) {
|
|
137754
|
+
currentType = identifier.getText();
|
|
137755
|
+
}
|
|
137756
|
+
}
|
|
137757
|
+
for (const op of postfixOps) {
|
|
137758
|
+
if (!currentType) return null;
|
|
137759
|
+
currentType = this.resolvePostfixOpType(currentType, op);
|
|
137760
|
+
}
|
|
137761
|
+
return currentType;
|
|
137762
|
+
}
|
|
137763
|
+
/**
|
|
137764
|
+
* Resolve the base type of a primary expression.
|
|
137765
|
+
*/
|
|
137766
|
+
resolveBaseType(primaryExpr) {
|
|
137767
|
+
const literal = primaryExpr.literal();
|
|
137768
|
+
if (literal) {
|
|
137769
|
+
if (LiteralUtils_default.isFloat(literal)) return "float literal";
|
|
137770
|
+
return null;
|
|
137771
|
+
}
|
|
137772
|
+
const parenExpr = primaryExpr.expression();
|
|
137773
|
+
if (parenExpr) {
|
|
137774
|
+
const innerOperands = this.collectOperands(parenExpr);
|
|
137775
|
+
for (const innerOp of innerOperands) {
|
|
137776
|
+
const innerType = this.resolveOperandType(innerOp);
|
|
137777
|
+
if (innerType) return innerType;
|
|
137778
|
+
}
|
|
137779
|
+
return null;
|
|
137780
|
+
}
|
|
137781
|
+
const identifier = primaryExpr.IDENTIFIER();
|
|
137782
|
+
if (!identifier) return null;
|
|
137783
|
+
const varName = identifier.getText();
|
|
137784
|
+
const localType = this.varTypes.get(varName);
|
|
137785
|
+
if (localType) return localType;
|
|
137786
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(varName);
|
|
137787
|
+
if (typeInfo) return typeInfo.baseType;
|
|
137788
|
+
return null;
|
|
137789
|
+
}
|
|
137790
|
+
/**
|
|
137791
|
+
* Resolve the resulting type after applying a postfix operator.
|
|
137792
|
+
*/
|
|
137793
|
+
resolvePostfixOpType(currentType, op) {
|
|
137794
|
+
if (op.DOT()) {
|
|
137795
|
+
const fieldId = op.IDENTIFIER();
|
|
137796
|
+
if (!fieldId) return null;
|
|
137797
|
+
const fieldName = fieldId.getText();
|
|
137798
|
+
if (CodeGenState.isKnownEnum(currentType)) return null;
|
|
137799
|
+
const fieldType = CodeGenState.getStructFieldType(currentType, fieldName);
|
|
137800
|
+
return fieldType ?? null;
|
|
137801
|
+
}
|
|
137802
|
+
if (op.LBRACKET()) {
|
|
137803
|
+
if (TypeConstants_default.UNSIGNED_INDEX_TYPES.includes(currentType)) {
|
|
137804
|
+
return "bool";
|
|
137805
|
+
}
|
|
137806
|
+
if (TypeConstants_default.SIGNED_TYPES.includes(currentType)) {
|
|
137807
|
+
return "bool";
|
|
137808
|
+
}
|
|
137809
|
+
return currentType;
|
|
137810
|
+
}
|
|
137811
|
+
if (op.LPAREN()) {
|
|
137812
|
+
const returnType = CodeGenState.getFunctionReturnType(currentType);
|
|
137813
|
+
return returnType ?? null;
|
|
137814
|
+
}
|
|
137815
|
+
return null;
|
|
137816
|
+
}
|
|
137817
|
+
};
|
|
137818
|
+
var ArrayIndexTypeAnalyzer = class {
|
|
137819
|
+
errors = [];
|
|
137820
|
+
/**
|
|
137821
|
+
* Analyze the parse tree for invalid subscript index types
|
|
137822
|
+
*/
|
|
137823
|
+
analyze(tree) {
|
|
137824
|
+
this.errors = [];
|
|
137825
|
+
const collector = new VariableTypeCollector();
|
|
137826
|
+
ParseTreeWalker8.DEFAULT.walk(collector, tree);
|
|
137827
|
+
const varTypes = collector.getVarTypes();
|
|
137828
|
+
const listener = new IndexTypeListener(this, varTypes);
|
|
137829
|
+
ParseTreeWalker8.DEFAULT.walk(listener, tree);
|
|
137830
|
+
return this.errors;
|
|
137831
|
+
}
|
|
137832
|
+
/**
|
|
137833
|
+
* Add an index type error
|
|
137834
|
+
*/
|
|
137835
|
+
addError(line, column, code, actualType) {
|
|
137836
|
+
this.errors.push({
|
|
137837
|
+
code,
|
|
137838
|
+
line,
|
|
137839
|
+
column,
|
|
137840
|
+
actualType,
|
|
137841
|
+
message: `Subscript index must be an unsigned integer type; got '${actualType}'`,
|
|
137842
|
+
helpText: "Use an unsigned integer type (u8, u16, u32, u64) for array and bit subscript indexes."
|
|
137843
|
+
});
|
|
137844
|
+
}
|
|
137845
|
+
/**
|
|
137846
|
+
* Get all detected errors
|
|
137847
|
+
*/
|
|
137848
|
+
getErrors() {
|
|
137849
|
+
return this.errors;
|
|
137850
|
+
}
|
|
137851
|
+
};
|
|
137852
|
+
var ArrayIndexTypeAnalyzer_default = ArrayIndexTypeAnalyzer;
|
|
137853
|
+
|
|
137164
137854
|
// src/transpiler/logic/analysis/runAnalyzers.ts
|
|
137165
137855
|
function collectErrors(analyzerErrors, target, formatMessage) {
|
|
137166
137856
|
const formatter = formatMessage ?? ((e) => e.message);
|
|
@@ -137214,6 +137904,10 @@ function runAnalyzers(tree, tokenStream, options) {
|
|
|
137214
137904
|
if (collectErrors(floatModAnalyzer.analyze(tree), errors, formatWithCode)) {
|
|
137215
137905
|
return errors;
|
|
137216
137906
|
}
|
|
137907
|
+
const indexTypeAnalyzer = new ArrayIndexTypeAnalyzer_default();
|
|
137908
|
+
if (collectErrors(indexTypeAnalyzer.analyze(tree), errors, formatWithCode)) {
|
|
137909
|
+
return errors;
|
|
137910
|
+
}
|
|
137217
137911
|
const commentExtractor = new CommentExtractor_default(tokenStream);
|
|
137218
137912
|
collectErrors(
|
|
137219
137913
|
commentExtractor.validate(),
|
|
@@ -137821,7 +138515,7 @@ var TransitiveEnumCollector = class {
|
|
|
137821
138515
|
/**
|
|
137822
138516
|
* Collect symbol info for standalone mode from resolved includes.
|
|
137823
138517
|
*
|
|
137824
|
-
* Issue #591: Extracted
|
|
138518
|
+
* Issue #591: Extracted to unify enum collection across transpilation modes.
|
|
137825
138519
|
* Unlike collect() which starts from a file path and parses it, this method
|
|
137826
138520
|
* starts from already-resolved includes (from IncludeResolver.resolve()).
|
|
137827
138521
|
*
|
|
@@ -137899,83 +138593,53 @@ var Transpiler = class {
|
|
|
137899
138593
|
this.cacheManager = projectRoot ? new CacheManager_default(projectRoot, this.fs) : null;
|
|
137900
138594
|
}
|
|
137901
138595
|
// ===========================================================================
|
|
137902
|
-
// Public API
|
|
138596
|
+
// Public API
|
|
137903
138597
|
// ===========================================================================
|
|
137904
138598
|
/**
|
|
137905
|
-
*
|
|
138599
|
+
* Unified entry point for all transpilation.
|
|
137906
138600
|
*
|
|
137907
|
-
*
|
|
138601
|
+
* @param input - What to transpile:
|
|
138602
|
+
* - { kind: 'files' } — discover from config.inputs, write to disk
|
|
138603
|
+
* - { kind: 'source', source, ... } — transpile in-memory source
|
|
138604
|
+
* @returns ITranspilerResult with per-file results in .files[]
|
|
137908
138605
|
*/
|
|
137909
|
-
async
|
|
138606
|
+
async transpile(input) {
|
|
137910
138607
|
const result = this._initResult();
|
|
137911
138608
|
try {
|
|
137912
138609
|
await this._initializeRun();
|
|
137913
|
-
const
|
|
137914
|
-
if (cnextFiles.length === 0) {
|
|
138610
|
+
const pipelineInput = await this.discoverIncludes(input);
|
|
138611
|
+
if (pipelineInput.cnextFiles.length === 0) {
|
|
137915
138612
|
return this._finalizeResult(result, "No C-Next source files found");
|
|
137916
138613
|
}
|
|
137917
|
-
|
|
137918
|
-
|
|
137919
|
-
|
|
137920
|
-
|
|
137921
|
-
}));
|
|
137922
|
-
const input = {
|
|
137923
|
-
cnextFiles: pipelineFiles,
|
|
137924
|
-
headerFiles,
|
|
137925
|
-
writeOutputToDisk: true
|
|
137926
|
-
};
|
|
137927
|
-
await this._executePipeline(input, result);
|
|
138614
|
+
if (input.kind === "files") {
|
|
138615
|
+
this._ensureOutputDirectories();
|
|
138616
|
+
}
|
|
138617
|
+
await this._executePipeline(pipelineInput, result);
|
|
137928
138618
|
return await this._finalizeResult(result);
|
|
137929
138619
|
} catch (err) {
|
|
137930
138620
|
return this._handleRunError(result, err);
|
|
137931
138621
|
}
|
|
137932
138622
|
}
|
|
137933
138623
|
/**
|
|
137934
|
-
*
|
|
138624
|
+
* Stage 1: Discover files and build pipeline input.
|
|
137935
138625
|
*
|
|
137936
|
-
*
|
|
137937
|
-
*
|
|
138626
|
+
* Branches on input kind:
|
|
138627
|
+
* - 'files': filesystem scan, dependency graph, topological sort
|
|
138628
|
+
* - 'source': parse in-memory string, walk include tree
|
|
137938
138629
|
*
|
|
137939
|
-
*
|
|
137940
|
-
*
|
|
137941
|
-
|
|
137942
|
-
|
|
137943
|
-
|
|
137944
|
-
|
|
137945
|
-
|
|
137946
|
-
|
|
137947
|
-
|
|
137948
|
-
|
|
137949
|
-
|
|
137950
|
-
|
|
137951
|
-
|
|
137952
|
-
additionalIncludeDirs,
|
|
137953
|
-
sourcePath
|
|
137954
|
-
);
|
|
137955
|
-
const result = this._initResult();
|
|
137956
|
-
await this._executePipeline(input, result);
|
|
137957
|
-
const fileResult = result.files.find((f) => f.sourcePath === sourcePath);
|
|
137958
|
-
if (fileResult) {
|
|
137959
|
-
return fileResult;
|
|
137960
|
-
}
|
|
137961
|
-
if (result.errors.length > 0) {
|
|
137962
|
-
return this.buildErrorResult(sourcePath, result.errors, 0);
|
|
137963
|
-
}
|
|
137964
|
-
return this.buildErrorResult(
|
|
137965
|
-
sourcePath,
|
|
137966
|
-
[
|
|
137967
|
-
{
|
|
137968
|
-
line: 1,
|
|
137969
|
-
column: 0,
|
|
137970
|
-
message: "Pipeline produced no result for source file",
|
|
137971
|
-
severity: "error"
|
|
137972
|
-
}
|
|
137973
|
-
],
|
|
137974
|
-
0
|
|
137975
|
-
);
|
|
137976
|
-
} catch (err) {
|
|
137977
|
-
return this.buildCatchResult(sourcePath, err);
|
|
137978
|
-
}
|
|
138630
|
+
* Header directive storage happens via IncludeResolver.resolve() for both
|
|
138631
|
+
* C headers and cnext includes (Issue #854).
|
|
138632
|
+
*/
|
|
138633
|
+
async discoverIncludes(input) {
|
|
138634
|
+
if (input.kind === "files") {
|
|
138635
|
+
return this._discoverFromFiles();
|
|
138636
|
+
}
|
|
138637
|
+
return this._discoverFromSource(
|
|
138638
|
+
input.source,
|
|
138639
|
+
input.workingDir ?? process.cwd(),
|
|
138640
|
+
input.includeDirs ?? [],
|
|
138641
|
+
input.sourcePath ?? "<string>"
|
|
138642
|
+
);
|
|
137979
138643
|
}
|
|
137980
138644
|
// ===========================================================================
|
|
137981
138645
|
// Unified Pipeline
|
|
@@ -137983,7 +138647,7 @@ var Transpiler = class {
|
|
|
137983
138647
|
/**
|
|
137984
138648
|
* The single unified pipeline for all transpilation.
|
|
137985
138649
|
*
|
|
137986
|
-
*
|
|
138650
|
+
* transpile() delegates here after file discovery via discoverIncludes().
|
|
137987
138651
|
*
|
|
137988
138652
|
* Stage 2: Collect symbols from C/C++ headers (includes building analyzer context)
|
|
137989
138653
|
* Stage 3: Collect symbols from C-Next files
|
|
@@ -138090,14 +138754,6 @@ var Transpiler = class {
|
|
|
138090
138754
|
if (this.config.parseOnly) {
|
|
138091
138755
|
return this.buildParseOnlyResult(sourcePath, declarationCount);
|
|
138092
138756
|
}
|
|
138093
|
-
const analyzerErrors = runAnalyzers_default(tree, tokenStream);
|
|
138094
|
-
if (analyzerErrors.length > 0) {
|
|
138095
|
-
return this.buildErrorResult(
|
|
138096
|
-
sourcePath,
|
|
138097
|
-
analyzerErrors,
|
|
138098
|
-
declarationCount
|
|
138099
|
-
);
|
|
138100
|
-
}
|
|
138101
138757
|
const tSymbols = cnext_default.resolve(tree, sourcePath);
|
|
138102
138758
|
let symbolInfo = TSymbolInfoAdapter_default.convert(tSymbols);
|
|
138103
138759
|
const externalEnumSources = this._collectExternalEnumSources(
|
|
@@ -138110,6 +138766,15 @@ var Transpiler = class {
|
|
|
138110
138766
|
externalEnumSources
|
|
138111
138767
|
);
|
|
138112
138768
|
}
|
|
138769
|
+
CodeGenState.symbols = symbolInfo;
|
|
138770
|
+
const analyzerErrors = runAnalyzers_default(tree, tokenStream);
|
|
138771
|
+
if (analyzerErrors.length > 0) {
|
|
138772
|
+
return this.buildErrorResult(
|
|
138773
|
+
sourcePath,
|
|
138774
|
+
analyzerErrors,
|
|
138775
|
+
declarationCount
|
|
138776
|
+
);
|
|
138777
|
+
}
|
|
138113
138778
|
this._setupCrossFileModifications();
|
|
138114
138779
|
const code = this.codeGenerator.generate(tree, tokenStream, {
|
|
138115
138780
|
debugMode: this.config.debugMode,
|
|
@@ -138127,15 +138792,7 @@ var Transpiler = class {
|
|
|
138127
138792
|
if (this.cppDetected) {
|
|
138128
138793
|
this._accumulateFileModifications();
|
|
138129
138794
|
}
|
|
138130
|
-
const
|
|
138131
|
-
const headerCode = this.generateHeaderContent(
|
|
138132
|
-
fileSymbols,
|
|
138133
|
-
sourcePath,
|
|
138134
|
-
this.cppDetected,
|
|
138135
|
-
userIncludes,
|
|
138136
|
-
passByValueCopy,
|
|
138137
|
-
symbolInfo
|
|
138138
|
-
);
|
|
138795
|
+
const headerCode = this.generateHeaderForFile(file) ?? void 0;
|
|
138139
138796
|
return this.buildSuccessResult(
|
|
138140
138797
|
sourcePath,
|
|
138141
138798
|
code,
|
|
@@ -138200,6 +138857,13 @@ var Transpiler = class {
|
|
|
138200
138857
|
this.state.setHeaderDirective(header.path, directive);
|
|
138201
138858
|
}
|
|
138202
138859
|
}
|
|
138860
|
+
for (const cnxInclude of resolved.cnextIncludes) {
|
|
138861
|
+
const includePath = resolve12(cnxInclude.path);
|
|
138862
|
+
const directive = resolved.headerIncludeDirectives.get(includePath);
|
|
138863
|
+
if (directive) {
|
|
138864
|
+
this.state.setHeaderDirective(includePath, directive);
|
|
138865
|
+
}
|
|
138866
|
+
}
|
|
138203
138867
|
const cnextIncludeFiles = [];
|
|
138204
138868
|
IncludeTreeWalker_default.walk(
|
|
138205
138869
|
resolved.cnextIncludes,
|
|
@@ -138257,6 +138921,7 @@ var Transpiler = class {
|
|
|
138257
138921
|
this.state.reset();
|
|
138258
138922
|
CodeGenState.symbolTable.clear();
|
|
138259
138923
|
SymbolRegistry_default.reset();
|
|
138924
|
+
CodeGenState.callbackCompatibleFunctions = /* @__PURE__ */ new Map();
|
|
138260
138925
|
}
|
|
138261
138926
|
/**
|
|
138262
138927
|
* Ensure output directories exist
|
|
@@ -138335,8 +139000,12 @@ var Transpiler = class {
|
|
|
138335
139000
|
if (file.symbolOnly) {
|
|
138336
139001
|
continue;
|
|
138337
139002
|
}
|
|
138338
|
-
const
|
|
138339
|
-
if (
|
|
139003
|
+
const headerContent = this.generateHeaderForFile(file);
|
|
139004
|
+
if (headerContent) {
|
|
139005
|
+
const headerPath = this.pathResolver.getHeaderOutputPath(
|
|
139006
|
+
file.discoveredFile
|
|
139007
|
+
);
|
|
139008
|
+
this.fs.writeFile(headerPath, headerContent);
|
|
138340
139009
|
result.outputFiles.push(headerPath);
|
|
138341
139010
|
}
|
|
138342
139011
|
}
|
|
@@ -138370,7 +139039,7 @@ var Transpiler = class {
|
|
|
138370
139039
|
return result;
|
|
138371
139040
|
}
|
|
138372
139041
|
// ===========================================================================
|
|
138373
|
-
//
|
|
139042
|
+
// File Discovery (Stage 1 for files mode)
|
|
138374
139043
|
// ===========================================================================
|
|
138375
139044
|
/**
|
|
138376
139045
|
* Discover C-Next files from a single input (file or directory).
|
|
@@ -138431,6 +139100,10 @@ var Transpiler = class {
|
|
|
138431
139100
|
""
|
|
138432
139101
|
);
|
|
138433
139102
|
depGraph.addDependency(cnxPath, includePath);
|
|
139103
|
+
const directive = resolved.headerIncludeDirectives.get(includePath);
|
|
139104
|
+
if (directive) {
|
|
139105
|
+
this.state.setHeaderDirective(includePath, directive);
|
|
139106
|
+
}
|
|
138434
139107
|
const alreadyExists = cnextBaseNames.has(includeBaseName) || cnextFiles.some((f) => resolve12(f.path) === includePath);
|
|
138435
139108
|
if (!alreadyExists) {
|
|
138436
139109
|
cnextFiles.push(cnxInclude);
|
|
@@ -138494,14 +139167,14 @@ var Transpiler = class {
|
|
|
138494
139167
|
* This ensures headers are found based on what the source actually
|
|
138495
139168
|
* includes, not by blindly scanning include directories.
|
|
138496
139169
|
*/
|
|
138497
|
-
async
|
|
139170
|
+
async _discoverFromFiles() {
|
|
138498
139171
|
const cnextFiles = [];
|
|
138499
139172
|
const fileByPath = /* @__PURE__ */ new Map();
|
|
138500
139173
|
for (const input of this.config.inputs) {
|
|
138501
139174
|
this._discoverCNextFromInput(input, cnextFiles, fileByPath);
|
|
138502
139175
|
}
|
|
138503
139176
|
if (cnextFiles.length === 0) {
|
|
138504
|
-
return { cnextFiles: [], headerFiles: [] };
|
|
139177
|
+
return { cnextFiles: [], headerFiles: [], writeOutputToDisk: true };
|
|
138505
139178
|
}
|
|
138506
139179
|
const headerSet = /* @__PURE__ */ new Map();
|
|
138507
139180
|
const depGraph = new DependencyGraph_default();
|
|
@@ -138529,9 +139202,14 @@ var Transpiler = class {
|
|
|
138529
139202
|
}
|
|
138530
139203
|
);
|
|
138531
139204
|
this.warnings.push(...headerWarnings);
|
|
139205
|
+
const pipelineFiles = sortedCnextFiles.map((f) => ({
|
|
139206
|
+
path: f.path,
|
|
139207
|
+
discoveredFile: f
|
|
139208
|
+
}));
|
|
138532
139209
|
return {
|
|
138533
|
-
cnextFiles:
|
|
138534
|
-
headerFiles: allHeaders
|
|
139210
|
+
cnextFiles: pipelineFiles,
|
|
139211
|
+
headerFiles: allHeaders,
|
|
139212
|
+
writeOutputToDisk: true
|
|
138535
139213
|
};
|
|
138536
139214
|
}
|
|
138537
139215
|
// ===========================================================================
|
|
@@ -138716,17 +139394,22 @@ var Transpiler = class {
|
|
|
138716
139394
|
* Stage 6: Generate header file for a C-Next file
|
|
138717
139395
|
* ADR-055 Phase 7: Uses TSymbol directly, converts to IHeaderSymbol for generation.
|
|
138718
139396
|
*/
|
|
138719
|
-
|
|
138720
|
-
|
|
139397
|
+
/**
|
|
139398
|
+
* Generate header content for a single file's exported symbols.
|
|
139399
|
+
* Unified method replacing both generateHeader() and generateHeaderContent().
|
|
139400
|
+
* Reads all needed data from state (populated during Stage 5).
|
|
139401
|
+
*/
|
|
139402
|
+
generateHeaderForFile(file) {
|
|
139403
|
+
const sourcePath = file.path;
|
|
139404
|
+
const tSymbols = CodeGenState.symbolTable.getTSymbolsByFile(sourcePath);
|
|
138721
139405
|
const exportedSymbols = tSymbols.filter((s) => s.isExported);
|
|
138722
139406
|
if (exportedSymbols.length === 0) {
|
|
138723
139407
|
return null;
|
|
138724
139408
|
}
|
|
138725
|
-
const headerName = basename5(
|
|
138726
|
-
const
|
|
138727
|
-
const
|
|
138728
|
-
const
|
|
138729
|
-
const userIncludes = this.state.getUserIncludes(file.path);
|
|
139409
|
+
const headerName = basename5(sourcePath).replace(/\.cnx$|\.cnext$/, ".h");
|
|
139410
|
+
const typeInput = this.state.getSymbolInfo(sourcePath);
|
|
139411
|
+
const passByValueParams = this.state.getPassByValueParams(sourcePath) ?? /* @__PURE__ */ new Map();
|
|
139412
|
+
const userIncludes = this.state.getUserIncludes(sourcePath);
|
|
138730
139413
|
const allKnownEnums = TransitiveEnumCollector_default.aggregateKnownEnums(
|
|
138731
139414
|
this.state.getAllSymbolInfo()
|
|
138732
139415
|
);
|
|
@@ -138741,7 +139424,7 @@ var Transpiler = class {
|
|
|
138741
139424
|
unmodifiedParams,
|
|
138742
139425
|
allKnownEnums
|
|
138743
139426
|
);
|
|
138744
|
-
|
|
139427
|
+
return this.headerGenerator.generate(
|
|
138745
139428
|
headerSymbols,
|
|
138746
139429
|
headerName,
|
|
138747
139430
|
{
|
|
@@ -138754,8 +139437,6 @@ var Transpiler = class {
|
|
|
138754
139437
|
passByValueParams,
|
|
138755
139438
|
allKnownEnums
|
|
138756
139439
|
);
|
|
138757
|
-
this.fs.writeFile(headerPath, headerContent);
|
|
138758
|
-
return headerPath;
|
|
138759
139440
|
}
|
|
138760
139441
|
/**
|
|
138761
139442
|
* Collect external enum sources from included C-Next files.
|
|
@@ -138788,43 +139469,6 @@ var Transpiler = class {
|
|
|
138788
139469
|
);
|
|
138789
139470
|
}
|
|
138790
139471
|
}
|
|
138791
|
-
/**
|
|
138792
|
-
* Generate header content for exported symbols.
|
|
138793
|
-
* Issue #591: Extracted from transpileSource() for reduced complexity.
|
|
138794
|
-
* ADR-055 Phase 7: Works with TSymbol[], converts to IHeaderSymbol for generation.
|
|
138795
|
-
*/
|
|
138796
|
-
generateHeaderContent(tSymbols, sourcePath, cppMode, userIncludes, passByValueParams, symbolInfo) {
|
|
138797
|
-
const exportedSymbols = tSymbols.filter((s) => s.isExported);
|
|
138798
|
-
if (exportedSymbols.length === 0) {
|
|
138799
|
-
return void 0;
|
|
138800
|
-
}
|
|
138801
|
-
const unmodifiedParams = this.codeGenerator.getFunctionUnmodifiedParams();
|
|
138802
|
-
const headerSymbols = this.convertToHeaderSymbols(
|
|
138803
|
-
exportedSymbols,
|
|
138804
|
-
unmodifiedParams,
|
|
138805
|
-
symbolInfo.knownEnums
|
|
138806
|
-
);
|
|
138807
|
-
const headerName = basename5(sourcePath).replace(/\.cnx$|\.cnext$/, ".h");
|
|
138808
|
-
const typeInput = CodeGenState.symbols;
|
|
138809
|
-
const externalTypeHeaders = ExternalTypeHeaderBuilder_default.build(
|
|
138810
|
-
this.state.getAllHeaderDirectives(),
|
|
138811
|
-
CodeGenState.symbolTable
|
|
138812
|
-
);
|
|
138813
|
-
const typeInputWithSymbolTable = typeInput ? { ...typeInput, symbolTable: CodeGenState.symbolTable } : void 0;
|
|
138814
|
-
return this.headerGenerator.generate(
|
|
138815
|
-
headerSymbols,
|
|
138816
|
-
headerName,
|
|
138817
|
-
{
|
|
138818
|
-
exportedOnly: true,
|
|
138819
|
-
userIncludes,
|
|
138820
|
-
externalTypeHeaders,
|
|
138821
|
-
cppMode
|
|
138822
|
-
},
|
|
138823
|
-
typeInputWithSymbolTable,
|
|
138824
|
-
passByValueParams,
|
|
138825
|
-
symbolInfo.knownEnums
|
|
138826
|
-
);
|
|
138827
|
-
}
|
|
138828
139472
|
/**
|
|
138829
139473
|
* Convert TSymbols to IHeaderSymbols with auto-const information applied.
|
|
138830
139474
|
* ADR-055 Phase 7: Replaces mutation-based auto-const updating.
|
|
@@ -139032,7 +139676,7 @@ var Runner = class {
|
|
|
139032
139676
|
target: config.target,
|
|
139033
139677
|
debugMode: config.debugMode
|
|
139034
139678
|
});
|
|
139035
|
-
const result = await pipeline.
|
|
139679
|
+
const result = await pipeline.transpile({ kind: "files" });
|
|
139036
139680
|
this._renameOutputIfNeeded(result, explicitOutputFile);
|
|
139037
139681
|
ResultPrinter_default.print(result);
|
|
139038
139682
|
process.exit(result.success ? 0 : 1);
|
|
@@ -139742,16 +140386,31 @@ var ServeCommand = class _ServeCommand {
|
|
|
139742
140386
|
}
|
|
139743
140387
|
const { source, filePath } = params;
|
|
139744
140388
|
const options = filePath ? { workingDir: dirname11(filePath), sourcePath: filePath } : void 0;
|
|
139745
|
-
const
|
|
140389
|
+
const transpileResult = await _ServeCommand.transpiler.transpile({
|
|
140390
|
+
kind: "source",
|
|
139746
140391
|
source,
|
|
139747
|
-
options
|
|
139748
|
-
);
|
|
140392
|
+
...options
|
|
140393
|
+
});
|
|
140394
|
+
const fileResult = transpileResult.files.find(
|
|
140395
|
+
(f) => f.sourcePath === (filePath ?? "<string>")
|
|
140396
|
+
) ?? transpileResult.files[0];
|
|
140397
|
+
if (!fileResult) {
|
|
140398
|
+
return {
|
|
140399
|
+
success: true,
|
|
140400
|
+
result: {
|
|
140401
|
+
success: false,
|
|
140402
|
+
code: "",
|
|
140403
|
+
errors: transpileResult.errors,
|
|
140404
|
+
cppDetected: _ServeCommand.transpiler.isCppDetected()
|
|
140405
|
+
}
|
|
140406
|
+
};
|
|
140407
|
+
}
|
|
139749
140408
|
return {
|
|
139750
140409
|
success: true,
|
|
139751
140410
|
result: {
|
|
139752
|
-
success:
|
|
139753
|
-
code:
|
|
139754
|
-
errors:
|
|
140411
|
+
success: fileResult.success,
|
|
140412
|
+
code: fileResult.code,
|
|
140413
|
+
errors: fileResult.errors,
|
|
139755
140414
|
cppDetected: _ServeCommand.transpiler.isCppDetected()
|
|
139756
140415
|
}
|
|
139757
140416
|
};
|
|
@@ -139765,7 +140424,9 @@ var ServeCommand = class _ServeCommand {
|
|
|
139765
140424
|
const { source, filePath } = params;
|
|
139766
140425
|
if (_ServeCommand.transpiler && filePath) {
|
|
139767
140426
|
try {
|
|
139768
|
-
await _ServeCommand.transpiler.
|
|
140427
|
+
await _ServeCommand.transpiler.transpile({
|
|
140428
|
+
kind: "source",
|
|
140429
|
+
source,
|
|
139769
140430
|
workingDir: dirname11(filePath),
|
|
139770
140431
|
sourcePath: filePath
|
|
139771
140432
|
});
|