/
RefResolver.java
495 lines (434 loc) · 19.6 KB
/
RefResolver.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
package play;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import play.PlayScriptParser.*;
import java.util.LinkedList;
import java.util.List;
/**
* 语义解析的第三步:引用消解和类型推断
* 1.解析所有的本地变量引用、函数调用和类成员引用。
* 2.类型推断:从下而上推断表达式的类型。
* 这两件事要放在一起做,因为:
* (1)对于变量,只有做了消解,才能推断出类型来。
* (2)对于FunctionCall,只有把参数(表达式)的类型都推断出来,才能匹配到正确的函数(方法)。
* (3)表达式里包含FunctionCall,所以要推导表达式的类型,必须知道是哪个Function,从而才能得到返回值。
*
*/
public class RefResolver extends PlayScriptBaseListener {
private AnnotatedTree at = null;
//用于把本地变量添加到符号表,并计算类型
ParseTreeWalker typeResolverWalker = new ParseTreeWalker();
TypeResolver localVariableEnter = null;
//this()和super()构造函数留到最后去消解,因为它可能引用别的构造函数,必须等这些构造函数都消解完。
private List<FunctionCallContext> thisConstructorList = new LinkedList<>();
private List<FunctionCallContext> superConstructorList = new LinkedList<>();
public RefResolver(AnnotatedTree at) {
this.at = at;
localVariableEnter = new TypeResolver(at, true);
}
//把本地变量加到符号表。本地变量必须是边添加,边解析,不能先添加后解析,否则会引起引用消解的错误。
//Aaaaaaaaaaayou同学请看这里。
//2021-3-4 添加了scope是Function的情况,上次修改不小心漏掉了:-(
@Override
public void enterVariableDeclarators(VariableDeclaratorsContext ctx) {
Scope scope = at.enclosingScopeOfNode(ctx);
if (scope instanceof BlockScope || scope instanceof Function){
typeResolverWalker.walk(localVariableEnter, ctx);
}
}
@Override
public void exitPrimary(PrimaryContext ctx) {
Scope scope = at.enclosingScopeOfNode(ctx);
Type type = null;
//标识符
if (ctx.IDENTIFIER() != null) {
String idName = ctx.IDENTIFIER().getText();
Variable variable = at.lookupVariable(scope, idName);
if (variable == null) {
// 看看是不是函数,因为函数可以作为值来传递。这个时候,函数重名没法区分。
// 因为普通Scope中的函数是不可以重名的,所以这应该是没有问题的。 //TODO 但如果允许重名,那就不行了。
// TODO 注意,查找function的时候,可能会把类的方法包含进去
Function function = at.lookupFunction(scope, idName);
if (function != null) {
at.symbolOfNode.put(ctx, function);
type = function;
} else {
at.log("unknown variable or function: " + idName, ctx);
}
} else {
at.symbolOfNode.put(ctx, variable);
type = variable.type;
}
}
//字面量
else if (ctx.literal() != null) {
type = at.typeOfNode.get(ctx.literal());
}
//括号里的表达式
else if (ctx.expression() != null) {
type = at.typeOfNode.get(ctx.expression());
}
//this关键字
else if (ctx.THIS() != null){
//找到Class类型的上级Scope
Class theClass = at.enclosingClassOfNode(ctx);
if (theClass != null){
This variable = theClass.getThis();
at.symbolOfNode.put(ctx, variable);
type = theClass;
}
else{
at.log("keyword \"this\" can only be used inside a class", ctx);
}
}
//super关键字。看上去跟This关键字的用法完全一样?
else if (ctx.SUPER() != null){
//找到Class类型的上级Scope
Class theClass = at.enclosingClassOfNode(ctx);
if (theClass != null){
Super variable = theClass.getSuper();
at.symbolOfNode.put(ctx, variable);
type = theClass;
}
else{
at.log("keyword \"super\" can only be used inside a class", ctx);
}
}
//类型推断、冒泡
at.typeOfNode.put(ctx,type);
}
@Override
public void exitFunctionCall(FunctionCallContext ctx) {
// this
if(ctx.THIS() != null){
thisConstructorList.add(ctx);
return;
}
// super
else if(ctx.SUPER() != null){
superConstructorList.add(ctx);
return;
}
//TODO 临时代码,支持println
if(ctx.IDENTIFIER().getText().equals("println")){
return;
}
String idName = ctx.IDENTIFIER().getText();
// 获得参数类型,这些类型已经在表达式中推断出来
List<Type> paramTypes = getParamTypes(ctx);
boolean found = false;
// 看看是不是点符号表达式调用的,调用的是类的方法
if (ctx.parent instanceof ExpressionContext) {
ExpressionContext exp = (ExpressionContext) ctx.parent;
if (exp.bop != null && exp.bop.getType() == PlayScriptParser.DOT) {
Symbol symbol = at.symbolOfNode.get(exp.expression(0));
if (symbol instanceof Variable && ((Variable) symbol).type instanceof Class) {
Class theClass = (Class) ((Variable) symbol).type;
//查找名称和参数类型都匹配的函数。不允许名称和参数都相同,但返回值不同的情况。
Function function = theClass.getFunction(idName, paramTypes);
if (function != null) {
found = true;
at.symbolOfNode.put(ctx, function);
at.typeOfNode.put(ctx, function.getReturnType());
}
else {
Variable funcVar = theClass.getFunctionVariable(idName,paramTypes);
if (funcVar != null){
found = true;
at.symbolOfNode.put(ctx, funcVar);
at.typeOfNode.put(ctx, ((FunctionType)funcVar.type).getReturnType());
}
else {
at.log("unable to find method " + idName + " in Class " + theClass.name, exp);
}
}
} else {
at.log("unable to resolve a class", ctx);
}
}
}
Scope scope = at.enclosingScopeOfNode(ctx);
//从当前Scope逐级查找函数(或方法)
if (!found) {
Function function = at.lookupFunction(scope, idName, paramTypes);
if (function != null){
found = true;
at.symbolOfNode.put(ctx, function);
at.typeOfNode.put(ctx, function.returnType);
}
}
if (!found) {
// 看看是不是类的构建函数,用相同的名称查找一个class
Class theClass = at.lookupClass(scope, idName);
if (theClass != null) {
Function function = theClass.findConstructor(paramTypes);
if (function != null) {
found = true;
at.symbolOfNode.put(ctx, function);
}
//如果是与类名相同的方法,并且没有参数,那么就是缺省构造方法
else if (ctx.expressionList() == null){
found = true;
//at.symbolOfNode.put(ctx, theClass); // TODO 直接赋予class
at.symbolOfNode.put(ctx, theClass.defaultConstructor());
}
else{
at.log("unknown class constructor: " + ctx.getText(), ctx);
}
at.typeOfNode.put(ctx, theClass); // 这次函数调用是返回一个对象
}
//看看是不是一个函数型的变量
else{
Variable variable = at.lookupFunctionVariable(scope,idName, paramTypes);
if (variable != null && variable.type instanceof FunctionType){
found = true;
at.symbolOfNode.put(ctx, variable);
at.typeOfNode.put(ctx, variable.type);
}
else {
at.log("unknown function or function variable: " + ctx.getText(), ctx);
}
}
}
}
/**
* 消解this()构造函数
* @param ctx
*/
private void resolveThisConstructorCall(FunctionCallContext ctx){
Class theClass = at.enclosingClassOfNode(ctx);
if (theClass != null){
Function function = at.enclosingFunctionOfNode(ctx);
if (function != null && function.isConstructor()){
//检查是不是构造函数中的第一句
FunctionDeclarationContext fdx = (FunctionDeclarationContext) function.ctx;
if (!firstStatmentInFunction(fdx, ctx)){
at.log("this() must be first statement in a constructor", ctx);
return;
}
List<Type> paramTypes = getParamTypes(ctx);
Function refered = theClass.findConstructor(paramTypes);
if (refered != null){
at.symbolOfNode.put(ctx,refered);
at.typeOfNode.put(ctx,theClass);
at.thisConstructorRef.put(function, refered);
}
else if (paramTypes.size() == 0){ //缺省构造函数
at.symbolOfNode.put(ctx,theClass.defaultConstructor());
at.typeOfNode.put(ctx,theClass);
at.thisConstructorRef.put(function, theClass.defaultConstructor());
}
else{
at.log("can not find a constructor matches this()", ctx);
}
}
else{
at.log("this() should only be called inside a class constructor", ctx);
}
}
else{
at.log("this() should only be called inside a class", ctx);
}
}
private boolean firstStatmentInFunction(FunctionDeclarationContext fdx, FunctionCallContext ctx){
if (fdx.functionBody().block().blockStatements().blockStatement(0).statement()!= null
&& fdx.functionBody().block().blockStatements().blockStatement(0).statement().expression()!= null
&& fdx.functionBody().block().blockStatements().blockStatement(0).statement().expression().functionCall()==ctx){
return true;
}
return false;
}
/**
* 消解Super()构造函数
* TODO 对于调用super()是有要求的,比如:
* (1)必须出现在构造函数的第一行,
* (2)this()和super不能同时出现,等等。
* @param ctx
*/
private void resolveSuperConstructorCall(FunctionCallContext ctx){
Class theClass = at.enclosingClassOfNode(ctx);
if (theClass != null){
Function function = at.enclosingFunctionOfNode(ctx);
if (function != null && function.isConstructor()){
Class parentClass = theClass.getParentClass();
if (parentClass != null){
//检查是不是构造函数中的第一句
FunctionDeclarationContext fdx = (FunctionDeclarationContext) function.ctx;
if (!firstStatmentInFunction(fdx, ctx)){
at.log("super() must be first statement in a constructor", ctx);
return;
}
List<Type> paramTypes = getParamTypes(ctx);
Function refered = parentClass.findConstructor(paramTypes);
if (refered != null){
at.symbolOfNode.put(ctx,refered);
at.typeOfNode.put(ctx,theClass);
at.superConstructorRef.put(function, refered);
}
else if(paramTypes.size() == 0) { //缺省构造函数
at.symbolOfNode.put(ctx, parentClass.defaultConstructor());
at.typeOfNode.put(ctx,theClass);
at.superConstructorRef.put(function, theClass.defaultConstructor());
}
else{
at.log("can not find a constructor matches this()", ctx);
}
}
else{ //父类是最顶层的基类。
//TODO 这里暂时不处理
}
}
else{
at.log("super() should only be called inside a class constructor", ctx);
}
}
else{
at.log("super() should only be called inside a class", ctx);
}
}
/**
* 获得函数的参数列表
* @param ctx
* @return
*/
private List<Type> getParamTypes(FunctionCallContext ctx){
List<Type> paramTypes = new LinkedList<Type>();
if (ctx.expressionList() != null) {
for (ExpressionContext exp : ctx.expressionList().expression()) {
Type type = at.typeOfNode.get(exp);
paramTypes.add(type);
}
}
return paramTypes;
}
//消解处理点符号表达式的层层引用
@Override
public void exitExpression(ExpressionContext ctx) {
Type type = null;
if (ctx.bop != null && ctx.bop.getType() == PlayScriptParser.DOT) {
// 这是个左递归,要不断的把左边的节点的计算结果存到node2Symbol,所以要在exitExpression里操作
Symbol symbol = at.symbolOfNode.get(ctx.expression(0));
if (symbol instanceof Variable && ((Variable) symbol).type instanceof Class) {
Class theClass = (Class) ((Variable) symbol).type;
//引用类的属性
if (ctx.IDENTIFIER() != null) {
String idName = ctx.IDENTIFIER().getText();
Variable variable = at.lookupVariable(theClass, idName); // 在类的scope里去查找,不需要改变当前的scope
if (variable != null) {
at.symbolOfNode.put(ctx, variable);
type = variable.type; //类型综合(冒泡)
} else {
at.log("unable to find field " + idName + " in Class " + theClass.name, ctx);
}
}
//引用类的方法
else if (ctx.functionCall() != null){
type = at.typeOfNode.get(ctx.functionCall());
}
} else {
at.log("symbol is not a qualified object:" + symbol, ctx);
}
}
//变量引用冒泡: 如果下级是一个变量,往上冒泡传递,以便在点符号表达式中使用
//也包括This和Super的冒泡
else if (ctx.primary() != null) {
Symbol symbol = at.symbolOfNode.get(ctx.primary());
at.symbolOfNode.put(ctx, symbol);
}
//类型推断和综合
if (ctx.primary() != null) {
type = at.typeOfNode.get(ctx.primary());
} else if (ctx.functionCall() != null) {
type = at.typeOfNode.get(ctx.functionCall());
} else if (ctx.bop != null && ctx.expression().size() >= 2) {
Type type1 = at.typeOfNode.get(ctx.expression(0));
Type type2 = at.typeOfNode.get(ctx.expression(1));
switch (ctx.bop.getType()) {
case PlayScriptParser.ADD:
if (type1 == PrimitiveType.String || type2 == PrimitiveType.String){
type = PrimitiveType.String;
}
else if (type1 instanceof PrimitiveType && type2 instanceof PrimitiveType){
//类型“向上”对齐,比如一个int和一个float,取float
type = PrimitiveType.getUpperType(type1,type2);
}else{
at.log("operand should be PrimitiveType for additive and multiplicative operation", ctx);
}
break;
case PlayScriptParser.SUB:
case PlayScriptParser.MUL:
case PlayScriptParser.DIV:
if (type1 instanceof PrimitiveType && type2 instanceof PrimitiveType){
//类型“向上”对齐,比如一个int和一个float,取float
type = PrimitiveType.getUpperType(type1,type2);
}else{
at.log("operand should be PrimitiveType for additive and multiplicative operation", ctx);
}
break;
case PlayScriptParser.EQUAL:
case PlayScriptParser.NOTEQUAL:
case PlayScriptParser.LE:
case PlayScriptParser.LT:
case PlayScriptParser.GE:
case PlayScriptParser.GT:
case PlayScriptParser.AND:
case PlayScriptParser.OR:
case PlayScriptParser.BANG:
type = PrimitiveType.Boolean;
break;
case PlayScriptParser.ASSIGN:
case PlayScriptParser.ADD_ASSIGN:
case PlayScriptParser.SUB_ASSIGN:
case PlayScriptParser.MUL_ASSIGN:
case PlayScriptParser.DIV_ASSIGN:
case PlayScriptParser.AND_ASSIGN:
case PlayScriptParser.OR_ASSIGN:
case PlayScriptParser.XOR_ASSIGN:
case PlayScriptParser.MOD_ASSIGN:
case PlayScriptParser.LSHIFT_ASSIGN:
case PlayScriptParser.RSHIFT_ASSIGN:
case PlayScriptParser.URSHIFT_ASSIGN:
type = type1;
break;
}
}
//类型冒泡
at.typeOfNode.put(ctx, type);
}
//对变量初始化部分也做一下类型推断
@Override
public void exitVariableInitializer(VariableInitializerContext ctx) {
if (ctx.expression() != null){
at.typeOfNode.put(ctx, at.typeOfNode.get(ctx.expression()));
}
}
//根据字面量来推断类型
@Override
public void exitLiteral(LiteralContext ctx) {
if (ctx.BOOL_LITERAL() != null) {
at.typeOfNode.put(ctx, PrimitiveType.Boolean);
} else if (ctx.CHAR_LITERAL() != null) {
at.typeOfNode.put(ctx, PrimitiveType.Char);
} else if (ctx.NULL_LITERAL() != null) {
at.typeOfNode.put(ctx, PrimitiveType.Null);
} else if (ctx.STRING_LITERAL() != null) {
at.typeOfNode.put(ctx, PrimitiveType.String);
} else if (ctx.integerLiteral() != null) {
at.typeOfNode.put(ctx, PrimitiveType.Integer);
} else if (ctx.floatLiteral() != null) {
at.typeOfNode.put(ctx, PrimitiveType.Float);
}
}
/**
* 在结束扫描之前,把this()和super()构造函数消解掉
* @param ctx
*/
@Override
public void exitProg(ProgContext ctx) {
for (FunctionCallContext fcc : thisConstructorList){
resolveThisConstructorCall(fcc);
}
for (FunctionCallContext fcc : superConstructorList){
resolveSuperConstructorCall(fcc);
}
}
}