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

org.jamon.parser.TopLevelParser 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 java.io.Reader;

import org.jamon.api.Location;
import org.jamon.api.TemplateLocation;
import org.jamon.codegen.AnnotationType;
import org.jamon.compiler.ParserErrorImpl;
import org.jamon.compiler.ParserErrorsImpl;
import org.jamon.node.AbsMethodNode;
import org.jamon.node.AbstractPathNode;
import org.jamon.node.AliasDefNode;
import org.jamon.node.AliasesNode;
import org.jamon.node.AnnotationNode;
import org.jamon.node.ClassNode;
import org.jamon.node.EscapeDirectiveNode;
import org.jamon.node.ExtendsNode;
import org.jamon.node.ImplementNode;
import org.jamon.node.ImplementsNode;
import org.jamon.node.ReplaceableNode;
import org.jamon.node.ReplacesNode;
import org.jamon.node.ImportsNode;
import org.jamon.node.LocationImpl;
import org.jamon.node.ParentMarkerNode;
import org.jamon.node.TopNode;

public class TopLevelParser extends AbstractBodyParser {
  public static final String BAD_ABSMETH_CONTENT =
    "<%absmeth> sections can only contain <%args> and <%frag> blocks";
  public static final String EXPECTING_SEMI = "Expecting ';'";
  public static final String EXPECTING_ARROW = "Expecting '=' or '=>'";
  public static final String MALFORMED_EXTENDS_TAG_ERROR = "Malformed <%extends ...> tag";
  public static final String MALFORMED_REPLACES_TAG_ERROR = "Malformed <%replaces ...> tag";
  public static final String MALFORMED_ANNOTATE_TAG_ERROR = "Malformed <%annotate...> tag";
  public static final String UNRECOGNIZED_ANNOTATION_TYPE_ERROR = "Unrecognized annotation type";
  private static final String BAD_ALIASES_CLOSE_TAG = "Malformed  tag";
  private static final String BAD_ABS_METHOD_CLOSE_TAG = "Malformed  tag";
  public static final String EXPECTING_IMPLEMENTS_CLOSE = "Expecting class name or ";
  public static final String EXPECTING_IMPORTS_CLOSE = "Expecting import or ";

  public TopLevelParser(TemplateLocation location, Reader reader, String encoding) {
    super(new TopNode(
      new LocationImpl(location, 1, 1), encoding),
      new PositionalPushbackReader(location, reader, 2),
      new ParserErrorsImpl());
  }

  @Override
  public AbstractBodyParser parse() throws IOException {
    super.parse();
    if (errors.hasErrors()) {
      throw errors;
    }
    return this;
  }

  @Override
  protected void handleMethodTag(Location tagLocation) throws IOException {
    if (soakWhitespace()) {
      String name = readIdentifier(true);
      if (checkForTagClosure(tagLocation)) {
        root
            .addSubNode(new MethodParser(name, tagLocation, reader, errors).parse().getRootNode());
      }
    }
    else {
      addError(tagLocation, "malformed <%method methodName> tag");
    }
  }

  @Override
  protected void handleOverrideTag(Location tagLocation) throws IOException {
    if (soakWhitespace()) {
      String name = readIdentifier(true);
      if (checkForTagClosure(tagLocation)) {
        root.addSubNode(
          new OverrideParser(name, tagLocation, reader, errors).parse().getRootNode());
      }
    }
    else {
      addError(tagLocation, "malformed <%override methodName> tag");
    }
  }

  @Override
  protected void handleDefTag(Location tagLocation) throws IOException {
    if (soakWhitespace()) {
      String name = readIdentifier(true);
      if (checkForTagClosure(tagLocation)) {
        root.addSubNode(new DefParser(name, tagLocation, reader, errors).parse().getRootNode());
      }
    }
    else {
      addError(tagLocation, "malformed <%def defName> tag");
    }
  }

  @Override
  protected void handleClassTag(Location tagLocation) throws IOException {
    if (checkForTagClosure(tagLocation)) {
      root.addSubNode(new ClassNode(tagLocation, readUntil("", tagLocation)));
      soakWhitespace();
    }
  }

