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 com.google.clearsilver.jsilver.autoescape.EscapeMode;
2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport static com.google.clearsilver.jsilver.compiler.JavaExpression.BooleanLiteralExpression;
2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport static com.google.clearsilver.jsilver.compiler.JavaExpression.Type;
2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport static com.google.clearsilver.jsilver.compiler.JavaExpression.call;
2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport static com.google.clearsilver.jsilver.compiler.JavaExpression.callFindVariable;
2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport static com.google.clearsilver.jsilver.compiler.JavaExpression.callOn;
2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport static com.google.clearsilver.jsilver.compiler.JavaExpression.declare;
2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport static com.google.clearsilver.jsilver.compiler.JavaExpression.increment;
2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport static com.google.clearsilver.jsilver.compiler.JavaExpression.infix;
2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport static com.google.clearsilver.jsilver.compiler.JavaExpression.inlineIf;
2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport static com.google.clearsilver.jsilver.compiler.JavaExpression.integer;
3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport static com.google.clearsilver.jsilver.compiler.JavaExpression.literal;
3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport static com.google.clearsilver.jsilver.compiler.JavaExpression.macro;
3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport static com.google.clearsilver.jsilver.compiler.JavaExpression.string;
3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport static com.google.clearsilver.jsilver.compiler.JavaExpression.symbol;
3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.data.Data;
3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.data.DataContext;
3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.functions.Function;
3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.functions.FunctionExecutor;
3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.analysis.DepthFirstAdapter;
3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AAltCommand;
4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AAutoescapeCommand;
4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ACallCommand;
4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ADataCommand;
4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ADefCommand;
4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AEachCommand;
4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AEscapeCommand;
4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AEvarCommand;
4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AHardIncludeCommand;
4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AHardLincludeCommand;
4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AIfCommand;
5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AIncludeCommand;
5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALincludeCommand;
5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALoopCommand;
5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALoopIncCommand;
5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALoopToCommand;
5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALvarCommand;
5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ANameCommand;
5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ANoopCommand;
5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ASetCommand;
5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AUvarCommand;
6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AVarCommand;
6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AWithCommand;
6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.PCommand;
6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.PExpression;
6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.PPosition;
6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.PVariable;
6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.Start;
6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.TCsOpen;
6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.TWord;
6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.template.Macro;
7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.template.RenderingContext;
7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.template.Template;
7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.values.Value;
7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.IOException;
7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.Writer;
7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.lang.reflect.Method;
7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.HashMap;
7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.LinkedList;
7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.Map;
8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.Queue;
8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/**
8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Translates a JSilver AST into compilable Java code. This executes much faster than the
8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * interpreter.
8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson *
8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @see TemplateCompiler
8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */
8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic class TemplateTranslator extends DepthFirstAdapter {
8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  // Root data
9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static final JavaExpression DATA = symbol(Type.DATA, "data");
9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  // RenderingContext
9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static final JavaExpression CONTEXT = symbol("context");
9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  // DataContext
9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static final JavaExpression DATA_CONTEXT = symbol(Type.DATA_CONTEXT, "dataContext");
9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static final JavaExpression NULL = symbol("null");
9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  // Accessed from macros as well.
9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static final JavaExpression RESOURCE_LOADER = callOn(CONTEXT, "getResourceLoader");
9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static final JavaExpression TEMPLATE_LOADER = symbol("getTemplateLoader()");
10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public static final JavaExpression THIS_TEMPLATE = symbol("this");
10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final JavaSourceWriter java;
10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final String packageName;
10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final String className;
10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final ExpressionTranslator expressionTranslator = new ExpressionTranslator();
10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final VariableTranslator variableTranslator =
10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      new VariableTranslator(expressionTranslator);
11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final EscapingEvaluator escapingEvaluator = new EscapingEvaluator(variableTranslator);
11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private static final Method RENDER_METHOD;
11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private int tempVariable = 0;
11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Used to determine the escaping to apply before displaying a variable. If propagateEscapeStatus
11756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * is enabled, string and numeric literals are not escaped, nor is the output of an escaping
11856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * function. If not, any expression that contains an escaping function is not escaped. This
11956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * maintains compatibility with the way ClearSilver works.
12056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
12156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private boolean propagateEscapeStatus;
12256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
12356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
12456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Holds Macro information used while generating code.
12556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
12656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private static class MacroInfo {
12756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    /**
12856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson     * JavaExpression used for outputting the static Macro variable name.
12956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson     */
13056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression symbol;
13156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
13256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    /**
13356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson     * Parser node for the definition. Stored for evaluation after main render method is output.
13456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson     */
13556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    ADefCommand defNode;
13656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
13756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
13856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
13956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Map of macro names to definition nodes and java expressions used to refer to them.
14056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
14156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final Map<String, MacroInfo> macroMap = new HashMap<String, MacroInfo>();
14256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
14356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
14456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Used to iterate through list of macros. We can't rely on Map's iterator because we may be
14556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * adding to the map as we iterate through the values() list and that would throw a
14656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * ConcurrentModificationException.
14756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
14856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private final Queue<MacroInfo> macroQueue = new LinkedList<MacroInfo>();
14956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
15056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
15156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Creates a MacroInfo object and adds it to the data structures. Also outputs statement to
15256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * register the macro.
15356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *
15456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param name name of the macro as defined in the template.
15556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param symbol static variable name of the macro definition.
15656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * @param defNode parser node holding the macro definition to be evaluated later.
15756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
15856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private void addMacro(String name, JavaExpression symbol, ADefCommand defNode) {
15956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (macroMap.get(name) != null) {
16056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // TODO: This macro is already defined. Should throw an error.
16156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
16256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    MacroInfo info = new MacroInfo();
16356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    info.symbol = symbol;
16456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    info.defNode = defNode;
16556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    macroMap.put(name, info);
16656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    macroQueue.add(info);
16756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
16856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Register the macro.
16956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(CONTEXT, "registerMacro", string(name), symbol));
17056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
17156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
17256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  static {
17356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    try {
17456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      RENDER_METHOD = Template.class.getMethod("render", RenderingContext.class);
17556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } catch (NoSuchMethodException e) {
17656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      throw new Error("Cannot find CompiledTemplate.render() method! " + "Has signature changed?",
17756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          e);
17856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
17956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
18056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
18156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public TemplateTranslator(String packageName, String className, Writer output,
18256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      boolean propagateEscapeStatus) {
18356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.packageName = packageName;
18456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.className = className;
18556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java = new JavaSourceWriter(output);
18656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    this.propagateEscapeStatus = propagateEscapeStatus;
18756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
18856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
18956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
19056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseStart(Start node) {
19156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeComment("This class is autogenerated by JSilver. Do not edit.");
19256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writePackage(packageName);
19356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeImports(BaseCompiledTemplate.class, Template.class, Macro.class,
19456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        RenderingContext.class, Data.class, DataContext.class, Function.class,
19556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        FunctionExecutor.class, Value.class, EscapeMode.class, IOException.class);
19656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.startClass(className, BaseCompiledTemplate.class.getSimpleName());
19756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
19856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Implement render() method.
19956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.startMethod(RENDER_METHOD, "context");
20056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java
20156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        .writeStatement(declare(Type.DATA_CONTEXT, "dataContext", callOn(CONTEXT, "getDataContext")));
20256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(CONTEXT, "pushExecutionContext", THIS_TEMPLATE));
20356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    super.caseStart(node); // Walk template AST.
20456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(CONTEXT, "popExecutionContext"));
20556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.endMethod();
20656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
20756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // The macros have to be defined outside of the render method.
20856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // (Well actually they *could* be defined inline as anon classes, but it
20956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // would make the generated code quite hard to understand).
21056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    MacroTransformer macroTransformer = new MacroTransformer();
21156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
21256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    while (!macroQueue.isEmpty()) {
21356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      MacroInfo curr = macroQueue.remove();
21456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      macroTransformer.parseDefNode(curr.symbol, curr.defNode);
21556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
21656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
21756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.endClass();
21856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
21956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
22056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
22156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Chunk of data (i.e. not a CS command).
22256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
22356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
22456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseADataCommand(ADataCommand node) {
22556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String content = node.getData().getText();
22656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(CONTEXT, "writeUnescaped", string(content)));
22756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
22856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
22956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
23056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs var:blah &gt; expression. Evaluate as string and write output, using default escaping.
23156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
23256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
23356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAVarCommand(AVarCommand node) {
23456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
23556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
23656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String tempVariableName = generateTempVariable("result");
23756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression result = symbol(Type.STRING, tempVariableName);
23856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(declare(Type.STRING, tempVariableName, expressionTranslator
23956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        .translateToString(node.getExpression())));
24056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
24156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression escaping =
24256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        escapingEvaluator.computeIfExemptFromEscaping(node.getExpression(), propagateEscapeStatus);
24356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeVariable(result, escaping);
24456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
24556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
24656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
24756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs uvar:blah &gt; expression. Evaluate as string and write output, but don't escape.
24856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
24956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
25056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAUvarCommand(AUvarCommand node) {
25156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
25256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(CONTEXT, "writeUnescaped", expressionTranslator
25356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        .translateToString(node.getExpression())));
25456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
25556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
25656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
25756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs set:x='y' &gt; command.
25856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
25956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
26056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseASetCommand(ASetCommand node) {
26156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
26256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String tempVariableName = generateTempVariable("setNode");
26356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
26456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Data setNode1 = dataContext.findVariable("x", true);
26556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression setNode = symbol(Type.DATA, tempVariableName);
26656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(declare(Type.DATA, tempVariableName, callFindVariable(variableTranslator
26756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        .translate(node.getVariable()), true)));
26856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // setNode1.setValue("hello");
26956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(setNode, "setValue", expressionTranslator.translateToString(node
27056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        .getExpression())));
27156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
27256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (propagateEscapeStatus) {
27356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // setNode1.setEscapeMode(EscapeMode.ESCAPE_IS_CONSTANT);
27456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.writeStatement(callOn(setNode, "setEscapeMode", escapingEvaluator.computeEscaping(node
27556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          .getExpression(), propagateEscapeStatus)));
27656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
27756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
27856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
27956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
28056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs name:blah &gt; command. Writes out the name of the original variable referred to by a
28156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * given node.
28256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
28356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
28456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseANameCommand(ANameCommand node) {
28556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
28656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression readNode =
28756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        callFindVariable(variableTranslator.translate(node.getVariable()), false);
28856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(CONTEXT, "writeEscaped", call("getNodeName", readNode)));
28956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
29056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
29156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
29256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs if:blah &gt; ... &lt;?cs else &gt; ... &lt;?cs /if &gt; command.
29356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
29456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
29556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAIfCommand(AIfCommand node) {
29656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
29756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
29856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.startIfBlock(expressionTranslator.translateToBoolean(node.getExpression()));
29956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    node.getBlock().apply(this);
30056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (!(node.getOtherwise() instanceof ANoopCommand)) {
30156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.endIfStartElseBlock();
30256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      node.getOtherwise().apply(this);
30356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
30456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.endIfBlock();
30556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
30656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
30756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
30856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs each:x=Stuff &gt; ... &lt;?cs /each &gt; command. Loops over child items of a data
30956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * node.
31056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
31156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
31256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAEachCommand(AEachCommand node) {
31356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
31456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
31556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression parent = expressionTranslator.translateToData(node.getExpression());
31656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeEach(node.getVariable(), parent, node.getCommand());
31756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
31856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
31956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
32056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs with:x=Something &gt; ... &lt;?cs /with &gt; command. Aliases a value within a specific
32156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * scope.
32256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
32356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
32456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAWithCommand(AWithCommand node) {
32556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
32656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
32756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.startScopedBlock();
32856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeComment("with:");
32956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
33056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Extract the value first in case the temp variable has the same name.
33156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression value = expressionTranslator.translateUntyped(node.getExpression());
33256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String methodName = null;
33356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (value.getType() == Type.VAR_NAME) {
33456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      String withValueName = generateTempVariable("withValue");
33556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.writeStatement(declare(Type.STRING, withValueName, value));
33656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      value = symbol(Type.VAR_NAME, withValueName);
33756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      methodName = "createLocalVariableByPath";
33856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
33956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // We need to check if the variable exists. If not, we skip the with
34056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // call.
34156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.startIfBlock(JavaExpression.infix(Type.BOOLEAN, "!=", value.cast(Type.DATA), literal(
34256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          Type.DATA, "null")));
34356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } else {
34456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // Cast to string so we support numeric or boolean values as well.
34556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      value = value.cast(Type.STRING);
34656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      methodName = "createLocalVariableByValue";
34756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
34856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
34956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression itemKey = variableTranslator.translate(node.getVariable());
35056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
35156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Push a new local variable scope for the with local variable
35256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(DATA_CONTEXT, "pushVariableScope"));
35356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
35456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(DATA_CONTEXT, methodName, itemKey, value));
35556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    node.getCommand().apply(this);
35656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
35756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Release the variable scope used by the with statement
35856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(DATA_CONTEXT, "popVariableScope"));
35956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
36056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (value.getType() == Type.VAR_NAME) {
36156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // End of if block that checks that the Data node exists.
36256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.endIfBlock();
36356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
36456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
36556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.endScopedBlock();
36656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
36756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
36856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
36956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs loop:10 &gt; ... &lt;?cs /loop &gt; command. Loops over a range of numbers, starting at
37056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * zero.
37156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
37256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
37356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseALoopToCommand(ALoopToCommand node) {
37456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
37556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
37656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression start = integer(0);
37756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression end = expressionTranslator.translateToNumber(node.getExpression());
37856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression incr = integer(1);
37956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeLoop(node.getVariable(), start, end, incr, node.getCommand());
38056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
38156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
38256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
38356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs loop:0,10 &gt; ... &lt;?cs /loop &gt; command. Loops over a range of numbers.
38456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
38556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
38656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseALoopCommand(ALoopCommand node) {
38756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
38856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
38956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression start = expressionTranslator.translateToNumber(node.getStart());
39056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression end = expressionTranslator.translateToNumber(node.getEnd());
39156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression incr = integer(1);
39256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeLoop(node.getVariable(), start, end, incr, node.getCommand());
39356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
39456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
39556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
39656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs loop:0,10,2 &gt; ... &lt;?cs /loop &gt; command. Loops over a range of numbers, with a
39756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * specific increment.
39856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
39956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
40056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseALoopIncCommand(ALoopIncCommand node) {
40156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
40256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
40356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression start = expressionTranslator.translateToNumber(node.getStart());
40456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression end = expressionTranslator.translateToNumber(node.getEnd());
40556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression incr = expressionTranslator.translateToNumber(node.getIncrement());
40656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeLoop(node.getVariable(), start, end, incr, node.getCommand());
40756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
40856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
40956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private void writeLoop(PVariable itemVariable, JavaExpression start, JavaExpression end,
41056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      JavaExpression incr, PCommand command) {
41156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
41256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.startScopedBlock();
41356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
41456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String startVarName = generateTempVariable("start");
41556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(declare(Type.INT, startVarName, start));
41656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression startVar = symbol(Type.INT, startVarName);
41756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
41856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String endVarName = generateTempVariable("end");
41956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(declare(Type.INT, endVarName, end));
42056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression endVar = symbol(Type.INT, endVarName);
42156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
42256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String incrVarName = generateTempVariable("incr");
42356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(declare(Type.INT, incrVarName, incr));
42456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression incrVar = symbol(Type.INT, incrVarName);
42556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
42656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // TODO: Test correctness of values.
42756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.startIfBlock(call(Type.BOOLEAN, "validateLoopArgs", startVar, endVar, incrVar));
42856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
42956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression itemKey = variableTranslator.translate(itemVariable);
43056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
43156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Push a new local variable scope for the loop local variable
43256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(DATA_CONTEXT, "pushVariableScope"));
43356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
43456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String loopVariable = generateTempVariable("loop");
43556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression loopVar = symbol(Type.INT, loopVariable);
43656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression ifStart = declare(Type.INT, loopVariable, startVar);
43756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression ifEnd =
43856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        inlineIf(Type.BOOLEAN, infix(Type.BOOLEAN, ">=", incrVar, integer(0)), infix(Type.BOOLEAN,
43956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson            "<=", loopVar, endVar), infix(Type.BOOLEAN, ">=", loopVar, endVar));
44056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.startForLoop(ifStart, ifEnd, increment(Type.INT, loopVar, incrVar));
44156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
44256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(DATA_CONTEXT, "createLocalVariableByValue", itemKey, symbol(
44356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        loopVariable).cast(Type.STRING), infix(Type.BOOLEAN, "==", symbol(loopVariable), startVar),
44456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        infix(Type.BOOLEAN, "==", symbol(loopVariable), endVar)));
44556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    command.apply(this);
44656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
44756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.endLoop();
44856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
44956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Release the variable scope used by the loop statement
45056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(DATA_CONTEXT, "popVariableScope"));
45156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
45256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.endIfBlock();
45356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.endScopedBlock();
45456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
45556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
45656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private void writeEach(PVariable itemVariable, JavaExpression parentData, PCommand command) {
45756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
45856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression itemKey = variableTranslator.translate(itemVariable);
45956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
46056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Push a new local variable scope for the each local variable
46156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(DATA_CONTEXT, "pushVariableScope"));
46256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
46356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String childDataVariable = generateTempVariable("child");
46456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.startIterableForLoop("Data", childDataVariable, call("getChildren", parentData));
46556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
46656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(DATA_CONTEXT, "createLocalVariableByPath", itemKey, callOn(
46756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        Type.STRING, symbol(childDataVariable), "getFullPath")));
46856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    command.apply(this);
46956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
47056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.endLoop();
47156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
47256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Release the variable scope used by the each statement
47356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(DATA_CONTEXT, "popVariableScope"));
47456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
47556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
47656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
47756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs alt:someValue &gt; ... &lt;?cs /alt &gt; command. If value exists, write it, otherwise
47856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * write the body of the command.
47956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
48056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
48156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAAltCommand(AAltCommand node) {
48256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
48356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String tempVariableName = generateTempVariable("altVar");
48456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
48556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression declaration =
48656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        expressionTranslator.declareAsVariable(tempVariableName, node.getExpression());
48756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression reference = symbol(declaration.getType(), tempVariableName);
48856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(declaration);
48956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.startIfBlock(reference.cast(Type.BOOLEAN));
49056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
49156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression escaping =
49256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        escapingEvaluator.computeIfExemptFromEscaping(node.getExpression(), propagateEscapeStatus);
49356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    writeVariable(reference, escaping);
49456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.endIfStartElseBlock();
49556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    node.getCommand().apply(this);
49656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.endIfBlock();
49756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
49856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
49956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /*
50056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Generates a statement that will write out a variable expression, after determining whether the
50156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * variable expression should be exempted from any global escaping that may currently be in
50256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * effect. We try to make this determination during translation if possible, and if we cannot, we
50356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * output an if/else statement to check the escaping status of the expression at run time.
50456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *
50556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Currently, unless the expression contains a function call, we know at translation tmie that it
50656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * does not need to be exempted.
50756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
50856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private void writeVariable(JavaExpression result, JavaExpression escapingExpression) {
50956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
51056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (escapingExpression instanceof BooleanLiteralExpression) {
51156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      BooleanLiteralExpression expr = (BooleanLiteralExpression) escapingExpression;
51256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (expr.getValue()) {
51356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        java.writeStatement(callOn(CONTEXT, "writeUnescaped", result.cast(Type.STRING)));
51456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      } else {
51556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        java.writeStatement(callOn(CONTEXT, "writeEscaped", result.cast(Type.STRING)));
51656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
51756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
51856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } else {
51956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.startIfBlock(escapingExpression);
52056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.writeStatement(callOn(CONTEXT, "writeUnescaped", result.cast(Type.STRING)));
52156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.endIfStartElseBlock();
52256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.writeStatement(callOn(CONTEXT, "writeEscaped", result.cast(Type.STRING)));
52356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.endIfBlock();
52456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
52556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
52656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
52756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
52856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs escape:'html' &gt; command. Changes default escaping function.
52956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
53056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
53156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAEscapeCommand(AEscapeCommand node) {
53256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
53356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(CONTEXT, "pushEscapingFunction", expressionTranslator
53456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        .translateToString(node.getExpression())));
53556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    node.getCommand().apply(this);
53656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(CONTEXT, "popEscapingFunction"));
53756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
53856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
53956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
54056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * A fake command injected by AutoEscaper.
54156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *
54256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * AutoEscaper determines the html context in which an include or lvar or evar command is called
54356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * and stores this context in the AAutoescapeCommand node. This function loads the include or lvar
54456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * template in this stored context.
54556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
54656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
54756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAAutoescapeCommand(AAutoescapeCommand node) {
54856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
54956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
55056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(CONTEXT, "pushAutoEscapeMode", callOn(symbol("EscapeMode"),
55156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        "computeEscapeMode", expressionTranslator.translateToString(node.getExpression()))));
55256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    node.getCommand().apply(this);
55356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(CONTEXT, "popAutoEscapeMode"));
55456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
55556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
55656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
55756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
55856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs linclude:'somefile.cs' &gt; command. Lazily includes another template (at render time).
55956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Throw an error if file does not exist.
56056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
56156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
56256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAHardLincludeCommand(AHardLincludeCommand node) {
56356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
56456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(call("include", expressionTranslator
56556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        .translateToString(node.getExpression()), JavaExpression.bool(false), CONTEXT));
56656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
56756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
56856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
56956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs linclude:'somefile.cs' &gt; command. Lazily includes another template (at render time).
57056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Silently ignore if the included file does not exist.
57156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
57256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
57356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseALincludeCommand(ALincludeCommand node) {
57456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
57556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(call("include", expressionTranslator
57656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        .translateToString(node.getExpression()), JavaExpression.bool(true), CONTEXT));
57756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
57856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
57956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
58056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs include!'somefile.cs' &gt; command. Throw an error if file does not exist.
58156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
58256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
58356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAHardIncludeCommand(AHardIncludeCommand node) {
58456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
58556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(call("include", expressionTranslator
58656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        .translateToString(node.getExpression()), JavaExpression.bool(false), CONTEXT));
58756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
58856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
58956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
59056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs include:'somefile.cs' &gt; command. Silently ignore if the included file does not
59156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * exist.
59256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
59356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
59456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAIncludeCommand(AIncludeCommand node) {
59556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
59656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(call("include", expressionTranslator
59756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        .translateToString(node.getExpression()), JavaExpression.bool(true), CONTEXT));
59856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
59956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
60056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
60156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs lvar:blah &gt; command. Evaluate expression and execute commands within.
60256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
60356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
60456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseALvarCommand(ALvarCommand node) {
60556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
60656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    evaluateVariable(node.getExpression(), "[lvar expression]");
60756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
60856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
60956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
61056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs evar:blah &gt; command. Evaluate expression and execute commands within.
61156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
61256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
61356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseAEvarCommand(AEvarCommand node) {
61456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
61556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    evaluateVariable(node.getExpression(), "[evar expression]");
61656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
61756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
61856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private void evaluateVariable(PExpression expression, String stackTraceDescription) {
61956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(callOn(TEMPLATE_LOADER, "createTemp", string(stackTraceDescription),
62056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        expressionTranslator.translateToString(expression), callOn(CONTEXT, "getAutoEscapeMode")),
62156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        "render", CONTEXT));
62256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
62356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
62456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
62556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs def:someMacro(x,y) &gt; ... &lt;?cs /def &gt; command. Define a macro (available for
62656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * the remainder of the context).
62756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
62856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
62956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseADefCommand(ADefCommand node) {
63056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
63156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
63256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // This doesn't actually define the macro body yet, it just calls:
63356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // registerMacro("someMacroName", someReference);
63456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // where someReference is defined as a field later on (with the body).
63556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String name = makeWord(node.getMacro());
63656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (macroMap.containsKey(name)) {
63756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // this is a duplicated definition.
63856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // TODO: Handle duplicates correctly.
63956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
64056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Keep track of the macro so we can generate the body later.
64156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // See MacroTransformer.
64256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    addMacro(name, macro("macro" + macroMap.size()), node);
64356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
64456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
64556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
64656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * This is a special tree walker that's called after the render() method has been generated to
64756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * create the macro definitions and their bodies.
64856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *
64956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * It basically generates fields that look like this:
65056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   *
65156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * private final Macro macro1 = new CompiledMacro("myMacro", "arg1", "arg2"...) { public void
65256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * render(Data data, RenderingContext context) { // macro body. } };
65356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
65456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private class MacroTransformer {
65556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
65656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    public void parseDefNode(JavaExpression macroName, ADefCommand node) {
65756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.startField("Macro", macroName);
65856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
65956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // Parameters passed to constructor. First is name of macro, the rest
66056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // are the name of the arguments.
66156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // e.g. cs def:doStuff(person, cheese)
66256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // -> new CompiledMacro("doStuff", "person", "cheese") { .. }.
66356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      int i = 0;
66456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      JavaExpression[] args = new JavaExpression[1 + node.getArguments().size()];
66556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      args[i++] = string(makeWord(node.getMacro()));
66656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      for (PVariable argName : node.getArguments()) {
66756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        args[i++] = variableTranslator.translate(argName);
66856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
66956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.startAnonymousClass("CompiledMacro", args);
67056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
67156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.startMethod(RENDER_METHOD, "context");
67256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.writeStatement(declare(Type.DATA_CONTEXT, "dataContext", callOn(CONTEXT,
67356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          "getDataContext")));
67456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.writeStatement(callOn(CONTEXT, "pushExecutionContext", THIS_TEMPLATE));
67556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // If !context.isRuntimeAutoEscaping(), enable runtime autoescaping for macro call.
67656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      String tempVariableName = generateTempVariable("doRuntimeAutoEscaping");
67756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      JavaExpression value =
67856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          JavaExpression.prefix(Type.BOOLEAN, "!", callOn(CONTEXT, "isRuntimeAutoEscaping"));
67956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      JavaExpression stmt = declare(Type.BOOLEAN, tempVariableName, value);
68056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.writeStatement(stmt);
68156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
68256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      JavaExpression doRuntimeAutoEscaping = symbol(Type.BOOLEAN, tempVariableName);
68356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.startIfBlock(doRuntimeAutoEscaping.cast(Type.BOOLEAN));
68456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.writeStatement(callOn(CONTEXT, "startRuntimeAutoEscaping"));
68556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.endIfBlock();
68656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
68756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      node.getCommand().apply(TemplateTranslator.this);
68856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
68956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.startIfBlock(doRuntimeAutoEscaping.cast(Type.BOOLEAN));
69056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.writeStatement(callOn(CONTEXT, "stopRuntimeAutoEscaping"));
69156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.endIfBlock();
69256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.writeStatement(callOn(CONTEXT, "popExecutionContext"));
69356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.endMethod();
69456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.endAnonymousClass();
69556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.endField();
69656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
69756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
69856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
69956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private String makeWord(LinkedList<TWord> words) {
70056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (words.size() == 1) {
70156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      return words.getFirst().getText();
70256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
70356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    StringBuilder result = new StringBuilder();
70456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    for (TWord word : words) {
70556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      if (result.length() > 0) {
70656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        result.append('.');
70756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
70856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      result.append(word.getText());
70956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
71056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return result.toString();
71156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
71256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
71356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
71456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * &lt;?cs call:someMacro(x,y) command. Call a macro.
71556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
71656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
71756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseACallCommand(ACallCommand node) {
71856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    capturePosition(node.getPosition());
71956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
72056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    String name = makeWord(node.getMacro());
72156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
72256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.startScopedBlock();
72356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeComment("call:" + name);
72456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
72556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Lookup macro.
72656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // The expression used for the macro will either be the name of the
72756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // static Macro object representing the macro (if we can statically
72856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // determine it), or will be a temporary Macro variable (named
72956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // 'macroCall###') that gets the result of findMacro at evaluation time.
73056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    JavaExpression macroCalled;
73156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    MacroInfo macroInfo = macroMap.get(name);
73256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (macroInfo == null) {
73356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // We never saw the definition of the macro. Assume it might come in an
73456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // included file and look it up at render time.
73556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      String macroCall = generateTempVariable("macroCall");
73656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java
73756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          .writeStatement(declare(Type.MACRO, macroCall, callOn(CONTEXT, "findMacro", string(name))));
73856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
73956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      macroCalled = macro(macroCall);
74056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    } else {
74156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      macroCalled = macroInfo.symbol;
74256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
74356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
74456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    int numArgs = node.getArguments().size();
74556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (numArgs > 0) {
74656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
74756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // TODO: Add check that number of arguments passed in equals the
74856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // number expected by the macro. This should be done at translation
74956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // time in a future CL.
75056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
75156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      JavaExpression[] argValues = new JavaExpression[numArgs];
75256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      JavaExpression[] argStatus = new JavaExpression[numArgs];
75356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
75456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // Read the values first in case the new local variables shares the same
75556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // name as a variable (or variable expansion) being passed in to the macro.
75656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      int i = 0;
75756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      for (PExpression argNode : node.getArguments()) {
75856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        JavaExpression value = expressionTranslator.translateUntyped(argNode);
75956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        if (value.getType() != Type.VAR_NAME) {
76056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          value = value.cast(Type.STRING);
76156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        }
76256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        String valueName = generateTempVariable("argValue");
76356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        java.writeStatement(declare(Type.STRING, valueName, value));
76456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        argValues[i] = JavaExpression.symbol(value.getType(), valueName);
76556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        if (propagateEscapeStatus) {
76656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          argStatus[i] = escapingEvaluator.computeEscaping(argNode, propagateEscapeStatus);
76756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        } else {
76856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          argStatus[i] = JavaExpression.symbol("EscapeMode.ESCAPE_NONE");
76956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        }
77056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
77156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        i++;
77256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
77356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
77456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // Push a new local variable scope for this macro execution.
77556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.writeStatement(callOn(DATA_CONTEXT, "pushVariableScope"));
77656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
77756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // Create the local variables for each argument.
77856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      for (i = 0; i < argValues.length; i++) {
77956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        JavaExpression value = argValues[i];
78056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        JavaExpression tempVar = callOn(macroCalled, "getArgumentName", integer(i));
78156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        String methodName;
78256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        if (value.getType() == Type.VAR_NAME) {
78356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          methodName = "createLocalVariableByPath";
78456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          java.writeStatement(callOn(DATA_CONTEXT, methodName, tempVar, value));
78556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        } else {
78656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          // Must be String as we cast it above.
78756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          methodName = "createLocalVariableByValue";
78856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson          java.writeStatement(callOn(DATA_CONTEXT, methodName, tempVar, value, argStatus[i]));
78956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        }
79056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      }
79156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
79256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
79356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    // Render macro.
79456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(macroCalled, "render", CONTEXT));
79556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
79656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    if (numArgs > 0) {
79756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      // Release the variable scope used by the macro call
79856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson      java.writeStatement(callOn(DATA_CONTEXT, "popVariableScope"));
79956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    }
80056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
80156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.endScopedBlock();
80256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
80356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
80456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
80556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Walks the PPosition tree, which calls {@link #caseTCsOpen(TCsOpen)} below. This is simply to
80656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * capture the position of the node in the original template file, to help developers diagnose
80756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * errors.
80856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
80956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private void capturePosition(PPosition position) {
81056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    position.apply(this);
81156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
81256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
81356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  /**
81456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * Every time a &lt;cs token is found, grab the line and column and call
81556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   * context.setCurrentPosition() so this is captured for stack traces.
81656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson   */
81756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  @Override
81856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  public void caseTCsOpen(TCsOpen node) {
81956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    int line = node.getLine();
82056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    int column = node.getPos();
82156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    java.writeStatement(callOn(CONTEXT, "setCurrentPosition", JavaExpression.integer(line),
82256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson        JavaExpression.integer(column)));
82356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
82456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson
82556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  private String generateTempVariable(String prefix) {
82656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson    return prefix + tempVariable++;
82756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson  }
82856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson}
829