/** * Fills in all used scopes of the given one. * * @param curr current scope * @return IDs of all directly reachable scopes * @throws QueryException if a variable directly calls itself */ private int[] neighbors(final Scope curr) throws QueryException { final IntList adj = new IntList(0); final boolean ok = curr.visit( new ASTVisitor() { @Override public boolean staticVar(final StaticVar var) { return var != curr && neighbor(var); } @Override public boolean staticFuncCall(final StaticFuncCall call) { return neighbor(call.func()); } @Override public boolean inlineFunc(final Scope sub) { return sub.visit(this); } @Override public boolean funcItem(final FuncItem func) { return neighbor(func); } /** * Adds a neighbor of the currently inspected scope. * * @param scp the neighbor * @return {@code true} for convenience */ private boolean neighbor(final Scope scp) { final int old = id(scp), id = old == -1 ? add(scp) : old; if (old == -1 || !adj.contains(id)) adj.add(id); return true; } }); if (!ok) { final StaticVar var = (StaticVar) curr; throw CIRCREF_X.get(var.info, "$" + var.name); } return adj.finish(); }
/** * Algorithm of Tarjan for computing the strongly connected components of a graph. * * @param v current node * @throws QueryException if a variable directly calls itself */ private void tarjan(final int v) throws QueryException { final int ixv = 2 * v, llv = ixv + 1, idx = next++; while (list.size() <= llv) list.add(-1); list.set(ixv, idx); list.set(llv, idx); stack.push(v); for (final int w : adjacentTo(v)) { final int ixw = 2 * w, llw = ixw + 1; if (list.size() <= ixw || list.get(ixw) < 0) { // Successor w has not yet been visited; recurse on it tarjan(w); list.set(llv, Math.min(list.get(llv), list.get(llw))); } else if (stack.contains(w)) { // Successor w is in stack S and hence in the current SCC list.set(llv, Math.min(list.get(llv), list.get(ixw))); } } // If v is a root node, pop the stack and generate an SCC if (list.get(llv) == list.get(ixv)) { int w; Scope[] out = null; do { w = stack.pop(); final Scope scp = scopes.get(w); out = out == null ? new Scope[] {scp} : Array.add(out, scp); } while (w != v); result.add(out); } }