Skip to content

Commit

Permalink
refactor: add method context
Browse files Browse the repository at this point in the history
  • Loading branch information
lbqh committed Nov 30, 2018
1 parent 34f823b commit e1f9cc7
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 52 deletions.
97 changes: 45 additions & 52 deletions src/main/java/kalang/compiler/compile/AstBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,9 @@ static class VarInfo{
protected ClassNode thisClazz;

private ClassNode topClass;

private boolean returned = false;

private MethodNode method;

private VarTable<VarObject,Type> overrideTypes = new VarTable();


private MethodContext methodCtx;

//TODO merge SemanticAnalyzer.assignedVars
//private VarTable<VarObject,NullableKind> assignedNullables = new VarTable();

Expand All @@ -124,10 +120,7 @@ static class VarInfo{
NULLSTATE_MUST_NONNULL = 1,
NULLSTATE_UNKNOWN = 2,
NULLSTATE_NULLABLE = 3;

private VarTable<VarObject,Integer> nullState = new VarTable();

private VarTable<String,LocalVarNode> varTables = new VarTable();

//private final HashMap<MethodNode,BlockStmtContext> methodBodys = new HashMap<>();

@Nonnull
Expand All @@ -149,16 +142,16 @@ static class VarInfo{
private final CompilationUnit compilationUnit;

private void newOverrideTypeStack(){
overrideTypes = new VarTable(overrideTypes);
methodCtx.overrideTypes = new VarTable(methodCtx.overrideTypes);
}

private void popOverrideTypeStack(){
overrideTypes = overrideTypes.getParent();
methodCtx.overrideTypes = methodCtx.overrideTypes.getParent();
}

private void removeOverrideType(ExprNode expr){
VarObject key = getOverrideTypeKey(expr);
if(key!=null) overrideTypes.remove(key, true);
if(key!=null) methodCtx.overrideTypes.remove(key, true);
}

@Nullable
Expand All @@ -178,15 +171,15 @@ private VarObject getOverrideTypeKey(ExprNode expr){
private void changeTypeTemporarilyIfCould(ExprNode expr,Type type){
VarObject key = getOverrideTypeKey(expr);
if(key!=null){
overrideTypes.put(key, type);
methodCtx.overrideTypes.put(key, type);
}
}

private void onNull(ExprNode expr,boolean onTrue,boolean isEQ){
boolean mustNull = (onTrue && isEQ) || (!onTrue && !isEQ);
VarObject key = this.getOverrideTypeKey(expr);
if(key!=null){
nullState.put(key,mustNull ? NULLSTATE_MUST_NULL : NULLSTATE_MUST_NONNULL);
methodCtx.nullState.put(key,mustNull ? NULLSTATE_MUST_NULL : NULLSTATE_MUST_NONNULL);
}
}

Expand Down Expand Up @@ -486,7 +479,7 @@ public Object visit(ParseTree tree) {
ex.printStackTrace(System.err);
return null;
}
if(tree instanceof StatContext && returned){
if(tree instanceof StatContext && methodCtx.returned){
diagnosisReporter.report(Diagnosis.Kind.ERROR
,"unreachable statement"
, (StatContext) tree
Expand All @@ -507,11 +500,11 @@ BlockStmt wrapBlock(Statement... statms){
}

private void newFrame(){
this.varTables = this.varTables.newStack();
methodCtx.newFrame();
}

private void popFrame(){
this.varTables = this.varTables.popStack();
methodCtx.popFrame();
}

BlockStmt newBlock(){
Expand Down Expand Up @@ -541,7 +534,7 @@ protected void mapAst(@Nonnull AstNode node,@Nonnull Token token){
public ThrowStmt visitThrowStat(KalangParser.ThrowStatContext ctx) {
ThrowStmt ts = new ThrowStmt(visitExpression(ctx.expression()));
mapAst(ts, ctx);
this.returned = true;
this.methodCtx.returned = true;
return ts;
}

Expand Down Expand Up @@ -761,29 +754,29 @@ public AstNode visitIfStat(IfStatContext ctx) {
BlockStmt trueBody = null;
BlockStmt falseBody = null;
VarTable<VarObject,Integer> trueAssigned,falseAssigned;
this.nullState = trueAssigned = this.nullState.newStack();
this.methodCtx.nullState = trueAssigned = this.methodCtx.nullState.newStack();
newOverrideTypeStack();
onIf(expr, true);
if (ctx.trueStmt != null) {
trueBody=requireBlock(ctx.trueStmt);
}
popOverrideTypeStack();
this.nullState = this.nullState.popStack();
boolean trueReturned = this.returned;
this.returned = false;
this.nullState = falseAssigned = this.nullState.newStack();
this.methodCtx.nullState = this.methodCtx.nullState.popStack();
boolean trueReturned = this.methodCtx.returned;
this.methodCtx.returned = false;
this.methodCtx.nullState = falseAssigned = this.methodCtx.nullState.newStack();
newOverrideTypeStack();
onIf(expr,false);
if (ctx.falseStmt != null) {
falseBody=requireBlock(ctx.falseStmt);
}
popOverrideTypeStack();
this.nullState = this.nullState.popStack();
this.methodCtx.nullState = this.methodCtx.nullState.popStack();
handleMultiBranchedAssign(trueAssigned.vars(),falseAssigned.vars());
boolean falseReturned = this.returned;
boolean falseReturned = this.methodCtx.returned;
if(trueReturned) onIf(expr,false);
if(falseReturned) onIf(expr,true);
this.returned = falseReturned && trueReturned;
this.methodCtx.returned = falseReturned && trueReturned;
IfStmt ifStmt = new IfStmt(expr,trueBody,falseBody);
mapAst(ifStmt,ctx);
return ifStmt;
Expand Down Expand Up @@ -816,7 +809,7 @@ private void handleMultiBranchedAssign(Map<VarObject,Integer>... assignedTable){
}
}
for(Map.Entry<VarObject,Integer> e:ret.entrySet()){
this.nullState.put(e.getKey(), e.getValue());
this.methodCtx.nullState.put(e.getKey(), e.getValue());
}
}

Expand Down Expand Up @@ -849,8 +842,8 @@ public AstNode visitReturnStat(ReturnStatContext ctx) {
if (ctx.expression() != null) {
rs.expr = visitExpression(ctx.expression());
}
if(!semanticAnalyzer.validateReturnStmt(method, rs)) return null;
this.returned = true;
if(!semanticAnalyzer.validateReturnStmt(methodCtx.method, rs)) return null;
this.methodCtx.returned = true;
return rs;
}

Expand Down Expand Up @@ -1205,7 +1198,7 @@ private void onAssign(ExprNode to,ExprNode expr){
}else{
throw Exceptions.unexceptedValue(type);
}
nullState.put(key, ns);
methodCtx.nullState.put(key, ns);
}
}
}
Expand Down Expand Up @@ -1538,8 +1531,8 @@ private boolean isDefindedId(String id){

@Nullable
private ParameterNode getNamedParameter(String name){
if (method != null) {
for (ParameterNode p : method.getParameters()) {
if (methodCtx != null) {
for (ParameterNode p : methodCtx.method.getParameters()) {
if (p.getName().equals(name)) {
return p;
}
Expand All @@ -1550,7 +1543,7 @@ private ParameterNode getNamedParameter(String name){

@Nullable
private LocalVarNode getNamedLocalVar(String name){
return this.varTables.get(name);
return methodCtx!=null ? this.methodCtx.varTables.get(name) : null;
}

@Nullable
Expand Down Expand Up @@ -1774,20 +1767,20 @@ public AstNode visitCastExpr(CastExprContext ctx) {
public AstNode visitTryStat(TryStatContext ctx) {
//TODO handle multi-branched assign
BlockStmt tryExecStmt = requireBlock(ctx.exec);
boolean tryReturned = this.returned;
boolean tryReturned = this.methodCtx.returned;
List<CatchBlock> tryCatchBlocks = new LinkedList<>();
if (ctx.catchTypes != null) {
for (int i = 0; i < ctx.catchTypes.size(); i++) {
this.newFrame();
this.returned = false;
this.methodCtx.returned = false;
String vName = ctx.catchVarNames.get(i).getText();
String vType = ctx.catchTypes.get(i).getText();
LocalVarNode vo = this.declareLocalVar(vName,requireClassType(vType, ctx.catchTypes.get(i).start),Modifier.FINAL,ctx);
if(vo==null) return null;
BlockStmt catchExecStmt = requireBlock(ctx.catchExec.get(i));
CatchBlock catchStmt = new CatchBlock(vo,catchExecStmt);
tryCatchBlocks.add(catchStmt);
this.returned = this.returned && tryReturned;
this.methodCtx.returned = this.methodCtx.returned && tryReturned;
this.popFrame();
}
}
Expand Down Expand Up @@ -2043,7 +2036,7 @@ public Object visitLambdaExpr(KalangParser.LambdaExprContext ctx) {
LocalVarNode tmpVar = this.declareTempLocalVar(type);
LambdaExpr ms = new LambdaExpr(tmpVar,functionType);
Map<String,VarObject> accessibleVars = new HashMap();
VarTable<String, LocalVarNode> vtb = this.varTables;
VarTable<String, LocalVarNode> vtb = this.methodCtx.varTables;
while(vtb!=null) {
for(Map.Entry<String, LocalVarNode> v:vtb.vars().entrySet()) {
String name = v.getKey();
Expand All @@ -2054,7 +2047,7 @@ public Object visitLambdaExpr(KalangParser.LambdaExprContext ctx) {
}
vtb = vtb.getParent();
}
ParameterNode[] paramNodes = this.method.getParameters();
ParameterNode[] paramNodes = this.methodCtx.method.getParameters();
for(ParameterNode p:paramNodes) {
String name = p.getName();
if (!accessibleVars.containsKey(name)) {
Expand Down Expand Up @@ -2189,7 +2182,7 @@ private LocalVarNode declareLocalVar(String name,Type type,int modifier,ParserRu
return null;
}
if(name!=null){
this.varTables.put(name,localVarNode);
this.methodCtx.varTables.put(name,localVarNode);
}
return localVarNode;
}
Expand Down Expand Up @@ -2346,11 +2339,11 @@ public Object visitArrayExpr(KalangParser.ArrayExprContext ctx) {
}

private Type getVarObjectType(VarObject p) {
Type type = this.overrideTypes.get(p);
Type type = this.methodCtx.overrideTypes.get(p);
if(type==null) type = p.getType();
//TODO handle other object type
if(type instanceof ClassType){
Integer ns = nullState.get(p);
Integer ns = methodCtx.nullState.get(p);
NullableKind nullable;
if(ns==null){
nullable = ((ObjectType) type).getNullable();
Expand Down Expand Up @@ -2467,7 +2460,7 @@ public void importStaticMember(ClassNode classNode,@Nullable String name) {
}

private boolean isInConstructor(){
return "<init>".equals(this.method.getName());
return "<init>".equals(this.methodCtx.method.getName());
}

@Nullable
Expand Down Expand Up @@ -2608,7 +2601,7 @@ private ClassNode createFunctionClassNode(ClassType type,LambdaExpr lambdaExpr,K
}
String lambdaName = this.thisClazz.name + "$" + ++anonymousClassCounter;
ClassNode oldClass = thisClazz;
MethodNode oldMethod = method;
MethodContext oldMethodCtx = this.methodCtx;
ClassNode classNode = thisClazz = new ClassNode(lambdaName,Modifier.PUBLIC);
classNode.setSuperType(Types.getRootType());
Map<String, VarObject> accessibleVars = lambdaExpr.getAccessibleVarObjects();
Expand Down Expand Up @@ -2656,36 +2649,36 @@ private ClassNode createFunctionClassNode(ClassType type,LambdaExpr lambdaExpr,K
}
if (returnType.equals(Types.getVoidClassType())) {
bs.statements.add(new ReturnStmt(new ConstExpr(null)));
returned = true;
methodCtx.returned = true;
}
methodNode.getBody().statements.add(bs);
checkMethod();
//TODO check return
thisClazz = oldClass;
method = oldMethod;
methodCtx = oldMethodCtx;
return classNode;
}

private void enterMethod(MethodNode method) {
this.method = method;
returned = false;
methodCtx = new MethodContext(this.thisClazz,method);
methodCtx.returned = false;
}

private void checkMethod() {
MethodNode m = this.method;
MethodNode m = this.methodCtx.method;
boolean needReturn = (
m.getType() != null
&& !m.getType().equals(Types.VOID_TYPE)
);
BlockStmt mbody = m.getBody();
if (mbody != null && needReturn && !returned) {
if (mbody != null && needReturn && !methodCtx.returned) {
ConstExpr defaultVal = m.getDefaultReturnValue();
if (defaultVal!=null) {
mbody.statements.add(new ReturnStmt(defaultVal));
} else {
this.diagnosisReporter.report(
Diagnosis.Kind.ERROR
, "Missing return statement in method:" + MethodUtil.toString(method)
, "Missing return statement in method:" + MethodUtil.toString(methodCtx.method)
, m.offset
);
}
Expand Down
37 changes: 37 additions & 0 deletions src/main/java/kalang/compiler/compile/MethodContext.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package kalang.compiler.compile;

import kalang.compiler.ast.ClassNode;
import kalang.compiler.ast.LocalVarNode;
import kalang.compiler.ast.MethodNode;
import kalang.compiler.ast.VarObject;
import kalang.compiler.core.Type;
import kalang.compiler.core.VarTable;

public class MethodContext {

public final ClassNode classNode;

public final MethodNode method;

public boolean returned = false;

public VarTable<String,LocalVarNode> varTables = new VarTable();

public VarTable<VarObject, Type> overrideTypes = new VarTable();

public VarTable<VarObject,Integer> nullState = new VarTable();

public MethodContext(ClassNode classNode, MethodNode methodNode) {
this.classNode = classNode;
this.method = methodNode;
}

public void newFrame(){
this.varTables = varTables.newStack();
}

public void popFrame(){
this.varTables = this.varTables.popStack();
}

}

0 comments on commit e1f9cc7

Please sign in to comment.