summaryrefslogtreecommitdiff
path: root/RGens/src/main
diff options
context:
space:
mode:
authorstudent <student@69.161.224.76>2018-04-05 11:28:16 -0400
committerstudent <student@69.161.224.76>2018-04-05 11:28:16 -0400
commit4eb3c7dc36a05dd8b4dbcfd4e244f995c3bf800f (patch)
tree14974d1ae08340e854fa617efe4bce5800456910 /RGens/src/main
parent6aa15e30fa75211964428e386b4b6b0f2c66dbc5 (diff)
Refactor CaseElement into seperate classes
Diffstat (limited to 'RGens/src/main')
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/CaseElement.java423
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/RGrammar.java146
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/RGrammarBuilder.java1
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/RGrammarFormatter.java1
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/RGrammarParser.java1
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/RegexRuleCase.java1
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/RuleCase.java1
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/elements/BlankCaseElement.java7
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/elements/CaseElement.java149
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java7
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java7
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java7
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java43
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java7
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java41
-rw-r--r--RGens/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java60
16 files changed, 404 insertions, 498 deletions
diff --git a/RGens/src/main/java/bjc/rgens/parser/CaseElement.java b/RGens/src/main/java/bjc/rgens/parser/CaseElement.java
deleted file mode 100644
index e9e3a0a..0000000
--- a/RGens/src/main/java/bjc/rgens/parser/CaseElement.java
+++ /dev/null
@@ -1,423 +0,0 @@
-package bjc.rgens.parser;
-
-import static bjc.rgens.parser.CaseElement.ElementType.*;
-
-/*
- * @TODO 10/11/17 Ben Culkin :CaseElementSplit
- * Split this into multiple subclasses based off of a value of ElementType.
- */
-/**
- * A element in a rule case.
- *
- * @author EVE
- */
-public class CaseElement {
- /**
- * The possible types of an element.
- *
- * @author EVE
- */
- public static enum ElementType {
- /** An element that represents a literal string. */
- LITERAL,
- /** An element that represents a rule reference. */
- RULEREF,
- /** An element that represents a random range. */
- RANGE,
- /** An element that represents a variable that stores a string. */
- VARDEF,
- /**
- * An element that represents a variable that stores the result
- * of generating a rule.
- */
- EXPVARDEF;
- }
-
- /* Regexps for marking rule types. */
- private static final String SPECIAL_CASELEM = "\\{[^}]+\\}";
- private static final String REFER_CASELEM = "\\[[^\\]]+\\]";
- private static final String RANGE_CASELM = "\\[\\d+\\.\\.\\d+\\]";
-
- /** The type of this element. */
- public final ElementType type;
-
- /**
- * The literal string value of this element.
- *
- * This means that it is a string whose value should always mean the
- * same thing.
- *
- * <h2>Used For</h2>
- * <dl>
- * <dt>LITERAL</dt>
- * <dd>The string this element represents</dd>
- * <dt>RULEREF</dt>
- * <dd>The name of the rule this element references</dd>
- * </dl>
- */
- private String literalVal;
-
- /**
- * The starting integer value of this element.
- *
- * <h2>Used For</h2>
- * <dl>
- * <dt>RANGE</dt>
- * <dd>The inclusive start of the range</dd>
- * </dl>
- */
- private int start;
-
- /**
- * The starting integer value of this element.
- *
- * <h2>Used For</h2>
- * <dl>
- * <dt>RANGE</dt>
- * <dd>The inclusive end of the range</dd>
- * </dl>
- */
- private int end;
-
- /**
- * The name of the variable this element defines.
- *
- * <h2>Used For</h2>
- * <dl>
- * <dt>VARDEF</dt>
- * <dd>The name of the variable</dd>
- * <dt>EXPVARDEF</dt>
- * <dd>The name of the variable</dd>
- * </dl>
- */
- private String varName;
-
- /**
- * The definition of the variable this element defines.
- *
- * <h2>Used For</h2>
- * <dl>
- * <dt>VARDEF</dt>
- * <dd>The value of the variable</dd>
- * <dt>EXPVARDEF</dt>
- * <dd>The rule to expand for the value of this variable</dd>
- * </dl>
- */
- private String varDef;
-
- /**
- * Create a new case element.
- *
- * @param typ
- * The type of this element.
- *
- * @throws IllegalArgumentException
- * If the specified type needs parameters.
- */
- public CaseElement(ElementType typ) {
- switch (typ) {
- case LITERAL:
- case RULEREF:
- throw new IllegalArgumentException("This type requires a string parameter");
- case RANGE:
- throw new IllegalArgumentException("This type requires two integer parameters");
- case VARDEF:
- case EXPVARDEF:
- throw new IllegalArgumentException("This type requires two string parameters");
- default:
- break;
- }
-
- type = typ;
- }
-
- /**
- * Create a new case element that has a single string value.
- *
- * @param typ
- * The type of this element.
- *
- * @param val
- * The string value of this element.
- *
- * @throws IllegalArgumentException
- * If the specified type doesn't take a single string parameter.
- */
- public CaseElement(ElementType typ, String val) {
- switch (typ) {
- case LITERAL:
- case RULEREF:
- break;
- case RANGE:
- throw new IllegalArgumentException("This type requires two integer parameters");
- case VARDEF:
- case EXPVARDEF:
- throw new IllegalArgumentException("This type requires two string parameters");
- default:
- throw new IllegalArgumentException("This type doesn't have a string parameter");
- }
-
- type = typ;
-
- literalVal = val;
- }
-
- /**
- * Create a new case element that has two integer values.
- *
- * @param typ
- * The type of this element.
- *
- * @param first
- * The first integer value for this element.
- *
- * @param second
- * The second integer value for this element.
- *
- * @throws IllegalArgumentException
- * If the specified type doesn't take two integer parameters.
- */
- public CaseElement(ElementType typ, int first, int second) {
- switch (typ) {
- case LITERAL:
- case RULEREF:
- throw new IllegalArgumentException("This type requires a string parameter");
- case RANGE:
- break;
- case VARDEF:
- case EXPVARDEF:
- throw new IllegalArgumentException("This type requires two string parameters");
- default:
- throw new IllegalArgumentException("This type doesn't have two integer parameters");
- }
-
- type = typ;
-
- this.start = first;
- this.end = second;
- }
-
- /**
- * Create a new case element that has two string values.
- *
- * @param typ
- * The type of this element.
- *
- * @param name
- * The first string value for this element.
- *
- * @param def
- * The second string value for this element.
- *
- * @throws IllegalArgumentException
- * If the specified type doesn't take two string parameters.
- */
- public CaseElement(ElementType typ, String name, String def) {
- switch (typ) {
- case LITERAL:
- case RULEREF:
- throw new IllegalArgumentException("This type requires a string parameter");
- case RANGE:
- throw new IllegalArgumentException("This type requires two integer parameters");
- case VARDEF:
- case EXPVARDEF:
- break;
- default:
- throw new IllegalArgumentException("This type doesn't have two string parameters");
- }
-
- type = typ;
-
- this.varName = name;
- this.varDef = def;
- }
-
- /**
- * Get the literal string value for this element.
- *
- * @return
- * The literal string value for this element.
- *
- * @throws IllegalStateException
- * If this type doesn't have a literal string value.
- */
- public String getLiteral() {
- switch (type) {
- case LITERAL:
- case RULEREF:
- break;
- default:
- throw new IllegalStateException(
- String.format("Type '%s' doesn't have a literal string value"));
- }
-
- return literalVal;
- }
-
- /**
- * Get the starting integer value for this element.
- *
- * @return
- * The starting integer value for this element.
- *
- * @throws IllegalStateException
- * If this type doesn't have a starting integer value.
- */
- public int getStart() {
- switch (type) {
- case RANGE:
- break;
- default:
- throw new IllegalStateException(
- String.format("Type '%s' doesn't have a starting integer value", type));
- }
-
- return start;
- }
-
- /**
- * Get the ending integer value for this element.
- *
- * @return
- * The ending integer value for this element.
- *
- * @throws IllegalStateException
- * If this type doesn't have a ending integer value.
- */
- public int getEnd() {
- switch (type) {
- case RANGE:
- break;
- default:
- throw new IllegalStateException(
- String.format("Type '%s' doesn't have a ending integer value", type));
- }
-
- return end;
- }
-
- /**
- * Get the variable name for this element.
- *
- * @return
- * The variable name of this element.
- *
- * @throws IllegalStateException
- * If the type doesn't have a variable name.
- */
- public String getName() {
- switch (type) {
- case VARDEF:
- case EXPVARDEF:
- break;
- default:
- throw new IllegalStateException(String.format("Type '%s' doesn't have a name", type));
- }
-
- return varName;
- }
-
- /**
- * Get the variable definition for this element.
- *
- * @return
- * The variable definition of this element.
- *
- * @throws IllegalStateException
- * If the type doesn't have a variable definition.
- */
- public String getDefn() {
- switch (type) {
- case VARDEF:
- case EXPVARDEF:
- break;
- default:
- throw new IllegalStateException(String.format("Type '%s' doesn't have a name", type));
- }
-
- return varDef;
- }
-
- @Override
- public String toString() {
- switch (type) {
- case LITERAL:
- case RULEREF:
- return literalVal;
- case RANGE:
- return String.format("[%d..%d]", start, end);
- case VARDEF:
- return String.format("{%s:=%s}", varName, varDef);
- case EXPVARDEF:
- return String.format("{%s=%s}", varName, varDef);
- default:
- return String.format("Unknown type '%s'", type);
- }
- }
-
- /**
- * Create a case element from a string.
- *
- * @param csepart
- * The string to convert.
- *
- * @return
- * A case element representing the string.
- */
- public static CaseElement createElement(String csepart) {
- if (csepart == null) {
- throw new NullPointerException("Case part cannot be null");
- }
-
- if (csepart.matches(SPECIAL_CASELEM)) {
- /* Handle special cases. */
- String specialBody = csepart.substring(1, csepart.length() - 1);
-
- System.out.printf("\t\tTRACE: special body is '%s'\n", specialBody);
-
- if (specialBody.matches("\\S+:=\\S+")) {
- /* Handle expanding variable definitions. */
- String[] parts = specialBody.split(":=");
-
- if (parts.length != 2) {
- String msg = "Expanded variables must be a name and a definition, seperated by :=";
-
- throw new GrammarException(msg);
- }
-
- return new CaseElement(EXPVARDEF, parts[0], parts[1]);
- } else if (specialBody.matches("\\S+=\\S+")) {
- /* Handle regular variable definitions. */
- String[] parts = specialBody.split("=");
-
- if (parts.length != 2) {
- String msg = "Variables must be a name and a definition, seperated by =";
-
- throw new GrammarException(msg);
- }
-
- return new CaseElement(VARDEF, parts[0], parts[1]);
- } else if (specialBody.matches("{empty}")) {
- /* Literal blank, for empty cases. */
- return new CaseElement(LITERAL, "");
- } else {
- throw new IllegalArgumentException(
- String.format("Unknown special case part '%s'", specialBody));
- }
- } else if (csepart.matches(REFER_CASELEM)) {
- if (csepart.matches(RANGE_CASELM)) {
- /* Handle ranges */
- String rawRange = csepart.substring(1, csepart.length() - 1);
-
- int firstNum = Integer.parseInt(rawRange.substring(0, rawRange.indexOf('.')));
- int secondNum = Integer.parseInt(rawRange.substring(rawRange.lastIndexOf('.') + 1));
-
- return new CaseElement(RANGE, firstNum, secondNum);
- }
-
- return new CaseElement(RULEREF, csepart);
- } else {
- return new CaseElement(LITERAL, csepart);
- }
- }
-}
diff --git a/RGens/src/main/java/bjc/rgens/parser/RGrammar.java b/RGens/src/main/java/bjc/rgens/parser/RGrammar.java
index 17ca4fe..38f38c8 100644
--- a/RGens/src/main/java/bjc/rgens/parser/RGrammar.java
+++ b/RGens/src/main/java/bjc/rgens/parser/RGrammar.java
@@ -1,5 +1,10 @@
package bjc.rgens.parser;
+import bjc.rgens.parser.elements.CaseElement;
+import bjc.rgens.parser.elements.LiteralCaseElement;
+import bjc.rgens.parser.elements.RangeCaseElement;
+import bjc.rgens.parser.elements.RuleCaseElement;
+import bjc.rgens.parser.elements.VariableCaseElement;
import bjc.utils.funcutils.StringUtils;
import java.util.HashMap;
@@ -48,8 +53,8 @@ public class RGrammar {
/* The current string. */
public StringBuilder contents;
/* The RNG. */
- public Random rnd;
-
+ public Random rnd;
+
/* The current set of variables. */
public Map<String, String> vars;
@@ -57,13 +62,13 @@ public class RGrammar {
* Create a new generation state.
*
* @param cont
- * The string being generated.
+ * The string being generated.
*
* @param rand
- * The RNG to use.
+ * The RNG to use.
*
* @param vs
- * The variables to use.
+ * The variables to use.
*/
public GenerationState(StringBuilder cont, Random rand, Map<String, String> vs) {
contents = cont;
@@ -76,14 +81,14 @@ public class RGrammar {
private static Pattern NAMEVAR_PATTERN = Pattern.compile("\\$(\\w+)");
/* The rules of the grammar. */
- private Map<String, Rule> rules;
+ private Map<String, Rule> rules;
/* The rules imported from other grammars. */
- private Map<String, RGrammar> importRules;
+ private Map<String, RGrammar> importRules;
/* The rules exported from this grammar. */
- private Set<String> exportRules;
+ private Set<String> exportRules;
/* The initial rule of this grammar. */
- private String initialRule;
-
+ private String initialRule;
+
/* The tree to use for finding rule suggestions. */
private BkTreeSearcher<String> ruleSearcher;
@@ -91,7 +96,7 @@ public class RGrammar {
* Create a new randomized grammar using the specified set of rules.
*
* @param ruls
- * The rules to use.
+ * The rules to use.
*/
public RGrammar(Map<String, Rule> ruls) {
rules = ruls;
@@ -100,19 +105,18 @@ public class RGrammar {
/**
* Sets the imported rules to use.
*
- * Imported rules are checked for rule definitions after local
- * definitions are checked.
+ * Imported rules are checked for rule definitions after local definitions are
+ * checked.
*
* @param importedRules
- * The set of imported rules to use.
+ * The set of imported rules to use.
*/
public void setImportedRules(Map<String, RGrammar> importedRules) {
importRules = importedRules;
}
/**
- * Generates the data structure backing rule suggestions for unknown
- * rules.
+ * Generates the data structure backing rule suggestions for unknown rules.
*/
public void generateSuggestions() {
MutableBkTree<String> ruleSuggester = new MutableBkTree<>(new LevenshteinMetric());
@@ -124,44 +128,39 @@ public class RGrammar {
}
/**
- * Generate a string from this grammar, starting from the specified
- * rule.
+ * Generate a string from this grammar, starting from the specified rule.
*
* @param startRule
- * The rule to start generating at, or null to use the initial rule
- * for this grammar.
+ * The rule to start generating at, or null to use the initial rule
+ * for this grammar.
*
- * @return
- * A possible string from the grammar.
+ * @return A possible string from the grammar.
*/
public String generate(String startRule) {
return generate(startRule, new Random(), new HashMap<>());
}
/**
- * Generate a string from this grammar, starting from the specified
- * rule.
+ * Generate a string from this grammar, starting from the specified rule.
*
* @param startRule
- * The rule to start generating at, or null to use the initial rule
- * for this grammar.
+ * The rule to start generating at, or null to use the initial rule
+ * for this grammar.
*
* @param rnd
- * The random number generator to use.
+ * The random number generator to use.
*
* @param vars
- * The set of variables to use.
+ * The set of variables to use.
*
- * @return
- * A possible string from the grammar.
+ * @return A possible string from the grammar.
*/
public String generate(String startRule, Random rnd, Map<String, String> vars) {
String fromRule = startRule;
if (startRule == null) {
if (initialRule == null) {
- throw new GrammarException(
- "Must specify a start rule for grammars with no initial rule");
+ throw new GrammarException("Must specify a start rule for grammars with no initial rule");
}
fromRule = initialRule;
@@ -186,8 +185,7 @@ public class RGrammar {
/*
* Remove extraneous spaces around punctutation marks.
*
- * This can be done in the grammars, but it is very tedious to
- * do so.
+ * This can be done in the grammars, but it is very tedious to do so.
*/
/* Handle 's */
@@ -212,8 +210,9 @@ public class RGrammar {
*/
body = body.replaceAll("\\s+", " ");
- /* @TODO 11/01/17 Ben Culkin :RegexRule
- * Replace this once it is no longer needed.
+ /*
+ * @TODO 11/01/17 Ben Culkin :RegexRule Replace this once it is no longer
+ * needed.
*/
body = body.replaceAll("\\s(ish|burg|ton|ville|opolis|field|boro|dale)", "$1");
@@ -228,7 +227,7 @@ public class RGrammar {
for (CaseElement elm : start.getElements()) {
generateElement(elm, state);
- if(elm.type != CaseElement.ElementType.VARDEF) {
+ if (elm.type != CaseElement.ElementType.VARDEF) {
state.contents.append(" ");
}
}
@@ -252,26 +251,32 @@ public class RGrammar {
private void generateElement(CaseElement elm, GenerationState state) {
try {
switch (elm.type) {
- case LITERAL:
- state.contents.append(elm.getLiteral());
+ case LITERAL: {
+ LiteralCaseElement lit = (LiteralCaseElement)elm;
+
+ state.contents.append(lit.val);
break;
- case RULEREF:
- generateRuleReference(elm, state);
+ }
+ case RULEREF: {
+ RuleCaseElement rle = (RuleCaseElement)elm;
+
+ generateRuleReference(rle, state);
break;
- case RANGE:
- int start = elm.getStart();
- int end = elm.getEnd();
+ }
+ case RANGE: {
+ RangeCaseElement rang = (RangeCaseElement)elm;
- int val = state.rnd.nextInt(end - start);
- val += start;
+ int val = state.rnd.nextInt(rang.end - rang.begin);
+ val += rang.begin;
state.contents.append(val);
break;
+ }
case VARDEF:
- generateVarDef(elm.getName(), elm.getDefn(), state);
+ generateVarDef(((VariableCaseElement)elm).varName, ((VariableCaseElement)elm).varDef, state);
break;
case EXPVARDEF:
- generateExpVarDef(elm.getName(), elm.getDefn(), state);
+ generateExpVarDef(((VariableCaseElement)elm).varName, ((VariableCaseElement)elm).varDef, state);
break;
default:
String msg = String.format("Unknown element type '%s'", elm.type);
@@ -285,8 +290,7 @@ public class RGrammar {
/* Generate a expanding variable definition. */
private void generateExpVarDef(String name, String defn, GenerationState state) {
- GenerationState newState = new GenerationState(
- new StringBuilder(), state.rnd, state.vars);
+ GenerationState newState = new GenerationState(new StringBuilder(), state.rnd, state.vars);
if (rules.containsKey(defn)) {
RuleCase destCase = rules.get(defn).getCase();
@@ -294,7 +298,7 @@ public class RGrammar {
generateCase(destCase, newState);
} else if (importRules.containsKey(defn)) {
RGrammar destGrammar = importRules.get(defn);
- String res = destGrammar.generate(defn, state.rnd, state.vars);
+ String res = destGrammar.generate(defn, state.rnd, state.vars);
newState.contents.append(res);
} else {
@@ -311,11 +315,10 @@ public class RGrammar {
}
/* Generate a rule reference. */
- private void generateRuleReference(CaseElement elm, GenerationState state) {
- String refersTo = elm.getLiteral();
+ private void generateRuleReference(RuleCaseElement elm, GenerationState state) {
+ String refersTo = elm.val;
- GenerationState newState = new GenerationState(
- new StringBuilder(), state.rnd, state.vars);
+ GenerationState newState = new GenerationState(new StringBuilder(), state.rnd, state.vars);
if (refersTo.contains("$")) {
/* Parse variables */
@@ -338,11 +341,9 @@ public class RGrammar {
String name = state.vars.get(var);
if (name.contains(" ")) {
- throw new GrammarException(
- "Variables substituted into names cannot contain spaces");
+ throw new GrammarException("Variables substituted into names cannot contain spaces");
} else if (name.equals("")) {
- throw new GrammarException(
- "Variables substituted into names cannot be empty");
+ throw new GrammarException("Variables substituted into names cannot be empty");
}
nameMatcher.appendReplacement(nameBuffer, name);
@@ -370,7 +371,7 @@ public class RGrammar {
}
}
- if(refersTo.startsWith("[^")) {
+ if (refersTo.startsWith("[^")) {
refersTo = "[" + refersTo.substring(2);
RGrammar dst = importRules.get(refersTo);
@@ -388,11 +389,10 @@ public class RGrammar {
if (ruleSearcher != null) {
Set<Match<? extends String>> results = ruleSearcher.search(refersTo, 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?)",
- refersTo, StringUtils.toEnglishList(resArray, false));
+ String msg = String.format("No rule '%s' defined (perhaps you meant %s?)", refersTo,
+ StringUtils.toEnglishList(resArray, false));
throw new GrammarException(msg);
}
@@ -412,8 +412,7 @@ public class RGrammar {
/**
* Get the initial rule of this grammar.
*
- * @return
- * The initial rule of this grammar.
+ * @return The initial rule of this grammar.
*/
public String getInitialRule() {
return initialRule;
@@ -423,8 +422,8 @@ public class RGrammar {
* Set the initial rule of this grammar.
*
* @param initRule
- * The initial rule of this grammar, or null to say there is no
- * initial rule.
+ * The initial rule of this grammar, or null to say there is no
+ * initial rule.
*/
public void setInitialRule(String initRule) {
/* Passing null, nulls our initial rule. */
@@ -449,16 +448,14 @@ public class RGrammar {
*
* The initial rule is exported by default if specified.
*
- * @return
- * The rules exported by this grammar.
+ * @return The rules exported by this grammar.
*/
public Set<Rule> getExportedRules() {
Set<Rule> res = new HashSet<>();
for (String rname : exportRules) {
if (!rules.containsKey(rname)) {
- String msg = String.format("No rule '%s' local to this grammar defined",
- initialRule);
+ String msg = String.format("No rule '%s' local to this grammar defined", initialRule);
throw new GrammarException(msg);
}
@@ -477,7 +474,7 @@ public class RGrammar {
* Set the rules exported by this grammar.
*
* @param exportedRules
- * The rules exported by this grammar.
+ * The rules exported by this grammar.
*/
public void setExportedRules(Set<String> exportedRules) {
exportRules = exportedRules;
@@ -486,8 +483,7 @@ public class RGrammar {
/**
* Get all the rules in this grammar.
*
- * @return
- * All the rules in this grammar.
+ * @return All the rules in this grammar.
*/
public Map<String, Rule> getRules() {
return rules;
diff --git a/RGens/src/main/java/bjc/rgens/parser/RGrammarBuilder.java b/RGens/src/main/java/bjc/rgens/parser/RGrammarBuilder.java
index 096decf..b4cb04a 100644
--- a/RGens/src/main/java/bjc/rgens/parser/RGrammarBuilder.java
+++ b/RGens/src/main/java/bjc/rgens/parser/RGrammarBuilder.java
@@ -1,5 +1,6 @@
package bjc.rgens.parser;
+import bjc.rgens.parser.elements.CaseElement;
import bjc.utils.funcdata.FunctionalList;
import bjc.utils.funcdata.IList;
diff --git a/RGens/src/main/java/bjc/rgens/parser/RGrammarFormatter.java b/RGens/src/main/java/bjc/rgens/parser/RGrammarFormatter.java
index 96bdee8..a2454dc 100644
--- a/RGens/src/main/java/bjc/rgens/parser/RGrammarFormatter.java
+++ b/RGens/src/main/java/bjc/rgens/parser/RGrammarFormatter.java
@@ -1,5 +1,6 @@
package bjc.rgens.parser;
+import bjc.rgens.parser.elements.CaseElement;
import bjc.utils.funcdata.IList;
import java.util.HashSet;
diff --git a/RGens/src/main/java/bjc/rgens/parser/RGrammarParser.java b/RGens/src/main/java/bjc/rgens/parser/RGrammarParser.java
index 83b295a..cffb896 100644
--- a/RGens/src/main/java/bjc/rgens/parser/RGrammarParser.java
+++ b/RGens/src/main/java/bjc/rgens/parser/RGrammarParser.java
@@ -1,5 +1,6 @@
package bjc.rgens.parser;
+import bjc.rgens.parser.elements.CaseElement;
import bjc.utils.funcdata.FunctionalList;
import bjc.utils.funcdata.IList;
import bjc.utils.funcutils.TriConsumer;
diff --git a/RGens/src/main/java/bjc/rgens/parser/RegexRuleCase.java b/RGens/src/main/java/bjc/rgens/parser/RegexRuleCase.java
index 82417da..5e03cd6 100644
--- a/RGens/src/main/java/bjc/rgens/parser/RegexRuleCase.java
+++ b/RGens/src/main/java/bjc/rgens/parser/RegexRuleCase.java
@@ -1,5 +1,6 @@
package bjc.rgens.parser;
+import bjc.rgens.parser.elements.CaseElement;
import bjc.utils.funcdata.IList;
import java.util.regex.Pattern;
diff --git a/RGens/src/main/java/bjc/rgens/parser/RuleCase.java b/RGens/src/main/java/bjc/rgens/parser/RuleCase.java
index 764fa89..9c0a856 100644
--- a/RGens/src/main/java/bjc/rgens/parser/RuleCase.java
+++ b/RGens/src/main/java/bjc/rgens/parser/RuleCase.java
@@ -1,5 +1,6 @@
package bjc.rgens.parser;
+import bjc.rgens.parser.elements.CaseElement;
import bjc.utils.funcdata.IList;
/*
diff --git a/RGens/src/main/java/bjc/rgens/parser/elements/BlankCaseElement.java b/RGens/src/main/java/bjc/rgens/parser/elements/BlankCaseElement.java
new file mode 100644
index 0000000..7229e92
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/parser/elements/BlankCaseElement.java
@@ -0,0 +1,7 @@
+package bjc.rgens.parser.elements;
+
+public class BlankCaseElement extends LiteralCaseElement {
+ public BlankCaseElement() {
+ super("");
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/parser/elements/CaseElement.java b/RGens/src/main/java/bjc/rgens/parser/elements/CaseElement.java
new file mode 100644
index 0000000..7cad599
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/parser/elements/CaseElement.java
@@ -0,0 +1,149 @@
+package bjc.rgens.parser.elements;
+
+import static bjc.rgens.parser.elements.CaseElement.ElementType.*;
+
+import bjc.rgens.parser.GrammarException;
+
+/*
+ * @TODO 10/11/17 Ben Culkin :CaseElementSplit Split this into multiple
+ * subclasses based off of a value of ElementType.
+ */
+/**
+ * A element in a rule case.
+ *
+ * @author EVE
+ */
+public class CaseElement {
+ /**
+ * The possible types of an element.
+ *
+ * @author EVE
+ */
+ public static enum ElementType {
+ /** An element that represents a literal string. */
+ LITERAL,
+ /** An element that represents a rule reference. */
+ RULEREF,
+ /** An element that represents a random range. */
+ RANGE,
+ /** An element that represents a variable that stores a string. */
+ VARDEF,
+ /**
+ * An element that represents a variable that stores the result of generating a
+ * rule.
+ */
+ EXPVARDEF;
+ }
+
+ /* Regexps for marking rule types. */
+ private static final String SPECIAL_CASELEM = "\\{[^}]+\\}";
+ private static final String REFER_CASELEM = "\\[[^\\]]+\\]";
+ private static final String RANGE_CASELM = "\\[\\d+\\.\\.\\d+\\]";
+
+ /** The type of this element. */
+ public final ElementType type;
+
+ /**
+ * Create a new case element.
+ *
+ * @param typ
+ * The type of this element.
+ */
+ protected CaseElement(ElementType typ) {
+ type = typ;
+ }
+
+ @Override
+ public String toString() {
+ switch (type) {
+ default:
+ return String.format("Unknown type '%s'", type);
+ }
+ }
+
+ /**
+ * Create a case element from a string.
+ *
+ * @param csepart
+ * The string to convert.
+ *
+ * @return A case element representing the string.
+ */
+ public static CaseElement createElement(String csepart) {
+ if (csepart == null) {
+ throw new NullPointerException("Case part cannot be null");
+ }
+
+ if (csepart.matches(SPECIAL_CASELEM)) {
+ /* Handle special cases. */
+ String specialBody = csepart.substring(1, csepart.length() - 1);
+
+ System.out.printf("\t\tTRACE: special body is '%s'\n", specialBody);
+
+ if (specialBody.matches("\\S+:=\\S+")) {
+ /* Handle expanding variable definitions. */
+ String[] parts = specialBody.split(":=");
+
+ if (parts.length != 2) {
+ String msg = "Expanded variables must be a name and a definition, seperated by :=";
+
+ throw new GrammarException(msg);
+ }
+
+ return new ExpVariableCaseElement(parts[0], parts[1]);
+ } else if (specialBody.matches("\\S+=\\S+")) {
+ /* Handle regular variable definitions. */
+ String[] parts = specialBody.split("=");
+
+ if (parts.length != 2) {
+ String msg = "Variables must be a name and a definition, seperated by =";
+
+ throw new GrammarException(msg);
+ }
+
+ return new LitVariableCaseElement(parts[0], parts[1]);
+ } else if (specialBody.matches("{empty}")) {
+ /* Literal blank, for empty cases. */
+ return new BlankCaseElement();
+ } else {
+ throw new IllegalArgumentException(String.format("Unknown special case part '%s'", specialBody));
+ }
+ } else if (csepart.matches(REFER_CASELEM)) {
+ if (csepart.matches(RANGE_CASELM)) {
+ /* Handle ranges */
+ String rawRange = csepart.substring(1, csepart.length() - 1);
+
+ int firstNum = Integer.parseInt(rawRange.substring(0, rawRange.indexOf('.')));
+ int secondNum = Integer.parseInt(rawRange.substring(rawRange.lastIndexOf('.') + 1));
+
+ return new RangeCaseElement(firstNum, secondNum);
+ }
+
+ return new RuleCaseElement(csepart);
+ } else {
+ return new LiteralCaseElement(csepart);
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((type == null) ? 0 : type.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ CaseElement other = (CaseElement) obj;
+ if (type != other.type)
+ return false;
+ return true;
+ }
+} \ No newline at end of file
diff --git a/RGens/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java b/RGens/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java
new file mode 100644
index 0000000..30925e2
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java
@@ -0,0 +1,7 @@
+package bjc.rgens.parser.elements;
+
+public class ExpVariableCaseElement extends VariableCaseElement {
+ public ExpVariableCaseElement(String name, String def) {
+ super(name, def, true);
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java b/RGens/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java
new file mode 100644
index 0000000..11035b1
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java
@@ -0,0 +1,7 @@
+package bjc.rgens.parser.elements;
+
+public class LitVariableCaseElement extends VariableCaseElement {
+ public LitVariableCaseElement(String name, String def) {
+ super(name, def, false);
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java b/RGens/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java
new file mode 100644
index 0000000..d96a32d
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java
@@ -0,0 +1,7 @@
+package bjc.rgens.parser.elements;
+
+public class LiteralCaseElement extends StringCaseElement {
+ public LiteralCaseElement(String vl) {
+ super(vl, true);
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java b/RGens/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java
new file mode 100644
index 0000000..d98bc61
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java
@@ -0,0 +1,43 @@
+package bjc.rgens.parser.elements;
+
+public class RangeCaseElement extends CaseElement {
+ public final int begin;
+ public final int end;
+
+ public RangeCaseElement(int beg, int en) {
+ super(ElementType.RANGE);
+
+ begin = beg;
+ end = en;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + begin;
+ result = prime * result + end;
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ RangeCaseElement other = (RangeCaseElement) obj;
+ if (begin != other.begin)
+ return false;
+ if (end != other.end)
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("[%d..%d]", begin, end);
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java b/RGens/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java
new file mode 100644
index 0000000..f4d3512
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java
@@ -0,0 +1,7 @@
+package bjc.rgens.parser.elements;
+
+public class RuleCaseElement extends StringCaseElement {
+ public RuleCaseElement(String vl) {
+ super(vl, false);
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java b/RGens/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java
new file mode 100644
index 0000000..0e64fd3
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java
@@ -0,0 +1,41 @@
+package bjc.rgens.parser.elements;
+
+public class StringCaseElement extends CaseElement {
+ public final String val;
+
+ protected StringCaseElement(String vl, boolean isLiteral) {
+ super(isLiteral ? ElementType.LITERAL : ElementType.RULEREF);
+
+ val = vl;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + ((val == null) ? 0 : val.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ StringCaseElement other = (StringCaseElement) obj;
+ if (val == null) {
+ if (other.val != null)
+ return false;
+ } else if (!val.equals(other.val))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return val;
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java b/RGens/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java
new file mode 100644
index 0000000..920445a
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java
@@ -0,0 +1,60 @@
+package bjc.rgens.parser.elements;
+
+public class VariableCaseElement extends CaseElement {
+ /**
+ * The name of the variable this element defines.
+ */
+ public final String varName;
+
+ /**
+ * The definition of the variable this element defines.
+ */
+ public final String varDef;
+
+ public VariableCaseElement(String name, String def, boolean isExp) {
+ super(isExp ? ElementType.EXPVARDEF : ElementType.VARDEF);
+
+ varName = name;
+ varDef = def;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + ((varDef == null) ? 0 : varDef.hashCode());
+ result = prime * result + ((varName == null) ? 0 : varName.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (!super.equals(obj))
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ VariableCaseElement other = (VariableCaseElement) obj;
+ if (varDef == null) {
+ if (other.varDef != null)
+ return false;
+ } else if (!varDef.equals(other.varDef))
+ return false;
+ if (varName == null) {
+ if (other.varName != null)
+ return false;
+ } else if (!varName.equals(other.varName))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ if (type == ElementType.VARDEF) {
+ return String.format("{%s:=%s}", varName, varDef);
+ } else {
+ return String.format("{%s=%s}", varName, varDef);
+ }
+ }
+}