Add regex/2,3 predicate
regex/3 predicate takes a pattern term in the form of a regular
expression and either a single term or a list of terms to match the
pattern against. Returns each match.
regex/2 predicate takes the pattern and term(s) to match and returns
true if any match exists.
Change-Id: I20e18a84ea22f9c508aac9beb3136798b9c88eee
diff --git a/src/builtin/PRED_regex_compile_2.java b/src/builtin/PRED_regex_compile_2.java
new file mode 100644
index 0000000..142234f
--- /dev/null
+++ b/src/builtin/PRED_regex_compile_2.java
@@ -0,0 +1,47 @@
+package com.googlecode.prolog_cafe.builtin;
+import com.googlecode.prolog_cafe.lang.IllegalTypeException;
+import com.googlecode.prolog_cafe.lang.JavaObjectTerm;
+import com.googlecode.prolog_cafe.lang.Operation;
+import com.googlecode.prolog_cafe.lang.PInstantiationException;
+import com.googlecode.prolog_cafe.lang.Predicate;
+import com.googlecode.prolog_cafe.lang.Prolog;
+import com.googlecode.prolog_cafe.lang.SymbolTerm;
+import com.googlecode.prolog_cafe.lang.Term;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * <code>regex_compile/2</code><br>
+ *
+ * <pre>
+ * 'regex_compile'(+regex string, -Pattern object)
+ * </pre>
+ */
+public class PRED_regex_compile_2 extends Predicate.P2 {
+
+ public PRED_regex_compile_2(Term a1, Term a2, Operation cont) {
+ arg1 = a1;
+ arg2 = a2;
+ this.cont = cont;
+ }
+
+ public Operation exec(Prolog engine) {
+ engine.setB0();
+ Term a1 = arg1.dereference();
+ Term a2 = arg2.dereference();
+
+ if (a1.isVariable()) {
+ throw new PInstantiationException(this, 1);
+ }
+ if (!a1.isSymbol()) {
+ throw new IllegalTypeException(this, 1, "atom", a1);
+ }
+ Pattern pattern = Pattern.compile(a1.name());
+
+ if (!a2.unify(new JavaObjectTerm(pattern), engine.trail)) {
+ return engine.fail();
+ }
+ return cont;
+ }
+}
\ No newline at end of file
diff --git a/src/builtin/PRED_regex_match_3.java b/src/builtin/PRED_regex_match_3.java
new file mode 100644
index 0000000..830d787
--- /dev/null
+++ b/src/builtin/PRED_regex_match_3.java
@@ -0,0 +1,108 @@
+package com.googlecode.prolog_cafe.builtin;
+import com.googlecode.prolog_cafe.lang.IllegalTypeException;
+import com.googlecode.prolog_cafe.lang.JavaObjectTerm;
+import com.googlecode.prolog_cafe.lang.ListTerm;
+import com.googlecode.prolog_cafe.lang.Operation;
+import com.googlecode.prolog_cafe.lang.PInstantiationException;
+import com.googlecode.prolog_cafe.lang.Predicate;
+import com.googlecode.prolog_cafe.lang.Prolog;
+import com.googlecode.prolog_cafe.lang.SymbolTerm;
+import com.googlecode.prolog_cafe.lang.Term;
+
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * <code>regex_match/3</code><br>
+ *
+ * <pre>
+ * 'regex_match'(+Pattern object, +Chars, -Matches)
+ * </pre>
+ */
+public class PRED_regex_match_3 extends Predicate.P3 {
+
+ private static final Operation regex_check = new PRED_regex_check();
+ private static final Operation regex_next = new PRED_regex_next();
+ private static final Operation regex_empty = new PRED_regex_empty();
+
+ public PRED_regex_match_3(Term a1, Term a2, Term a3, Operation cont) {
+ arg1 = a1;
+ arg2 = a2;
+ arg3 = a3;
+ this.cont = cont;
+ }
+
+ public Operation exec(Prolog engine) {
+ engine.setB0();
+ engine.cont = cont;
+ Term a1 = arg1.dereference();
+ Term a2 = arg2.dereference();
+
+ if (a1.isVariable()) {
+ throw new PInstantiationException(this, 1);
+ }
+ Pattern pattern = (Pattern)((JavaObjectTerm)a1).object();
+
+ if (a2.isVariable()) {
+ throw new PInstantiationException(this, 1);
+ }
+ if (!a2.isSymbol()) {
+ throw new IllegalTypeException(this, 1, "atom", a2);
+ }
+ Matcher matcher = pattern.matcher(a2.name());
+
+ if (!matcher.find()) {
+ return engine.fail();
+ }
+
+ engine.areg1 = new JavaObjectTerm(matcher);
+ engine.areg2 = arg3;
+ return engine.jtry2(regex_check, regex_next);
+ }
+
+ private static final class PRED_regex_check extends Operation {
+ @Override
+ public Operation exec(Prolog engine) {
+ Term a1 = engine.areg1;
+ Term result = engine.areg2;
+ Matcher matcher = (Matcher)((JavaObjectTerm)a1).object();
+
+ Term matches = getMatches(matcher);
+
+ if (matches == Prolog.Nil || !result.unify(matches, engine.trail)) {
+ return engine.fail();
+ }
+ return engine.cont;
+ }
+ }
+
+ private static final class PRED_regex_next extends Operation {
+ @Override
+ public Operation exec(Prolog engine) {
+ return engine.trust(regex_empty);
+ }
+ }
+
+ private static final class PRED_regex_empty extends Operation {
+ @Override
+ public Operation exec(Prolog engine) {
+ Term a1 = engine.areg1;
+ Matcher matcher = (Matcher)((JavaObjectTerm)a1).object();
+ if (!matcher.find()) {
+ return engine.fail();
+ }
+
+ return engine.jtry2(regex_check, regex_next);
+ }
+ }
+
+ private static Term getMatches(Matcher matcher) {
+ Term list = Prolog.Nil;
+ for (int i = matcher.groupCount(); i >= 0; i--) {
+ SymbolTerm match = SymbolTerm.create(matcher.group(i));
+ list = new ListTerm(match, list);
+ }
+ return list;
+ }
+}
\ No newline at end of file
diff --git a/src/builtin/builtins.pl b/src/builtin/builtins.pl
index f0e3178..b6dcda6 100644
--- a/src/builtin/builtins.pl
+++ b/src/builtin/builtins.pl
@@ -1693,6 +1693,8 @@
%:- public char_code/2. written in Java
%:- public number_chars/2, number_codes/2. written in Java
:- public name/2.
+:- public regex/3.
+:- public regex/2.
sub_atom(Atom, Before, Length, After, Sub_atom) :-
atom_concat(AtomL, X, Atom),
@@ -1714,6 +1716,22 @@
; illarg(type(list(char)), name(Constant,Chars), 2)
).
+regex(_, [], _) :- !, fail.
+regex(Pattern, List, Result) :-
+ List = [_ | _],
+ !,
+ regex_list(Pattern, List, Result).
+regex(Pattern, String, Result) :-
+ atom(String),
+ regex_compile(Pattern, Matcher),
+ regex_match(Matcher, String, Result).
+
+regex(Pattern, String) :-
+ once(regex(Pattern, String, _)).
+
+regex_list(Pattern, [H | _ ], Result) :- regex(Pattern, H, Result).
+regex_list(Pattern, [_ | Ls], Result) :- regex_list(Pattern, Ls, Result).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Implementation defined hooks
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%