summaryrefslogtreecommitdiff
path: root/src/main/java/bjc/rgens
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/bjc/rgens')
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/RGrammar.java11
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/RGrammarBuilder.java11
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/RGrammarParser.java14
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/RGrammarTest.java7
-rw-r--r--src/main/java/bjc/rgens/parser/RecurLimitException.java35
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/Rule.java28
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/RuleCase.java7
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java15
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/elements/RuleCaseElement.java28
9 files changed, 133 insertions, 23 deletions
diff --git a/src/main/java/bjc/rgens/parser/RGrammar.java b/src/main/java/bjc/rgens/parser/RGrammar.java
index 0c572a7..e650a27 100755
--- a/src/main/java/bjc/rgens/parser/RGrammar.java
+++ b/src/main/java/bjc/rgens/parser/RGrammar.java
@@ -155,10 +155,17 @@ public class RGrammar {
}
}
- RuleCase start = rules.get(fromRule).getCase(state.rnd);
+ Rule rl = rules.get(fromRule);
- generateCase(start, state);
+ if(rl.doRecur()) {
+ RuleCase start = rules.get(fromRule).getCase(state.rnd);
+ generateCase(start, state);
+
+ rl.endRecur();
+ } else {
+ throw new RecurLimitException("Rule recurrence limit exceeded");
+ }
/*
* @NOTE
*
diff --git a/src/main/java/bjc/rgens/parser/RGrammarBuilder.java b/src/main/java/bjc/rgens/parser/RGrammarBuilder.java
index 047567d..bc93fa6 100755
--- a/src/main/java/bjc/rgens/parser/RGrammarBuilder.java
+++ b/src/main/java/bjc/rgens/parser/RGrammarBuilder.java
@@ -275,6 +275,17 @@ public class RGrammarBuilder {
rules.get(ruleName).replaceCases(newCaseList);
}
+ public void setRuleRecur(String ruleName, int recurLimit) {
+ if (ruleName == null) {
+ throw new NullPointerException("ruleName must not be null");
+ } else if (ruleName.equals("")) {
+ throw new IllegalArgumentException("The empty string is not a valid rule name");
+ } else if (!rules.containsKey(ruleName)) {
+ throw new IllegalArgumentException(String.format("The rule '%s' doesn't exist", ruleName));
+ }
+
+ rules.get(ruleName).recurLimit = recurLimit;
+ }
/*
* @TODO
*
diff --git a/src/main/java/bjc/rgens/parser/RGrammarParser.java b/src/main/java/bjc/rgens/parser/RGrammarParser.java
index 9232013..827cbb6 100755
--- a/src/main/java/bjc/rgens/parser/RGrammarParser.java
+++ b/src/main/java/bjc/rgens/parser/RGrammarParser.java
@@ -81,6 +81,20 @@ public class RGrammarParser {
}
});
+ pragmas.put("recur-limit", (body, build, level) -> {
+ String[] parts = body.split(" ");
+
+ if(parts.length != 2) {
+ throw new GrammarException("Recur-limit pragma takes two arguments: the name of the rule to set the limit for, and the new value of the limit");
+ }
+
+ if(!parts[1].matches("\\A\\d+\\Z")) {
+ throw new GrammarException("Limit value must be an integer");
+ }
+
+ build.setRuleRecur(parts[0], Integer.parseInt(parts[1]));
+ });
+
pragmas.put("regex-rule", (body, build, level) -> {
int nameIndex = body.indexOf(" ");
diff --git a/src/main/java/bjc/rgens/parser/RGrammarTest.java b/src/main/java/bjc/rgens/parser/RGrammarTest.java
index 02a32f7..c86336c 100755
--- a/src/main/java/bjc/rgens/parser/RGrammarTest.java
+++ b/src/main/java/bjc/rgens/parser/RGrammarTest.java
@@ -69,10 +69,13 @@ public class RGrammarTest {
System.out.printf(fmt, exportName, loadSrc);
System.out.println();
+ System.out.println();
+
+ System.err.printf(fmt, exportName, loadSrc);
gex.printStackTrace();
- System.out.println();
- System.out.println();
+ System.err.println();
+ System.err.println();
}
}
long endGenTime = System.nanoTime();
diff --git a/src/main/java/bjc/rgens/parser/RecurLimitException.java b/src/main/java/bjc/rgens/parser/RecurLimitException.java
new file mode 100644
index 0000000..faeffb3
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/RecurLimitException.java
@@ -0,0 +1,35 @@
+package bjc.rgens.parser;
+
+/**
+ * The exception thrown when a rule exceeds its recurrence limit
+ *
+ * @author student
+ */
+public class RecurLimitException extends GrammarException {
+ /* Serialization ID. */
+ private static final long serialVersionUID = -7287427479316953668L;
+
+ /**
+ * Create a new grammar exception with the specified message.
+ *
+ * @param msg
+ * The message for this exception.
+ */
+ public RecurLimitException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Create a new grammar exception with the specified message and
+ * cause.
+ *
+ * @param msg
+ * The message for this exception.
+ *
+ * @param cause
+ * The cause of this exception.
+ */
+ public RecurLimitException(String msg, Exception cause) {
+ super(msg, cause);
+ }
+}
diff --git a/src/main/java/bjc/rgens/parser/Rule.java b/src/main/java/bjc/rgens/parser/Rule.java
index 0022732..4e43fd7 100755
--- a/src/main/java/bjc/rgens/parser/Rule.java
+++ b/src/main/java/bjc/rgens/parser/Rule.java
@@ -19,6 +19,9 @@ public class Rule {
/* The cases for this rule. */
private WeightedRandom<RuleCase> cases;
+ public int recurLimit = 5;
+ private int currentRecur;
+
/**
* Create a new grammar rule.
*
@@ -47,11 +50,7 @@ public class Rule {
* The case to add.
*/
public void addCase(RuleCase cse) {
- if (cse == null) {
- throw new NullPointerException("Case must not be null");
- }
-
- cases.addProbability(1, cse);
+ addCase(cse, 1);
}
/**
@@ -65,6 +64,8 @@ public class Rule {
throw new NullPointerException("Case must not be null");
}
+ cse.belongsTo = name;
+
cases.addProbability(weight, cse);
}
@@ -111,7 +112,10 @@ public class Rule {
this.cases = new WeightedRandom<>();
for(IPair<Integer, RuleCase> cse : cases) {
- this.cases.addProbability(cse.getLeft(), cse.getRight());
+ RuleCase cs = cse.getRight();
+ cs.belongsTo = name;
+
+ this.cases.addProbability(cse.getLeft(), cs);
}
}
@@ -151,4 +155,16 @@ public class Rule {
public String toString() {
return String.format("Rule [ruleName='%s', ruleCases=%s]", name, cases);
}
+
+ public boolean doRecur() {
+ if(currentRecur > recurLimit) return false;
+
+ currentRecur += 1;
+
+ return true;
+ }
+
+ public void endRecur() {
+ if(currentRecur > 0) currentRecur -= 1;
+ }
}
diff --git a/src/main/java/bjc/rgens/parser/RuleCase.java b/src/main/java/bjc/rgens/parser/RuleCase.java
index bb82ff2..21a7ed6 100755
--- a/src/main/java/bjc/rgens/parser/RuleCase.java
+++ b/src/main/java/bjc/rgens/parser/RuleCase.java
@@ -31,6 +31,8 @@ public abstract class RuleCase {
/** The type of this case. */
public final CaseType type;
+ public String belongsTo;
+
/**
* The list of element values for this case.
*
@@ -87,4 +89,9 @@ public abstract class RuleCase {
public IList<CaseElement> getElements() {
return elementList;
}
+
+ public String toString() {
+ return String.format("Case %d of %s", hashCode(), belongsTo);
+ }
+
}
diff --git a/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java
index 8598fbd..9c5ad1b 100755
--- a/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java
@@ -2,7 +2,9 @@ package bjc.rgens.parser.elements;
import bjc.rgens.parser.GenerationState;
import bjc.rgens.parser.GrammarException;
+import bjc.rgens.parser.RecurLimitException;
import bjc.rgens.parser.RGrammar;
+import bjc.rgens.parser.Rule;
import bjc.rgens.parser.RuleCase;
public class ExpVariableCaseElement extends VariableCaseElement {
@@ -15,9 +17,17 @@ public class ExpVariableCaseElement extends VariableCaseElement {
GenerationState newState = state.newBuf();
if (state.rules.containsKey(varDef)) {
- RuleCase destCase = state.rules.get(varDef).getCase();
+ Rule rl = state.rules.get(varDef);
- state.gram.generateCase(destCase, newState);
+ if(rl.doRecur()) {
+ RuleCase destCase = state.rules.get(varDef).getCase();
+
+ state.gram.generateCase(destCase, newState);
+
+ rl.endRecur();
+ } else {
+ throw new RecurLimitException("Rule recurrence limit exceeded");
+ }
} else if (state.importRules.containsKey(varDef)) {
RGrammar destGrammar = state.importRules.get(varDef);
@@ -40,6 +50,5 @@ public class ExpVariableCaseElement extends VariableCaseElement {
}
state.vars.put(varName, newState.contents.toString());
-
}
}
diff --git a/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java b/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java
index b4a4b58..0869a2f 100755
--- a/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java
@@ -33,9 +33,17 @@ public abstract class RuleCaseElement extends StringCaseElement {
/* :Postprocessing */
newState.contents = new StringBuilder(dst.generate(actName, state.rnd, state.vars));
} else if (state.rules.containsKey(actName)) {
- RuleCase cse = state.rules.get(actName).getCase(state.rnd);
+ Rule rl = state.rules.get(actName);
- state.gram.generateCase(cse, newState);
+ if(rl.doRecur()) {
+ RuleCase cse = rl.getCase(state.rnd);
+
+ state.gram.generateCase(cse, newState);
+
+ rl.endRecur();
+ } else {
+ throw new RecurLimitException("Rule recurrence limit exceeded");
+ }
} else if (state.importRules.containsKey(actName)) {
RGrammar dst = state.importRules.get(actName);
@@ -50,17 +58,17 @@ public abstract class RuleCaseElement extends StringCaseElement {
* Re-get this working again.
*/
/*
- if (ruleSearcher != null) {
- Set<Match<? extends String>> results = ruleSearcher.search(actName, MAX_DISTANCE);
+ if (ruleSearcher != null) {
+ Set<Match<? extends String>> results = ruleSearcher.search(actName, MAX_DISTANCE);
- String[] resArray = results.stream().map(Match::getMatch).toArray((i) -> new String[i]);
+ String[] resArray = results.stream().map(Match::getMatch).toArray((i) -> new String[i]);
- String msg = String.format("No rule '%s' defined (perhaps you meant %s?)", actName,
- StringUtils.toEnglishList(resArray, false));
+ String msg = String.format("No rule '%s' defined (perhaps you meant %s?)", actName,
+ StringUtils.toEnglishList(resArray, false));
- throw new GrammarException(msg);
- }
- */
+ throw new GrammarException(msg);
+ }
+ */
String msg = String.format("No rule '%s' defined", actName);
throw new GrammarException(msg);