Package com.xfltr.hapax.parser

Source Code of com.xfltr.hapax.parser.EztParser

package com.xfltr.hapax.parser;

import java.util.LinkedList;
import java.util.List;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* A parser for EZT-style templates.  This differs from the collab.net
* implementation in a variety of ways.
*
* Features supported:
*
* Includes: [include "filename"] [include variable]
*
* Inserts, which are identical to includes: [insertfile "filename"] [insertfile
* variable]
*
* Variable replacement: [varable]
*
* Existence: [if-any variable]x[else]y[end]
*
* Comparisons: [is x "y"][else][end]
*
* Nesting for [if-any], [is], and [define] is supported.
*
* No escaping is performed, so [format raw] is a no-op.
*
* @author dcoker
*/
public class EztParser implements TemplateParser {
  private static final Logger logger_ =
      Logger.getLogger(EztParser.class.getSimpleName());

  private static final String TOK_LITERAL = "([^\\[]+)";

  // for variable names
  private static final String TOK_IDENT = "[a-z][a-z0-9_.-]*";

  // for if-any, include, define, etc
  private static final String TOK_DIRECTIVE = "[a-z_-]+";

  // for the args list of the STMT_DIRECTIVE
  private static final String TOK_DIRECTIVE_ARGS =
      "((" + TOK_IDENT + ")|(\\\"[^\"]*\\\")|(" + TOK_IDENT +
          " \\\"[^\"]*\\\"))";

  // for variable [dereference]
  private static final String STMT_VARIABLE_DEREF = "(\\[" + TOK_IDENT + "\\])";

  // for [directive arg], [directive arg arg], [directive "arg" "arg"]
  private static final String STMT_DIRECTIVE =
      "(\\[(" + TOK_DIRECTIVE + ")\\s+" + TOK_DIRECTIVE_ARGS + "\\s*\\])";

  // for [[] => "["
  private static final String STMT_BRACKET = "(\\[\\[\\])";

  // for [#comments]
  private static final String STMT_COMMENT = "(\\[#[^\\]]*\\])";

  private static final Pattern PATTERN = Pattern
      .compile(TOK_LITERAL + "|" + STMT_BRACKET + "|" + STMT_COMMENT + "|" +
          STMT_VARIABLE_DEREF + "|" + STMT_DIRECTIVE,
          Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);

  /**
   * Private constructor
   */
  private EztParser() {

  }

  public static EztParser create() {
    return new EztParser();
  }


  public List<TemplateNode> parse(String input) throws TemplateParserException {
    final List<TemplateNode> node_list = new LinkedList<TemplateNode>();
    if (input == null || input.length() == 0) {
      return node_list;
    }

    final Matcher matcher = PATTERN.matcher(input);

    while (matcher.find()) {
      for (int i = 1; i <= matcher.groupCount(); i++) {
        if (matcher.group(i) != null) {
          switch (i) {
            case 1: // literal string
              node_list.add(TextNode.create(matcher.group(i)));
              break;
            case 2: // left bracket ([[])
              node_list.add(TextNode.create("["));
              break;
            case 3: // a [# comment]
              break;
            case 4: // a [variable]
              handleVariable(node_list, matcher);
              break;
            case 5: // some kind of directive
              handleDirective(node_list, matcher);
              break;
            default:
              break;
          }
        }
      }
    }

    return node_list;
  }

  private void handleVariable(List<TemplateNode> node_list, Matcher matcher)
      throws TemplateParserException {
    String text = matcher.group(4);

    // Just in case the user messes up, give them a helpful error message.
    if (text.matches("\\[(is|if-any|define|include|insertfile|format)\\]")) {
      throw new TemplateParserException(
          "You cannot dereference variables named after reserved words: " +
              text);
    }

    // Catch [end] and [else] cases.
    if (text.equals("[end]")) {
      node_list.add(EztEndNode.create());
    } else if (text.equals("[else]")) {
      node_list.add(EztElseNode.create());
    } else {
      node_list.add(VariableNode.parse(
          matcher.group(4).replaceAll("(^\\[)|(\\]$)", "")));
    }
  }

  private void handleDirective(List<TemplateNode> node_list, Matcher matcher)
      throws TemplateParserException {
    final String directive = matcher.group(6);
    final String one_parameter = matcher.group(8);
    final String quoted_include_parameter = matcher.group(9);
    final String two_parameters = matcher.group(10);

    if (directive.equals("include") || directive.equals("insertfile")) {
      if (one_parameter != null) {
        node_list.add(EztIncludeNode.parse(one_parameter));
      } else {
        node_list.add(EztIncludeNode.parse(quoted_include_parameter));
      }
    } else if (directive.equals("define")) {
      node_list.add(EztDefineNode.parse(one_parameter));
    } else if (directive.equals("is")) {
      if (two_parameters == null) {
        throw new TemplateParserException("[is] requires two parameters.");
      }
      String[] tokenized = two_parameters.split("\\s+");
      String varname = tokenized[0];
      String value = tokenized[1].replace("\"", "");
      node_list.add(EztConditionalNode.is(varname, value));
    } else if (directive.equals("if-any")) {
      if (one_parameter == null) {
        throw new TemplateParserException("[if-any] requires one parameter.");
      }
      node_list.add(EztConditionalNode.ifAny(one_parameter));
    } else if (directive.equals("format")) {
      // do nothing
      logger_.info("encountered a [format] directive; ignoring.");
    }
  }
}
TOP

Related Classes of com.xfltr.hapax.parser.EztParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.