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 Pattern
s used to construct replacement functions.
* All sub-functions which are referenced within these Pattern
s 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 Pattern
s used to construct replacement functions.
* All sub-functions which are referenced within these Pattern
s 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(