diff --git a/core/src/main/java/it/cavallium/warppi/math/rules/dsl/PatternRule.java b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/PatternRule.java index af9a09c9..6e0c67d0 100644 --- a/core/src/main/java/it/cavallium/warppi/math/rules/dsl/PatternRule.java +++ b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/PatternRule.java @@ -29,7 +29,8 @@ public class PatternRule implements Rule { * @param target the Pattern used to match functions and capture sub-functions. * @param replacements the list of Patterns used to construct replacement functions. * All sub-functions which are referenced within these Patterns must be captured - * by target. + * by target, otherwise the {@link #execute} method will throw an + * {@link UndefinedSubFunction} exception when constructing the replacement functions. */ public PatternRule( final String ruleName, @@ -51,7 +52,8 @@ public class PatternRule implements Rule { * @param target the Pattern used to match functions and capture sub-functions. * @param replacements the Patterns used to construct replacement functions. * All sub-functions which are referenced within these Patterns must be captured - * by target. + * by target, otherwise the {@link #execute} method will throw an + * {@link UndefinedSubFunction} exception when constructing the replacement functions. */ public PatternRule( final String ruleName, @@ -86,6 +88,13 @@ public class PatternRule implements Rule { 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 execute(final Function func) { return target.match(func) diff --git a/core/src/main/java/it/cavallium/warppi/math/rules/dsl/UndefinedSubFunctionException.java b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/UndefinedSubFunctionException.java new file mode 100644 index 00000000..e0edc8b9 --- /dev/null +++ b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/UndefinedSubFunctionException.java @@ -0,0 +1,26 @@ +package it.cavallium.warppi.math.rules.dsl; + +/** + * Thrown when a SubFunctionPattern is used to generate a Function, but the named sub-function + * it references is not defined. + */ +public class UndefinedSubFunctionException extends RuntimeException { + private final String subFunctionName; + + /** + * Constructs an UndefinedSubFunction instance with the specified sub-function name. + * + * @param subFunctionName the name of the undefined sub-function. + */ + public UndefinedSubFunctionException(final String subFunctionName) { + super("Sub-function '" + subFunctionName + "' is not defined"); + this.subFunctionName = subFunctionName; + } + + /** + * @return the name of the undefined sub-function. + */ + public String getSubFunctionName() { + return subFunctionName; + } +} diff --git a/core/src/main/java/it/cavallium/warppi/math/rules/dsl/patterns/SubFunctionPattern.java b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/patterns/SubFunctionPattern.java index 40e0fbb2..9e2217d7 100644 --- a/core/src/main/java/it/cavallium/warppi/math/rules/dsl/patterns/SubFunctionPattern.java +++ b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/patterns/SubFunctionPattern.java @@ -3,6 +3,7 @@ package it.cavallium.warppi.math.rules.dsl.patterns; import it.cavallium.warppi.math.Function; import it.cavallium.warppi.math.MathContext; import it.cavallium.warppi.math.rules.dsl.Pattern; +import it.cavallium.warppi.math.rules.dsl.UndefinedSubFunctionException; import java.util.Map; import java.util.Objects; @@ -29,8 +30,16 @@ public class SubFunctionPattern implements Pattern { return existingSubFunction == null || existingSubFunction.equals(function); } + /** + * @throws UndefinedSubFunctionException if the subFunctions Map doesn't contain a + * sub-function with the name specified in this + * SubFunctionPattern's constructor. + */ @Override public Function replace(final MathContext mathContext, final Map subFunctions) { + if (!subFunctions.containsKey(name)) { + throw new UndefinedSubFunctionException(name); + } return subFunctions.get(name); } diff --git a/core/src/test/java/it/cavallium/warppi/math/rules/dsl/PatternTest.java b/core/src/test/java/it/cavallium/warppi/math/rules/dsl/PatternTest.java index 56c6884c..e8636e1b 100644 --- a/core/src/test/java/it/cavallium/warppi/math/rules/dsl/PatternTest.java +++ b/core/src/test/java/it/cavallium/warppi/math/rules/dsl/PatternTest.java @@ -13,10 +13,7 @@ import org.apache.commons.lang3.tuple.ImmutablePair; import org.junit.Test; import java.math.BigDecimal; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import static org.junit.Assert.*; @@ -39,6 +36,14 @@ public class PatternTest { assertEquals(func, pattern.replace(mathContext, subFunctions.get())); } + @Test(expected = UndefinedSubFunctionException.class) // TODO assert exception.getSubFunctionName().equals("x") + public void undefinedSubFunction() { + final Pattern pattern = new SubFunctionPattern("x"); + final Map subFunctions = Collections.singletonMap("y", new Number(mathContext, 1)); + + pattern.replace(mathContext, subFunctions); + } + @Test public void sumPattern() { final Pattern pattern = new SumPattern(