c-next 0.1.29 → 0.1.30
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/package.json
CHANGED
|
@@ -319,6 +319,13 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
319
319
|
*/
|
|
320
320
|
private functionParamLists: Map<string, string[]> = new Map();
|
|
321
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Issue #369: Tracks whether self-include was added.
|
|
324
|
+
* When true, skip struct/enum/bitmap definitions in .c file because
|
|
325
|
+
* they'll be defined in the included header.
|
|
326
|
+
*/
|
|
327
|
+
private selfIncludeAdded: boolean = false;
|
|
328
|
+
|
|
322
329
|
/**
|
|
323
330
|
* Initialize generator registry with extracted generators.
|
|
324
331
|
* Called once before code generation begins.
|
|
@@ -380,6 +387,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
380
387
|
localVariables: this.context.localVariables,
|
|
381
388
|
localArrays: this.context.localArrays,
|
|
382
389
|
expectedType: this.context.expectedType,
|
|
390
|
+
selfIncludeAdded: this.selfIncludeAdded, // Issue #369
|
|
383
391
|
};
|
|
384
392
|
}
|
|
385
393
|
|
|
@@ -1383,6 +1391,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1383
1391
|
this.needsString = false; // ADR-045: Reset string header tracking
|
|
1384
1392
|
this.needsISR = false; // ADR-040: Reset ISR typedef tracking
|
|
1385
1393
|
this.needsCMSIS = false; // ADR-049/050: Reset CMSIS include tracking
|
|
1394
|
+
this.selfIncludeAdded = false; // Issue #369: Reset self-include tracking
|
|
1386
1395
|
|
|
1387
1396
|
// First pass: collect namespace and class members
|
|
1388
1397
|
// Issue #60: Create SymbolCollector (extracted from CodeGenerator)
|
|
@@ -1443,6 +1452,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1443
1452
|
// When file has public symbols and headers are being generated,
|
|
1444
1453
|
// include own header to ensure proper C linkage
|
|
1445
1454
|
// Issue #339: Use relative path from source root when available
|
|
1455
|
+
// Issue #369: Track self-include to skip type definitions in .c file
|
|
1446
1456
|
if (
|
|
1447
1457
|
options?.generateHeaders &&
|
|
1448
1458
|
this.symbols!.hasPublicSymbols() &&
|
|
@@ -1455,6 +1465,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1455
1465
|
const headerName = pathToUse.replace(/\.cnx$|\.cnext$/, ".h");
|
|
1456
1466
|
output.push(`#include "${headerName}"`);
|
|
1457
1467
|
output.push("");
|
|
1468
|
+
// Issue #369: Mark that self-include was added - types will be in header
|
|
1469
|
+
this.selfIncludeAdded = true;
|
|
1458
1470
|
}
|
|
1459
1471
|
|
|
1460
1472
|
// Pass through #include directives from source
|
|
@@ -2136,16 +2148,62 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2136
2148
|
}
|
|
2137
2149
|
}
|
|
2138
2150
|
|
|
2139
|
-
//
|
|
2140
|
-
//
|
|
2141
|
-
//
|
|
2151
|
+
// Issue #365: Handle scope-qualified calls: Scope.method(...) or global.Scope.method(...)
|
|
2152
|
+
// Track member accesses to build the mangled callee name (e.g., Storage_load)
|
|
2153
|
+
// Then when we find the function call, record it to the call graph
|
|
2154
|
+
if (postfixOps.length > 0) {
|
|
2155
|
+
const memberNames: string[] = [];
|
|
2156
|
+
|
|
2157
|
+
// Start with primary identifier if it's a scope name (not 'global' or 'this')
|
|
2158
|
+
const primaryId = primary.IDENTIFIER()?.getText();
|
|
2159
|
+
if (primaryId && primaryId !== "global" && primaryId !== "this") {
|
|
2160
|
+
memberNames.push(primaryId);
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
// Collect member access names until we hit a function call
|
|
2164
|
+
for (const op of postfixOps) {
|
|
2165
|
+
if (op.IDENTIFIER()) {
|
|
2166
|
+
// Member access: .IDENTIFIER
|
|
2167
|
+
memberNames.push(op.IDENTIFIER()!.getText());
|
|
2168
|
+
} else if (op.LPAREN()) {
|
|
2169
|
+
// Function call found - record to call graph if we have a callee name
|
|
2170
|
+
if (memberNames.length >= 1) {
|
|
2171
|
+
// Build mangled name: e.g., ["Storage", "load"] -> "Storage_load"
|
|
2172
|
+
// For scope methods, the last name is the method, everything before is scope
|
|
2173
|
+
const calleeName = memberNames.join("_");
|
|
2174
|
+
const argList = op.argumentList();
|
|
2175
|
+
|
|
2176
|
+
if (argList) {
|
|
2177
|
+
const args = argList.expression();
|
|
2178
|
+
for (let j = 0; j < args.length; j++) {
|
|
2179
|
+
const arg = args[j];
|
|
2180
|
+
const argName = this.getSimpleIdentifierFromExpr(arg);
|
|
2181
|
+
if (argName && paramSet.has(argName)) {
|
|
2182
|
+
this.functionCallGraph.get(funcName)!.push({
|
|
2183
|
+
callee: calleeName,
|
|
2184
|
+
paramIndex: j,
|
|
2185
|
+
argParamName: argName,
|
|
2186
|
+
});
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
}
|
|
2191
|
+
// Reset for potential chained calls like obj.foo().bar()
|
|
2192
|
+
memberNames.length = 0;
|
|
2193
|
+
} else if (op.expression().length > 0) {
|
|
2194
|
+
// Array subscript - doesn't contribute to method name
|
|
2195
|
+
// but reset member chain as array access breaks scope chain
|
|
2196
|
+
memberNames.length = 0;
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
2142
2200
|
|
|
2143
2201
|
// Recurse into primary expression if it's a parenthesized expression
|
|
2144
2202
|
if (primary.expression()) {
|
|
2145
2203
|
this.walkExpressionForCalls(funcName, paramSet, primary.expression()!);
|
|
2146
2204
|
}
|
|
2147
2205
|
|
|
2148
|
-
// Walk arguments in any postfix function call ops
|
|
2206
|
+
// Walk arguments in any postfix function call ops (for nested calls)
|
|
2149
2207
|
for (const op of postfixOps) {
|
|
2150
2208
|
if (op.argumentList()) {
|
|
2151
2209
|
for (const argExpr of op.argumentList()!.expression()) {
|
|
@@ -4372,15 +4430,26 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4372
4430
|
if (ctx.registerDeclaration()) {
|
|
4373
4431
|
return this.generateRegister(ctx.registerDeclaration()!);
|
|
4374
4432
|
}
|
|
4433
|
+
// Issue #369: Skip struct/enum/bitmap definitions when self-include is added
|
|
4434
|
+
// These types will be defined in the included header file
|
|
4375
4435
|
if (ctx.structDeclaration()) {
|
|
4436
|
+
if (this.selfIncludeAdded) {
|
|
4437
|
+
return ""; // Definition will come from header
|
|
4438
|
+
}
|
|
4376
4439
|
return this.generateStruct(ctx.structDeclaration()!);
|
|
4377
4440
|
}
|
|
4378
4441
|
// ADR-017: Handle enum declarations
|
|
4379
4442
|
if (ctx.enumDeclaration()) {
|
|
4443
|
+
if (this.selfIncludeAdded) {
|
|
4444
|
+
return ""; // Definition will come from header
|
|
4445
|
+
}
|
|
4380
4446
|
return this.generateEnum(ctx.enumDeclaration()!);
|
|
4381
4447
|
}
|
|
4382
4448
|
// ADR-034: Handle bitmap declarations
|
|
4383
4449
|
if (ctx.bitmapDeclaration()) {
|
|
4450
|
+
if (this.selfIncludeAdded) {
|
|
4451
|
+
return ""; // Definition will come from header
|
|
4452
|
+
}
|
|
4384
4453
|
return this.generateBitmap(ctx.bitmapDeclaration()!);
|
|
4385
4454
|
}
|
|
4386
4455
|
if (ctx.functionDeclaration()) {
|
|
@@ -6859,14 +6928,22 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
6859
6928
|
const exprs = arrayAccessCtx.expression();
|
|
6860
6929
|
const typeInfo = this.context.typeRegistry.get(name);
|
|
6861
6930
|
|
|
6931
|
+
// Issue #368: Check if this is an array parameter (e.g., void foo(u8 data[]))
|
|
6932
|
+
// Array parameters may not have arrayDimensions in typeRegistry (for unsized params),
|
|
6933
|
+
// but they ARE arrays and should use array indexing, not bit manipulation.
|
|
6934
|
+
const paramInfo = this.context.currentParameters.get(name);
|
|
6935
|
+
const isArrayParameter = paramInfo?.isArray ?? false;
|
|
6936
|
+
|
|
6862
6937
|
// ADR-040: ISR arrays use normal array indexing, not bit manipulation
|
|
6863
6938
|
// Also handle any array type that isn't an integer scalar
|
|
6864
6939
|
// Issue #213: String parameters (isString=true) should also use memcpy for slice assignment
|
|
6940
|
+
// Issue #368: Array parameters (even unsized like u8 data[]) should use array indexing
|
|
6865
6941
|
const isActualArray =
|
|
6866
6942
|
(typeInfo?.isArray &&
|
|
6867
6943
|
typeInfo.arrayDimensions &&
|
|
6868
6944
|
typeInfo.arrayDimensions.length > 0) ||
|
|
6869
|
-
typeInfo?.isString
|
|
6945
|
+
typeInfo?.isString ||
|
|
6946
|
+
isArrayParameter;
|
|
6870
6947
|
const isISRType = typeInfo?.baseType === "ISR";
|
|
6871
6948
|
|
|
6872
6949
|
if (isActualArray || isISRType) {
|
|
@@ -866,16 +866,8 @@ class TypeValidator {
|
|
|
866
866
|
for (const add of shift.additiveExpression()) {
|
|
867
867
|
for (const mult of add.multiplicativeExpression()) {
|
|
868
868
|
for (const unary of mult.unaryExpression()) {
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
for (const op of postfix.postfixOp()) {
|
|
872
|
-
if (
|
|
873
|
-
op.argumentList() ||
|
|
874
|
-
op.getText().startsWith("(")
|
|
875
|
-
) {
|
|
876
|
-
return true;
|
|
877
|
-
}
|
|
878
|
-
}
|
|
869
|
+
if (this.hasPostfixFunctionCallInUnary(unary)) {
|
|
870
|
+
return true;
|
|
879
871
|
}
|
|
880
872
|
}
|
|
881
873
|
}
|
|
@@ -890,6 +882,32 @@ class TypeValidator {
|
|
|
890
882
|
return false;
|
|
891
883
|
}
|
|
892
884
|
|
|
885
|
+
/**
|
|
886
|
+
* Issue #366: Recursively check unaryExpression for function calls.
|
|
887
|
+
* Handles unary operators (!, -, ~, &) that wrap function calls,
|
|
888
|
+
* including arbitrary nesting like !!isReady() or -~getValue().
|
|
889
|
+
*/
|
|
890
|
+
private hasPostfixFunctionCallInUnary(
|
|
891
|
+
unary: Parser.UnaryExpressionContext,
|
|
892
|
+
): boolean {
|
|
893
|
+
// Recurse through nested unary operators (!, -, ~, &) until we reach postfixExpression
|
|
894
|
+
const nestedUnary = unary.unaryExpression();
|
|
895
|
+
if (nestedUnary) {
|
|
896
|
+
return this.hasPostfixFunctionCallInUnary(nestedUnary);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// Base case: check postfixExpression
|
|
900
|
+
const postfix = unary.postfixExpression();
|
|
901
|
+
if (postfix) {
|
|
902
|
+
for (const op of postfix.postfixOp()) {
|
|
903
|
+
if (op.argumentList() || op.getText().startsWith("(")) {
|
|
904
|
+
return true;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
return false;
|
|
909
|
+
}
|
|
910
|
+
|
|
893
911
|
// ========================================================================
|
|
894
912
|
// Shift Amount Validation (MISRA C:2012 Rule 12.2)
|
|
895
913
|
// ========================================================================
|
|
@@ -26,6 +26,13 @@ interface IGeneratorState {
|
|
|
26
26
|
|
|
27
27
|
/** Expected type for inferred struct initializers */
|
|
28
28
|
readonly expectedType: string | null;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Issue #369: Whether self-include was added.
|
|
32
|
+
* When true, type definitions (struct/enum/bitmap) should not be emitted
|
|
33
|
+
* in the .c file as they'll come from the included header.
|
|
34
|
+
*/
|
|
35
|
+
readonly selfIncludeAdded: boolean;
|
|
29
36
|
}
|
|
30
37
|
|
|
31
38
|
export default IGeneratorState;
|
|
@@ -142,14 +142,16 @@ const generateScope: TGeneratorFn<Parser.ScopeDeclarationContext> = (
|
|
|
142
142
|
|
|
143
143
|
// ADR-017: Handle enum declarations inside scopes
|
|
144
144
|
// The enum generator will use state.currentScope which we've set via orchestrator
|
|
145
|
-
if (
|
|
145
|
+
// Issue #369: Skip enum definition if self-include was added (it will be in the header)
|
|
146
|
+
if (member.enumDeclaration() && !state.selfIncludeAdded) {
|
|
146
147
|
const enumDecl = member.enumDeclaration()!;
|
|
147
148
|
lines.push("");
|
|
148
149
|
lines.push(generateScopedEnumInline(enumDecl, name, input, orchestrator));
|
|
149
150
|
}
|
|
150
151
|
|
|
151
152
|
// ADR-034: Handle bitmap declarations inside scopes
|
|
152
|
-
if (
|
|
153
|
+
// Issue #369: Skip bitmap definition if self-include was added (it will be in the header)
|
|
154
|
+
if (member.bitmapDeclaration() && !state.selfIncludeAdded) {
|
|
153
155
|
const bitmapDecl = member.bitmapDeclaration()!;
|
|
154
156
|
lines.push("");
|
|
155
157
|
lines.push(generateScopedBitmapInline(bitmapDecl, name, input));
|