==== Patch <unparse> level 1
Source: 1adc4bfb-2c32-0410-81b9-bf0f0eac59bd:/unparse:74426
Target: 737f8f2c-97f8-0310-ac9b-cfac8cc1a2f5:/eng/third-party/janino/trunk:72599
        (svn+ssh://svn.streambase.com/repos/sb)
Log:
 r74425@spiceweasel:  fowles | 2008-05-22 13:20:29 -0400
 creating a branch for local unparse fixes
 
 r74426@spiceweasel:  fowles | 2008-05-22 13:51:26 -0400
 Add more tests and fix a few small problems in Unparsing
 

=== tests/src/UnparseTests.java
==================================================================
--- tests/src/UnparseTests.java	(revision 72599)
+++ tests/src/UnparseTests.java	(patch unparse level 1)
@@ -331,21 +331,32 @@
         final String[][] exprs = new String[][] {
               //input                                  expected simplified                    expect non-simplified
             { "((1)+2)",                               "1 + 2",                               "((1) + 2)"           },
+            { "1 - 2 + 3",                             null,                                  null                  },
+            { "(1 - 2) + 3",                           "1 - 2 + 3",                           null                  },
+            { "1 - (2 + 3)",                           "1 - (2 + 3)",                         null                  },
             { "1 + 2 * 3",                             null,                                  null                  },
             { "1 + (2 * 3)",                           "1 + 2 * 3",                           null                  },
             { "3 - (2 - 1)",                           null,                                  null                  },
             { "true ? 1 : 2",                          null,                                  null                  },
             { "(true ? false : true) ? 1 : 2",         null,                                  null                  },
             { "true ? false : (true ? false : true)",  "true ? false : true ? false : true",  null                  },
-            { "-(-(2))",                               "-(-2)",                               null                  },
+            { "-(-(2))",                               "-(-2)",                               "-(-(2))"             },
             { "- - 2",                                 "-(-2)",                               "-(-2)"               },
             { "x && (y || z)",                         null,                                  null                  },
             { "(x && y) || z",                         "x && y || z",                         null                  },
             { "x = (y = z)",                           "x = y = z",                           null                  },
+            { "x *= (y *= z)",                         "x *= y *= z",                         null                  },
             { "(--x) + 3",                             "--x + 3",                             null                  },
             { "(baz.bar).foo(x, (3 + 4) * 5)",         "baz.bar.foo(x, (3 + 4) * 5)",         null                  },
             { "!(bar instanceof Integer)",             null,                                  null                  },
             { "(true ? foo : bar).baz()",              null,                                  null                  },
+            { "((String) foo).length()",               null,                                  null                  },
+            { "-~2",                                   "-(~2)",                               "-(~2)"               },            
+            { "(new String[1])[0]",                    null,                                  null                  },
+            { "(new String()).length()",               null,                                  null                  },
+            { "(new int[] { 1, 2 })[0]",               "new int[] { 1, 2 }[0]",               null                  },
+            { "(\"asdf\" + \"qwer\").length()",        null,                                  null                  },
+            { "-(a++)",                                "-a++",                                null                  },
         };
         
         for(int i = 0; i < exprs.length; ++i) {
=== src/org/codehaus/janino/UnparseVisitor.java
==================================================================
--- src/org/codehaus/janino/UnparseVisitor.java	(revision 72599)
+++ src/org/codehaus/janino/UnparseVisitor.java	(patch unparse level 1)
@@ -503,7 +503,7 @@
     private void unparse(Java.Atom operand) {
         ((Java.Atom) operand).accept(this);
     }
-
+    
     /**
      * Iff the <code>operand</code> is unnatural for the <code>unaryOperator</code>, enclose the
      * <code>operand</code> in parentheses. Example: "a+b" is an unnatural operand for unary "!x". 
@@ -512,7 +512,7 @@
      */
     private void unparseUnaryOperation(Java.Rvalue operand, String unaryOperator) {
         int cmp = UnparseVisitor.comparePrecedence(unaryOperator, operand);
-        this.unparse(operand, cmp <= 0);
+        this.unparse(operand, cmp < 0);
     }
 
     /**
@@ -524,16 +524,17 @@
 
     private void unparseLhs(Java.Atom lhs, String binaryOperator) {
         int cmp = UnparseVisitor.comparePrecedence(binaryOperator, lhs);
-        this.unparse(lhs, cmp < 0 || (cmp == 0 && !binaryOperator.endsWith("=") && binaryOperator != "?:" && binaryOperator != "cast"));
+        this.unparse(lhs, cmp < 0 || (cmp == 0 && UnparseVisitor.isLeftAssociate(binaryOperator)));
     }
 
+
     /**
      * Iff the <code>rhs</code> is unnatural for the <code>binaryOperator</code>, enclose the
      * <code>rhs</code> in parentheses. Example: "a+b" is an unnatural rhs for operator "*". 
      */
     private void unparseRhs(Java.Rvalue rhs, String binaryOperator) {
         int cmp = UnparseVisitor.comparePrecedence(binaryOperator, rhs);
-        this.unparse(rhs, cmp < 0 || (cmp == 0 && (binaryOperator.endsWith("=") || binaryOperator == "?:" || binaryOperator == "cast")));
+        this.unparse(rhs, cmp < 0 || (cmp == 0 && UnparseVisitor.isRightAssociate(binaryOperator)));
     }
 
     private void unparse(Java.Atom operand, boolean natural) {
@@ -541,6 +542,26 @@
         this.unparse(operand);
         if (!natural) this.pw.print(" )))");
     }
+    
+    /**
+     * Return true iff operator is right associative
+     *  i.e. <code>a `op` b `op` c</code> evaluates as <code>a (`op` b `op`) c</code>
+     * @param op
+     * @return Return true iff operator is right associative
+     */
+    private static boolean isRightAssociate(String op) {
+        return op.endsWith("=") || op == "?:" || op == "cast";
+    }
+    
+    /**
+     * Return true iff operator is left associative
+     *  i.e. <code>a `op` b `op` c</code> evaluates as <code>(a `op` b) `op` c</code>
+     * @param op
+     * @return Return true iff operator is left associative
+     */
+    private static boolean isLeftAssociate(String op) {
+        return !isRightAssociate(op);
+    }
 
     /**
      * Returns a value
@@ -555,7 +576,7 @@
             return UnparseVisitor.getOperatorPrecedence(operator) - UnparseVisitor.getOperatorPrecedence(((Java.BinaryOperation) operand).op); 
         } else
         if (operand instanceof Java.UnaryOperation) {
-            return UnparseVisitor.getOperatorPrecedence(operator) - UnparseVisitor.getOperatorPrecedence(((Java.UnaryOperation) operand).operator); 
+            return UnparseVisitor.getOperatorPrecedence(operator) - UnparseVisitor.getOperatorPrecedence(((Java.UnaryOperation) operand).operator + "x"); 
         } else
         if (operand instanceof Java.ConditionalExpression) {
             return UnparseVisitor.getOperatorPrecedence(operator) - UnparseVisitor.getOperatorPrecedence("?:"); 
@@ -564,11 +585,14 @@
             return UnparseVisitor.getOperatorPrecedence(operator) - UnparseVisitor.getOperatorPrecedence("instanceof"); 
         } else
         if (operand instanceof Java.Cast) {
-            return UnparseVisitor.getOperatorPrecedence(operator) - UnparseVisitor.getOperatorPrecedence("case"); 
+            return UnparseVisitor.getOperatorPrecedence(operator) - UnparseVisitor.getOperatorPrecedence("cast"); 
         } else
         if (operand instanceof Java.MethodInvocation || operand instanceof Java.FieldAccess) {
             return UnparseVisitor.getOperatorPrecedence(operator) - UnparseVisitor.getOperatorPrecedence("."); 
         } else
+        if (operand instanceof Java.NewArray || operand instanceof Java.NewClassInstance) {
+            return UnparseVisitor.getOperatorPrecedence(operator) - UnparseVisitor.getOperatorPrecedence("new"); 
+        } else
         {
             // All other rvalues (e.g. literal) have higher precedence than any operator.
             return -1;
@@ -592,11 +616,10 @@
             "<<", ">>", ">>>", null,
             "+", "-", null,
             "*", "/", "%", null,
-            "++x", "--x", "+x", "-x", null,
-            "~x", "!x", null,
-            "cast", null,
+            "cast", "new", null,
+            "++x", "--x", "+x", "-x", "~x", "!x", null,
             "x++", "x--", null,
-            ".", null,
+            ".", "[ ]", null,
         };
         int precedence = 0;
         for (int i = 0; i < ops.length; ++i) {

==== BEGIN SVK PATCH BLOCK ====
Version: svk v2.0.2 (linux)

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
==== END SVK PATCH BLOCK ====
