drill-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jacq...@apache.org
Subject [11/17] git commit: DRILL-1155: Add option to use JDK compiler and use it for runtime generated code over a certain threshold
Date Mon, 21 Jul 2014 02:46:33 GMT
DRILL-1155: Add option to use JDK compiler and use it for runtime generated code over a certain threshold

+ Updating Janino to 2.7.4 (from 2.6.1).
+ Added session options `exec.java_compiler`:[DEFAULT, JDK, JANINO] and `exec.java_compiler_janino_maxsize`(256k).
+ Fix a bug in FragmentExecutor.java(125) where the root operator is not stopped in case of fragment failure.
+ Print Java stack trace of the allocator code if a TLA detects that any of the ChildAllocator is not closed.


Project: http://git-wip-us.apache.org/repos/asf/incubator-drill/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-drill/commit/02f1c82d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-drill/tree/02f1c82d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-drill/diff/02f1c82d

Branch: refs/heads/master
Commit: 02f1c82d8d7c87ed416a19b7a13463fdbffeb86d
Parents: 2beeda0
Author: Aditya Kishore <aditya@maprtech.com>
Authored: Thu Jul 10 01:31:39 2014 -0700
Committer: Jacques Nadeau <jacques@apache.org>
Committed: Sun Jul 20 16:32:59 2014 -0700

----------------------------------------------------------------------
 .../apache/drill/common/config/DrillConfig.java |   3 +
 .../drill/common/util/DrillStringUtils.java     |  14 +
 .../java/org/apache/drill/test/DrillTest.java   |  16 +-
 exec/java-exec/pom.xml                          |   7 +-
 .../exec/compile/AbstractClassCompiler.java     |  75 ++
 .../drill/exec/compile/ClassCompiler.java       |   3 +-
 .../drill/exec/compile/ClassTransformer.java    | 100 +-
 .../exec/compile/DrillDiagnosticListener.java   |  49 +
 .../exec/compile/DrillJavaFileManager.java      |  69 ++
 .../drill/exec/compile/DrillJavaFileObject.java | 109 +++
 .../drill/exec/compile/JDKClassCompiler.java    |  96 ++
 .../drill/exec/compile/JaninoClassCompiler.java |  47 +-
 .../drill/exec/compile/QueryClassLoader.java    |  93 +-
 .../exec/expr/fn/ModifiedUnparseVisitor.java    | 976 ++-----------------
 .../drill/exec/memory/TopLevelAllocator.java    |  24 +-
 .../apache/drill/exec/ops/FragmentContext.java  |  10 +-
 .../server/options/FragmentOptionsManager.java  |   2 +-
 .../server/options/SessionOptionManager.java    |   5 +-
 .../server/options/SystemOptionManager.java     |   5 +-
 .../exec/work/fragment/FragmentExecutor.java    |   1 +
 .../java/org/apache/drill/BaseTestQuery.java    |   2 +-
 .../exec/compile/TestClassTransformation.java   |  51 +-
 .../exec/compile/TestLargeFileCompilation.java  |  63 ++
 23 files changed, 773 insertions(+), 1047 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/02f1c82d/common/src/main/java/org/apache/drill/common/config/DrillConfig.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/drill/common/config/DrillConfig.java b/common/src/main/java/org/apache/drill/common/config/DrillConfig.java
index 2455dd9..0b2b22d 100644
--- a/common/src/main/java/org/apache/drill/common/config/DrillConfig.java
+++ b/common/src/main/java/org/apache/drill/common/config/DrillConfig.java
@@ -122,6 +122,9 @@ public final class DrillConfig extends NestedConfig{
     return create(overrideFileName, true);
   }
 
