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; }
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 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); }