summaryrefslogtreecommitdiff
path: root/src/main/java/bjc/rgens/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/bjc/rgens/parser')
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/RGrammarBuilder.java37
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/RGrammarParser.java30
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/Rule.java81
3 files changed, 114 insertions, 34 deletions
diff --git a/src/main/java/bjc/rgens/parser/RGrammarBuilder.java b/src/main/java/bjc/rgens/parser/RGrammarBuilder.java
index 1bc849b..535d818 100755
--- a/src/main/java/bjc/rgens/parser/RGrammarBuilder.java
+++ b/src/main/java/bjc/rgens/parser/RGrammarBuilder.java
@@ -350,33 +350,40 @@ public class RGrammarBuilder {
public void addAutoRlVar(String name, CaseElement elm) {
autoRlVars.put(name, elm);
}
- /*
- * @TODO
- *
- * Figure out how this should work, and get this working.
- */
- /*
- public void regexizeRule(String rule, String pattern) {
+
+ public void rejectRule(String rule, String reject) {
if (rule == null) {
throw new NullPointerException("rule must not be null");
- } else if(pattern == null) {
- throw new NullPointerException("pattern must not be null");
+ } else if(reject == null) {
+ throw new NullPointerException("reject must not be null");
} else if (rule.equals("")) {
throw new IllegalArgumentException("The empty string is not a valid rule name");
} else if(!rules.containsKey(rule)) {
throw new IllegalArgumentException(String.format("The rule '%s' doesn't exist", rule));
}
- IList<RuleCase> caseList = rules.get(rule).getCases();
+ Rule rl = rules.get(rule);
- IList<RuleCase> newCaseList = new FunctionalList<>();
+ rl.addRejection(reject);
+ }
- for(RuleCase cse : caseList) {
- newCaseList.add(new RegexRuleCase(cse.getElements(), pattern));
+ public void findReplaceRule(String rule, String find, String replace) {
+ if (rule == null) {
+ throw new NullPointerException("rule must not be null");
+ } else if(find == null) {
+ throw new NullPointerException("find must not be null");
+ } else if(replace == null) {
+ throw new NullPointerException("replace must not be null");
+ } else if (rule.equals("")) {
+ throw new IllegalArgumentException("The empty string is not a valid rule name");
+ } else if(!rules.containsKey(rule)) {
+ throw new IllegalArgumentException(String.format("The rule '%s' doesn't exist", rule));
}
- rules.get(rule).replaceCases(newCaseList);
- }*/
+ Rule rl = rules.get(rule);
+
+ rl.addFindReplace(find, replace);
+ }
/*
* @NOTE
diff --git a/src/main/java/bjc/rgens/parser/RGrammarParser.java b/src/main/java/bjc/rgens/parser/RGrammarParser.java
index 4014baa..a95cefc 100755
--- a/src/main/java/bjc/rgens/parser/RGrammarParser.java
+++ b/src/main/java/bjc/rgens/parser/RGrammarParser.java
@@ -169,18 +169,32 @@ public class RGrammarParser {
build.setBinomial(parts.get(0), Integer.parseInt(parts.get(1)), Integer.parseInt(parts.get(2)), Integer.parseInt(parts.get(3)));
});
- pragmas.put("regex-rule", (body, build, level) -> {
- int nameIndex = body.indexOf(" ");
+ /*
+ * @NOTE 4/9/18
+ *
+ * Consider if we want to replace this with something more akin
+ * to the `definer` feature from DiceLang. This will work fine
+ * in most cases, but there are some cases where you'd want the
+ * extra power. No examples are apparent at the moment.
+ */
+ pragmas.put("find-replace-rule", (body, build, level) -> {
+ List<String> bits = StringUtils.levelSplit(body, " ");
- if(nameIndex == -1) {
- throw new GrammarException("Regex-rule pragma takes two arguments: the name of the rule to process, then the regex to apply after the rule has been generated.");
+ if(bits.size() != 3) {
+ throw new GrammarException("Regex-rule pragma takes three arguments: the name of the rule to process, then the find/replace pair to apply after the rule has been generated.");
}
- String name = body.substring(0, nameIndex).trim();
- String patt = body.substring(nameIndex + 1).trim();
+ build.findReplaceRule(bits.get(0), bits.get(1), bits.get(2));
+ });
+
+ pragmas.put("reject-rule", (body, build, level) -> {
+ List<String> bits = StringUtils.levelSplit(body, " ");
+
+ if(bits.size() != 3) {
+ throw new GrammarException("Reject-rule pragma takes two arguments: the name of the rule to process, then the rejection pattern to apply after the rule has been generated.");
+ }
- throw new GrammarException("Regexize-rule pragma not yet supported");
- //build.regexizeRule(name, patt);
+ build.rejectRule(bits.get(0), bits.get(1));
});
pragmas.put("prefix-with", (body, build, level) -> {
diff --git a/src/main/java/bjc/rgens/parser/Rule.java b/src/main/java/bjc/rgens/parser/Rule.java
index a86f84e..21d197d 100755
--- a/src/main/java/bjc/rgens/parser/Rule.java
+++ b/src/main/java/bjc/rgens/parser/Rule.java
@@ -5,9 +5,15 @@ import bjc.utils.funcdata.FunctionalList;
import bjc.utils.funcdata.IList;
import bjc.utils.gen.WeightedRandom;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Random;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
import static bjc.rgens.parser.RGrammarLogging.*;
+import static bjc.utils.data.IPair.pair;
/**
* A rule in a randomized grammar.
@@ -37,12 +43,17 @@ public class Rule {
public ProbType prob;
- public int descentFactor;
-
+ // Probability vars
+ /* Descent vars */
+ public int descentFactor;
+ /* Binomial vars */
public int target;
public int bound;
public int trials;
+ private List<String> rejectionPreds;
+ private List<IPair<String, String>> findReplaces;
+
// @TODO This default should be configurable in some way
public int recurLimit = 5;
private int currentRecur;
@@ -77,6 +88,9 @@ public class Rule {
cases = new WeightedRandom<>();
prob = ProbType.NORMAL;
+
+ rejectionPreds = new ArrayList<>();
+ findReplaces = new ArrayList<>();
}
/**
@@ -106,6 +120,26 @@ public class Rule {
cases.addProbability(weight, cse);
}
+ public void addRejection(String reject) {
+ try {
+ Pattern.compile(reject);
+ } catch (PatternSyntaxException psex) {
+ throw new GrammarException(String.format("String %s is not a valid regex for rejection", reject), psex);
+ }
+
+ rejectionPreds.add(reject);
+ }
+
+ public void addFindReplace(String find, String replace) {
+ try {
+ Pattern.compile(find);
+ } catch (PatternSyntaxException psex) {
+ throw new GrammarException(String.format("String %s is not a valid regex for finding", find), psex);
+ }
+
+ findReplaces.add(pair(find, replace));
+ }
+
/**
* Get a random case from this rule.
*
@@ -248,18 +282,43 @@ public class Rule {
public void generate(GenerationState state) {
state.swapGrammar(belongsTo);
- if(doRecur()) {
- RuleCase cse = getCase(state.rnd);
+ boolean rejected;
- fine("Generating %s (from %s)", cse, belongsTo.name);
+ do {
+ rejected = false;
- belongsTo.generateCase(cse, state);
+ if(doRecur()) {
+ RuleCase cse = getCase(state.rnd);
- endRecur();
- }
+ fine("Generating %s (from %s)", cse, belongsTo.name);
- if(name.contains("+")) {
- state.contents = new StringBuilder(state.contents.toString().replaceAll("\\s+", ""));
- }
+ belongsTo.generateCase(cse, state);
+
+ endRecur();
+ }
+
+ if(name.contains("+")) {
+ state.contents = new StringBuilder(state.contents.toString().replaceAll("\\s+", ""));
+ }
+
+ String conts = state.contents.toString();
+
+ for(IPair<String, String> findRep : findReplaces) {
+ conts = conts.replaceAll(findRep.getLeft(), findRep.getRight());
+ }
+
+ state.contents = new StringBuilder(conts);
+
+ for(String pat : rejectionPreds) {
+ if(!conts.matches(pat)) {
+ fine("Rejected %s by %s (from %s)", conts, pat, belongsTo.name);
+
+ rejected = true;
+ state.contents = new StringBuilder();
+
+ break;
+ }
+ }
+ } while (rejected);
}
}