summaryrefslogtreecommitdiff
path: root/src/main/java/bjc/rgens/parser/elements
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/bjc/rgens/parser/elements')
-rwxr-xr-x[-rw-r--r--]src/main/java/bjc/rgens/parser/elements/BlankCaseElement.java2
-rwxr-xr-x[-rw-r--r--]src/main/java/bjc/rgens/parser/elements/CaseElement.java143
-rw-r--r--src/main/java/bjc/rgens/parser/elements/ChanceCaseElement.java20
-rwxr-xr-x[-rw-r--r--]src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java37
-rw-r--r--src/main/java/bjc/rgens/parser/elements/InlineRuleCaseElement.java41
-rwxr-xr-x[-rw-r--r--]src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java10
-rw-r--r--src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java16
-rwxr-xr-x[-rw-r--r--]src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java11
-rwxr-xr-x[-rw-r--r--]src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java100
-rw-r--r--src/main/java/bjc/rgens/parser/elements/RuleVariableCaseElement.java39
-rw-r--r--src/main/java/bjc/rgens/parser/elements/SerialCaseElement.java30
-rwxr-xr-x[-rw-r--r--]src/main/java/bjc/rgens/parser/elements/StringCaseElement.java6
-rwxr-xr-x[-rw-r--r--]src/main/java/bjc/rgens/parser/elements/VariableDefCaseElement.java (renamed from src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java)24
-rw-r--r--src/main/java/bjc/rgens/parser/elements/vars/ARefVariableElement.java31
-rw-r--r--src/main/java/bjc/rgens/parser/elements/vars/LiteralVariableElement.java17
-rw-r--r--src/main/java/bjc/rgens/parser/elements/vars/RRefVariableElement.java31
-rw-r--r--src/main/java/bjc/rgens/parser/elements/vars/TRefVariableElement.java42
-rw-r--r--src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java27
-rw-r--r--src/main/java/bjc/rgens/parser/elements/vars/VariableElement.java71
19 files changed, 618 insertions, 80 deletions
diff --git a/src/main/java/bjc/rgens/parser/elements/BlankCaseElement.java b/src/main/java/bjc/rgens/parser/elements/BlankCaseElement.java
index 7229e92..66ff310 100644..100755
--- a/src/main/java/bjc/rgens/parser/elements/BlankCaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/BlankCaseElement.java
@@ -1,5 +1,7 @@
package bjc.rgens.parser.elements;
+import bjc.rgens.parser.GenerationState;
+
public class BlankCaseElement extends LiteralCaseElement {
public BlankCaseElement() {
super("");
diff --git a/src/main/java/bjc/rgens/parser/elements/CaseElement.java b/src/main/java/bjc/rgens/parser/elements/CaseElement.java
index d74ab52..a44ef6c 100644..100755
--- a/src/main/java/bjc/rgens/parser/elements/CaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/CaseElement.java
@@ -1,17 +1,16 @@
package bjc.rgens.parser.elements;
+import bjc.utils.funcutils.StringUtils;
+
+import bjc.rgens.parser.GenerationState;
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 {
+public abstract class CaseElement {
/**
* The possible types of an element.
*
@@ -19,27 +18,27 @@ public class CaseElement {
*/
public static enum ElementType {
/** An element that represents a literal string. */
- LITERAL,
+ LITERAL(true),
/** An element that represents a rule reference. */
- RULEREF,
+ RULEREF(true),
/** An element that represents a random range. */
- RANGE,
+ RANGE(true),
/** 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;
- }
+ VARIABLE(false);
- /* 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+\\]";
+ public final boolean spacing;
+
+ private ElementType(boolean spacing) {
+ this.spacing = spacing;
+ }
+ }
/** The type of this element. */
- public final ElementType type;
+ public boolean spacing;
+
+ protected CaseElement() {
+ this(true);
+ }
/**
* Create a new case element.
@@ -47,17 +46,17 @@ public class CaseElement {
* @param typ
* The type of this element.
*/
- protected CaseElement(ElementType typ) {
- type = typ;
+ protected CaseElement(boolean spacing) {
+ this.spacing = spacing;
}
- @Override
- public String toString() {
- switch (type) {
- default:
- return String.format("Unknown type '%s'", type);
- }
- }
+ /**
+ * Generate this case element.
+ *
+ * @param state
+ * The current state of generation.
+ */
+ public abstract void generate(GenerationState state);
/**
* Create a case element from a string.
@@ -72,52 +71,80 @@ public class CaseElement {
throw new NullPointerException("Case part cannot be null");
}
- if (csepart.matches(SPECIAL_CASELEM)) {
- /* Handle special cases. */
+ if (csepart.matches("\\(\\S+\\)")) {
+ return createElement(csepart.substring(1, csepart.length() - 1));
+ } else if (csepart.matches("\\{\\S+\\}")) {
+ /*
+ * Handle special case elements.
+ *
+ */
String specialBody = csepart.substring(1, csepart.length() - 1);
- System.out.printf("\t\tTRACE: special body is '%s'\n", specialBody);
+ if (specialBody.matches("\\S+:\\S=\\S+")) {
+ String[] parts = StringUtils.levelSplit(specialBody, "=").toArray(new String[0]);
- if (specialBody.matches("\\S+:=\\S+")) {
- /* Handle expanding variable definitions. */
- String[] parts = specialBody.split(":=");
+ if(parts.length != 2) {
+ throw new GrammarException("Colon variables must have a name and a definition");
+ }
+
+ String varName = parts[0];
+
+ char op = varName.charAt(varName.length() - 1);
+
+ System.err.printf("\t\tTRACE: Colon definition w/ op %d", (int)op);
- if (parts.length != 2) {
- String msg = "Expanded variables must be a name and a definition, seperated by :=";
+ // Remove the colon, plus any tacked on operator
+ varName = varName.substring(0, varName.length() - 2);
- throw new GrammarException(msg);
+ return VariableDefCaseElement.parseVariable(varName, parts[1], op, true);
+ } else if (specialBody.matches("\\S+:=\\S+")) {
+ String[] parts = StringUtils.levelSplit(specialBody, "=").toArray(new String[0]);
+
+ if(parts.length != 2) {
+ throw new GrammarException("Colon variables must have a name and a definition");
}
- return new ExpVariableCaseElement(parts[0], parts[1]);
- } else if (specialBody.matches("\\S+=\\S+")) {
- /* Handle regular variable definitions. */
- String[] parts = specialBody.split("=");
+ String varName = parts[0];
- if (parts.length != 2) {
- String msg = "Variables must be a name and a definition, seperated by =";
+ varName = varName.substring(0, varName.length() - 1);
- throw new GrammarException(msg);
+ return VariableDefCaseElement.parseVariable(varName, parts[1], ' ', true);
+ } else if (specialBody.matches("\\S+=\\S+")) {
+ String[] parts = specialBody.split("=");
+ if(parts.length != 2) {
+ throw new GrammarException("Variables must have a name and a definition");
}
- return new LitVariableCaseElement(parts[0], parts[1]);
- } else if (specialBody.matches("{empty}")) {
+ // Non-colon variables can't take an operator
+ return VariableDefCaseElement.parseVariable(parts[0], parts[1], (char)0, false);
+ } 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);
+ } else if (csepart.matches("\\[\\S+\\]")) {
+ String rawCase = csepart.substring(1, csepart.length() - 1);
- int firstNum = Integer.parseInt(rawRange.substring(0, rawRange.indexOf('.')));
- int secondNum = Integer.parseInt(rawRange.substring(rawRange.lastIndexOf('.') + 1));
+ if (rawCase.matches("\\d+\\.{2}\\d+")) {
+ int firstNum = Integer.parseInt(rawCase.substring(0, rawCase.indexOf('.')));
+ int secondNum = Integer.parseInt(rawCase.substring(rawCase.lastIndexOf('.') + 1));
return new RangeCaseElement(firstNum, secondNum);
- }
+ } else if(rawCase.contains("||")) {
+ String[] elms = StringUtils.levelSplit(rawCase, "||").toArray(new String[0]);
- return new RuleCaseElement(csepart);
+ return new InlineRuleCaseElement(elms);
+ } else if(rawCase.contains("|")) {
+ throw new GrammarException("\t\tERROR: Inline rule using | found, they use || now");
+
+ // String[] elms = StringUtils.levelSplit(rawCase, "|").toArray(new String[0]);
+ // return new InlineRuleCaseElement(elms);
+ } else {
+ return new RuleCaseElement(rawCase);
+ }
+ } else if(csepart.startsWith("%") && !csepart.equals("%")) {
+ return new RuleCaseElement(csepart);
} else {
return new LiteralCaseElement(csepart);
}
@@ -127,7 +154,7 @@ public class CaseElement {
public int hashCode() {
final int prime = 31;
int result = 1;
- result = prime * result + ((type == null) ? 0 : type.hashCode());
+ result = prime * result + (spacing ? 0 : 2);
return result;
}
@@ -140,8 +167,8 @@ public class CaseElement {
if (getClass() != obj.getClass())
return false;
CaseElement other = (CaseElement) obj;
- if (type != other.type)
+ if (spacing != other.spacing)
return false;
return true;
}
-} \ No newline at end of file
+}
diff --git a/src/main/java/bjc/rgens/parser/elements/ChanceCaseElement.java b/src/main/java/bjc/rgens/parser/elements/ChanceCaseElement.java
new file mode 100644
index 0000000..483a103
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/elements/ChanceCaseElement.java
@@ -0,0 +1,20 @@
+package bjc.rgens.parser.elements;
+
+import bjc.rgens.parser.GenerationState;
+
+public class ChanceCaseElement extends CaseElement {
+ public final CaseElement elm;
+
+ public int chance;
+
+ public ChanceCaseElement(CaseElement elm, int chance) {
+ super(elm.spacing);
+
+ this.elm = elm;
+ this.chance = chance;
+ }
+
+ public void generate(GenerationState state) {
+ if(state.rnd.nextInt(chance) == 0) elm.generate(state);
+ }
+}
diff --git a/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java
index 30925e2..e58d073 100644..100755
--- a/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java
@@ -1,7 +1,40 @@
package bjc.rgens.parser.elements;
-public class ExpVariableCaseElement extends VariableCaseElement {
+import bjc.utils.data.IPair;
+
+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 VariableDefCaseElement {
public ExpVariableCaseElement(String name, String def) {
- super(name, def, true);
+ super(name, def);
+ }
+
+ @Override
+ public void generate(GenerationState state) {
+ GenerationState newState = state.newBuf();
+
+ Rule rl = state.findRule(varDef, true);
+
+ if(rl != null) {
+ RGrammar destGrammar = rl.belongsTo;
+ newState.swapGrammar(destGrammar);
+ /*
+ * Don't post-process the string, we should only do that
+ * once.
+ */
+ String res = destGrammar.generate(varDef, state, false);
+
+ newState.contents = new StringBuilder(res);
+ } else {
+ String msg = String.format("No rule '%s' defined", varDef);
+ throw new GrammarException(msg);
+ }
+
+ state.vars.put(varName, newState.contents.toString());
}
}
diff --git a/src/main/java/bjc/rgens/parser/elements/InlineRuleCaseElement.java b/src/main/java/bjc/rgens/parser/elements/InlineRuleCaseElement.java
new file mode 100644
index 0000000..917dd33
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/elements/InlineRuleCaseElement.java
@@ -0,0 +1,41 @@
+package bjc.rgens.parser.elements;
+
+import bjc.rgens.parser.GenerationState;
+import bjc.rgens.parser.RGrammarParser;
+
+import bjc.utils.data.IPair;
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.funcdata.IList;
+import bjc.utils.funcutils.StringUtils;
+import bjc.utils.gen.WeightedRandom;
+
+public class InlineRuleCaseElement extends CaseElement {
+ public final WeightedRandom<CaseElement> elements;
+
+ public InlineRuleCaseElement(String... parts) {
+ super(true);
+
+ this.elements = new WeightedRandom<>();
+
+ for(String part : parts) {
+ String[] partArr;
+
+ if(StringUtils.levelContains(part, "|")) {
+ partArr = StringUtils.levelSplit(part, "||").toArray(new String[0]);
+ } else {
+ partArr = new String[] {part};
+ }
+
+ IPair<IList<CaseElement>, Integer> par = RGrammarParser.parseElementString(partArr);
+ int prob = par.getRight();
+
+ for(CaseElement elm : par.getLeft()) {
+ elements.addProbability(prob, elm);
+ }
+ }
+ }
+
+ public void generate(GenerationState state) {
+ elements.generateValue(state.rnd).generate(state);
+ }
+}
diff --git a/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java
index 11035b1..3c6ba98 100644..100755
--- a/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java
@@ -1,7 +1,13 @@
package bjc.rgens.parser.elements;
-public class LitVariableCaseElement extends VariableCaseElement {
+import bjc.rgens.parser.GenerationState;
+
+public class LitVariableCaseElement extends VariableDefCaseElement {
public LitVariableCaseElement(String name, String def) {
- super(name, def, false);
+ super(name, def);
+ }
+
+ public void generate(GenerationState state) {
+ state.vars.put(varName, varDef);
}
}
diff --git a/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java b/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java
index d96a32d..6e0f8fd 100644
--- a/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java
@@ -1,7 +1,17 @@
package bjc.rgens.parser.elements;
-public class LiteralCaseElement extends StringCaseElement {
- public LiteralCaseElement(String vl) {
- super(vl, true);
+import bjc.rgens.parser.GenerationState;
+
+public class LiteralCaseElement extends CaseElement {
+ public String val;
+
+ public LiteralCaseElement(String val) {
+ super(true);
+
+ this.val = val;
+ }
+
+ public void generate(GenerationState state) {
+ state.contents.append(val);
}
}
diff --git a/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java b/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java
index d98bc61..e877dd1 100644..100755
--- a/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java
@@ -1,16 +1,25 @@
package bjc.rgens.parser.elements;
+import bjc.rgens.parser.GenerationState;
+
public class RangeCaseElement extends CaseElement {
public final int begin;
public final int end;
public RangeCaseElement(int beg, int en) {
- super(ElementType.RANGE);
+ super(true);
begin = beg;
end = en;
}
+ public void generate(GenerationState state) {
+ int val = state.rnd.nextInt(end - begin);
+ val += begin;
+
+ state.contents.append(val);
+ }
+
@Override
public int hashCode() {
final int prime = 31;
diff --git a/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java b/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java
index f4d3512..f13dbdb 100644..100755
--- a/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java
@@ -1,7 +1,103 @@
package bjc.rgens.parser.elements;
-public class RuleCaseElement extends StringCaseElement {
+import bjc.utils.data.IPair;
+import bjc.utils.data.Pair;
+
+import bjc.rgens.parser.*;
+import bjc.rgens.parser.elements.vars.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class RuleCaseElement extends CaseElement {
+ public List<VariableElement> elements;
+
public RuleCaseElement(String vl) {
- super(vl, false);
+ super(true);
+
+ this.elements = VariableElement.parseElementString(vl);
+ }
+
+ public RuleCaseElement(String vl, List<VariableElement> elements) {
+ super(true);
+
+ this.elements = elements;
+ }
+
+ public void generate(GenerationState state) {
+ GenerationState newState = state.newBuf();
+
+ boolean inName = false;
+
+ for(VariableElement elm : elements) {
+ elm.generate(newState);
+
+ if(inName == false) inName = elm.forbidSpaces;
+ }
+
+ String body = newState.contents.toString();
+
+ if(inName) {
+ doGenerate(String.format("[%s]", body), state);
+ } else {
+ state.contents.append(body);
+ }
+ }
+
+ protected void doGenerate(String actName, GenerationState state) {
+ GenerationState newState = state.newBuf();
+
+ Rule rl;
+
+ if (actName.startsWith("[^")) {
+ actName = "[" + actName.substring(2);
+
+ rl = state.findImport(actName);
+ } else {
+ rl = state.findRule(actName, true);
+ }
+
+ if(rl != null) {
+ RGrammar destGrammar = rl.belongsTo;
+ newState.swapGrammar(destGrammar);
+ /*
+ * Don't postprocess the string, we should only do that
+ * once.
+ */
+ String res = destGrammar.generate(actName, newState, false);
+ newState.contents = new StringBuilder(res);
+ } else {
+ /*
+ * @TODO 5/29/18 Ben Culkin :RuleSuggesting
+ *
+ * Re-get this working again.
+ */
+ /*
+ 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 msg = String.format("No rule '%s' defined (perhaps you meant %s?)", actName,
+ StringUtils.toEnglishList(resArray, false));
+
+ throw new GrammarException(msg);
+ }
+ */
+
+ String msg = String.format("No rule '%s' defined", actName);
+ throw new GrammarException(msg);
+ }
+
+ String res = newState.contents.toString();
+
+ if (actName.contains("+")) {
+ /* Rule names with pluses in them get space-flattened */
+ state.contents.append(res.replaceAll("\\s+", ""));
+ } else {
+ state.contents.append(res);
+ }
}
}
diff --git a/src/main/java/bjc/rgens/parser/elements/RuleVariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/RuleVariableCaseElement.java
new file mode 100644
index 0000000..29b6fc9
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/elements/RuleVariableCaseElement.java
@@ -0,0 +1,39 @@
+package bjc.rgens.parser.elements;
+
+import bjc.utils.data.IPair;
+import bjc.utils.data.Pair;
+
+import bjc.rgens.parser.GrammarException;
+import bjc.rgens.parser.GenerationState;
+import bjc.rgens.parser.Rule;
+import bjc.rgens.parser.RGrammar;
+
+public class RuleVariableCaseElement extends VariableDefCaseElement {
+ public final boolean exhaust;
+
+ public RuleVariableCaseElement(String varName, String varDef, boolean exhaust) {
+ super(varName, varDef);
+
+ this.exhaust = exhaust;
+ }
+
+ public void generate(GenerationState state) {
+ Rule rl = state.findRule(varDef, true);
+
+ if(rl == null) {
+ throw new GrammarException("Can't create variable referencing non-existent rule " + varDef);
+ }
+
+ if(exhaust) {
+ rl = rl.exhaust();
+ }
+
+ state.rlVars.put(varName, rl);
+
+ if(exhaust) {
+ System.err.printf("\t\tFINE: Defined exhausted rulevar '%s' ('%s')\n", varName, varDef);
+ } else {
+ System.err.printf("\t\tFINE: Defined rulevar '%s' ('%s')\n", varName, varDef);
+ }
+ }
+}
diff --git a/src/main/java/bjc/rgens/parser/elements/SerialCaseElement.java b/src/main/java/bjc/rgens/parser/elements/SerialCaseElement.java
new file mode 100644
index 0000000..348cfbb
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/elements/SerialCaseElement.java
@@ -0,0 +1,30 @@
+package bjc.rgens.parser.elements;
+
+import bjc.rgens.parser.GenerationState;
+
+public class SerialCaseElement extends CaseElement {
+ public final CaseElement rep;
+
+ public final int lower;
+ public final int upper;
+
+ public SerialCaseElement(CaseElement rep, int lower, int upper) {
+ super(rep.spacing);
+
+ this.rep = rep;
+
+ this.lower = lower;
+ this.upper = upper;
+ }
+
+ public void generate(GenerationState state) {
+ int num = state.rnd.nextInt(upper - lower) + lower;
+
+ for(int i = 0; i < num; i++) {
+ rep.generate(state);
+
+ if(rep.spacing)
+ state.contents.append(" ");
+ }
+ }
+}
diff --git a/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java b/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java
index 0e64fd3..00441c0 100644..100755
--- a/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java
@@ -1,10 +1,10 @@
package bjc.rgens.parser.elements;
-public class StringCaseElement extends CaseElement {
+public abstract class StringCaseElement extends CaseElement {
public final String val;
- protected StringCaseElement(String vl, boolean isLiteral) {
- super(isLiteral ? ElementType.LITERAL : ElementType.RULEREF);
+ protected StringCaseElement(String vl) {
+ super(true);
val = vl;
}
diff --git a/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/VariableDefCaseElement.java
index 920445a..37a12b6 100644..100755
--- a/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/VariableDefCaseElement.java
@@ -1,6 +1,8 @@
package bjc.rgens.parser.elements;
-public class VariableCaseElement extends CaseElement {
+import bjc.rgens.parser.GrammarException;
+
+public abstract class VariableDefCaseElement extends CaseElement {
/**
* The name of the variable this element defines.
*/
@@ -11,8 +13,8 @@ public class VariableCaseElement extends CaseElement {
*/
public final String varDef;
- public VariableCaseElement(String name, String def, boolean isExp) {
- super(isExp ? ElementType.EXPVARDEF : ElementType.VARDEF);
+ public VariableDefCaseElement(String name, String def) {
+ super(false);
varName = name;
varDef = def;
@@ -35,7 +37,7 @@ public class VariableCaseElement extends CaseElement {
return false;
if (getClass() != obj.getClass())
return false;
- VariableCaseElement other = (VariableCaseElement) obj;
+ VariableDefCaseElement other = (VariableDefCaseElement) obj;
if (varDef == null) {
if (other.varDef != null)
return false;
@@ -49,12 +51,16 @@ public class VariableCaseElement extends CaseElement {
return true;
}
- @Override
- public String toString() {
- if (type == ElementType.VARDEF) {
- return String.format("{%s:=%s}", varName, varDef);
+ public static CaseElement parseVariable(String varName, String varDef, char op, boolean colon) {
+ if(varName.startsWith("$")) {
+ // Handle normal/expanding variable definitions
+ if(colon) return new ExpVariableCaseElement(varName.substring(1), varDef);
+
+ return new LitVariableCaseElement(varName.substring(1), varDef);
+ } else if(varName.startsWith("@")) {
+ return new RuleVariableCaseElement(varName.substring(1), varDef, colon);
} else {
- return String.format("{%s=%s}", varName, varDef);
+ throw new GrammarException("Unrecognized declaration sigil " + varName.charAt(0));
}
}
}
diff --git a/src/main/java/bjc/rgens/parser/elements/vars/ARefVariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/ARefVariableElement.java
new file mode 100644
index 0000000..a4bb730
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/elements/vars/ARefVariableElement.java
@@ -0,0 +1,31 @@
+package bjc.rgens.parser.elements.vars;
+
+import bjc.rgens.parser.GenerationState;
+import bjc.rgens.parser.GrammarException;
+import bjc.rgens.parser.Rule;
+
+public class ARefVariableElement extends VariableElement {
+ public String value;
+
+ public ARefVariableElement(String val) {
+ super(false);
+
+ value = val;
+ }
+
+ public void generate(GenerationState state) {
+ if(!state.rlVars.containsKey(value)) {
+ throw new GrammarException("No rule variable named " + value);
+ }
+
+ Rule rl = state.rlVars.get(value);
+
+ GenerationState newState = state.newBuf();
+
+ rl.generate(newState);
+
+ String res = newState.contents.toString();
+
+ state.contents.append(res);
+ }
+}
diff --git a/src/main/java/bjc/rgens/parser/elements/vars/LiteralVariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/LiteralVariableElement.java
new file mode 100644
index 0000000..cf33c66
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/elements/vars/LiteralVariableElement.java
@@ -0,0 +1,17 @@
+package bjc.rgens.parser.elements.vars;
+
+import bjc.rgens.parser.GenerationState;
+
+public class LiteralVariableElement extends VariableElement {
+ public String val;
+
+ public LiteralVariableElement(boolean forbidSpaces, String val) {
+ super(forbidSpaces);
+
+ this.val = val;
+ }
+
+ public void generate(GenerationState state) {
+ state.contents.append(val);
+ }
+}
diff --git a/src/main/java/bjc/rgens/parser/elements/vars/RRefVariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/RRefVariableElement.java
new file mode 100644
index 0000000..d731d64
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/elements/vars/RRefVariableElement.java
@@ -0,0 +1,31 @@
+package bjc.rgens.parser.elements.vars;
+
+import bjc.rgens.parser.GenerationState;
+import bjc.rgens.parser.GrammarException;
+import bjc.rgens.parser.Rule;
+
+public class RRefVariableElement extends VariableElement {
+ public String value;
+
+ public RRefVariableElement(boolean forbidSpaces, String val) {
+ super(forbidSpaces);
+
+ value = val;
+ }
+
+ public void generate(GenerationState state) {
+ Rule rl = state.findRule(value, true);
+
+ GenerationState newState = state.newBuf();
+
+ rl.generate(newState);
+
+ String res = newState.contents.toString();
+
+ if(forbidSpaces && res.contains(" ")) {
+ throw new GrammarException("Spaces not allowed in this context (rule-reference %s)");
+ }
+
+ state.contents.append(res);
+ }
+}
diff --git a/src/main/java/bjc/rgens/parser/elements/vars/TRefVariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/TRefVariableElement.java
new file mode 100644
index 0000000..a33d78c
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/elements/vars/TRefVariableElement.java
@@ -0,0 +1,42 @@
+package bjc.rgens.parser.elements.vars;
+
+import bjc.rgens.parser.GenerationState;
+import bjc.rgens.parser.GrammarException;
+import bjc.rgens.parser.templates.GrammarTemplate;
+
+/*
+ * @TODO
+ *
+ * finish when template vars are implemented.
+ */
+public class TRefVariableElement extends VariableElement {
+ public String value;
+
+ public TRefVariableElement(boolean forbidSpaces, String val) {
+ super(forbidSpaces);
+
+ value = val;
+ }
+
+ public void generate(GenerationState state) {
+ /*
+ if(!state.rlVars.containsKey(val)) {
+ throw new GrammarException("No rule variable named " + val);
+ }
+
+ Rule rl = state.rlVars.get(val);
+
+ GenerationState newState = state.newBuf();
+
+ rl.generate(newState);
+
+ String res = newState.contents.toString();
+
+ if(forbidSpaces && res.contains(" ")) {
+ throw new GrammarException("Spaces not allowed in this context (rule-var %s)");
+ }
+
+ return res;
+ */
+ }
+}
diff --git a/src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java
new file mode 100644
index 0000000..b19f785
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java
@@ -0,0 +1,27 @@
+package bjc.rgens.parser.elements.vars;
+
+import bjc.rgens.parser.GenerationState;
+import bjc.rgens.parser.GrammarException;
+
+public class VRefVariableElement extends VariableElement {
+ public final String nam;
+
+ public VRefVariableElement(boolean forbidSpaces, String nam) {
+ super(forbidSpaces);
+
+ this.nam = nam;
+ }
+
+ public void generate(GenerationState state) {
+ if (!state.vars.containsKey(nam)) {
+ throw new GrammarException(String.format("No variable '%s' defined", nam));
+ }
+
+ String strang = state.vars.get(nam);
+ if(forbidSpaces && strang.contains(" ")) {
+ throw new GrammarException(String.format("Cannot include variable %s w/ spaces in body in rule name", nam));
+ }
+
+ state.contents.append(strang);
+ }
+}
diff --git a/src/main/java/bjc/rgens/parser/elements/vars/VariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/VariableElement.java
new file mode 100644
index 0000000..19c1e2c
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/elements/vars/VariableElement.java
@@ -0,0 +1,71 @@
+package bjc.rgens.parser.elements.vars;
+
+import bjc.utils.funcutils.StringUtils;
+
+import bjc.rgens.parser.GenerationState;
+import bjc.rgens.parser.GrammarException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class VariableElement {
+ public boolean forbidSpaces;
+
+ protected VariableElement(boolean forbidSpacing) {
+ forbidSpaces = forbidSpacing;
+ }
+
+ public abstract void generate(GenerationState state);
+
+ public static List<VariableElement> parseElementString(String varElm) {
+ boolean forbidSpaces = StringUtils.levelContains(varElm, "-", "+");
+
+ String[] parts;
+
+ if(forbidSpaces) {
+ parts = StringUtils.levelSplit(varElm, true, "-", "+").toArray(new String[0]);
+ } else {
+ parts = new String[] { varElm };
+ }
+
+ return parseElementString(forbidSpaces, parts);
+ }
+
+ public static List<VariableElement> parseElementString(boolean forbidSpaces, String... parts) {
+ List<VariableElement> elms = new ArrayList<>(parts.length);
+
+ VariableElement prevElement = null;
+
+ for (String part : parts) {
+ VariableElement elm = null;
+
+ if(part.startsWith("$")) {
+ elm = new VRefVariableElement(forbidSpaces, part.substring(1));
+ } else if (part.startsWith("@")) {
+ if(forbidSpaces)
+ throw new GrammarException("Arrays references aren't allowed in rule names");
+
+ elm = new ARefVariableElement(part.substring(1));
+ } else if (part.startsWith("%")) {
+ elm = new RRefVariableElement(forbidSpaces, part.substring(1));
+ } else if (part.startsWith("/")) {
+ throw new GrammarException("Template variables aren't implemented yet");
+ } else {
+ if(prevElement != null && prevElement instanceof LiteralVariableElement) {
+ /* Aggregate chain literals together */
+ ((LiteralVariableElement)prevElement).val += part;
+ } else {
+ elm = new LiteralVariableElement(forbidSpaces, part);
+ }
+ }
+
+ if(elm != null) {
+ elms.add(elm);
+
+ prevElement = elm;
+ }
+ }
+
+ return elms;
+ }
+}