WarpPI/core/src/main/java/it/cavallium/warppi/math/rules/dsl/PatternRule.java

131 lines
4.4 KiB
Java

package it.cavallium.warppi.math.rules.dsl;
import it.cavallium.warppi.math.Function;
import it.cavallium.warppi.math.MathContext;
import it.cavallium.warppi.math.rules.Rule;
import it.cavallium.warppi.math.rules.RuleType;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* A <code>Rule</code> which uses <code>Pattern</code>s to match and replace functions.
*/
public class PatternRule implements Rule {
private final String ruleName;
private final RuleType ruleType;
private final Pattern target;
private final List<Pattern> replacements;
/**
* Constructs a <code>PatternRule</code> with the given name, type and <code>Pattern</code>s.
*
* @param ruleName the name of the rule.
* @param ruleType the type of the rule.
* @param target the <code>Pattern</code> used to match functions and capture sub-functions.
* @param replacements the list of <code>Pattern</code>s used to construct replacement functions.
* All sub-functions which are referenced within these <code>Pattern</code>s must be captured
* by <code>target</code>, otherwise the {@link #execute} method will throw an
* {@link UndefinedSubFunction} exception when constructing the replacement functions.
*/
public PatternRule(
final String ruleName,
final RuleType ruleType,
final Pattern target,
final List<Pattern> replacements
) {
this.ruleName = ruleName;
this.ruleType = ruleType;
this.target = target;
this.replacements = replacements;
}
/**
* Constructs a <code>PatternRule</code> with the given name, type and <code>Pattern</code>s.
*
* @param ruleName the name of the rule.
* @param ruleType the type of the rule.
* @param target the <code>Pattern</code> used to match functions and capture sub-functions.
* @param replacements the <code>Pattern</code>s used to construct replacement functions.
* All sub-functions which are referenced within these <code>Pattern</code>s must be captured
* by <code>target</code>, otherwise the {@link #execute} method will throw an
* {@link UndefinedSubFunction} exception when constructing the replacement functions.
*/
public PatternRule(
final String ruleName,
final RuleType ruleType,
final Pattern target,
final Pattern... replacements
) {
this(ruleName, ruleType, target, Arrays.asList(replacements));
}
@Override
public String getRuleName() {
return ruleName;
}
@Override
public RuleType getRuleType() {
return ruleType;
}
/**
* @return the <code>Pattern</code> used to match functions and capture sub-functions.
*/
public Pattern getTarget() {
return target;
}
/**
* @return the list of <code>Pattern</code>s used to construct replacement functions.
*/
public List<Pattern> getReplacements() {
return replacements;
}
/**
* @throws UndefinedSubFunctionException if the target pattern matches, but it doesn't capture all of the
* sub-functions required by the replacement patterns.
* This exception will never be thrown for well-formed rules (like the ones
* returned by {@link RulesDsl#makeRules}), in which the target pattern
* correctly captures all sub-functions referenced by the replacement patterns.
*/
@Override
public ObjectArrayList<Function> execute(final Function func) {
return target.match(func)
.map(subFunctions -> applyReplacements(func.getMathContext(), subFunctions))
.orElse(null);
}
private ObjectArrayList<Function> applyReplacements(
final MathContext mathContext,
final Map<String, Function> subFunctions
) {
return replacements.stream()
.map(replacement -> replacement.replace(mathContext, subFunctions))
.collect(Collectors.toCollection(ObjectArrayList::new));
}
@Override
public boolean equals(final Object o) {
if (!(o instanceof PatternRule)) {
return false;
}
final PatternRule other = (PatternRule) o;
return ruleName.equals(other.ruleName)
&& ruleType == other.ruleType
&& target.equals(other.target)
&& replacements.equals(other.replacements);
}
@Override
public int hashCode() {
return Objects.hash(ruleName, ruleType, target, replacements);
}
}