/** Desugar a generalized While clause. */ @Override public Node forWhile(While w) { GeneratorClause g = w.getTestExpr(); if (g.getBind().size() > 0) { // while binds <- expr do body end // desugars to // while __whileCond(expr, fn (binds) => body) do end ArrayList<Expr> args = new ArrayList<Expr>(2); args.add(g.getInit()); args.add(bindsAndBody(g, w.getBody())); Expr cond = ExprFactory.make_RewriteFnApp( NodeUtil.getSpan(g), WHILECOND_NAME, ExprFactory.makeTupleExpr(NodeUtil.getSpan(w), args)); w = ExprFactory.makeWhile(NodeUtil.getSpan(w), cond); } return (Expr) super.forWhile(w); }
/** * Add an if clause to a (potentially) pre-existing else clause. The else clase can be null, or * can be an if expression. */ private Expr addIfClause(IfClause c, Expr elsePart) { GeneratorClause g = c.getTestClause(); if (g.getBind().size() > 0) { // if binds <- expr then body else elsePart end desugars to // __cond(expr, fn (binds) => body, elsePart) ArrayList<Expr> args = new ArrayList<Expr>(3); args.add(g.getInit()); args.add(bindsAndBody(g, c.getBody())); if (elsePart != null) args.add(thunk(elsePart)); return (Expr) recur( ExprFactory.make_RewriteFnApp( NodeUtil.getSpan(c), COND_NAME, ExprFactory.makeTupleExpr(NodeUtil.getSpan(c), args))); } // if expr then body else elsePart end is preserved // (but we replace elif chains by nesting). if (elsePart == null) { return (Expr) super.forIf(ExprFactory.makeIf(NodeUtil.getSpan(c), c)); } else { return (Expr) super.forIf(ExprFactory.makeIf(NodeUtil.getSpan(c), c, ExprFactory.makeBlock(elsePart))); } }
private Expr cleanupOpExpr(OpExpr opExp) { FunctionalRef ref = opExp.getOp(); List<Expr> args = opExp.getArgs(); if (args.size() <= 1) return opExp; IdOrOp name = ref.getNames().get(0); if (!(name instanceof Op)) return bug(name, "The name field of OpRef should be Op."); Op qop = (Op) name; if (OprUtil.isEnclosing(qop)) return opExp; if (OprUtil.isUnknownFixity(qop)) return bug(opExp, "The operator fixity is unknown: " + ((Op) qop).getText()); boolean prefix = OprUtil.hasPrefixColon(qop); boolean suffix = OprUtil.hasSuffixColon(qop); if (!prefix && !suffix) return opExp; qop = OprUtil.noColon(qop); Iterator<Expr> i = args.iterator(); Expr res = i.next(); Span sp = NodeUtil.getSpan(opExp); for (Expr arg : Iter.iter(i)) { if (prefix) { res = thunk(res); } if (suffix) { arg = thunk(arg); } res = ExprFactory.makeOpExpr(sp, qop, res, arg); } return res; }
/** * @param loc Containing context * @param gens Generators in generator list * @return single generator equivalent to the generator list Desugars as follows: body, empty => * body body, x <- exp, gs => exp.loop(fn x => body, gs) */ Expr visitLoop(Span span, List<GeneratorClause> gens, Expr body) { for (int i = gens.size() - 1; i >= 0; i--) { GeneratorClause g = gens.get(i); Expr loopBody = bindsAndBody(g, body); body = ExprFactory.makeMethodInvocation(NodeUtil.getSpan(g), g.getInit(), LOOP_NAME, loopBody); } // System.out.println("Desugared to "+body.toStringVerbose()); return (Expr) recur(body); }
@Override public Node forSubscriptExpr(SubscriptExpr that) { if (!Shell.getAssignmentPreDesugaring()) { return super.forSubscriptExpr(that); } else { // Rewrite a subscript expression into a method call (pretty straightforward) Expr obj = that.getObj(); List<Expr> subs = that.getSubs(); Option<Op> op = that.getOp(); List<StaticArg> staticArgs = that.getStaticArgs(); if (!op.isSome()) bug(that, "Subscript operator expected"); Op knownOp = op.unwrap(); Expr result = ExprFactory.makeMethodInvocation( that, obj, knownOp, staticArgs, ExprFactory.makeTupleExpr(NodeUtil.getSpan(knownOp), subs)); return (Expr) recur(result); } }
private Expr visitAccumulator( Span span, List<GeneratorClause> gens, Op op, Expr body, List<StaticArg> staticArgs, boolean isParen) { body = visitGenerators(span, gens, body); /** * * If the accumulation is a nested reduction like BIG OP [ys <- gg] BIG OT <| f y | y <- ys |> * , visitGenerators returns a tuple of ((BIG OT, f), gg) (this should be refactored, though) */ Expr res; if (body instanceof FnExpr) { Expr opexp = ExprFactory.makeOpExpr(span, op, staticArgs); res = ExprFactory.make_RewriteFnApp( span, BIGOP_NAME, ExprFactory.makeTupleExpr(span, opexp, body)); } else if (body instanceof TupleExpr) { /** * * For BIG OP [ys <- gg] BIG OT <| f y | y <- ys |> The nested reduction is replaced with * __bigOperator2(BIG OP, BIG OT, gg) * * <p>This is similar to forOpExpr(OpExpr that) . * * <p>by Kento */ // a tuple of the inner Accumulator (op, body) and the gg TupleExpr tuple = (TupleExpr) body; TupleExpr innerAccumTuple = (TupleExpr) tuple.getExprs().get(0); Expr opexpI = (Expr) innerAccumTuple.getExprs().get(0); Expr innerBody = (Expr) innerAccumTuple.getExprs().get(1); Expr opexpO = ExprFactory.makeOpExpr(span, op, staticArgs); Expr gg = tuple.getExprs().get(1); res = ExprFactory.make_RewriteFnApp( span, BIGOP2_NAME, ExprFactory.makeTupleExpr(span, opexpO, opexpI, gg, innerBody)); } else res = bug(body, "Function expressions or tuple expressions are expected."); if (isParen) res = ExprFactory.makeInParentheses(res); return (Expr) recur(res); }
@Override public Node forAmbiguousMultifixOpExpr(AmbiguousMultifixOpExpr that) { // If there is a colon at all, the operator is no longer ambiguous: // It must be infix. IdOrOp name = that.getInfix_op().getNames().get(0); if (!(name instanceof Op)) return bug(name, "The name field of OpRef should be Op."); Op op_name = (Op) name; boolean prefix = OprUtil.hasPrefixColon(op_name); boolean suffix = OprUtil.hasSuffixColon(op_name); if (prefix || suffix) { OpExpr new_op = ExprFactory.makeOpExpr( NodeUtil.getSpan(that), NodeUtil.isParenthesized(that), NodeUtil.getExprType(that), that.getInfix_op(), that.getArgs()); return recur(new_op); } else { return super.forAmbiguousMultifixOpExpr(that); } }
@Override public Node forAssignment(Assignment that) { // System.out.println("PreDesugar entry"); // Here there are three sorts of rewrite to consider: // (a) If this is a compound assignment, rewrite to use ordinary assignment. // (b) If the lhs is a tuple, rewrite into a set of individual assignments. // (c) If the lhs is a subscript expression, rewrite to a method call. List<Lhs> lhs = that.getLhs(); Option<FunctionalRef> assignOp = that.getAssignOp(); Expr rhs = that.getRhs(); List<CompoundAssignmentInfo> assignmentInfos = that.getAssignmentInfos(); if (!Shell.getAssignmentPreDesugaring()) { // System.out.println("Did not PreDesugar"); return super.forAssignment(that); } else if (assignOp.isSome() || lhs.size() > 1) { // System.out.println("Compound/tuple PreDesugar"); // Compound and/or tuple assignment // The basic idea is to transform `(a, b.field, c[sub1,sub2]) := e` into // `do (ta, tb, tc, tsub1, tsub2, (t1, t2, t3)) = (a, b, c, sub1, sub2, e) // a := t1; tb.field := t2; tc[tsub1, tsub2] := t3 end` // (TODO) Unfortunately, currently we don't handle nested binding tuples. // For now, we'll just transform it into // `do (ta, tb, tc, tsub1, tsub2) = (a, b, c, sub1, sub2) // (t1, t2, t3) = e // a := t1; tb.field := t2; tc[tsub1, tsub2] := t3 end` // which merely loses a bit of potential parallelism. // We omit the first tuple binding if the tuple is empty. // If it is a compound assignment `(a, b.field, c[sub1,sub2]) OP= e`, it becomes // `do (ta, tb, tc, tsub1, tsub2) = (a, b, c, sub1, sub2) // (t1, t2, t3) = (ta, tb, tc[tsub1, tsub2]) OP e // a := t1; tb.field := t2; tc[tsub1, tsub2] := t3 end` List<LValue> exprLValues = Useful.list(); List<LValue> otherLValues = Useful.list(); List<Expr> otherExprs = Useful.list(); List<Expr> assignments = Useful.list(); boolean isCompound = assignOp.isSome(); List<Expr> accesses = Useful.list(); Span thatSpan = NodeUtil.getSpan(that); for (Lhs lh : lhs) { Span lhSpan = NodeUtil.getSpan((Expr) lh); Id tempId = DesugarerUtil.gensymId(lhSpan, "e"); VarRef tempVar = ExprFactory.makeVarRef(lhSpan, tempId); exprLValues = Useful.snoc(exprLValues, NodeFactory.makeLValue(lhSpan, tempId)); if (lh instanceof SubscriptExpr) { SubscriptExpr lhsub = (SubscriptExpr) lh; Expr obj = lhsub.getObj(); Span objSpan = NodeUtil.getSpan(obj); List<Expr> subs = lhsub.getSubs(); Id baseTempId = DesugarerUtil.gensymId(objSpan, "b"); VarRef baseTempVar = ExprFactory.makeVarRef(objSpan, baseTempId); otherLValues = Useful.snoc(otherLValues, NodeFactory.makeLValue(objSpan, baseTempId)); otherExprs = Useful.snoc(otherExprs, obj); List<Expr> subTempVars = Useful.list(); for (Expr sub : lhsub.getSubs()) { Span subSpan = NodeUtil.getSpan(sub); Id subTempId = DesugarerUtil.gensymId(subSpan, "s"); subTempVars = Useful.snoc(subTempVars, ExprFactory.makeVarRef(subSpan, subTempId)); otherLValues = Useful.snoc(otherLValues, NodeFactory.makeLValue(subSpan, subTempId)); } otherExprs = Useful.concat(otherExprs, subs); SubscriptExpr newLhs = ExprFactory.makeSubscriptExpr( NodeUtil.getSpan(lhsub), baseTempVar, subTempVars, lhsub.getOp(), lhsub.getStaticArgs()); if (isCompound) accesses = Useful.snoc(accesses, newLhs); assignments = Useful.snoc(assignments, ExprFactory.makeAssignment(thatSpan, newLhs, tempVar)); } else if (lh instanceof FieldRef) { FieldRef lhref = (FieldRef) lh; Expr obj = lhref.getObj(); Span objSpan = NodeUtil.getSpan(obj); Id objTempId = DesugarerUtil.gensymId(objSpan, "o"); VarRef objTempVar = ExprFactory.makeVarRef(objSpan, objTempId); otherLValues = Useful.snoc(otherLValues, NodeFactory.makeLValue(objSpan, objTempId)); otherExprs = Useful.snoc(otherExprs, obj); FieldRef newLhs = ExprFactory.makeFieldRef(NodeUtil.getSpan(lhref), objTempVar, lhref.getField()); if (isCompound) accesses = Useful.snoc(accesses, newLhs); assignments = Useful.snoc(assignments, ExprFactory.makeAssignment(thatSpan, newLhs, tempVar)); } else if (lh instanceof VarRef) { VarRef lhvar = (VarRef) lh; Span varSpan = NodeUtil.getSpan(lhvar); Id varTempId = DesugarerUtil.gensymId(varSpan, "v"); VarRef varTempVar = ExprFactory.makeVarRef(varSpan, varTempId); otherLValues = Useful.snoc(otherLValues, NodeFactory.makeLValue(varSpan, varTempId)); otherExprs = Useful.snoc(otherExprs, lhvar); if (isCompound) accesses = Useful.snoc(accesses, varTempVar); assignments = Useful.snoc(assignments, ExprFactory.makeAssignment(thatSpan, lhvar, tempVar)); } else { bug(that, "Malformed assignment LHS"); } } Expr result = ExprFactory.makeBlock(thatSpan, assignments); if (otherExprs.size() > 0) { Expr otherRhs = ExprFactory.makeMaybeTupleExpr(thatSpan, otherExprs); result = ExprFactory.makeLocalVarDecl(thatSpan, otherLValues, otherRhs, result); } Expr newRhs = isCompound ? ExprFactory.makeOpExpr( NodeUtil.spanTwo(assignOp.unwrap(), rhs), assignOp.unwrap(), ExprFactory.makeMaybeTupleExpr(thatSpan, accesses), rhs) : rhs; result = ExprFactory.makeLocalVarDecl(thatSpan, exprLValues, newRhs, result); return (Expr) recur(result); } else if (lhs.get(0) instanceof SubscriptExpr) { // System.out.println("PreDesugar single subscript expr"); // Subscripted assignment SubscriptExpr lhExpr = (SubscriptExpr) lhs.get(0); Expr obj = lhExpr.getObj(); List<Expr> subs = lhExpr.getSubs(); Option<Op> op = lhExpr.getOp(); List<StaticArg> staticArgs = lhExpr.getStaticArgs(); if (!op.isSome()) bug(lhExpr, "Subscript operator expected"); Op knownOp = op.unwrap(); Expr result = ExprFactory.makeMethodInvocation( that, obj, NodeFactory.makeOp(knownOp, knownOp.getText() + ":="), staticArgs, ExprFactory.makeTupleExpr(NodeUtil.spanTwo(knownOp, rhs), Useful.cons(rhs, subs))); return (Expr) recur(result); } else { // System.out.println("PreDesugar single expr of class " + lhs.get(0).getClass().getName()); return super.forAssignment(that); } }
@Override public Node forFor(For f) { Block df = f.getBody(); Do doBlock = ExprFactory.makeDo(NodeUtil.getSpan(df), Useful.list(df)); return visitLoop(NodeUtil.getSpan(f), f.getGens(), doBlock); }
private static Expr thunk(Expr e) { return ExprFactory.makeFnExpr(NodeUtil.getSpan(e), Collections.<Param>emptyList(), e); }
@Override public Node forOpExpr(OpExpr that) { FunctionalRef op_result = (FunctionalRef) recur(that.getOp()); /** * * For BIG OP <| BIG OT <| f y | y <- ys |> | ys <- gg |> Is this case, BIG <||> is being * removed. The nested reduction is replaced with __bigOperator2(BIG OP, BIG OT, gg) * * <p>by Kento */ String str = op_result.toString(); String theListEnclosingOperatorName = "BIG <| BIG |>"; String someBigOperatorName = "BIG"; // make sure the body is of application of some big operator if ((str.length() >= someBigOperatorName.length() && str.substring(0, someBigOperatorName.length()).equals(someBigOperatorName))) { // make sure that BIG OP (Accumulator (BIG <||>, gs)) if (that.getArgs().size() == 1 && that.getArgs().get(0) instanceof Accumulator && ((Accumulator) that.getArgs().get(0)) .getAccOp() .toString() .equals(theListEnclosingOperatorName)) { Accumulator acc = (Accumulator) that.getArgs().get(0); Expr body = visitGenerators(NodeUtil.getSpan(acc), acc.getGens(), acc.getBody()); /** * * If the accumulation is a nested reduction like <| BIG OT <| f y | y <- ys |> | ys <- gg * |> , visitGenerators returns a tuple of ((BIG OT, f), gg) (this should be refactored, * though) In this case, the nested reduction is replaced with __bigOperator2 */ if (body instanceof TupleExpr) { // a tuple of the inner Accumulator (op, body) and the gg TupleExpr tuple = (TupleExpr) body; TupleExpr innerAccumTuple = (TupleExpr) tuple.getExprs().get(0); Expr opexpI = (Expr) innerAccumTuple.getExprs().get(0); Expr innerBody = (Expr) innerAccumTuple.getExprs().get(1); FunctionalRef ref = (FunctionalRef) op_result; IdOrOp name = ref.getNames().get(0); // make sure the operator is actually an operator if (!(name instanceof Op)) return null; Expr opexpO = ExprFactory.makeOpExpr(NodeUtil.getSpan(that), (Op) name, ref.getStaticArgs()); Expr gg = tuple.getExprs().get(1); Expr res = ExprFactory.make_RewriteFnApp( NodeUtil.getSpan(that), BIGOP2_NAME, ExprFactory.makeTupleExpr(NodeUtil.getSpan(body), opexpO, opexpI, gg, innerBody)); return (Expr) recur(res); } } } List<Expr> args_result = recurOnListOfExpr(that.getArgs()); OpExpr new_op; if (op_result == that.getOp() && args_result == that.getArgs()) { new_op = that; } else { new_op = ExprFactory.makeOpExpr( NodeUtil.getSpan(that), NodeUtil.isParenthesized(that), NodeUtil.getExprType(that), op_result, args_result); } return cleanupOpExpr(new_op); }