+  /**
+   * <b><u>Do not use this method outside of test code.</u></b>
+   */
   @VisibleForTesting
   public static DrillConfig create(Properties testConfigurations) {
     return create(null, testConfigurations, true);

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/02f1c82d/common/src/main/java/org/apache/drill/common/util/DrillStringUtils.java
----------------------------------------------------------------------
diff --git a/common/src/main/java/org/apache/drill/common/util/DrillStringUtils.java b/common/src/main/java/org/apache/drill/common/util/DrillStringUtils.java
index 96b5776..c23424e 100644
--- a/common/src/main/java/org/apache/drill/common/util/DrillStringUtils.java
+++ b/common/src/main/java/org/apache/drill/common/util/DrillStringUtils.java
@@ -22,6 +22,20 @@ import org.apache.commons.lang3.StringEscapeUtils;
 import io.netty.buffer.ByteBuf;
 
 public class DrillStringUtils {
+
+  /**
+   * Converts the long number into more human readable string.
+   */
+  public static String readable(long bytes) {
+    int unit = 1024;
+    long absBytes = Math.abs(bytes);
+    if (absBytes < unit) return bytes + " B";
+    int exp = (int) (Math.log(absBytes) / Math.log(unit));
+    char pre = ("KMGTPE").charAt(exp-1);
+    return String.format("%s%.1f %ciB", (bytes == absBytes ? "" : "-"), absBytes / Math.pow(unit, exp), pre);
+  }
+
+
   /**
    * Unescapes any Java literals found in the {@code String}.
    * For example, it will turn a sequence of {@code '\'} and

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/02f1c82d/common/src/test/java/org/apache/drill/test/DrillTest.java
----------------------------------------------------------------------
diff --git a/common/src/test/java/org/apache/drill/test/DrillTest.java b/common/src/test/java/org/apache/drill/test/DrillTest.java
index 6716f83..55f89b3 100644
--- a/common/src/test/java/org/apache/drill/test/DrillTest.java
+++ b/common/src/test/java/org/apache/drill/test/DrillTest.java
@@ -22,6 +22,7 @@ import java.lang.management.ManagementFactory;
 import java.lang.management.MemoryMXBean;
 import java.util.List;
 
+import org.apache.drill.common.util.DrillStringUtils;
 import org.apache.drill.common.util.TestTools;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -84,9 +85,9 @@ public class DrillTest {
       long endHeap = manager.getMemHeap();
       long endNonHeap = manager.getMemNonHeap();
       return String.format("d: %s(%s), h: %s(%s), nh: %s(%s)", //
-          readable(endDirect - startDirect), readable(endDirect), //
-          readable(endHeap - startHeap), readable(endHeap), //
-          readable(endNonHeap - startNonHeap), readable(endNonHeap) //
+          DrillStringUtils.readable(endDirect - startDirect), DrillStringUtils.readable(endDirect), //
+          DrillStringUtils.readable(endHeap - startHeap), DrillStringUtils.readable(endHeap), //
+          DrillStringUtils.readable(endNonHeap - startNonHeap), DrillStringUtils.readable(endNonHeap) //
        );
     }
 
@@ -135,15 +136,6 @@ public class DrillTest {
     }
   }
 
-  public static String readable(long bytes) {
-    int unit = 1024;
-    long absBytes = Math.abs(bytes);
-    if (absBytes < unit) return bytes + " B";
-    int exp = (int) (Math.log(absBytes) / Math.log(unit));
-    char pre = ("KMGTPE").charAt(exp-1);
-    return String.format("%s%.1f %ciB", (bytes == absBytes ? "" : "-"), absBytes / Math.pow(unit, exp), pre);
-  }
-
   private static class SystemManager {
 
     final BufferPoolMXBean directBean;

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/02f1c82d/exec/java-exec/pom.xml
----------------------------------------------------------------------
diff --git a/exec/java-exec/pom.xml b/exec/java-exec/pom.xml
index 0516967..30dff55 100644
--- a/exec/java-exec/pom.xml
+++ b/exec/java-exec/pom.xml
@@ -237,7 +237,12 @@
     <dependency>
       <groupId>org.codehaus.janino</groupId>
       <artifactId>janino</artifactId>
-      <version>2.6.1</version>
+      <version>2.7.4</version>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.janino</groupId>
+      <artifactId>commons-compiler-jdk</artifactId>
+      <version>2.7.4</version>
     </dependency>
     <dependency>
       <groupId>org.mortbay.jetty</groupId>

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/02f1c82d/exec/java-exec/src/main/java/org/apache/drill/exec/compile/AbstractClassCompiler.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/AbstractClassCompiler.java b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/AbstractClassCompiler.java
new file mode 100644
index 0000000..91588b8
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/AbstractClassCompiler.java
@@ -0,0 +1,75 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.compile;
+
+import java.io.IOException;
+
+import org.apache.drill.common.util.DrillStringUtils;
+import org.apache.drill.exec.compile.ClassTransformer.ClassNames;
+import org.apache.drill.exec.exception.ClassTransformationException;
+import org.codehaus.commons.compiler.CompileException;
+
+public abstract class AbstractClassCompiler implements ClassCompiler {
+  static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(AbstractClassCompiler.class);
+
+  protected boolean debugLines = true;
+  protected boolean debugVars = true;
+  protected boolean debugSource = true;
+
+  protected abstract byte[][] getByteCode(ClassNames className, String sourcecode)
+      throws CompileException, IOException, ClassNotFoundException, ClassTransformationException;
+
+  @Override
+  public byte[][] getClassByteCode(ClassNames className, String sourceCode)
+      throws CompileException, IOException, ClassNotFoundException, ClassTransformationException {
+    if(getLogger().isDebugEnabled()){
+      getLogger().debug("Compiling (source size={}):\n{}", DrillStringUtils.readable(sourceCode.length()), prefixLineNumbers(sourceCode));
+    }
+    return getByteCode(className, sourceCode);
+  }
+
+  public void setDebuggingOptions(boolean debugSource, boolean debugLines, boolean debugVars) {
+    this.debugSource = debugSource;
+    this.debugLines = debugLines;
+    this.debugVars = debugVars;
+    updateDebugOptions();
+  }
+
+  protected String prefixLineNumbers(String code) {
+    if (!debugLines) return code;
+    StringBuilder out = new StringBuilder();
+    int i = 1;
+    for (String line : code.split("\n")) {
+      int start = out.length();
+      out.append(i++);
+      int numLength = out.length() - start;
+      out.append(":");
+      for (int spaces = 0; spaces < 7 - numLength; ++spaces){
+        out.append(" ");
+      }
+      out.append(line);
+      out.append('\n');
+    }
+    return out.toString();
+  }
+
+  protected void updateDebugOptions() { } // default no-op implementation
+
+  protected org.slf4j.Logger getLogger() { return logger; }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/02f1c82d/exec/java-exec/src/main/java/org/apache/drill/exec/compile/ClassCompiler.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/ClassCompiler.java b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/ClassCompiler.java
index 36db9d7..fb080f8 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/ClassCompiler.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/ClassCompiler.java
@@ -19,11 +19,12 @@ package org.apache.drill.exec.compile;
 
 import java.io.IOException;
 
+import org.apache.drill.exec.compile.ClassTransformer.ClassNames;
 import org.apache.drill.exec.exception.ClassTransformationException;
 import org.codehaus.commons.compiler.CompileException;
 
 interface ClassCompiler {
 
-  public abstract byte[][] getClassByteCode(String className, String sourcecode) throws CompileException, IOException, ClassNotFoundException, ClassTransformationException ;
+  public abstract byte[][] getClassByteCode(ClassNames className, String sourcecode) throws CompileException, IOException, ClassNotFoundException, ClassTransformationException ;
 
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/02f1c82d/exec/java-exec/src/main/java/org/apache/drill/exec/compile/ClassTransformer.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/ClassTransformer.java b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/ClassTransformer.java
index 25c71b1..44ea5b5 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/ClassTransformer.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/ClassTransformer.java
@@ -23,6 +23,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 
+import org.apache.drill.common.util.DrillStringUtils;
 import org.apache.drill.common.util.FileUtils;
 import org.apache.drill.exec.compile.MergeAdapter.MergedClassResult;
 import org.apache.drill.exec.exception.ClassTransformationException;
@@ -61,27 +62,27 @@ public class ClassTransformer {
 //
 //  }
 
-  
-  
+
+
   public static class ClassSet{
     public final ClassSet parent;
     public final ClassNames precompiled;
     public final ClassNames generated;
-    
+
     public ClassSet(ClassSet parent, String precompiled, String generated) {
       super();
       this.parent = parent;
-      
+
       this.precompiled = new ClassNames(precompiled);
       this.generated = new ClassNames(generated);
-      Preconditions.checkArgument(!generated.startsWith(precompiled), 
+      Preconditions.checkArgument(!generated.startsWith(precompiled),
           String.format("The new name of a class cannot start with the old name of a class, otherwise class renaming will cause problems.  Precompiled class name %s.  Generated class name %s", precompiled, generated));
     }
-    
+
     public ClassSet getChild(String precompiled, String generated){
       return new ClassSet(this, precompiled, generated);
     }
-    
+
     public ClassSet getChild(String precompiled){
       return new ClassSet(this, precompiled, precompiled.replace(this.precompiled.dot, this.generated.dot));
     }
@@ -122,16 +123,16 @@ public class ClassTransformer {
         return false;
       return true;
     }
-    
-    
+
+
   }
-  
+
   public static class ClassNames{
-    
+
     public final String dot;
     public final String slash;
     public final String clazz;
-    
+
     public ClassNames(String className){
       dot = className;
       slash = className.replace('.', FileUtils.separatorChar);
@@ -174,16 +175,16 @@ public class ClassTransformer {
         return false;
       return true;
     }
-    
-    
-//    
+
+
+//
 //    public ClassNames getFixed(ClassNames precompiled, ClassNames generated){
 //      if(!dot.startsWith(precompiled.dot)) throw new IllegalStateException(String.format("Expected a class that starts with %s.  However the class %s does not start with this string.", precompiled.dot, dot));
 //      return new ClassNames(dot.replace(precompiled.dot, generated.dot));
 //    }
   }
-  
-//  
+
+//
 //  private void mergeAndInjectClass(QueryClassLoader classLoader, byte[] implementationClass, ClassNames precompiled, ClassNames generated){
 //    // Get Template Class
 //    final byte[] templateClass = byteCodeLoader.getClassByteCodeFromPath(precompiled.clazz);
@@ -193,11 +194,11 @@ public class ClassTransformer {
 //
 //    // Setup adapters for merging, remapping class names and class writing. This is done in reverse order of how they
 //    // will be evaluated.
-//    
+//
 //    Stopwatch t3;
 //    {
 //
-//      // 
+//      //
 //      ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
 //
 //      ClassVisitor remappingAdapter = new RemappingClassAdapter(cw, remapper);
@@ -232,15 +233,14 @@ public class ClassTransformer {
 //      i++;
 //    }
 //  }
-//  
+//
   private static ClassNode getClassNodeFromByteCode(byte[] bytes) {
     ClassReader iReader = new ClassReader(bytes);
     ClassNode impl = new ClassNode();
-    iReader.accept(impl, 0);
+    iReader.accept(impl, ClassReader.EXPAND_FRAMES);
     return impl;
   }
 
-  
   @SuppressWarnings("unchecked")
   public <T, I> T getImplementationClass( //
       QueryClassLoader classLoader, //
@@ -248,71 +248,53 @@ public class ClassTransformer {
       String entireClass, //
       String materializedClassName) throws ClassTransformationException {
 
-    final ClassSet set = new ClassSet(null, templateDefinition.getTemplateClassName(), materializedClassName);
-
-      
-
     try {
-      final byte[][] implementationClasses = classLoader.getClassByteCode(set.generated.clazz, entireClass);
-      
-      
+      long t1 = System.nanoTime();
+      final ClassSet set = new ClassSet(null, templateDefinition.getTemplateClassName(), materializedClassName);
+      final byte[][] implementationClasses = classLoader.getClassByteCode(set.generated, entireClass);
+
+      long totalBytecodeSize = 0;
       Map<String, ClassNode> classesToMerge = Maps.newHashMap();
-      for(byte[] clazz : implementationClasses){
+      for(byte[] clazz : implementationClasses) {
+        totalBytecodeSize += clazz.length;
         ClassNode node = getClassNodeFromByteCode(clazz);
         classesToMerge.put(node.name, node);
       }
-      
+
       LinkedList<ClassSet> names = Lists.newLinkedList();
       Set<ClassSet> namesCompleted = Sets.newHashSet();
       names.add(set);
-      
-      while( !names.isEmpty() ){
+
+      while ( !names.isEmpty() ) {
         final ClassSet nextSet = names.removeFirst();
-        if(namesCompleted.contains(nextSet)) continue;
+        if (namesCompleted.contains(nextSet)) continue;
         final ClassNames nextPrecompiled = nextSet.precompiled;
         final byte[] precompiledBytes = byteCodeLoader.getClassByteCodeFromPath(nextPrecompiled.clazz);
         ClassNames nextGenerated = nextSet.generated;
         ClassNode generatedNode = classesToMerge.get(nextGenerated.slash);
         MergedClassResult result = MergeAdapter.getMergedClass(nextSet, precompiledBytes, generatedNode);
-        
-        for(String s : result.innerClasses){
+
+        for(String s : result.innerClasses) {
           s = s.replace(FileUtils.separatorChar, '.');
           names.add(nextSet.getChild(s));
         }
         classLoader.injectByteCode(nextGenerated.dot, result.bytes);
         namesCompleted.add(nextSet);
-        
       }
-      
-
-      
-      
-//      logger.debug(String.format("[Compile Time] Janino: %dms, Bytecode load and parse: %dms, Class Merge: %dms, Subclass remap and load: %dms.", t1.elapsed(TimeUnit.MILLISECONDS), t2.elapsed(TimeUnit.MILLISECONDS), t3.elapsed(TimeUnit.MILLISECONDS), t4.elapsed(TimeUnit.MILLISECONDS)));
-      
-      
-      
+
       Class<?> c = classLoader.findClass(set.generated.dot);
       if (templateDefinition.getExternalInterface().isAssignableFrom(c)) {
-        return (T) c.newInstance();
+        T instance = (T) c.newInstance();
+        logger.debug("Done compiling (bytecode size={}, time:{} millis).",
+            DrillStringUtils.readable(totalBytecodeSize), (System.nanoTime() - t1) / 1000000);
+        return instance;
       } else {
         throw new ClassTransformationException("The requested class did not implement the expected interface.");
       }
-      
     } catch (CompileException | IOException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
-      throw new ClassTransformationException(String.format(
-          "Failure generating transformation classes for value: \n %s", entireClass), e);
+      throw new ClassTransformationException(String.format("Failure generating transformation classes for value: \n %s", entireClass), e);
     }
 
   }
 
-
-
-  // private void traceClassToSystemOut(byte[] bytecode) {
-  // TraceClassVisitor tcv = new TraceClassVisitor(new EmptyVisitor(), new PrintWriter(System.out));
-  // ClassReader cr = new ClassReader(bytecode);
-  // cr.accept(tcv, 0);
-  // }
-
-
-
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/02f1c82d/exec/java-exec/src/main/java/org/apache/drill/exec/compile/DrillDiagnosticListener.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/DrillDiagnosticListener.java b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/DrillDiagnosticListener.java
new file mode 100644
index 0000000..890243c
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/DrillDiagnosticListener.java
@@ -0,0 +1,49 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.compile;
+
+import javax.tools.Diagnostic;
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaFileObject;
+
+import org.codehaus.commons.compiler.CompileException;
+import org.codehaus.commons.compiler.Location;
+
+/* package */
+final class DrillDiagnosticListener implements DiagnosticListener<JavaFileObject> {
+  static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DrillDiagnosticListener.class);
+
+  @Override
+  public void report(Diagnostic<? extends JavaFileObject> diagnostic) {
+    if (diagnostic.getKind() == javax.tools.Diagnostic.Kind.ERROR) {
+      String message = diagnostic.toString() + " (" + diagnostic.getCode() + ")";
+      logger.error(message);
+      Location loc = new Location( //
+          diagnostic.getSource().toString(), //
+          (short) diagnostic.getLineNumber(), //
+          (short) diagnostic.getColumnNumber() //
+      );
+      // Wrap the exception in a RuntimeException, because "report()"
+      // does not declare checked exceptions.
+      throw new RuntimeException(new CompileException(message, loc));
+    } else if (logger.isTraceEnabled()) {
+      logger.trace(diagnostic.toString() + " (" + diagnostic.getCode() + ")");
+    }
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/02f1c82d/exec/java-exec/src/main/java/org/apache/drill/exec/compile/DrillJavaFileManager.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/DrillJavaFileManager.java b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/DrillJavaFileManager.java
new file mode 100644
index 0000000..96d3119
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/DrillJavaFileManager.java
@@ -0,0 +1,69 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.compile;
+
+import java.io.IOException;
+import java.util.Set;
+
+import javax.tools.FileObject;
+import javax.tools.ForwardingJavaFileManager;
+import javax.tools.JavaFileManager;
+import javax.tools.JavaFileObject;
+import javax.tools.JavaFileObject.Kind;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.Sets;
+
+/* package */
+class DrillJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {
+  static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(DrillJavaFileManager.class);
+
+  public static final Predicate<Kind> NO_SOURCES_KIND = new Predicate<Kind>() {
+    @Override
+    public boolean apply(Kind input) {
+      return input != Kind.SOURCE;
+    }
+  };
+
+  private final ClassLoader classLoader;
+
+  protected DrillJavaFileManager(JavaFileManager fileManager, ClassLoader classLoader) {
+    super(fileManager);
+    this.classLoader = classLoader;
+  }
+
+  @Override
+  public ClassLoader getClassLoader(Location location) {
+    return classLoader;
+  }
+
+  @Override
+  public Iterable<JavaFileObject> list(Location location, String packageName, Set<Kind> kinds, boolean recurse) throws IOException {
+    return super.list(location, packageName, Sets.filter(kinds, NO_SOURCES_KIND), recurse);
+  }
+
+  @Override
+  public JavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) throws IOException {
+    logger.trace("Creating JavaFileForOutput@(location:{}, className:{}, kinds:{})", location, className, kind);
+    if (sibling != null && sibling instanceof DrillJavaFileObject) {
+      return ((DrillJavaFileObject)sibling).addOutputJavaFile(className);
+    }
+    throw new IOException("The source file passed to getJavaFileForOutput() is not a DrillJavaFileObject: " + sibling);
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/02f1c82d/exec/java-exec/src/main/java/org/apache/drill/exec/compile/DrillJavaFileObject.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/DrillJavaFileObject.java b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/DrillJavaFileObject.java
new file mode 100644
index 0000000..024fd01
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/DrillJavaFileObject.java
@@ -0,0 +1,109 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.compile;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Map;
+
+import javax.tools.SimpleJavaFileObject;
+
+import com.google.common.collect.Maps;
+
+/* package */
+final class DrillJavaFileObject extends SimpleJavaFileObject {
+  private final String sourceCode;
+
+  private final ByteArrayOutputStream outputStream;
+
+  private Map<String, DrillJavaFileObject> outputFiles;
+
+  public DrillJavaFileObject(final String className, final String sourceCode) {
+    super(makeURI(className), Kind.SOURCE);
+    this.sourceCode = sourceCode;
+    this.outputStream = null;
+  }
+
+  private DrillJavaFileObject(final String name, final Kind kind) {
+    super(makeURI(name), kind);
+    this.outputStream = new ByteArrayOutputStream();
+    this.sourceCode = null;
+  }
+
+  public boolean isCompiled() {
+    return (outputFiles != null);
+  }
+
+  public byte[][] getByteCode() {
+    if (!isCompiled()) {
+      return null;
+    } else {
+      int index = 0;
+      byte[][] byteCode = new byte[outputFiles.size()][];
+      for(DrillJavaFileObject outputFile : outputFiles.values()) {
+        byteCode[index++] = outputFile.outputStream.toByteArray();
+      }
+      return byteCode;
+    }
+  }
+
+  public DrillJavaFileObject addOutputJavaFile(String className) {
+    if (outputFiles == null) {
+      outputFiles = Maps.newLinkedHashMap();
+    }
+    DrillJavaFileObject outputFile = new DrillJavaFileObject(className, Kind.CLASS);
+    outputFiles.put(className, outputFile);
+    return outputFile;
+  }
+
+  @Override
+  public Reader openReader(final boolean ignoreEncodingErrors) throws IOException {
+    return new StringReader(sourceCode);
+  }
+
+  @Override
+  public CharSequence getCharContent(final boolean ignoreEncodingErrors) throws IOException {
+    if (sourceCode == null)
+      throw new UnsupportedOperationException("This instance of DrillJavaFileObject is not an input object.");
+    return sourceCode;
+  }
+
+  @Override
+  public OutputStream openOutputStream() {
+    if (outputStream == null) {
+      throw new UnsupportedOperationException("This instance of DrillJavaFileObject is not an output object.");
+    }
+    return outputStream;
+  }
+
+  private static URI makeURI(final String canonicalClassName) {
+    final int dotPos = canonicalClassName.lastIndexOf('.');
+    final String simpleClassName = dotPos == -1 ? canonicalClassName : canonicalClassName.substring(dotPos + 1);
+    try {
+      return new URI(simpleClassName + Kind.SOURCE.extension);
+    } catch (URISyntaxException e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/02f1c82d/exec/java-exec/src/main/java/org/apache/drill/exec/compile/JDKClassCompiler.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/JDKClassCompiler.java b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/JDKClassCompiler.java
new file mode 100644
index 0000000..2bbf4f8
--- /dev/null
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/JDKClassCompiler.java
@@ -0,0 +1,96 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.drill.exec.compile;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Collections;
+
+import javax.tools.DiagnosticListener;
+import javax.tools.JavaCompiler;
+import javax.tools.JavaCompiler.CompilationTask;
+import javax.tools.JavaFileObject;
+import javax.tools.ToolProvider;
+
+import org.apache.drill.exec.compile.ClassTransformer.ClassNames;
+import org.codehaus.commons.compiler.CompileException;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.Lists;
+
+class JDKClassCompiler extends AbstractClassCompiler {
+  static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(JDKClassCompiler.class);
+
+  private Collection<String> compilerOptions;
+  private DiagnosticListener<JavaFileObject> listener;
+  private final JavaCompiler compiler;
+  private final DrillJavaFileManager fileManager;
+
+  public JDKClassCompiler(ClassLoader classLoader) {
+    this.compiler = ToolProvider.getSystemJavaCompiler();
+    if (compiler == null) {
+      throw new UnsupportedOperationException("JDK Java compiler not available - probably you're running a JRE, not a JDK");
+    }
+    this.listener = new DrillDiagnosticListener();
+    this.fileManager = new DrillJavaFileManager(compiler.getStandardFileManager(listener, null, Charsets.UTF_8), classLoader);
+    updateDebugOptions();
+  }
+
+  @Override
+  protected byte[][] getByteCode(final ClassNames className, final String sourceCode)
+      throws CompileException, IOException, ClassNotFoundException {
+    try {
+      // Create one Java source file in memory, which will be compiled later.
+      DrillJavaFileObject compilationUnit = new DrillJavaFileObject(className.dot, sourceCode);
+
+      CompilationTask task = compiler.getTask(null, fileManager, listener, compilerOptions, null, Collections.singleton(compilationUnit));
+
+      // Run the compiler.
+      if(!task.call()) {
+        throw new CompileException("Compilation failed", null);
+      } else if (!compilationUnit.isCompiled()) {
+        throw new ClassNotFoundException(className + ": Class file not created by compilation.");
+      }
+      // all good
+      return compilationUnit.getByteCode();
+    } catch (RuntimeException rte) {
+      // Unwrap the compilation exception and throw it.
+      Throwable cause = rte.getCause();
+      if (cause != null) {
+        cause = cause.getCause();
+        if (cause instanceof CompileException) throw (CompileException) cause;
+        if (cause instanceof IOException) throw (IOException) cause;
+      }
+      throw rte;
+    }
+  }
+
+  protected void updateDebugOptions() {
+    StringBuilder sb = new StringBuilder("-g:");
+    if (this.debugSource) sb.append("source,");
+    if (this.debugLines) sb.append("lines,");
+    if (this.debugVars) sb.append("vars,");
+    if (sb.length() == 3) { // "-g:"
+      sb.append("none,");
+    }
+    compilerOptions = Lists.newArrayList(sb.substring(0, sb.length()-1));
+  }
+
+  protected org.slf4j.Logger getLogger() { return logger; }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/02f1c82d/exec/java-exec/src/main/java/org/apache/drill/exec/compile/JaninoClassCompiler.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/JaninoClassCompiler.java b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/JaninoClassCompiler.java
index e381e32..4b17598 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/JaninoClassCompiler.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/JaninoClassCompiler.java
@@ -20,6 +20,7 @@ package org.apache.drill.exec.compile;
 import java.io.IOException;
 import java.io.StringReader;
 
+import org.apache.drill.exec.compile.ClassTransformer.ClassNames;
 import org.apache.drill.exec.exception.ClassTransformationException;
 import org.codehaus.commons.compiler.CompileException;
 import org.codehaus.janino.ClassLoaderIClassLoader;
@@ -30,58 +31,30 @@ import org.codehaus.janino.Scanner;
 import org.codehaus.janino.UnitCompiler;
 import org.codehaus.janino.util.ClassFile;
 
-public class JaninoClassCompiler implements ClassCompiler{
+public class JaninoClassCompiler extends AbstractClassCompiler {
   static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(JaninoClassCompiler.class);
 
   private IClassLoader compilationClassLoader;
 
-  private boolean debugLines = true;
-  private boolean debugVars = true;
-  private boolean debugSource = true;
-
   public JaninoClassCompiler(ClassLoader parentClassLoader) {
     this.compilationClassLoader = new ClassLoaderIClassLoader(parentClassLoader);
   }
 
-  public byte[][] getClassByteCode(final String className, final String code) throws CompileException, IOException, ClassNotFoundException, ClassTransformationException {
-    if(logger.isDebugEnabled()){
-      logger.debug("Compiling:\n{}", prefixLineNumbers(code));
-    }
-    StringReader reader = new StringReader(code);
+  protected byte[][] getByteCode(final ClassNames className, final String sourcecode)
+      throws CompileException, IOException, ClassNotFoundException, ClassTransformationException {
+    StringReader reader = new StringReader(sourcecode);
     Scanner scanner = new Scanner((String) null, reader);
     Java.CompilationUnit compilationUnit = new Parser(scanner).parseCompilationUnit();
-    ClassFile[] classFiles = new UnitCompiler(compilationUnit, compilationClassLoader).compileUnit(this.debugSource,
-        this.debugLines, this.debugVars);
-    
+    ClassFile[] classFiles = new UnitCompiler(compilationUnit, compilationClassLoader)
+                                  .compileUnit(this.debugSource, this.debugLines, this.debugVars);
+
     byte[][] byteCodes = new byte[classFiles.length][];
-    for(int i =0; i < classFiles.length; i++){
+    for(int i = 0; i < classFiles.length; i++){
       byteCodes[i] = classFiles[i].toByteArray();
     }
     return byteCodes;
   }
 
+  protected org.slf4j.Logger getLogger() { return logger; }
 
-  private String prefixLineNumbers(String code) {
-    if (!debugLines) return code;
-    StringBuilder out = new StringBuilder();
-    int i = 1;
-    for (String line : code.split("\n")) {
-      int start = out.length();
-      out.append(i++);
-      int numLength = out.length() - start;
-      out.append(":");
-      for (int spaces = 0; spaces < 7 - numLength; ++spaces){
-        out.append(" ");
-      }
-      out.append(line);
-      out.append('\n');
-    }
-    return out.toString();
-  }
-
-  public void setDebuggingInformation(boolean debugSource, boolean debugLines, boolean debugVars) {
-    this.debugSource = debugSource;
-    this.debugLines = debugLines;
-    this.debugVars = debugVars;
-  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/02f1c82d/exec/java-exec/src/main/java/org/apache/drill/exec/compile/QueryClassLoader.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/QueryClassLoader.java b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/QueryClassLoader.java
index de7ee96..8f1abcb 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/compile/QueryClassLoader.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/compile/QueryClassLoader.java
@@ -20,35 +20,59 @@ package org.apache.drill.exec.compile;
 import java.io.IOException;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.util.Arrays;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicLong;
 
+import org.apache.drill.common.exceptions.ExpressionParsingException;
+import org.apache.drill.exec.compile.ClassTransformer.ClassNames;
 import org.apache.drill.exec.exception.ClassTransformationException;
+import org.apache.drill.exec.server.options.OptionManager;
+import org.apache.drill.exec.server.options.OptionValidator;
+import org.apache.drill.exec.server.options.OptionValue;
+import org.apache.drill.exec.server.options.TypeValidators.LongValidator;
+import org.apache.drill.exec.server.options.TypeValidators.StringValidator;
 import org.codehaus.commons.compiler.CompileException;
+import org.eigenbase.sql.SqlLiteral;
 
 import com.google.common.collect.MapMaker;
 
 public class QueryClassLoader extends URLClassLoader {
-
   static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(QueryClassLoader.class);
 
-  private final ClassCompiler classCompiler;
+  public static final String JAVA_COMPILER_OPTION = "exec.java_compiler";
+  public static final StringValidator JAVA_COMPILER_VALIDATOR = new StringValidator(JAVA_COMPILER_OPTION, CompilerPolicy.DEFAULT.toString()) {
+    @Override
+    public OptionValue validate(SqlLiteral value) throws ExpressionParsingException {
+      OptionValue ov = super.validate(value);
+      try {
+        CompilerPolicy.valueOf(ov.string_val.toUpperCase());
+      } catch (IllegalArgumentException e) {
+        throw new ExpressionParsingException(String.format("Invalid value '%s' specified for option '%s'. Valid values are %s.",
+            ov.string_val, getOptionName(), Arrays.toString(CompilerPolicy.values())));
+      }
+      return ov;
+    }
+  };
+
+  public static final String JAVA_COMPILER_JANINO_MAXSIZE_OPTION = "exec.java_compiler_janino_maxsize";
+  public static final OptionValidator JAVA_COMPILER_JANINO_MAXSIZE = new LongValidator(JAVA_COMPILER_JANINO_MAXSIZE_OPTION, 256*1024);
+
+  private ClassCompilerSelector compilerSelector;
+
   private AtomicLong index = new AtomicLong(0);
+  
   private ConcurrentMap<String, byte[]> customClasses = new MapMaker().concurrencyLevel(4).makeMap();
 
-  public QueryClassLoader(boolean useJanino) {
+  public QueryClassLoader(OptionManager sessionOptions) {
     super(new URL[0]);
-    if (useJanino) {
-      this.classCompiler = new JaninoClassCompiler(this);
-    } else {
-      throw new UnsupportedOperationException("Drill no longer supports using the JDK class compiler.");
-    }
+    compilerSelector = new ClassCompilerSelector(sessionOptions);
   }
 
   public long getNextClassIndex(){
     return index.getAndIncrement();
   }
-  
+
   public void injectByteCode(String className, byte[] classBytes) throws IOException {
     if(customClasses.containsKey(className)) throw new IOException(String.format("The class defined {} has already been loaded.", className));
     customClasses.put(className, classBytes);
@@ -64,10 +88,53 @@ public class QueryClassLoader extends URLClassLoader {
     }
   }
 
-  public byte[][] getClassByteCode(final String className, final String sourcecode) throws CompileException, IOException,
-      ClassNotFoundException, ClassTransformationException {
-    byte[][] bc = classCompiler.getClassByteCode(className, sourcecode);
-    return bc;
+  public byte[][] getClassByteCode(final ClassNames className, final String sourceCode)
+      throws CompileException, IOException, ClassNotFoundException, ClassTransformationException {
+    return compilerSelector.getClassByteCode(className, sourceCode);
+  }
+
+  public enum CompilerPolicy {
+    DEFAULT, JDK, JANINO;
+  }
+
+  private class ClassCompilerSelector {
+    private final CompilerPolicy policy;
+    private final long janinoThreshold;
+
+    private ClassCompiler jdkClassCompiler;
+    private ClassCompiler janinoClassCompiler;
+
+
+    ClassCompilerSelector(OptionManager sessionOptions) {
+      OptionValue value = sessionOptions.getOption(JAVA_COMPILER_OPTION);
+      this.policy = (value != null) ? CompilerPolicy.valueOf(value.string_val.toUpperCase()) : CompilerPolicy.DEFAULT;
+      value = sessionOptions.getOption(JAVA_COMPILER_JANINO_MAXSIZE_OPTION);
+      this.janinoThreshold = (value != null) ? value.num_val : JAVA_COMPILER_JANINO_MAXSIZE.getDefault().num_val;
+
+      this.janinoClassCompiler = new JaninoClassCompiler(QueryClassLoader.this);
+      this.jdkClassCompiler = new JDKClassCompiler(QueryClassLoader.this);
+    }
+
+    private byte[][] getClassByteCode(ClassNames className, String sourceCode)
+        throws CompileException, ClassNotFoundException, ClassTransformationException, IOException {
+      ClassCompiler classCompiler;
+      if (policy == CompilerPolicy.JDK || (policy == CompilerPolicy.DEFAULT && sourceCode.length() > janinoThreshold)) {
+        classCompiler = jdkClassCompiler;
+      } else {
+        classCompiler = janinoClassCompiler;
+      }
+
+      byte[][] bc = classCompiler.getClassByteCode(className, sourceCode);
+      /*
+       * final String baseDir = System.getProperty("java.io.tmpdir") + File.separator + classCompiler.getClass().getSimpleName();
+       * File classFile = new File(baseDir + className.clazz);
+       * classFile.getParentFile().mkdirs();
+       * BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(classFile));
+       * out.write(bc[0]);
+       * out.close();
+       */
+      return bc;
+    }
 
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/02f1c82d/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/ModifiedUnparseVisitor.java
----------------------------------------------------------------------
diff --git a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/ModifiedUnparseVisitor.java b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/ModifiedUnparseVisitor.java
index c80493c..4b79bba 100644
--- a/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/ModifiedUnparseVisitor.java
+++ b/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/ModifiedUnparseVisitor.java
@@ -17,904 +17,100 @@
  */
 package org.apache.drill.exec.expr.fn;
 
-
-/*
- * 
- * Modified so that we can avoid printing some things.
- * 
- * Janino - An embedded Java[TM] compiler
- *
- * Copyright (c) 2001-2010, Arno Unkrig
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
- * following conditions are met:
- *
- *    1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
- *       following disclaimer.
- *    2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
- *       following disclaimer in the documentation and/or other materials provided with the distribution.
- *    3. The name of the author may not be used to endorse or promote products derived from this software without
- *       specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.StringReader;
 import java.io.Writer;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
-import java.util.Set;
 
-import org.codehaus.janino.JaninoRuntimeException;
 import org.codehaus.janino.Java;
-import org.codehaus.janino.Mod;
-import org.codehaus.janino.Parser;
-import org.codehaus.janino.Scanner;
-import org.codehaus.janino.Visitor.ComprehensiveVisitor;
+import org.codehaus.janino.UnparseVisitor;
 import org.codehaus.janino.util.AutoIndentWriter;
 
 /**
- * A visitor that unparses (un-compiles) an AST to a {@link Writer}. See
- * {@link #main(String[])} for a usage example.
+ * This is a modified version of {@link UnparseVisitor} so that we can avoid
+ * rendering few things. Based on janino version 2.7.4.
  */
-public class ModifiedUnparseVisitor implements ComprehensiveVisitor {
-    protected final AutoIndentWriter aiw;
-    protected final PrintWriter      pw;
-    private         String           returnLabel;
-
-    /**
-     * Testing of parsing/unparsing.
-     * <p>
-     * Reads compilation units from the files named on the command line
-     * and unparses them to {@link System#out}.
-     */
-    public static void main(String[] args) throws Exception {
-        Writer w = new BufferedWriter(new OutputStreamWriter(System.out));
-        for (int i = 0; i < args.length; ++i) {
-            String fileName = args[i];
-
-            // Parse each compilation unit.
-            FileReader r = new FileReader(fileName);
-            Java.CompilationUnit cu;
-            try {
-                cu = new Parser(new Scanner(fileName, r)).parseCompilationUnit();
-            } finally {
-                r.close();
-            }
-
-            // Unparse each compilation unit.
-            ModifiedUnparseVisitor.unparse(cu, w);
-        }
-        w.flush();
-    }
-
-    /**
-     * Unparse the given {@link Java.CompilationUnit} to the given {@link Writer}.
-     */
-    public static void unparse(Java.CompilationUnit cu, Writer w) {
-        ModifiedUnparseVisitor uv = new ModifiedUnparseVisitor(w);
-        uv.unparseCompilationUnit(cu);
-        uv.close();
-    }
-
-    public ModifiedUnparseVisitor(Writer w) {
-        this.aiw = new AutoIndentWriter(w);
-        this.pw = new PrintWriter(this.aiw, true);
-    }
-
-    /**
-     * Flushes all generated code and closes the {@link Writer} that was passed
-     * to {@link #ModifiedUnparseVisitor(Writer)}.
-     */
-    public void close() {
-        this.pw.close();
-    }
-
-    public void unparseCompilationUnit(Java.CompilationUnit cu) {
-        if (cu.optionalPackageDeclaration != null) {
-            this.pw.println();
-            this.pw.println("package " + cu.optionalPackageDeclaration.packageName + ';');
-        }
-        if (!cu.importDeclarations.isEmpty()) {
-            this.pw.println();
-            for (Iterator it = cu.importDeclarations.iterator(); it.hasNext();) {
-                ((Java.CompilationUnit.ImportDeclaration) it.next()).accept(this);
-            }
-        }
-        for (Iterator it = cu.packageMemberTypeDeclarations.iterator(); it.hasNext();) {
-            this.pw.println();
-            this.unparseTypeDeclaration((Java.PackageMemberTypeDeclaration) it.next());
-            this.pw.println();
-        }
-    }
-
-    public void visitSingleTypeImportDeclaration(Java.CompilationUnit.SingleTypeImportDeclaration stid) {
-        this.pw.println("import " + Java.join(stid.identifiers, ".") + ';');
-    }
-    public void visitTypeImportOnDemandDeclaration(Java.CompilationUnit.TypeImportOnDemandDeclaration tiodd) {
-        this.pw.println("import " + Java.join(tiodd.identifiers, ".") + ".*;");
-    }
-    public void visitSingleStaticImportDeclaration(Java.CompilationUnit.SingleStaticImportDeclaration ssid) {
-        this.pw.println("import static " + Java.join(ssid.identifiers, ".") + ';');
-    }
-    public void visitStaticImportOnDemandDeclaration(Java.CompilationUnit.StaticImportOnDemandDeclaration siodd) {
-        this.pw.println("import static " + Java.join(siodd.identifiers, ".") + ".*;");
-    }
-
-    public void visitLocalClassDeclaration(Java.LocalClassDeclaration lcd) {
-        this.unparseNamedClassDeclaration(lcd);
-    }
-    public void visitMemberClassDeclaration(Java.MemberClassDeclaration mcd) {
-        this.unparseNamedClassDeclaration(mcd);
-    }
-    public void visitMemberInterfaceDeclaration(Java.MemberInterfaceDeclaration mid) {
-        this.unparseInterfaceDeclaration(mid);
-    }
-    public void visitPackageMemberClassDeclaration(Java.PackageMemberClassDeclaration pmcd) {
-        this.unparseNamedClassDeclaration(pmcd);
-    }
-    public void visitPackageMemberInterfaceDeclaration(Java.PackageMemberInterfaceDeclaration pmid) {
-        this.unparseInterfaceDeclaration(pmid);
-    }
-    public void visitConstructorDeclarator(Java.ConstructorDeclarator cd) {
-        this.unparseDocComment(cd);
-        this.unparseModifiers(cd.modifiers);
-        Java.ClassDeclaration declaringClass = cd.getDeclaringClass();
-        this.pw.print(
-            declaringClass instanceof Java.NamedClassDeclaration
-            ? ((Java.NamedClassDeclaration) declaringClass).name
-            : "UNNAMED"
-        );
-        this.unparseFunctionDeclaratorRest(cd);
-        this.pw.print(' ');
-        if (cd.optionalConstructorInvocation != null) {
-            this.pw.println('{');
-            this.pw.print(AutoIndentWriter.INDENT);
-            this.unparseBlockStatement(cd.optionalConstructorInvocation);
-            this.pw.println(';');
-
-            if (!cd.optionalStatements.isEmpty()) {
-                this.pw.println();
-                this.unparseStatements(cd.optionalStatements);
-            }
-            this.pw.print(AutoIndentWriter.UNINDENT + "}");
-        } else
-        if (cd.optionalStatements.isEmpty()) {
-            this.pw.print("{}");
-        } else
-        {
-            this.pw.println('{');
-            this.pw.print(AutoIndentWriter.INDENT);
-            this.unparseStatements(cd.optionalStatements);
-            this.pw.print(AutoIndentWriter.UNINDENT + "}");
-        }
-    }
-    public void visitMethodDeclarator(Java.MethodDeclarator md) {
-        // modified to remove method declaration printing.
-         if (md.optionalStatements == null) {
-             this.pw.print(';');
-         } else
-         if (md.optionalStatements.isEmpty()) {
-         this.pw.print(" {}");
-         } else
-         {
-         this.pw.println(' ');
-         // Add labels to handle return statements within function templates
-         String[] fQCN = md.getDeclaringType().getClassName().split("\\.");
-         returnLabel = fQCN[fQCN.length - 1] + "_" + md.name;
-
-         this.pw.println(returnLabel + ": {");
-         this.pw.print(AutoIndentWriter.INDENT);
-         this.unparseStatements(md.optionalStatements);
-         this.pw.print(AutoIndentWriter.UNINDENT);
-         this.pw.println("}");
-         this.pw.print(' ');
-         }
-
-    }
-    public void visitFieldDeclaration(Java.FieldDeclaration fd) {
-        this.unparseDocComment(fd);
-        this.unparseModifiers(fd.modifiers);
-        this.unparseType(fd.type);
-        this.pw.print(' ');
-        for (int i = 0; i < fd.variableDeclarators.length; ++i) {
-            if (i > 0) this.pw.print(", ");
-            this.unparseVariableDeclarator(fd.variableDeclarators[i]);
-        }
-        this.pw.print(';');
-    }
-    public void visitInitializer(Java.Initializer i) {
-        if (i.statiC) this.pw.print("static ");
-        this.unparseBlockStatement(i.block);
-    }
-    public void visitBlock(Java.Block b) {
-        if (b.statements.isEmpty()) {
-            this.pw.print("{}");
-            return;
-        }
-        this.pw.println('{');
+public class ModifiedUnparseVisitor extends UnparseVisitor {
+
+  private String returnLabel;
+
+  /**
+   * Testing of parsing/unparsing.
+   * <p>
+   * Reads compilation units from the files named on the command line
+   * and unparses them to {@link System#out}.
+   */
+  public static void main(String[] args) throws Exception {
+    UnparseVisitor.main(args);
+  }
+
+  /**
+   * Unparse the given {@link Java.CompilationUnit} to the given {@link Writer}.
+   */
+  public static void unparse(Java.CompilationUnit cu, Writer w) {
+    UnparseVisitor.unparse(cu, w);
+  }
+
+  public ModifiedUnparseVisitor(Writer w) {
+    super(w);
+  }
+
+  public void visitMethodDeclarator(Java.MethodDeclarator md) {
+    if (md.optionalStatements == null) {
+      this.pw.print(';');
+    } else
+      if (md.optionalStatements.isEmpty()) {
+        this.pw.print(" {}");
+      } else {
+        this.pw.println(' ');
+        // Add labels to handle return statements within function templates
+        String[] fQCN = md.getDeclaringType().getClassName().split("\\.");
+        returnLabel = fQCN[fQCN.length - 1] + "_" + md.name;
+        this.pw.println(returnLabel + ": {");
         this.pw.print(AutoIndentWriter.INDENT);
-        this.unparseStatements(b.statements);
-        this.pw.print(AutoIndentWriter.UNINDENT + "}");
-    }
-
-    private void unparseStatements(List statements) {
-        int state = -1;
-        for (Iterator it = statements.iterator(); it.hasNext();) {
-            Java.BlockStatement bs = (Java.BlockStatement) it.next();
-            int x = (
-                bs instanceof Java.Block                             ? 1 :
-                bs instanceof Java.LocalClassDeclarationStatement    ? 2 :
-                bs instanceof Java.LocalVariableDeclarationStatement ? 3 :
-                bs instanceof Java.SynchronizedStatement             ? 4 :
-                99
-            );
-            if (state != -1 && state != x) this.pw.println(AutoIndentWriter.CLEAR_TABULATORS);
-            state = x;
-
-            this.unparseBlockStatement(bs);
-            this.pw.println();
-        }
-    }
-    public void visitBreakStatement(Java.BreakStatement bs) {
-        this.pw.print("break");
-        if (bs.optionalLabel != null) this.pw.print(' ' + bs.optionalLabel);
-        this.pw.print(';');
-    }
-    public void visitContinueStatement(Java.ContinueStatement cs) {
-        this.pw.print("continue");
-        if (cs.optionalLabel != null) this.pw.print(' ' + cs.optionalLabel);
-        this.pw.print(';');
-    }
-    public void visitDoStatement(Java.DoStatement ds) {
-        this.pw.print("do ");
-        this.unparseBlockStatement(ds.body);
-        this.pw.print("while (");
-        this.unparse(ds.condition);
-        this.pw.print(");");
-    }
-    public void visitEmptyStatement(Java.EmptyStatement es) {
-        this.pw.print(';');
-    }
-    public void visitExpressionStatement(Java.ExpressionStatement es) {
-        this.unparse(es.rvalue);
-        this.pw.print(';');
-    }
-    public void visitForStatement(Java.ForStatement fs) {
-        this.pw.print("for (");
-        if (fs.optionalInit != null) {
-            this.unparseBlockStatement(fs.optionalInit);
-        } else {
-            this.pw.print(';');
-        }
-        if (fs.optionalCondition != null) {
-            this.pw.print(' ');
-            this.unparse(fs.optionalCondition);
-        }
-        this.pw.print(';');
-        if (fs.optionalUpdate != null) {
-            this.pw.print(' ');
-            for (int i = 0; i < fs.optionalUpdate.length; ++i) {
-                if (i > 0) this.pw.print(", ");
-                this.unparse(fs.optionalUpdate[i]);
-            }
-        }
-        this.pw.print(") ");
-        this.unparseBlockStatement(fs.body);
-    }
-    public void visitIfStatement(Java.IfStatement is) {
-        this.pw.print("if (");
-        this.unparse(is.condition);
-        this.pw.print(") ");
-        this.unparseBlockStatement(is.thenStatement);
-        if (is.optionalElseStatement != null) {
-            this.pw.println(" else");
-            this.unparseBlockStatement(is.optionalElseStatement);
-        }
-    }
-    public void visitLabeledStatement(Java.LabeledStatement ls) {
-        this.pw.println(ls.label + ':');
-        this.unparseBlockStatement(ls.body);
-    }
-    public void visitLocalClassDeclarationStatement(Java.LocalClassDeclarationStatement lcds) {
-        this.unparseTypeDeclaration(lcds.lcd);
-    }
-    public void visitLocalVariableDeclarationStatement(Java.LocalVariableDeclarationStatement lvds) {
-        this.unparseModifiers(lvds.modifiers);
-        this.unparseType(lvds.type);
+        this.unparseStatements(md.optionalStatements);
+        this.pw.print(AutoIndentWriter.UNINDENT);
+        this.pw.println("}");
         this.pw.print(' ');
-        this.pw.print(AutoIndentWriter.TABULATOR);
-        this.unparseVariableDeclarator(lvds.variableDeclarators[0]);
-        for (int i = 1; i < lvds.variableDeclarators.length; ++i) {
-            this.pw.print(", ");
-            this.unparseVariableDeclarator(lvds.variableDeclarators[i]);
-        }
-        this.pw.print(';');
-    }
-    public void visitReturnStatement(Java.ReturnStatement rs) {
-        this.pw.print("break " + returnLabel);
-      
-        if (rs.optionalReturnValue != null) {
-            this.pw.print(' ');
-            this.unparse(rs.optionalReturnValue);
-        }
-        this.pw.print(';');
-    }
-    public void visitSwitchStatement(Java.SwitchStatement ss) {
-        this.pw.print("switch (");
-        this.unparse(ss.condition);
-        this.pw.println(") {");
-        for (Iterator it = ss.sbsgs.iterator(); it.hasNext();) {
-            Java.SwitchStatement.SwitchBlockStatementGroup sbgs = (
-                (Java.SwitchStatement.SwitchBlockStatementGroup) it.next()
-            );
-            this.pw.print(AutoIndentWriter.UNINDENT);
-            try {
-                for (Iterator it2 = sbgs.caseLabels.iterator(); it2.hasNext();) {
-                    Java.Rvalue rv = (Java.Rvalue) it2.next();
-                    this.pw.print("case ");
-                    this.unparse(rv);
-                    this.pw.println(':');
-                }
-                if (sbgs.hasDefaultLabel) this.pw.println("default:");
-            } finally {
-                this.pw.print(AutoIndentWriter.INDENT);
-            }
-            for (Iterator it2 = sbgs.blockStatements.iterator(); it2.hasNext();) {
-                this.unparseBlockStatement((Java.BlockStatement) it2.next());
-                this.pw.println();
-            }
-        }
-        this.pw.print('}');
-    }
-    public void visitSynchronizedStatement(Java.SynchronizedStatement ss) {
-        this.pw.print("synchronized (");
-        this.unparse(ss.expression);
-        this.pw.print(") ");
-        this.unparseBlockStatement(ss.body);
-    }
-    public void visitThrowStatement(Java.ThrowStatement ts) {
-        this.pw.print("throw ");
-        this.unparse(ts.expression);
-        this.pw.print(';');
-    }
-    public void visitTryStatement(Java.TryStatement ts) {
-        this.pw.print("try ");
-        this.unparseBlockStatement(ts.body);
-        for (Iterator it = ts.catchClauses.iterator(); it.hasNext();) {
-            Java.CatchClause cc = (Java.CatchClause) it.next();
-            this.pw.print(" catch (");
-            this.unparseFormalParameter(cc.caughtException);
-            this.pw.print(") ");
-            this.unparseBlockStatement(cc.body);
-        }
-        if (ts.optionalFinally != null) {
-            this.pw.print(" finally ");
-            this.unparseBlockStatement(ts.optionalFinally);
-        }
-    }
-    public void visitWhileStatement(Java.WhileStatement ws) {
-        this.pw.print("while (");
-        this.unparse(ws.condition);
-        this.pw.print(") ");
-        this.unparseBlockStatement(ws.body);
-    }
-    public void unparseVariableDeclarator(Java.VariableDeclarator vd) {
-        this.pw.print(vd.name);
-        for (int i = 0; i < vd.brackets; ++i) this.pw.print("[]");
-        if (vd.optionalInitializer != null) {
-            this.pw.print(" = ");
-            this.unparseArrayInitializerOrRvalue(vd.optionalInitializer);
-        }
-    }
-    public void unparseFormalParameter(Java.FunctionDeclarator.FormalParameter fp) {
-        if (fp.finaL) this.pw.print("final ");
-        this.unparseType(fp.type);
-        this.pw.print(" " + AutoIndentWriter.TABULATOR + fp.name);
-    }
-    public void visitMethodInvocation(Java.MethodInvocation mi) {
-        if (mi.optionalTarget != null) {
-            this.unparseLhs(mi.optionalTarget, ".");
-            this.pw.print('.');
-        }
-        this.pw.print(mi.methodName);
-        this.unparseFunctionInvocationArguments(mi.arguments);
-    }
-    public void visitAlternateConstructorInvocation(Java.AlternateConstructorInvocation aci) {
-        this.pw.print("this");
-        this.unparseFunctionInvocationArguments(aci.arguments);
-    }
-    public void visitSuperConstructorInvocation(Java.SuperConstructorInvocation sci) {
-        if (sci.optionalQualification != null) {
-            this.unparseLhs(sci.optionalQualification, ".");
-            this.pw.print('.');
-        }
-        this.pw.print("super");
-        this.unparseFunctionInvocationArguments(sci.arguments);
-    }
-    public void visitNewClassInstance(Java.NewClassInstance nci) {
-        if (nci.optionalQualification != null) {
-            this.unparseLhs(nci.optionalQualification, ".");
-            this.pw.print('.');
-        }
-        this.pw.print("new " + nci.type.toString());
-        this.unparseFunctionInvocationArguments(nci.arguments);
-    }
-    public void visitAssignment(Java.Assignment a) {
-        this.unparseLhs(a.lhs, a.operator);
-        this.pw.print(' ' + a.operator + ' ');
-        this.unparseRhs(a.rhs, a.operator);
-    }
-    public void visitAmbiguousName(Java.AmbiguousName an) { this.pw.print(an.toString()); }
-    public void visitArrayAccessExpression(Java.ArrayAccessExpression aae) {
-        this.unparseLhs(aae.lhs, "[ ]");
-        this.pw.print('[');
-        this.unparse(aae.index);
-        this.pw.print(']');
-    }
-    public void visitArrayLength(Java.ArrayLength al) {
-        this.unparseLhs(al.lhs, ".");
-        this.pw.print(".length");
-    }
-    public void visitArrayType(Java.ArrayType at) {
-        this.unparseType(at.componentType);
-        this.pw.print("[]");
-    }
-    public void visitBasicType(Java.BasicType bt) {
-        this.pw.print(bt.toString());
-    }
-    public void visitBinaryOperation(Java.BinaryOperation bo) {
-        this.unparseLhs(bo.lhs, bo.op);
-        this.pw.print(' ' + bo.op + ' ');
-        this.unparseRhs(bo.rhs, bo.op);
-    }
-    public void visitCast(Java.Cast c) {
-        this.pw.print('(');
-        this.unparseType(c.targetType);
-        this.pw.print(") ");
-        this.unparseRhs(c.value, "cast");
-    }
-    public void visitClassLiteral(Java.ClassLiteral cl) {
-        this.unparseType(cl.type);
-        this.pw.print(".class");
-    }
-    public void visitConditionalExpression(Java.ConditionalExpression ce) {
-        this.unparseLhs(ce.lhs, "?:");
-        this.pw.print(" ? ");
-        this.unparseLhs(ce.mhs, "?:");
-        this.pw.print(" : ");
-        this.unparseRhs(ce.rhs, "?:");
-    }
-    public void visitCrement(Java.Crement c) {
-        if (c.pre) {
-            this.pw.print(c.operator);
-            this.unparseUnaryOperation(c.operand, c.operator + "x");
-        } else
-        {
-            this.unparseUnaryOperation(c.operand, "x" + c.operator);
-            this.pw.print(c.operator);
-        }
-    }
-    public void visitFieldAccess(Java.FieldAccess fa) {
-        this.unparseLhs(fa.lhs, ".");
-        this.pw.print('.' + fa.field.getName());
-    }
-    public void visitFieldAccessExpression(Java.FieldAccessExpression fae) {
-        this.unparseLhs(fae.lhs, ".");
-        this.pw.print('.' + fae.fieldName);
-    }
-    public void visitSuperclassFieldAccessExpression(Java.SuperclassFieldAccessExpression scfae) {
-        if (scfae.optionalQualification != null) {
-            this.unparseType(scfae.optionalQualification);
-            this.pw.print(".super." + scfae.fieldName);
-        } else
-        {
-            this.pw.print("super." + scfae.fieldName);
-        }
-    }
-    public void visitInstanceof(Java.Instanceof io) {
-        this.unparseLhs(io.lhs, "instanceof");
-        this.pw.print(" instanceof ");
-        this.unparseType(io.rhs);
-    }
-    public void visitLiteral(Java.Literal l) { this.pw.print(l.toString()); }
-    public void visitLocalVariableAccess(Java.LocalVariableAccess lva) { this.pw.print(lva.toString()); }
-    public void visitNewArray(Java.NewArray na) {
-        this.pw.print("new ");
-        this.unparseType(na.type);
-        for (int i = 0; i < na.dimExprs.length; ++i) {
-            this.pw.print('[');
-            this.unparse(na.dimExprs[i]);
-            this.pw.print(']');
-        }
-        for (int i = 0; i < na.dims; ++i) {
-            this.pw.print("[]");
-        }
-    }
-    public void visitNewInitializedArray(Java.NewInitializedArray nai) {
-        this.pw.print("new ");
-        this.unparseType(nai.arrayType);
-        this.pw.print(" ");
-        this.unparseArrayInitializerOrRvalue(nai.arrayInitializer);
-    }
-    public void visitPackage(Java.Package p) { this.pw.print(p.toString()); }
-    public void visitParameterAccess(Java.ParameterAccess pa) { this.pw.print(pa.toString()); }
-    public void visitQualifiedThisReference(Java.QualifiedThisReference qtr) {
-        this.unparseType(qtr.qualification);
-        this.pw.print(".this");
-    }
-    public void visitReferenceType(Java.ReferenceType rt) { this.pw.print(rt.toString()); }
-    public void visitRvalueMemberType(Java.RvalueMemberType rmt) { this.pw.print(rmt.toString()); }
-    public void visitSimpleType(Java.SimpleType st) { this.pw.print(st.toString()); }
-    public void visitSuperclassMethodInvocation(Java.SuperclassMethodInvocation smi) {
-        this.pw.print("super." + smi.methodName);
-        this.unparseFunctionInvocationArguments(smi.arguments);
-    }
-    public void visitThisReference(Java.ThisReference tr) {
-        this.pw.print("this");
-    }
-    public void visitUnaryOperation(Java.UnaryOperation uo) {
-        this.pw.print(uo.operator);
-        this.unparseUnaryOperation(uo.operand, uo.operator + "x");
-    }
-    public void visitParenthesizedExpression(Java.ParenthesizedExpression pe) {
-        this.pw.print('(');
-        this.unparse(pe.value);
-        this.pw.print(')');
-    }
-
-    // Helpers
-
-    private void unparseBlockStatement(Java.BlockStatement blockStatement) {
-        blockStatement.accept(this);
-    }
-
-    private void unparseTypeDeclaration(Java.TypeDeclaration typeDeclaration) {
-        typeDeclaration.accept(this);
-    }
-
-    private void unparseType(Java.Type type) {
-        ((Java.Atom) type).accept(this);
-    }
-
-    private void unparse(Java.Atom operand) {
-        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".
-     *
-     * @param unaryOperator ++x --x +x -x ~x !x x++ x--
-     */
-    private void unparseUnaryOperation(Java.Rvalue operand, String unaryOperator) {
-        int cmp = ModifiedUnparseVisitor.comparePrecedence(unaryOperator, operand);
-        this.unparse(operand, cmp < 0);
-    }
-
-    /**
-     * Iff the <code>lhs</code> is unnatural for the <code>binaryOperator</code>, enclose the
-     * <code>lhs</code> in parentheses. Example: "a+b" is an unnatural lhs for operator "*".
-     *
-     * @param binaryOperator = +=... ?: || && | ^ & == != < > <= >= instanceof << >> >>> + - * / % cast
-     */
-
-    private void unparseLhs(Java.Atom lhs, String binaryOperator) {
-        int cmp = ModifiedUnparseVisitor.comparePrecedence(binaryOperator, lhs);
-        this.unparse(lhs, cmp < 0 || (cmp == 0 && ModifiedUnparseVisitor.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 = ModifiedUnparseVisitor.comparePrecedence(binaryOperator, rhs);
-        this.unparse(rhs, cmp < 0 || (cmp == 0 && ModifiedUnparseVisitor.isRightAssociate(binaryOperator)));
-    }
-
-    private void unparse(Java.Atom operand, boolean natural) {
-        if (!natural) this.pw.print("((( ");
-        this.unparse(operand);
-        if (!natural) this.pw.print(" )))");
-    }
-
-    /**
-     * Return true iff operator is right associative e.g. <code>a = b = c</code> evaluates as
-     * <code>a = (b = c)</code>.
-     *
-     * @return Return true iff operator is right associative
-     */
-    private static boolean isRightAssociate(String op) {
-        return ModifiedUnparseVisitor.RIGHT_ASSOCIATIVE_OPERATORS.contains(op);
-    }
-
-    /**
-     * Return true iff operator is left associative e.g. <code>a - b - c</code> evaluates as
-     * <code>(a - b) - c</code>.
-     *
-     * @return Return true iff operator is left associative
-     */
-    private static boolean isLeftAssociate(String op) {
-        return ModifiedUnparseVisitor.LEFT_ASSOCIATIVE_OPERATORS.contains(op);
-    }
-
-    /**
-     * Returns a value
-     * <ul>
-     *   <li>&lt; 0 iff the <code>operator</code> has lower precedence than the <code>operand</code>
-     *   <li>==; 0 iff the <code>operator</code> has equal precedence than the <code>operand</code>
-     *   <li>&gt; 0 iff the <code>operator</code> has higher precedence than the <code>operand</code>
-     * </ul>
-     */
-    private static int comparePrecedence(String operator, Java.Atom operand) {
-        if (operand instanceof Java.BinaryOperation) {
-            return (
-                ModifiedUnparseVisitor.getOperatorPrecedence(operator)
-                - ModifiedUnparseVisitor.getOperatorPrecedence(((Java.BinaryOperation) operand).op)
-            );
-        } else
-        if (operand instanceof Java.UnaryOperation) {
-            return (
-                ModifiedUnparseVisitor.getOperatorPrecedence(operator)
-                - ModifiedUnparseVisitor.getOperatorPrecedence(((Java.UnaryOperation) operand).operator + "x")
-            );
-        } else
-        if (operand instanceof Java.ConditionalExpression) {
-            return ModifiedUnparseVisitor.getOperatorPrecedence(operator) - ModifiedUnparseVisitor.getOperatorPrecedence("?:");
-        } else
-        if (operand instanceof Java.Instanceof) {
-            return ModifiedUnparseVisitor.getOperatorPrecedence(operator) - ModifiedUnparseVisitor.getOperatorPrecedence("instanceof");
-        } else
-        if (operand instanceof Java.Cast) {
-            return ModifiedUnparseVisitor.getOperatorPrecedence(operator) - ModifiedUnparseVisitor.getOperatorPrecedence("cast");
-        } else
-        if (operand instanceof Java.MethodInvocation || operand instanceof Java.FieldAccess) {
-            return ModifiedUnparseVisitor.getOperatorPrecedence(operator) - ModifiedUnparseVisitor.getOperatorPrecedence(".");
-        } else
-        if (operand instanceof Java.NewArray) {
-            return ModifiedUnparseVisitor.getOperatorPrecedence(operator) - ModifiedUnparseVisitor.getOperatorPrecedence("new");
-        } else
-        if (operand instanceof Java.Crement) {
-            Java.Crement c = (Java.Crement) operand;
-            return (
-                ModifiedUnparseVisitor.getOperatorPrecedence(operator)
-                - ModifiedUnparseVisitor.getOperatorPrecedence(c.pre ? c.operator + "x" : "x" + c.operator)
-            );
-        } else
-        {
-            // All other rvalues (e.g. literal) have higher precedence than any operator.
-            return -1;
-        }
-    }
-    private static int getOperatorPrecedence(String operator) {
-        return ((Integer) ModifiedUnparseVisitor.OPERATOR_PRECEDENCE.get(operator)).intValue();
-    }
-    private static final Set LEFT_ASSOCIATIVE_OPERATORS = new HashSet();
-    private static final Set RIGHT_ASSOCIATIVE_OPERATORS = new HashSet();
-    private static final Set UNARY_OPERATORS = new HashSet();
-    private static final Map OPERATOR_PRECEDENCE = new HashMap();
-    static {
-        Object[] ops = {
-            ModifiedUnparseVisitor.RIGHT_ASSOCIATIVE_OPERATORS, "=", "*=", "/=", "%=", "+=", "-=", "<<=", ">>=", ">>>=",
-                                                        "&=", "^=", "|=",
-            ModifiedUnparseVisitor.RIGHT_ASSOCIATIVE_OPERATORS, "?:",
-            ModifiedUnparseVisitor.LEFT_ASSOCIATIVE_OPERATORS,  "||",
-            ModifiedUnparseVisitor.LEFT_ASSOCIATIVE_OPERATORS,  "&&",
-            ModifiedUnparseVisitor.LEFT_ASSOCIATIVE_OPERATORS,  "|",
-            ModifiedUnparseVisitor.LEFT_ASSOCIATIVE_OPERATORS,  "^",
-            ModifiedUnparseVisitor.LEFT_ASSOCIATIVE_OPERATORS,  "&",
-            ModifiedUnparseVisitor.LEFT_ASSOCIATIVE_OPERATORS,  "==", "!=",
-            ModifiedUnparseVisitor.LEFT_ASSOCIATIVE_OPERATORS,  "<", ">", "<=", ">=", "instanceof",
-            ModifiedUnparseVisitor.LEFT_ASSOCIATIVE_OPERATORS,  "<<", ">>", ">>>",
-            ModifiedUnparseVisitor.LEFT_ASSOCIATIVE_OPERATORS,  "+", "-",
-            ModifiedUnparseVisitor.LEFT_ASSOCIATIVE_OPERATORS,  "*", "/", "%",
-            ModifiedUnparseVisitor.RIGHT_ASSOCIATIVE_OPERATORS, "cast",
-            ModifiedUnparseVisitor.UNARY_OPERATORS,             "++x", "--x", "+x", "-x", "~x", "!x",
-            ModifiedUnparseVisitor.UNARY_OPERATORS,             "x++", "x--",
-            ModifiedUnparseVisitor.LEFT_ASSOCIATIVE_OPERATORS,  "new",
-            ModifiedUnparseVisitor.LEFT_ASSOCIATIVE_OPERATORS,  ".", "[ ]",
-        };
-        int precedence = 0;
-        LOOP1: for (int i = 0;;) {
-            Set s = (Set) ops[i++];
-            Integer pi = new Integer(++precedence);
-            for (;;) {
-                if (i == ops.length) break LOOP1;
-                if (!(ops[i] instanceof String)) break;
-                String op = (String) ops[i++];
-                s.add(op);
-                ModifiedUnparseVisitor.OPERATOR_PRECEDENCE.put(op, pi);
-            }
-        }
-    }
-
-    private void unparseNamedClassDeclaration(Java.NamedClassDeclaration ncd) {
-        this.unparseDocComment(ncd);
-        this.unparseModifiers(ncd.getModifiers());
-        this.pw.print("class " + ncd.name);
-        if (ncd.optionalExtendedType != null) {
-            this.pw.print(" extends ");
-            this.unparseType(ncd.optionalExtendedType);
-        }
-        if (ncd.implementedTypes.length > 0) this.pw.print(" implements " + Java.join(ncd.implementedTypes, ", "));
-        this.pw.println(" {");
-        this.pw.print(AutoIndentWriter.INDENT);
-        this.unparseClassDeclarationBody(ncd);
-        this.pw.print(AutoIndentWriter.UNINDENT + "}");
-    }
-    private void unparseArrayInitializerOrRvalue(Java.ArrayInitializerOrRvalue aiorv) {
-        if (aiorv instanceof Java.Rvalue) {
-            this.unparse((Java.Rvalue) aiorv);
-        } else
-        if (aiorv instanceof Java.ArrayInitializer) {
-            Java.ArrayInitializer ai = (Java.ArrayInitializer) aiorv;
-            if (ai.values.length == 0) {
-                this.pw.print("{}");
-            } else
-            {
-                this.pw.print("{ ");
-                this.unparseArrayInitializerOrRvalue(ai.values[0]);
-                for (int i = 1; i < ai.values.length; ++i) {
-                    this.pw.print(", ");
-                    this.unparseArrayInitializerOrRvalue(ai.values[i]);
-                }
-                this.pw.print(" }");
-            }
-        } else
-        {
-            throw new JaninoRuntimeException(
-                "Unexpected array initializer or rvalue class "
-                + aiorv.getClass().getName()
-            );
-        }
-    }
-
-    public void visitAnonymousClassDeclaration(Java.AnonymousClassDeclaration acd) {
-        this.unparseType(acd.baseType);
-        this.pw.println(" {");
-        this.pw.print(AutoIndentWriter.INDENT);
-        this.unparseClassDeclarationBody(acd);
-        this.pw.print(AutoIndentWriter.UNINDENT + "}");
-    }
-    public void visitNewAnonymousClassInstance(Java.NewAnonymousClassInstance naci) {
-        if (naci.optionalQualification != null) {
-            this.unparseLhs(naci.optionalQualification, ".");
-            this.pw.print('.');
-        }
-        this.pw.print("new " + naci.anonymousClassDeclaration.baseType.toString() + '(');
-        for (int i = 0; i < naci.arguments.length; ++i) {
-            if (i > 0) this.pw.print(", ");
-            this.unparse(naci.arguments[i]);
-        }
-        this.pw.println(") {");
-        this.pw.print(AutoIndentWriter.INDENT);
-        this.unparseClassDeclarationBody(naci.anonymousClassDeclaration);
-        this.pw.print(AutoIndentWriter.UNINDENT + "}");
-    }
-    // Multi-line!
-    private void unparseClassDeclarationBody(Java.ClassDeclaration cd) {
-        for (Iterator it = cd.constructors.iterator(); it.hasNext();) {
-            this.pw.println();
-            ((Java.ConstructorDeclarator) it.next()).accept(this);
-            this.pw.println();
-        }
-        this.unparseAbstractTypeDeclarationBody(cd);
-        for (Iterator it = cd.variableDeclaratorsAndInitializers.iterator(); it.hasNext();) {
-            this.pw.println();
-            ((Java.TypeBodyDeclaration) it.next()).accept(this);
-            this.pw.println();
-        }
-    }
-    private void unparseInterfaceDeclaration(Java.InterfaceDeclaration id) {
-        this.unparseDocComment(id);
-        this.unparseModifiers(id.getModifiers());
-        //make sure we print "interface", even if it wasn't in the modifiers
-        if ((id.getModifiers() & Mod.INTERFACE) == 0) {
-            this.pw.print("interface ");
-        }
-        this.pw.print(id.name);
-        if (id.extendedTypes.length > 0) this.pw.print(" extends " + Java.join(id.extendedTypes, ", "));
-        this.pw.println(" {");
-        this.pw.print(AutoIndentWriter.INDENT);
-        this.unparseAbstractTypeDeclarationBody(id);
-        for (Iterator it = id.constantDeclarations.iterator(); it.hasNext();) {
-            ((Java.TypeBodyDeclaration) it.next()).accept(this);
-            this.pw.println();
-        }
-        this.pw.print(AutoIndentWriter.UNINDENT + "}");
-    }
-    // Multi-line!
-    private void unparseAbstractTypeDeclarationBody(Java.AbstractTypeDeclaration atd) {
-        for (Iterator it = atd.getMethodDeclarations().iterator(); it.hasNext();) {
-            this.pw.println();
-            ((Java.MethodDeclarator) it.next()).accept(this);
-            this.pw.println();
-        }
-        for (Iterator it = atd.getMemberTypeDeclarations().iterator(); it.hasNext();) {
-            this.pw.println();
-            ((Java.TypeBodyDeclaration) it.next()).accept(this);
-            this.pw.println();
-        }
-    }
-    private void unparseFunctionDeclaratorRest(Java.FunctionDeclarator fd) {
-        boolean big = fd.formalParameters.length >= 4;
-        this.pw.print('(');
-        if (big) { this.pw.println(); this.pw.print(AutoIndentWriter.INDENT); }
-        for (int i = 0; i < fd.formalParameters.length; ++i) {
-            if (i > 0) {
-                if (big) {
-                    this.pw.println(',');
-                } else
-                {
-                    this.pw.print(", ");
-                }
-            }
-            this.unparseFormalParameter(fd.formalParameters[i]);
-        }
-        if (big) { this.pw.println(); this.pw.print(AutoIndentWriter.UNINDENT); }
-        this.pw.print(')');
-        if (fd.thrownExceptions.length > 0) this.pw.print(" throws " + Java.join(fd.thrownExceptions, ", "));
-    }
-    private void unparseDocComment(Java.DocCommentable dc) {
-        String optionalDocComment = dc.getDocComment();
-        if (optionalDocComment != null) {
-            this.pw.print("/**");
-            BufferedReader br = new BufferedReader(new StringReader(optionalDocComment));
-            for (;;) {
-                String line;
-                try {
-                    line = br.readLine();
-                } catch (IOException e) {
-                    throw new JaninoRuntimeException();
-                }
-                if (line == null) break;
-                this.pw.println(line);
-                this.pw.print(" *");
-            }
-            this.pw.println("/");
-        }
-    }
-    private void unparseModifiers(short modifiers) {
-        if (modifiers != 0) {
-            this.pw.print(Mod.shortToString(modifiers) + ' ');
-        }
-    }
-    private void unparseFunctionInvocationArguments(Java.Rvalue[] arguments) {
-        boolean big = arguments.length >= 5;
-        this.pw.print('(');
-        if (big) { this.pw.println(); this.pw.print(AutoIndentWriter.INDENT); }
-        for (int i = 0; i < arguments.length; ++i) {
-            if (i > 0) {
-                if (big) {
-                    this.pw.println(',');
-                } else
-                {
-                    this.pw.print(", ");
-                }
-            }
-            this.unparse(arguments[i]);
-        }
-        if (big) { this.pw.println(); this.pw.print(AutoIndentWriter.UNINDENT); }
-        this.pw.print(')');
-    }
-
+      }
+  }
+
+  public void visitReturnStatement(Java.ReturnStatement rs) {
+    this.pw.print("break " + returnLabel);
+    if (rs.optionalReturnValue != null) {
+      this.pw.print(' ');
+      this.unparse(rs.optionalReturnValue);
+    }
+    this.pw.print(';');
+  }
+
+  /*
+   * The following helper methods are copied from the parent class since they
+   * are declared private in the parent class and can not be used in the child
+   * class (this).
+   */
+
+  private void unparseStatements(List<? extends Java.BlockStatement> statements) {
+    int state = -1;
+    for (Java.BlockStatement bs : statements) {
+      int x  = (
+          bs instanceof Java.Block                             ? 1 :
+          bs instanceof Java.LocalClassDeclarationStatement    ? 2 :
+          bs instanceof Java.LocalVariableDeclarationStatement ? 3 :
+          bs instanceof Java.SynchronizedStatement             ? 4 :
+          99
+      );
+      if (state != -1 && state != x) this.pw.println(AutoIndentWriter.CLEAR_TABULATORS);
+      state = x;
+
+      this.unparseBlockStatement(bs);
+      this.pw.println();
+    }
+  }
+
+  private void unparseBlockStatement(Java.BlockStatement blockStatement) {
+    blockStatement.accept(this);
+  }
+
+  private void unparse(Java.Atom operand) {
+    operand.accept(this);
+  }
 }


Mime
View raw message