Skip to content

Commit f499353

Browse files
committed
Add extractor for array local variable declarations
1 parent b9e0a37 commit f499353

File tree

9 files changed

+115
-42
lines changed

9 files changed

+115
-42
lines changed
Lines changed: 61 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,101 @@
11
import {
2+
ArrayInitializerCtx,
23
BaseJavaCstVisitorWithDefaults,
34
BlockStatementCstNode,
5+
LocalVariableDeclarationCtx,
6+
LocalVariableDeclarationStatementCtx,
47
LocalVariableTypeCtx,
8+
VariableDeclaratorCtx,
59
VariableDeclaratorIdCtx,
10+
VariableDeclaratorListCtx,
611
VariableInitializerCtx,
12+
VariableInitializerListCtx,
713
} from "java-parser";
814
import {
915
BlockStatement,
10-
Expression,
16+
LocalVariableDeclarationStatement,
1117
VariableDeclarator,
1218
} from "../types/blocks-and-statements";
13-
import { Identifier, UnannType } from "../types/classes";
1419
import { ExpressionExtractor } from "./expression-extractor";
1520
import { StatementExtractor } from "./statement-extractor";
1621
import { TypeExtractor } from "./type-extractor";
1722

1823
export class BlockStatementExtractor extends BaseJavaCstVisitorWithDefaults {
19-
private type: UnannType;
20-
private identifier: Identifier[] = [];
21-
private value: Expression[] = [];
22-
2324
extract(cst: BlockStatementCstNode): BlockStatement {
2425
this.visit(cst);
2526
if (cst.children.localVariableDeclarationStatement) {
26-
const variableDeclaratorList = this.identifier.map(
27-
(identifier, index): VariableDeclarator => ({
28-
kind: "VariableDeclarator",
29-
variableDeclaratorId: identifier,
30-
variableInitializer: this.value[index],
31-
})
32-
);
33-
return {
34-
kind: "LocalVariableDeclarationStatement",
35-
localVariableType: this.type,
36-
variableDeclaratorList,
37-
location: cst.location,
38-
};
27+
return this.visit(cst.children.localVariableDeclarationStatement);
3928
} /* if (cst.children.statement) */ else {
4029
const statementExtractor = new StatementExtractor();
4130
return statementExtractor.extract(cst.children.statement![0]);
4231
}
4332
}
4433

34+
localVariableDeclarationStatement(
35+
ctx: LocalVariableDeclarationStatementCtx
36+
): LocalVariableDeclarationStatement {
37+
return {
38+
kind: "LocalVariableDeclarationStatement",
39+
...this.visit(ctx.localVariableDeclaration),
40+
};
41+
}
42+
43+
localVariableDeclaration(
44+
ctx: LocalVariableDeclarationCtx
45+
): Omit<LocalVariableDeclarationStatement, "kind"> {
46+
return {
47+
localVariableType: this.visit(ctx.localVariableType),
48+
variableDeclaratorList: this.visit(ctx.variableDeclaratorList),
49+
};
50+
}
51+
4552
localVariableType(ctx: LocalVariableTypeCtx) {
4653
const typeExtractor = new TypeExtractor();
4754
if (ctx.unannType) {
48-
this.type = typeExtractor.extract(ctx.unannType[0]);
55+
return typeExtractor.extract(ctx.unannType[0]);
56+
} else if (ctx.Var) {
57+
throw new Error("Not implemented");
4958
}
5059
}
5160

61+
variableDeclaratorList(ctx: VariableDeclaratorListCtx) {
62+
return ctx.variableDeclarator.map((variableDeclarator) => {
63+
return this.visit(variableDeclarator);
64+
});
65+
}
66+
67+
variableDeclarator(ctx: VariableDeclaratorCtx): VariableDeclarator {
68+
return {
69+
kind: "VariableDeclarator",
70+
variableDeclaratorId: this.visit(ctx.variableDeclaratorId),
71+
variableInitializer: ctx.variableInitializer
72+
? this.visit(ctx.variableInitializer)
73+
: undefined,
74+
};
75+
}
76+
5277
variableDeclaratorId(ctx: VariableDeclaratorIdCtx) {
53-
this.identifier.push(ctx.Identifier[0].image);
78+
return ctx.Identifier[0].image;
5479
}
5580

5681
variableInitializer(ctx: VariableInitializerCtx) {
5782
if (ctx.expression) {
5883
const expressionExtractor = new ExpressionExtractor();
59-
ctx.expression.forEach((expression) => {
60-
this.value.push(expressionExtractor.extract(expression));
61-
});
84+
return expressionExtractor.extract(ctx.expression[0]);
85+
} else if (ctx.arrayInitializer) {
86+
return this.visit(ctx.arrayInitializer);
6287
}
6388
}
89+
90+
arrayInitializer(ctx: ArrayInitializerCtx) {
91+
if (ctx.variableInitializerList) {
92+
return this.visit(ctx.variableInitializerList);
93+
}
94+
}
95+
96+
variableInitializerList(ctx: VariableInitializerListCtx) {
97+
return ctx.variableInitializer.map((variableInitializer) => {
98+
return this.visit(variableInitializer);
99+
});
100+
}
64101
}