  @Override
  protected void handleExtendsTag(Location tagLocation) throws IOException {
    if (soakWhitespace()) {
      root.addSubNode(new ExtendsNode(tagLocation, parsePath()));
      soakWhitespace();
      checkForTagClosure(reader.getLocation());
      soakWhitespace();
    }
    else {
      addError(tagLocation, MALFORMED_EXTENDS_TAG_ERROR);
    }
  }

  @Override
  protected void handleReplacesTag(Location tagLocation) throws IOException {
    if (soakWhitespace()) {
      root.addSubNode(new ReplacesNode(tagLocation, parsePath()));
      soakWhitespace();
      checkForTagClosure(reader.getLocation());
      soakWhitespace();
    }
    else {
      addError(tagLocation, MALFORMED_REPLACES_TAG_ERROR);
    }
  }

  @Override
  protected void handleReplaceableTag(Location tagLocation) throws IOException {
    if (checkForTagClosure(tagLocation)) {
      root.addSubNode(new ReplaceableNode(tagLocation));
      soakWhitespace();
    }
  }

  @Override
  protected void handleImplementsTag(Location tagLocation) throws IOException {
    if (checkForTagClosure(tagLocation)) {
      ImplementsNode implementsNode = new ImplementsNode(tagLocation);
      root.addSubNode(implementsNode);
      while (true) {
        soakWhitespace();
        Location location = reader.getNextLocation();
        if (readChar('<')) {
          if (!checkToken("/%implements>")) {
            addError(location, EXPECTING_IMPLEMENTS_CLOSE);
          }
          soakWhitespace();
          return;
        }
        String className = readClassName(reader.getCurrentNodeLocation());
        if (className.length() == 0) {
          addError(location, EXPECTING_IMPLEMENTS_CLOSE);
          return;
        }
        if (!readChar(';')) {
          addError(reader.getNextLocation(), EXPECTING_SEMI);
        }
        implementsNode.addImplement(new ImplementNode(location, className));
      }
    }
  }

  @Override
  protected void handleImportTag(Location tagLocation) throws IOException {
    if (checkForTagClosure(tagLocation)) {
      ImportsNode importsNode = new ImportsNode(tagLocation);
      root.addSubNode(importsNode);
      while (true) {
        soakWhitespace();
        Location location = reader.getNextLocation();
        if (readChar('<')) {
          if (!checkToken("/%import>")) {
            addError(location, EXPECTING_IMPORTS_CLOSE);
          }
          soakWhitespace();
          return;
        }
        try {
          importsNode.addImport(new ImportParser(reader, errors).parse().getNode());
        }
        catch (ParserErrorImpl e) {
          addError(e);
          addError(reader.getLocation(), EXPECTING_IMPORTS_CLOSE);
          return;
        }
        soakWhitespace();
        if (!readChar(';')) {
          addError(reader.getNextLocation(), EXPECTING_SEMI);
        }

      }
    }
  }

  @Override
  protected void handleAliasesTag(Location tagLocation) throws IOException {
    checkForTagClosure(tagLocation);
    AliasesNode aliases = new AliasesNode(tagLocation);
    root.addSubNode(aliases);
    while (true) {
      soakWhitespace();
      reader.markNodeEnd();
      if (readChar('<')) {
        if (!checkToken("/%alias>")) {
          addError(reader.getLocation(), BAD_ALIASES_CLOSE_TAG);
        }
        soakWhitespace();
        return;
      }
      String name = readChar('/')
          ? "/"
          : readIdentifier(false);
      if (name.length() == 0) {
        addError(reader.getCurrentNodeLocation(), "Alias name expected");
        return;
      }
      soakWhitespace();
      if (readChar('=')) {
        readChar('>'); // support old-style syntax
        soakWhitespace();
        AbstractPathNode path = parsePath();
        if (path.getPathElements().isEmpty()) {
          return;
        }
        aliases.addAlias(new AliasDefNode(reader.getCurrentNodeLocation(), name, path));
        if (!readChar(';')) {
          addError(reader.getLocation(), EXPECTING_SEMI);
        }
      }
      else {
        addError(reader.getLocation(), EXPECTING_ARROW);
      }
    }
  }

