/plugins/JavaSideKick/tags/javasidekick-2-7-0/src/sidekick/property/parser/property/PropertyParser.jj
# · Unknown · 302 lines · 256 code · 46 blank · 0 comment · 0 complexity · 54b8ebd8373da531361e3df1db72ad42 MD5 · raw file
- /*
- Copyright (c) 2006, Dale Anson
- All rights reserved.
- Redistribution and use in source and binary forms, with or without modification,
- are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of the <ORGANIZATION> nor the names of its contributors
- may be used to endorse or promote products derived from this software without
- specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- /*
- Simple parser to read Java property files. See Sun's javadoc for
- java.util.Properties.load() for the specification of a property file,
- that's what I used as the rules for this parser.
- */
- options {
- JAVA_UNICODE_ESCAPE = true;
- STATIC = false;
- }
- PARSER_BEGIN(PropertyParser)
- package sidekick.property.parser.property;
- import java.util.*;
- import sidekick.util.Location;
- public class PropertyParser {
- // accumulates parse exceptions
- private List<ParseException> exceptions = new ArrayList<ParseException>();
- // for testing...
- public static void main(String args[]) throws ParseException {
- PropertyParser parser = new PropertyParser(System.in);
- parser.Properties();
- }
- /**
- * Utility to trim horizontal whitespace from the front of a string.
- * @param the string to trim
- * @return the trimmed string
- */
- public String trimFront(String s) {
- if (s == null || s.length() == 0) {
- return s;
- }
- int index = 0;
- for (int i = 0; i < s.length(); i++) {
- if (s.charAt(i) == ' ' || s.charAt(i) == '\t')
- ++index;
- else
- break;
- }
- return s.substring(index);
- }
- /**
- * Setting the tab size makes the token locations more accurate.
- * @param size the size of the tabs in the current jEdit buffer
- */
- public void setTabSize(int size) {
- jj_input_stream.setTabSize(size);
- }
- /**
- * @return the current tab size that the parser is using
- */
- public int getTabSize() {
- return jj_input_stream.getTabSize(0);
- }
- /**
- * Creates a start location from the given token.
- * @param t a token
- * @return the start location of the token.
- */
- public Location createStartLocation(Token t) {
- if (t == null)
- return new Location(0, 0);
- return new Location(t.beginLine, t.beginColumn);
- }
- /**
- * Creates an end location from the given token.
- * @param t a token
- * @return the end location of the token.
- */
- public Location createEndLocation(Token t) {
- if (t == null)
- return new Location(0, 0);
- return new Location(t.endLine, t.endColumn);
- }
- /**
- * Add an exception to the list of exceptions. Rather than failing on
- * any exception, this parser will continue parsing and will accumulate
- * any/all exceptions.
- * @param pe a ParseException to accumulate
- */
- public void addException(ParseException pe) {
- if (pe != null)
- exceptions.add(pe);
- }
- /**
- * @return the list of accumulated ParseExceptions
- */
- public List<ParseException> getExceptions() {
- return exceptions;
- }
- }
- PARSER_END(PropertyParser)
- /* skip blank lines and continuation characters */
- SKIP:
- {
- <NEWLINE: (["\r", "\n"])+ >
- |
- <BLANK_LINE: ([" ", "\t"])+(<NEWLINE>) >
- |
- <CONTINUATION: ("\\")(<NEWLINE>) >
- }
- <DEFAULT> TOKEN :
- {
- /* comments are single line only. They start with # or ! as the first non-
- whitespace character and extend to the end of the line. Comments cannot
- go at the end of a key/value line -- they will be treated as part of the
- value, NOT as a comment! */
- <COMMENT: ([" ", "\t"])*("#" | "!")(~["\r", "\n"])*("\n"|"\r"|"\r\n")? > : DEFAULT
- |
- /* a key with no value is assumed to have an empty value */
- <BARE_KEY: (([" ", "\t"])*((("\\") ( ":" | "=" | " " | "\t" | "#")) | (~[" ", "\t", "=", ":", "#"]))+ (<NEWLINE>)) > : DEFAULT
- |
- /* a key actually starts with the first non-whitespace character on a line and
- extends through the last character before the first horizontal whitespace
- character or : or =. This means that a key cannot contain any whitespace
- characters. Note that a key can have escaped space and tab and : and = as
- part of the key name. */
- <KEY: ([" ", "\t"])*((("\\") ( ":" | "=" | " " | "\t" | "#")) | (~[" ", "\t", "=", ":", "#"]))+ > : ParseEquals
- |
- <OTHER: ~[] >
- }
- <ParseEquals> TOKEN :
- {
- /* the equals may be horizontal whitespace or = or :. There can be horizontal
- whitespace before and after the = and :. I'm not worrying about the
- trailing whitespace here, that gets captured by the VALUE regex and is
- trimmed in the bnf production below. */
- <EQUALS: ([" ", "\t"])*("=") | ([" ", "\t"])*(":") | ([" ", "\t"])+ > : ParseValue
- }
- <ParseValue> TOKEN:
- {
- /* the value actually starts with the first non-horizontal whitespace character
- following the EQUALS, but this regex will also capture the horizontal whitespace
- following the EQUALS. This whitespace is trimmed in the bnf production below.
- The value can span several lines if the continuation character is the last
- character on the line. This needs work -- the value can have escaped \
- characters, and I'm not checking if that's the case. For example, if a line
- ends in \\, then it's an escaped \, not a continuation character, and should
- be part of the value. I think this is a rare use case, so I'm not going
- to worry about it until someone complains. */
- <VALUE: ((~["\r", "\n"])*(<CONTINUATION>)*)+(<NEWLINE>)? > : DEFAULT
- }
- List<Property> Properties() :
- {
- List<Property> list = new ArrayList<Property>();
- Property p = null;
- }
- {
- /* Property files are simple, there are either comments or properties,
- there is nothing else. */
- (
- LOOKAHEAD(2)
- (
- Comment()
- )
- |
- (
- p = Property()
- {
- if (p != null)
- list.add(p);
- }
- )
- )*
- <EOF>
- {
- /* always sort the list by property name -- could make the caller do
- this and just return the properties in the original order */
- Collections.sort(list);
- return list;
- }
- }
- /**
- * @return a single property from the property file.
- */
- Property Property() :
- {
- Token key = null;
- Token value = null;
- }
- {
- try {
- (
- LOOKAHEAD(2)
- (
- key=<KEY>
- {
- token_source.SwitchTo(ParseEquals);
- }
- <EQUALS>
- {
- token_source.SwitchTo(ParseValue);
- }
- value=<VALUE>
- )
- |
- (
- key=<BARE_KEY>
- {
- token_source.SwitchTo(DEFAULT);
- }
- )
- )
- {
- Property prop = new Property();
- prop.setStartLocation(createStartLocation(key));
- prop.setEndLocation(createEndLocation(value == null ? key : value));
- /* key -- need to trim as the regex production can capture whitespace,
- and by definition, the key cannot contain any whitespace characters */
- String out = key.image.trim();
- /* key can have escaped 'equals' characters, unescape them */
- out = out.replaceAll("\\\\=", "=");
- out = out.replaceAll("\\\\:", ":");
- out = out.replaceAll("\\\\ ", " ");
- out = out.replaceAll("\\\\\\t", "\t");
- prop.setKey(out);
- /* value -- need to combine multi-line values into a single line. Leading
- whitespace on continuation lines is discarded, as is leading whitespace
- at the start of the value. */
- out = value == null ? "" : value.image.replaceAll("\\\\(\\s)+", "");
- out = trimFront(out);
- prop.setValue(out);
- return prop;
- }
- } catch (ParseException e) {
- addException(generateParseException());
- }
- }
- /* For completeness only. This parser does nothing special with comments. */
- void Comment() :
- {}
- {
- <COMMENT>
- }