All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jamon.parser.AbstractParser Maven / Gradle / Ivy

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
package org.jamon.parser;

import java.io.IOException;

import org.jamon.api.Location;
import org.jamon.compiler.ParserErrorImpl;
import org.jamon.compiler.ParserErrorsImpl;
import org.jamon.node.AbstractPathNode;

/**
 * @author ian
 **/
public class AbstractParser {
  public static final String MALFORMED_TAG_ERROR = "Malformed tag";
  public static final String EOF_IN_JAVA_QUOTE_ERROR = "Reached end of file while inside a java quote";
  public static final String NOT_AN_IDENTIFIER_ERROR = "identifier exepected";
  public static final String BAD_JAVA_TYPE_SPECIFIER = "Bad java type specifier";
  public static final String BAD_ARGS_CLOSE_TAG = "malformed  tag";
  public static final String INCOMPLETE_ARRAY_SPECIFIER_ERROR = "Expecting ']'";

  public AbstractParser(PositionalPushbackReader reader, ParserErrorsImpl errors) {
    this.reader = reader;
    this.errors = errors;
  }

  /**
   * Soak up all whitespace from the reader until non-whitespace or EOF is encountered.
   *
   * @return Whether or not any whitespace was encountered
   **/
  protected boolean soakWhitespace() throws IOException {
    int c;
    boolean whitespaceSeen = false;
    while ((c = reader.read()) >= 0 && Character.isWhitespace((char) c)) {
      whitespaceSeen = true;
    }
    reader.unread(c);
    return whitespaceSeen;
  }

  protected void addError(Location location, String message) {
    errors.addError(new ParserErrorImpl(location, message));
  }

  protected void addError(ParserErrorImpl error) {
    errors.addError(error);
  }

  protected static class NotAnIdentifierException extends Exception {

    private static final long serialVersionUID = 2006091701L;

  }

  /**
   * Reads in a java identifier.
   *
   * @return The identifier read.
   * @throws IOException
   * @throws NotAnIdentifierException if no identifier is found
   */
  protected String readIdentifierOrThrow() throws IOException, NotAnIdentifierException {
    int c;
    StringBuilder builder = new StringBuilder();
    if ((c = reader.read()) <= 0 || !Character.isJavaIdentifierStart((char) c)) {
      reader.unread(c);
      throw new NotAnIdentifierException();
    }
    else {
      builder.append((char) c);
    }

    while ((c = reader.read()) >= 0 && Character.isJavaIdentifierPart((char) c)) {
      builder.append((char) c);
    }
    reader.unread(c);
    return builder.toString();
  }

  /**
   * Read in a java identifier.
   *
   * @param addErrorIfNoneFound if true, and no identifier is found, then call
   *          {@link #addError(ParserErrorImpl)}
   * @return the identifier read, or the empty string if no identifier was found.
   * @throws IOException
   */
  protected String readIdentifier(boolean addErrorIfNoneFound) throws IOException {
    try {
      return readIdentifierOrThrow();
    }
    catch (NotAnIdentifierException e) {
      if (addErrorIfNoneFound) {
        addError(reader.getNextLocation(), NOT_AN_IDENTIFIER_ERROR);
      }
      return "";
    }
  }

  protected final PositionalPushbackReader reader;
  protected final ParserErrorsImpl errors;

  /**
   * Read a single character from the reader. If it is the expected character, return true;
   * otherwise, unread it and return false
   *
   * @param chararacter The expected character.
   * @return True if the character read was that expected.
   * @throws IOException
   */
  protected boolean readChar(char chararacter) throws IOException {
    int c;
    if ((c = reader.read()) == chararacter) {
      return true;
    }
    else {
      reader.unread(c);
      return false;
    }
  }

