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 * <?cs var:blah > 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 * <?cs uvar:blah > 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 * <?cs set:x='y' > 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 * <?cs name:blah > 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 * <?cs if:blah > ... <?cs else > ... <?cs /if > 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 * <?cs each:x=Stuff > ... <?cs /each > 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 * <?cs with:x=Something > ... <?cs /with > 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 * <?cs loop:10 > ... <?cs /loop > 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 * <?cs loop:0,10 > ... <?cs /loop > 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 * <?cs loop:0,10,2 > ... <?cs /loop > 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 * <?cs alt:someValue > ... <?cs /alt > 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 * <?cs escape:'html' > 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 * <?cs linclude:'somefile.cs' > 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 * <?cs linclude:'somefile.cs' > 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 * <?cs include!'somefile.cs' > 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 * <?cs include:'somefile.cs' > 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 * <?cs lvar:blah > 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 * <?cs evar:blah > 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 * <?cs def:someMacro(x,y) > ... <?cs /def > 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 * <?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 <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