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.interpreter; 1856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 1956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.autoescape.EscapeMode; 2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.data.Data; 2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.data.DataContext; 2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.exceptions.ExceptionUtil; 2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.exceptions.JSilverIOException; 2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.exceptions.JSilverInterpreterException; 2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.functions.FunctionExecutor; 2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.analysis.DepthFirstAdapter; 2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AAltCommand; 2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AAutoescapeCommand; 2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ACallCommand; 3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ADataCommand; 3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ADefCommand; 3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AEachCommand; 3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AEscapeCommand; 3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AEvarCommand; 3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AHardIncludeCommand; 3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AHardLincludeCommand; 3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AIfCommand; 3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AIncludeCommand; 3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALincludeCommand; 4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALoopCommand; 4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALoopIncCommand; 4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALoopToCommand; 4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALvarCommand; 4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ANameCommand; 4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ANameVariable; 4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ASetCommand; 4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AUvarCommand; 4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AVarCommand; 4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AWithCommand; 5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.PCommand; 5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.PExpression; 5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.PPosition; 5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.PVariable; 5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.TCsOpen; 5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.TWord; 5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.template.Macro; 5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.template.RenderingContext; 5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.template.Template; 5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.template.TemplateLoader; 6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.values.Value; 6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.values.VariableValue; 6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.IOException; 6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.Iterator; 6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.LinkedList; 6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/** 6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Main JSilver interpreter. This walks a template's AST and renders the result out. 6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic class TemplateInterpreter extends DepthFirstAdapter { 7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private final Template template; 7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private final ExpressionEvaluator expressionEvaluator; 7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private final VariableLocator variableLocator; 7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private final TemplateLoader templateLoader; 7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private final RenderingContext context; 7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private final DataContext dataContext; 7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public TemplateInterpreter(Template template, TemplateLoader templateLoader, 8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson RenderingContext context, FunctionExecutor functionExecutor) { 8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.template = template; 8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.templateLoader = templateLoader; 8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.context = context; 8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.dataContext = context.getDataContext(); 8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson expressionEvaluator = new ExpressionEvaluator(dataContext, functionExecutor); 8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson variableLocator = new VariableLocator(expressionEvaluator); 8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // ------------------------------------------------------------------------ 9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // COMMAND PROCESSING 9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Chunk of data (i.e. not a CS command). 9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseADataCommand(ADataCommand node) { 9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson context.writeUnescaped(node.getData().getText()); 10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs var:blah > expression. Evaluate as string and write output, using default escaping. 10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAVarCommand(AVarCommand node) { 10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Evaluate expression. 11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Value value = expressionEvaluator.evaluate(node.getExpression()); 11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson writeVariable(value); 11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs uvar:blah > expression. Evaluate as string and write output, but don't escape. 11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 11756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 11856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAUvarCommand(AUvarCommand node) { 11956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 12056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 12156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Evaluate expression. 12256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Value value = expressionEvaluator.evaluate(node.getExpression()); 12356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson context.writeUnescaped(value.asString()); 12456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 12556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 12656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 12756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs lvar:blah > command. Evaluate expression and execute commands within. 12856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 12956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 13056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseALvarCommand(ALvarCommand node) { 13156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 13256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson evaluateVariable(node.getExpression(), "[lvar expression]"); 13356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 13456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 13556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 13656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs evar:blah > command. Evaluate expression and execute commands within. 13756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 13856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 13956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAEvarCommand(AEvarCommand node) { 14056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 14156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson evaluateVariable(node.getExpression(), "[evar expression]"); 14256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 14356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 14456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void evaluateVariable(PExpression expression, String stackTraceDescription) { 14556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Evaluate expression. 14656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Value value = expressionEvaluator.evaluate(expression); 14756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 14856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Now parse result, into new mini template. 14956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Template template = 15056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson templateLoader.createTemp(stackTraceDescription, value.asString(), context 15156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson .getAutoEscapeMode()); 15256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 15356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Intepret new template. 15456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson try { 15556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson template.render(context); 15656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } catch (IOException e) { 15756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverInterpreterException(e.getMessage()); 15856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 15956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 16056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 16156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 16256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs linclude!'somefile.cs' > command. Lazily includes another template (at render time). 16356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Throw an error if file does not exist. 16456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 16556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 16656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAHardLincludeCommand(AHardLincludeCommand node) { 16756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 16856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson include(node.getExpression(), false); 16956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 17056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 17156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 17256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs linclude:'somefile.cs' > command. Lazily includes another template (at render time). 17356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Silently ignore if the included file does not exist. 17456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 17556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 17656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseALincludeCommand(ALincludeCommand node) { 17756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 17856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson include(node.getExpression(), true); 17956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 18056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 18156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 18256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs include!'somefile.cs' > command. Throw an error if file does not exist. 18356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 18456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 18556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAHardIncludeCommand(AHardIncludeCommand node) { 18656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 18756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson include(node.getExpression(), false); 18856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 18956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 19056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 19156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs include:'somefile.cs' > command. Silently ignore if the included file does not 19256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * exist. 19356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 19456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 19556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAIncludeCommand(AIncludeCommand node) { 19656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 19756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson include(node.getExpression(), true); 19856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 19956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 20056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 20156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs set:x='y' > command. 20256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 20356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 20456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseASetCommand(ASetCommand node) { 20556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 20656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String variableName = variableLocator.getVariableName(node.getVariable()); 20756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 20856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson try { 20956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Data variable = dataContext.findVariable(variableName, true); 21056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Value value = expressionEvaluator.evaluate(node.getExpression()); 21156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson variable.setValue(value.asString()); 21256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // TODO: what about nested structures? 21356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // "set" was used to set a variable to a constant or escaped value like 21456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // <?cs set: x = "<b>X</b>" ?> or <?cs set: y = html_escape(x) ?> 21556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Keep track of this so autoescaping code can take it into account. 21656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson variable.setEscapeMode(value.getEscapeMode()); 21756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } catch (UnsupportedOperationException e) { 21856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // An error occurred - probably due to trying to modify an UnmodifiableData 21956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new UnsupportedOperationException(createUnsupportedOperationMessage(node, context 22056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson .getIncludedTemplateNames()), e); 22156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 22256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 22356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 22456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 22556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs name:blah > command. Writes out the name of the original variable referred to by a 22656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * given node. 22756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 22856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 22956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseANameCommand(ANameCommand node) { 23056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 23156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String variableName = variableLocator.getVariableName(node.getVariable()); 23256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Data variable = dataContext.findVariable(variableName, false); 23356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (variable != null) { 23456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson context.writeEscaped(variable.getSymlink().getName()); 23556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 23656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 23756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 23856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 23956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs if:blah > ... <?cs else > ... <?cs /if > command. 24056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 24156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 24256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAIfCommand(AIfCommand node) { 24356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 24456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Value value = expressionEvaluator.evaluate(node.getExpression()); 24556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (value.asBoolean()) { 24656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson node.getBlock().apply(this); 24756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 24856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson node.getOtherwise().apply(this); 24956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 25056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 25156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 25256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 25356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 25456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs escape:'html' > command. Changes default escaping function. 25556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 25656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 25756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAEscapeCommand(AEscapeCommand node) { 25856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 25956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Value value = expressionEvaluator.evaluate(node.getExpression()); 26056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String escapeStrategy = value.asString(); 26156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 26256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson context.pushEscapingFunction(escapeStrategy); 26356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson node.getCommand().apply(this); 26456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson context.popEscapingFunction(); 26556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 26656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 26756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 26856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * A fake command injected by AutoEscaper. 26956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 27056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * AutoEscaper determines the html context in which an include or lvar or evar command is called 27156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * and stores this context in the AAutoescapeCommand node. 27256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 27356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 27456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAAutoescapeCommand(AAutoescapeCommand node) { 27556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 27656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Value value = expressionEvaluator.evaluate(node.getExpression()); 27756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String escapeStrategy = value.asString(); 27856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 27956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson EscapeMode mode = EscapeMode.computeEscapeMode(escapeStrategy); 28056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 28156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson context.pushAutoEscapeMode(mode); 28256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson node.getCommand().apply(this); 28356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson context.popAutoEscapeMode(); 28456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 28556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 28656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 28756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs with:x=Something > ... <?cs /with > command. Aliases a value within a specific 28856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * scope. 28956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 29056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 29156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAWithCommand(AWithCommand node) { 29256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 29356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson VariableLocator variableLocator = new VariableLocator(expressionEvaluator); 29456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String withVar = variableLocator.getVariableName(node.getVariable()); 29556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Value value = expressionEvaluator.evaluate(node.getExpression()); 29656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 29756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (value instanceof VariableValue) { 29856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (((VariableValue) value).getReference() == null) { 29956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // With refers to a non-existent variable. Do nothing. 30056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 30156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 30256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 30356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 30456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson dataContext.pushVariableScope(); 30556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setTempVariable(withVar, value); 30656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson node.getCommand().apply(this); 30756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson dataContext.popVariableScope(); 30856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 30956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 31056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 31156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs loop:10 > ... <?cs /loop > command. Loops over a range of numbers, starting at 31256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * zero. 31356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 31456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 31556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseALoopToCommand(ALoopToCommand node) { 31656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 31756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int end = expressionEvaluator.evaluate(node.getExpression()).asNumber(); 31856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 31956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Start is always zero, increment is always 1, so end < 0 is invalid. 32056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (end < 0) { 32156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; // Incrementing the wrong way. Avoid infinite loop. 32256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 32356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 32456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson loop(node.getVariable(), 0, end, 1, node.getCommand()); 32556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 32656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 32756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 32856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs loop:0,10 > ... <?cs /loop > command. Loops over a range of numbers. 32956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 33056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 33156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseALoopCommand(ALoopCommand node) { 33256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 33356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int start = expressionEvaluator.evaluate(node.getStart()).asNumber(); 33456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int end = expressionEvaluator.evaluate(node.getEnd()).asNumber(); 33556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 33656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Start is always zero, increment is always 1, so end < 0 is invalid. 33756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (end < start) { 33856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; // Incrementing the wrong way. Avoid infinite loop. 33956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 34056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 34156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson loop(node.getVariable(), start, end, 1, node.getCommand()); 34256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 34356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 34456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 34556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs loop:0,10,2 > ... <?cs /loop > command. Loops over a range of numbers, with a 34656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * specific increment. 34756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 34856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 34956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseALoopIncCommand(ALoopIncCommand node) { 35056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 35156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int start = expressionEvaluator.evaluate(node.getStart()).asNumber(); 35256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int end = expressionEvaluator.evaluate(node.getEnd()).asNumber(); 35356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int incr = expressionEvaluator.evaluate(node.getIncrement()).asNumber(); 35456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 35556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (incr == 0) { 35656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; // No increment. Avoid infinite loop. 35756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 35856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (incr > 0 && start > end) { 35956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; // Incrementing the wrong way. Avoid infinite loop. 36056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 36156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (incr < 0 && start < end) { 36256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; // Incrementing the wrong way. Avoid infinite loop. 36356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 36456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 36556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson loop(node.getVariable(), start, end, incr, node.getCommand()); 36656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 36756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 36856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 36956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs each:x=Stuff > ... <?cs /each > command. Loops over child items of a data 37056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * node. 37156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 37256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 37356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAEachCommand(AEachCommand node) { 37456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 37556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Value expression = expressionEvaluator.evaluate(node.getExpression()); 37656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 37756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (expression instanceof VariableValue) { 37856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson VariableValue variableValue = (VariableValue) expression; 37956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Data parent = variableValue.getReference(); 38056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (parent != null) { 38156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson each(node.getVariable(), variableValue.getName(), parent, node.getCommand()); 38256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 38356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 38456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 38556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 38656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 38756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs alt:someValue > ... <?cs /alt > command. If value exists, write it, otherwise 38856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * write the body of the command. 38956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 39056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 39156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAAltCommand(AAltCommand node) { 39256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setLastPosition(node.getPosition()); 39356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Value value = expressionEvaluator.evaluate(node.getExpression()); 39456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (value.asBoolean()) { 39556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson writeVariable(value); 39656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 39756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson node.getCommand().apply(this); 39856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 39956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 40056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 40156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void writeVariable(Value value) { 40256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (template.getEscapeMode().isAutoEscapingMode()) { 40356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson autoEscapeAndWriteVariable(value); 40456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else if (value.isPartiallyEscaped()) { 40556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson context.writeUnescaped(value.asString()); 40656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 40756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson context.writeEscaped(value.asString()); 40856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 40956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 41056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 41156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void autoEscapeAndWriteVariable(Value value) { 41256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (isTrustedValue(value) || value.isPartiallyEscaped()) { 41356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson context.writeUnescaped(value.asString()); 41456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 41556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson context.writeEscaped(value.asString()); 41656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 41756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 41856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 41956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private boolean isTrustedValue(Value value) { 42056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // True if PropagateEscapeStatus is enabled and value has either been 42156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // escaped or contains a constant string. 42256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return context.getAutoEscapeOptions().getPropagateEscapeStatus() 42356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson && !value.getEscapeMode().equals(EscapeMode.ESCAPE_NONE); 42456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 42556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 42656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // ------------------------------------------------------------------------ 42756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // MACROS 42856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 42956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 43056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs def:someMacro(x,y) > ... <?cs /def > command. Define a macro (available for 43156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * the remainder of the interpreter context. 43256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 43356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 43456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseADefCommand(ADefCommand node) { 43556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String macroName = makeWord(node.getMacro()); 43656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson LinkedList<PVariable> arguments = node.getArguments(); 43756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String[] argumentNames = new String[arguments.size()]; 43856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int i = 0; 43956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson for (PVariable argument : arguments) { 44056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (!(argument instanceof ANameVariable)) { 44156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverInterpreterException("Invalid name for macro '" + macroName 44256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson + "' argument " + i + " : " + argument); 44356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 44456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson argumentNames[i++] = ((ANameVariable) argument).getWord().getText(); 44556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 44656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // TODO: Should we enforce that macro args can't repeat the same 44756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // name? 44856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson context.registerMacro(macroName, new InterpretedMacro(node.getCommand(), template, macroName, 44956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson argumentNames, this, context)); 45056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 45156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 45256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private String makeWord(LinkedList<TWord> words) { 45356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (words.size() == 1) { 45456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return words.getFirst().getText(); 45556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 45656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson StringBuilder result = new StringBuilder(); 45756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson for (TWord word : words) { 45856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (result.length() > 0) { 45956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson result.append('.'); 46056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 46156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson result.append(word.getText()); 46256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 46356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return result.toString(); 46456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 46556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 46656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 46756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs call:someMacro(x,y) command. Call a macro. Need to create a new variable scope to hold 46856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * the local variables defined by the parameters of the macro definition 46956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 47056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 47156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseACallCommand(ACallCommand node) { 47256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String macroName = makeWord(node.getMacro()); 47356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Macro macro = context.findMacro(macroName); 47456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 47556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Make sure that the number of arguments passed to the macro match the 47656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // number expected. 47756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (node.getArguments().size() != macro.getArgumentCount()) { 47856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverInterpreterException("Number of arguments to macro " + macroName + " (" 47956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson + node.getArguments().size() + ") does not match " + "number of expected arguments (" 48056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson + macro.getArgumentCount() + ")"); 48156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 48256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 48356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int numArgs = node.getArguments().size(); 48456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (numArgs > 0) { 48556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Value[] argValues = new Value[numArgs]; 48656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 48756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // We must first evaluate the parameters we are passing or there could be 48856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // conflicts if new argument names match existing variables. 48956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Iterator<PExpression> argumentValues = node.getArguments().iterator(); 49056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson for (int i = 0; argumentValues.hasNext(); i++) { 49156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson argValues[i] = expressionEvaluator.evaluate(argumentValues.next()); 49256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 49356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 49456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // No need to bother pushing and popping the variable scope stack 49556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // if there are no new local variables to declare. 49656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson dataContext.pushVariableScope(); 49756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 49856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson for (int i = 0; i < argValues.length; i++) { 49956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setTempVariable(macro.getArgumentName(i), argValues[i]); 50056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 50156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 50256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson try { 50356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson macro.render(context); 50456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } catch (IOException e) { 50556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverIOException(e); 50656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 50756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (numArgs > 0) { 50856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // No need to bother pushing and popping the variable scope stack 50956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // if there are no new local variables to declare. 51056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson dataContext.popVariableScope(); 51156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 51256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 51356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 51456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // ------------------------------------------------------------------------ 51556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // HELPERS 51656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // 51756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Much of the functionality in this section could easily be inlined, 51856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // however it makes the rest of the interpreter much easier to understand 51956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // and refactor with them defined here. 52056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 52156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void each(PVariable variable, String parentName, Data items, PCommand command) { 52256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Since HDF variables are now passed to macro parameters by path name 52356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // we need to create a path for each child when generating the 52456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // VariableValue object. 52556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson VariableLocator variableLocator = new VariableLocator(expressionEvaluator); 52656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String eachVar = variableLocator.getVariableName(variable); 52756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson StringBuilder pathBuilder = new StringBuilder(parentName); 52856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson pathBuilder.append('.'); 52956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int length = pathBuilder.length(); 53056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson dataContext.pushVariableScope(); 53156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson for (Data child : items.getChildren()) { 53256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson pathBuilder.delete(length, pathBuilder.length()); 53356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson pathBuilder.append(child.getName()); 53456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson setTempVariable(eachVar, Value.variableValue(pathBuilder.toString(), dataContext)); 53556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson command.apply(this); 53656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 53756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson dataContext.popVariableScope(); 53856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 53956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 54056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void loop(PVariable loopVar, int start, int end, int incr, PCommand command) { 54156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson VariableLocator variableLocator = new VariableLocator(expressionEvaluator); 54256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String varName = variableLocator.getVariableName(loopVar); 54356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 54456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson dataContext.pushVariableScope(); 54556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Loop deals with counting forward or backwards. 54656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson for (int index = start; incr > 0 ? index <= end : index >= end; index += incr) { 54756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // We reuse the same scope for efficiency and simply overwrite the 54856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // previous value of the loop variable. 54956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson dataContext.createLocalVariableByValue(varName, String.valueOf(index), index == start, 55056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index == end); 55156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 55256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson command.apply(this); 55356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 55456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson dataContext.popVariableScope(); 55556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 55656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 55756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 55856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Code common to all three include commands. 55956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 56056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param expression expression representing name of file to include. 56156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param ignoreMissingFile {@code true} if any FileNotFound error generated by the template 56256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * loader should be ignored, {@code false} otherwise. 56356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 56456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void include(PExpression expression, boolean ignoreMissingFile) { 56556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Evaluate expression. 56656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Value path = expressionEvaluator.evaluate(expression); 56756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 56856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String templateName = path.asString(); 56956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (!context.pushIncludeStackEntry(templateName)) { 57056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverInterpreterException(createIncludeLoopErrorMessage(templateName, context 57156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson .getIncludedTemplateNames())); 57256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 57356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 57456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson loadAndRenderIncludedTemplate(templateName, ignoreMissingFile); 57556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 57656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (!context.popIncludeStackEntry(templateName)) { 57756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Include stack trace is corrupted 57856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new IllegalStateException("Unable to find on include stack: " + templateName); 57956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 58056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 58156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 58256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private String createIncludeLoopErrorMessage(String templateName, Iterable<String> includeStack) { 58356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson StringBuilder message = new StringBuilder(); 58456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append("File included twice: "); 58556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append(templateName); 58656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 58756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append(" Include stack:"); 58856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson for (String fileName : includeStack) { 58956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append("\n -> "); 59056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append(fileName); 59156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 59256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append("\n -> "); 59356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append(templateName); 59456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return message.toString(); 59556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 59656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 59756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private String createUnsupportedOperationMessage(PCommand node, Iterable<String> includeStack) { 59856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson StringBuilder message = new StringBuilder(); 59956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 60056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append("exception thrown while parsing node: "); 60156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append(node.toString()); 60256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append(" (class ").append(node.getClass().getSimpleName()).append(")"); 60356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append("\nTemplate include stack: "); 60456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 60556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson for (Iterator<String> iter = includeStack.iterator(); iter.hasNext();) { 60656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append(iter.next()); 60756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (iter.hasNext()) { 60856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append(" -> "); 60956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 61056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 61156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append("\n"); 61256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 61356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return message.toString(); 61456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 61556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 61656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // This method should ONLY be called from include() 61756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void loadAndRenderIncludedTemplate(String templateName, boolean ignoreMissingFile) { 61856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Now load new template with given name. 61956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Template template = null; 62056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson try { 62156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson template = 62256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson templateLoader.load(templateName, context.getResourceLoader(), context 62356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson .getAutoEscapeMode()); 62456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } catch (RuntimeException e) { 62556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (ignoreMissingFile && ExceptionUtil.isFileNotFoundException(e)) { 62656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 62756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 62856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw e; 62956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 63056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 63156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 63256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Intepret loaded template. 63356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson try { 63456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // TODO: Execute lincludes (but not includes) in a separate 63556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // context. 63656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson template.render(context); 63756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } catch (IOException e) { 63856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new JSilverInterpreterException(e.getMessage()); 63956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 64056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 64156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 64256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void setLastPosition(PPosition position) { 64356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Walks position node which will eventually result in calling 64456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // caseTCsOpen(). 64556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson position.apply(this); 64656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 64756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 64856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 64956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Every time a <cs token is found, grab the line and position (for helpful error messages). 65056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 65156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 65256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseTCsOpen(TCsOpen node) { 65356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int line = node.getLine(); 65456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int column = node.getPos(); 65556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson context.setCurrentPosition(line, column); 65656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 65756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 65856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void setTempVariable(String variableName, Value value) { 65956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (value instanceof VariableValue) { 66056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // If the value is a Data variable name, then we store a reference to its 66156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // name as discovered by the expression evaluator and resolve it each 66256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // time for correctness. 66356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson dataContext.createLocalVariableByPath(variableName, ((VariableValue) value).getName()); 66456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 66556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson dataContext.createLocalVariableByValue(variableName, value.asString(), value.getEscapeMode()); 66656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 66756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 66856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 66956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson} 670