src/types/checker/__tests__/arrays.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const testcases: {
1919
{
2020
input: `int[] numbers = {1, 2, 3, 4, 5};`,
2121
result: { type: null, errors: [] },
22+
only: true,
2223
},
2324
{
2425
input: `double[] values;`,

src/types/checker/arrays.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export const isArrayType = (typeDeclaration: string): boolean => {
2+
typeDeclaration = typeDeclaration.trim();
3+
if (typeDeclaration.length < 2) return false;
4+
const arraySuffix = typeDeclaration.slice(-2);
5+
return arraySuffix === "[]";
6+
};
7+
8+
export const removeArraySuffix = (typeDeclaration: string): string => {
9+
typeDeclaration = typeDeclaration.trim();
10+
if (!isArrayType(typeDeclaration)) return typeDeclaration;
11+
return typeDeclaration.substring(0, typeDeclaration.length - 2);
12+
};

src/types/checker/environment.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import * as Primitives from "../types/primitives";
33
import { Method } from "../types/methods";
44
import { Type } from "../types/type";
55
import { CannotFindSymbolError, VariableAlreadyDefinedError } from "../errors";
6+
import { isArrayType, removeArraySuffix } from "./arrays";
7+
import { Array } from "../types/arrays";
68

79
const GLOBAL_TYPE_ENVIRONMENT: { [key: string]: Type } = {
810
boolean: new Primitives.Boolean(),
@@ -60,6 +62,13 @@ export class Frame {
6062
}
6163

6264
public getType(name: string): Type | Error {
65+
if (isArrayType(name)) {
66+
const typePrefix = removeArraySuffix(name);
67+
const prefixType = this.getType(typePrefix);
68+
if (prefixType instanceof Error) return prefixType;
69+
return new Array(prefixType);
70+
}
71+
6372
let frame: Frame | null = this;
6473
while (frame) {
6574
const type = frame._types.get(name);

src/types/checker/index.ts

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ExpressionName } from "../../ast/types/blocks-and-statements";
12
import { Frame } from "./environment";
23
import { Method } from "../types/methods";
34
import { Node } from "../../ast/types/ast";
@@ -13,10 +14,6 @@ import {
1314
createMethod,
1415
createMethodSignature,
1516
} from "../typeFactories/methodFactory";
16-
import {
17-
Expression,
18-
ExpressionName,
19-
} from "../../ast/types/blocks-and-statements";
2017
import {
2118
Boolean,
2219
Char,
@@ -263,17 +260,19 @@ export const check = (
263260
const { variableInitializer } = variableDeclarator;
264261
if (!variableInitializer)
265262
throw new Error("Variable initializer is undefined.");
266-
const { currentType, errors } = check(
267-
variableInitializer as Expression,
268-
frame
269-
);
270-
if (errors.length > 0) return { currentType: null, errors };
271-
if (currentType == null)
272-
throw new Error(
273-
"Variable initializer in local variable declaration statement should return a type."
274-
);
275-
if (!declaredType.canBeAssigned(currentType))
276-
return newResult(null, [new IncompatibleTypesError()]);
263+
if (Array.isArray(variableInitializer)) {
264+
// Is array initializer
265+
} else {
266+
// Is not array initializer
267+
const { currentType, errors } = check(variableInitializer, frame);
268+
if (errors.length > 0) return { currentType: null, errors };
269+
if (currentType == null)
270+
throw new Error(
271+
"Variable initializer in local variable declaration statement should return a type."
272+
);
273+
if (!declaredType.canBeAssigned(currentType))
274+
return newResult(null, [new IncompatibleTypesError()]);
275+
}
277276
const error = frame.setVariable(
278277
variableDeclarator.variableDeclaratorId,
279278
declaredType

src/types/inputs/Main.class

-105 Bytes
Binary file not shown.

src/types/inputs/Main.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
public class Main {
2-
public static void main(String[] args) { getStringLength("Hello World!"); }
3-
public static String getStringLength(String input) { return 1; }
2+
public static void main(String[] args) {
3+
int test1, test2 = 1, 2;
4+
}
45
}

src/types/types/arrays.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { Type } from "./type";
2+
3+
export class Array extends Type {
4+
private _type: Type;
5+
constructor(type: Type) {
6+
super("array");
7+
this._type = type;
8+
}
9+
10+
public canBeAssigned(type: Type): boolean {
11+
if (!(type instanceof Array)) return false;
12+
return this._type.equals(type._type);
13+
}
14+
}

tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"moduleResolution": "node",
1111
"noImplicitAny": true,
1212
"noImplicitThis": true,
13-
"noImplicitReturns": true,
13+
"noImplicitReturns": false,
1414
"noUnusedLocals": true,
1515
"outDir": "./dist",
1616
"removeComments": false,

0 commit comments

Comments
 (0)