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
|
@@ -1117,4 +1117,204 @@ describe("FunctionCallAnalyzer", () => {
|
|
|
1117
1117
|
);
|
|
1118
1118
|
});
|
|
1119
1119
|
});
|
|
1120
|
+
|
|
1121
|
+
// ========================================================================
|
|
1122
|
+
// Issue #985: global. prefix function call validation
|
|
1123
|
+
// ========================================================================
|
|
1124
|
+
|
|
1125
|
+
describe("global prefix function calls (Issue #985)", () => {
|
|
1126
|
+
it("should detect undeclared global.func() call", () => {
|
|
1127
|
+
const code = `
|
|
1128
|
+
scope Test {
|
|
1129
|
+
void run() {
|
|
1130
|
+
u32 now <- global.millis();
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
`;
|
|
1134
|
+
const tree = parse(code);
|
|
1135
|
+
const analyzer = new FunctionCallAnalyzer();
|
|
1136
|
+
const errors = analyzer.analyze(tree);
|
|
1137
|
+
|
|
1138
|
+
expect(errors).toHaveLength(1);
|
|
1139
|
+
expect(errors[0].code).toBe("E0422");
|
|
1140
|
+
expect(errors[0].message).toContain("'millis'");
|
|
1141
|
+
expect(errors[0].message).toContain(
|
|
1142
|
+
"not declared in any included header",
|
|
1143
|
+
);
|
|
1144
|
+
expect(errors[0].message).toContain("#include <Arduino.h>");
|
|
1145
|
+
});
|
|
1146
|
+
|
|
1147
|
+
it("should detect undeclared global.func() with unknown function", () => {
|
|
1148
|
+
const code = `
|
|
1149
|
+
scope Test {
|
|
1150
|
+
void run() {
|
|
1151
|
+
u32 result <- global.unknownFunc();
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
`;
|
|
1155
|
+
const tree = parse(code);
|
|
1156
|
+
const analyzer = new FunctionCallAnalyzer();
|
|
1157
|
+
const errors = analyzer.analyze(tree);
|
|
1158
|
+
|
|
1159
|
+
expect(errors).toHaveLength(1);
|
|
1160
|
+
expect(errors[0].code).toBe("E0422");
|
|
1161
|
+
expect(errors[0].message).toContain("'unknownFunc'");
|
|
1162
|
+
expect(errors[0].message).toContain(
|
|
1163
|
+
"not declared in any included header",
|
|
1164
|
+
);
|
|
1165
|
+
expect(errors[0].message).not.toContain("#include");
|
|
1166
|
+
});
|
|
1167
|
+
|
|
1168
|
+
it("should allow global.func() when function is defined", () => {
|
|
1169
|
+
const code = `
|
|
1170
|
+
void helper() {
|
|
1171
|
+
u32 x <- 5;
|
|
1172
|
+
}
|
|
1173
|
+
scope Test {
|
|
1174
|
+
void run() {
|
|
1175
|
+
global.helper();
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
`;
|
|
1179
|
+
const tree = parse(code);
|
|
1180
|
+
const analyzer = new FunctionCallAnalyzer();
|
|
1181
|
+
const errors = analyzer.analyze(tree);
|
|
1182
|
+
|
|
1183
|
+
expect(errors).toHaveLength(0);
|
|
1184
|
+
});
|
|
1185
|
+
|
|
1186
|
+
it("should allow global.func() when header is included", () => {
|
|
1187
|
+
const code = `
|
|
1188
|
+
#include <Arduino.h>
|
|
1189
|
+
scope Test {
|
|
1190
|
+
void run() {
|
|
1191
|
+
u32 now <- global.millis();
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
`;
|
|
1195
|
+
const tree = parse(code);
|
|
1196
|
+
const analyzer = new FunctionCallAnalyzer();
|
|
1197
|
+
const errors = analyzer.analyze(tree);
|
|
1198
|
+
|
|
1199
|
+
expect(errors).toHaveLength(0);
|
|
1200
|
+
});
|
|
1201
|
+
|
|
1202
|
+
it("should allow global.Scope.method() when scope is defined", () => {
|
|
1203
|
+
const code = `
|
|
1204
|
+
scope Motor {
|
|
1205
|
+
public void start() {
|
|
1206
|
+
u32 x <- 5;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
scope Controller {
|
|
1210
|
+
void run() {
|
|
1211
|
+
global.Motor.start();
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
`;
|
|
1215
|
+
const tree = parse(code);
|
|
1216
|
+
const analyzer = new FunctionCallAnalyzer();
|
|
1217
|
+
const errors = analyzer.analyze(tree);
|
|
1218
|
+
|
|
1219
|
+
expect(errors).toHaveLength(0);
|
|
1220
|
+
});
|
|
1221
|
+
|
|
1222
|
+
it("should detect undeclared global.Scope.method() call", () => {
|
|
1223
|
+
const code = `
|
|
1224
|
+
scope Motor {
|
|
1225
|
+
public void start() {
|
|
1226
|
+
u32 x <- 5;
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
scope Controller {
|
|
1230
|
+
void run() {
|
|
1231
|
+
global.Motor.undefinedMethod();
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
`;
|
|
1235
|
+
const tree = parse(code);
|
|
1236
|
+
const analyzer = new FunctionCallAnalyzer();
|
|
1237
|
+
const errors = analyzer.analyze(tree);
|
|
1238
|
+
|
|
1239
|
+
expect(errors).toHaveLength(1);
|
|
1240
|
+
expect(errors[0].code).toBe("E0422");
|
|
1241
|
+
expect(errors[0].functionName).toBe("Motor_undefinedMethod");
|
|
1242
|
+
expect(errors[0].message).toContain("called before definition");
|
|
1243
|
+
expect(errors[0].message).not.toContain(
|
|
1244
|
+
"not declared in any included header",
|
|
1245
|
+
);
|
|
1246
|
+
});
|
|
1247
|
+
|
|
1248
|
+
it("should NOT resolve global.helper() to scope method Test_helper", () => {
|
|
1249
|
+
const code = `
|
|
1250
|
+
scope Test {
|
|
1251
|
+
void helper() {
|
|
1252
|
+
}
|
|
1253
|
+
void run() {
|
|
1254
|
+
global.helper();
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
`;
|
|
1258
|
+
const tree = parse(code);
|
|
1259
|
+
const symbolTable = new SymbolTable();
|
|
1260
|
+
|
|
1261
|
+
const analyzer = new FunctionCallAnalyzer();
|
|
1262
|
+
const errors = analyzer.analyze(tree, symbolTable);
|
|
1263
|
+
|
|
1264
|
+
expect(errors).toHaveLength(1);
|
|
1265
|
+
expect(errors[0].code).toBe("E0422");
|
|
1266
|
+
expect(errors[0].functionName).toBe("helper");
|
|
1267
|
+
});
|
|
1268
|
+
|
|
1269
|
+
it("should say 'called before definition' for global.func() on local function", () => {
|
|
1270
|
+
const code = `
|
|
1271
|
+
scope Test {
|
|
1272
|
+
void run() {
|
|
1273
|
+
global.helper();
|
|
1274
|
+
}
|
|
1275
|
+
}
|
|
1276
|
+
void helper() {
|
|
1277
|
+
}
|
|
1278
|
+
`;
|
|
1279
|
+
const tree = parse(code);
|
|
1280
|
+
const symbolTable = new SymbolTable();
|
|
1281
|
+
|
|
1282
|
+
const analyzer = new FunctionCallAnalyzer();
|
|
1283
|
+
const errors = analyzer.analyze(tree, symbolTable);
|
|
1284
|
+
|
|
1285
|
+
expect(errors).toHaveLength(1);
|
|
1286
|
+
expect(errors[0].code).toBe("E0422");
|
|
1287
|
+
expect(errors[0].message).toContain("called before definition");
|
|
1288
|
+
expect(errors[0].message).not.toContain(
|
|
1289
|
+
"not declared in any included header",
|
|
1290
|
+
);
|
|
1291
|
+
});
|
|
1292
|
+
|
|
1293
|
+
it("should allow global.func() for external C function", () => {
|
|
1294
|
+
const code = `
|
|
1295
|
+
scope Test {
|
|
1296
|
+
void run() {
|
|
1297
|
+
global.externalFunc();
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
1300
|
+
`;
|
|
1301
|
+
const tree = parse(code);
|
|
1302
|
+
const symbolTable = new SymbolTable();
|
|
1303
|
+
symbolTable.addCSymbol({
|
|
1304
|
+
name: "externalFunc",
|
|
1305
|
+
kind: "function",
|
|
1306
|
+
sourceLanguage: ESourceLanguage.C,
|
|
1307
|
+
sourceFile: "external.h",
|
|
1308
|
+
sourceLine: 1,
|
|
1309
|
+
isExported: true,
|
|
1310
|
+
type: "void",
|
|
1311
|
+
parameters: [],
|
|
1312
|
+
});
|
|
1313
|
+
|
|
1314
|
+
const analyzer = new FunctionCallAnalyzer();
|
|
1315
|
+
const errors = analyzer.analyze(tree, symbolTable);
|
|
1316
|
+
|
|
1317
|
+
expect(errors).toHaveLength(0);
|
|
1318
|
+
});
|
|
1319
|
+
});
|
|
1120
1320
|
});
|
|
@@ -822,7 +822,159 @@ describe("InitializationAnalyzer", () => {
|
|
|
822
822
|
});
|
|
823
823
|
|
|
824
824
|
// ========================================================================
|
|
825
|
-
// Group I:
|
|
825
|
+
// Group I: Compound Assignment (Issue #1012)
|
|
826
|
+
// ========================================================================
|
|
827
|
+
|
|
828
|
+
describe("compound assignment (Issue #1012)", () => {
|
|
829
|
+
it("should flag compound assignment on uninitialized variable", () => {
|
|
830
|
+
const code = `
|
|
831
|
+
void main() {
|
|
832
|
+
u32 sum;
|
|
833
|
+
sum +<- 5;
|
|
834
|
+
}
|
|
835
|
+
`;
|
|
836
|
+
const tree = parse(code);
|
|
837
|
+
const analyzer = new InitializationAnalyzer();
|
|
838
|
+
const errors = analyzer.analyze(tree);
|
|
839
|
+
|
|
840
|
+
expect(errors).toHaveLength(1);
|
|
841
|
+
expect(errors[0].code).toBe("E0381");
|
|
842
|
+
expect(errors[0].variable).toBe("sum");
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
it("should not flag compound assignment on initialized variable", () => {
|
|
846
|
+
const code = `
|
|
847
|
+
void main() {
|
|
848
|
+
u32 sum <- 0;
|
|
849
|
+
sum +<- 5;
|
|
850
|
+
}
|
|
851
|
+
`;
|
|
852
|
+
const tree = parse(code);
|
|
853
|
+
const analyzer = new InitializationAnalyzer();
|
|
854
|
+
const errors = analyzer.analyze(tree);
|
|
855
|
+
|
|
856
|
+
expect(errors).toHaveLength(0);
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
it("should flag compound assignment on uninitialized struct field", () => {
|
|
860
|
+
const code = `
|
|
861
|
+
struct Point {
|
|
862
|
+
u32 x;
|
|
863
|
+
u32 y;
|
|
864
|
+
}
|
|
865
|
+
void main() {
|
|
866
|
+
Point p;
|
|
867
|
+
p.x +<- 10;
|
|
868
|
+
}
|
|
869
|
+
`;
|
|
870
|
+
const tree = parse(code);
|
|
871
|
+
const analyzer = new InitializationAnalyzer();
|
|
872
|
+
const errors = analyzer.analyze(tree);
|
|
873
|
+
|
|
874
|
+
expect(errors).toHaveLength(1);
|
|
875
|
+
expect(errors[0].code).toBe("E0381");
|
|
876
|
+
expect(errors[0].variable).toContain("p.x");
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
it("should not flag compound assignment on initialized struct field", () => {
|
|
880
|
+
const code = `
|
|
881
|
+
struct Point {
|
|
882
|
+
u32 x;
|
|
883
|
+
u32 y;
|
|
884
|
+
}
|
|
885
|
+
void main() {
|
|
886
|
+
Point p <- {x: 10, y: 20};
|
|
887
|
+
p.x +<- 5;
|
|
888
|
+
}
|
|
889
|
+
`;
|
|
890
|
+
const tree = parse(code);
|
|
891
|
+
const analyzer = new InitializationAnalyzer();
|
|
892
|
+
const errors = analyzer.analyze(tree);
|
|
893
|
+
|
|
894
|
+
expect(errors).toHaveLength(0);
|
|
895
|
+
});
|
|
896
|
+
|
|
897
|
+
it("should flag all compound operators on uninitialized variable", () => {
|
|
898
|
+
const operators = [
|
|
899
|
+
"+<-",
|
|
900
|
+
"-<-",
|
|
901
|
+
"*<-",
|
|
902
|
+
"/<-",
|
|
903
|
+
"%<-",
|
|
904
|
+
"&<-",
|
|
905
|
+
"|<-",
|
|
906
|
+
"^<-",
|
|
907
|
+
"<<<-",
|
|
908
|
+
">><-",
|
|
909
|
+
];
|
|
910
|
+
|
|
911
|
+
for (const op of operators) {
|
|
912
|
+
const code = `
|
|
913
|
+
void main() {
|
|
914
|
+
u32 x;
|
|
915
|
+
x ${op} 1;
|
|
916
|
+
}
|
|
917
|
+
`;
|
|
918
|
+
const tree = parse(code);
|
|
919
|
+
const analyzer = new InitializationAnalyzer();
|
|
920
|
+
const errors = analyzer.analyze(tree);
|
|
921
|
+
|
|
922
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
923
|
+
expect(errors[0].code).toBe("E0381");
|
|
924
|
+
expect(errors[0].variable).toBe("x");
|
|
925
|
+
}
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
it("should not flag simple assignment on uninitialized variable", () => {
|
|
929
|
+
const code = `
|
|
930
|
+
void main() {
|
|
931
|
+
u32 x;
|
|
932
|
+
x <- 5;
|
|
933
|
+
u32 y <- x;
|
|
934
|
+
}
|
|
935
|
+
`;
|
|
936
|
+
const tree = parse(code);
|
|
937
|
+
const analyzer = new InitializationAnalyzer();
|
|
938
|
+
const errors = analyzer.analyze(tree);
|
|
939
|
+
|
|
940
|
+
// Simple assignment initializes the variable, so no error
|
|
941
|
+
expect(errors).toHaveLength(0);
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
it("should flag compound assignment on array element with uninitialized array", () => {
|
|
945
|
+
const code = `
|
|
946
|
+
void main() {
|
|
947
|
+
u32[4] arr;
|
|
948
|
+
arr[0] +<- 5;
|
|
949
|
+
}
|
|
950
|
+
`;
|
|
951
|
+
const tree = parse(code);
|
|
952
|
+
const analyzer = new InitializationAnalyzer();
|
|
953
|
+
const errors = analyzer.analyze(tree);
|
|
954
|
+
|
|
955
|
+
// Array is uninitialized, reading arr[0] for compound assignment is an error
|
|
956
|
+
expect(errors).toHaveLength(1);
|
|
957
|
+
expect(errors[0].code).toBe("E0381");
|
|
958
|
+
expect(errors[0].variable).toBe("arr");
|
|
959
|
+
});
|
|
960
|
+
|
|
961
|
+
it("should not flag compound assignment on array element with initialized array", () => {
|
|
962
|
+
const code = `
|
|
963
|
+
void main() {
|
|
964
|
+
u32[4] arr <- [1, 2, 3, 4];
|
|
965
|
+
arr[0] +<- 5;
|
|
966
|
+
}
|
|
967
|
+
`;
|
|
968
|
+
const tree = parse(code);
|
|
969
|
+
const analyzer = new InitializationAnalyzer();
|
|
970
|
+
const errors = analyzer.analyze(tree);
|
|
971
|
+
|
|
972
|
+
expect(errors).toHaveLength(0);
|
|
973
|
+
});
|
|
974
|
+
});
|
|
975
|
+
|
|
976
|
+
// ========================================================================
|
|
977
|
+
// Group J: C++ Non-Struct Symbol
|
|
826
978
|
// ========================================================================
|
|
827
979
|
|
|
828
980
|
describe("C++ non-struct symbol", () => {
|
|
@@ -854,4 +1006,237 @@ describe("InitializationAnalyzer", () => {
|
|
|
854
1006
|
expect(errors[0].variable).toBe("e");
|
|
855
1007
|
});
|
|
856
1008
|
});
|
|
1009
|
+
|
|
1010
|
+
// ========================================================================
|
|
1011
|
+
// Issue #1019: Scope Member Initialization
|
|
1012
|
+
// ========================================================================
|
|
1013
|
+
|
|
1014
|
+
describe("scope member initialization (Issue #1019)", () => {
|
|
1015
|
+
it("should allow reading scope member with inline initializer", () => {
|
|
1016
|
+
const code = `
|
|
1017
|
+
scope S {
|
|
1018
|
+
u32 value <- 42;
|
|
1019
|
+
public u32 get() { return value; }
|
|
1020
|
+
}
|
|
1021
|
+
void main() {
|
|
1022
|
+
u32 v <- S.get();
|
|
1023
|
+
}
|
|
1024
|
+
`;
|
|
1025
|
+
const tree = parse(code);
|
|
1026
|
+
const analyzer = new InitializationAnalyzer();
|
|
1027
|
+
const errors = analyzer.analyze(tree);
|
|
1028
|
+
|
|
1029
|
+
expect(errors).toHaveLength(0);
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
it("should allow reading scope member assigned in another function", () => {
|
|
1033
|
+
const code = `
|
|
1034
|
+
scope S {
|
|
1035
|
+
u32 value;
|
|
1036
|
+
public void init() { value <- 10; }
|
|
1037
|
+
public u32 get() { return value; }
|
|
1038
|
+
}
|
|
1039
|
+
void main() {
|
|
1040
|
+
S.init();
|
|
1041
|
+
u32 v <- S.get();
|
|
1042
|
+
}
|
|
1043
|
+
`;
|
|
1044
|
+
const tree = parse(code);
|
|
1045
|
+
const analyzer = new InitializationAnalyzer();
|
|
1046
|
+
const errors = analyzer.analyze(tree);
|
|
1047
|
+
|
|
1048
|
+
// value is assigned in init(), so get() can read it
|
|
1049
|
+
expect(errors).toHaveLength(0);
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
it("should flag uninitialized scope member read", () => {
|
|
1053
|
+
const code = `
|
|
1054
|
+
scope S {
|
|
1055
|
+
u32 value;
|
|
1056
|
+
public u32 get() { return value; }
|
|
1057
|
+
}
|
|
1058
|
+
void main() {
|
|
1059
|
+
u32 v <- S.get();
|
|
1060
|
+
}
|
|
1061
|
+
`;
|
|
1062
|
+
const tree = parse(code);
|
|
1063
|
+
const analyzer = new InitializationAnalyzer();
|
|
1064
|
+
const errors = analyzer.analyze(tree);
|
|
1065
|
+
|
|
1066
|
+
// value is never assigned - should error
|
|
1067
|
+
expect(errors.length).toBeGreaterThan(0);
|
|
1068
|
+
expect(errors[0].code).toBe("E0381");
|
|
1069
|
+
expect(errors[0].variable).toBe("value");
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1072
|
+
it("should detect assignment in do-while body", () => {
|
|
1073
|
+
const code = `
|
|
1074
|
+
scope S {
|
|
1075
|
+
u32 count;
|
|
1076
|
+
public void init() {
|
|
1077
|
+
u32 i <- 0;
|
|
1078
|
+
do {
|
|
1079
|
+
count <- i;
|
|
1080
|
+
i <- i + 1;
|
|
1081
|
+
} while (i < 1);
|
|
1082
|
+
}
|
|
1083
|
+
public u32 get() { return count; }
|
|
1084
|
+
}
|
|
1085
|
+
void main() {
|
|
1086
|
+
S.init();
|
|
1087
|
+
u32 c <- S.get();
|
|
1088
|
+
}
|
|
1089
|
+
`;
|
|
1090
|
+
const tree = parse(code);
|
|
1091
|
+
const analyzer = new InitializationAnalyzer();
|
|
1092
|
+
const errors = analyzer.analyze(tree);
|
|
1093
|
+
|
|
1094
|
+
// count is assigned inside do-while in init()
|
|
1095
|
+
expect(errors).toHaveLength(0);
|
|
1096
|
+
});
|
|
1097
|
+
|
|
1098
|
+
it("should detect assignment in if statement", () => {
|
|
1099
|
+
const code = `
|
|
1100
|
+
scope S {
|
|
1101
|
+
u32 value;
|
|
1102
|
+
public void set(bool flag) {
|
|
1103
|
+
if (flag = true) {
|
|
1104
|
+
value <- 1;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
public u32 get() { return value; }
|
|
1108
|
+
}
|
|
1109
|
+
void main() {
|
|
1110
|
+
S.set(true);
|
|
1111
|
+
u32 v <- S.get();
|
|
1112
|
+
}
|
|
1113
|
+
`;
|
|
1114
|
+
const tree = parse(code);
|
|
1115
|
+
const analyzer = new InitializationAnalyzer();
|
|
1116
|
+
const errors = analyzer.analyze(tree);
|
|
1117
|
+
|
|
1118
|
+
// value is assigned in if branch
|
|
1119
|
+
expect(errors).toHaveLength(0);
|
|
1120
|
+
});
|
|
1121
|
+
|
|
1122
|
+
it("should detect assignment in for loop", () => {
|
|
1123
|
+
const code = `
|
|
1124
|
+
scope S {
|
|
1125
|
+
u32 total;
|
|
1126
|
+
public void calc() {
|
|
1127
|
+
for (u32 i <- 0; i < 5; i <- i + 1) {
|
|
1128
|
+
total <- i;
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
public u32 get() { return total; }
|
|
1132
|
+
}
|
|
1133
|
+
void main() {
|
|
1134
|
+
S.calc();
|
|
1135
|
+
u32 t <- S.get();
|
|
1136
|
+
}
|
|
1137
|
+
`;
|
|
1138
|
+
const tree = parse(code);
|
|
1139
|
+
const analyzer = new InitializationAnalyzer();
|
|
1140
|
+
const errors = analyzer.analyze(tree);
|
|
1141
|
+
|
|
1142
|
+
// total is assigned in for loop
|
|
1143
|
+
expect(errors).toHaveLength(0);
|
|
1144
|
+
});
|
|
1145
|
+
|
|
1146
|
+
it("should detect assignment via this.member", () => {
|
|
1147
|
+
const code = `
|
|
1148
|
+
scope S {
|
|
1149
|
+
u32 data;
|
|
1150
|
+
public void set() { this.data <- 100; }
|
|
1151
|
+
public u32 get() { return data; }
|
|
1152
|
+
}
|
|
1153
|
+
void main() {
|
|
1154
|
+
S.set();
|
|
1155
|
+
u32 d <- S.get();
|
|
1156
|
+
}
|
|
1157
|
+
`;
|
|
1158
|
+
const tree = parse(code);
|
|
1159
|
+
const analyzer = new InitializationAnalyzer();
|
|
1160
|
+
const errors = analyzer.analyze(tree);
|
|
1161
|
+
|
|
1162
|
+
// data is assigned via this.data
|
|
1163
|
+
expect(errors).toHaveLength(0);
|
|
1164
|
+
});
|
|
1165
|
+
|
|
1166
|
+
it("should detect assignment in switch case", () => {
|
|
1167
|
+
const code = `
|
|
1168
|
+
scope S {
|
|
1169
|
+
u32 result;
|
|
1170
|
+
public void choose(u32 opt) {
|
|
1171
|
+
switch (opt) {
|
|
1172
|
+
case 1 { result <- 10; }
|
|
1173
|
+
case 2 { result <- 20; }
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
public u32 get() { return result; }
|
|
1177
|
+
}
|
|
1178
|
+
void main() {
|
|
1179
|
+
S.choose(1);
|
|
1180
|
+
u32 r <- S.get();
|
|
1181
|
+
}
|
|
1182
|
+
`;
|
|
1183
|
+
const tree = parse(code);
|
|
1184
|
+
const analyzer = new InitializationAnalyzer();
|
|
1185
|
+
const errors = analyzer.analyze(tree);
|
|
1186
|
+
|
|
1187
|
+
// result is assigned in switch cases
|
|
1188
|
+
expect(errors).toHaveLength(0);
|
|
1189
|
+
});
|
|
1190
|
+
|
|
1191
|
+
it("should detect assignment in while loop", () => {
|
|
1192
|
+
const code = `
|
|
1193
|
+
scope S {
|
|
1194
|
+
u32 counter;
|
|
1195
|
+
public void loop() {
|
|
1196
|
+
u32 i <- 0;
|
|
1197
|
+
while (i < 3) {
|
|
1198
|
+
counter <- i;
|
|
1199
|
+
i <- i + 1;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
public u32 get() { return counter; }
|
|
1203
|
+
}
|
|
1204
|
+
void main() {
|
|
1205
|
+
S.loop();
|
|
1206
|
+
u32 c <- S.get();
|
|
1207
|
+
}
|
|
1208
|
+
`;
|
|
1209
|
+
const tree = parse(code);
|
|
1210
|
+
const analyzer = new InitializationAnalyzer();
|
|
1211
|
+
const errors = analyzer.analyze(tree);
|
|
1212
|
+
|
|
1213
|
+
// counter is assigned in while loop
|
|
1214
|
+
expect(errors).toHaveLength(0);
|
|
1215
|
+
});
|
|
1216
|
+
|
|
1217
|
+
it("should detect assignment in switch default case", () => {
|
|
1218
|
+
const code = `
|
|
1219
|
+
scope S {
|
|
1220
|
+
u32 result;
|
|
1221
|
+
public void choose(u32 opt) {
|
|
1222
|
+
switch (opt) {
|
|
1223
|
+
case 1 { result <- 10; }
|
|
1224
|
+
default { result <- 99; }
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
public u32 get() { return result; }
|
|
1228
|
+
}
|
|
1229
|
+
void main() {
|
|
1230
|
+
S.choose(5);
|
|
1231
|
+
u32 r <- S.get();
|
|
1232
|
+
}
|
|
1233
|
+
`;
|
|
1234
|
+
const tree = parse(code);
|
|
1235
|
+
const analyzer = new InitializationAnalyzer();
|
|
1236
|
+
const errors = analyzer.analyze(tree);
|
|
1237
|
+
|
|
1238
|
+
// result is assigned in default case
|
|
1239
|
+
expect(errors).toHaveLength(0);
|
|
1240
|
+
});
|
|
1241
|
+
});
|
|
857
1242
|
});
|