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.syntax; 1856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 1956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.analysis.DepthFirstAdapter; 2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AAltCommand; 2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ACallCommand; 2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ADataCommand; 2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ADefCommand; 2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AEachCommand; 2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AEscapeCommand; 2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AEvarCommand; 2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AIfCommand; 2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALoopCommand; 2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALoopIncCommand; 3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALoopToCommand; 3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ALvarCommand; 3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ANameCommand; 3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ANoopCommand; 3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.ASetCommand; 3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AUvarCommand; 3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AVarCommand; 3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.AWithCommand; 3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.Start; 3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.syntax.node.TData; 4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.ArrayList; 4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.List; 4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.regex.Matcher; 4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.regex.Pattern; 4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/** 4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Detects sequences of commands corresponding to a line in the template containing only structural 4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * commands, comments or whitespace and rewrites the syntax tree to effectively remove any data 4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * (text) associated with that line (including the trailing whitespace). 5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p> 5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * A structural command is any command that never emits any output. These come in three types: 5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <ul> 5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <li>Commands that can contain other commands (eg, "alt", "each", "escape", "if", "loop", "with", 5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * etc...). 5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <li>Commands that operate on the template itself (eg, "include", "autoescape", etc...). 5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <li>Comments. 5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * </ul> 5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p> 5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * This makes it much easier to write human readable templates in cases where the output format is 6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * whitespace sensitive. 6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p> 6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Thus the input: 6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <pre> 6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * {@literal 6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * ---------------- 6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Value is: 6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs if:x>0 ?> 6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * positive 7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs elif:x<0 ?> 7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * negative 7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs else ?> 7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * zero 7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs /if ?>. 7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * ---------------- 7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * } 7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * </pre> 7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * is equivalent to: 7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <pre> 8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * {@literal 8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * ---------------- 8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Value is: 8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs if:x>0 ?> positive 8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs elif:x<0 ?> negative 8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs else ?> zero 8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs /if ?>. 8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * ---------------- 8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * } 9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * </pre> 9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * but is much easier to read. 9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p> 9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Where data commands become empty they are replaced with Noop commands, which effectively removes 9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * them from the tree. These can be removed (if needed) by a later optimization step but shouldn't 9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * cause any issues. 9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic class StructuralWhitespaceStripper extends DepthFirstAdapter { 9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * A regex snippet to match sequences of inline whitespace. The easiest way to define this is as 10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * "not (non-space or newline)". 10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static final String IWS = "[^\\S\\n]*"; 10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** Pattern to match strings that consist only of inline whitespace. */ 10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static final Pattern INLINE_WHITESPACE = Pattern.compile(IWS); 10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Pattern to match strings that start with arbitrary (inline) whitespace, followed by a newline. 10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static final Pattern STARTS_WITH_NEWLINE = Pattern.compile("^" + IWS + "\\n"); 11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Pattern to match strings that end with a newline, followed by trailing (inline) whitespace. 11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static final Pattern ENDS_WITH_NEWLINE = Pattern.compile("\\n" + IWS + "$"); 11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 11756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 11856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Pattern to capture the content of a string after a leading newline. Only ever used on input 11956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * that previously matched STARTS_WITH_NEWLINE. 12056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 12156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static final Pattern LEADING_WHITESPACE_AND_NEWLINE = 12256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Pattern.compile("^" + IWS + "\\n(.*)$", Pattern.DOTALL); 12356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 12456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 12556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Pattern to capture the content of a string before a trailing newline. Note that this may have 12656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * to match text that has already had the final newline removed so we must greedily match the 12756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * whitespace rather than the content. 12856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 12956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static final Pattern TRAILING_WHITESPACE = 13056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Pattern.compile("^(.*?)" + IWS + "$", Pattern.DOTALL); 13156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 13256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 13356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Flag to tell us if we are in whitespace chomping mode. By default we start in this mode because 13456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * the content of the first line in a template is not preceded by a newline (but should behave as 13556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * if it was). Once this flag has been set to false, it remains unset until a new line is 13656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * encountered. 13756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p> 13856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Note that we only actually remove whitespace when we find the terminating condition rather than 13956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * when as visit the nodes (ie, this mode can be aborted and any visited whitespace will be left 14056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * untouched). 14156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 14256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private boolean maybeChompWhitespace = true; 14356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 14456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 14556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Flag to tell us if the line we are processing has an inline command in it. 14656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p> 14756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * An inline command is a complex command (eg. 'if', 'loop') where both the start and end of the 14856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * command exists on the same line. Non-complex commands (eg. 'var', 'name') cannot be considered 14956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * inline. 15056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p> 15156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * This flag is set when we process the start of a complex command and unset when we finish 15256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * processing a line. Thus if the flag is still true when we encounter the end of a complex 15356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * command, it tells us that (at least one) complex command was entirely contained within the 15456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * current line and that we should stop chomping whitespace for the current line. 15556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p> 15656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * This means we can detect input such as: 15756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 15856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <pre> 15956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * {@literal <?cs if:x?> <?cs /if?>} 16056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * </pre> 16156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * for which the trailing newline and surrounding whitespace should not be removed, as opposed to: 16256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 16356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <pre> 16456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * {@literal <?cs if:x?> 16556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * something 16656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <?cs /if?> 16756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * } 16856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * </pre> 16956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * where the trailing newlines for both the opening and closing of the 'if' command should be 17056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * removed. 17156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 17256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private boolean currentLineContainsInlineComplexCommand = false; 17356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 17456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 17556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * First data command we saw when we started 'chomping' whitespace (note that this can be null if 17656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * we are at the beginning of a file or when we have chomped a previous data command down to 17756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * nothing). 17856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 17956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private ADataCommand firstChompedData = null; 18056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 18156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 18256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Intermediate whitespace-only data commands that we may need to remove. 18356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p> 18456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * This list is built up as we visit commands and is either processed when we need to remove 18556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * structural whitespace or cleared if we encounter situations that prohibit whitespace removal. 18656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 18756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private List<ADataCommand> whitespaceData = new ArrayList<ADataCommand>(); 18856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 18956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static boolean isInlineWhitespace(String text) { 19056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return INLINE_WHITESPACE.matcher(text).matches(); 19156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 19256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 19356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static boolean startsWithNewline(String text) { 19456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return STARTS_WITH_NEWLINE.matcher(text).find(); 19556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 19656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 19756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static boolean endsWithNewline(String text) { 19856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return ENDS_WITH_NEWLINE.matcher(text).find(); 19956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 20056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 20156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 20256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Removes leading whitespace (including first newline) from the given string. The text must start 20356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * with optional whitespace followed by a newline. 20456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 20556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static String stripLeadingWhitespaceAndNewline(String text) { 20656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Matcher matcher = LEADING_WHITESPACE_AND_NEWLINE.matcher(text); 20756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (!matcher.matches()) { 20856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new IllegalStateException("Text '" + text + "' should have leading whitespace/newline."); 20956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 21056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return matcher.group(1); 21156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 21256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 21356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 21456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Removes trailing whitespace (if present) from the given string. 21556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 21656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static String stripTrailingWhitespace(String text) { 21756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Matcher matcher = TRAILING_WHITESPACE.matcher(text); 21856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (!matcher.matches()) { 21956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // The trailing whitespace regex should never fail to match a string. 22056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new AssertionError("Error in regular expression"); 22156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 22256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return matcher.group(1); 22356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 22456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 22556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 22656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Remove whitespace (including first newline) from the start of the given data command (replacing 22756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * it with a Noop command if it becomes empty). Returns a modified data command, or null if all 22856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * text was removed. 22956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p> 23056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * The given command can be null at the beginning of the file or if the original data command was 23156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * entirely consumed by a previous strip operation (remember that data commands can be processed 23256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * twice, at both the start and end of a whitespace sequence). 23356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 23456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static ADataCommand stripLeadingWhitespaceAndNewline(ADataCommand data) { 23556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (data != null) { 23656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String text = stripLeadingWhitespaceAndNewline(data.getData().getText()); 23756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (text.isEmpty()) { 23856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson data.replaceBy(new ANoopCommand()); 23956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Returning null just means we have chomped the whitespace to nothing. 24056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson data = null; 24156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 24256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson data.setData(new TData(text)); 24356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 24456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 24556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return data; 24656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 24756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 24856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 24956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Removes whitespace from the end of the given data command (replacing it with a Noop command if 25056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * it becomes empty). 25156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 25256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static void stripTrailingWhitespace(ADataCommand data) { 25356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (data != null) { 25456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String text = stripTrailingWhitespace(data.getData().getText()); 25556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (text.isEmpty()) { 25656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson data.replaceBy(new ANoopCommand()); 25756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 25856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson data.setData(new TData(text)); 25956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 26056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 26156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 26256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 26356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 26456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Removes all data commands collected while chomping the current line and clears the given list. 26556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 26656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static void removeWhitespace(List<ADataCommand> whitespaceData) { 26756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson for (ADataCommand data : whitespaceData) { 26856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson data.replaceBy(new ANoopCommand()); 26956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 27056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson whitespaceData.clear(); 27156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 27256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 27356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 27456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseStart(Start node) { 27556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Process the hierarchy. 27656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson super.caseStart(node); 27756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // We might end after processing a non-data node, so deal with any 27856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // unprocessed whitespace before we exit. 27956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (maybeChompWhitespace) { 28056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson stripTrailingWhitespace(firstChompedData); 28156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson removeWhitespace(whitespaceData); 28256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson firstChompedData = null; 28356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 28456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Verify we have consumed (and cleared) any object references. 28556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (firstChompedData != null) { 28656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new IllegalStateException("Unexpected first data node."); 28756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 28856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (!whitespaceData.isEmpty()) { 28956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new IllegalStateException("Unexpected data nodes."); 29056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 29156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 29256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 29356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 29456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseADataCommand(ADataCommand data) { 29556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson final String originalText = data.getData().getText(); 29656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (maybeChompWhitespace) { 29756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (isInlineWhitespace(originalText)) { 29856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // This data command is whitespace between two commands on the same 29956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // line, simply chomp it and continue ("Om-nom-nom"). 30056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson whitespaceData.add(data); 30156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 30256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 30356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (startsWithNewline(originalText)) { 30456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // This data command is at the end of a line that contains only 30556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // structural commands and whitespace. We remove all whitespace 30656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // associated with this line by: 30756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // * Stripping whitespace from the end of the data command at the start 30856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // of this line. 30956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // * Removing all intermediate (whitespace only) data commands. 31056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // * Stripping whitespace from the start of the current data command. 31156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson stripTrailingWhitespace(firstChompedData); 31256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson removeWhitespace(whitespaceData); 31356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson data = stripLeadingWhitespaceAndNewline(data); 31456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson currentLineContainsInlineComplexCommand = false; 31556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 31656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // This data command contains some non-whitespace text so we must abort 31756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // the chomping of this line and output it normally. 31856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson abortWhitespaceChompingForCurrentLine(); 31956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 32056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 32156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Test to see if we should start chomping on the next line. 32256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson maybeChompWhitespace = endsWithNewline(originalText); 32356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Note that data can be null here if we stripped all the whitespace from 32456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // it (which means that firstChompedData can be null next time around). 32556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson firstChompedData = maybeChompWhitespace ? data : null; 32656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 32756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 32856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 32956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Helper method to abort whitespace processing for the current line. This method is idempotent on 33056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * a per line basis, and once it has been called the state is only reset at the start of the next 33156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * line. 33256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 33356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void abortWhitespaceChompingForCurrentLine() { 33456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson maybeChompWhitespace = false; 33556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson currentLineContainsInlineComplexCommand = false; 33656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson whitespaceData.clear(); 33756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 33856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 33956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // ---- Inline commands that prohibit whitespace removal. ---- 34056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 34156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 34256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void inAAltCommand(AAltCommand node) { 34356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson abortWhitespaceChompingForCurrentLine(); 34456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 34556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 34656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 34756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void inACallCommand(ACallCommand node) { 34856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson abortWhitespaceChompingForCurrentLine(); 34956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 35056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 35156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 35256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void inAEvarCommand(AEvarCommand node) { 35356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson abortWhitespaceChompingForCurrentLine(); 35456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 35556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 35656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 35756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void inALvarCommand(ALvarCommand node) { 35856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson abortWhitespaceChompingForCurrentLine(); 35956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 36056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 36156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 36256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void inANameCommand(ANameCommand node) { 36356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson abortWhitespaceChompingForCurrentLine(); 36456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 36556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 36656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 36756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void inASetCommand(ASetCommand node) { 36856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson abortWhitespaceChompingForCurrentLine(); 36956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 37056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 37156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 37256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void inAUvarCommand(AUvarCommand node) { 37356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson abortWhitespaceChompingForCurrentLine(); 37456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 37556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 37656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 37756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void inAVarCommand(AVarCommand node) { 37856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson abortWhitespaceChompingForCurrentLine(); 37956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 38056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 38156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // ---- Two part (open/close) commands that can have child commands. ---- 38256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 38356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void enterComplexCommand() { 38456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson currentLineContainsInlineComplexCommand = true; 38556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 38656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 38756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void exitComplexCommand() { 38856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (currentLineContainsInlineComplexCommand) { 38956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson abortWhitespaceChompingForCurrentLine(); 39056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 39156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 39256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 39356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 39456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAAltCommand(AAltCommand node) { 39556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson enterComplexCommand(); 39656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson super.caseAAltCommand(node); 39756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson exitComplexCommand(); 39856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 39956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 40056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 40156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseADefCommand(ADefCommand node) { 40256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson enterComplexCommand(); 40356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson super.caseADefCommand(node); 40456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson exitComplexCommand(); 40556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 40656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 40756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 40856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAEachCommand(AEachCommand node) { 40956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson enterComplexCommand(); 41056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson super.caseAEachCommand(node); 41156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson exitComplexCommand(); 41256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 41356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 41456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 41556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAEscapeCommand(AEscapeCommand node) { 41656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson enterComplexCommand(); 41756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson super.caseAEscapeCommand(node); 41856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson exitComplexCommand(); 41956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 42056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 42156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 42256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAIfCommand(AIfCommand node) { 42356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson enterComplexCommand(); 42456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson super.caseAIfCommand(node); 42556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson exitComplexCommand(); 42656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 42756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 42856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 42956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseALoopCommand(ALoopCommand node) { 43056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson enterComplexCommand(); 43156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson super.caseALoopCommand(node); 43256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson exitComplexCommand(); 43356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 43456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 43556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 43656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseALoopIncCommand(ALoopIncCommand node) { 43756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson enterComplexCommand(); 43856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson super.caseALoopIncCommand(node); 43956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson exitComplexCommand(); 44056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 44156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 44256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 44356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseALoopToCommand(ALoopToCommand node) { 44456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson enterComplexCommand(); 44556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson super.caseALoopToCommand(node); 44656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson exitComplexCommand(); 44756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 44856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 44956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 45056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void caseAWithCommand(AWithCommand node) { 45156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson enterComplexCommand(); 45256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson super.caseAWithCommand(node); 45356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson exitComplexCommand(); 45456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 45556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson} 456