private void compileTestProgram(String testFileName) throws UserError {
    Path path = ProjectProperties.SOURCE_PATH;
    String s = ProjectProperties.BASEDIR + "tests" + File.separator + testFileName;

    //        System.err.println("compileTestProgram(" + s + ")");

    File file = new File(s);
    s = file.getPath();

    if (s.contains(File.separator)) {
      String head = s.substring(0, s.lastIndexOf(File.separator));
      s = s.substring(s.lastIndexOf(File.separator) + 1, s.length());
      path = path.prepend(head);
    }

    // HACK: We need to compile these test programs using the old Fortress
    // libraries instead of the new compiler libraries.
    // Shell.useFortressLibraries();

    Iterable<? extends StaticError> errors = Shell.compilerPhases(path, s);

    for (StaticError error : errors) {
      fail(error.toString());
    }
  }
  /* (non-Javadoc)
   * @see junit.framework.TestCase#setUp()
   */
  @Override
  protected void setUp() throws Exception {
    Shell.setPhaseOrder(PhaseOrder.interpreterPhaseOrder);
    Shell.setScala(false);
    fssFiles = new String[4];
    fsiFiles = new String[3];

    fssFiles[0] = "TestCompiledEnvironments";
    fssFiles[1] = "TestCompiledImports";
    fssFiles[2] = "TestCompiledNestedImports";
    fssFiles[3] = WellKnownNames.fortressLibrary();

    for (String fssFile : fssFiles) {
      compileTestProgram(fssFile + ".fss");
    }
    testCompiledEnv = SimpleClassLoader.loadEnvironment(fssFiles[0], false);
    testCompiledImportEnv = SimpleClassLoader.loadEnvironment(fssFiles[1], false);
    testCompiledNestedImportEnv = SimpleClassLoader.loadEnvironment(fssFiles[2], false);
    testLibraryEnv = SimpleClassLoader.loadEnvironment(fssFiles[3], false);

    fsiFiles[0] = "AsciiVal";
    fsiFiles[1] = "a.b.NestedOne";
    fsiFiles[2] = "a.b.c.d.NestedTwo";
  }
 @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);
   }
 }