156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/*
256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Copyright (C) 2010 Google Inc.
356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Licensed under the Apache License, Version 2.0 (the "License");
556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * you may not use this file except in compliance with the License.
656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * You may obtain a copy of the License at
756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * http://www.apache.org/licenses/LICENSE-2.0
956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
1056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Unless required by applicable law or agreed to in writing, software
1156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * distributed under the License is distributed on an "AS IS" BASIS,
1256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * See the License for the specific language governing permissions and
1456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * limitations under the License.
1556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
1656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
1756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpackage com.google.clearsilver.jsilver.compiler;
1856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
1956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.Closeable;
2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.Flushable;
2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.PrintWriter;
2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.Writer;
2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.lang.reflect.Method;
2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.lang.reflect.Modifier;
2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/**
2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Simple API for generating Java source code. Easier than lots of string manipulation.
2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <h3>Example</h3>
3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <pre>
3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * java = new JavaSourceWriter(out);
3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * java.writeComment("// Auto generated file");
3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * java.writePackage("com.something.mypackage");
3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * java.writeImports(SomeClassToImport.class, Another.class);
3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * java.startClass("SomeClass", "InterfaceA");
3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * java.startMethod(Object.class.getMethod("toString"));
4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * java.writeStatement(call("System.out.println", string("hello")));
4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * java.endClass();
4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * </pre>
4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Note: For writing statements/expressions, staticly import the methods on {@link JavaExpression}.
4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic class JavaSourceWriter implements Closeable, Flushable {
4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final PrintWriter out;
4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private int indent;
5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public JavaSourceWriter(Writer out) {
5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.out = new PrintWriter(out);
5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void writePackage(String packageName) {
5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // TODO: Verify packageName is valid.
5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (packageName != null) {
5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      startLine();
5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      out.append("package ").append(packageName).append(';');
6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      endLine();
6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      emptyLine();
6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void writeImports(Class... javaClasses) {
6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    for (Class javaClass : javaClasses) {
6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      startLine();
6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      out.append("import ").append(javaClass.getName()).append(';');
6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      endLine();
7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (javaClasses.length > 0) {
7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      emptyLine();
7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void writeComment(String comment) {
7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // TODO: Handle line breaks in comments.
7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startLine();
7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append("// ").append(comment);
8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endLine();
8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void startClass(String className, String baseClassName, String... interfaceNames) {
8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startLine();
8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append("public class ");
8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeJavaSymbol(out, className);
8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (baseClassName != null) {
8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      out.append(" extends ");
9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      writeJavaSymbol(out, baseClassName);
9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    boolean seenAnyInterfaces = false;
9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    for (String interfaceName : interfaceNames) {
9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (!seenAnyInterfaces) {
9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        seenAnyInterfaces = true;
9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        out.append(" implements ");
9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      } else {
9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        out.append(", ");
10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      writeJavaSymbol(out, interfaceName);
10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(' ');
10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startBlock();
10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    emptyLine();
10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void startAnonymousClass(String baseClass, JavaExpression... constructorArgs) {
11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append("new ");
11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeJavaSymbol(out, baseClass);
11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append('(');
11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    boolean seenAnyArgs = false;
11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    for (JavaExpression constructorArg : constructorArgs) {
11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (seenAnyArgs) {
11756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        out.append(", ");
11856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
11956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      seenAnyArgs = true;
12056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      constructorArg.write(out);
12156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
12256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
12356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(") ");
12456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startBlock();
12556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    emptyLine();
12656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
12756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
12856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void endAnonymousClass() {
12956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endBlock();
13056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
13156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
13256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
13356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Start a method. The signature is based on that of an existing method.
13456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
13556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void startMethod(Method method, String... paramNames) {
13656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // This currently does not support generics, varargs or arrays.
13756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // If you need it - add the support. Don't want to overcomplicate it
13856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // until necessary.
13956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
14056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (paramNames.length != method.getParameterTypes().length) {
14156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new IllegalArgumentException("Did not specifiy correct "
14256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          + "number of parameter names for method signature " + method);
14356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
14456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
14556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startLine();
14656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
14756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // @Override abstract methods.
14856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    int modifiers = method.getModifiers();
14956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (Modifier.isAbstract(modifiers)) {
15056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      out.append("@Override");
15156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      endLine();
15256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      startLine();
15356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
15456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
15556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Modifiers: (public, protected, static)
15656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (modifiers != 0) {
15756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // Modifiers we care about. Ditch the rest. Specifically NOT ABSTRACT.
15856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      modifiers &= Modifier.PUBLIC | Modifier.PROTECTED | Modifier.STATIC;
15956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      out.append(Modifier.toString(modifiers)).append(' ');
16056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
16156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
16256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Return type and name: (e.g. "void doStuff(")
16356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(method.getReturnType().getSimpleName()).append(' ').append(method.getName()).append(
16456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        '(');
16556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
16656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Parameters.
16756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    int paramIndex = 0;
16856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    for (Class<?> paramType : method.getParameterTypes()) {
16956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (paramIndex > 0) {
17056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        out.append(", ");
17156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
17256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      writeJavaSymbol(out, paramType.getSimpleName());
17356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      out.append(' ');
17456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      writeJavaSymbol(out, paramNames[paramIndex]);
17556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      paramIndex++;
17656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
17756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
17856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(')');
17956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
18056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Exceptions thrown.
18156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    boolean seenAnyExceptions = false;
18256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    for (Class exception : method.getExceptionTypes()) {
18356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (!seenAnyExceptions) {
18456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        seenAnyExceptions = true;
18556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        endLine();
18656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        startLine();
18756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        out.append("    throws ");
18856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      } else {
18956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        out.append(", ");
19056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
19156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      writeJavaSymbol(out, exception.getSimpleName());
19256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
19356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
19456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(' ');
19556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startBlock();
19656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
19756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
19856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void startIfBlock(JavaExpression expression) {
19956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startLine();
20056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append("if (");
20156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeExpression(expression);
20256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(") ");
20356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startBlock();
20456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
20556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
20656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void endIfStartElseBlock() {
20756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endBlock();
20856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(" else ");
20956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startBlock();
21056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
21156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
21256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void endIfBlock() {
21356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endBlock();
21456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endLine();
21556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
21656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
21756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void startScopedBlock() {
21856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startLine();
21956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startBlock();
22056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
22156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
22256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void endScopedBlock() {
22356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endBlock();
22456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endLine();
22556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
22656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
22756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void startIterableForLoop(String type, String name, JavaExpression expression) {
22856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startLine();
22956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append("for (");
23056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeJavaSymbol(out, type);
23156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(' ');
23256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeJavaSymbol(out, name);
23356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(" : ");
23456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeExpression(expression);
23556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(") ");
23656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startBlock();
23756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
23856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
23956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void startForLoop(JavaExpression start, JavaExpression end, JavaExpression increment) {
24056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startLine();
24156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append("for (");
24256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeExpression(start);
24356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append("; ");
24456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeExpression(end);
24556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append("; ");
24656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeExpression(increment);
24756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(") ");
24856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startBlock();
24956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
25056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
25156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void endLoop() {
25256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endBlock();
25356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endLine();
25456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
25556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
25656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void writeStatement(JavaExpression expression) {
25756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startLine();
25856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeExpression(expression);
25956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(';');
26056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endLine();
26156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
26256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
26356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void writeExpression(JavaExpression expression) {
26456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    expression.write(out);
26556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
26656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
26756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void endMethod() {
26856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endBlock();
26956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endLine();
27056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    emptyLine();
27156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
27256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
27356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void endClass() {
27456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endBlock();
27556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endLine();
27656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    emptyLine();
27756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
27856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
27956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
28056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void flush() {
28156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.flush();
28256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
28356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
28456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
28556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void close() {
28656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.close();
28756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
28856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
28956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private void startBlock() {
29056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append('{');
29156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endLine();
29256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    indent++;
29356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
29456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
29556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private void endBlock() {
29656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    indent--;
29756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startLine();
29856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append('}');
29956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
30056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
30156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private void startLine() {
30256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    for (int i = 0; i < indent; i++) {
30356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      out.append("  ");
30456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
30556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
30656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
30756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private void endLine() {
30856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append('\n');
30956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
31056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
31156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private void emptyLine() {
31256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append('\n');
31356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
31456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
31556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static void writeJavaSymbol(PrintWriter out, String symbol) {
31656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(symbol); // TODO Make safe and validate.
31756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
31856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
31956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void startField(String type, JavaExpression name) {
32056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    startLine();
32156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append("private final ");
32256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeJavaSymbol(out, type);
32356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(' ');
32456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    name.write(out);
32556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(" = ");
32656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
32756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
32856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void endField() {
32956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    out.append(';');
33056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    endLine();
33156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    emptyLine();
33256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
33356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
33456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson}
335