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

com.floreysoft.jmte.util.NestedParser Maven / Gradle / Ivy

package com.floreysoft.jmte.util;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/**
 * Mini parser for mini DSL stuff. Use it when you do not want
 * 
    *
  • a full parser, as it would be overkill *
  • to code by hand it in an ad-hoc way, as you have done this wrong too many * times (just think about escaping and quoting) *
  • built-in regexp , as it is too slow and you actually do not quite up to * it (true for me) *
* *

* This is a fast, simple parser that takes input and a single, global hierarchy * of operators and spits out "AST" implemented as nested Lists. *

* *
 * String input = "string(maxLength=10, trim, uppercase)";
 * String[] operators = { "()", ",", "=" }; // in order of precedence, can be pair of start/end or single char separator
 * List parse = new NestedParser().parse(input, operators);
 * System.out.println(parse);
 * 
 * Output =>
 * 
 * [string, [[maxLength, 10], trim, uppercase]]
 * 
 * TODO: Possible extensions could be
 * 
    *
  • a hierarchy of operators (not a list, but a tree) to parser even more complicated inputs *
  • Panic mode calling a user specified callback for further processing when either less or more segments as expected are found in a split *
* */ public final class NestedParser { private final static MiniParser MINI_PARSER = MiniParser.rawOutputInstance(); private final static MiniParser INNER_MINI_PARSER = MiniParser.trimmedInstance(); public static String access(final List ast, final int index) { return access(ast, index, null); } public static String access(final List ast, final int index, final String defaultValue) { if (ast == null) { return defaultValue; } if (index < ast.size()) { Object object = ast.get(index); if (object instanceof String) { return (String) object; } else { throw new IllegalArgumentException( "You can only access scalar strings"); } } return defaultValue; } // TODO create a version that allows for multi character operators public List parse(final String input, final List operators) { final List result = new ArrayList(); if (operators.size() != 0) { final boolean innerLoop = operators.size() == 1; final MiniParser currentParser = innerLoop ? INNER_MINI_PARSER : MINI_PARSER; final String operator = operators.get(0); final List segments; if (operator.length() == 1) { segments = currentParser.split(input, operator.charAt(0)); } else if (operator.length() == 2) { List allSegments = currentParser.scan(input, String .valueOf(operator.charAt(0)), String.valueOf(operator .charAt(1)), true); if (allSegments.size() > 0) { // the first part is not processed any further result.add(allSegments.get(0)); } if (allSegments.size() > 1) { segments = allSegments.subList(1, allSegments.size()); } else { segments = Collections.emptyList(); } } else { throw new IllegalArgumentException( "Operators must either be start/end pairs or single characters"); } if (innerLoop) { result.addAll(segments); } else { for (String segment : segments) { List parse = parse(segment, operators.subList(1, operators.size())); if (parse.size() == 1 && parse.get(0) instanceof String) { result.add(parse.get(0)); } else { result.add(parse); } } } } return result; } public List parse(final String input, final String[] operators) { return parse(input, Arrays.asList(operators)); } }