c-next 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +224 -69
- package/dist/index.js.map +2 -2
- package/package.json +1 -1
- package/src/transpiler/Transpiler.ts +4 -1
- package/src/transpiler/logic/IncludeExtractor.ts +12 -6
- package/src/transpiler/logic/__tests__/IncludeExtractor.test.ts +24 -0
- package/src/transpiler/output/codegen/CodeGenerator.ts +32 -24
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +3 -3
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +16 -16
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +8 -1
- package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +41 -6
- package/src/transpiler/output/codegen/generators/expressions/LiteralGenerator.ts +15 -2
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +38 -11
- package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +60 -0
- package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +2 -1
- package/src/transpiler/output/codegen/generators/support/IncludeGenerator.ts +19 -7
- package/src/transpiler/output/codegen/generators/support/__tests__/IncludeGenerator.test.ts +68 -0
- package/src/transpiler/output/codegen/helpers/ArgumentGenerator.ts +14 -2
- package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +3 -5
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +56 -8
- package/src/transpiler/output/codegen/helpers/ParameterDereferenceResolver.ts +8 -4
- package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +5 -6
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +60 -2
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +14 -16
- package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +25 -0
- package/src/transpiler/state/CodeGenState.ts +40 -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.9",
|
|
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",
|
|
@@ -110828,6 +110828,13 @@ var CodeGenState = class {
|
|
|
110828
110828
|
static inFunctionBody = false;
|
|
110829
110829
|
/** Expected type for struct initializers and enum inference */
|
|
110830
110830
|
static expectedType = null;
|
|
110831
|
+
/**
|
|
110832
|
+
* Suppress bare enum resolution even when expectedType is set.
|
|
110833
|
+
* Issue #872: MISRA 7.2 requires expectedType for U suffix on function args,
|
|
110834
|
+
* but bare enum resolution in function args was never allowed and changing
|
|
110835
|
+
* that would require ADR approval.
|
|
110836
|
+
*/
|
|
110837
|
+
static suppressBareEnumResolution = false;
|
|
110831
110838
|
/** Track args parameter name for main() translation */
|
|
110832
110839
|
static mainArgsName = null;
|
|
110833
110840
|
/** ADR-044: Current assignment context for overflow behavior */
|
|
@@ -110922,6 +110929,7 @@ var CodeGenState = class {
|
|
|
110922
110929
|
this.indentLevel = 0;
|
|
110923
110930
|
this.inFunctionBody = false;
|
|
110924
110931
|
this.expectedType = null;
|
|
110932
|
+
this.suppressBareEnumResolution = false;
|
|
110925
110933
|
this.mainArgsName = null;
|
|
110926
110934
|
this.assignmentContext = {
|
|
110927
110935
|
targetName: null,
|
|
@@ -110972,6 +110980,32 @@ var CodeGenState = class {
|
|
|
110972
110980
|
this.floatBitShadows.clear();
|
|
110973
110981
|
this.floatShadowCurrent.clear();
|
|
110974
110982
|
}
|
|
110983
|
+
/**
|
|
110984
|
+
* Execute a function with a temporary expectedType, restoring on completion.
|
|
110985
|
+
* Issue #872: Extracted to eliminate duplicate save/restore pattern and add exception safety.
|
|
110986
|
+
*
|
|
110987
|
+
* @param type - The expected type to set (if falsy, no change is made)
|
|
110988
|
+
* @param fn - The function to execute
|
|
110989
|
+
* @param suppressEnumResolution - If true, suppress bare enum resolution (for MISRA-only contexts)
|
|
110990
|
+
* @returns The result of the function
|
|
110991
|
+
*/
|
|
110992
|
+
static withExpectedType(type, fn, suppressEnumResolution = false) {
|
|
110993
|
+
if (!type) {
|
|
110994
|
+
return fn();
|
|
110995
|
+
}
|
|
110996
|
+
const savedType = this.expectedType;
|
|
110997
|
+
const savedSuppress = this.suppressBareEnumResolution;
|
|
110998
|
+
this.expectedType = type;
|
|
110999
|
+
if (suppressEnumResolution) {
|
|
111000
|
+
this.suppressBareEnumResolution = true;
|
|
111001
|
+
}
|
|
111002
|
+
try {
|
|
111003
|
+
return fn();
|
|
111004
|
+
} finally {
|
|
111005
|
+
this.expectedType = savedType;
|
|
111006
|
+
this.suppressBareEnumResolution = savedSuppress;
|
|
111007
|
+
}
|
|
111008
|
+
}
|
|
110975
111009
|
// ===========================================================================
|
|
110976
111010
|
// CONVENIENCE LOOKUP METHODS
|
|
110977
111011
|
// ===========================================================================
|
|
@@ -114424,8 +114458,14 @@ var UNSIGNED_TYPES3 = /* @__PURE__ */ new Set([
|
|
|
114424
114458
|
"u32",
|
|
114425
114459
|
"uint8_t",
|
|
114426
114460
|
"uint16_t",
|
|
114427
|
-
"uint32_t"
|
|
114461
|
+
"uint32_t",
|
|
114462
|
+
"size_t"
|
|
114463
|
+
// Array indices (MISRA 7.2)
|
|
114428
114464
|
]);
|
|
114465
|
+
function resolveTypedef(typeName) {
|
|
114466
|
+
const underlyingType = CodeGenState.getTypedefType(typeName);
|
|
114467
|
+
return underlyingType ?? typeName;
|
|
114468
|
+
}
|
|
114429
114469
|
function isNumericIntegerLiteral(text) {
|
|
114430
114470
|
if (text.startsWith('"') || text.startsWith("'")) {
|
|
114431
114471
|
return false;
|
|
@@ -114471,9 +114511,10 @@ var generateLiteral = (node, _input, state, _orchestrator) => {
|
|
|
114471
114511
|
}
|
|
114472
114512
|
const expectedType = state?.expectedType;
|
|
114473
114513
|
if (expectedType && isNumericIntegerLiteral(literalText) && !hasUnsignedSuffix(literalText)) {
|
|
114474
|
-
|
|
114514
|
+
const resolvedType = resolveTypedef(expectedType);
|
|
114515
|
+
if (UNSIGNED_64_TYPES.has(resolvedType)) {
|
|
114475
114516
|
literalText = literalText + "ULL";
|
|
114476
|
-
} else if (UNSIGNED_TYPES3.has(
|
|
114517
|
+
} else if (UNSIGNED_TYPES3.has(resolvedType)) {
|
|
114477
114518
|
literalText = literalText + "U";
|
|
114478
114519
|
}
|
|
114479
114520
|
}
|
|
@@ -115127,7 +115168,23 @@ var _parameterExpectsAddressOf = (paramType, argType, orchestrator) => {
|
|
|
115127
115168
|
return paramBaseType === argType;
|
|
115128
115169
|
};
|
|
115129
115170
|
var _generateCFunctionArg = (e, targetParam, input, orchestrator) => {
|
|
115130
|
-
|
|
115171
|
+
const argIdentifier = orchestrator.getSimpleIdentifier(e);
|
|
115172
|
+
const paramInfo = argIdentifier ? CodeGenState.currentParameters.get(argIdentifier) : void 0;
|
|
115173
|
+
const isCallbackPromotedParam = paramInfo?.forcePointerSemantics ?? false;
|
|
115174
|
+
if (targetParam?.baseType?.endsWith("*") && isCallbackPromotedParam) {
|
|
115175
|
+
return wrapWithCppEnumCast(
|
|
115176
|
+
argIdentifier,
|
|
115177
|
+
e,
|
|
115178
|
+
targetParam?.baseType,
|
|
115179
|
+
orchestrator
|
|
115180
|
+
);
|
|
115181
|
+
}
|
|
115182
|
+
const argCode = CodeGenState.withExpectedType(
|
|
115183
|
+
targetParam?.baseType,
|
|
115184
|
+
() => orchestrator.generateExpression(e),
|
|
115185
|
+
true
|
|
115186
|
+
// suppressEnumResolution
|
|
115187
|
+
);
|
|
115131
115188
|
if (!targetParam?.baseType?.endsWith("*")) {
|
|
115132
115189
|
return wrapWithCppEnumCast(argCode, e, targetParam?.baseType, orchestrator);
|
|
115133
115190
|
}
|
|
@@ -115143,10 +115200,13 @@ var _generateCFunctionArg = (e, targetParam, input, orchestrator) => {
|
|
|
115143
115200
|
isPointerVariable = true;
|
|
115144
115201
|
}
|
|
115145
115202
|
const needsAddressOf = argType && !argType.endsWith("*") && !argCode.startsWith("&") && !targetParam.isArray && !isPointerVariable && (orchestrator.isStructType(argType) || _parameterExpectsAddressOf(targetParam.baseType, argType, orchestrator));
|
|
115146
|
-
|
|
115147
|
-
|
|
115148
|
-
|
|
115149
|
-
|
|
115203
|
+
const finalArgCode = needsAddressOf ? `&${argCode}` : argCode;
|
|
115204
|
+
return wrapWithCppEnumCast(
|
|
115205
|
+
finalArgCode,
|
|
115206
|
+
e,
|
|
115207
|
+
targetParam?.baseType,
|
|
115208
|
+
orchestrator
|
|
115209
|
+
);
|
|
115150
115210
|
};
|
|
115151
115211
|
var _shouldPassByValue = (funcExpr, idx, targetParam, isCrossFile, orchestrator) => {
|
|
115152
115212
|
if (!targetParam) return false;
|
|
@@ -115193,7 +115253,12 @@ var generateFunctionCall = (funcExpr, argCtx, input, _state, orchestrator) => {
|
|
|
115193
115253
|
resolved.isCrossFile,
|
|
115194
115254
|
orchestrator
|
|
115195
115255
|
)) {
|
|
115196
|
-
const argCode =
|
|
115256
|
+
const argCode = CodeGenState.withExpectedType(
|
|
115257
|
+
targetParam?.baseType,
|
|
115258
|
+
() => orchestrator.generateExpression(e),
|
|
115259
|
+
true
|
|
115260
|
+
// suppressEnumResolution
|
|
115261
|
+
);
|
|
115197
115262
|
return wrapWithCppEnumCast(
|
|
115198
115263
|
argCode,
|
|
115199
115264
|
e,
|
|
@@ -116545,12 +116610,15 @@ var generateSubscriptAccess = (ctx, input, state, orchestrator, effects) => {
|
|
|
116545
116610
|
return output;
|
|
116546
116611
|
};
|
|
116547
116612
|
var handleSingleSubscript = (ctx, expr, input, orchestrator, output) => {
|
|
116548
|
-
const index =
|
|
116613
|
+
const index = CodeGenState.withExpectedType(
|
|
116614
|
+
"size_t",
|
|
116615
|
+
() => orchestrator.generateExpression(expr)
|
|
116616
|
+
);
|
|
116549
116617
|
validateNotBitmapMember(ctx, input);
|
|
116550
116618
|
const isRegisterAccess = checkRegisterAccess(ctx, input);
|
|
116551
116619
|
const identifierTypeInfo = getIdentifierTypeInfo(ctx, input);
|
|
116552
116620
|
if (isRegisterAccess) {
|
|
116553
|
-
output.result = `((${ctx.result} >> ${index}) & 1)`;
|
|
116621
|
+
output.result = index === "0" || index === "0U" ? `((${ctx.result}) & 1)` : `((${ctx.result} >> ${index}) & 1)`;
|
|
116554
116622
|
return output;
|
|
116555
116623
|
}
|
|
116556
116624
|
if (ctx.currentMemberIsArray) {
|
|
@@ -116564,7 +116632,7 @@ var handleSingleSubscript = (ctx, expr, input, orchestrator, output) => {
|
|
|
116564
116632
|
}
|
|
116565
116633
|
const isPrimitiveIntMember = ctx.currentStructType && TypeCheckUtils_default.isInteger(ctx.currentStructType);
|
|
116566
116634
|
if (isPrimitiveIntMember) {
|
|
116567
|
-
output.result = `((${ctx.result} >> ${index}) & 1)`;
|
|
116635
|
+
output.result = index === "0" || index === "0U" ? `((${ctx.result}) & 1)` : `((${ctx.result} >> ${index}) & 1)`;
|
|
116568
116636
|
output.currentStructType = void 0;
|
|
116569
116637
|
return output;
|
|
116570
116638
|
}
|
|
@@ -116622,12 +116690,18 @@ var handleDefaultSubscript = (ctx, index, typeInfo, output) => {
|
|
|
116622
116690
|
subscriptCount: 1,
|
|
116623
116691
|
isRegisterAccess: false
|
|
116624
116692
|
});
|
|
116625
|
-
|
|
116693
|
+
if (subscriptKind === "bit_single") {
|
|
116694
|
+
output.result = index === "0" || index === "0U" ? `((${ctx.result}) & 1)` : `((${ctx.result} >> ${index}) & 1)`;
|
|
116695
|
+
} else {
|
|
116696
|
+
output.result = `${ctx.result}[${index}]`;
|
|
116697
|
+
}
|
|
116626
116698
|
return output;
|
|
116627
116699
|
};
|
|
116628
116700
|
var handleBitRangeSubscript = (ctx, exprs, input, state, orchestrator, effects, output) => {
|
|
116629
|
-
const start =
|
|
116630
|
-
|
|
116701
|
+
const [start, width] = CodeGenState.withExpectedType("size_t", () => [
|
|
116702
|
+
orchestrator.generateExpression(exprs[0]),
|
|
116703
|
+
orchestrator.generateExpression(exprs[1])
|
|
116704
|
+
]);
|
|
116631
116705
|
const isFloatType = ctx.primaryTypeInfo?.baseType === "f32" || ctx.primaryTypeInfo?.baseType === "f64";
|
|
116632
116706
|
if (isFloatType && ctx.rootIdentifier) {
|
|
116633
116707
|
output.result = handleFloatBitRange(
|
|
@@ -116644,7 +116718,7 @@ var handleBitRangeSubscript = (ctx, exprs, input, state, orchestrator, effects,
|
|
|
116644
116718
|
);
|
|
116645
116719
|
} else {
|
|
116646
116720
|
const mask = orchestrator.generateBitMask(width);
|
|
116647
|
-
if (start === "0") {
|
|
116721
|
+
if (start === "0" || start === "0U") {
|
|
116648
116722
|
output.result = `((${ctx.result}) & ${mask})`;
|
|
116649
116723
|
} else {
|
|
116650
116724
|
output.result = `((${ctx.result} >> ${start}) & ${mask})`;
|
|
@@ -116679,7 +116753,7 @@ var handleFloatBitRange = (ctx, state, orchestrator, effects) => {
|
|
|
116679
116753
|
if (!shadowIsCurrent) {
|
|
116680
116754
|
orchestrator.addPendingTempDeclaration(`${shadowName}.f = ${ctx.result};`);
|
|
116681
116755
|
}
|
|
116682
|
-
if (ctx.start === "0") {
|
|
116756
|
+
if (ctx.start === "0" || ctx.start === "0U") {
|
|
116683
116757
|
return `(${shadowName}.u & ${mask})`;
|
|
116684
116758
|
}
|
|
116685
116759
|
return `((${shadowName}.u >> ${ctx.start}) & ${mask})`;
|
|
@@ -117601,7 +117675,11 @@ var FunctionGenerator_default = generateFunction;
|
|
|
117601
117675
|
// src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts
|
|
117602
117676
|
function generateInitializer(varDecl, isArray, orchestrator) {
|
|
117603
117677
|
if (varDecl.expression()) {
|
|
117604
|
-
|
|
117678
|
+
const typeName = orchestrator.generateType(varDecl.type());
|
|
117679
|
+
return CodeGenState.withExpectedType(
|
|
117680
|
+
typeName,
|
|
117681
|
+
() => ` = ${orchestrator.generateExpression(varDecl.expression())}`
|
|
117682
|
+
);
|
|
117605
117683
|
}
|
|
117606
117684
|
return ` = ${orchestrator.getZeroInitializer(varDecl.type(), isArray)}`;
|
|
117607
117685
|
}
|
|
@@ -118793,7 +118871,7 @@ var CnxFileResolver = class {
|
|
|
118793
118871
|
var CnxFileResolver_default = CnxFileResolver;
|
|
118794
118872
|
|
|
118795
118873
|
// src/transpiler/output/codegen/generators/support/IncludeGenerator.ts
|
|
118796
|
-
var resolveAngleIncludePath = (filename, sourcePath, includeDirs, inputs) => {
|
|
118874
|
+
var resolveAngleIncludePath = (filename, sourcePath, includeDirs, inputs, cppMode) => {
|
|
118797
118875
|
if (inputs.length === 0) {
|
|
118798
118876
|
return null;
|
|
118799
118877
|
}
|
|
@@ -118807,25 +118885,33 @@ var resolveAngleIncludePath = (filename, sourcePath, includeDirs, inputs) => {
|
|
|
118807
118885
|
foundPath,
|
|
118808
118886
|
inputs
|
|
118809
118887
|
);
|
|
118810
|
-
|
|
118888
|
+
const ext = cppMode ? ".hpp" : ".h";
|
|
118889
|
+
return relativePath ? relativePath.replace(/\.cnx$/, ext) : null;
|
|
118811
118890
|
};
|
|
118812
118891
|
var transformAngleInclude = (includeText, filename, options) => {
|
|
118813
|
-
const {
|
|
118892
|
+
const {
|
|
118893
|
+
sourcePath,
|
|
118894
|
+
includeDirs = [],
|
|
118895
|
+
inputs = [],
|
|
118896
|
+
cppMode = false
|
|
118897
|
+
} = options;
|
|
118814
118898
|
if (sourcePath) {
|
|
118815
118899
|
const resolvedPath = resolveAngleIncludePath(
|
|
118816
118900
|
filename,
|
|
118817
118901
|
sourcePath,
|
|
118818
118902
|
includeDirs,
|
|
118819
|
-
inputs
|
|
118903
|
+
inputs,
|
|
118904
|
+
cppMode
|
|
118820
118905
|
);
|
|
118821
118906
|
if (resolvedPath) {
|
|
118822
118907
|
return includeText.replace(`<${filename}.cnx>`, `<${resolvedPath}>`);
|
|
118823
118908
|
}
|
|
118824
118909
|
}
|
|
118825
|
-
|
|
118910
|
+
const ext = cppMode ? ".hpp" : ".h";
|
|
118911
|
+
return includeText.replace(`<${filename}.cnx>`, `<${filename}${ext}>`);
|
|
118826
118912
|
};
|
|
118827
118913
|
var transformQuoteInclude = (includeText, filepath, options) => {
|
|
118828
|
-
const { sourcePath } = options;
|
|
118914
|
+
const { sourcePath, cppMode = false } = options;
|
|
118829
118915
|
if (sourcePath) {
|
|
118830
118916
|
const sourceDir = path.dirname(sourcePath);
|
|
118831
118917
|
const cnxPath = path.resolve(sourceDir, `${filepath}.cnx`);
|
|
@@ -118837,7 +118923,8 @@ var transformQuoteInclude = (includeText, filepath, options) => {
|
|
|
118837
118923
|
);
|
|
118838
118924
|
}
|
|
118839
118925
|
}
|
|
118840
|
-
|
|
118926
|
+
const ext = cppMode ? ".hpp" : ".h";
|
|
118927
|
+
return includeText.replace(`"${filepath}.cnx"`, `"${filepath}${ext}"`);
|
|
118841
118928
|
};
|
|
118842
118929
|
var transformIncludeDirective = (includeText, options) => {
|
|
118843
118930
|
const angleMatch = /#\s*include\s*<([^>]+)\.cnx>/.exec(includeText);
|
|
@@ -122607,6 +122694,7 @@ var ArgumentGenerator = class _ArgumentGenerator {
|
|
|
122607
122694
|
}
|
|
122608
122695
|
/**
|
|
122609
122696
|
* Handle rvalue argument (literals or complex expressions).
|
|
122697
|
+
* Issue #872: Sets expectedType for MISRA 7.2 U suffix on unsigned literals.
|
|
122610
122698
|
*/
|
|
122611
122699
|
static handleRvalueArg(ctx, targetParamBaseType, callbacks) {
|
|
122612
122700
|
if (!targetParamBaseType) {
|
|
@@ -122614,9 +122702,19 @@ var ArgumentGenerator = class _ArgumentGenerator {
|
|
|
122614
122702
|
}
|
|
122615
122703
|
const cType = TYPE_MAP_default[targetParamBaseType];
|
|
122616
122704
|
if (!cType || cType === "void") {
|
|
122617
|
-
return
|
|
122705
|
+
return CodeGenState.withExpectedType(
|
|
122706
|
+
targetParamBaseType,
|
|
122707
|
+
() => callbacks.generateExpression(ctx),
|
|
122708
|
+
true
|
|
122709
|
+
// suppressEnumResolution
|
|
122710
|
+
);
|
|
122618
122711
|
}
|
|
122619
|
-
const value =
|
|
122712
|
+
const value = CodeGenState.withExpectedType(
|
|
122713
|
+
targetParamBaseType,
|
|
122714
|
+
() => callbacks.generateExpression(ctx),
|
|
122715
|
+
true
|
|
122716
|
+
// suppressEnumResolution
|
|
122717
|
+
);
|
|
122620
122718
|
if (CodeGenState.cppMode) {
|
|
122621
122719
|
return value;
|
|
122622
122720
|
}
|
|
@@ -123035,6 +123133,14 @@ var AssignmentExpectedTypeResolver = class _AssignmentExpectedTypeResolver {
|
|
|
123035
123133
|
identifiers
|
|
123036
123134
|
);
|
|
123037
123135
|
}
|
|
123136
|
+
if (identifiers.length === 1 && hasSubscript) {
|
|
123137
|
+
return _AssignmentExpectedTypeResolver.resolveForArrayElement(baseId);
|
|
123138
|
+
}
|
|
123139
|
+
if (identifiers.length >= 2 && hasSubscript) {
|
|
123140
|
+
return _AssignmentExpectedTypeResolver.resolveForMemberArrayElement(
|
|
123141
|
+
identifiers
|
|
123142
|
+
);
|
|
123143
|
+
}
|
|
123038
123144
|
}
|
|
123039
123145
|
return { expectedType: null, assignmentContext: null };
|
|
123040
123146
|
}
|
|
@@ -123061,8 +123167,40 @@ var AssignmentExpectedTypeResolver = class _AssignmentExpectedTypeResolver {
|
|
|
123061
123167
|
*
|
|
123062
123168
|
* Issue #452: Enables type-aware resolution of unqualified enum members
|
|
123063
123169
|
* for nested access (e.g., config.nested.field).
|
|
123170
|
+
*
|
|
123171
|
+
* Delegates to walkMemberChain shared implementation.
|
|
123064
123172
|
*/
|
|
123065
123173
|
static resolveForMemberChain(identifiers) {
|
|
123174
|
+
return _AssignmentExpectedTypeResolver.walkMemberChain(identifiers);
|
|
123175
|
+
}
|
|
123176
|
+
/**
|
|
123177
|
+
* Resolve expected type for array element access.
|
|
123178
|
+
* Issue #872: arr[i] <- value needs baseType for MISRA 7.2 U suffix.
|
|
123179
|
+
*/
|
|
123180
|
+
static resolveForArrayElement(id) {
|
|
123181
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(id);
|
|
123182
|
+
if (!typeInfo?.isArray) {
|
|
123183
|
+
return { expectedType: null, assignmentContext: null };
|
|
123184
|
+
}
|
|
123185
|
+
return { expectedType: typeInfo.baseType, assignmentContext: null };
|
|
123186
|
+
}
|
|
123187
|
+
/**
|
|
123188
|
+
* Resolve expected type for member chain ending with array access.
|
|
123189
|
+
* Issue #872: struct.arr[i] <- value needs element type for MISRA 7.2.
|
|
123190
|
+
*
|
|
123191
|
+
* Delegates to walkMemberChain which handles both member chain and
|
|
123192
|
+
* member-array-element patterns identically (both return final field type).
|
|
123193
|
+
*/
|
|
123194
|
+
static resolveForMemberArrayElement(identifiers) {
|
|
123195
|
+
return _AssignmentExpectedTypeResolver.walkMemberChain(identifiers);
|
|
123196
|
+
}
|
|
123197
|
+
/**
|
|
123198
|
+
* Walk a struct member chain to find the final field's type.
|
|
123199
|
+
* Shared implementation for both member chain and member-array-element patterns.
|
|
123200
|
+
*
|
|
123201
|
+
* Issue #831: Uses SymbolTable as single source of truth for struct fields.
|
|
123202
|
+
*/
|
|
123203
|
+
static walkMemberChain(identifiers) {
|
|
123066
123204
|
if (identifiers.length < 2) {
|
|
123067
123205
|
return { expectedType: null, assignmentContext: null };
|
|
123068
123206
|
}
|
|
@@ -123608,11 +123746,10 @@ var ArrayInitHelper = class _ArrayInitHelper {
|
|
|
123608
123746
|
*/
|
|
123609
123747
|
static _generateArrayInitValue(typeCtx, expression, callbacks) {
|
|
123610
123748
|
const typeName = callbacks.getTypeName(typeCtx);
|
|
123611
|
-
|
|
123612
|
-
|
|
123613
|
-
|
|
123614
|
-
|
|
123615
|
-
return initValue;
|
|
123749
|
+
return CodeGenState.withExpectedType(
|
|
123750
|
+
typeName,
|
|
123751
|
+
() => callbacks.generateExpression(expression)
|
|
123752
|
+
);
|
|
123616
123753
|
}
|
|
123617
123754
|
/**
|
|
123618
123755
|
* Check if the last expression was an array initializer
|
|
@@ -124305,15 +124442,14 @@ ${assignments}`;
|
|
|
124305
124442
|
return `${decl} = ${callbacks.getZeroInitializer(typeCtx, isArray)}`;
|
|
124306
124443
|
}
|
|
124307
124444
|
const typeName = callbacks.getTypeName(typeCtx);
|
|
124308
|
-
const savedExpectedType = CodeGenState.expectedType;
|
|
124309
|
-
CodeGenState.expectedType = typeName;
|
|
124310
124445
|
EnumAssignmentValidator_default.validateEnumAssignment(typeName, ctx.expression());
|
|
124311
124446
|
_VariableDeclHelper.validateIntegerInitializer(ctx, typeName, {
|
|
124312
124447
|
getExpressionType: callbacks.getExpressionType
|
|
124313
124448
|
});
|
|
124314
|
-
|
|
124315
|
-
|
|
124316
|
-
|
|
124449
|
+
return CodeGenState.withExpectedType(
|
|
124450
|
+
typeName,
|
|
124451
|
+
() => `${decl} = ${callbacks.generateExpression(ctx.expression())}`
|
|
124452
|
+
);
|
|
124317
124453
|
}
|
|
124318
124454
|
// ========================================================================
|
|
124319
124455
|
// Tier 4: Orchestrators (main entry points)
|
|
@@ -127234,13 +127370,16 @@ var CodeGenerator = class _CodeGenerator {
|
|
|
127234
127370
|
/**
|
|
127235
127371
|
* Issue #477: Generate expression with a specific expected type context.
|
|
127236
127372
|
* Used by return statements to resolve unqualified enum values.
|
|
127373
|
+
* Note: Uses explicit save/restore (not withExpectedType) to support null values.
|
|
127237
127374
|
*/
|
|
127238
127375
|
generateExpressionWithExpectedType(ctx, expectedType) {
|
|
127239
|
-
const
|
|
127376
|
+
const saved = CodeGenState.expectedType;
|
|
127240
127377
|
CodeGenState.expectedType = expectedType;
|
|
127241
|
-
|
|
127242
|
-
|
|
127243
|
-
|
|
127378
|
+
try {
|
|
127379
|
+
return this.generateExpression(ctx);
|
|
127380
|
+
} finally {
|
|
127381
|
+
CodeGenState.expectedType = saved;
|
|
127382
|
+
}
|
|
127244
127383
|
}
|
|
127245
127384
|
/**
|
|
127246
127385
|
* Generate type translation (C-Next type -> C type).
|
|
@@ -128585,15 +128724,17 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
128585
128724
|
return DEFAULT_TARGET2;
|
|
128586
128725
|
}
|
|
128587
128726
|
/**
|
|
128588
|
-
* ADR-010: Transform #include directives, converting .cnx to .h
|
|
128727
|
+
* ADR-010: Transform #include directives, converting .cnx to .h or .hpp
|
|
128589
128728
|
* ADR-053 A5: Delegates to IncludeGenerator
|
|
128590
128729
|
* Issue #349: Now passes includeDirs and inputs for angle-bracket resolution
|
|
128730
|
+
* Issue #941: Now passes cppMode for .hpp extension in C++ mode
|
|
128591
128731
|
*/
|
|
128592
128732
|
transformIncludeDirective(includeText) {
|
|
128593
128733
|
return includeTransformIncludeDirective(includeText, {
|
|
128594
128734
|
sourcePath: CodeGenState.sourcePath,
|
|
128595
128735
|
includeDirs: CodeGenState.includeDirs,
|
|
128596
|
-
inputs: CodeGenState.inputs
|
|
128736
|
+
inputs: CodeGenState.inputs,
|
|
128737
|
+
cppMode: CodeGenState.cppMode
|
|
128597
128738
|
});
|
|
128598
128739
|
}
|
|
128599
128740
|
// Issue #63: validateIncludeNotImplementationFile moved to TypeValidator
|
|
@@ -129331,19 +129472,20 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
129331
129472
|
const structFieldTypes = CodeGenState.symbolTable?.getStructFieldTypes(typeName);
|
|
129332
129473
|
const fields = fieldList.fieldInitializer().map((field) => {
|
|
129333
129474
|
const fieldName = field.IDENTIFIER().getText();
|
|
129334
|
-
|
|
129475
|
+
let fieldType;
|
|
129335
129476
|
if (structFieldTypes?.has(fieldName)) {
|
|
129336
|
-
|
|
129477
|
+
fieldType = structFieldTypes.get(fieldName);
|
|
129337
129478
|
if (fieldType.includes("_")) {
|
|
129338
129479
|
const parts = fieldType.split("_");
|
|
129339
129480
|
if (parts.length > 1 && this.isCppScopeSymbol(parts[0])) {
|
|
129340
129481
|
fieldType = parts.join("::");
|
|
129341
129482
|
}
|
|
129342
129483
|
}
|
|
129343
|
-
CodeGenState.expectedType = fieldType;
|
|
129344
129484
|
}
|
|
129345
|
-
const value =
|
|
129346
|
-
|
|
129485
|
+
const value = CodeGenState.withExpectedType(
|
|
129486
|
+
fieldType,
|
|
129487
|
+
() => this.generateExpression(field.expression())
|
|
129488
|
+
);
|
|
129347
129489
|
return { fieldName, value };
|
|
129348
129490
|
});
|
|
129349
129491
|
if (isCppClass) {
|
|
@@ -129858,18 +130000,20 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
129858
130000
|
// ADR-001: <- becomes = in C, with compound assignment operators
|
|
129859
130001
|
generateAssignment(ctx) {
|
|
129860
130002
|
const targetCtx = ctx.assignmentTarget();
|
|
129861
|
-
const savedExpectedType = CodeGenState.expectedType;
|
|
129862
130003
|
const savedAssignmentContext = { ...CodeGenState.assignmentContext };
|
|
129863
130004
|
const resolved = AssignmentExpectedTypeResolver_default.resolve(targetCtx);
|
|
129864
|
-
if (resolved.expectedType) {
|
|
129865
|
-
CodeGenState.expectedType = resolved.expectedType;
|
|
129866
|
-
}
|
|
129867
130005
|
if (resolved.assignmentContext) {
|
|
129868
130006
|
CodeGenState.assignmentContext = resolved.assignmentContext;
|
|
129869
130007
|
}
|
|
129870
|
-
|
|
129871
|
-
|
|
129872
|
-
|
|
130008
|
+
let value;
|
|
130009
|
+
try {
|
|
130010
|
+
value = CodeGenState.withExpectedType(
|
|
130011
|
+
resolved.expectedType,
|
|
130012
|
+
() => this.generateExpression(ctx.expression())
|
|
130013
|
+
);
|
|
130014
|
+
} finally {
|
|
130015
|
+
CodeGenState.assignmentContext = savedAssignmentContext;
|
|
130016
|
+
}
|
|
129873
130017
|
const operatorCtx = ctx.assignmentOperator();
|
|
129874
130018
|
const cnextOp = operatorCtx.getText();
|
|
129875
130019
|
const cOp = ASSIGNMENT_OPERATOR_MAP2[cnextOp] || "=";
|
|
@@ -130079,7 +130223,11 @@ typedef ${callbackInfo.returnType} (*${callbackInfo.typedefName})(${paramList});
|
|
|
130079
130223
|
* @returns The qualified enum member access, or null if not an enum member
|
|
130080
130224
|
*/
|
|
130081
130225
|
_resolveUnqualifiedEnumMember(id) {
|
|
130082
|
-
if (CodeGenState.
|
|
130226
|
+
if (CodeGenState.suppressBareEnumResolution) {
|
|
130227
|
+
} else if (
|
|
130228
|
+
// Type-aware resolution: check only the expected enum type
|
|
130229
|
+
CodeGenState.expectedType && CodeGenState.symbols.knownEnums.has(CodeGenState.expectedType)
|
|
130230
|
+
) {
|
|
130083
130231
|
const members = CodeGenState.symbols.enumMembers.get(
|
|
130084
130232
|
CodeGenState.expectedType
|
|
130085
130233
|
);
|
|
@@ -130877,15 +131025,16 @@ var HeaderGeneratorUtils = class _HeaderGeneratorUtils {
|
|
|
130877
131025
|
}
|
|
130878
131026
|
if (options.userIncludes && options.userIncludes.length > 0) {
|
|
130879
131027
|
for (const include of options.userIncludes) {
|
|
130880
|
-
|
|
130881
|
-
|
|
131028
|
+
lines.push(include);
|
|
131029
|
+
}
|
|
131030
|
+
}
|
|
131031
|
+
const userIncludeSet = new Set(options.userIncludes ?? []);
|
|
131032
|
+
if (options.cppMode && options.userIncludes) {
|
|
131033
|
+
for (const inc of options.userIncludes) {
|
|
131034
|
+
const hVersion = inc.replace(/\.hpp"/, '.h"').replace(/\.hpp>/, ".h>");
|
|
131035
|
+
userIncludeSet.add(hVersion);
|
|
130882
131036
|
}
|
|
130883
131037
|
}
|
|
130884
|
-
const userIncludeSet = new Set(
|
|
130885
|
-
options.userIncludes?.map(
|
|
130886
|
-
(inc) => options.cppMode ? inc.replace(/\.h"/, '.hpp"').replace(/\.h>/, ".hpp>") : inc
|
|
130887
|
-
) ?? []
|
|
130888
|
-
);
|
|
130889
131038
|
for (const directive of headersToInclude) {
|
|
130890
131039
|
if (!userIncludeSet.has(directive)) {
|
|
130891
131040
|
lines.push(directive);
|
|
@@ -131263,18 +131412,21 @@ var IncludeExtractor = class {
|
|
|
131263
131412
|
/**
|
|
131264
131413
|
* Extract user includes from a parsed C-Next program.
|
|
131265
131414
|
*
|
|
131266
|
-
* Extracts #include directives for .cnx files and transforms them to .h includes.
|
|
131415
|
+
* Extracts #include directives for .cnx files and transforms them to .h or .hpp includes.
|
|
131416
|
+
* Issue #941: Uses .hpp extension when cppMode is true.
|
|
131267
131417
|
* This enables cross-file type definitions in generated headers.
|
|
131268
131418
|
*
|
|
131269
131419
|
* @param tree The parsed C-Next program
|
|
131270
|
-
* @
|
|
131420
|
+
* @param cppMode Whether to use .hpp extension (C++ mode)
|
|
131421
|
+
* @returns Array of transformed include strings (e.g., '#include "types.h"' or '#include "types.hpp"')
|
|
131271
131422
|
*/
|
|
131272
|
-
static collectUserIncludes(tree) {
|
|
131423
|
+
static collectUserIncludes(tree, cppMode = false) {
|
|
131273
131424
|
const userIncludes = [];
|
|
131425
|
+
const ext = cppMode ? ".hpp" : ".h";
|
|
131274
131426
|
for (const includeDir of tree.includeDirective()) {
|
|
131275
131427
|
const includeText = includeDir.getText();
|
|
131276
131428
|
if (includeText.includes(".cnx")) {
|
|
131277
|
-
const transformedInclude = includeText.replace(/\.cnx"/,
|
|
131429
|
+
const transformedInclude = includeText.replace(/\.cnx"/, `${ext}"`).replace(/\.cnx>/, `${ext}>`);
|
|
131278
131430
|
userIncludes.push(transformedInclude);
|
|
131279
131431
|
}
|
|
131280
131432
|
}
|
|
@@ -138912,7 +139064,10 @@ var Transpiler = class {
|
|
|
138912
139064
|
cppMode: this.cppDetected,
|
|
138913
139065
|
symbolInfo
|
|
138914
139066
|
});
|
|
138915
|
-
const userIncludes = IncludeExtractor_default.collectUserIncludes(
|
|
139067
|
+
const userIncludes = IncludeExtractor_default.collectUserIncludes(
|
|
139068
|
+
tree,
|
|
139069
|
+
this.cppDetected
|
|
139070
|
+
);
|
|
138916
139071
|
const passByValue = this.codeGenerator.getPassByValueParams();
|
|
138917
139072
|
const passByValueCopy = MapUtils_default.deepCopyStringSetMap(passByValue);
|
|
138918
139073
|
this.state.setSymbolInfo(sourcePath, symbolInfo);
|