package ceylon.tool.converter.java2ceylon;
import java.util.ArrayList;
import java.util.List;
import org.antlr.v4.runtime.ParserRuleContext;
import ceylon.tool.converter.java2ceylon.Java8Parser.AssignmentContext;
import ceylon.tool.converter.java2ceylon.Java8Parser.CompilationUnitContext;
import ceylon.tool.converter.java2ceylon.Java8Parser.LocalVariableDeclarationContext;
import ceylon.tool.converter.java2ceylon.Java8Parser.MethodDeclarationContext;
import ceylon.tool.converter.java2ceylon.Java8Parser.NormalClassDeclarationContext;
import ceylon.tool.converter.java2ceylon.Java8Parser.PostDecrementExpressionContext;
import ceylon.tool.converter.java2ceylon.Java8Parser.PostIncrementExpressionContext;
import ceylon.tool.converter.java2ceylon.Java8Parser.PostfixExpressionContext;
import ceylon.tool.converter.java2ceylon.Java8Parser.PreDecrementExpressionContext;
import ceylon.tool.converter.java2ceylon.Java8Parser.PreIncrementExpressionContext;
import ceylon.tool.converter.java2ceylon.Java8Parser.VariableDeclaratorContext;
import ceylon.tool.converter.java2ceylon.Java8Parser.VariableDeclaratorIdContext;
import ceylon.tool.converter.java2ceylon.Java8Parser.VariableInitializerContext;
public class ScopeTree extends Java8BaseVisitor<Void> {
public Node root, scopeNode;
public ScopeTree() {
root = new Node();
}
public static class Node {
ParserRuleContext data;
Node parent;
List<Node> children;
boolean scope, variable, optional;
Node() {
data = new ParserRuleContext();
scope = false;
variable = false;
optional = false;
children = new ArrayList<>();
}
void addNode(Node n) {
children.add(n);
}
}
public Node getNode(ParserRuleContext ctx, Node n) {
if (ctx == n.data) {
return n;
} else {
for (Node c : n.children) {
Node found = getNode(ctx, c);
if (found != null)
return found;
}
}
return null;
}
@Override
public Void visitCompilationUnit(CompilationUnitContext ctx) {
Node n = new Node();
n.data = ctx;
n.scope = true;
root = n;
scopeNode = n;
return super.visitCompilationUnit(ctx);
}
@Override
public Void visitNormalClassDeclaration(NormalClassDeclarationContext ctx) {
Node n = new Node();
n.data = ctx;
n.parent = scopeNode;
n.scope = true;
scopeNode.addNode(n);
scopeNode = n;
visitClassBody(ctx.classBody());
scopeNode = n.parent;
return null;
}
@Override
public Void visitVariableDeclaratorId(VariableDeclaratorIdContext ctx) {
Node n = new Node();
n.data = ctx;
n.parent = scopeNode;
ParserRuleContext parent = ctx.getParent();
if (parent instanceof VariableDeclaratorContext) {
VariableInitializerContext initial = ((VariableDeclaratorContext) parent).variableInitializer();
if (initial != null && initial.getText().equals("null"))
n.optional = true;
}
scopeNode.addNode(n);
return super.visitVariableDeclaratorId(ctx);
}
@Override
public Void visitMethodDeclaration(MethodDeclarationContext ctx) {
Node n = new Node();
n.parent = scopeNode;
n.data = ctx;
n.scope = true;
scopeNode.addNode(n);
scopeNode = n;
visitMethodHeader(ctx.methodHeader());
visitMethodBody(ctx.methodBody());
scopeNode = n.parent;
return null;
}
@Override
public Void visitPostIncrementExpression(PostIncrementExpressionContext ctx) {
String var = ctx.postfixExpression().getText();
checkVariable(scopeNode, var, false);
return super.visitPostIncrementExpression(ctx);
}
@Override
public Void visitPostfixExpression(PostfixExpressionContext ctx) {
if (ctx.postDecrementExpression_lf_postfixExpression(0) != null
|| ctx.postIncrementExpression_lf_postfixExpression(0) != null) {
String var = ctx.expressionName().getText();
checkVariable(scopeNode, var, false);
}
return super.visitPostfixExpression(ctx);
}
@Override
public Void visitPostDecrementExpression(PostDecrementExpressionContext ctx) {
String var = ctx.postfixExpression().getText();
checkVariable(scopeNode, var, false);
return super.visitPostDecrementExpression(ctx);
}
@Override
public Void visitPreIncrementExpression(PreIncrementExpressionContext ctx) {
String var = ctx.unaryExpression().getText();
checkVariable(scopeNode, var, false);
return super.visitPreIncrementExpression(ctx);
}
@Override
public Void visitPreDecrementExpression(PreDecrementExpressionContext ctx) {
String var = ctx.unaryExpression().getText();
checkVariable(scopeNode, var, false);
return super.visitPreDecrementExpression(ctx);
}
@Override
public Void visitAssignment(AssignmentContext ctx) {
String leftHandSide = ctx.leftHandSide().getText();
String expression = ctx.expression().getText();
checkVariable(scopeNode, leftHandSide, expression.equals("null"));
return super.visitAssignment(ctx);
}
private void checkVariable(Node n, String var, boolean isNull) {
boolean flag = false;
for (Node c : n.children) {
if (c.data instanceof LocalVariableDeclarationContext) {
LocalVariableDeclarationContext context = (LocalVariableDeclarationContext) c.data;
for (VariableDeclaratorContext x : context.variableDeclaratorList().variableDeclarator()) {
String id = x.variableDeclaratorId().getText();
if (var.equals(id)) {
c.variable = true;
if (isNull)
c.optional = true;
flag = true;
break;
}
}
}
if (c.data instanceof VariableDeclaratorIdContext) {
VariableDeclaratorIdContext context = (VariableDeclaratorIdContext) c.data;
if (var.equals(context.Identifier().getText())) {
c.variable = true;
flag = true;
if (isNull)
c.optional = true;
}
}
}
if (!flag && n.parent != null)
checkVariable(n.parent, var, isNull);
}
}