/** {@inheritDoc} */ @Override public void toString(StringBuilder out, int indent) { if (indent < 0) { out.append(fun.label); if (args.size() == 0) return; out.append('['); for (int i = 0; i < args.size(); i++) { if (i > 0) out.append(", "); args.get(i).toString(out, -1); } out.append(']'); } else { for (int i = 0; i < indent; i++) { out.append(' '); } out.append("call ") .append(fun) .append(" at position <") .append(fun.pos) .append("> with type=") .append(type) .append('\n'); for (Expr a : args) { a.toString(out, indent + 2); } } }
/** * Returns true if we can determine the two expressions are equivalent; may sometimes return * false. */ @Override public boolean isSame(Expr obj) { while (obj instanceof ExprUnary && ((ExprUnary) obj).op == ExprUnary.Op.NOOP) obj = ((ExprUnary) obj).sub; if (obj == this) return true; if (!(obj instanceof ExprCall)) return false; ExprCall x = (ExprCall) obj; if (fun != x.fun || args.size() != x.args.size()) return false; for (int i = 0; i < args.size(); i++) if (!args.get(i).isSame(x.args.get(i))) return false; return true; }
/** {@inheritDoc} */ @Override public List<? extends Browsable> getSubnodes() { if (args.size() == 0) { Expr b = fun.getBody(); return Util.asList(make(b.pos(), b.span(), b.getHTML(), b.getSubnodes())); } Pos p = pos; if (p == Pos.UNKNOWN) p = span(); Browsable f = make(p, p, (fun.isPred ? "<b>pred</b> " : "<b>fun</b> ") + fun.label, fun.getSubnodes()); Browsable a = make( span(), span(), "<b>" + args.size() + " argument" + (args.size() == 1 ? "</b>" : "s</b>"), args); return Util.asList(f, a); }
/** * Constructs an ExprCall node with the given predicate/function "fun" and the list of arguments * "args". */ public static Expr make( Pos pos, Pos closingBracket, Func fun, List<Expr> args, long extraPenalty) { if (extraPenalty < 0) extraPenalty = 0; if (args == null) args = ConstList.make(); long weight = extraPenalty; boolean ambiguous = false; JoinableList<Err> errs = emptyListOfErrors; TempList<Expr> newargs = new TempList<Expr>(args.size()); if (args.size() != fun.count()) { errs = errs.make( new ErrorSyntax( pos, "" + fun + " has " + fun.count() + " parameters but is called with " + args.size() + " arguments.")); } for (int i = 0; i < args.size(); i++) { final int a = (i < fun.count()) ? fun.get(i).type.arity() : 0; final Expr x = args.get(i).typecheck_as_set(); ambiguous = ambiguous || x.ambiguous; errs = errs.make(x.errors); weight = weight + x.weight; if (x.mult != 0) errs = errs.make(new ErrorSyntax(x.span(), "Multiplicity expression not allowed here.")); if (a > 0 && x.errors.isEmpty() && !x.type.hasArity(a)) errs = errs.make( new ErrorType( x.span(), "This should have arity " + a + " but instead its possible type(s) are " + x.type)); newargs.add(x); } Type t = Type.FORMULA; if (!fun.isPred && errs.size() == 0) { final Type tt = fun.returnDecl.type; try { // This provides a limited form of polymorphic function, // by using actual arguments at each call site to derive a tighter bound on the return // value. DeduceType d = new DeduceType(); for (int i = 0; i < args.size(); i++) { ExprVar param = fun.get(i); d.env.put(param, newargs.get(i).type.extract(param.type.arity())); } t = fun.returnDecl.accept(d); if (t == null || t.is_int() || t.is_bool || t.arity() != tt.arity()) t = tt; // Just in case an error occurred... } catch (Throwable ex) { t = tt; // Just in case an error occurred... } } return new ExprCall( pos, closingBracket, ambiguous, t, fun, newargs.makeConst(), extraPenalty, weight, errs); }