Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package org.petitparser.tools;
import org.petitparser.parser.Parser;
import org.petitparser.parser.combinators.ChoiceParser;
import org.petitparser.parser.combinators.SequenceParser;
import org.petitparser.parser.combinators.SettableParser;
import org.petitparser.parser.primitive.FailureParser;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
/**
* A builder that allows the simple definition of expression grammars with
* prefix, postfix, and left- and right-associative infix operators.
*/
public class ExpressionBuilder {
private final SettableParser loopback = SettableParser.undefined();
private final List groups = new ArrayList<>();
/**
* Creates a new group of operators that share the same priority.
*/
public ExpressionGroup group() {
ExpressionGroup group = new ExpressionGroup();
groups.add(group);
return group;
}
/**
* Builds the expression parser.
*/
public Parser build() {
Parser parser = FailureParser.withMessage(
"Highest priority group should define a primitive parser.");
for (ExpressionGroup group : groups) {
parser = group.build(parser);
}
loopback.set(parser);
return parser;
}
/**
* Models a group of operators of the same precedence.
*/
public class ExpressionGroup {
private final List primitives = new ArrayList<>();
private final List wrappers = new ArrayList<>();
private final List prefix = new ArrayList<>();
private final List postfix = new ArrayList<>();
private final List right = new ArrayList<>();
private final List left = new ArrayList<>();
/**
* Defines a new primitive or literal {@code parser}.
*/
public ExpressionGroup primitive(Parser parser) {
return primitive(parser, null);
}
/**
* Defines a new primitive or literal {@code parser}. Evaluates the optional
* {@code action} with the parsed {@code value}.
*/
public ExpressionGroup primitive(
Parser parser, @Nullable Function action) {
primitives.add(action == null ? parser : parser.map(action));
return this;
}
private Parser buildPrimitive(Parser inner) {
return buildChoice(primitives, inner);
}
/**
* Defines a new wrapper using {@code left} and {@code right} parsers.
*/
public ExpressionGroup wrapper(Parser left, Parser right) {
return wrapper(left, right, null);
}
/**
* Defines a new wrapper using {@code left} and {@code right} parsers.
* Evaluates the optional {@code action} with the parsed {@code left},
* {@code value} and {@code right}.
*/
public ExpressionGroup wrapper(
Parser left, Parser right, @Nullable Function action) {
Parser parser = new SequenceParser(left, loopback, right);
wrappers.add(action == null ? parser : parser.map(action));
return this;
}
private Parser buildWrapper(Parser inner) {
List choices = new ArrayList<>(wrappers);
choices.add(inner);
return buildChoice(choices, inner);
}
/**
* Adds a prefix operator {@code parser}.
*/
public ExpressionGroup prefix(Parser parser) {
return prefix(parser, null);
}
/**
* Adds a prefix operator {@code parser}. Evaluates the optional {@code
* action} with the parsed {@code operator} and {@code value}.
*/
public ExpressionGroup prefix(
Parser parser, @Nullable Function action) {
addTo(prefix, parser, action);
return this;
}
private Parser buildPrefix(Parser inner) {
if (prefix.isEmpty()) {
return inner;
} else {
Parser sequence = new SequenceParser(buildChoice(prefix).star(), inner);
return sequence.map((List> tuple) -> {
Object value = tuple.get(1);
List tuples = tuple.get(0);
Collections.reverse(tuples);
for (ExpressionResult result : tuples) {
value = result.action.apply(Arrays.asList(result.operator, value));
}
return value;
});
}
}
/**
* Adds a postfix operator {@code parser}.
*/
public ExpressionGroup postfix(Parser parser) {
return postfix(parser, null);
}
/**
* Adds a postfix operator {@code parser}. Evaluates the optional {@code
* action} with the parsed {@code value} and {@code operator}.
*/
public ExpressionGroup postfix(
Parser parser, @Nullable Function action) {
addTo(postfix, parser, action);
return this;
}
private Parser buildPostfix(Parser inner) {
if (postfix.isEmpty()) {
return inner;
} else {
Parser sequence =
new SequenceParser(inner, buildChoice(postfix).star());
return sequence.map((List> tuple) -> {
Object value = tuple.get(0);
for (ExpressionResult result : tuple.get(1)) {
value = result.action.apply(Arrays.asList(value, result.operator));
}
return value;
});
}
}
/**
* Adds a right-associative operator {@code parser}.
*/
public ExpressionGroup right(Parser parser) {
return right(parser, null);
}
/**
* Adds a right-associative operator {@code parser}. Evaluates the optional
* {@code action} with the parsed {@code left} term, {@code operator}, and
* {@code right} term.
*/
public ExpressionGroup right(
Parser parser, @Nullable Function action) {
addTo(right, parser, action);
return this;
}
private Parser buildRight(Parser inner) {
if (right.isEmpty()) {
return inner;
} else {
Parser sequence = inner.separatedBy(buildChoice(right));
return sequence.map((List