summaryrefslogtreecommitdiff
path: root/base/src/main/java/bjc/utils/patterns/ComplexPattern.java
diff options
context:
space:
mode:
Diffstat (limited to 'base/src/main/java/bjc/utils/patterns/ComplexPattern.java')
-rw-r--r--base/src/main/java/bjc/utils/patterns/ComplexPattern.java183
1 files changed, 183 insertions, 0 deletions
diff --git a/base/src/main/java/bjc/utils/patterns/ComplexPattern.java b/base/src/main/java/bjc/utils/patterns/ComplexPattern.java
new file mode 100644
index 0000000..3926f2c
--- /dev/null
+++ b/base/src/main/java/bjc/utils/patterns/ComplexPattern.java
@@ -0,0 +1,183 @@
+package bjc.utils.patterns;
+
+import java.util.function.*;
+import java.util.regex.*;
+
+import bjc.data.*;
+
+/**
+ * A pattern that can be matched against.
+ *
+ * @author Ben Culkin
+ *
+ * @param <InputType> The type of object being matched against.
+ * @param <ReturnType> The type returned by the pattern.
+ * @param <PredType> The state type returned by the predicate.
+ */
+public interface ComplexPattern<ReturnType, PredType, InputType> {
+ /**
+ * Whether or not the given input matches this pattern.
+ *
+ * @param input The object to check against this pattern.
+ *
+ * @return Whether or not this pattern is matched, as well as a state value
+ * that will get passed to the pattern if it did match.
+ */
+ IPair<Boolean, PredType> matches(InputType input);
+
+ /**
+ * Apply this pattern, once it has matched.
+ *
+ * @param input The object to apply this pattern to.
+ * @param state The state from the matcher.
+ *
+ * @return The result of applying this pattern.
+ */
+ ReturnType apply(InputType input, PredType state);
+
+ /**
+ * Create a pattern composed from a predicate & a function.
+ *
+ * @param <RetType> The type returned by the pattern.
+ * @param <PreType> The type used as intermediate state.
+ * @param <InpType> The type initially matched against.
+ *
+ * @param matcher The predicate that says what this pattern matches.
+ * @param accepter The action that happens when this pattern matches.
+ *
+ * @return A pattern composed from the passed in functions.
+ */
+ static <RetType, PreType, InpType> ComplexPattern<RetType, PreType, InpType> from(
+ Function<InpType, IPair<Boolean, PreType>> matcher,
+ BiFunction<InpType, PreType, RetType> accepter) {
+ return new FunctionalPattern<>(matcher, accepter);
+ }
+
+ /**
+ * Create a pattern which checks if an object is of a given type (or a subtype of it).
+ *
+ * @param <ClassType> The type to check if the object is an instance of.
+ * @param <RetType> The type returned by the action.
+ * @param <InpType> The type of the thing to match.
+ *
+ * @param clasz The Class instance for the type you want to check.
+ * @param action The action to execute if the pattern does match.
+ *
+ * @return A pattern which follows the specified condition.
+ */
+ @SuppressWarnings("unchecked")
+ static <ClassType, RetType, InpType> ComplexPattern<RetType, ?, InpType> ofClass(
+ Class<ClassType> clasz,
+ Function<ClassType, RetType> action) {
+ return from(
+ (input) -> IPair.pair(clasz.isInstance(input), null),
+ (input, ignored) -> action.apply((ClassType)input)
+ );
+ }
+
+ /**
+ * Creates a pattern which matches a given object.
+ *
+ * @param <RetType> The type returned when the pattern matches.
+ * @param <InpType> The type of the thing to match.
+ *
+ * @param obj The object being tested for equality.
+ * @param action The action to execute when the object matches.
+ *
+ * @return A pattern which tests against the equality of an object.
+ */
+ static <RetType, InpType> ComplexPattern<RetType, ?, InpType> matchesObject(
+ InpType obj,
+ Function<InpType, RetType> action
+ ) {
+ return from(
+ (input) -> IPair.pair(obj.equals(input), null),
+ (input, ignored) -> action.apply(input)
+ );
+ }
+
+ /**
+ * Tests if the toString rendition of an object matches a given condition.
+ *
+ * @param <RetType> The type returned by the pattern.
+ * @param <InpType> The type of the thing to match.
+ *
+ * @param pattern The string to check against.
+ * @param action The action to check when the toString of the object matches
+ * the provided string. This is passed both the object, and its
+ * string form (in the event that you don't want to call toString
+ * multiple times, for whatever reason)
+ *
+ * @return A pattern which tests against the toString representation of an object.
+ */
+ static <RetType, InpType> ComplexPattern<RetType, ?, InpType> equalsString(
+ String pattern,
+ BiFunction<InpType, String, RetType> action
+ ) {
+ return from(
+ (input) -> {
+ String objString = input.toString();
+
+ return IPair.pair(pattern.equals(objString), objString);
+ },
+ (input, objString) -> action.apply(input, objString)
+ );
+ }
+
+ /**
+ * Check if the toString of a given object matches a regex.
+ *
+ * @param <RetType> The type returned by the pattern.
+ * @param <InpType> The type of object to match against.
+ *
+ * @param regex The regex to match against.
+ * @param cond The predicate to use to determine if the regex matched.
+ * @param action The action to call when the regex matched.
+ *
+ * @return A pattern which does the regex matching.
+ */
+ static <RetType, InpType> ComplexPattern<RetType, Matcher, InpType> matchesRegex(
+ String regex,
+ Predicate<Matcher> cond,
+ BiFunction<InpType, Matcher, RetType> action
+ ) {
+ java.util.regex.Pattern regexPat = java.util.regex.Pattern.compile(regex);
+
+ return from(
+ (input) -> {
+ String inpString = input.toString();
+
+ Matcher mat = regexPat.matcher(inpString);
+
+ if (cond.test(mat)) {
+ return IPair.pair(true, mat);
+ } else {
+ return IPair.pair(false, null);
+ }
+ },
+ (input, res) -> action.apply(input, res)
+ );
+ }
+
+ // @TODO Nov 21, 2020 Ben Culkin :MorePatterns
+ // Try and write something to iterate over Iterator in a type-safe manner
+ // Also, something for doing a sub-pattern match
+ /**
+ * Create a pattern which will always execute.
+ *
+ * @param <RetType> The type returned.
+ * @param <InpType> The type being matched against.
+ *
+ * @param action The action to execute.
+ *
+ * @return A pattern which will be executed.
+ */
+ static <RetType, InpType> ComplexPattern<RetType, ?, InpType> otherwise(
+ Function<InpType, RetType> action
+ ) {
+ return from(
+ (input) -> IPair.pair(true, null),
+ (input, ignored) -> action.apply(input)
+ );
+ }
+} \ No newline at end of file