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.data; 1856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 1956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport com.google.clearsilver.jsilver.resourceloader.ResourceLoader; 2056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 2156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.IOException; 2256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.LineNumberReader; 2356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.io.Reader; 2456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.ArrayList; 2556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.Iterator; 2656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonimport java.util.Stack; 2756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 2856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson/** 2956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Parser for HDF based on the following grammar by Brandon Long. 3056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 3156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * COMMAND := (INCLUDE | COMMENT | HDF_SET | HDF_DESCEND | HDF_ASCEND ) INCLUDE := #include 3256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * "FILENAME" EOL COMMENT := # .* EOL HDF_DESCEND := HDF_NAME_ATTRS { EOL HDF_ASCEND := } EOL 3356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * HDF_SET := (HDF_ASSIGN | HDF_MULTILINE_ASSIGN | HDF_COPY | HDF_LINK) HDF_ASSIGN := HDF_NAME_ATTRS 3456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * = .* EOL HDF_MULTILINE_ASSIGN := HDF_NAME_ATTRS << EOM_MARKER EOL (.* EOL)* EOM_MARKER EOL 3556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * HDF_COPY := HDF_NAME_ATTRS := HDF_NAME EOL HDF_LINK := HDF_NAME_ATTRS : HDF_NAME EOL 3656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * HDF_NAME_ATTRS := (HDF_NAME | HDF_NAME [HDF_ATTRS]) HDF_ATTRS := (HDF_ATTR | HDF_ATTR, HDF_ATTRS) 3756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * HDF_ATTR := (HDF_ATTR_KEY | HDF_ATTR_KEY = [^\s,\]]+ | HDF_ATTR_KEY = DQUOTED_STRING) 3856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * HDF_ATTR_KEY := [0-9a-zA-Z]+ DQUOTED_STRING := "([^\\"]|\\[ntr]|\\.)*" HDF_NAME := (HDF_SUB_NAME 3956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * | HDF_SUB_NAME\.HDF_NAME) HDF_SUB_NAME := [0-9a-zA-Z_]+ EOM_MARKER := \S.*\S EOL := \n 4056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 4156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodsonpublic class NewHdfParser implements Parser { 4256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 4356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private final StringInternStrategy internStrategy; 4456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 4556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 4656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Special exception used to detect when we unexpectedly run out of characters on the line. 4756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 4856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static class OutOfCharsException extends Exception {} 4956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 5056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 5156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Object used to hold the name and attributes of an HDF node before we are ready to commit it to 5256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * the Data object. 5356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 5456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static class HdfNameAttrs { 5556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String name; 5656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson ArrayList<String> attrs = null; 5756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int endOfSequence; 5856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 5956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson void reset(String newname) { 6056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // TODO: think about moving interning here instead of parser code 6156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.name = newname; 6256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (attrs != null) { 6356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson attrs.clear(); 6456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 6556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson endOfSequence = 0; 6656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 6756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 6856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson void addAttribute(String key, String value) { 6956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (attrs == null) { 7056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson attrs = new ArrayList<String>(10); 7156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 7256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson attrs.ensureCapacity(attrs.size() + 2); 7356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // TODO: think about moving interning here instead of parser code 7456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson attrs.add(key); 7556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson attrs.add(value); 7656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 7756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 7856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Data toData(Data data) { 7956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Data child = data.createChild(name); 8056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (attrs != null) { 8156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Iterator<String> it = attrs.iterator(); 8256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson while (it.hasNext()) { 8356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String key = it.next(); 8456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String value = it.next(); 8556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson child.setAttribute(key, value); 8656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 8756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 8856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return child; 8956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 9056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 9156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 9256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson static final String UNNAMED_INPUT = "[UNNAMED_INPUT]"; 9356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 9456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 9556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * State information that we pass through the parse methods. Allows parser to be reentrant as all 9656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * the state is passed through method calls. 9756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 9856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson static class ParseState { 9956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson final Stack<Data> context = new Stack<Data>(); 10056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson final Data output; 10156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson final LineNumberReader lineReader; 10256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson final ErrorHandler errorHandler; 10356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson final ResourceLoader resourceLoader; 10456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson final NewHdfParser hdfParser; 10556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson final boolean ignoreAttributes; 10656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson final HdfNameAttrs hdfNameAttrs; 10756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson final UniqueStack<String> includeStack; 10856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson final String parsedFileName; 10956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 11056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String line; 11156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Data currentNode; 11256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 11356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private ParseState(Data output, LineNumberReader lineReader, ErrorHandler errorHandler, 11456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson ResourceLoader resourceLoader, NewHdfParser hdfParser, String parsedFileName, 11556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson boolean ignoreAttributes, HdfNameAttrs hdfNameAttrs, UniqueStack<String> includeStack) { 11656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.lineReader = lineReader; 11756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.errorHandler = errorHandler; 11856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.output = output; 11956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson currentNode = output; 12056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.resourceLoader = resourceLoader; 12156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.hdfParser = hdfParser; 12256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.parsedFileName = parsedFileName; 12356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.ignoreAttributes = ignoreAttributes; 12456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.hdfNameAttrs = hdfNameAttrs; 12556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.includeStack = includeStack; 12656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 12756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 12856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public static ParseState createNewParseState(Data output, Reader reader, 12956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson ErrorHandler errorHandler, ResourceLoader resourceLoader, NewHdfParser hdfParser, 13056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String parsedFileName, boolean ignoreAttributes) { 13156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 13256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (parsedFileName == null) { 13356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson parsedFileName = UNNAMED_INPUT; 13456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 13556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson UniqueStack<String> includeStack = new UniqueStack<String>(); 13656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson includeStack.push(parsedFileName); 13756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 13856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return new ParseState(output, new LineNumberReader(reader), errorHandler, resourceLoader, 13956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson hdfParser, parsedFileName, ignoreAttributes, new HdfNameAttrs(), includeStack); 14056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 14156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 14256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public static ParseState createParseStateForIncludedFile(ParseState originalState, 14356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String includeFileName, Reader includeFileReader) { 14456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return new ParseState(originalState.output, new LineNumberReader(includeFileReader), 14556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson originalState.errorHandler, originalState.resourceLoader, originalState.hdfParser, 14656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson originalState.parsedFileName, originalState.ignoreAttributes, new HdfNameAttrs(), 14756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson originalState.includeStack); 14856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 14956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 15056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 15156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 15256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 15356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Constructor for {@link NewHdfParser}. 15456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 15556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param internPool - {@link StringInternStrategy} instance used to optimize the HDF parsing. 15656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 15756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public NewHdfParser(StringInternStrategy internPool) { 15856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.internStrategy = internPool; 15956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 16056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 16156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static class NewHdfParserFactory implements ParserFactory { 16256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private final StringInternStrategy stringInternStrategy; 16356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 16456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public NewHdfParserFactory(StringInternStrategy stringInternStrategy) { 16556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson this.stringInternStrategy = stringInternStrategy; 16656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 16756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 16856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson @Override 16956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public Parser newInstance() { 17056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return new NewHdfParser(stringInternStrategy); 17156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 17256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 17356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 17456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 17556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Creates a {@link ParserFactory} instance. 17656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 17756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * <p> 17856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Provided {@code stringInternStrategy} instance will be used by shared all {@link Parser} 17956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * objects created by the factory and used to optimize the HDF parsing process by reusing the 18056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * String for keys and values. 18156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 18256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param stringInternStrategy - {@link StringInternStrategy} instance used to optimize the HDF 18356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * parsing. 18456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @return an instance of {@link ParserFactory} implementation. 18556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 18656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public static ParserFactory newFactory(StringInternStrategy stringInternStrategy) { 18756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return new NewHdfParserFactory(stringInternStrategy); 18856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 18956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 19056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson public void parse(Reader reader, Data output, Parser.ErrorHandler errorHandler, 19156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson ResourceLoader resourceLoader, String dataFileName, boolean ignoreAttributes) 19256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throws IOException { 19356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 19456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson parse(ParseState.createNewParseState(output, reader, errorHandler, resourceLoader, this, 19556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson dataFileName, ignoreAttributes)); 19656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 19756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 19856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void parse(ParseState state) throws IOException { 19956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson while ((state.line = state.lineReader.readLine()) != null) { 20056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String seq = stripWhitespace(state.line); 20156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson try { 20256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson parseCommand(seq, state); 20356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } catch (OutOfCharsException e) { 20456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "End of line was prematurely reached. Parse error."); 20556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 20656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 20756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 20856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 20956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static final String INCLUDE_WS = "#include "; 21056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 21156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void parseCommand(String seq, ParseState state) throws IOException, OutOfCharsException { 21256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (seq.length() == 0) { 21356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Empty line. 21456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 21556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 21656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (charAt(seq, 0) == '#') { 21756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // If there isn't a match on include then this is a comment and we do nothing. 21856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (matches(seq, 0, INCLUDE_WS)) { 21956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // This is an include command 22056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int start = skipLeadingWhitespace(seq, INCLUDE_WS.length()); 22156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson parseInclude(seq, start, state); 22256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 22356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 22456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else if (charAt(seq, 0) == '}') { 22556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (skipLeadingWhitespace(seq, 1) != seq.length()) { 22656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "Extra chars after '}'"); 22756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 22856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 22956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson handleAscend(state); 23056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 23156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson parseHdfElement(seq, state); 23256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 23356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 23456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 23556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void parseInclude(String seq, int start, ParseState state) throws IOException, 23656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson OutOfCharsException { 23756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int end = seq.length(); 23856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (charAt(seq, start) == '"') { 23956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (charAt(seq, end - 1) == '"') { 24056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson start++; 24156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson end--; 24256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 24356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "Missing '\"' at end of include"); 24456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 24556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 24656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 24756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson handleInclude(seq.substring(start, end), state); 24856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 24956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 25056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static final int NO_MATCH = -1; 25156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 25256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void parseHdfElement(String seq, ParseState state) throws IOException, 25356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson OutOfCharsException { 25456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Re-use a single element to avoid repeated allocations/trashing (serious 25556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // performance impact, 5% of real service performance) 25656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson HdfNameAttrs element = state.hdfNameAttrs; 25756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (!parseHdfNameAttrs(element, seq, 0, state)) { 25856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 25956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 26056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int index = skipLeadingWhitespace(seq, element.endOfSequence); 26156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson switch (charAt(seq, index)) { 26256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson case '{': 26356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Descend 26456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (index + 1 != seq.length()) { 26556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "No characters expected after '{'"); 26656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 26756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 26856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson handleDescend(state, element); 26956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 27056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson case '=': 27156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Assignment 27256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index = skipLeadingWhitespace(seq, index + 1); 27356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String value = internStrategy.intern(seq.substring(index, seq.length())); 27456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson handleAssign(state, element, value); 27556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 27656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson case ':': 27756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (charAt(seq, index + 1) == '=') { 27856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Copy 27956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index = skipLeadingWhitespace(seq, index + 2); 28056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String src = parseHdfName(seq, index); 28156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (src == null) { 28256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "Invalid HDF name"); 28356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 28456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 28556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (index + src.length() != seq.length()) { 28656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "No characters expected after '{'"); 28756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 28856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 28956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson handleCopy(state, element, src); 29056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 29156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Link 29256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index = skipLeadingWhitespace(seq, index + 1); 29356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String src = parseHdfName(seq, index); 29456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (src == null) { 29556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "Invalid HDF name"); 29656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 29756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 29856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (index + src.length() != seq.length()) { 29956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "No characters expected after '{'"); 30056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 30156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 30256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson handleLink(state, element, src); 30356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 30456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 30556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson case '<': 30656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (charAt(seq, index + 1) != '<') { 30756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "Expected '<<'"); 30856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 30956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index = skipLeadingWhitespace(seq, index + 2); 31056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String eomMarker = seq.substring(index, seq.length()); 31156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // TODO: think about moving interning to handleAssign() 31256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String multilineValue = internStrategy.intern(parseMultilineValue(state, eomMarker)); 31356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (multilineValue == null) { 31456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 31556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 31656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson handleAssign(state, element, multilineValue); 31756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 31856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson default: 31956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "No valid operator"); 32056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 32156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 32256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 32356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 32456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 32556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * This method parses out an HDF element name and any optional attributes into a caller-supplied 32656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * HdfNameAttrs object. It returns a {@code boolean} with whether it succeeded to parse. 32756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 32856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private boolean parseHdfNameAttrs(HdfNameAttrs destination, String seq, int index, 32956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson ParseState state) throws OutOfCharsException { 33056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String hdfName = parseHdfName(seq, index); 33156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (hdfName == null) { 33256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "Invalid HDF name"); 33356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return false; 33456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 33556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson destination.reset(hdfName); 33656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index = skipLeadingWhitespace(seq, index + hdfName.length()); 33756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int end = parseAttributes(seq, index, state, destination); 33856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (end == NO_MATCH) { 33956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Error already reported below. 34056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return false; 34156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 34256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson destination.endOfSequence = end; 34356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return true; 34456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 34556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 34656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 34756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 34856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Parses a valid hdf path name. 34956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 35056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private String parseHdfName(String seq, int index) throws OutOfCharsException { 35156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int end = index; 35256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson while (end < seq.length() && isHdfNameChar(charAt(seq, end))) { 35356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson end++; 35456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 35556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (end == index) { 35656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return null; 35756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 35856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return internStrategy.intern(seq.substring(index, end)); 35956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 36056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 36156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 36256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Looks for optional attributes and adds them to the HdfNameAttrs object passed into the method. 36356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 36456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private int parseAttributes(String seq, int index, ParseState state, HdfNameAttrs element) 36556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throws OutOfCharsException { 36656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (charAt(seq, index) != '[') { 36756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // No attributes to parse 36856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return index; 36956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 37056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index = skipLeadingWhitespace(seq, index + 1); 37156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 37256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // If we don't care about attributes, just skip over them. 37356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (state.ignoreAttributes) { 37456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson while (charAt(seq, index) != ']') { 37556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index++; 37656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 37756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return index + 1; 37856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 37956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 38056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson boolean first = true; 38156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson do { 38256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (first) { 38356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson first = false; 38456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else if (charAt(seq, index) == ',') { 38556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index = skipLeadingWhitespace(seq, index + 1); 38656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 38756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "Error parsing attribute list"); 38856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 38956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index = parseAttribute(seq, index, state, element); 39056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (index == NO_MATCH) { 39156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // reportError called by parseAttribute already. 39256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return NO_MATCH; 39356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 39456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index = skipLeadingWhitespace(seq, index); 39556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } while (charAt(seq, index) != ']'); 39656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return index + 1; 39756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 39856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 39956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static final String DEFAULT_ATTR_VALUE = "1"; 40056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 40156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 40256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Parse out a single HDF attribute. If there is no explicit value, use default value of "1" like 40356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * in C clearsilver. Returns NO_MATCH if it fails to parse an attribute. 40456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 40556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private int parseAttribute(String seq, int index, ParseState state, HdfNameAttrs element) 40656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throws OutOfCharsException { 40756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int end = parseAttributeKey(seq, index); 40856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (index == end) { 40956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "No valid attribute key"); 41056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return NO_MATCH; 41156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 41256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String attrKey = internStrategy.intern(seq.substring(index, end)); 41356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index = skipLeadingWhitespace(seq, end); 41456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (charAt(seq, index) != '=') { 41556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // No value for this attribute key. Use default value of "1" 41656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson element.addAttribute(attrKey, DEFAULT_ATTR_VALUE); 41756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return index; 41856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 41956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // We need to parse out the attribute value. 42056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index = skipLeadingWhitespace(seq, index + 1); 42156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (charAt(seq, index) == '"') { 42256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index++; 42356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson StringBuilder sb = new StringBuilder(); 42456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson end = parseQuotedAttributeValue(seq, index, sb); 42556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (end == NO_MATCH) { 42656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "Unable to parse quoted attribute value"); 42756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return NO_MATCH; 42856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 42956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String attrValue = internStrategy.intern(sb.toString()); 43056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson element.addAttribute(attrKey, attrValue); 43156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson end++; 43256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 43356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Simple attribute that has no whitespace. 43456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String attrValue = parseAttributeValue(seq, index, state); 43556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (attrValue == null || attrValue.length() == 0) { 43656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "No attribute for key " + attrKey); 43756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return NO_MATCH; 43856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 43956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 44056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson attrValue = internStrategy.intern(attrValue); 44156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson element.addAttribute(attrKey, attrValue); 44256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson end = index + attrValue.length(); 44356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 44456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return end; 44556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 44656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 44756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 44856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Returns the range in the sequence starting at start that corresponds to a valid attribute key. 44956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 45056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private int parseAttributeKey(String seq, int index) throws OutOfCharsException { 45156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson while (isAlphaNumericChar(charAt(seq, index))) { 45256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index++; 45356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 45456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return index; 45556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 45656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 45756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 45856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Parses a quoted attribute value. Unescapes octal characters and \n, \r, \t, \", etc. 45956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 46056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private int parseQuotedAttributeValue(String seq, int index, StringBuilder sb) 46156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throws OutOfCharsException { 46256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson char c; 46356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson while ((c = charAt(seq, index)) != '"') { 46456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (c == '\\') { 46556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Escaped character. Look for 1 to 3 digits in a row as octal or n,t,r. 46656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index++; 46756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson char next = charAt(seq, index); 46856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (isNumericChar(next)) { 46956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Parse the next 1 to 3 characters if they are digits. Treat it as an octal code. 47056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int val = next - '0'; 47156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (isNumericChar(charAt(seq, index + 1))) { 47256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index++; 47356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson val = val * 8 + (charAt(seq, index) - '0'); 47456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (isNumericChar(charAt(seq, index + 1))) { 47556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index++; 47656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson val = val * 8 + (charAt(seq, index) - '0'); 47756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 47856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 47956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson c = (char) val; 48056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else if (next == 'n') { 48156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson c = '\n'; 48256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else if (next == 't') { 48356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson c = '\t'; 48456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else if (next == 'r') { 48556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson c = '\r'; 48656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 48756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Regular escaped char like " or / 48856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson c = next; 48956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 49056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 49156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson sb.append(c); 49256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index++; 49356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 49456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return index; 49556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 49656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 49756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 49856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Parses a simple attribute value that cannot have any whitespace or specific punctuation 49956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * reserved by the HDF grammar. 50056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 50156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private String parseAttributeValue(String seq, int index, ParseState state) 50256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throws OutOfCharsException { 50356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int end = index; 50456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson char c = charAt(seq, end); 50556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson while (c != ',' && c != ']' && c != '"' && !Character.isWhitespace(c)) { 50656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson end++; 50756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson c = charAt(seq, end); 50856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 50956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return seq.substring(index, end); 51056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 51156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 51256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private String parseMultilineValue(ParseState state, String eomMarker) throws IOException { 51356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson StringBuilder sb = new StringBuilder(256); 51456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String line; 51556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson while ((line = state.lineReader.readLine()) != null) { 51656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (line.startsWith(eomMarker) 51756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson && skipLeadingWhitespace(line, eomMarker.length()) == line.length()) { 51856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return sb.toString(); 51956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 52056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson sb.append(line).append('\n'); 52156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 52256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 52356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "EOM " + eomMarker + " never found"); 52456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return null; 52556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 52656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 52756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // ////////////////////////////////////////////////////////////////////////// 52856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // 52956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Handlers 53056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 53156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void handleDescend(ParseState state, HdfNameAttrs element) { 53256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Data child = handleNodeCreation(state.currentNode, element); 53356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson state.context.push(state.currentNode); 53456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson state.currentNode = child; 53556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 53656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 53756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private Data handleNodeCreation(Data node, HdfNameAttrs element) { 53856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return element.toData(node); 53956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 54056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 54156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void handleAssign(ParseState state, HdfNameAttrs element, String value) { 54256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // TODO: think about moving interning here 54356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Data child = handleNodeCreation(state.currentNode, element); 54456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson child.setValue(value); 54556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 54656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 54756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void handleCopy(ParseState state, HdfNameAttrs element, String srcName) { 54856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Data child = handleNodeCreation(state.currentNode, element); 54956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Data src = state.output.getChild(srcName); 55056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (src != null) { 55156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson child.setValue(src.getValue()); 55256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 55356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson child.setValue(""); 55456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 55556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 55656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 55756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void handleLink(ParseState state, HdfNameAttrs element, String srcName) { 55856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Data child = handleNodeCreation(state.currentNode, element); 55956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson child.setSymlink(state.output.createChild(srcName)); 56056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 56156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 56256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void handleAscend(ParseState state) { 56356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (state.context.isEmpty()) { 56456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "Too many '}'"); 56556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 56656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 56756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson state.currentNode = state.context.pop(); 56856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 56956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 57056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private void handleInclude(String seq, ParseState state) throws IOException { 57156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String includeFileName = internStrategy.intern(seq); 57256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 57356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Load the file 57456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson Reader reader = state.resourceLoader.open(includeFileName); 57556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (reader == null) { 57656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, "Unable to find file " + includeFileName); 57756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 57856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 57956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 58056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Check whether we are in include loop 58156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (!state.includeStack.push(includeFileName)) { 58256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson reportError(state, createIncludeStackTraceMessage(state.includeStack, includeFileName)); 58356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return; 58456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 58556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 58656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Parse the file 58756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson state.hdfParser.parse(ParseState 58856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson .createParseStateForIncludedFile(state, includeFileName, reader)); 58956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 59056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (!includeFileName.equals(state.includeStack.pop())) { 59156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Include stack trace is corrupted 59256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new IllegalStateException("Unable to find on include stack: " + includeFileName); 59356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 59456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 59556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 59656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private String createIncludeStackTraceMessage(UniqueStack<String> includeStack, 59756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson String includeFileName) { 59856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson StringBuilder message = new StringBuilder(); 59956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append("File included twice: "); 60056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append(includeFileName); 60156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 60256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append(" Include stack: "); 60356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson for (String fileName : includeStack) { 60456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append(fileName); 60556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append(" -> "); 60656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 60756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson message.append(includeFileName); 60856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return message.toString(); 60956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 61056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 61156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // ///////////////////////////////////////////////////////////////////////// 61256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // 61356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson // Character values 61456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 61556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static boolean isNumericChar(char c) { 61656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if ('0' <= c && c <= '9') { 61756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return true; 61856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 61956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return false; 62056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 62156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 62256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 62356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static boolean isAlphaNumericChar(char c) { 62456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9')) { 62556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return true; 62656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 62756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return false; 62856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 62956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 63056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 63156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static boolean isHdfNameChar(char c) { 63256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (isAlphaNumericChar(c) || c == '_' || c == '.') { 63356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return true; 63456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 63556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return false; 63656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 63756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 63856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 63956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static String stripWhitespace(String seq) { 64056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int start = skipLeadingWhitespace(seq, 0); 64156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson int end = seq.length() - 1; 64256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson while (end > start && Character.isWhitespace(seq.charAt(end))) { 64356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson --end; 64456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 64556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (start == 0 && end == seq.length() - 1) { 64656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return seq; 64756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 64856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return seq.substring(start, end + 1); 64956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 65056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 65156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 65256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static int skipLeadingWhitespace(String seq, int index) { 65356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson while (index < seq.length() && Character.isWhitespace(seq.charAt(index))) { 65456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson index++; 65556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 65656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return index; 65756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 65856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 65956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 66056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Determines if a character sequence appears in the given sequence starting at a specified index. 66156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * 66256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param seq the sequence that we want to see if it contains the string match. 66356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param start the index into seq where we want to check for match 66456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @param match the String we want to look for in the sequence. 66556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * @return {@code true} if the string match appears in seq starting at the index start, {@code 66656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * false} otherwise. 66756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 66856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static boolean matches(String seq, int start, String match) { 66956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (seq.length() - start < match.length()) { 67056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return false; 67156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 67256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson for (int i = 0; i < match.length(); i++) { 67356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (match.charAt(i) != seq.charAt(start + i)) { 67456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return false; 67556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 67656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 67756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return true; 67856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 67956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 68056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson /** 68156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * Reads the character at the specified index in the given String. Throws an exception to be 68256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson * caught above if the index is out of range. 68356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson */ 68456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static char charAt(String seq, int index) throws OutOfCharsException { 68556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (0 <= index && index < seq.length()) { 68656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson return seq.charAt(index); 68756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 68856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new OutOfCharsException(); 68956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 69056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 69156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 69256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson 69356ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson private static void reportError(ParseState state, String errorMessage) { 69456ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson if (state.errorHandler != null) { 69556ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson state.errorHandler.error(state.lineReader.getLineNumber(), state.line, state.parsedFileName, 69656ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson errorMessage); 69756ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } else { 69856ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson throw new RuntimeException("Parse Error on line " + state.lineReader.getLineNumber() + ": " 69956ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson + errorMessage + " : " + state.line); 70056ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 70156ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson } 70256ed4167b942ec265f9cee70ac4d71d10b3835ceBen Dodson} 703