Skip to content

Commit fbe7220

Browse files
authored
Merge pull request #42 from source-academy/csec/bugfix
CSEC Bug Fixes
2 parents fe3aded + 43fd72d commit fbe7220

File tree

3 files changed

+136
-15
lines changed

3 files changed

+136
-15
lines changed

src/ec-evaluator/__tests__/mtd-overloading.test.ts

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,4 +1211,117 @@ describe("evaluate method overloading correctly", () => {
12111211

12121212
expect(() => evaluate(context)).toThrowError(ResOverloadError);
12131213
});
1214+
1215+
it("should invoke inherited method", () => {
1216+
const programStr = `
1217+
class Parent {
1218+
static void test() {}
1219+
}
1220+
class Test extends Parent {
1221+
public static void main(String[] args) {
1222+
test();
1223+
}
1224+
}
1225+
`;
1226+
1227+
const compilationUnit = parse(programStr);
1228+
expect(compilationUnit).toBeTruthy();
1229+
1230+
const context = createContextStub();
1231+
context.control.push(compilationUnit!);
1232+
1233+
const result = evaluate(context);
1234+
1235+
const expectedControlTrace = [
1236+
"CompilationUnit",
1237+
1238+
"ExpressionStatement", // Test.main([""]);
1239+
"NormalClassDeclaration", // class Test extends Parent {...}
1240+
"NormalClassDeclaration", // class Parent {...}
1241+
"NormalClassDeclaration", // class Object {...}
1242+
1243+
"Env", // from NormalClassDeclaration
1244+
"ConstructorDeclaration", // Object() {...}
1245+
1246+
"Env", // from NormalClassDeclaration
1247+
"MethodDeclaration", // static void test() {...}
1248+
"ConstructorDeclaration", // Parent() {...}
1249+
1250+
"Env", // from NormalClassDeclaration
1251+
"MethodDeclaration", // public static void main(String[] args) {...}
1252+
"ConstructorDeclaration", // Test() {...}
1253+
1254+
"Pop",
1255+
"MethodInvocation", // Test.main([""])
1256+
1257+
"Invocation", // ()
1258+
"Literal", // [""]
1259+
"ResOverride",
1260+
"ExpressionName", // Test
1261+
"ResOverload", // main
1262+
"ResType", // [""]
1263+
"ResType", // Test
1264+
1265+
"Deref",
1266+
"EvalVariable", // Test
1267+
1268+
"Env", // from Invocation
1269+
"Marker",
1270+
"Block", // {...}
1271+
1272+
"Env", // from Block
1273+
"ReturnStatement", // return;
1274+
"ExpressionStatement", // Test.test();
1275+
1276+
"Pop",
1277+
"MethodInvocation", // Test.test()
1278+
1279+
"Invocation", // ()
1280+
"ResOverride",
1281+
"ExpressionName", // Test
1282+
"ResOverload", // test
1283+
"ResType", // Test
1284+
1285+
"Deref",
1286+
"EvalVariable", // Test
1287+
1288+
"Env", // from Invocation
1289+
"Marker",
1290+
"Block", // {...}
1291+
1292+
"Env", // from Block
1293+
"ReturnStatement", // return;
1294+
1295+
"Reset", // return
1296+
"Void",
1297+
1298+
"Reset", // Skip Env from Block
1299+
1300+
"Reset", // return
1301+
"Void",
1302+
1303+
"Reset", // Skip Env from Block
1304+
];
1305+
const expectedStashTrace = [
1306+
"Test", // ResType
1307+
"String[]", // ResType
1308+
"main", // ResOverload
1309+
"Test", // EvalVariable
1310+
"Test", // Deref
1311+
"main", // ResOverride
1312+
`[""]`, // Literal
1313+
"Test", // ResType
1314+
"test", // ResOverload
1315+
"Test", // EvalVariable
1316+
"Test", // Deref
1317+
"test", // ResOverride
1318+
"Void",
1319+
"Void",
1320+
];
1321+
1322+
expect(result).toEqual(undefined);
1323+
expect((context.control as ControlStub).getTrace().map(i => getControlItemStr(i))).toEqual(expectedControlTrace);
1324+
expect((context.stash as StashStub).getTrace().map(i => getStashItemStr(i))).toEqual(expectedStashTrace);
1325+
// TODO test env
1326+
});
12141327
});

src/ec-evaluator/interpreter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ export const evaluate = (context: Context, targetStep: number = STEP_LIMIT): Sta
103103
const control = context.control;
104104
const stash = context.stash;
105105

106-
context.totalSteps = 1;
106+
context.totalSteps = 0;
107107

108108
let command = control.peek();
109109

src/ec-evaluator/utils.ts

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -396,22 +396,30 @@ export const resOverload = (
396396
): Closure => {
397397
// Identify potentially applicable methods.
398398
const appClosures: Closure[] = [];
399-
for (const [closureName, closure] of classToSearchIn.frame.frame.entries()) {
400-
// Methods contains parantheses and must have return type.
401-
if (closureName.includes(mtdName + "(") && closureName[closureName.length - 1] !== ")") {
402-
const params = ((closure as Closure).mtdOrCon as MethodDeclaration).methodHeader.formalParameterList;
403-
404-
if (argTypes.length != params.length) continue;
405-
406-
let match = true;
407-
for (let i = 0; i < argTypes.length; i++) {
408-
match &&= (argTypes[i].type === params[i].unannType
409-
|| isSubtype(argTypes[i].type, params[i].unannType, classStore));
410-
if (!match) break; // short circuit
399+
let c: Class | undefined = classToSearchIn;
400+
while (c) {
401+
for (const [closureName, closure] of c.frame.frame.entries()) {
402+
// Methods contains parantheses and must have return type.
403+
if (closureName.includes(mtdName + "(") && closureName[closureName.length - 1] !== ")") {
404+
const params = ((closure as Closure).mtdOrCon as MethodDeclaration).methodHeader.formalParameterList;
405+
406+
if (argTypes.length != params.length) continue;
407+
408+
let match = true;
409+
for (let i = 0; i < argTypes.length; i++) {
410+
match &&= (argTypes[i].type === params[i].unannType
411+
|| isSubtype(argTypes[i].type, params[i].unannType, classStore));
412+
if (!match) break; // short circuit
413+
}
414+
415+
match && appClosures.push(closure as Closure);
411416
}
412-
413-
match && appClosures.push(closure as Closure);
414417
}
418+
419+
if (appClosures.length > 0) break;
420+
421+
// Search recursively.
422+
c = c.superclass;
415423
}
416424

417425
if (appClosures.length === 0) {

0 commit comments

Comments
 (0)