private static APIName cuName(String fileName) { if (fileName.endsWith(ProjectProperties.COMP_SOURCE_SUFFIX) || fileName.endsWith(ProjectProperties.API_SOURCE_SUFFIX)) { return NodeFactory.makeAPIName( NodeFactory.shellSpan, fileName.substring(0, fileName.lastIndexOf("."))); } return NodeFactory.makeAPIName(NodeFactory.shellSpan, fileName); }
/** * If the extends clause of a trait declaration, an object declaration, or an object expression is * empty, then replace the empty extends clause with {Object}. */ private List<TraitTypeWhere> rewriteExtendsClause( Node whence, List<TraitTypeWhere> extendsClause) { if (extendsClause.size() > 0) return extendsClause; if (!(whence instanceof ASTNode)) bug(whence, "Only ASTNodes are supported."); Id objectId = NodeFactory.makeId(NodeUtil.getSpan((ASTNode) whence), WellKnownNames.objectTypeName); TraitType typeObject = NodeFactory.makeTraitType(objectId); TraitTypeWhere extendsObject = NodeFactory.makeTraitTypeWhere(typeObject); return Collections.singletonList(extendsObject); }
public TypeCheckerResult removeStaticParamsFromScope(List<StaticParam> staticParams) { List<VarType> var_types = new LinkedList<VarType>(); for (StaticParam static_param : staticParams) { if (NodeUtil.isTypeParam(static_param)) { var_types.add( NodeFactory.makeVarType(NodeUtil.getSpan(static_param), (Id) static_param.getName())); } } return new TypeCheckerResult(this.ast, this.type, this.errors()); }
@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); } }
/** * Run desugaring phases that must occur after disambiguation and before type checking. 1) Desugar * compound/tuple assignments (this requires identifying subexpressions of LHS) 2) Desugar * subscripting expressions to method calls. 3) Desugar subscripting assignments */ public class PreTypeCheckDesugaringVisitor extends NodeUpdateVisitor { private final Id anyTypeId = NodeFactory.makeId(NodeFactory.makeSpan("singleton"), WellKnownNames.anyTypeName); /** * If the extends clause of a trait declaration, an object declaration, or an object expression is * empty, then replace the empty extends clause with {Object}. */ private List<TraitTypeWhere> rewriteExtendsClause( Node whence, List<TraitTypeWhere> extendsClause) { if (extendsClause.size() > 0) return extendsClause; if (!(whence instanceof ASTNode)) bug(whence, "Only ASTNodes are supported."); Id objectId = NodeFactory.makeId(NodeUtil.getSpan((ASTNode) whence), WellKnownNames.objectTypeName); TraitType typeObject = NodeFactory.makeTraitType(objectId); TraitTypeWhere extendsObject = NodeFactory.makeTraitTypeWhere(typeObject); return Collections.singletonList(extendsObject); } /* THESE THREE METHODS ARE SUSPECT @Override public Node forObjectExprOnly(ObjectExpr that, ExprInfo info, TraitTypeHeader header, Option<SelfType> selfType) { SelfTypeBoundsInserter bi = new SelfTypeBoundsInserter(); that = (ObjectExpr)that.accept(bi); header = (TraitTypeHeader)header.accept(bi); Span span = NodeUtil.getSpan(that); List<TraitTypeWhere> extendsClause = rewriteExtendsClause(that, header.getExtendsClause()); header = NodeFactory.makeTraitTypeHeader(NodeFactory.makeId(span,"_"), extendsClause, header.getDecls()); return super.forObjectExprOnly(that, info, header, selfType); } @Override public Node forTraitDecl(TraitDecl that) { that = (TraitDecl)that.accept(new SelfTypeBoundsInserter()); TraitTypeHeader header_result = (TraitTypeHeader) recur(that.getHeader()); List<BaseType> excludesClause_result = recurOnListOfBaseType(that.getExcludesClause()); Option<List<NamedType>> comprisesClause_result = recurOnOptionOfListOfNamedType(that.getComprisesClause()); if (!NodeUtil.getName(that).equals(anyTypeId)) { header_result = NodeFactory.makeTraitTypeHeader(header_result, rewriteExtendsClause(that, header_result.getExtendsClause())); } return super.forTraitDeclOnly(that, that.getInfo(), header_result, that.getSelfType(), excludesClause_result, comprisesClause_result); } @Override public Node forObjectDecl(ObjectDecl that) { that = (ObjectDecl)that.accept(new SelfTypeBoundsInserter()); TraitTypeHeader header_result = (TraitTypeHeader) recur(that.getHeader()); Option<List<Param>> params_result = recurOnOptionOfListOfParam(NodeUtil.getParams(that)); header_result = NodeFactory.makeTraitTypeHeader(header_result, rewriteExtendsClause(that, header_result.getExtendsClause()), params_result); return super.forObjectDeclOnly(that, that.getInfo(), header_result, that.getSelfType()); } TO HERE */ @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 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); } private static Expr thunk(Expr e) { return ExprFactory.makeFnExpr(NodeUtil.getSpan(e), Collections.<Param>emptyList(), e); } 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; } /** Given generalized if expression, desugar into __cond calls (binding) where required. */ @Override public Node forIf(If i) { List<IfClause> clauses = i.getClauses(); int n = clauses.size(); if (n <= 0) bug(i, "if with no clauses!"); for (IfClause c : clauses) { if (c.getTestClause().getBind().size() == 0) continue; // If we get here we have a generalized if. // Desugar it into nested ifs and calls. // Then return the desugared result. Expr result = null; if (i.getElseClause().isSome()) { result = i.getElseClause().unwrap(); } // Traverse each clause and desugar it into an if or a __cond as appropriate. for (--n; n >= 0; --n) { result = addIfClause(clauses.get(n), result); } return result; } // If we get here, it's not a generalized if. Just recur. return super.forIf(i); } /** * 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))); } } /** 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); } @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); } /** * @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 forAccumulator(Accumulator that) { return visitAccumulator( NodeUtil.getSpan(that), that.getGens(), that.getAccOp(), that.getBody(), that.getStaticArgs(), that.getInfo().isParenthesized()); } 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 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); } } @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); } } // private Block forCaseClauses(Expr e1, FunctionalRef comp, List<CaseClause> l, Option<Block> // def) { // // int size = l.size(); // // if (size == 0) // throw new Error("Desugarer found no case clauses in a case expression, please report."); // // // CaseClause c = l.get(0); // l.remove(0); // Expr e2 = c.getMatchClause(); // List<Expr> tuple = new ArrayList<Expr>(); // tuple.add(e1); // tuple.add(e2); // Expr arg = ExprFactory.makeTupleExpr(NodeFactory.desugarerSpan, tuple); // Expr cond = ExprFactory.make_RewriteFnApp(comp, arg); // If i; // // if (size > 1) { // i = ExprFactory.makeIf(NodeFactory.desugarerSpan, cond, c.getBody(), // forCaseClauses(e1,comp,l,def)); // } else if (def.isSome()) { // i = ExprFactory.makeIf(NodeFactory.desugarerSpan, cond, c.getBody(), def.unwrap()); // } else { // Expr ex = ExprFactory.makeThrow(NodeFactory.desugarerSpan, "MatchFailure"); // i = ExprFactory.makeIf(NodeFactory.desugarerSpan, cond, // c.getBody(),ExprFactory.makeBlock(ex)); // } // // return ExprFactory.makeBlock(i); // // } // // @Override // public Node forCaseExpr(CaseExpr x) { // // if (x.getParam().isNone()) // throw new Error("Desugaring failed for case expression. The case expression has no // conditional expression. Please report."); // // NameOracle naming = new NameOracle(this); // Id fresh = naming.makeId(); // // Option<FunctionalRef> fn_op = x.getCompare(); // FunctionalRef fn; // // if (fn_op.isSome()) { // fn = fn_op.unwrap(); // } else { // fn = x.getEqualsOp(); // } // // Block cascade = // forCaseClauses(ExprFactory.makeVarRef(NodeFactory.desugarerSpan,fresh),fn,x.getClauses(),x.getElseClause()); // // return ExprFactory.makeLocalVarDecl(fresh ,x.getParam().unwrap(), cascade); // // } }