  /**
   * Read from the reader until encountering an end marker
   *
   * @param end The end marker for the string
   * @param startLocation The location marking the start of the block being read - only used for
   *          construcing error messages.
   **/
  protected String readUntil(String end, Location startLocation) throws IOException {
    StringBuilder buffer = new StringBuilder();
    int charsSeen = 0;
    int c = -1;
    while (charsSeen < end.length() && (c = reader.read()) >= 0) {
      if (end.charAt(charsSeen) == c) {
        charsSeen++;
      }
      else if (charsSeen > 0) {
        buffer.append(end.substring(0, charsSeen));
        charsSeen = 0;
        reader.unread(c);
      }
      else {
        buffer.append((char) c);
      }
    }
    if (c < 0) {
      addError(startLocation, eofErrorMessage(end));
    }
    return buffer.toString();
  }

  public static String eofErrorMessage(String end) {
    return "Reached end of file while looking for '" + end + "'";
  }

  protected String readJava(Location startLocation, TagEndDetector tagEndDetector) throws IOException,
    ParserErrorImpl {
    StringBuilder buffer = new StringBuilder();
    int c = -1;
    boolean inString = false;
    boolean inChar = false;
    Location quoteStart = null;
    while ((c = reader.read()) >= 0) {
      switch (c) {
        case '"':
          inString = !inChar && !inString;
          if (inString) {
            quoteStart = reader.getLocation();
            tagEndDetector.resetEndMatch();
          }
          else {
            quoteStart = null;
          }
          break;
        case '\'':
          inChar = !inString && !inChar;
          if (inChar) {
            quoteStart = reader.getLocation();
            tagEndDetector.resetEndMatch();
          }
          else {
            quoteStart = null;
          }
          break;
        case '\\':
          if (inString || inChar) {
            buffer.append((char) c);
            if ((c = reader.read()) < 0) {
              reader.unread(c);
              // pick up the EOF the next time
            }
          }
          break;
      }
      buffer.append((char) c);
      int endTokenLength;
      if (!(inString || inChar) && (endTokenLength = tagEndDetector.checkEnd((char) c)) > 0) {
        buffer.delete(buffer.length() - endTokenLength, buffer.length());
        return buffer.toString();
      }
    }
    if (quoteStart != null) {
      throw new ParserErrorImpl(quoteStart, EOF_IN_JAVA_QUOTE_ERROR);
    }
    else {
      throw tagEndDetector.getEofError(startLocation);
    }
  }

  protected boolean checkForTagClosure(Location tagLocation) throws IOException {
    if (readChar('>')) {
      return true;
    }
    else {
      addError(tagLocation, MALFORMED_TAG_ERROR);
      return false;
    }
  }

  /**
   * @param token The token or token fragment we expect to see
   * @return True if we see that token or token fragment
   **/
  protected boolean checkToken(String token) throws IOException {
    for (int i = 0; i < token.length(); i++) {
      if (!readChar(token.charAt(i))) {
        return false;
      }
    }
    return true;
  }

  protected String readType(final Location location) throws IOException {
    try {
      return new TypeNameParser(location, reader, errors).getType();
    }
    catch (ParserErrorImpl e) {
      addError(e);
      return "";
    }
  }

  protected String readClassName(final Location p_location) throws IOException {
    try {
      return new ClassNameParser(p_location, reader, errors).getType();
    }
    catch (ParserErrorImpl e) {
      addError(e);
      return "";
    }
  }

  protected AbstractPathNode parsePath() throws IOException {
    return new PathParser(reader, errors).getPathNode();
  }

  /**
   * Determine if the next character is a particular one, and if so, read and append it to a
   * StringBuilder. Otherwise, do nothing.
   *
   * @param p_char The character being looked for
   * @param builder The StringBuilder
   * @return true if the character matched and was appended.
   * @throws IOException
   */
  protected boolean readAndAppendChar(char p_char, StringBuilder builder) throws IOException {
    if (readChar(p_char)) {
      builder.append(p_char);
      return true;
    }
    else {
      return false;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy