c-next 0.2.2 → 0.2.4
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 +641 -191
- package/dist/index.js.map +4 -4
- package/package.json +1 -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 +170 -14
- package/src/transpiler/logic/analysis/__tests__/ArrayIndexTypeAnalyzer.test.ts +545 -0
- package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +327 -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/index.ts +50 -1
- package/src/transpiler/logic/symbols/c/utils/DeclaratorUtils.ts +99 -2
- package/src/transpiler/logic/symbols/c/utils/__tests__/DeclaratorUtils.test.ts +128 -0
- package/src/transpiler/output/codegen/CodeGenerator.ts +31 -5
- package/src/transpiler/output/codegen/TypeValidator.ts +10 -7
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +49 -36
- package/src/transpiler/output/codegen/__tests__/ExpressionWalker.test.ts +9 -3
- package/src/transpiler/output/codegen/__tests__/RequireInclude.test.ts +90 -25
- 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 +23 -14
- package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +10 -7
- package/src/transpiler/output/codegen/generators/statements/ControlFlowGenerator.ts +12 -3
- package/src/transpiler/output/codegen/generators/statements/SwitchGenerator.ts +10 -1
- package/src/transpiler/output/codegen/generators/statements/__tests__/ControlFlowGenerator.test.ts +4 -4
- package/src/transpiler/output/codegen/helpers/ArrayAccessHelper.ts +6 -3
- package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +36 -22
- package/src/transpiler/output/codegen/helpers/FunctionContextManager.ts +9 -1
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayAccessHelper.test.ts +8 -6
- package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +34 -18
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +5 -2
- package/src/transpiler/state/CodeGenState.ts +6 -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/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.4",
|
|
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",
|
|
@@ -110764,6 +110764,8 @@ var CodeGenState = class {
|
|
|
110764
110764
|
static callbackTypes = /* @__PURE__ */ new Map();
|
|
110765
110765
|
/** Callback field types: "Struct.field" -> callbackTypeName */
|
|
110766
110766
|
static callbackFieldTypes = /* @__PURE__ */ new Map();
|
|
110767
|
+
/** Functions that need C-callback-compatible (by-value) struct parameters */
|
|
110768
|
+
static callbackCompatibleFunctions = /* @__PURE__ */ new Set();
|
|
110767
110769
|
// ===========================================================================
|
|
110768
110770
|
// PASS-BY-VALUE ANALYSIS (Issue #269)
|
|
110769
110771
|
// ===========================================================================
|
|
@@ -114074,14 +114076,14 @@ var TypeValidator = class _TypeValidator {
|
|
|
114074
114076
|
}
|
|
114075
114077
|
}
|
|
114076
114078
|
// ========================================================================
|
|
114077
|
-
//
|
|
114079
|
+
// Condition Boolean Validation (ADR-027, Issue #884)
|
|
114078
114080
|
// ========================================================================
|
|
114079
|
-
static
|
|
114081
|
+
static validateConditionIsBoolean(ctx, conditionType) {
|
|
114080
114082
|
const ternaryExpr = ctx.ternaryExpression();
|
|
114081
114083
|
const orExprs = ternaryExpr.orExpression();
|
|
114082
114084
|
if (orExprs.length !== 1) {
|
|
114083
114085
|
throw new Error(
|
|
114084
|
-
`Error E0701:
|
|
114086
|
+
`Error E0701: ${conditionType} condition must be a boolean expression, not a ternary (MISRA C:2012 Rule 14.4)`
|
|
114085
114087
|
);
|
|
114086
114088
|
}
|
|
114087
114089
|
const orExpr = orExprs[0];
|
|
@@ -114092,7 +114094,7 @@ var TypeValidator = class _TypeValidator {
|
|
|
114092
114094
|
const andExpr = orExpr.andExpression(0);
|
|
114093
114095
|
if (!andExpr) {
|
|
114094
114096
|
throw new Error(
|
|
114095
|
-
`Error E0701:
|
|
114097
|
+
`Error E0701: ${conditionType} condition must be a boolean expression (comparison or logical operation), not '${text}' (MISRA C:2012 Rule 14.4)`
|
|
114096
114098
|
);
|
|
114097
114099
|
}
|
|
114098
114100
|
if (andExpr.equalityExpression().length > 1) {
|
|
@@ -114101,7 +114103,7 @@ var TypeValidator = class _TypeValidator {
|
|
|
114101
114103
|
const equalityExpr = andExpr.equalityExpression(0);
|
|
114102
114104
|
if (!equalityExpr) {
|
|
114103
114105
|
throw new Error(
|
|
114104
|
-
`Error E0701:
|
|
114106
|
+
`Error E0701: ${conditionType} condition must be a boolean expression (comparison or logical operation), not '${text}' (MISRA C:2012 Rule 14.4)`
|
|
114105
114107
|
);
|
|
114106
114108
|
}
|
|
114107
114109
|
if (equalityExpr.relationalExpression().length > 1) {
|
|
@@ -114110,7 +114112,7 @@ var TypeValidator = class _TypeValidator {
|
|
|
114110
114112
|
const relationalExpr = equalityExpr.relationalExpression(0);
|
|
114111
114113
|
if (!relationalExpr) {
|
|
114112
114114
|
throw new Error(
|
|
114113
|
-
`Error E0701:
|
|
114115
|
+
`Error E0701: ${conditionType} condition must be a boolean expression (comparison or logical operation), not '${text}' (MISRA C:2012 Rule 14.4)`
|
|
114114
114116
|
);
|
|
114115
114117
|
}
|
|
114116
114118
|
if (relationalExpr.bitwiseOrExpression().length > 1) {
|
|
@@ -114121,7 +114123,7 @@ var TypeValidator = class _TypeValidator {
|
|
|
114121
114123
|
return;
|
|
114122
114124
|
}
|
|
114123
114125
|
throw new Error(
|
|
114124
|
-
`Error E0701:
|
|
114126
|
+
`Error E0701: ${conditionType} condition must be a boolean expression (comparison or logical operation), not '${text}' (MISRA C:2012 Rule 14.4)
|
|
114125
114127
|
help: use explicit comparison: ${text} > 0 or ${text} != 0`
|
|
114126
114128
|
);
|
|
114127
114129
|
}
|
|
@@ -116790,37 +116792,37 @@ var handleBitRangeSubscript = (ctx, exprs, input, state, orchestrator, effects,
|
|
|
116790
116792
|
}
|
|
116791
116793
|
return output;
|
|
116792
116794
|
};
|
|
116795
|
+
var getFloatTypeName = (baseType) => {
|
|
116796
|
+
return baseType === "f64" ? "double" : "float";
|
|
116797
|
+
};
|
|
116793
116798
|
var handleFloatBitRange = (ctx, state, orchestrator, effects) => {
|
|
116794
116799
|
if (!state.inFunctionBody) {
|
|
116795
116800
|
throw new Error(
|
|
116796
116801
|
`Float bit indexing reads (${ctx.rootIdentifier}[${ctx.start}, ${ctx.width}]) cannot be used at global scope.`
|
|
116797
116802
|
);
|
|
116798
116803
|
}
|
|
116799
|
-
effects.push(
|
|
116800
|
-
{ type: "include", header: "string" },
|
|
116801
|
-
{ type: "include", header: "float_static_assert" }
|
|
116802
|
-
);
|
|
116804
|
+
effects.push({ type: "include", header: "float_static_assert" });
|
|
116803
116805
|
const isF64 = ctx.baseType === "f64";
|
|
116804
|
-
const
|
|
116806
|
+
const floatType = getFloatTypeName(ctx.baseType);
|
|
116807
|
+
const intType = isF64 ? "uint64_t" : "uint32_t";
|
|
116805
116808
|
const shadowName = `__bits_${ctx.rootIdentifier}`;
|
|
116806
116809
|
const mask = orchestrator.generateBitMask(ctx.width, isF64);
|
|
116807
116810
|
const needsDeclaration = !orchestrator.hasFloatBitShadow(shadowName);
|
|
116808
116811
|
if (needsDeclaration) {
|
|
116809
116812
|
orchestrator.registerFloatBitShadow(shadowName);
|
|
116810
|
-
orchestrator.addPendingTempDeclaration(
|
|
116813
|
+
orchestrator.addPendingTempDeclaration(
|
|
116814
|
+
`union { ${floatType} f; ${intType} u; } ${shadowName};`
|
|
116815
|
+
);
|
|
116811
116816
|
}
|
|
116812
116817
|
const shadowIsCurrent = orchestrator.isFloatShadowCurrent(shadowName);
|
|
116813
116818
|
orchestrator.markFloatShadowCurrent(shadowName);
|
|
116814
|
-
if (shadowIsCurrent) {
|
|
116815
|
-
|
|
116816
|
-
return `(${shadowName} & ${mask})`;
|
|
116817
|
-
}
|
|
116818
|
-
return `((${shadowName} >> ${ctx.start}) & ${mask})`;
|
|
116819
|
+
if (!shadowIsCurrent) {
|
|
116820
|
+
orchestrator.addPendingTempDeclaration(`${shadowName}.f = ${ctx.result};`);
|
|
116819
116821
|
}
|
|
116820
116822
|
if (ctx.start === "0") {
|
|
116821
|
-
return `(
|
|
116823
|
+
return `(${shadowName}.u & ${mask})`;
|
|
116822
116824
|
}
|
|
116823
|
-
return `(
|
|
116825
|
+
return `((${shadowName}.u >> ${ctx.start}) & ${mask})`;
|
|
116824
116826
|
};
|
|
116825
116827
|
var applyAccessEffects = (sourceEffects, targetEffects) => {
|
|
116826
116828
|
for (const effect of sourceEffects) {
|
|
@@ -116940,6 +116942,7 @@ var generateIf = (node, _input, _state, orchestrator) => {
|
|
|
116940
116942
|
}
|
|
116941
116943
|
const cacheDecls = orchestrator.setupLengthCache(lengthCounts);
|
|
116942
116944
|
orchestrator.validateConditionNoFunctionCall(node.expression(), "if");
|
|
116945
|
+
orchestrator.validateConditionIsBoolean(node.expression(), "if");
|
|
116943
116946
|
const condition = orchestrator.generateExpression(node.expression());
|
|
116944
116947
|
const conditionTemps = orchestrator.flushPendingTempDeclarations();
|
|
116945
116948
|
const thenBranch = orchestrator.generateStatement(thenStmt);
|
|
@@ -116960,6 +116963,7 @@ var generateIf = (node, _input, _state, orchestrator) => {
|
|
|
116960
116963
|
var generateWhile = (node, _input, _state, orchestrator) => {
|
|
116961
116964
|
const effects = [];
|
|
116962
116965
|
orchestrator.validateConditionNoFunctionCall(node.expression(), "while");
|
|
116966
|
+
orchestrator.validateConditionIsBoolean(node.expression(), "while");
|
|
116963
116967
|
const condition = orchestrator.generateExpression(node.expression());
|
|
116964
116968
|
const conditionTemps = orchestrator.flushPendingTempDeclarations();
|
|
116965
116969
|
const body = orchestrator.generateStatement(node.statement());
|
|
@@ -116971,8 +116975,8 @@ var generateWhile = (node, _input, _state, orchestrator) => {
|
|
|
116971
116975
|
};
|
|
116972
116976
|
var generateDoWhile = (node, _input, _state, orchestrator) => {
|
|
116973
116977
|
const effects = [];
|
|
116974
|
-
orchestrator.validateDoWhileCondition(node.expression());
|
|
116975
116978
|
orchestrator.validateConditionNoFunctionCall(node.expression(), "do-while");
|
|
116979
|
+
orchestrator.validateConditionIsBoolean(node.expression(), "do-while");
|
|
116976
116980
|
const body = orchestrator.generateBlock(node.block());
|
|
116977
116981
|
const condition = orchestrator.generateExpression(node.expression());
|
|
116978
116982
|
const conditionTemps = orchestrator.flushPendingTempDeclarations();
|
|
@@ -117037,6 +117041,7 @@ var generateFor = (node, input, state, orchestrator) => {
|
|
|
117037
117041
|
let condition = "";
|
|
117038
117042
|
if (node.expression()) {
|
|
117039
117043
|
orchestrator.validateConditionNoFunctionCall(node.expression(), "for");
|
|
117044
|
+
orchestrator.validateConditionIsBoolean(node.expression(), "for");
|
|
117040
117045
|
condition = orchestrator.generateExpression(node.expression());
|
|
117041
117046
|
}
|
|
117042
117047
|
const conditionTemps = orchestrator.flushPendingTempDeclarations();
|
|
@@ -117370,6 +117375,12 @@ var generateSwitch = (node, input, state, orchestrator) => {
|
|
|
117370
117375
|
);
|
|
117371
117376
|
lines.push(defaultResult.code);
|
|
117372
117377
|
effects.push(...defaultResult.effects);
|
|
117378
|
+
} else {
|
|
117379
|
+
lines.push(
|
|
117380
|
+
orchestrator.indent("default: {"),
|
|
117381
|
+
orchestrator.indent(orchestrator.indent("break;")),
|
|
117382
|
+
orchestrator.indent("}")
|
|
117383
|
+
);
|
|
117373
117384
|
}
|
|
117374
117385
|
lines.push("}");
|
|
117375
117386
|
return { code: lines.join("\n"), effects };
|
|
@@ -122737,11 +122748,16 @@ var MemberChainAnalyzer = class _MemberChainAnalyzer {
|
|
|
122737
122748
|
var MemberChainAnalyzer_default = MemberChainAnalyzer;
|
|
122738
122749
|
|
|
122739
122750
|
// src/transpiler/output/codegen/helpers/FloatBitHelper.ts
|
|
122751
|
+
var getFloatTypeName2 = (baseType) => {
|
|
122752
|
+
return baseType === "f64" ? "double" : "float";
|
|
122753
|
+
};
|
|
122740
122754
|
var FloatBitHelper = class {
|
|
122741
122755
|
/**
|
|
122742
|
-
* Generate float bit write using
|
|
122756
|
+
* Generate float bit write using union-based type punning.
|
|
122743
122757
|
* Returns null if typeInfo is not a float type.
|
|
122744
122758
|
*
|
|
122759
|
+
* Uses union { float f; uint32_t u; } for MISRA 21.15 compliance instead of memcpy.
|
|
122760
|
+
*
|
|
122745
122761
|
* @param name - Variable name being written
|
|
122746
122762
|
* @param typeInfo - Type information for the variable
|
|
122747
122763
|
* @param bitIndex - Bit index expression (start position)
|
|
@@ -122755,10 +122771,10 @@ var FloatBitHelper = class {
|
|
|
122755
122771
|
if (!isFloatType) {
|
|
122756
122772
|
return null;
|
|
122757
122773
|
}
|
|
122758
|
-
callbacks.requireInclude("string");
|
|
122759
122774
|
callbacks.requireInclude("float_static_assert");
|
|
122760
122775
|
const isF64 = typeInfo.baseType === "f64";
|
|
122761
|
-
const
|
|
122776
|
+
const floatType = getFloatTypeName2(typeInfo.baseType);
|
|
122777
|
+
const intType = isF64 ? "uint64_t" : "uint32_t";
|
|
122762
122778
|
const shadowName = `__bits_${name}`;
|
|
122763
122779
|
const maskSuffix = isF64 ? "ULL" : "U";
|
|
122764
122780
|
const needsDeclaration = !CodeGenState.floatBitShadows.has(shadowName);
|
|
@@ -122766,14 +122782,18 @@ var FloatBitHelper = class {
|
|
|
122766
122782
|
CodeGenState.floatBitShadows.add(shadowName);
|
|
122767
122783
|
}
|
|
122768
122784
|
const shadowIsCurrent = CodeGenState.floatShadowCurrent.has(shadowName);
|
|
122769
|
-
const decl = needsDeclaration ?
|
|
122770
|
-
|
|
122785
|
+
const decl = needsDeclaration ? `union { ${floatType} f; ${intType} u; } ${shadowName};
|
|
122786
|
+
` : "";
|
|
122787
|
+
const readUnion = shadowIsCurrent ? "" : `${shadowName}.f = ${name};
|
|
122788
|
+
`;
|
|
122771
122789
|
CodeGenState.floatShadowCurrent.add(shadowName);
|
|
122772
122790
|
if (width === null) {
|
|
122773
|
-
return `${decl}${
|
|
122791
|
+
return `${decl}${readUnion}${shadowName}.u = (${shadowName}.u & ~(1${maskSuffix} << ${bitIndex})) | ((${intType})${callbacks.foldBooleanToInt(value)} << ${bitIndex});
|
|
122792
|
+
${name} = ${shadowName}.f;`;
|
|
122774
122793
|
} else {
|
|
122775
122794
|
const mask = callbacks.generateBitMask(width, isF64);
|
|
122776
|
-
return `${decl}${
|
|
122795
|
+
return `${decl}${readUnion}${shadowName}.u = (${shadowName}.u & ~(${mask} << ${bitIndex})) | (((${intType})${value} & ${mask}) << ${bitIndex});
|
|
122796
|
+
${name} = ${shadowName}.f;`;
|
|
122777
122797
|
}
|
|
122778
122798
|
}
|
|
122779
122799
|
};
|
|
@@ -125511,11 +125531,14 @@ var FunctionContextManager = class _FunctionContextManager {
|
|
|
125511
125531
|
typeCtx,
|
|
125512
125532
|
callbacks
|
|
125513
125533
|
);
|
|
125534
|
+
const isCallbackCompat = CodeGenState.currentFunctionName !== null && CodeGenState.callbackCompatibleFunctions.has(
|
|
125535
|
+
CodeGenState.currentFunctionName
|
|
125536
|
+
);
|
|
125514
125537
|
const paramInfo = {
|
|
125515
125538
|
name,
|
|
125516
125539
|
baseType: typeInfo.typeName,
|
|
125517
125540
|
isArray,
|
|
125518
|
-
isStruct: typeInfo.isStruct,
|
|
125541
|
+
isStruct: isCallbackCompat ? false : typeInfo.isStruct,
|
|
125519
125542
|
isConst,
|
|
125520
125543
|
isCallback: typeInfo.isCallback,
|
|
125521
125544
|
isString: typeInfo.isString
|
|
@@ -127546,11 +127569,11 @@ var CodeGenerator = class _CodeGenerator {
|
|
|
127546
127569
|
TypeValidator_default.validateSwitchStatement(ctx, switchExpr);
|
|
127547
127570
|
}
|
|
127548
127571
|
/**
|
|
127549
|
-
* Validate
|
|
127572
|
+
* Validate condition is a boolean expression (ADR-027, Issue #884).
|
|
127550
127573
|
* Part of IOrchestrator interface (ADR-053 A3).
|
|
127551
127574
|
*/
|
|
127552
|
-
|
|
127553
|
-
TypeValidator_default.
|
|
127575
|
+
validateConditionIsBoolean(ctx, conditionType) {
|
|
127576
|
+
TypeValidator_default.validateConditionIsBoolean(ctx, conditionType);
|
|
127554
127577
|
}
|
|
127555
127578
|
/**
|
|
127556
127579
|
* Issue #254: Validate no function calls in condition (E0702).
|
|
@@ -127936,8 +127959,8 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
127936
127959
|
}
|
|
127937
127960
|
/**
|
|
127938
127961
|
* Issue #561: Analyze modifications in a parse tree without full code generation.
|
|
127939
|
-
* Used by
|
|
127940
|
-
* for cross-file const inference
|
|
127962
|
+
* Used by the transpile() pipeline to collect modification info from includes
|
|
127963
|
+
* for cross-file const inference.
|
|
127941
127964
|
*
|
|
127942
127965
|
* Issue #565: Now accepts optional cross-file data for transitive propagation.
|
|
127943
127966
|
* When a file calls a function from an included file that modifies its param,
|
|
@@ -129318,6 +129341,9 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
129318
129341
|
return "{}";
|
|
129319
129342
|
}
|
|
129320
129343
|
const fieldInits = fields.map((f) => `.${f.fieldName} = ${f.value}`);
|
|
129344
|
+
if (CodeGenState.cppMode && (typeName.startsWith("struct {") || typeName.startsWith("union {"))) {
|
|
129345
|
+
return `{ ${fieldInits.join(", ")} }`;
|
|
129346
|
+
}
|
|
129321
129347
|
return `(${castType}){ ${fieldInits.join(", ")} }`;
|
|
129322
129348
|
}
|
|
129323
129349
|
/**
|
|
@@ -129501,6 +129527,11 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
129501
129527
|
)) {
|
|
129502
129528
|
return true;
|
|
129503
129529
|
}
|
|
129530
|
+
if (CodeGenState.currentFunctionName && CodeGenState.callbackCompatibleFunctions.has(
|
|
129531
|
+
CodeGenState.currentFunctionName
|
|
129532
|
+
) && this.isKnownStruct(typeName)) {
|
|
129533
|
+
return true;
|
|
129534
|
+
}
|
|
129504
129535
|
return false;
|
|
129505
129536
|
}
|
|
129506
129537
|
// ========================================================================
|
|
@@ -130713,8 +130744,11 @@ var HeaderGeneratorUtils = class _HeaderGeneratorUtils {
|
|
|
130713
130744
|
lines.push(include);
|
|
130714
130745
|
}
|
|
130715
130746
|
}
|
|
130747
|
+
const userIncludeSet = new Set(options.userIncludes ?? []);
|
|
130716
130748
|
for (const directive of headersToInclude) {
|
|
130717
|
-
|
|
130749
|
+
if (!userIncludeSet.has(directive)) {
|
|
130750
|
+
lines.push(directive);
|
|
130751
|
+
}
|
|
130718
130752
|
}
|
|
130719
130753
|
const hasIncludes = options.includeSystemHeaders !== false || options.userIncludes && options.userIncludes.length > 0 || headersToInclude.size > 0;
|
|
130720
130754
|
if (hasIncludes) {
|
|
@@ -132808,7 +132842,7 @@ var DeclaratorUtils = class _DeclaratorUtils {
|
|
|
132808
132842
|
if (identifier) {
|
|
132809
132843
|
parts.push(identifier.getText());
|
|
132810
132844
|
} else {
|
|
132811
|
-
parts.push(
|
|
132845
|
+
parts.push(_DeclaratorUtils.reconstructAnonymousStruct(structSpec));
|
|
132812
132846
|
}
|
|
132813
132847
|
} else {
|
|
132814
132848
|
parts.push(typeSpec.getText());
|
|
@@ -132822,6 +132856,74 @@ var DeclaratorUtils = class _DeclaratorUtils {
|
|
|
132822
132856
|
}
|
|
132823
132857
|
return parts.join(" ") || "int";
|
|
132824
132858
|
}
|
|
132859
|
+
/**
|
|
132860
|
+
* Reconstruct an anonymous struct/union type with proper spacing.
|
|
132861
|
+
* For `struct { unsigned int flag_a: 1; }`, returns the properly formatted string
|
|
132862
|
+
* instead of the concatenated tokens from getText().
|
|
132863
|
+
*/
|
|
132864
|
+
static reconstructAnonymousStruct(structSpec) {
|
|
132865
|
+
const structOrUnion = structSpec.structOrUnion();
|
|
132866
|
+
const keyword = structOrUnion.Struct() ? "struct" : "union";
|
|
132867
|
+
const declList = structSpec.structDeclarationList();
|
|
132868
|
+
if (!declList) {
|
|
132869
|
+
return `${keyword} { }`;
|
|
132870
|
+
}
|
|
132871
|
+
const fields = _DeclaratorUtils.reconstructStructFields(declList);
|
|
132872
|
+
return `${keyword} { ${fields} }`;
|
|
132873
|
+
}
|
|
132874
|
+
/**
|
|
132875
|
+
* Reconstruct struct fields with proper spacing.
|
|
132876
|
+
*/
|
|
132877
|
+
static reconstructStructFields(declList) {
|
|
132878
|
+
const fieldStrings = [];
|
|
132879
|
+
for (const decl of declList.structDeclaration()) {
|
|
132880
|
+
const fieldStr = _DeclaratorUtils.reconstructStructField(decl);
|
|
132881
|
+
if (fieldStr) {
|
|
132882
|
+
fieldStrings.push(fieldStr);
|
|
132883
|
+
}
|
|
132884
|
+
}
|
|
132885
|
+
return fieldStrings.join(" ");
|
|
132886
|
+
}
|
|
132887
|
+
/**
|
|
132888
|
+
* Reconstruct a single struct field declaration.
|
|
132889
|
+
*/
|
|
132890
|
+
static reconstructStructField(decl) {
|
|
132891
|
+
const specQualList = decl.specifierQualifierList();
|
|
132892
|
+
if (!specQualList) return null;
|
|
132893
|
+
const baseType = _DeclaratorUtils.extractTypeFromSpecQualList(specQualList);
|
|
132894
|
+
const declaratorList = decl.structDeclaratorList();
|
|
132895
|
+
if (!declaratorList) {
|
|
132896
|
+
return `${baseType};`;
|
|
132897
|
+
}
|
|
132898
|
+
const declarators = [];
|
|
132899
|
+
for (const structDecl of declaratorList.structDeclarator()) {
|
|
132900
|
+
const declStr = _DeclaratorUtils.reconstructStructDeclarator(structDecl);
|
|
132901
|
+
if (declStr) {
|
|
132902
|
+
declarators.push(declStr);
|
|
132903
|
+
}
|
|
132904
|
+
}
|
|
132905
|
+
if (declarators.length === 0) {
|
|
132906
|
+
return `${baseType};`;
|
|
132907
|
+
}
|
|
132908
|
+
return `${baseType} ${declarators.join(", ")};`;
|
|
132909
|
+
}
|
|
132910
|
+
/**
|
|
132911
|
+
* Reconstruct a struct declarator (field name with optional bitfield width).
|
|
132912
|
+
*/
|
|
132913
|
+
static reconstructStructDeclarator(structDecl) {
|
|
132914
|
+
const declarator = structDecl.declarator();
|
|
132915
|
+
const hasColon = structDecl.Colon() !== null;
|
|
132916
|
+
const constExpr = structDecl.constantExpression();
|
|
132917
|
+
let name = "";
|
|
132918
|
+
if (declarator) {
|
|
132919
|
+
name = _DeclaratorUtils.extractDeclaratorName(declarator) || "";
|
|
132920
|
+
}
|
|
132921
|
+
if (hasColon && constExpr) {
|
|
132922
|
+
const width = constExpr.getText();
|
|
132923
|
+
return `${name}: ${width}`;
|
|
132924
|
+
}
|
|
132925
|
+
return name || null;
|
|
132926
|
+
}
|
|
132825
132927
|
/**
|
|
132826
132928
|
* Extract typedef name from declaration specifiers.
|
|
132827
132929
|
* For "typedef struct { ... } AppConfig;", this returns "AppConfig".
|
|
@@ -133259,8 +133361,9 @@ var CResolver = class _CResolver {
|
|
|
133259
133361
|
if (!name) continue;
|
|
133260
133362
|
const isFunction = DeclaratorUtils_default.declaratorIsFunction(declarator);
|
|
133261
133363
|
if (ctx.isTypedef) {
|
|
133364
|
+
const typedefType = _CResolver.isFunctionPointerDeclarator(declarator) ? `${baseType} (*)(${_CResolver.extractParamText(declarator)})` : baseType;
|
|
133262
133365
|
ctx.symbols.push(
|
|
133263
|
-
TypedefCollector_default.collect(name,
|
|
133366
|
+
TypedefCollector_default.collect(name, typedefType, ctx.sourceFile, ctx.line)
|
|
133264
133367
|
);
|
|
133265
133368
|
} else if (isFunction) {
|
|
133266
133369
|
ctx.symbols.push(
|
|
@@ -133363,6 +133466,36 @@ var CResolver = class _CResolver {
|
|
|
133363
133466
|
}
|
|
133364
133467
|
return typeParts.join(" ") || "int";
|
|
133365
133468
|
}
|
|
133469
|
+
/**
|
|
133470
|
+
* Check if a declarator represents a function pointer.
|
|
133471
|
+
* For `(*PointCallback)(Point p)`, the C grammar parses as:
|
|
133472
|
+
* declarator -> directDeclarator
|
|
133473
|
+
* directDeclarator -> directDeclarator '(' parameterTypeList ')'
|
|
133474
|
+
* inner directDeclarator -> '(' declarator ')'
|
|
133475
|
+
* inner declarator -> pointer directDeclarator -> * PointCallback
|
|
133476
|
+
*/
|
|
133477
|
+
static isFunctionPointerDeclarator(declarator) {
|
|
133478
|
+
const directDecl = declarator.directDeclarator?.();
|
|
133479
|
+
if (!directDecl) return false;
|
|
133480
|
+
const hasParams = directDecl.parameterTypeList?.() !== null || Boolean(directDecl.LeftParen?.());
|
|
133481
|
+
if (!hasParams) return false;
|
|
133482
|
+
const innerDirectDecl = directDecl.directDeclarator?.();
|
|
133483
|
+
if (!innerDirectDecl) return false;
|
|
133484
|
+
const nestedDecl = innerDirectDecl.declarator?.();
|
|
133485
|
+
if (!nestedDecl) return false;
|
|
133486
|
+
return Boolean(nestedDecl.pointer?.());
|
|
133487
|
+
}
|
|
133488
|
+
/**
|
|
133489
|
+
* Extract parameter text from a function pointer declarator.
|
|
133490
|
+
* Returns the text of the parameters from a function pointer like "(*Callback)(Point p)".
|
|
133491
|
+
*/
|
|
133492
|
+
static extractParamText(declarator) {
|
|
133493
|
+
const directDecl = declarator.directDeclarator?.();
|
|
133494
|
+
if (!directDecl) return "";
|
|
133495
|
+
const paramTypeList = directDecl.parameterTypeList?.();
|
|
133496
|
+
if (!paramTypeList) return "";
|
|
133497
|
+
return paramTypeList.getText();
|
|
133498
|
+
}
|
|
133366
133499
|
};
|
|
133367
133500
|
var c_default = CResolver;
|
|
133368
133501
|
|
|
@@ -134992,6 +135125,9 @@ var IncludeResolver = class _IncludeResolver {
|
|
|
134992
135125
|
}
|
|
134993
135126
|
if (file.type === EFileType_default.CNext) {
|
|
134994
135127
|
result.cnextIncludes.push(file);
|
|
135128
|
+
const headerPath = includeInfo.path.replace(/\.cnx$|\.cnext$/, ".h");
|
|
135129
|
+
const directive = includeInfo.isLocal ? `#include "${headerPath}"` : `#include <${headerPath}>`;
|
|
135130
|
+
result.headerIncludeDirectives.set(absolutePath, directive);
|
|
134995
135131
|
}
|
|
134996
135132
|
}
|
|
134997
135133
|
/**
|
|
@@ -135129,8 +135265,8 @@ var IncludeResolver = class _IncludeResolver {
|
|
|
135129
135265
|
/**
|
|
135130
135266
|
* Build search paths from a source file location
|
|
135131
135267
|
*
|
|
135132
|
-
* Consolidates the search path building logic used by
|
|
135133
|
-
*
|
|
135268
|
+
* Consolidates the search path building logic used by the unified
|
|
135269
|
+
* transpile() entry point.
|
|
135134
135270
|
*
|
|
135135
135271
|
* Search order (highest to lowest priority):
|
|
135136
135272
|
* 1. Source file's directory (for relative includes)
|
|
@@ -136465,16 +136601,20 @@ var FunctionCallListener = class extends CNextListener {
|
|
|
136465
136601
|
// ========================================================================
|
|
136466
136602
|
// ISR/Callback Variable Tracking (ADR-040)
|
|
136467
136603
|
// ========================================================================
|
|
136604
|
+
/**
|
|
136605
|
+
* Check if a type name represents a callable type (ISR, callback, or C function pointer typedef).
|
|
136606
|
+
*/
|
|
136607
|
+
isCallableType(typeName) {
|
|
136608
|
+
return typeName === "ISR" || this.analyzer.isCallbackType(typeName) || this.analyzer.isCFunctionPointerTypedef(typeName);
|
|
136609
|
+
}
|
|
136468
136610
|
/**
|
|
136469
136611
|
* Track ISR-typed variables from variable declarations
|
|
136470
136612
|
* e.g., `ISR handler <- myFunction;`
|
|
136471
136613
|
*/
|
|
136472
136614
|
enterVariableDeclaration = (ctx) => {
|
|
136473
|
-
const
|
|
136474
|
-
|
|
136475
|
-
|
|
136476
|
-
const varName = ctx.IDENTIFIER().getText();
|
|
136477
|
-
this.analyzer.defineCallableVariable(varName);
|
|
136615
|
+
const typeName = ctx.type().getText();
|
|
136616
|
+
if (this.isCallableType(typeName)) {
|
|
136617
|
+
this.analyzer.defineCallableVariable(ctx.IDENTIFIER().getText());
|
|
136478
136618
|
}
|
|
136479
136619
|
};
|
|
136480
136620
|
/**
|
|
@@ -136482,11 +136622,9 @@ var FunctionCallListener = class extends CNextListener {
|
|
|
136482
136622
|
* e.g., `void execute(ISR handler) { handler(); }`
|
|
136483
136623
|
*/
|
|
136484
136624
|
enterParameter = (ctx) => {
|
|
136485
|
-
const
|
|
136486
|
-
|
|
136487
|
-
|
|
136488
|
-
const paramName = ctx.IDENTIFIER().getText();
|
|
136489
|
-
this.analyzer.defineCallableVariable(paramName);
|
|
136625
|
+
const typeName = ctx.type().getText();
|
|
136626
|
+
if (this.isCallableType(typeName)) {
|
|
136627
|
+
this.analyzer.defineCallableVariable(ctx.IDENTIFIER().getText());
|
|
136490
136628
|
}
|
|
136491
136629
|
};
|
|
136492
136630
|
// ========================================================================
|
|
@@ -136625,6 +136763,7 @@ var FunctionCallAnalyzer = class {
|
|
|
136625
136763
|
this.collectIncludes(tree);
|
|
136626
136764
|
this.collectCallbackTypes(tree);
|
|
136627
136765
|
this.collectAllLocalFunctions(tree);
|
|
136766
|
+
this.collectCallbackCompatibleFunctions(tree);
|
|
136628
136767
|
const listener = new FunctionCallListener(this);
|
|
136629
136768
|
ParseTreeWalker5.DEFAULT.walk(listener, tree);
|
|
136630
136769
|
return this.errors;
|
|
@@ -136708,6 +136847,120 @@ var FunctionCallAnalyzer = class {
|
|
|
136708
136847
|
isCallbackType(name) {
|
|
136709
136848
|
return this.callbackTypes.has(name);
|
|
136710
136849
|
}
|
|
136850
|
+
/**
|
|
136851
|
+
* Check if a type name is a C function pointer typedef.
|
|
136852
|
+
* Looks up the type in the symbol table and checks if it's a typedef
|
|
136853
|
+
* whose underlying type contains "(*)" indicating a function pointer.
|
|
136854
|
+
*/
|
|
136855
|
+
isCFunctionPointerTypedef(typeName) {
|
|
136856
|
+
if (!this.symbolTable) return false;
|
|
136857
|
+
const sym = this.symbolTable.getCSymbol(typeName);
|
|
136858
|
+
if (sym?.kind !== "type") return false;
|
|
136859
|
+
return "type" in sym && typeof sym.type === "string" && sym.type.includes("(*)");
|
|
136860
|
+
}
|
|
136861
|
+
/**
|
|
136862
|
+
* Detect functions assigned to C function pointer typedefs.
|
|
136863
|
+
* When `PointCallback cb <- my_handler;` is found and PointCallback
|
|
136864
|
+
* is a C function pointer typedef, mark my_handler as callback-compatible.
|
|
136865
|
+
*/
|
|
136866
|
+
collectCallbackCompatibleFunctions(tree) {
|
|
136867
|
+
for (const decl of tree.declaration()) {
|
|
136868
|
+
const funcDecl = decl.functionDeclaration();
|
|
136869
|
+
if (!funcDecl) continue;
|
|
136870
|
+
const block = funcDecl.block();
|
|
136871
|
+
if (!block) continue;
|
|
136872
|
+
this.scanBlockForCallbackAssignments(block);
|
|
136873
|
+
}
|
|
136874
|
+
}
|
|
136875
|
+
/**
|
|
136876
|
+
* Recursively scan all statements in a block for callback typedef assignments.
|
|
136877
|
+
*/
|
|
136878
|
+
scanBlockForCallbackAssignments(block) {
|
|
136879
|
+
for (const stmt of block.statement()) {
|
|
136880
|
+
this.scanStatementForCallbackAssignments(stmt);
|
|
136881
|
+
}
|
|
136882
|
+
}
|
|
136883
|
+
/**
|
|
136884
|
+
* Scan a single statement for callback typedef assignments,
|
|
136885
|
+
* recursing into nested blocks (if/while/for/do-while/switch/critical).
|
|
136886
|
+
*/
|
|
136887
|
+
scanStatementForCallbackAssignments(stmt) {
|
|
136888
|
+
const varDecl = stmt.variableDeclaration();
|
|
136889
|
+
if (varDecl) {
|
|
136890
|
+
this.checkVarDeclForCallbackAssignment(varDecl);
|
|
136891
|
+
return;
|
|
136892
|
+
}
|
|
136893
|
+
const ifStmt = stmt.ifStatement();
|
|
136894
|
+
if (ifStmt) {
|
|
136895
|
+
for (const child of ifStmt.statement()) {
|
|
136896
|
+
this.scanStatementForCallbackAssignments(child);
|
|
136897
|
+
}
|
|
136898
|
+
return;
|
|
136899
|
+
}
|
|
136900
|
+
const whileStmt = stmt.whileStatement();
|
|
136901
|
+
if (whileStmt) {
|
|
136902
|
+
this.scanStatementForCallbackAssignments(whileStmt.statement());
|
|
136903
|
+
return;
|
|
136904
|
+
}
|
|
136905
|
+
const forStmt = stmt.forStatement();
|
|
136906
|
+
if (forStmt) {
|
|
136907
|
+
this.scanStatementForCallbackAssignments(forStmt.statement());
|
|
136908
|
+
return;
|
|
136909
|
+
}
|
|
136910
|
+
const doWhileStmt = stmt.doWhileStatement();
|
|
136911
|
+
if (doWhileStmt) {
|
|
136912
|
+
this.scanBlockForCallbackAssignments(doWhileStmt.block());
|
|
136913
|
+
return;
|
|
136914
|
+
}
|
|
136915
|
+
const switchStmt = stmt.switchStatement();
|
|
136916
|
+
if (switchStmt) {
|
|
136917
|
+
for (const caseCtx of switchStmt.switchCase()) {
|
|
136918
|
+
this.scanBlockForCallbackAssignments(caseCtx.block());
|
|
136919
|
+
}
|
|
136920
|
+
const defaultCtx = switchStmt.defaultCase();
|
|
136921
|
+
if (defaultCtx) {
|
|
136922
|
+
this.scanBlockForCallbackAssignments(defaultCtx.block());
|
|
136923
|
+
}
|
|
136924
|
+
return;
|
|
136925
|
+
}
|
|
136926
|
+
const criticalStmt = stmt.criticalStatement();
|
|
136927
|
+
if (criticalStmt) {
|
|
136928
|
+
this.scanBlockForCallbackAssignments(criticalStmt.block());
|
|
136929
|
+
return;
|
|
136930
|
+
}
|
|
136931
|
+
const nestedBlock = stmt.block();
|
|
136932
|
+
if (nestedBlock) {
|
|
136933
|
+
this.scanBlockForCallbackAssignments(nestedBlock);
|
|
136934
|
+
}
|
|
136935
|
+
}
|
|
136936
|
+
/**
|
|
136937
|
+
* Check if a variable declaration assigns a function to a C callback typedef.
|
|
136938
|
+
*/
|
|
136939
|
+
checkVarDeclForCallbackAssignment(varDecl) {
|
|
136940
|
+
const typeName = varDecl.type().getText();
|
|
136941
|
+
if (!this.isCFunctionPointerTypedef(typeName)) return;
|
|
136942
|
+
const expr = varDecl.expression();
|
|
136943
|
+
if (!expr) return;
|
|
136944
|
+
const funcRef = this.extractFunctionReference(expr);
|
|
136945
|
+
if (!funcRef) return;
|
|
136946
|
+
const lookupName = funcRef.includes(".") ? funcRef.replace(".", "_") : funcRef;
|
|
136947
|
+
if (this.allLocalFunctions.has(lookupName)) {
|
|
136948
|
+
CodeGenState.callbackCompatibleFunctions.add(lookupName);
|
|
136949
|
+
}
|
|
136950
|
+
}
|
|
136951
|
+
/**
|
|
136952
|
+
* Extract a function reference from an expression context.
|
|
136953
|
+
* Matches bare identifiers (e.g., "my_handler") and qualified scope
|
|
136954
|
+
* names (e.g., "MyScope.handler").
|
|
136955
|
+
* Returns null if the expression is not a function reference.
|
|
136956
|
+
*/
|
|
136957
|
+
extractFunctionReference(expr) {
|
|
136958
|
+
const text = expr.getText();
|
|
136959
|
+
if (/^\w+(\.\w+)?$/.test(text)) {
|
|
136960
|
+
return text;
|
|
136961
|
+
}
|
|
136962
|
+
return null;
|
|
136963
|
+
}
|
|
136711
136964
|
/**
|
|
136712
136965
|
* ADR-040: Register a variable that holds a callable (ISR or callback)
|
|
136713
136966
|
*/
|
|
@@ -136961,6 +137214,26 @@ var TypeConstants = class {
|
|
|
136961
137214
|
"float",
|
|
136962
137215
|
"double"
|
|
136963
137216
|
];
|
|
137217
|
+
/**
|
|
137218
|
+
* Unsigned integer types valid as array/bit subscript indexes.
|
|
137219
|
+
*
|
|
137220
|
+
* Used by:
|
|
137221
|
+
* - ArrayIndexTypeAnalyzer: validating subscript index types
|
|
137222
|
+
*/
|
|
137223
|
+
static UNSIGNED_INDEX_TYPES = [
|
|
137224
|
+
"u8",
|
|
137225
|
+
"u16",
|
|
137226
|
+
"u32",
|
|
137227
|
+
"u64",
|
|
137228
|
+
"bool"
|
|
137229
|
+
];
|
|
137230
|
+
/**
|
|
137231
|
+
* Signed integer types (rejected as subscript indexes).
|
|
137232
|
+
*
|
|
137233
|
+
* Used by:
|
|
137234
|
+
* - ArrayIndexTypeAnalyzer: detecting signed integer subscript indexes
|
|
137235
|
+
*/
|
|
137236
|
+
static SIGNED_TYPES = ["i8", "i16", "i32", "i64"];
|
|
136964
137237
|
};
|
|
136965
137238
|
var TypeConstants_default = TypeConstants;
|
|
136966
137239
|
|
|
@@ -137078,6 +137351,212 @@ var FloatModuloAnalyzer = class {
|
|
|
137078
137351
|
};
|
|
137079
137352
|
var FloatModuloAnalyzer_default = FloatModuloAnalyzer;
|
|
137080
137353
|
|
|
137354
|
+
// src/transpiler/logic/analysis/ArrayIndexTypeAnalyzer.ts
|
|
137355
|
+
import { ParseTreeWalker as ParseTreeWalker8 } from "antlr4ng";
|
|
137356
|
+
var VariableTypeCollector = class extends CNextListener {
|
|
137357
|
+
varTypes = /* @__PURE__ */ new Map();
|
|
137358
|
+
getVarTypes() {
|
|
137359
|
+
return this.varTypes;
|
|
137360
|
+
}
|
|
137361
|
+
trackType(typeCtx, identifier) {
|
|
137362
|
+
if (!typeCtx || !identifier) return;
|
|
137363
|
+
this.varTypes.set(identifier.getText(), typeCtx.getText());
|
|
137364
|
+
}
|
|
137365
|
+
enterVariableDeclaration = (ctx) => {
|
|
137366
|
+
this.trackType(ctx.type(), ctx.IDENTIFIER());
|
|
137367
|
+
};
|
|
137368
|
+
enterParameter = (ctx) => {
|
|
137369
|
+
this.trackType(ctx.type(), ctx.IDENTIFIER());
|
|
137370
|
+
};
|
|
137371
|
+
enterForVarDecl = (ctx) => {
|
|
137372
|
+
this.trackType(ctx.type(), ctx.IDENTIFIER());
|
|
137373
|
+
};
|
|
137374
|
+
};
|
|
137375
|
+
var IndexTypeListener = class extends CNextListener {
|
|
137376
|
+
analyzer;
|
|
137377
|
+
// eslint-disable-next-line @typescript-eslint/lines-between-class-members
|
|
137378
|
+
varTypes;
|
|
137379
|
+
constructor(analyzer, varTypes) {
|
|
137380
|
+
super();
|
|
137381
|
+
this.analyzer = analyzer;
|
|
137382
|
+
this.varTypes = varTypes;
|
|
137383
|
+
}
|
|
137384
|
+
/**
|
|
137385
|
+
* Check postfix operations in expressions (RHS: arr[idx], flags[bit])
|
|
137386
|
+
*/
|
|
137387
|
+
enterPostfixOp = (ctx) => {
|
|
137388
|
+
if (!ctx.LBRACKET()) return;
|
|
137389
|
+
const expressions = ctx.expression();
|
|
137390
|
+
for (const expr of expressions) {
|
|
137391
|
+
this.validateIndexExpression(expr);
|
|
137392
|
+
}
|
|
137393
|
+
};
|
|
137394
|
+
/**
|
|
137395
|
+
* Check postfix target operations in assignments (LHS: arr[idx] <- val)
|
|
137396
|
+
*/
|
|
137397
|
+
enterPostfixTargetOp = (ctx) => {
|
|
137398
|
+
if (!ctx.LBRACKET()) return;
|
|
137399
|
+
const expressions = ctx.expression();
|
|
137400
|
+
for (const expr of expressions) {
|
|
137401
|
+
this.validateIndexExpression(expr);
|
|
137402
|
+
}
|
|
137403
|
+
};
|
|
137404
|
+
/**
|
|
137405
|
+
* Validate that a subscript index expression uses an unsigned integer type.
|
|
137406
|
+
* Collects all leaf operands from the expression and checks each one.
|
|
137407
|
+
*/
|
|
137408
|
+
validateIndexExpression(ctx) {
|
|
137409
|
+
const operands = this.collectOperands(ctx);
|
|
137410
|
+
for (const operand of operands) {
|
|
137411
|
+
const resolvedType = this.resolveOperandType(operand);
|
|
137412
|
+
if (!resolvedType) continue;
|
|
137413
|
+
if (TypeConstants_default.SIGNED_TYPES.includes(resolvedType)) {
|
|
137414
|
+
const { line: line2, column: column2 } = ParserUtils_default.getPosition(ctx);
|
|
137415
|
+
this.analyzer.addError(line2, column2, "E0850", resolvedType);
|
|
137416
|
+
return;
|
|
137417
|
+
}
|
|
137418
|
+
if (resolvedType === "float literal" || TypeConstants_default.FLOAT_TYPES.includes(resolvedType)) {
|
|
137419
|
+
const { line: line2, column: column2 } = ParserUtils_default.getPosition(ctx);
|
|
137420
|
+
this.analyzer.addError(line2, column2, "E0851", resolvedType);
|
|
137421
|
+
return;
|
|
137422
|
+
}
|
|
137423
|
+
if (TypeConstants_default.UNSIGNED_INDEX_TYPES.includes(resolvedType)) {
|
|
137424
|
+
continue;
|
|
137425
|
+
}
|
|
137426
|
+
const { line, column } = ParserUtils_default.getPosition(ctx);
|
|
137427
|
+
this.analyzer.addError(line, column, "E0852", resolvedType);
|
|
137428
|
+
return;
|
|
137429
|
+
}
|
|
137430
|
+
}
|
|
137431
|
+
/**
|
|
137432
|
+
* Collect all leaf unary expression operands from an expression tree.
|
|
137433
|
+
* Handles binary operators at any level by flatMapping through the grammar hierarchy.
|
|
137434
|
+
*/
|
|
137435
|
+
collectOperands(ctx) {
|
|
137436
|
+
const ternary = ctx.ternaryExpression();
|
|
137437
|
+
if (!ternary) return [];
|
|
137438
|
+
const orExpressions = ternary.orExpression();
|
|
137439
|
+
if (orExpressions.length === 0) return [];
|
|
137440
|
+
const valueExpressions = orExpressions.length === 3 ? orExpressions.slice(1) : orExpressions;
|
|
137441
|
+
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());
|
|
137442
|
+
}
|
|
137443
|
+
/**
|
|
137444
|
+
* Resolve the type of a unary expression operand.
|
|
137445
|
+
* Uses local varTypes first, then falls back to CodeGenState for
|
|
137446
|
+
* struct fields, function return types, and enum detection.
|
|
137447
|
+
*
|
|
137448
|
+
* Returns null if the type cannot be resolved (pass-through).
|
|
137449
|
+
*/
|
|
137450
|
+
resolveOperandType(operand) {
|
|
137451
|
+
const postfixExpr = operand.postfixExpression();
|
|
137452
|
+
if (!postfixExpr) return null;
|
|
137453
|
+
const primaryExpr = postfixExpr.primaryExpression();
|
|
137454
|
+
if (!primaryExpr) return null;
|
|
137455
|
+
let currentType = this.resolveBaseType(primaryExpr);
|
|
137456
|
+
const postfixOps = postfixExpr.postfixOp();
|
|
137457
|
+
if (!currentType && postfixOps.length > 0) {
|
|
137458
|
+
const identifier = primaryExpr.IDENTIFIER();
|
|
137459
|
+
if (identifier) {
|
|
137460
|
+
currentType = identifier.getText();
|
|
137461
|
+
}
|
|
137462
|
+
}
|
|
137463
|
+
for (const op of postfixOps) {
|
|
137464
|
+
if (!currentType) return null;
|
|
137465
|
+
currentType = this.resolvePostfixOpType(currentType, op);
|
|
137466
|
+
}
|
|
137467
|
+
return currentType;
|
|
137468
|
+
}
|
|
137469
|
+
/**
|
|
137470
|
+
* Resolve the base type of a primary expression.
|
|
137471
|
+
*/
|
|
137472
|
+
resolveBaseType(primaryExpr) {
|
|
137473
|
+
const literal = primaryExpr.literal();
|
|
137474
|
+
if (literal) {
|
|
137475
|
+
if (LiteralUtils_default.isFloat(literal)) return "float literal";
|
|
137476
|
+
return null;
|
|
137477
|
+
}
|
|
137478
|
+
const parenExpr = primaryExpr.expression();
|
|
137479
|
+
if (parenExpr) {
|
|
137480
|
+
const innerOperands = this.collectOperands(parenExpr);
|
|
137481
|
+
for (const innerOp of innerOperands) {
|
|
137482
|
+
const innerType = this.resolveOperandType(innerOp);
|
|
137483
|
+
if (innerType) return innerType;
|
|
137484
|
+
}
|
|
137485
|
+
return null;
|
|
137486
|
+
}
|
|
137487
|
+
const identifier = primaryExpr.IDENTIFIER();
|
|
137488
|
+
if (!identifier) return null;
|
|
137489
|
+
const varName = identifier.getText();
|
|
137490
|
+
const localType = this.varTypes.get(varName);
|
|
137491
|
+
if (localType) return localType;
|
|
137492
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(varName);
|
|
137493
|
+
if (typeInfo) return typeInfo.baseType;
|
|
137494
|
+
return null;
|
|
137495
|
+
}
|
|
137496
|
+
/**
|
|
137497
|
+
* Resolve the resulting type after applying a postfix operator.
|
|
137498
|
+
*/
|
|
137499
|
+
resolvePostfixOpType(currentType, op) {
|
|
137500
|
+
if (op.DOT()) {
|
|
137501
|
+
const fieldId = op.IDENTIFIER();
|
|
137502
|
+
if (!fieldId) return null;
|
|
137503
|
+
const fieldName = fieldId.getText();
|
|
137504
|
+
if (CodeGenState.isKnownEnum(currentType)) return null;
|
|
137505
|
+
const fieldType = CodeGenState.getStructFieldType(currentType, fieldName);
|
|
137506
|
+
return fieldType ?? null;
|
|
137507
|
+
}
|
|
137508
|
+
if (op.LBRACKET()) {
|
|
137509
|
+
if (TypeConstants_default.UNSIGNED_INDEX_TYPES.includes(currentType)) {
|
|
137510
|
+
return "bool";
|
|
137511
|
+
}
|
|
137512
|
+
if (TypeConstants_default.SIGNED_TYPES.includes(currentType)) {
|
|
137513
|
+
return "bool";
|
|
137514
|
+
}
|
|
137515
|
+
return currentType;
|
|
137516
|
+
}
|
|
137517
|
+
if (op.LPAREN()) {
|
|
137518
|
+
const returnType = CodeGenState.getFunctionReturnType(currentType);
|
|
137519
|
+
return returnType ?? null;
|
|
137520
|
+
}
|
|
137521
|
+
return null;
|
|
137522
|
+
}
|
|
137523
|
+
};
|
|
137524
|
+
var ArrayIndexTypeAnalyzer = class {
|
|
137525
|
+
errors = [];
|
|
137526
|
+
/**
|
|
137527
|
+
* Analyze the parse tree for invalid subscript index types
|
|
137528
|
+
*/
|
|
137529
|
+
analyze(tree) {
|
|
137530
|
+
this.errors = [];
|
|
137531
|
+
const collector = new VariableTypeCollector();
|
|
137532
|
+
ParseTreeWalker8.DEFAULT.walk(collector, tree);
|
|
137533
|
+
const varTypes = collector.getVarTypes();
|
|
137534
|
+
const listener = new IndexTypeListener(this, varTypes);
|
|
137535
|
+
ParseTreeWalker8.DEFAULT.walk(listener, tree);
|
|
137536
|
+
return this.errors;
|
|
137537
|
+
}
|
|
137538
|
+
/**
|
|
137539
|
+
* Add an index type error
|
|
137540
|
+
*/
|
|
137541
|
+
addError(line, column, code, actualType) {
|
|
137542
|
+
this.errors.push({
|
|
137543
|
+
code,
|
|
137544
|
+
line,
|
|
137545
|
+
column,
|
|
137546
|
+
actualType,
|
|
137547
|
+
message: `Subscript index must be an unsigned integer type; got '${actualType}'`,
|
|
137548
|
+
helpText: "Use an unsigned integer type (u8, u16, u32, u64) for array and bit subscript indexes."
|
|
137549
|
+
});
|
|
137550
|
+
}
|
|
137551
|
+
/**
|
|
137552
|
+
* Get all detected errors
|
|
137553
|
+
*/
|
|
137554
|
+
getErrors() {
|
|
137555
|
+
return this.errors;
|
|
137556
|
+
}
|
|
137557
|
+
};
|
|
137558
|
+
var ArrayIndexTypeAnalyzer_default = ArrayIndexTypeAnalyzer;
|
|
137559
|
+
|
|
137081
137560
|
// src/transpiler/logic/analysis/runAnalyzers.ts
|
|
137082
137561
|
function collectErrors(analyzerErrors, target, formatMessage) {
|
|
137083
137562
|
const formatter = formatMessage ?? ((e) => e.message);
|
|
@@ -137131,6 +137610,10 @@ function runAnalyzers(tree, tokenStream, options) {
|
|
|
137131
137610
|
if (collectErrors(floatModAnalyzer.analyze(tree), errors, formatWithCode)) {
|
|
137132
137611
|
return errors;
|
|
137133
137612
|
}
|
|
137613
|
+
const indexTypeAnalyzer = new ArrayIndexTypeAnalyzer_default();
|
|
137614
|
+
if (collectErrors(indexTypeAnalyzer.analyze(tree), errors, formatWithCode)) {
|
|
137615
|
+
return errors;
|
|
137616
|
+
}
|
|
137134
137617
|
const commentExtractor = new CommentExtractor_default(tokenStream);
|
|
137135
137618
|
collectErrors(
|
|
137136
137619
|
commentExtractor.validate(),
|
|
@@ -137738,7 +138221,7 @@ var TransitiveEnumCollector = class {
|
|
|
137738
138221
|
/**
|
|
137739
138222
|
* Collect symbol info for standalone mode from resolved includes.
|
|
137740
138223
|
*
|
|
137741
|
-
* Issue #591: Extracted
|
|
138224
|
+
* Issue #591: Extracted to unify enum collection across transpilation modes.
|
|
137742
138225
|
* Unlike collect() which starts from a file path and parses it, this method
|
|
137743
138226
|
* starts from already-resolved includes (from IncludeResolver.resolve()).
|
|
137744
138227
|
*
|
|
@@ -137816,83 +138299,53 @@ var Transpiler = class {
|
|
|
137816
138299
|
this.cacheManager = projectRoot ? new CacheManager_default(projectRoot, this.fs) : null;
|
|
137817
138300
|
}
|
|
137818
138301
|
// ===========================================================================
|
|
137819
|
-
// Public API
|
|
138302
|
+
// Public API
|
|
137820
138303
|
// ===========================================================================
|
|
137821
138304
|
/**
|
|
137822
|
-
*
|
|
138305
|
+
* Unified entry point for all transpilation.
|
|
137823
138306
|
*
|
|
137824
|
-
*
|
|
138307
|
+
* @param input - What to transpile:
|
|
138308
|
+
* - { kind: 'files' } — discover from config.inputs, write to disk
|
|
138309
|
+
* - { kind: 'source', source, ... } — transpile in-memory source
|
|
138310
|
+
* @returns ITranspilerResult with per-file results in .files[]
|
|
137825
138311
|
*/
|
|
137826
|
-
async
|
|
138312
|
+
async transpile(input) {
|
|
137827
138313
|
const result = this._initResult();
|
|
137828
138314
|
try {
|
|
137829
138315
|
await this._initializeRun();
|
|
137830
|
-
const
|
|
137831
|
-
if (cnextFiles.length === 0) {
|
|
138316
|
+
const pipelineInput = await this.discoverIncludes(input);
|
|
138317
|
+
if (pipelineInput.cnextFiles.length === 0) {
|
|
137832
138318
|
return this._finalizeResult(result, "No C-Next source files found");
|
|
137833
138319
|
}
|
|
137834
|
-
|
|
137835
|
-
|
|
137836
|
-
|
|
137837
|
-
|
|
137838
|
-
}));
|
|
137839
|
-
const input = {
|
|
137840
|
-
cnextFiles: pipelineFiles,
|
|
137841
|
-
headerFiles,
|
|
137842
|
-
writeOutputToDisk: true
|
|
137843
|
-
};
|
|
137844
|
-
await this._executePipeline(input, result);
|
|
138320
|
+
if (input.kind === "files") {
|
|
138321
|
+
this._ensureOutputDirectories();
|
|
138322
|
+
}
|
|
138323
|
+
await this._executePipeline(pipelineInput, result);
|
|
137845
138324
|
return await this._finalizeResult(result);
|
|
137846
138325
|
} catch (err) {
|
|
137847
138326
|
return this._handleRunError(result, err);
|
|
137848
138327
|
}
|
|
137849
138328
|
}
|
|
137850
138329
|
/**
|
|
137851
|
-
*
|
|
138330
|
+
* Stage 1: Discover files and build pipeline input.
|
|
137852
138331
|
*
|
|
137853
|
-
*
|
|
137854
|
-
*
|
|
138332
|
+
* Branches on input kind:
|
|
138333
|
+
* - 'files': filesystem scan, dependency graph, topological sort
|
|
138334
|
+
* - 'source': parse in-memory string, walk include tree
|
|
137855
138335
|
*
|
|
137856
|
-
*
|
|
137857
|
-
*
|
|
137858
|
-
|
|
137859
|
-
|
|
137860
|
-
|
|
137861
|
-
|
|
137862
|
-
|
|
137863
|
-
|
|
137864
|
-
|
|
137865
|
-
|
|
137866
|
-
|
|
137867
|
-
|
|
137868
|
-
|
|
137869
|
-
additionalIncludeDirs,
|
|
137870
|
-
sourcePath
|
|
137871
|
-
);
|
|
137872
|
-
const result = this._initResult();
|
|
137873
|
-
await this._executePipeline(input, result);
|
|
137874
|
-
const fileResult = result.files.find((f) => f.sourcePath === sourcePath);
|
|
137875
|
-
if (fileResult) {
|
|
137876
|
-
return fileResult;
|
|
137877
|
-
}
|
|
137878
|
-
if (result.errors.length > 0) {
|
|
137879
|
-
return this.buildErrorResult(sourcePath, result.errors, 0);
|
|
137880
|
-
}
|
|
137881
|
-
return this.buildErrorResult(
|
|
137882
|
-
sourcePath,
|
|
137883
|
-
[
|
|
137884
|
-
{
|
|
137885
|
-
line: 1,
|
|
137886
|
-
column: 0,
|
|
137887
|
-
message: "Pipeline produced no result for source file",
|
|
137888
|
-
severity: "error"
|
|
137889
|
-
}
|
|
137890
|
-
],
|
|
137891
|
-
0
|
|
137892
|
-
);
|
|
137893
|
-
} catch (err) {
|
|
137894
|
-
return this.buildCatchResult(sourcePath, err);
|
|
137895
|
-
}
|
|
138336
|
+
* Header directive storage happens via IncludeResolver.resolve() for both
|
|
138337
|
+
* C headers and cnext includes (Issue #854).
|
|
138338
|
+
*/
|
|
138339
|
+
async discoverIncludes(input) {
|
|
138340
|
+
if (input.kind === "files") {
|
|
138341
|
+
return this._discoverFromFiles();
|
|
138342
|
+
}
|
|
138343
|
+
return this._discoverFromSource(
|
|
138344
|
+
input.source,
|
|
138345
|
+
input.workingDir ?? process.cwd(),
|
|
138346
|
+
input.includeDirs ?? [],
|
|
138347
|
+
input.sourcePath ?? "<string>"
|
|
138348
|
+
);
|
|
137896
138349
|
}
|
|
137897
138350
|
// ===========================================================================
|
|
137898
138351
|
// Unified Pipeline
|
|
@@ -137900,7 +138353,7 @@ var Transpiler = class {
|
|
|
137900
138353
|
/**
|
|
137901
138354
|
* The single unified pipeline for all transpilation.
|
|
137902
138355
|
*
|
|
137903
|
-
*
|
|
138356
|
+
* transpile() delegates here after file discovery via discoverIncludes().
|
|
137904
138357
|
*
|
|
137905
138358
|
* Stage 2: Collect symbols from C/C++ headers (includes building analyzer context)
|
|
137906
138359
|
* Stage 3: Collect symbols from C-Next files
|
|
@@ -138007,14 +138460,6 @@ var Transpiler = class {
|
|
|
138007
138460
|
if (this.config.parseOnly) {
|
|
138008
138461
|
return this.buildParseOnlyResult(sourcePath, declarationCount);
|
|
138009
138462
|
}
|
|
138010
|
-
const analyzerErrors = runAnalyzers_default(tree, tokenStream);
|
|
138011
|
-
if (analyzerErrors.length > 0) {
|
|
138012
|
-
return this.buildErrorResult(
|
|
138013
|
-
sourcePath,
|
|
138014
|
-
analyzerErrors,
|
|
138015
|
-
declarationCount
|
|
138016
|
-
);
|
|
138017
|
-
}
|
|
138018
138463
|
const tSymbols = cnext_default.resolve(tree, sourcePath);
|
|
138019
138464
|
let symbolInfo = TSymbolInfoAdapter_default.convert(tSymbols);
|
|
138020
138465
|
const externalEnumSources = this._collectExternalEnumSources(
|
|
@@ -138027,6 +138472,15 @@ var Transpiler = class {
|
|
|
138027
138472
|
externalEnumSources
|
|
138028
138473
|
);
|
|
138029
138474
|
}
|
|
138475
|
+
CodeGenState.symbols = symbolInfo;
|
|
138476
|
+
const analyzerErrors = runAnalyzers_default(tree, tokenStream);
|
|
138477
|
+
if (analyzerErrors.length > 0) {
|
|
138478
|
+
return this.buildErrorResult(
|
|
138479
|
+
sourcePath,
|
|
138480
|
+
analyzerErrors,
|
|
138481
|
+
declarationCount
|
|
138482
|
+
);
|
|
138483
|
+
}
|
|
138030
138484
|
this._setupCrossFileModifications();
|
|
138031
138485
|
const code = this.codeGenerator.generate(tree, tokenStream, {
|
|
138032
138486
|
debugMode: this.config.debugMode,
|
|
@@ -138044,15 +138498,7 @@ var Transpiler = class {
|
|
|
138044
138498
|
if (this.cppDetected) {
|
|
138045
138499
|
this._accumulateFileModifications();
|
|
138046
138500
|
}
|
|
138047
|
-
const
|
|
138048
|
-
const headerCode = this.generateHeaderContent(
|
|
138049
|
-
fileSymbols,
|
|
138050
|
-
sourcePath,
|
|
138051
|
-
this.cppDetected,
|
|
138052
|
-
userIncludes,
|
|
138053
|
-
passByValueCopy,
|
|
138054
|
-
symbolInfo
|
|
138055
|
-
);
|
|
138501
|
+
const headerCode = this.generateHeaderForFile(file) ?? void 0;
|
|
138056
138502
|
return this.buildSuccessResult(
|
|
138057
138503
|
sourcePath,
|
|
138058
138504
|
code,
|
|
@@ -138117,6 +138563,13 @@ var Transpiler = class {
|
|
|
138117
138563
|
this.state.setHeaderDirective(header.path, directive);
|
|
138118
138564
|
}
|
|
138119
138565
|
}
|
|
138566
|
+
for (const cnxInclude of resolved.cnextIncludes) {
|
|
138567
|
+
const includePath = resolve12(cnxInclude.path);
|
|
138568
|
+
const directive = resolved.headerIncludeDirectives.get(includePath);
|
|
138569
|
+
if (directive) {
|
|
138570
|
+
this.state.setHeaderDirective(includePath, directive);
|
|
138571
|
+
}
|
|
138572
|
+
}
|
|
138120
138573
|
const cnextIncludeFiles = [];
|
|
138121
138574
|
IncludeTreeWalker_default.walk(
|
|
138122
138575
|
resolved.cnextIncludes,
|
|
@@ -138174,6 +138627,7 @@ var Transpiler = class {
|
|
|
138174
138627
|
this.state.reset();
|
|
138175
138628
|
CodeGenState.symbolTable.clear();
|
|
138176
138629
|
SymbolRegistry_default.reset();
|
|
138630
|
+
CodeGenState.callbackCompatibleFunctions = /* @__PURE__ */ new Set();
|
|
138177
138631
|
}
|
|
138178
138632
|
/**
|
|
138179
138633
|
* Ensure output directories exist
|
|
@@ -138252,8 +138706,12 @@ var Transpiler = class {
|
|
|
138252
138706
|
if (file.symbolOnly) {
|
|
138253
138707
|
continue;
|
|
138254
138708
|
}
|
|
138255
|
-
const
|
|
138256
|
-
if (
|
|
138709
|
+
const headerContent = this.generateHeaderForFile(file);
|
|
138710
|
+
if (headerContent) {
|
|
138711
|
+
const headerPath = this.pathResolver.getHeaderOutputPath(
|
|
138712
|
+
file.discoveredFile
|
|
138713
|
+
);
|
|
138714
|
+
this.fs.writeFile(headerPath, headerContent);
|
|
138257
138715
|
result.outputFiles.push(headerPath);
|
|
138258
138716
|
}
|
|
138259
138717
|
}
|
|
@@ -138287,7 +138745,7 @@ var Transpiler = class {
|
|
|
138287
138745
|
return result;
|
|
138288
138746
|
}
|
|
138289
138747
|
// ===========================================================================
|
|
138290
|
-
//
|
|
138748
|
+
// File Discovery (Stage 1 for files mode)
|
|
138291
138749
|
// ===========================================================================
|
|
138292
138750
|
/**
|
|
138293
138751
|
* Discover C-Next files from a single input (file or directory).
|
|
@@ -138348,6 +138806,10 @@ var Transpiler = class {
|
|
|
138348
138806
|
""
|
|
138349
138807
|
);
|
|
138350
138808
|
depGraph.addDependency(cnxPath, includePath);
|
|
138809
|
+
const directive = resolved.headerIncludeDirectives.get(includePath);
|
|
138810
|
+
if (directive) {
|
|
138811
|
+
this.state.setHeaderDirective(includePath, directive);
|
|
138812
|
+
}
|
|
138351
138813
|
const alreadyExists = cnextBaseNames.has(includeBaseName) || cnextFiles.some((f) => resolve12(f.path) === includePath);
|
|
138352
138814
|
if (!alreadyExists) {
|
|
138353
138815
|
cnextFiles.push(cnxInclude);
|
|
@@ -138411,14 +138873,14 @@ var Transpiler = class {
|
|
|
138411
138873
|
* This ensures headers are found based on what the source actually
|
|
138412
138874
|
* includes, not by blindly scanning include directories.
|
|
138413
138875
|
*/
|
|
138414
|
-
async
|
|
138876
|
+
async _discoverFromFiles() {
|
|
138415
138877
|
const cnextFiles = [];
|
|
138416
138878
|
const fileByPath = /* @__PURE__ */ new Map();
|
|
138417
138879
|
for (const input of this.config.inputs) {
|
|
138418
138880
|
this._discoverCNextFromInput(input, cnextFiles, fileByPath);
|
|
138419
138881
|
}
|
|
138420
138882
|
if (cnextFiles.length === 0) {
|
|
138421
|
-
return { cnextFiles: [], headerFiles: [] };
|
|
138883
|
+
return { cnextFiles: [], headerFiles: [], writeOutputToDisk: true };
|
|
138422
138884
|
}
|
|
138423
138885
|
const headerSet = /* @__PURE__ */ new Map();
|
|
138424
138886
|
const depGraph = new DependencyGraph_default();
|
|
@@ -138446,9 +138908,14 @@ var Transpiler = class {
|
|
|
138446
138908
|
}
|
|
138447
138909
|
);
|
|
138448
138910
|
this.warnings.push(...headerWarnings);
|
|
138911
|
+
const pipelineFiles = sortedCnextFiles.map((f) => ({
|
|
138912
|
+
path: f.path,
|
|
138913
|
+
discoveredFile: f
|
|
138914
|
+
}));
|
|
138449
138915
|
return {
|
|
138450
|
-
cnextFiles:
|
|
138451
|
-
headerFiles: allHeaders
|
|
138916
|
+
cnextFiles: pipelineFiles,
|
|
138917
|
+
headerFiles: allHeaders,
|
|
138918
|
+
writeOutputToDisk: true
|
|
138452
138919
|
};
|
|
138453
138920
|
}
|
|
138454
138921
|
// ===========================================================================
|
|
@@ -138633,17 +139100,22 @@ var Transpiler = class {
|
|
|
138633
139100
|
* Stage 6: Generate header file for a C-Next file
|
|
138634
139101
|
* ADR-055 Phase 7: Uses TSymbol directly, converts to IHeaderSymbol for generation.
|
|
138635
139102
|
*/
|
|
138636
|
-
|
|
138637
|
-
|
|
139103
|
+
/**
|
|
139104
|
+
* Generate header content for a single file's exported symbols.
|
|
139105
|
+
* Unified method replacing both generateHeader() and generateHeaderContent().
|
|
139106
|
+
* Reads all needed data from state (populated during Stage 5).
|
|
139107
|
+
*/
|
|
139108
|
+
generateHeaderForFile(file) {
|
|
139109
|
+
const sourcePath = file.path;
|
|
139110
|
+
const tSymbols = CodeGenState.symbolTable.getTSymbolsByFile(sourcePath);
|
|
138638
139111
|
const exportedSymbols = tSymbols.filter((s) => s.isExported);
|
|
138639
139112
|
if (exportedSymbols.length === 0) {
|
|
138640
139113
|
return null;
|
|
138641
139114
|
}
|
|
138642
|
-
const headerName = basename5(
|
|
138643
|
-
const
|
|
138644
|
-
const
|
|
138645
|
-
const
|
|
138646
|
-
const userIncludes = this.state.getUserIncludes(file.path);
|
|
139115
|
+
const headerName = basename5(sourcePath).replace(/\.cnx$|\.cnext$/, ".h");
|
|
139116
|
+
const typeInput = this.state.getSymbolInfo(sourcePath);
|
|
139117
|
+
const passByValueParams = this.state.getPassByValueParams(sourcePath) ?? /* @__PURE__ */ new Map();
|
|
139118
|
+
const userIncludes = this.state.getUserIncludes(sourcePath);
|
|
138647
139119
|
const allKnownEnums = TransitiveEnumCollector_default.aggregateKnownEnums(
|
|
138648
139120
|
this.state.getAllSymbolInfo()
|
|
138649
139121
|
);
|
|
@@ -138658,7 +139130,7 @@ var Transpiler = class {
|
|
|
138658
139130
|
unmodifiedParams,
|
|
138659
139131
|
allKnownEnums
|
|
138660
139132
|
);
|
|
138661
|
-
|
|
139133
|
+
return this.headerGenerator.generate(
|
|
138662
139134
|
headerSymbols,
|
|
138663
139135
|
headerName,
|
|
138664
139136
|
{
|
|
@@ -138671,8 +139143,6 @@ var Transpiler = class {
|
|
|
138671
139143
|
passByValueParams,
|
|
138672
139144
|
allKnownEnums
|
|
138673
139145
|
);
|
|
138674
|
-
this.fs.writeFile(headerPath, headerContent);
|
|
138675
|
-
return headerPath;
|
|
138676
139146
|
}
|
|
138677
139147
|
/**
|
|
138678
139148
|
* Collect external enum sources from included C-Next files.
|
|
@@ -138705,43 +139175,6 @@ var Transpiler = class {
|
|
|
138705
139175
|
);
|
|
138706
139176
|
}
|
|
138707
139177
|
}
|
|
138708
|
-
/**
|
|
138709
|
-
* Generate header content for exported symbols.
|
|
138710
|
-
* Issue #591: Extracted from transpileSource() for reduced complexity.
|
|
138711
|
-
* ADR-055 Phase 7: Works with TSymbol[], converts to IHeaderSymbol for generation.
|
|
138712
|
-
*/
|
|
138713
|
-
generateHeaderContent(tSymbols, sourcePath, cppMode, userIncludes, passByValueParams, symbolInfo) {
|
|
138714
|
-
const exportedSymbols = tSymbols.filter((s) => s.isExported);
|
|
138715
|
-
if (exportedSymbols.length === 0) {
|
|
138716
|
-
return void 0;
|
|
138717
|
-
}
|
|
138718
|
-
const unmodifiedParams = this.codeGenerator.getFunctionUnmodifiedParams();
|
|
138719
|
-
const headerSymbols = this.convertToHeaderSymbols(
|
|
138720
|
-
exportedSymbols,
|
|
138721
|
-
unmodifiedParams,
|
|
138722
|
-
symbolInfo.knownEnums
|
|
138723
|
-
);
|
|
138724
|
-
const headerName = basename5(sourcePath).replace(/\.cnx$|\.cnext$/, ".h");
|
|
138725
|
-
const typeInput = CodeGenState.symbols;
|
|
138726
|
-
const externalTypeHeaders = ExternalTypeHeaderBuilder_default.build(
|
|
138727
|
-
this.state.getAllHeaderDirectives(),
|
|
138728
|
-
CodeGenState.symbolTable
|
|
138729
|
-
);
|
|
138730
|
-
const typeInputWithSymbolTable = typeInput ? { ...typeInput, symbolTable: CodeGenState.symbolTable } : void 0;
|
|
138731
|
-
return this.headerGenerator.generate(
|
|
138732
|
-
headerSymbols,
|
|
138733
|
-
headerName,
|
|
138734
|
-
{
|
|
138735
|
-
exportedOnly: true,
|
|
138736
|
-
userIncludes,
|
|
138737
|
-
externalTypeHeaders,
|
|
138738
|
-
cppMode
|
|
138739
|
-
},
|
|
138740
|
-
typeInputWithSymbolTable,
|
|
138741
|
-
passByValueParams,
|
|
138742
|
-
symbolInfo.knownEnums
|
|
138743
|
-
);
|
|
138744
|
-
}
|
|
138745
139178
|
/**
|
|
138746
139179
|
* Convert TSymbols to IHeaderSymbols with auto-const information applied.
|
|
138747
139180
|
* ADR-055 Phase 7: Replaces mutation-based auto-const updating.
|
|
@@ -138949,7 +139382,7 @@ var Runner = class {
|
|
|
138949
139382
|
target: config.target,
|
|
138950
139383
|
debugMode: config.debugMode
|
|
138951
139384
|
});
|
|
138952
|
-
const result = await pipeline.
|
|
139385
|
+
const result = await pipeline.transpile({ kind: "files" });
|
|
138953
139386
|
this._renameOutputIfNeeded(result, explicitOutputFile);
|
|
138954
139387
|
ResultPrinter_default.print(result);
|
|
138955
139388
|
process.exit(result.success ? 0 : 1);
|
|
@@ -139659,16 +140092,31 @@ var ServeCommand = class _ServeCommand {
|
|
|
139659
140092
|
}
|
|
139660
140093
|
const { source, filePath } = params;
|
|
139661
140094
|
const options = filePath ? { workingDir: dirname11(filePath), sourcePath: filePath } : void 0;
|
|
139662
|
-
const
|
|
140095
|
+
const transpileResult = await _ServeCommand.transpiler.transpile({
|
|
140096
|
+
kind: "source",
|
|
139663
140097
|
source,
|
|
139664
|
-
options
|
|
139665
|
-
);
|
|
140098
|
+
...options
|
|
140099
|
+
});
|
|
140100
|
+
const fileResult = transpileResult.files.find(
|
|
140101
|
+
(f) => f.sourcePath === (filePath ?? "<string>")
|
|
140102
|
+
) ?? transpileResult.files[0];
|
|
140103
|
+
if (!fileResult) {
|
|
140104
|
+
return {
|
|
140105
|
+
success: true,
|
|
140106
|
+
result: {
|
|
140107
|
+
success: false,
|
|
140108
|
+
code: "",
|
|
140109
|
+
errors: transpileResult.errors,
|
|
140110
|
+
cppDetected: _ServeCommand.transpiler.isCppDetected()
|
|
140111
|
+
}
|
|
140112
|
+
};
|
|
140113
|
+
}
|
|
139666
140114
|
return {
|
|
139667
140115
|
success: true,
|
|
139668
140116
|
result: {
|
|
139669
|
-
success:
|
|
139670
|
-
code:
|
|
139671
|
-
errors:
|
|
140117
|
+
success: fileResult.success,
|
|
140118
|
+
code: fileResult.code,
|
|
140119
|
+
errors: fileResult.errors,
|
|
139672
140120
|
cppDetected: _ServeCommand.transpiler.isCppDetected()
|
|
139673
140121
|
}
|
|
139674
140122
|
};
|
|
@@ -139682,7 +140130,9 @@ var ServeCommand = class _ServeCommand {
|
|
|
139682
140130
|
const { source, filePath } = params;
|
|
139683
140131
|
if (_ServeCommand.transpiler && filePath) {
|
|
139684
140132
|
try {
|
|
139685
|
-
await _ServeCommand.transpiler.
|
|
140133
|
+
await _ServeCommand.transpiler.transpile({
|
|
140134
|
+
kind: "source",
|
|
140135
|
+
source,
|
|
139686
140136
|
workingDir: dirname11(filePath),
|
|
139687
140137
|
sourcePath: filePath
|
|
139688
140138
|
});
|