  @Override
  protected void handleAbsMethodTag(Location tagLocation) throws IOException {
    if (soakWhitespace()) {
      String name = readIdentifier(true);
      checkForTagClosure(tagLocation);
      AbsMethodNode absMethodNode = new AbsMethodNode(tagLocation, name);
      root.addSubNode(absMethodNode);
      while (true) {
        soakWhitespace();
        reader.markNodeEnd();
        if (readChar('<')) {
          if (readChar('%')) {
            String tagName = readTagName();
            if ("args".equals(tagName)) {
              try {
                absMethodNode.addArgsBlock(
                  new ArgsParser(reader, errors, reader.getCurrentNodeLocation()).getArgsNode());
              }
              catch (ParserErrorImpl e) {
                addError(e);
              }
            }
            else if ("frag".equals(tagName)) {
              try {
                absMethodNode.addArgsBlock(
                  new FragmentArgsParser(reader, errors, reader.getCurrentNodeLocation())
                  .getFragmentArgsNode());
              }
              catch (ParserErrorImpl e) {
                addError(e);
              }
            }
            else {
              addError(reader.getLocation(), BAD_ABSMETH_CONTENT);
              return;
            }
          }
          else {
            if (!checkToken("/%absmeth>")) {
              addError(reader.getLocation(), BAD_ABS_METHOD_CLOSE_TAG);
            }
            soakWhitespace();
            return;
          }
        }
        else {
          addError(reader.getLocation(), BAD_ABSMETH_CONTENT);
          return;
        }
      }
    }
    else {
      addError(reader.getLocation(), "malformed <%absmeth methodName> tag");
    }
  }

  @Override
  protected void handleParentArgsNode(Location tagLocation) throws IOException {
    root.addSubNode(new ParentArgsParser(reader, errors, tagLocation).getParentArgsNode());
  }

  @Override
  protected void handleParentMarkerTag(Location tagLocation) throws IOException {
    if (checkForTagClosure(tagLocation)) {
      root.addSubNode(new ParentMarkerNode(tagLocation));
      soakWhitespace();
    }
  }

  @Override
  protected void handleEof() {
  // end of file is a fine thing at the top level
  }

  @Override
  protected void handleEscapeTag(Location tagLocation) throws IOException {
    soakWhitespace();
    if (!readChar('#')) {
      addError(reader.getNextLocation(), "Expecting '#'");
    }
    else {
      soakWhitespace();
      int c = reader.read();
      if (Character.isLetter((char) c)) {
        root.addSubNode(
          new EscapeDirectiveNode(tagLocation, new String(new char[] { (char) c })));
      }
      else {
        addError(reader.getLocation(), "Expecting a letter");
      }
      soakWhitespace();
      checkForTagClosure(tagLocation);
    }
    soakWhitespace();
  }

  @Override
  protected void handleGenericTag(Location tagLocation) throws IOException {
    root.addSubNode(new GenericsParser(reader, errors, tagLocation).getGenericsNode());
  }

  @Override
  protected void handleAnnotationTag(Location tagLocation) throws IOException {
    if (soakWhitespace()) {
      try {
        HashEndDetector detector = new HashEndDetector();
        String annotations = readJava(tagLocation, detector);
        AnnotationType annotationType;
        if (detector.endedWithHash()) {
          annotationType = readAnnotationType();
          soakWhitespace();
          if (!(readChar('%') && readChar('>'))) {
            throw new ParserErrorImpl(tagLocation, MALFORMED_ANNOTATE_TAG_ERROR);
          }
        }
        else {
          annotationType = AnnotationType.BOTH;
        }
        root.addSubNode(new AnnotationNode(tagLocation, annotations, annotationType));

      }
      catch (ParserErrorImpl e) {
        addError(e);
      }
      soakWhitespace();
    }
    else {
      addError(tagLocation, MALFORMED_ANNOTATE_TAG_ERROR);
    }
  }

  private AnnotationType readAnnotationType() throws IOException, ParserErrorImpl {
    Location location = reader.getLocation();
    if (readChar('p')) {
      if (checkToken("roxy")) {
        return AnnotationType.PROXY;
      }
    }
    else if (readChar('i')) {
      if (checkToken("mpl")) {
        return AnnotationType.IMPL;
      }
    }
    throw new ParserErrorImpl(location, UNRECOGNIZED_ANNOTATION_TYPE_ERROR);
  }

  @Override
  protected boolean isTopLevel() {
    return true;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy