package nl.uva.bromance.QL.typechecking; import nl.uva.bromance.QL.ast.QLNode; import nl.uva.bromance.QL.ast.QLNodeVisitorInterface; import nl.uva.bromance.QL.ast.nodes.Calculation; import nl.uva.bromance.QL.ast.nodes.Form; import nl.uva.bromance.QL.ast.nodes.Question; import nl.uva.bromance.QL.ast.nodes.Questionnaire; import nl.uva.bromance.QL.controlstructures.Else; import nl.uva.bromance.QL.controlstructures.If; import nl.uva.bromance.QL.controlstructures.IfSequence; import nl.uva.bromance.QL.expressions.unary.Variable; import nl.uva.bromance.QL.exceptions.TypeCheckingError; import java.util.ArrayList; import java.util.List; public class CyclicDependencyVisitor implements QLNodeVisitorInterface{ private final QLNode node; private List<TypeCheckingError> exceptions = new ArrayList<>(); private List<VariableList> variableLookupList = new ArrayList<>(); public CyclicDependencyVisitor(QLNode node) { this.node = node; } public List<TypeCheckingError> check() { node.accept(this); return exceptions; } private class VariableList { private List<String> vars; private int lineNumber; public VariableList(List<String> vars, int lineNumber) { this.vars = vars; this.lineNumber = lineNumber; } public List<String> getVars() { return vars; } public int getLineNumber() { return lineNumber; } } @Override public void visit(QLNode qlNode) { } @Override public void visit(Form form) { } @Override public void visit(Question question) { for (VariableList varList : variableLookupList) { for (String var : varList.getVars()) { if (var.equals(question.getIdentifier())) exceptions.add(new TypeCheckingError("Question @ line "+question.getLineNumber()+" has cyclic dependency @ line "+varList.getLineNumber(), TypeCheckingError.Type.ERROR)); } } } @Override public void visit(Questionnaire questionnaire) { } // All we need to check for is if a question has its answer defined within the if statement @Override public void visit(If _if) { CylicDependencyVariableVisitor cdvv = new CylicDependencyVariableVisitor(); _if.visitExpression(cdvv); variableLookupList.add(new VariableList(cdvv.getIdentifierList(), _if.getLineNumber())); } @Override public void visit(Calculation calc) { for (VariableList varList : variableLookupList) { for (String var : varList.getVars()) { if (var.equals(calc.getIdentifier())) exceptions.add(new TypeCheckingError("Calculation @ line "+calc.getLineNumber()+" has cyclic dependency @ line "+varList.getLineNumber(), TypeCheckingError.Type.ERROR)); } } } @Override public void visit(Variable var) { } @Override public void visit() { } // Remove the last of list of variables we're looking for @Override public void exit(If _if) { variableLookupList.remove(variableLookupList.size() - 1); } @Override public void visit(Else _else) { } @Override public void visit(IfSequence sequence) { } @Override public void exit(IfSequence sequence) { } }