c-next 0.2.16 → 0.2.18
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 +18 -2
- package/dist/index.js +8897 -6260
- package/dist/index.js.map +4 -4
- package/grammar/CNext.g4 +12 -0
- package/package.json +4 -2
- package/src/transpiler/Transpiler.ts +376 -48
- package/src/transpiler/__tests__/DualCodePaths.test.ts +1 -1
- package/src/transpiler/__tests__/compileCommandsDiscovery.integration.test.ts +94 -0
- package/src/transpiler/__tests__/externalSymbolRecovery.integration.test.ts +215 -0
- package/src/transpiler/logic/__tests__/detectAssemblySyntax.test.ts +116 -0
- package/src/transpiler/logic/analysis/FunctionCallAnalyzer.ts +65 -10
- package/src/transpiler/logic/analysis/InitializationAnalyzer.ts +186 -14
- package/src/transpiler/logic/analysis/MixedTypeCategoryAnalyzer.ts +408 -0
- package/src/transpiler/logic/analysis/PassByValueAnalyzer.ts +16 -97
- package/src/transpiler/logic/analysis/ReturnPathAnalyzer.ts +171 -0
- package/src/transpiler/logic/analysis/SignedShiftAnalyzer.ts +124 -12
- package/src/transpiler/logic/analysis/__tests__/FunctionCallAnalyzer.test.ts +200 -0
- package/src/transpiler/logic/analysis/__tests__/InitializationAnalyzer.test.ts +386 -1
- package/src/transpiler/logic/analysis/__tests__/MixedTypeCategoryAnalyzer.test.ts +346 -0
- package/src/transpiler/logic/analysis/__tests__/ReturnPathAnalyzer.test.ts +232 -0
- package/src/transpiler/logic/analysis/__tests__/SignedShiftAnalyzer.test.ts +211 -0
- package/src/transpiler/logic/analysis/runAnalyzers.ts +23 -2
- package/src/transpiler/logic/analysis/types/IMixedTypeCategoryError.ts +17 -0
- package/src/transpiler/logic/analysis/types/IReturnPathError.ts +12 -0
- package/src/transpiler/logic/detectAssemblySyntax.ts +80 -0
- package/src/transpiler/logic/parser/grammar/CNext.interp +4 -1
- package/src/transpiler/logic/parser/grammar/CNext.tokens +169 -167
- package/src/transpiler/logic/parser/grammar/CNextLexer.interp +4 -1
- package/src/transpiler/logic/parser/grammar/CNextLexer.tokens +169 -167
- package/src/transpiler/logic/parser/grammar/CNextLexer.ts +545 -541
- package/src/transpiler/logic/parser/grammar/CNextListener.ts +11 -0
- package/src/transpiler/logic/parser/grammar/CNextParser.ts +1318 -1178
- package/src/transpiler/logic/parser/grammar/CNextVisitor.ts +7 -0
- package/src/transpiler/logic/preprocessor/CompileCommandsReader.ts +332 -0
- package/src/transpiler/logic/preprocessor/ExternalDeclarationOracle.ts +202 -0
- package/src/transpiler/logic/preprocessor/Preprocessor.ts +24 -6
- package/src/transpiler/logic/preprocessor/ToolchainDetector.ts +42 -1
- package/src/transpiler/logic/preprocessor/__tests__/CompileCommandsReader.test.ts +216 -0
- package/src/transpiler/logic/preprocessor/__tests__/ExternalDeclarationOracle.test.ts +153 -0
- package/src/transpiler/logic/preprocessor/__tests__/Preprocessor.test.ts +43 -18
- package/src/transpiler/logic/preprocessor/__tests__/ToolchainDetector.crossCompiler.test.ts +75 -0
- package/src/transpiler/logic/preprocessor/__tests__/fixtures/oracle/dependent.h +7 -0
- package/src/transpiler/logic/preprocessor/__tests__/fixtures/oracle/predecessor.h +5 -0
- package/src/transpiler/logic/preprocessor/types/ICompileCommandsResult.ts +14 -0
- package/src/transpiler/logic/preprocessor/types/IPreprocessOptions.ts +17 -0
- package/src/transpiler/logic/symbols/SymbolTable.ts +62 -2
- package/src/transpiler/logic/symbols/__tests__/SymbolTable.test.ts +55 -4
- package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +15 -2
- package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +64 -50
- package/src/transpiler/output/MisraSuppressionUtils.ts +52 -0
- package/src/transpiler/output/__tests__/MisraSuppressionUtils.test.ts +67 -0
- package/src/transpiler/output/codegen/CodeGenerator.ts +196 -98
- package/src/transpiler/output/codegen/TypeResolver.ts +148 -0
- package/src/transpiler/output/codegen/TypeValidator.ts +179 -81
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.coverage.test.ts +165 -17
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +163 -35
- package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +2 -2
- package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +93 -0
- package/src/transpiler/output/codegen/__tests__/TypeValidator.alwaysTrueLoop.test.ts +91 -0
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +97 -14
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +13 -0
- package/src/transpiler/output/codegen/assignment/AssignmentKind.ts +1 -1
- package/src/transpiler/output/codegen/assignment/handlers/AccessPatternHandlers.ts +20 -12
- package/src/transpiler/output/codegen/assignment/handlers/ArrayHandlers.ts +424 -22
- package/src/transpiler/output/codegen/assignment/handlers/BitAccessHandlers.ts +31 -18
- package/src/transpiler/output/codegen/assignment/handlers/BitmapHandlers.ts +7 -8
- package/src/transpiler/output/codegen/assignment/handlers/RegisterHandlers.ts +6 -8
- package/src/transpiler/output/codegen/assignment/handlers/RegisterUtils.ts +12 -10
- package/src/transpiler/output/codegen/assignment/handlers/SimpleHandler.ts +3 -7
- package/src/transpiler/output/codegen/assignment/handlers/SpecialHandlers.ts +7 -9
- package/src/transpiler/output/codegen/assignment/handlers/StringHandlers.ts +12 -10
- package/src/transpiler/output/codegen/assignment/handlers/__tests__/ArrayHandlers.test.ts +479 -11
- package/src/transpiler/output/codegen/generators/IOrchestrator.ts +3 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +26 -7
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +86 -0
- package/src/transpiler/output/codegen/generators/expressions/BinaryExprGenerator.ts +43 -24
- package/src/transpiler/output/codegen/generators/expressions/CallExprGenerator.ts +76 -58
- package/src/transpiler/output/codegen/generators/expressions/ExpressionGenerator.ts +9 -2
- package/src/transpiler/output/codegen/generators/expressions/PostfixExpressionGenerator.ts +26 -13
- package/src/transpiler/output/codegen/generators/expressions/__tests__/CallExprGenerator.test.ts +44 -0
- package/src/transpiler/output/codegen/generators/expressions/__tests__/ExpressionGenerator.test.ts +82 -1
- package/src/transpiler/output/codegen/generators/expressions/__tests__/PostfixExpressionGenerator.test.ts +129 -1
- package/src/transpiler/output/codegen/generators/statements/ControlFlowGenerator.ts +64 -8
- package/src/transpiler/output/codegen/generators/statements/__tests__/ControlFlowGenerator.test.ts +8 -5
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +30 -2
- package/src/transpiler/output/codegen/helpers/ParameterInputAdapter.ts +17 -3
- package/src/transpiler/output/codegen/helpers/ParameterSignatureBuilder.ts +17 -4
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +240 -42
- package/src/transpiler/output/codegen/helpers/SymbolLookupHelper.ts +0 -21
- package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +60 -39
- package/src/transpiler/output/codegen/helpers/TypeRegistrationEngine.ts +170 -36
- package/src/transpiler/output/codegen/helpers/VariableDeclHelper.ts +37 -39
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +19 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterInputAdapter.test.ts +117 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ParameterSignatureBuilder.test.ts +94 -2
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +322 -9
- package/src/transpiler/output/codegen/helpers/__tests__/SymbolLookupHelper.test.ts +0 -64
- package/src/transpiler/output/codegen/helpers/__tests__/TypeRegistrationEngine.test.ts +101 -0
- package/src/transpiler/output/codegen/helpers/__tests__/VariableDeclHelper.test.ts +29 -5
- package/src/transpiler/output/codegen/subscript/SubscriptClassifier.ts +30 -11
- package/src/transpiler/output/codegen/subscript/TSubscriptKind.ts +1 -1
- package/src/transpiler/output/codegen/subscript/__tests__/SubscriptClassifier.test.ts +38 -6
- package/src/transpiler/output/codegen/types/ICallbackTypeInfo.ts +2 -1
- package/src/transpiler/output/codegen/types/IParameterInput.ts +7 -0
- package/src/transpiler/output/headers/BaseHeaderGenerator.ts +8 -0
- package/src/transpiler/output/headers/HeaderGeneratorUtils.ts +140 -24
- package/src/transpiler/output/headers/__tests__/HeaderGeneratorUtils.test.ts +280 -0
- package/src/transpiler/output/headers/generators/IHeaderTypeInput.ts +13 -0
- package/src/transpiler/output/headers/generators/generateStructHeader.ts +48 -28
- package/src/transpiler/state/CodeGenState.ts +91 -22
- package/src/transpiler/state/__tests__/CodeGenState.test.ts +253 -11
- package/src/transpiler/types/ICachedFileEntry.ts +7 -0
- package/src/utils/LiteralUtils.ts +23 -0
- package/src/utils/__tests__/LiteralUtils.test.ts +101 -0
- package/src/utils/cache/CacheManager.ts +13 -2
- package/src/utils/cache/__tests__/CacheManager.test.ts +18 -1
- package/src/utils/constants/TypeConstants.ts +13 -0
- package/src/utils/types/IParameterSymbol.ts +1 -0
|
@@ -148,6 +148,7 @@ import EnumTypeResolver from "./resolution/EnumTypeResolver";
|
|
|
148
148
|
import ScopeResolver from "./resolution/ScopeResolver";
|
|
149
149
|
// Issue #797: Centralized C-style name generation
|
|
150
150
|
import QualifiedNameGenerator from "./utils/QualifiedNameGenerator";
|
|
151
|
+
import MisraSuppressionUtils from "../MisraSuppressionUtils";
|
|
151
152
|
|
|
152
153
|
const {
|
|
153
154
|
generateOverflowHelpers: helperGenerateOverflowHelpers,
|
|
@@ -299,6 +300,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
299
300
|
controlFlowGenerators.generateDoWhile,
|
|
300
301
|
);
|
|
301
302
|
this.registry.registerStatement("for", controlFlowGenerators.generateFor);
|
|
303
|
+
this.registry.registerStatement(
|
|
304
|
+
"forever",
|
|
305
|
+
controlFlowGenerators.generateForever,
|
|
306
|
+
);
|
|
302
307
|
this.registry.registerStatement("switch", switchGenerators.generateSwitch);
|
|
303
308
|
this.registry.registerStatement("critical", generateCriticalStatement);
|
|
304
309
|
|
|
@@ -726,6 +731,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
726
731
|
* Part of IOrchestrator interface.
|
|
727
732
|
* ADR-045: Used to detect string comparisons and generate strcmp().
|
|
728
733
|
* Issue #137: Extended to handle array element access (e.g., names[0])
|
|
734
|
+
* Issue #1030: Extended to handle struct member access (e.g., person.name)
|
|
729
735
|
*/
|
|
730
736
|
isStringExpression(ctx: Parser.RelationalExpressionContext): boolean {
|
|
731
737
|
const text = ctx.getText();
|
|
@@ -743,6 +749,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
743
749
|
}
|
|
744
750
|
}
|
|
745
751
|
|
|
752
|
+
// Issue #1030: Check for struct member access (e.g., person.name)
|
|
753
|
+
if (this._isStructMemberStringExpression(text)) {
|
|
754
|
+
return true;
|
|
755
|
+
}
|
|
756
|
+
|
|
746
757
|
// Issue #137: Check for array element access (e.g., names[0], arr[i])
|
|
747
758
|
return this._isArrayAccessStringExpression(text);
|
|
748
759
|
}
|
|
@@ -800,6 +811,59 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
800
811
|
);
|
|
801
812
|
}
|
|
802
813
|
|
|
814
|
+
/**
|
|
815
|
+
* Check if struct member access expression evaluates to a string.
|
|
816
|
+
* Issue #1030: Handles patterns like person.name, config.key
|
|
817
|
+
*/
|
|
818
|
+
private _isStructMemberStringExpression(text: string): boolean {
|
|
819
|
+
// Pattern: identifier.identifier (simple member access)
|
|
820
|
+
// Must not end with a property that returns a number
|
|
821
|
+
if (
|
|
822
|
+
text.endsWith(".char_count") ||
|
|
823
|
+
text.endsWith(".capacity") ||
|
|
824
|
+
text.endsWith(".size") ||
|
|
825
|
+
text.endsWith(".length") ||
|
|
826
|
+
text.endsWith(".bit_length") ||
|
|
827
|
+
text.endsWith(".byte_length") ||
|
|
828
|
+
text.endsWith(".element_count")
|
|
829
|
+
) {
|
|
830
|
+
return false;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
// Match simple struct.member pattern
|
|
834
|
+
const memberMatch = /^([a-zA-Z_]\w*)\.([a-zA-Z_]\w*)$/.exec(text);
|
|
835
|
+
if (!memberMatch) {
|
|
836
|
+
return false;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
const [, varName, fieldName] = memberMatch;
|
|
840
|
+
|
|
841
|
+
// Get the struct variable's type
|
|
842
|
+
const typeInfo = CodeGenState.getVariableTypeInfo(varName);
|
|
843
|
+
if (!typeInfo) {
|
|
844
|
+
return false;
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
// Get the struct type name - it might be directly the baseType
|
|
848
|
+
// or we might need to look it up by the variable's type
|
|
849
|
+
const structTypeName = typeInfo.baseType;
|
|
850
|
+
if (!structTypeName) {
|
|
851
|
+
return false;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
// Look up the field type from the struct
|
|
855
|
+
const fieldType = CodeGenState.getStructFieldType(
|
|
856
|
+
structTypeName,
|
|
857
|
+
fieldName,
|
|
858
|
+
);
|
|
859
|
+
if (!fieldType) {
|
|
860
|
+
return false;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
// Check if the field is a string type (e.g., "string<64>")
|
|
864
|
+
return fieldType.startsWith("string");
|
|
865
|
+
}
|
|
866
|
+
|
|
803
867
|
/**
|
|
804
868
|
* Get type of additive expression.
|
|
805
869
|
* Part of IOrchestrator interface - delegates to private implementation.
|
|
@@ -998,6 +1062,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
998
1062
|
result = this.generateDoWhile(ctx.doWhileStatement()!);
|
|
999
1063
|
} else if (ctx.forStatement()) {
|
|
1000
1064
|
result = this.generateFor(ctx.forStatement()!);
|
|
1065
|
+
} else if (ctx.foreverStatement()) {
|
|
1066
|
+
result = this.generateForever(ctx.foreverStatement()!);
|
|
1001
1067
|
} else if (ctx.switchStatement()) {
|
|
1002
1068
|
result = this.generateSwitch(ctx.switchStatement()!);
|
|
1003
1069
|
} else if (ctx.returnStatement()) {
|
|
@@ -1063,6 +1129,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1063
1129
|
TypeValidator.validateConditionIsBoolean(ctx, conditionType);
|
|
1064
1130
|
}
|
|
1065
1131
|
|
|
1132
|
+
/**
|
|
1133
|
+
* ADR-113 / #1075: reject an always-true literal loop condition (E0707).
|
|
1134
|
+
* Part of IOrchestrator interface.
|
|
1135
|
+
*/
|
|
1136
|
+
validateLoopConditionNotAlwaysTrue(ctx: Parser.ExpressionContext): void {
|
|
1137
|
+
TypeValidator.validateLoopConditionNotAlwaysTrue(ctx);
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1066
1140
|
/**
|
|
1067
1141
|
* Issue #254: Validate no function calls in condition (E0702).
|
|
1068
1142
|
* Part of IOrchestrator interface (ADR-053 A3).
|
|
@@ -1105,8 +1179,6 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1105
1179
|
|
|
1106
1180
|
// Issue #779: Resolve bare scope member identifiers before postfix chain processing
|
|
1107
1181
|
// This ensures scope members get their prefix even with array/member access.
|
|
1108
|
-
// Skip parameters - they don't need scope resolution and shouldn't be dereferenced
|
|
1109
|
-
// when used with array indexing (buf[idx] is valid C for pointer params).
|
|
1110
1182
|
// Also skip known registers - they should be handled by the postfix chain builder
|
|
1111
1183
|
// to enable proper register validation (requiring global. when shadowed).
|
|
1112
1184
|
let resolvedIdentifier = identifier ?? "";
|
|
@@ -1115,7 +1187,24 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1115
1187
|
const isLocalVariable = CodeGenState.localVariables.has(identifier);
|
|
1116
1188
|
const isKnownRegister =
|
|
1117
1189
|
CodeGenState.symbols?.knownRegisters.has(identifier);
|
|
1118
|
-
|
|
1190
|
+
// Issue #1100: Parameters with postfix ops (array/bit subscript, member
|
|
1191
|
+
// access) must resolve through the same dereference logic as a bare
|
|
1192
|
+
// parameter reference (ParameterDereferenceResolver), not skip it.
|
|
1193
|
+
// For array/struct/string/etc. parameters this is a no-op (they're
|
|
1194
|
+
// already pointer-like, matching the prior behavior verbatim — e.g.
|
|
1195
|
+
// `buf[idx]` stays `buf[idx]`). For a scalar parameter that became a
|
|
1196
|
+
// pointer because it's modified elsewhere in the function, a bit
|
|
1197
|
+
// access (`v[4] <- true`) now correctly dereferences to `(*v)[4]`
|
|
1198
|
+
// (which AssignmentContextBuilder reduces to base identifier `(*v)`)
|
|
1199
|
+
// instead of assigning through the raw pointer.
|
|
1200
|
+
if (isParameter) {
|
|
1201
|
+
const paramInfo = CodeGenState.currentParameters.get(identifier)!;
|
|
1202
|
+
resolvedIdentifier = ParameterDereferenceResolver.resolve(
|
|
1203
|
+
identifier,
|
|
1204
|
+
paramInfo,
|
|
1205
|
+
this._buildParameterDereferenceDeps(),
|
|
1206
|
+
);
|
|
1207
|
+
} else if (!isLocalVariable && !isKnownRegister) {
|
|
1119
1208
|
const resolved = TypeValidator.resolveBareIdentifier(
|
|
1120
1209
|
identifier,
|
|
1121
1210
|
false, // not local
|
|
@@ -1311,9 +1400,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1311
1400
|
* ADR-017: Handle enum types by initializing to first member
|
|
1312
1401
|
*/
|
|
1313
1402
|
getZeroInitializer(typeCtx: Parser.TypeContext, isArray: boolean): string {
|
|
1314
|
-
// Issue #379:
|
|
1403
|
+
// Issue #379 / #1004: arrays zero-init with the aggregate brace ({} in
|
|
1404
|
+
// C++, {0} in C) regardless of element type.
|
|
1315
1405
|
if (isArray) {
|
|
1316
|
-
return this.
|
|
1406
|
+
return this._getAggregateZeroInitBrace();
|
|
1317
1407
|
}
|
|
1318
1408
|
|
|
1319
1409
|
// Handle named types (scoped, global, qualified, user)
|
|
@@ -1323,11 +1413,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1323
1413
|
if (CodeGenState.symbols!.knownEnums.has(resolved.name)) {
|
|
1324
1414
|
return this._getEnumZeroValue(resolved.name, resolved.separator);
|
|
1325
1415
|
}
|
|
1326
|
-
//
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
return "{0}";
|
|
1416
|
+
// Issue #1004: struct/class zero-init. C++ value-initialization ({})
|
|
1417
|
+
// works for every aggregate (including ones whose first field is an
|
|
1418
|
+
// enum, where {0} is an invalid int->enum narrowing); C uses {0}.
|
|
1419
|
+
return this._getAggregateZeroInitBrace();
|
|
1331
1420
|
}
|
|
1332
1421
|
|
|
1333
1422
|
// Issue #295: C++ template types use value initialization {}
|
|
@@ -1335,6 +1424,11 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1335
1424
|
return "{}";
|
|
1336
1425
|
}
|
|
1337
1426
|
|
|
1427
|
+
// Issue #1019: string<N> types use empty string initializer
|
|
1428
|
+
if (typeCtx.stringType()) {
|
|
1429
|
+
return '""';
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1338
1432
|
// Primitive types use lookup map
|
|
1339
1433
|
if (typeCtx.primitiveType()) {
|
|
1340
1434
|
const primType = typeCtx.primitiveType()!.getText();
|
|
@@ -1490,9 +1584,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1490
1584
|
if (p.isArray) {
|
|
1491
1585
|
// Array parameters: type name[]
|
|
1492
1586
|
return `${constMod}${p.type} ${p.name}${p.arrayDims}`;
|
|
1493
|
-
} else if (p.
|
|
1494
|
-
// ADR-006:
|
|
1495
|
-
//
|
|
1587
|
+
} else if (p.isStruct) {
|
|
1588
|
+
// ADR-006: Struct parameters become pointers (C) or references (C++)
|
|
1589
|
+
// Only struct types get pointer/reference semantics, not primitives
|
|
1496
1590
|
const ptrOrRef = this.isCppMode() ? "&" : "*";
|
|
1497
1591
|
return `${constMod}${p.type}${ptrOrRef}`;
|
|
1498
1592
|
} else {
|
|
@@ -1776,7 +1870,17 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
1776
1870
|
}
|
|
1777
1871
|
|
|
1778
1872
|
if (ctx.IDENTIFIER()) {
|
|
1779
|
-
|
|
1873
|
+
const id = ctx.IDENTIFIER()!.getText();
|
|
1874
|
+
// Issue #1011: break/continue are not part of C-Next - use structured conditions
|
|
1875
|
+
// ADR-026 (Status: Rejected) explicitly excludes break/continue from the language
|
|
1876
|
+
if (id === "break" || id === "continue") {
|
|
1877
|
+
const line = ctx.start?.line ?? 0;
|
|
1878
|
+
const col = ctx.start?.column ?? 0;
|
|
1879
|
+
throw new Error(
|
|
1880
|
+
`${line}:${col} error[E0703]: '${id}' is not supported in C-Next - use structured conditions instead`,
|
|
1881
|
+
);
|
|
1882
|
+
}
|
|
1883
|
+
return this._resolveIdentifierExpression(id);
|
|
1780
1884
|
}
|
|
1781
1885
|
if (ctx.literal()) {
|
|
1782
1886
|
return this._generateLiteralExpression(ctx.literal()!);
|
|
@@ -2085,15 +2189,6 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2085
2189
|
return identifiers.join("_");
|
|
2086
2190
|
}
|
|
2087
2191
|
|
|
2088
|
-
/**
|
|
2089
|
-
* Issue #304: Check if a type name is from a C++ header
|
|
2090
|
-
* Used to determine whether to use {} or {0} for initialization.
|
|
2091
|
-
* C++ types with constructors may fail with {0} but work with {}.
|
|
2092
|
-
*/
|
|
2093
|
-
private isCppType(typeName: string): boolean {
|
|
2094
|
-
return SymbolLookupHelper.isCppType(CodeGenState.symbolTable, typeName);
|
|
2095
|
-
}
|
|
2096
|
-
|
|
2097
2192
|
/**
|
|
2098
2193
|
* Generate C code from a C-Next program
|
|
2099
2194
|
* @param tree The parsed C-Next program
|
|
@@ -2297,7 +2392,14 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2297
2392
|
includePaths,
|
|
2298
2393
|
);
|
|
2299
2394
|
|
|
2300
|
-
|
|
2395
|
+
// Issue #850: Add MISRA suppression for banned headers
|
|
2396
|
+
const includeText = includeDir.getText();
|
|
2397
|
+
const suppression =
|
|
2398
|
+
MisraSuppressionUtils.getMisraSuppressionComment(includeText);
|
|
2399
|
+
if (suppression) {
|
|
2400
|
+
output.push(suppression);
|
|
2401
|
+
}
|
|
2402
|
+
output.push(this.transformIncludeDirective(includeText));
|
|
2301
2403
|
}
|
|
2302
2404
|
|
|
2303
2405
|
if (tree.includeDirective().length > 0) {
|
|
@@ -2689,6 +2791,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2689
2791
|
type: string;
|
|
2690
2792
|
isConst: boolean;
|
|
2691
2793
|
isPointer: boolean;
|
|
2794
|
+
isStruct: boolean;
|
|
2692
2795
|
isArray: boolean;
|
|
2693
2796
|
arrayDims: string;
|
|
2694
2797
|
}> = [];
|
|
@@ -2704,6 +2807,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2704
2807
|
|
|
2705
2808
|
// ADR-029: Check if parameter type is itself a callback type
|
|
2706
2809
|
const isCallbackParam = CodeGenState.callbackTypes.has(typeName);
|
|
2810
|
+
// ADR-006: Check if parameter type is a struct (for pointer/reference semantics)
|
|
2811
|
+
const isStruct = this.isStructType(typeName);
|
|
2707
2812
|
|
|
2708
2813
|
let paramType: string;
|
|
2709
2814
|
let isPointer: boolean;
|
|
@@ -2715,8 +2820,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2715
2820
|
isPointer = false; // Function pointers are already pointers
|
|
2716
2821
|
} else {
|
|
2717
2822
|
paramType = this.generateType(param.type());
|
|
2718
|
-
// ADR-006: Non-array parameters become pointers
|
|
2719
|
-
isPointer = !isArray;
|
|
2823
|
+
// ADR-006: Non-array struct parameters become pointers in C mode
|
|
2824
|
+
isPointer = !isArray && isStruct;
|
|
2720
2825
|
}
|
|
2721
2826
|
|
|
2722
2827
|
let arrayDims: string;
|
|
@@ -2739,6 +2844,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
2739
2844
|
type: paramType,
|
|
2740
2845
|
isConst,
|
|
2741
2846
|
isPointer,
|
|
2847
|
+
isStruct,
|
|
2742
2848
|
isArray,
|
|
2743
2849
|
arrayDims,
|
|
2744
2850
|
});
|
|
@@ -3211,7 +3317,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3211
3317
|
decl += this._getStringCapacityDimension(varDecl.type());
|
|
3212
3318
|
|
|
3213
3319
|
if (varDecl.expression()) {
|
|
3214
|
-
decl += ` = ${this.generateExpression(varDecl.expression()!)}`;
|
|
3320
|
+
decl += ` = ${CodeGenState.withDeclarationInit(() => this.generateExpression(varDecl.expression()!))}`;
|
|
3215
3321
|
} else {
|
|
3216
3322
|
// ADR-015: Zero initialization for uninitialized scope variables
|
|
3217
3323
|
decl += ` = ${this.getZeroInitializer(varDecl.type(), isArray)}`;
|
|
@@ -3495,8 +3601,9 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3495
3601
|
);
|
|
3496
3602
|
|
|
3497
3603
|
if (!fieldList) {
|
|
3498
|
-
// Empty initializer: Point {} ->
|
|
3499
|
-
|
|
3604
|
+
// Empty initializer: Point {} -> { 0 } in declaration context, (Point){ 0 } elsewhere
|
|
3605
|
+
if (isCppClass) return "{}";
|
|
3606
|
+
return CodeGenState.inDeclarationInit ? "{ 0 }" : `(${castType}){ 0 }`;
|
|
3500
3607
|
}
|
|
3501
3608
|
|
|
3502
3609
|
// Get field type info for nested initializers
|
|
@@ -3507,28 +3614,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3507
3614
|
|
|
3508
3615
|
const fields = fieldList.fieldInitializer().map((field) => {
|
|
3509
3616
|
const fieldName = field.IDENTIFIER().getText();
|
|
3510
|
-
|
|
3511
|
-
// Compute expected type for nested initializers
|
|
3512
|
-
let fieldType: string | undefined;
|
|
3513
|
-
if (structFieldTypes?.has(fieldName)) {
|
|
3514
|
-
// Issue #502: Convert underscore format to correct output format
|
|
3515
|
-
// C-Next struct fields may store C++ types with _ separator (e.g., SeaDash_Parse_ParseResult)
|
|
3516
|
-
// but code generation needs :: for C++ types (e.g., SeaDash::Parse::ParseResult)
|
|
3517
|
-
fieldType = structFieldTypes.get(fieldName)!;
|
|
3518
|
-
if (fieldType.includes("_")) {
|
|
3519
|
-
// Check if this looks like a qualified type (contains _) and convert
|
|
3520
|
-
const parts = fieldType.split("_");
|
|
3521
|
-
if (parts.length > 1 && this.isCppScopeSymbol(parts[0])) {
|
|
3522
|
-
// It's a C++ namespaced type - convert _ to ::
|
|
3523
|
-
fieldType = parts.join("::");
|
|
3524
|
-
}
|
|
3525
|
-
}
|
|
3526
|
-
}
|
|
3527
|
-
|
|
3617
|
+
const fieldType = this._resolveFieldType(fieldName, structFieldTypes);
|
|
3528
3618
|
const value = CodeGenState.withExpectedType(fieldType, () =>
|
|
3529
3619
|
this.generateExpression(field.expression()),
|
|
3530
3620
|
);
|
|
3531
|
-
|
|
3532
3621
|
return { fieldName, value };
|
|
3533
3622
|
});
|
|
3534
3623
|
|
|
@@ -3545,6 +3634,23 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3545
3634
|
// For C-Next/C structs, generate designated initializer
|
|
3546
3635
|
const fieldInits = fields.map((f) => `.${f.fieldName} = ${f.value}`);
|
|
3547
3636
|
|
|
3637
|
+
return this.formatStructInitializer(typeName, castType, fieldInits);
|
|
3638
|
+
}
|
|
3639
|
+
|
|
3640
|
+
private formatStructInitializer(
|
|
3641
|
+
typeName: string,
|
|
3642
|
+
castType: string,
|
|
3643
|
+
fieldInits: string[],
|
|
3644
|
+
): string {
|
|
3645
|
+
const initializer: string = `{ ${fieldInits.join(", ")} }`;
|
|
3646
|
+
|
|
3647
|
+
// In a declaration initializer context, use plain designated initializer — no type cast
|
|
3648
|
+
// prefix needed, and compound literals are not C99 constant expressions so they fail
|
|
3649
|
+
// at file scope on GCC < 13.
|
|
3650
|
+
if (CodeGenState.inDeclarationInit) {
|
|
3651
|
+
return initializer;
|
|
3652
|
+
}
|
|
3653
|
+
|
|
3548
3654
|
// Issue #882: In C++ mode, anonymous structs/unions must use plain brace init.
|
|
3549
3655
|
// Compound literals like (struct { ... }){ ... } create incompatible types in C++
|
|
3550
3656
|
// because each struct { ... } definition creates a distinct nominal type.
|
|
@@ -3552,10 +3658,33 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3552
3658
|
CodeGenState.cppMode &&
|
|
3553
3659
|
(typeName.startsWith("struct {") || typeName.startsWith("union {"))
|
|
3554
3660
|
) {
|
|
3555
|
-
return
|
|
3661
|
+
return initializer;
|
|
3662
|
+
}
|
|
3663
|
+
|
|
3664
|
+
if (!CodeGenState.inFunctionBody) {
|
|
3665
|
+
return initializer;
|
|
3556
3666
|
}
|
|
3557
3667
|
|
|
3558
|
-
return `(${castType})
|
|
3668
|
+
return `(${castType})${initializer}`;
|
|
3669
|
+
}
|
|
3670
|
+
|
|
3671
|
+
/**
|
|
3672
|
+
* Resolve the C type string for a named struct field, converting C++ underscore-separated
|
|
3673
|
+
* names to :: notation. Returns undefined if the field is not in the type map.
|
|
3674
|
+
* Issue #502: C-Next stores C++ types with _ separator; codegen needs ::.
|
|
3675
|
+
*/
|
|
3676
|
+
private _resolveFieldType(
|
|
3677
|
+
fieldName: string,
|
|
3678
|
+
structFieldTypes: Map<string, string> | undefined,
|
|
3679
|
+
): string | undefined {
|
|
3680
|
+
if (!structFieldTypes?.has(fieldName)) return undefined;
|
|
3681
|
+
const fieldType = structFieldTypes.get(fieldName)!;
|
|
3682
|
+
if (!fieldType.includes("_")) return fieldType;
|
|
3683
|
+
const parts = fieldType.split("_");
|
|
3684
|
+
if (parts.length > 1 && this.isCppScopeSymbol(parts[0])) {
|
|
3685
|
+
return parts.join("::");
|
|
3686
|
+
}
|
|
3687
|
+
return fieldType;
|
|
3559
3688
|
}
|
|
3560
3689
|
|
|
3561
3690
|
/**
|
|
@@ -3776,6 +3905,8 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
3776
3905
|
forceConst,
|
|
3777
3906
|
isTypedefStructType: (t) =>
|
|
3778
3907
|
CodeGenState.symbolTable?.isTypedefStructType(t) ?? false,
|
|
3908
|
+
// Issue #995: Opaque handles should not get auto-const
|
|
3909
|
+
isOpaqueType: (t) => CodeGenState.isOpaqueType(t),
|
|
3779
3910
|
});
|
|
3780
3911
|
|
|
3781
3912
|
// Use shared builder with C/C++ mode
|
|
@@ -4102,31 +4233,13 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4102
4233
|
// and _generateConstructorDecl have been extracted to VariableDeclHelper.ts
|
|
4103
4234
|
|
|
4104
4235
|
/**
|
|
4105
|
-
*
|
|
4106
|
-
* Issue #379: C++
|
|
4236
|
+
* Brace initializer that zero-initializes an aggregate (struct or array).
|
|
4237
|
+
* Issue #379 / #1004: C++ uses value-initialization ({}), which is valid for
|
|
4238
|
+
* any aggregate element type (POD, struct, class) including enum-first
|
|
4239
|
+
* structs where {0} is an invalid int->enum narrowing; C uses {0}.
|
|
4107
4240
|
*/
|
|
4108
|
-
private
|
|
4109
|
-
|
|
4110
|
-
if (typeCtx.userType()) {
|
|
4111
|
-
const typeName = typeCtx.userType()!.getText();
|
|
4112
|
-
if (this._needsEmptyBraceInit(typeName)) {
|
|
4113
|
-
return "{}";
|
|
4114
|
-
}
|
|
4115
|
-
}
|
|
4116
|
-
// Also check C-Next style array type (e.g., CppClass[4]) where
|
|
4117
|
-
// the userType is nested inside arrayType.
|
|
4118
|
-
if (typeCtx.arrayType()?.userType()) {
|
|
4119
|
-
const typeName = typeCtx.arrayType()!.userType()!.getText();
|
|
4120
|
-
if (this._needsEmptyBraceInit(typeName)) {
|
|
4121
|
-
return "{}";
|
|
4122
|
-
}
|
|
4123
|
-
}
|
|
4124
|
-
// Template types are always C++ classes
|
|
4125
|
-
if (typeCtx.templateType()) {
|
|
4126
|
-
return "{}";
|
|
4127
|
-
}
|
|
4128
|
-
// Default: POD arrays use {0}
|
|
4129
|
-
return "{0}";
|
|
4241
|
+
private _getAggregateZeroInitBrace(): string {
|
|
4242
|
+
return CodeGenState.cppMode ? "{}" : "{0}";
|
|
4130
4243
|
}
|
|
4131
4244
|
|
|
4132
4245
|
/**
|
|
@@ -4158,20 +4271,19 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4158
4271
|
|
|
4159
4272
|
/**
|
|
4160
4273
|
* Resolve full type name from any TypeContext variant.
|
|
4161
|
-
* Returns { name, separator
|
|
4274
|
+
* Returns { name, separator } or null if not a named type.
|
|
4162
4275
|
* ADR-016: Handles scoped, global, qualified, and user types
|
|
4163
|
-
* checkCppType: only true for userType (original behavior preserved)
|
|
4164
4276
|
*/
|
|
4165
4277
|
private _resolveTypeNameFromContext(
|
|
4166
4278
|
typeCtx: Parser.TypeContext,
|
|
4167
|
-
): { name: string; separator: string
|
|
4279
|
+
): { name: string; separator: string } | null {
|
|
4168
4280
|
// ADR-016: Check for scoped types (this.Type)
|
|
4169
4281
|
if (typeCtx.scopedType()) {
|
|
4170
4282
|
const localName = typeCtx.scopedType()!.IDENTIFIER().getText();
|
|
4171
4283
|
const name = CodeGenState.currentScope
|
|
4172
4284
|
? `${CodeGenState.currentScope}_${localName}`
|
|
4173
4285
|
: localName;
|
|
4174
|
-
return { name, separator: "_"
|
|
4286
|
+
return { name, separator: "_" };
|
|
4175
4287
|
}
|
|
4176
4288
|
|
|
4177
4289
|
// Issue #478: Check for global types (global.Type)
|
|
@@ -4179,7 +4291,6 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4179
4291
|
return {
|
|
4180
4292
|
name: typeCtx.globalType()!.IDENTIFIER().getText(),
|
|
4181
4293
|
separator: "_",
|
|
4182
|
-
checkCppType: false,
|
|
4183
4294
|
};
|
|
4184
4295
|
}
|
|
4185
4296
|
|
|
@@ -4189,7 +4300,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4189
4300
|
const parts = typeCtx.qualifiedType()!.IDENTIFIER();
|
|
4190
4301
|
const name = this.resolveQualifiedType(parts.map((id) => id.getText()));
|
|
4191
4302
|
const separator = name.includes("::") ? "::" : "_";
|
|
4192
|
-
return { name, separator
|
|
4303
|
+
return { name, separator };
|
|
4193
4304
|
}
|
|
4194
4305
|
|
|
4195
4306
|
// Check for user-defined types (structs/classes/enums)
|
|
@@ -4197,28 +4308,12 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4197
4308
|
return {
|
|
4198
4309
|
name: typeCtx.userType()!.getText(),
|
|
4199
4310
|
separator: "_",
|
|
4200
|
-
checkCppType: true,
|
|
4201
4311
|
};
|
|
4202
4312
|
}
|
|
4203
4313
|
|
|
4204
4314
|
return null;
|
|
4205
4315
|
}
|
|
4206
4316
|
|
|
4207
|
-
/**
|
|
4208
|
-
* Check if a type needs empty brace initialization {}.
|
|
4209
|
-
* Issue #304: C++ types with constructors may fail with {0}
|
|
4210
|
-
* Issue #309: Unknown user types in C++ mode may have non-trivial constructors
|
|
4211
|
-
*/
|
|
4212
|
-
private _needsEmptyBraceInit(typeName: string): boolean {
|
|
4213
|
-
// C++ types (external libraries with constructors)
|
|
4214
|
-
if (this.isCppType(typeName)) {
|
|
4215
|
-
return true;
|
|
4216
|
-
}
|
|
4217
|
-
// In C++ mode, unknown user types may have non-trivial constructors
|
|
4218
|
-
// Known structs (C-Next or C headers) are POD types where {0} works
|
|
4219
|
-
return CodeGenState.cppMode && !this.isKnownStruct(typeName);
|
|
4220
|
-
}
|
|
4221
|
-
|
|
4222
4317
|
/**
|
|
4223
4318
|
* Generate a safe bit mask expression.
|
|
4224
4319
|
* Avoids undefined behavior when width >= 32 for 32-bit integers.
|
|
@@ -4461,6 +4556,10 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4461
4556
|
return this.invokeStatement("for", ctx);
|
|
4462
4557
|
}
|
|
4463
4558
|
|
|
4559
|
+
private generateForever(ctx: Parser.ForeverStatementContext): string {
|
|
4560
|
+
return this.invokeStatement("forever", ctx);
|
|
4561
|
+
}
|
|
4562
|
+
|
|
4464
4563
|
private generateReturn(ctx: Parser.ReturnStatementContext): string {
|
|
4465
4564
|
return this.invokeStatement("return", ctx);
|
|
4466
4565
|
}
|
|
@@ -4750,8 +4849,7 @@ export default class CodeGenerator implements IOrchestrator {
|
|
|
4750
4849
|
// MISRA 10.3: Cast limit macros to target type (they have type 'int')
|
|
4751
4850
|
const finalCast = CppModeHelper.cast(targetType, `(${expr})`);
|
|
4752
4851
|
const castMax = CppModeHelper.cast(targetType, maxValue);
|
|
4753
|
-
const castMin =
|
|
4754
|
-
minValue === "0" ? "0" : CppModeHelper.cast(targetType, minValue);
|
|
4852
|
+
const castMin = CppModeHelper.cast(targetType, minValue);
|
|
4755
4853
|
return `((${expr}) > ${maxComparison} ? ${castMax} : (${expr}) < ${minComparison} ? ${castMin} : ${finalCast})`;
|
|
4756
4854
|
}
|
|
4757
4855
|
|