// we drop all arguments that are types. We also drop stars as // arguments, for the benefit of Inj. public Expr dropAnnos(Context ctxt) { int iend = X.length; Expr[] X2 = new Expr[iend]; boolean changed = false; int cnt = 0; for (int i = 0; i < iend; i++) { Expr tmp = X[i]; if (tmp.isTypeOrKind(ctxt) || tmp.isProof(ctxt) || tmp.construct == STAR || specarg[i]) { changed = true; } else { tmp = tmp.dropAnnos(ctxt); X2[cnt] = tmp; if (X2[cnt] != X[i]) { changed = true; } cnt++; } } Expr[] X3 = new Expr[cnt]; System.arraycopy(X2, 0, X3, 0, cnt); Expr h = head.dropAnnos(ctxt); if (X3.length == 0) { return h; } if (changed || h != head) { return new TermApp(h, X3); } return this; }
/** * Checks if the predicates are successful for the specified item. * * @param it item to be checked * @param qc query context * @return result of check * @throws QueryException query exception */ protected final boolean preds(final Item it, final QueryContext qc) throws QueryException { if (preds.length == 0) return true; // set context value and position final Value cv = qc.value; try { if (qc.scoring) { double s = 0; for (final Expr p : preds) { qc.value = it; final Item i = p.test(qc, info); if (i == null) return false; s += i.score(); } it.score(Scoring.avg(s, preds.length)); } else { for (final Expr p : preds) { qc.value = it; if (p.test(qc, info) == null) return false; } } return true; } finally { qc.value = cv; } }
public Expr dropNoncompArgs(Context ctxt) { if (ctxt.getFlag("debug_drop_noncomp")) { ctxt.w.println("Dropping non-comp arguments from term-app " + toString(ctxt)); ctxt.w.flush(); } ArrayList nX = new ArrayList(); ArrayList no = new ArrayList(); boolean changed = false; Boolean b = new Boolean(false); for (int i = 0, iend = X.length; i < iend; i++) { if (X[i].isProof(ctxt) || specarg[i]) changed = true; else { nX.add(X[i]); no.add(b); } } Expr ret = this; if (changed) { if (nX.size() == 0) ret = head; else ret = new TermApp(head, Parser.toExprArray(nX), Parser.toBooleanArray(no)); } if (ctxt.getFlag("debug_drop_noncomp")) { ctxt.w.println("Returning " + ret.toString(ctxt)); ctxt.w.flush(); } return ret; }
public Expr classify(Context ctxt, int approx, boolean spec) { if (ctxt.getFlag("debug_classify_term_apps")) { ctxt.w.print("(Classifying "); print(ctxt.w, ctxt); ctxt.w.println(""); ctxt.w.flush(); } Expr cl = head.classify(ctxt, approx, spec).defExpandTop(ctxt, false, spec); Expr ret = apply_classifier(FUN_TYPE, approx, spec, ctxt, cl, 0); FunType ch = (FunType) ((FunType) cl).coalesce(ctxt, spec); boolean check_spec_terminates = ctxt.getFlag("check_spec_terminates"); for (int i = 0; i < X.length; i++) { if (ch.owned[i].status == Ownership.SPEC) { if (check_spec_terminates) X[i].checkTermination(ctxt); specarg[i] = true; } } if (ctxt.getFlag("debug_classify_term_apps")) { ctxt.w.println(") Classifier is:"); ret.print(ctxt.w, ctxt); ctxt.w.println(""); ctxt.w.flush(); } return ret; }
@Override public final Expr compile(final QueryContext qc, final VarScope scp) throws QueryException { if (root != null) root = root.compile(qc, scp); // no steps if (steps.length == 0) return root == null ? new Context(info) : root; final Value init = qc.value, cv = initial(qc); final boolean doc = cv != null && cv.type == NodeType.DOC; qc.value = cv; try { final int sl = steps.length; for (int s = 0; s < sl; s++) { Expr e = steps[s]; // axis step: if input is a document, its type is temporarily generalized final boolean as = e instanceof Step; if (as && s == 0 && doc) cv.type = NodeType.NOD; e = e.compile(qc, scp); if (e.isEmpty()) return optPre(qc); steps[s] = e; // no axis step: invalidate context value if (!as) qc.value = null; } } finally { if (doc) cv.type = NodeType.DOC; qc.value = init; } // optimize path return optimize(qc, scp); }
@Override public boolean has(final Flag flag) { for (final Expr pred : preds) { if (flag == Flag.FCS && pred.seqType().mayBeNumber() || pred.has(flag)) return true; } return false; }
@Override public final Expr optimize(final QueryContext qc, final VarScope scp) throws QueryException { final Value v = initial(qc); if (v != null && v.isEmpty() || emptyPath(v)) return optPre(qc); // merge descendant steps Expr e = mergeSteps(qc); if (e == this && v != null && v.type == NodeType.DOC) { // check index access e = index(qc, v); // rewrite descendant to child steps if (e == this) e = children(qc, v); } // recompile path if it has changed if (e != this) return e.compile(qc, scp); // set atomic type for single attribute steps to speed up predicate tests if (root == null && steps.length == 1 && steps[0] instanceof Step) { final Step curr = (Step) steps[0]; if (curr.axis == ATTR && curr.test.kind == Kind.URI_NAME) curr.seqType(SeqType.NOD_ZO); } // choose best path implementation and set type information final Path path = get(info, root, steps); path.size = path.size(qc); path.seqType = SeqType.get(steps[steps.length - 1].seqType().type, size); return path; }
@Override public final boolean has(final Flag flag) { // first step or root expression will be used as context if (flag == Flag.CTX) return root == null || root.has(flag); for (final Expr s : steps) if (s.has(flag)) return true; return root != null && root.has(flag); }
@Override public boolean accept(final ASTVisitor visitor) { if (!visitAll(visitor, specs)) return false; for (final Expr ng : preExpr) if (!ng.accept(visitor)) return false; for (final Var ng : post) if (!visitor.declared(ng)) return false; return true; }
@Override public int exprSize() { int sz = 0; for (final Expr e : preExpr) sz += e.exprSize(); for (final Expr e : specs) sz += e.exprSize(); return sz; }
public Eq(Expr e1, Expr e2) { super(e1, e2, "=="); if (e1.getType().isPrimitive() != e2.getType().isPrimitive()) throw new IllegalArgumentException("type mismatch"); if (e1.getType().isPrimitive() && e1.getType() != e2.getType()) throw new IllegalArgumentException("type mismatch"); // FEATURE: Check if we can compare these classes }
@Override public void visit(ConstructMultiArrayInstruction insn) { Expr[] dimensionExprs = new Expr[insn.getDimensions().size()]; for (int i = 0; i < dimensionExprs.length; ++i) { dimensionExprs[i] = Expr.var(insn.getDimensions().get(i).getIndex()); } assign(Expr.createArray(insn.getItemType(), dimensionExprs), insn.getReceiver()); }
@Override public void visit(BinaryExpr expr) { switch (expr.getOperation()) { case AND: case OR: resultExpr = expr; return; default: break; } expr.getSecondOperand().acceptVisitor(this); Expr b = resultExpr; if (b instanceof ConstantExpr && expr.getOperation() == BinaryOperation.SUBTRACT) { if (tryMakePositive((ConstantExpr) b)) { expr.setOperation(BinaryOperation.ADD); } } expr.getFirstOperand().acceptVisitor(this); Expr a = resultExpr; Expr p = a; Expr q = b; boolean invert = false; if (isZero(p)) { Expr tmp = p; p = q; q = tmp; invert = true; } if (isComparison(p) && isZero(q)) { switch (expr.getOperation()) { case EQUALS: case NOT_EQUALS: case LESS: case LESS_OR_EQUALS: case GREATER: case GREATER_OR_EQUALS: { BinaryExpr comparison = (BinaryExpr) p; Expr result = BinaryExpr.binary( expr.getOperation(), comparison.getFirstOperand(), comparison.getSecondOperand()); result.setLocation(comparison.getLocation()); if (invert) { result = ExprOptimizer.invert(result); } resultExpr = result; return; } default: break; } } expr.setFirstOperand(a); expr.setSecondOperand(b); resultExpr = expr; }
@Override public void visit(CloneArrayInstruction insn) { MethodDescriptor cloneMethodDesc = new MethodDescriptor("clone", ValueType.object("java.lang.Object")); MethodReference cloneMethod = new MethodReference("java.lang.Object", cloneMethodDesc); assign( Expr.invoke(cloneMethod, Expr.var(insn.getArray().getIndex()), new Expr[0]), insn.getReceiver()); }
@Override public void visit(NewMultiArrayExpr expr) { for (int i = 0; i < expr.getDimensions().size(); ++i) { Expr dimension = expr.getDimensions().get(i); dimension.acceptVisitor(this); expr.getDimensions().set(i, resultExpr); } resultExpr = expr; }
@Override public void visit(AssignInstruction insn) { AssignmentStatement stmt = Statement.assign( Expr.var(insn.getReceiver().getIndex()), Expr.var(insn.getAssignee().getIndex())); stmt.getDebugNames().addAll(insn.getReceiver().getDebugNames()); stmt.setLocation(currentLocation); statements.add(stmt); }
@Override public void visit(WhileStatement statement) { if (statement.getBody().size() == 1 && statement.getBody().get(0) instanceof WhileStatement) { WhileStatement innerLoop = (WhileStatement) statement.getBody().get(0); BreakToContinueReplacer replacer = new BreakToContinueReplacer(innerLoop, statement); replacer.visitSequence(innerLoop.getBody()); statement.getBody().clear(); statement.getBody().addAll(innerLoop.getBody()); } List<Statement> statements = processSequence(statement.getBody()); for (int i = 0; i < statements.size(); ++i) { if (statements.get(i) instanceof ContinueStatement) { ContinueStatement continueStmt = (ContinueStatement) statements.get(i); if (continueStmt.getTarget() == statement) { statements.subList(i, statements.size()).clear(); break; } } } statement.getBody().clear(); statement.getBody().addAll(statements); if (statement.getCondition() != null) { List<Statement> sequenceBackup = resultSequence; resultSequence = new ArrayList<>(); statement.getCondition().acceptVisitor(this); statement.setCondition(resultExpr); resultSequence = sequenceBackup; } while (true) { if (!statement.getBody().isEmpty() && statement.getBody().get(0) instanceof ConditionalStatement) { ConditionalStatement cond = (ConditionalStatement) statement.getBody().get(0); if (cond.getConsequent().size() == 1 && cond.getConsequent().get(0) instanceof BreakStatement) { BreakStatement breakStmt = (BreakStatement) cond.getConsequent().get(0); if (breakStmt.getTarget() == statement) { statement.getBody().remove(0); if (statement.getCondition() != null) { Expr newCondition = Expr.binary( BinaryOperation.AND, statement.getCondition(), ExprOptimizer.invert(cond.getCondition())); newCondition.setLocation(statement.getCondition().getLocation()); statement.setCondition(newCondition); } else { statement.setCondition(ExprOptimizer.invert(cond.getCondition())); } continue; } } } break; } resultStmt = statement; }
@Override public void visit(PutElementInstruction insn) { AssignmentStatement stmt = Statement.assign( Expr.subscript( Expr.var(insn.getArray().getIndex()), Expr.var(insn.getIndex().getIndex())), Expr.var(insn.getValue().getIndex())); stmt.setLocation(currentLocation); statements.add(stmt); }
/** * Prepares this expression for iterative evaluation. The expression can be iteratively evaluated * if no predicate or only the first is positional. * * @return result of check */ protected final boolean posIterator() { // check if first predicate is numeric if (preds.length == 1) { Expr p = preds[0]; if (p instanceof Int) p = Pos.get(((Int) p).itr(), info); pos = p instanceof Pos ? (Pos) p : null; last = p.isFunction(Function.LAST); preds[0] = p; } return pos != null || last; }
@Override public void visit(PutFieldInstruction insn) { Expr right = Expr.var(insn.getValue().getIndex()); Expr left; if (insn.getInstance() != null) { left = Expr.qualify(Expr.var(insn.getInstance().getIndex()), insn.getField()); } else { left = Expr.qualify(null, insn.getField()); } AssignmentStatement stmt = Statement.assign(left, right); stmt.setLocation(currentLocation); statements.add(stmt); }
// add selected vars public void addQueryExpr(String s) { try { Expr expr = model.parseExpr(s); if (expr instanceof RTVar) { addQueryVar(expr); } else { Expr.List vars = new Expr.List(); expr.addNamedExpr(vars); for (int i = 0; i < vars.size(); i++) addQueryVar(vars.expr(i)); } } catch (Xcept e) { // ignore } }
@Override public Expr optimize(final QueryContext ctx, final VarScope scp) throws QueryException { if (root instanceof Context) { ctx.compInfo(OPTREMCTX); root = null; } for (final Expr e : steps) { // check for empty steps if (e.isEmpty()) return optPre(null, ctx); } return this; }
/** Type check the expression. */ public Node typeCheck(TypeChecker tc) throws SemanticException { TypeSystem ts = tc.typeSystem(); if (!ts.isCastValid(expr.type(), castType.type())) { throw new SemanticException( "Cannot cast the expression of type \"" + expr.type() + "\" to type \"" + castType.type() + "\".", position()); } return type(castType.type()); }
/** * Returns the initial context value of a path or {@code null}. * * @param qc query context (may be @code null) * @return root */ private Value initial(final QueryContext qc) { // current context value final Value v = qc != null ? qc.value : null; // no root or context expression: return context if (root == null || root instanceof Context) return v; // root reference if (root instanceof Root) return v != null && v instanceof Item ? Root.root(v) : v; // root is value: return root if (root.isValue()) return (Value) root; // data reference final Data d = root.data(); if (d != null) return new DBNode(d, 0, Data.ELEM); // otherwise, return null return null; }
public App spineForm(Context ctxt, boolean drop_annos, boolean spec, boolean expand_defs) { Expr h = head; Expr prev = null; if (expand_defs) { Expr prev2 = null; while (h != prev) { prev2 = prev; prev = h; h = h.defExpandOne(ctxt, drop_annos, spec); } if (prev2 != null) prev = prev2; if (h.construct != construct && h.construct != CONST && h.construct != VAR) /* we are trying to keep these constructs in the head. */ h = prev; } if (ctxt.getFlag("debug_spine_form")) { ctxt.w.println("Computing spine form of " + toString(ctxt)); ctxt.w.println("{"); ctxt.w.println("Head expands to " + h.toString(ctxt)); ctxt.w.flush(); } App ret = this; if (h.construct == construct) { TermApp e = (TermApp) ((TermApp) h).spineForm(ctxt, drop_annos, spec, expand_defs); int eXlen = e.X.length; int newlen = X.length + eXlen; Expr[] X2 = new Expr[newlen]; boolean[] specarg2 = new boolean[newlen]; for (int i = 0; i < eXlen; i++) { X2[i] = e.X[i]; specarg2[i] = e.specarg[i]; } for (int i = 0, iend = X.length; i < iend; i++) { X2[i + eXlen] = X[i]; specarg2[i + eXlen] = specarg[i]; } ret = new TermApp(e.head, X2, specarg2); } else if (h != head) ret = new TermApp(h, X, specarg); if (ctxt.getFlag("debug_spine_form")) { ret.print(ctxt.w, ctxt); ctxt.w.println("\n}"); ctxt.w.flush(); } return ret; }
public List acceptCFG(CFGBuilder v, List succs) { v.visitCFGList(inits, (cond != null ? cond.entry() : body.entry())); if (cond != null) { if (condIsConstantTrue()) { v.visitCFG(cond, body.entry()); } else { v.visitCFG(cond, FlowGraph.EDGE_KEY_TRUE, body.entry(), FlowGraph.EDGE_KEY_FALSE, this); } } v.push(this).visitCFG(body, continueTarget()); v.visitCFGList(iters, (cond != null ? cond.entry() : body.entry())); return succs; }
public List throwTypes(TypeSystem ts) { if (expr.type().isReference()) { return Collections.singletonList(ts.ClassCastException()); } return Collections.EMPTY_LIST; }
/** * Checks if the path can be rewritten for iterative evaluation. * * @param root root expression; can be a {@code null} reference * @param steps path steps * @return result of check */ private static boolean iterative(final Expr root, final Expr... steps) { if (root == null || !root.iterable()) return false; final int sl = steps.length; for (int s = 0; s < sl; ++s) { switch (((Step) steps[s]).axis) { // reverse axes - don't iterate case ANC: case ANCORSELF: case PREC: case PRECSIBL: return false; // multiple, unsorted results - only iterate at last step, // or if last step uses attribute axis case DESC: case DESCORSELF: case FOLL: case FOLLSIBL: return s + 1 == sl || s + 2 == sl && ((Step) steps[s + 1]).axis == Axis.ATTR; // allow iteration for CHILD, ATTR, PARENT and SELF axes default: } } return true; }
public boolean subtermDefEqNoAnno(Context ctxt, Expr e) { // This check is captured below, all arguments always evaluated for a terminating term // // If it's a TermApp of a constructor, we need to look at all the sub expressions // if (head.construct == CONST && ctxt.isTermCtor((Const)head)) { // for (int i = 0; i < X.length; i++) // //if (X[i].defEqNoAnno(ctxt, e)) // if (X[i].subtermDefEqNoAnno(ctxt, e)) // return true; // return false; // } else { // Same as the head? // Same as the whole application? ("this") if (head.subtermDefEqNoAnno(ctxt, e) || super.subtermDefEqNoAnno(ctxt, e)) return true; // In our CBV instantiated function evaluation scheme, all arguments are evaluated, so check // equality for (int i = 0; i < X.length; i++) if (X[i].subtermDefEqNoAnno(ctxt, e)) return true; // Same as any of the spline form TermApp "heads"? for (int i = 0; i < X.length; i++) { Expr[] newX = new Expr[i + 1]; for (int j = 0; j <= i; j++) { newX[j] = X[j]; } if (e.defEqNoAnno(ctxt, new TermApp(head, newX), true)) return true; } return false; // } }
/** * Perform type propagation through a given expression, returning the type of value that is * returned by evaluating this expression. * * @param e * @param environment * @param generics * @param context * @return */ private SemanticType propagate( Expr e, HashMap<String, SemanticType> environment, HashSet<String> generics, WyalFile.Context context) { SemanticType t; if (e instanceof Expr.Variable) { t = propagate((Expr.Variable) e, environment, generics, context); } else if (e instanceof Expr.Constant) { t = propagate((Expr.Constant) e, environment, generics, context); } else if (e instanceof Expr.Unary) { t = propagate((Expr.Unary) e, environment, generics, context); } else if (e instanceof Expr.Binary) { t = propagate((Expr.Binary) e, environment, generics, context); } else if (e instanceof Expr.Ternary) { t = propagate((Expr.Ternary) e, environment, generics, context); } else if (e instanceof Expr.Nary) { t = propagate((Expr.Nary) e, environment, generics, context); } else if (e instanceof Expr.Quantifier) { t = propagate((Expr.Quantifier) e, environment, generics, context); } else if (e instanceof Expr.FunCall) { t = propagate((Expr.FunCall) e, environment, generics, context); } else if (e instanceof Expr.IndexOf) { t = propagate((Expr.IndexOf) e, environment, generics, context); } else { internalFailure("unknown expression encountered (" + e + ")", filename, e); return null; } e.attributes().add(new TypeAttribute(t)); return returnType(e); }