Skip to content

Commit 7a0beb2

Browse files
committed
Fix bugs in class typechecking
1 parent 6c71005 commit 7a0beb2

File tree

11 files changed

+173
-232
lines changed

11 files changed

+173
-232
lines changed

src/compiler/__tests__/output

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
true
2-
4
3-
167.5
4-
3.2
5-
16777215
6-
70000000000
1+
1
2+
2
3+
3
4+
-123
5+
9

src/types/ast/astExtractor/statement-extractor.ts

Lines changed: 2 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,17 @@ import {
22
ArgumentListCtx,
33
BaseJavaCstVisitorWithDefaults,
44
BasicForStatementCtx,
5-
BinaryExpressionCtx,
65
BlockCtx,
76
BlockStatementsCtx,
8-
ExpressionCtx,
9-
FqnOrRefTypeCtx,
10-
FqnOrRefTypePartCommonCtx,
11-
FqnOrRefTypePartFirstCtx,
12-
FqnOrRefTypePartRestCtx,
137
ForInitCtx,
148
ForStatementCtx,
159
ForUpdateCtx,
1610
IfStatementCtx,
1711
MethodInvocationSuffixCtx,
18-
PrimaryCtx,
19-
PrimaryPrefixCtx,
20-
PrimarySuffixCtx,
2112
ReturnStatementCtx,
2213
StatementCstNode,
2314
StatementExpressionCtx,
2415
StatementWithoutTrailingSubstatementCtx,
25-
TernaryExpressionCtx,
26-
UnaryExpressionCtx,
2716
WhileStatementCtx,
2817
LocalVariableDeclarationCtx,
2918
StatementExpressionListCtx,
@@ -38,13 +27,10 @@ import {
3827
EnhancedForStatement,
3928
ExpressionStatement,
4029
IfStatement,
41-
MethodInvocation,
42-
Primary,
4330
Statement,
4431
StatementExpression,
4532
VariableDeclarator
4633
} from '../types/blocks-and-statements'
47-
import { Location } from '../types'
4834
import { ExpressionExtractor } from './expression-extractor'
4935
import { BlockStatementExtractor } from './block-statement-extractor'
5036
import { TypeExtractor } from './type-extractor'
@@ -102,7 +88,8 @@ export class StatementExtractor extends BaseJavaCstVisitorWithDefaults {
10288
}
10389

10490
statementExpression(ctx: StatementExpressionCtx) {
105-
return this.visit(ctx.expression)
91+
const expressionExtractor = new ExpressionExtractor()
92+
return expressionExtractor.extract(ctx.expression[0])
10693
}
10794

10895
returnStatement(ctx: ReturnStatementCtx) {
@@ -113,122 +100,6 @@ export class StatementExtractor extends BaseJavaCstVisitorWithDefaults {
113100
return { kind: 'Void' }
114101
}
115102

116-
expression(ctx: ExpressionCtx) {
117-
if (ctx.lambdaExpression) {
118-
throw new Error('Unimplemented extractor.')
119-
} else if (ctx.ternaryExpression) {
120-
return this.visit(ctx.ternaryExpression)
121-
}
122-
}
123-
124-
ternaryExpression(ctx: TernaryExpressionCtx) {
125-
if (ctx.binaryExpression && ctx.QuestionMark && ctx.Colon && ctx.expression) {
126-
const expressionExtractor = new ExpressionExtractor()
127-
return expressionExtractor.ternaryExpression(ctx)
128-
}
129-
return this.visit(ctx.binaryExpression)
130-
}
131-
132-
binaryExpression(ctx: BinaryExpressionCtx) {
133-
// Assignment
134-
if (ctx.AssignmentOperator && ctx.expression) {
135-
const expressionExtractor = new ExpressionExtractor()
136-
const left = this.visit(ctx.unaryExpression[0])
137-
return {
138-
kind: 'Assignment',
139-
left,
140-
operator: '=',
141-
right: expressionExtractor.extract(ctx.expression[0]),
142-
location: left.location
143-
}
144-
}
145-
// MethodInvocation
146-
return this.visit(ctx.unaryExpression[0])
147-
}
148-
149-
unaryExpression(ctx: UnaryExpressionCtx) {
150-
if (ctx.UnaryPrefixOperator || ctx.UnarySuffixOperator) {
151-
const expressionExtractor = new ExpressionExtractor()
152-
return expressionExtractor.unaryExpression(ctx)
153-
}
154-
// Assignment LHS, MethodInvocation
155-
return this.visit(ctx.primary)
156-
}
157-
158-
primary(ctx: PrimaryCtx): Primary {
159-
// Assignment LHS, MethodInvocation identifier
160-
const primaryPrefix = this.visit(ctx.primaryPrefix)
161-
if (ctx.primarySuffix) {
162-
const lastSuffix = ctx.primarySuffix[ctx.primarySuffix.length - 1]
163-
if (lastSuffix.children.arrayAccessSuffix) {
164-
const expressionExtractor = new ExpressionExtractor()
165-
const newPrimaryCtx: PrimaryCtx = { primaryPrefix: ctx.primaryPrefix }
166-
if (ctx.primarySuffix.length - 1 > 0) {
167-
const newSuffixArray = ctx.primarySuffix.filter(
168-
(_, index) => index !== ctx.primarySuffix!.length - 1
169-
)
170-
newPrimaryCtx.primarySuffix = newSuffixArray
171-
}
172-
return {
173-
...expressionExtractor.visit(lastSuffix.children.arrayAccessSuffix),
174-
primary: this.primary(newPrimaryCtx)
175-
}
176-
}
177-
178-
for (const s of ctx.primarySuffix.filter(s => !s.children.methodInvocationSuffix)) {
179-
primaryPrefix.name += '.' + this.visit(s)
180-
}
181-
182-
// MethodInvocation
183-
if (ctx.primarySuffix[ctx.primarySuffix.length - 1].children.methodInvocationSuffix) {
184-
return {
185-
kind: 'MethodInvocation',
186-
identifier: primaryPrefix.name,
187-
argumentList: this.visit(ctx.primarySuffix[ctx.primarySuffix.length - 1]),
188-
location: primaryPrefix.location
189-
} as MethodInvocation
190-
}
191-
}
192-
return {
193-
kind: 'ExpressionName',
194-
name: primaryPrefix.name,
195-
location: primaryPrefix.location
196-
}
197-
}
198-
199-
primaryPrefix(ctx: PrimaryPrefixCtx): { name: string; location: Location } {
200-
// Assignment LHS, MethodInvocation identifier
201-
if (ctx.fqnOrRefType) {
202-
return this.visit(ctx.fqnOrRefType)
203-
} else if (ctx.This) {
204-
const thisKeyword = ctx.This[0]
205-
return {
206-
name: thisKeyword.image,
207-
location: {
208-
startOffset: thisKeyword.startOffset,
209-
startLine: thisKeyword.startLine,
210-
startColumn: thisKeyword.startColumn,
211-
endOffset: thisKeyword.endOffset,
212-
endLine: thisKeyword.endLine,
213-
endColumn: thisKeyword.endColumn
214-
} as Location
215-
}
216-
} else if (ctx.newExpression) {
217-
const expressionExtractor = new ExpressionExtractor()
218-
return expressionExtractor.visit(ctx.newExpression)
219-
}
220-
throw new Error('Unimplemeted extractor.')
221-
}
222-
223-
primarySuffix(ctx: PrimarySuffixCtx) {
224-
// MethodInvocation argumentList
225-
if (ctx.methodInvocationSuffix) {
226-
return this.visit(ctx.methodInvocationSuffix)
227-
} else if (ctx.Identifier) {
228-
return ctx.Identifier[0].image
229-
}
230-
}
231-
232103
methodInvocationSuffix(ctx: MethodInvocationSuffixCtx) {
233104
// MethodInvocation argumentList
234105
return ctx.argumentList ? this.visit(ctx.argumentList) : []
@@ -240,45 +111,6 @@ export class StatementExtractor extends BaseJavaCstVisitorWithDefaults {
240111
return ctx.expression.map(e => expressionExtractor.extract(e))
241112
}
242113

243-
fqnOrRefType(ctx: FqnOrRefTypeCtx) {
244-
// Assignment LHS, MethodInvocation identifier
245-
const fqnOrRefTypePartFirst = this.visit(ctx.fqnOrRefTypePartFirst)
246-
if (ctx.fqnOrRefTypePartRest) {
247-
for (const r of ctx.fqnOrRefTypePartRest) {
248-
fqnOrRefTypePartFirst.name += '.' + this.visit(r).name
249-
}
250-
}
251-
return fqnOrRefTypePartFirst
252-
}
253-
254-
fqnOrRefTypePartFirst(ctx: FqnOrRefTypePartFirstCtx) {
255-
// Assignment LHS, MethodInvocation identifier
256-
return this.visit(ctx.fqnOrRefTypePartCommon)
257-
}
258-
259-
fqnOrRefTypePartCommon(ctx: FqnOrRefTypePartCommonCtx) {
260-
// Assignment LHS, MethodInvocation identifier
261-
if (ctx.Identifier) {
262-
const identifier = ctx.Identifier[0]
263-
return {
264-
name: identifier.image,
265-
location: {
266-
startOffset: identifier.startOffset,
267-
startLine: identifier.startLine,
268-
startColumn: identifier.startColumn,
269-
endOffset: identifier.endOffset,
270-
endLine: identifier.endLine,
271-
endColumn: identifier.endColumn
272-
} as Location
273-
}
274-
}
275-
throw new Error('Unimplemented extractor.')
276-
}
277-
278-
fqnOrRefTypePartRest(ctx: FqnOrRefTypePartRestCtx) {
279-
return this.visit(ctx.fqnOrRefTypePartCommon)
280-
}
281-
282114
ifStatement(ctx: IfStatementCtx): IfStatement {
283115
const consequentStatements: StatementCstNode[] = []
284116
const alternateStatements: StatementCstNode[] = []

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { check } from '..'
22
import { parse } from '../../ast'
3+
import { CyclicInheritanceError } from '../../errors'
34
import { Type } from '../../types/type'
45

56
const testcases: {
@@ -83,8 +84,18 @@ const testcases: {
8384
}
8485
}
8586
`,
86-
result: { type: null, errors: [] },
87-
only: true
87+
result: { type: null, errors: [] }
88+
},
89+
{
90+
input: `
91+
class A extends B {}
92+
class B extends A {}
93+
94+
public class Main {
95+
public static void main(String[] args) {}
96+
}
97+
`,
98+
result: { type: null, errors: [new CyclicInheritanceError()] }
8899
}
89100
]
90101

@@ -106,7 +117,6 @@ describe('Type Checker', () => {
106117
})
107118
} else {
108119
result.errors.forEach((error, index) => {
109-
console.log(error)
110120
if (!testcase.result.errors[index]) expect(error.message).toBe('')
111121
expect(error.message).toBe(testcase.result.errors[index].message)
112122
})

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ describe('Type Checker', () => {
3939
})
4040
} else {
4141
result.errors.forEach((error, index) => {
42+
console.log(error)
4243
if (!testcase.result.errors[index]) expect(error.message).toBe('')
4344
expect(error.message).toBe(testcase.result.errors[index].message)
4445
})

0 commit comments

Comments
 (0)