Skip to content

Commit 425581b

Browse files
authored
Merge pull request #37 from source-academy/bryan/typechecking
Add type checking features
2 parents 8a4d420 + 74db126 commit 425581b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+4645
-1435
lines changed

.eslintignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,5 @@ node_modules
22
dist
33

44
src/ast
5-
src/types
65

76
**/__tests__/*

.prettierignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,3 @@ dist
33

44
src/ast
55
src/ec-evaluator
6-
src/types

src/compiler/__tests__/output

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
1
2+
2
3+
3
4+
-123
5+
9
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { BaseJavaCstVisitorWithDefaults, CstNode, TypeDeclarationCtx } from 'java-parser'
2+
3+
import { NormalClassDeclaration } from '../types/classes'
4+
import { AST } from '../types'
5+
import { ClassExtractor } from './class-extractor'
6+
7+
export class ASTExtractor extends BaseJavaCstVisitorWithDefaults {
8+
private topLevelClassOrInterfaceDeclarations: NormalClassDeclaration[] = []
9+
10+
extract(cst: CstNode): AST {
11+
this.visit(cst)
12+
return {
13+
kind: 'CompilationUnit',
14+
importDeclarations: [],
15+
topLevelClassOrInterfaceDeclarations: this.topLevelClassOrInterfaceDeclarations,
16+
location: cst.location
17+
}
18+
}
19+
20+
typeDeclaration(ctx: TypeDeclarationCtx) {
21+
if (ctx.classDeclaration) {
22+
ctx.classDeclaration.forEach(x => {
23+
const classExtractor = new ClassExtractor()
24+
this.topLevelClassOrInterfaceDeclarations.push(classExtractor.extract(x))
25+
})
26+
}
27+
}
28+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import {
2+
BaseJavaCstVisitorWithDefaults,
3+
BlockStatementCstNode,
4+
LocalVariableDeclarationCtx,
5+
LocalVariableDeclarationStatementCtx,
6+
LocalVariableTypeCtx,
7+
VariableDeclaratorCtx,
8+
VariableDeclaratorIdCtx,
9+
VariableDeclaratorListCtx
10+
} from 'java-parser'
11+
import {
12+
BlockStatement,
13+
LocalVariableDeclarationStatement,
14+
VariableDeclarator
15+
} from '../types/blocks-and-statements'
16+
import { ExpressionExtractor } from './expression-extractor'
17+
import { StatementExtractor } from './statement-extractor'
18+
import { TypeExtractor } from './type-extractor'
19+
20+
export class BlockStatementExtractor extends BaseJavaCstVisitorWithDefaults {
21+
extract(cst: BlockStatementCstNode): BlockStatement {
22+
if (cst.children.localVariableDeclarationStatement) {
23+
return this.visit(cst.children.localVariableDeclarationStatement)
24+
} else if (cst.children.statement) {
25+
const statementExtractor = new StatementExtractor()
26+
return statementExtractor.extract(cst.children.statement[0])
27+
}
28+
throw new Error('not implemented')
29+
}
30+
31+
localVariableDeclarationStatement(
32+
ctx: LocalVariableDeclarationStatementCtx
33+
): LocalVariableDeclarationStatement {
34+
return {
35+
kind: 'LocalVariableDeclarationStatement',
36+
...this.visit(ctx.localVariableDeclaration)
37+
}
38+
}
39+
40+
localVariableDeclaration(
41+
ctx: LocalVariableDeclarationCtx
42+
): Omit<LocalVariableDeclarationStatement, 'kind'> {
43+
return {
44+
localVariableType: this.visit(ctx.localVariableType),
45+
variableDeclaratorList: this.visit(ctx.variableDeclaratorList)
46+
}
47+
}
48+
49+
localVariableType(ctx: LocalVariableTypeCtx) {
50+
const typeExtractor = new TypeExtractor()
51+
if (ctx.unannType) {
52+
return typeExtractor.extract(ctx.unannType[0])
53+
} else if (ctx.Var) {
54+
throw new Error('Not implemented')
55+
}
56+
}
57+
58+
variableDeclaratorList(ctx: VariableDeclaratorListCtx) {
59+
return ctx.variableDeclarator.map(variableDeclarator => {
60+
return this.visit(variableDeclarator)
61+
})
62+
}
63+
64+
variableDeclarator(ctx: VariableDeclaratorCtx): VariableDeclarator {
65+
const variableDeclarator: { [key: string]: any } = { kind: 'VariableDeclarator' }
66+
variableDeclarator.variableDeclaratorId = this.visit(ctx.variableDeclaratorId)
67+
if (ctx.variableInitializer) {
68+
const expressionExtractor = new ExpressionExtractor()
69+
variableDeclarator.variableInitializer = expressionExtractor.visit(ctx.variableInitializer)
70+
}
71+
return variableDeclarator as VariableDeclarator
72+
}
73+
74+
variableDeclaratorId(ctx: VariableDeclaratorIdCtx) {
75+
return ctx.Identifier[0].image
76+
}
77+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import {
2+
BaseJavaCstVisitorWithDefaults,
3+
ClassBodyDeclarationCtx,
4+
ClassDeclarationCstNode,
5+
ClassMemberDeclarationCtx,
6+
ClassModifierCtx,
7+
ClassTypeCtx,
8+
TypeIdentifierCtx
9+
} from 'java-parser'
10+
11+
import {
12+
ClassModifier,
13+
Identifier,
14+
ClassBodyDeclaration,
15+
ClassDeclaration,
16+
NormalClassDeclaration
17+
} from '../types/classes'
18+
import { ConstructorExtractor } from './constructor-extractor'
19+
import { FieldExtractor } from './field-extractor'
20+
import { MethodExtractor } from './method-extractor'
21+
22+
export class ClassExtractor extends BaseJavaCstVisitorWithDefaults {
23+
private modifier: Array<ClassModifier> = []
24+
private identifier: Identifier
25+
private body: Array<ClassBodyDeclaration> = []
26+
private sclass: Identifier
27+
28+
extract(cst: ClassDeclarationCstNode): ClassDeclaration {
29+
this.visit(cst)
30+
return {
31+
kind: 'NormalClassDeclaration',
32+
classModifier: this.modifier,
33+
typeIdentifier: this.identifier,
34+
classBody: this.body,
35+
extendsTypeIdentifier: this.sclass,
36+
location: cst.location
37+
} as NormalClassDeclaration
38+
}
39+
40+
classModifier(ctx: ClassModifierCtx) {
41+
const possibleModifiers = [
42+
ctx.Public,
43+
ctx.Protected,
44+
ctx.Private,
45+
ctx.Abstract,
46+
ctx.Static,
47+
ctx.Final,
48+
ctx.Sealed,
49+
ctx.NonSealed,
50+
ctx.Strictfp
51+
]
52+
.filter(x => x !== undefined)
53+
.map(x => (x ? x[0].image : x))
54+
this.modifier.push(possibleModifiers[0] as ClassModifier)
55+
}
56+
57+
typeIdentifier(ctx: TypeIdentifierCtx) {
58+
this.identifier = ctx.Identifier[0].image
59+
}
60+
61+
classType(ctx: ClassTypeCtx) {
62+
this.sclass = ctx.Identifier[0].image
63+
}
64+
65+
classBodyDeclaration(ctx: ClassBodyDeclarationCtx) {
66+
if (ctx.constructorDeclaration) {
67+
ctx.constructorDeclaration.forEach(x => {
68+
const constructorExtractor = new ConstructorExtractor()
69+
const constructorNode = constructorExtractor.extract(x)
70+
this.body.push(constructorNode)
71+
})
72+
}
73+
if (ctx.classMemberDeclaration) {
74+
this.visit(ctx.classMemberDeclaration)
75+
}
76+
}
77+
78+
classMemberDeclaration(ctx: ClassMemberDeclarationCtx) {
79+
if (ctx.fieldDeclaration) {
80+
ctx.fieldDeclaration.forEach(x => {
81+
const fieldExtractor = new FieldExtractor()
82+
const fieldNode = fieldExtractor.extract(x)
83+
this.body.push(fieldNode)
84+
})
85+
}
86+
if (ctx.methodDeclaration) {
87+
ctx.methodDeclaration.forEach(x => {
88+
const methodExtractor = new MethodExtractor()
89+
const methodNode = methodExtractor.extract(x)
90+
this.body.push(methodNode)
91+
})
92+
}
93+
}
94+
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import {
2+
ArgumentListCtx,
3+
BaseJavaCstVisitorWithDefaults,
4+
BlockStatementsCtx,
5+
ConstructorDeclarationCstNode,
6+
ConstructorModifierCtx,
7+
FormalParameterCtx,
8+
FormalParameterListCtx,
9+
SimpleTypeNameCtx,
10+
UnqualifiedExplicitConstructorInvocationCtx,
11+
VariableArityParameterCtx,
12+
VariableDeclaratorIdCtx,
13+
VariableParaRegularParameterCtx
14+
} from 'java-parser'
15+
16+
import {
17+
Identifier,
18+
FormalParameter,
19+
ConstructorModifier,
20+
ConstructorDeclaration
21+
} from '../types/classes'
22+
import { BlockStatement, ExplicitConstructorInvocation } from '../types/blocks-and-statements'
23+
import { Location } from '../types'
24+
import { BlockStatementExtractor } from './block-statement-extractor'
25+
import { TypeExtractor } from './type-extractor'
26+
import { ExpressionExtractor } from './expression-extractor'
27+
28+
export class ConstructorExtractor extends BaseJavaCstVisitorWithDefaults {
29+
private modifier: Array<ConstructorModifier> = []
30+
private identifier: Identifier
31+
private params: Array<FormalParameter> = []
32+
private body: Array<BlockStatement> = []
33+
private location: Location
34+
35+
extract(cst: ConstructorDeclarationCstNode): ConstructorDeclaration {
36+
this.location = cst.location
37+
this.visit(cst)
38+
return {
39+
kind: 'ConstructorDeclaration',
40+
constructorModifier: this.modifier,
41+
constructorDeclarator: {
42+
identifier: this.identifier,
43+
formalParameterList: this.params
44+
},
45+
constructorBody: {
46+
kind: 'Block',
47+
blockStatements: this.body,
48+
location: this.location
49+
},
50+
location: this.location
51+
}
52+
}
53+
54+
constructorModifier(ctx: ConstructorModifierCtx) {
55+
const possibleModifiers = [ctx.Public, ctx.Protected, ctx.Private]
56+
.filter(x => x !== undefined)
57+
.map(x => (x ? x[0].image : x))
58+
this.modifier.push(possibleModifiers[0] as ConstructorModifier)
59+
}
60+
61+
simpleTypeName(ctx: SimpleTypeNameCtx) {
62+
this.identifier = ctx.Identifier[0].image
63+
}
64+
65+
formalParameterList(ctx: FormalParameterListCtx) {
66+
this.params = ctx.formalParameter.map(p => this.visit(p))
67+
}
68+
69+
formalParameter(ctx: FormalParameterCtx) {
70+
if (ctx.variableParaRegularParameter) {
71+
return this.visit(ctx.variableParaRegularParameter)
72+
} /* if (ctx.variableArityParameter) */ else {
73+
return this.visit(ctx.variableArityParameter!)
74+
}
75+
}
76+
77+
variableParaRegularParameter(ctx: VariableParaRegularParameterCtx) {
78+
const typeExtractor = new TypeExtractor()
79+
return {
80+
kind: 'FormalParameter',
81+
unannType: typeExtractor.extract(ctx.unannType[0]),
82+
identifier: this.visit(ctx.variableDeclaratorId)
83+
} as FormalParameter
84+
}
85+
86+
variableArityParameter(ctx: VariableArityParameterCtx) {
87+
const typeExtractor = new TypeExtractor()
88+
return {
89+
kind: 'FormalParameter',
90+
unannType: typeExtractor.extract(ctx.unannType[0]),
91+
identifier: ctx.Identifier[0].image
92+
} as FormalParameter
93+
}
94+
95+
variableDeclaratorId(ctx: VariableDeclaratorIdCtx) {
96+
return ctx.Identifier[0].image
97+
}
98+
99+
blockStatements(ctx: BlockStatementsCtx) {
100+
ctx.blockStatement.forEach(x => {
101+
const blockStatementExtractor = new BlockStatementExtractor()
102+
this.body.push(blockStatementExtractor.extract(x))
103+
})
104+
}
105+
106+
unqualifiedExplicitConstructorInvocation(ctx: UnqualifiedExplicitConstructorInvocationCtx) {
107+
const expConInv = {
108+
kind: 'ExplicitConstructorInvocation',
109+
thisOrSuper: ctx.This?.[0].image || ctx.Super?.[0].image,
110+
argumentList: ctx.argumentList ? this.visit(ctx.argumentList) : [],
111+
location: this.location
112+
} as ExplicitConstructorInvocation
113+
this.body.push(expConInv)
114+
}
115+
116+
argumentList(ctx: ArgumentListCtx) {
117+
const expressionExtractor = new ExpressionExtractor()
118+
return ctx.expression.map(e => expressionExtractor.extract(e))
119+
}
120+
}

0 commit comments

Comments
 (0)