summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin J. Culkin <bjculkin@mix.wvu.edu>2018-09-05 16:48:15 -0300
committerBenjamin J. Culkin <bjculkin@mix.wvu.edu>2018-09-05 16:48:15 -0300
commite26cdec45a32c2fc3069dea7cddceab5e40a4a8b (patch)
tree244b3bc1ed2a1f0c42b78d295127a5b98818567b
parent15f0bf5207df703ffbb53c18a147b440dcf43546 (diff)
Autovivify vars
Enable autovivifying variables. These will have their definition automatically ran when they are first referenced.
-rw-r--r--src/main/java/bjc/rgens/parser/GenerationState.java28
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/RGrammar.java9
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/RGrammarBuilder.java17
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/RGrammarParser.java76
-rw-r--r--src/main/java/bjc/rgens/parser/elements/vars/ARefVariableElement.java2
-rw-r--r--src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java2
6 files changed, 126 insertions, 8 deletions
diff --git a/src/main/java/bjc/rgens/parser/GenerationState.java b/src/main/java/bjc/rgens/parser/GenerationState.java
index ebe7ca4..b147dfd 100644
--- a/src/main/java/bjc/rgens/parser/GenerationState.java
+++ b/src/main/java/bjc/rgens/parser/GenerationState.java
@@ -113,28 +113,44 @@ public class GenerationState {
public void defineVar(String name, String val) {
if(vars.containsKey(name))
- warn("Shadowing variable %s with value %s (old value %s)", name, vars.get(name), val);
+ warn("Shadowing variable %s with value %s (old value %s)",
+ name, val, vars.get(name));
+ else if (gram.autoVars.containsKey(name))
+ warn("Shadowing autovariable %s with value %s (defn. %s)",
+ name, val, gram.autoVars.get(name));
vars.put(name, val);
}
public void defineRuleVar(String name, Rule rle) {
if(rlVars.containsKey(name))
- warn("Shadowing rule variable %s with value %s (old value %s)", name, rlVars.get(name), rle);
+ warn("Shadowing rule variable %s with value %s (old value %s)",
+ name, rlVars.get(name), rle);
+ else if (gram.autoRlVars.containsKey(name))
+ warn("Shadowing rule autovariable %s with value %s (defn. %s)",
+ name, rle, gram.autoRlVars.get(name));
rlVars.put(name, rle);
}
- public String findVar(String name, GenerationState stat) {
+ public String findVar(String name) {
if(!vars.containsKey(name))
- throw new GrammarException(String.format("Variable %s not defined", name));
+ if(gram.autoVars.containsKey(name)) {
+ gram.autoVars.get(name).generate(this);
+ } else {
+ throw new GrammarException(String.format("Variable %s not defined", name));
+ }
return vars.get(name);
}
- public Rule findRuleVar(String name, GenerationState stat) {
+ public Rule findRuleVar(String name) {
if(!rlVars.containsKey(name))
- throw new GrammarException(String.format("Rule variable %s not defined", name));
+ if(gram.autoRlVars.containsKey(name)) {
+ gram.autoRlVars.get(name).generate(this);
+ } else {
+ throw new GrammarException(String.format("Rule variable %s not defined", name));
+ }
return rlVars.get(name);
}
diff --git a/src/main/java/bjc/rgens/parser/RGrammar.java b/src/main/java/bjc/rgens/parser/RGrammar.java
index 5e3142b..03962b2 100755
--- a/src/main/java/bjc/rgens/parser/RGrammar.java
+++ b/src/main/java/bjc/rgens/parser/RGrammar.java
@@ -67,9 +67,13 @@ public class RGrammar {
private Map<String, Rule> importRules;
/* The rules exported from this grammar. */
private Set<String> exportRules;
+
/* The initial rule of this grammar. */
private String initialRule;
+ public Map<String, CaseElement> autoVars;
+ public Map<String, CaseElement> autoRlVars;
+
/* The tree to use for finding rule suggestions. */
private BkTreeSearcher<String> ruleSearcher;
@@ -349,4 +353,9 @@ public class RGrammar {
public Map<String, Rule> getImportRules() {
return importRules;
}
+
+ public void setAutoVars(Map<String, CaseElement> aVars, Map<String, CaseElement> aRlVars) {
+ autoVars = aVars;
+ autoRlVars = aRlVars;
+ }
}
diff --git a/src/main/java/bjc/rgens/parser/RGrammarBuilder.java b/src/main/java/bjc/rgens/parser/RGrammarBuilder.java
index 534d5ec..f1d0938 100755
--- a/src/main/java/bjc/rgens/parser/RGrammarBuilder.java
+++ b/src/main/java/bjc/rgens/parser/RGrammarBuilder.java
@@ -1,6 +1,7 @@
package bjc.rgens.parser;
import bjc.rgens.parser.elements.CaseElement;
+import bjc.rgens.parser.elements.VariableDefCaseElement;
import bjc.utils.data.IPair;
import bjc.utils.data.Pair;
@@ -34,11 +35,18 @@ public class RGrammarBuilder {
/* The current grammar name. */
public String name;
+ /* Autovivify variables */
+ private Map<String, CaseElement> autoVars;
+ private Map<String, CaseElement> autoRlVars;
+
/** Create a new randomized grammar builder. */
public RGrammarBuilder() {
rules = new HashMap<>();
exportedRules = new HashSet<>();
+
+ autoVars = new HashMap<>();
+ autoRlVars = new HashMap<>();
}
/**
@@ -93,6 +101,8 @@ public class RGrammarBuilder {
grammar.setExportedRules(exportedRules);
+ grammar.setAutoVars(autoVars, autoRlVars);
+
return grammar;
}
@@ -315,6 +325,13 @@ public class RGrammarBuilder {
rl.trials = trials;
}
+ public void addAutoVar(String name, CaseElement elm) {
+ autoVars.put(name, elm);
+ }
+
+ public void addAutoRlVar(String name, CaseElement elm) {
+ autoRlVars.put(name, elm);
+ }
/*
* @TODO
*
diff --git a/src/main/java/bjc/rgens/parser/RGrammarParser.java b/src/main/java/bjc/rgens/parser/RGrammarParser.java
index aae5c4a..ba1bd8d 100755
--- a/src/main/java/bjc/rgens/parser/RGrammarParser.java
+++ b/src/main/java/bjc/rgens/parser/RGrammarParser.java
@@ -205,6 +205,82 @@ public class RGrammarParser {
build.prefixWith(body.substring(0, idx), parseElementString(body.substring(idx + 1)).getLeft());
});
+
+ /*
+ * @NOTE 9/4/18
+ *
+ * Right now, we ignore additional elements to autovivify. Not
+ * sure yet if this is the desired behavior.
+ *
+ * As I see it, there are a couple of alternatives:
+ *
+ * 1) Continue what we're doing. This is simple, but seems
+ * somewhat inelegant.
+ *
+ * 2) Error if more than one is provided. Even simpler, but also
+ * seems inelegant.
+ *
+ * 3) Parse them independantly. Each element is treated as a
+ * seperate autovar. Seems simple, but may
+ * cause issues with mixing rule & nonrule
+ * variables, as well as naming.
+ *
+ * 4) Parse them together. Autovars are stored as cases instead
+ * of case elements. Also simple, but may have
+ * some odd corner cases, and I can't think of
+ * any cases where the additional power would
+ * be useful.
+ *
+ *
+ *
+ *
+ *
+ *
+ * As an additional aside, we currently error if we provide
+ * something that isn't a variable definition. This is because
+ * we pull the name for the auto-vivify variable from the
+ * element. If we go with option 4 above, the user will have to
+ * specify a name for the variable, and we should likely add
+ * some check when the variable is made live that it actually
+ * created the variable it said it would.
+ *
+ */
+ pragmas.put("autovivify", (body, build, level) -> {
+ doAutoVar(body, build, level, false);
+ });
+
+ pragmas.put("autovivify-rule", (body, build, level) -> {
+ doAutoVar(body, build, level, true);
+ });
+ }
+
+ private static void doAutoVar(String body, RGrammarBuilder build, int level, boolean isRule) {
+ List<String> bits = StringUtils.levelSplit(body, " ");
+
+ if (bits.size() < 1) {
+ String msg = "Must specify name of variable and definition to autovivify";
+ throw new GrammarException(msg);
+ }
+
+ String[] bitArr = bits.toArray(new String[0]);
+
+ IList<CaseElement> elmList = parseElementString(bitArr).getLeft();
+ CaseElement elm = elmList.first();
+
+ if (elmList.getSize() > 1) {
+ warn("Ignoring %d additional elements for autovivify: %s", elmList.getSize(), elmList.tail());
+ }
+
+ if (!(elm instanceof VariableDefCaseElement)) {
+ throw new GrammarException(String.format("Autovivify expression must be a variable defn. (expr. %s)", elm));
+ }
+
+ {
+ String name = ((VariableDefCaseElement)elm).varName;
+
+ if (isRule) build.addAutoRlVar(name, elm);
+ else build.addAutoVar(name, elm);
+ }
}
/**
diff --git a/src/main/java/bjc/rgens/parser/elements/vars/ARefVariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/ARefVariableElement.java
index 5e8fe05..99af354 100644
--- a/src/main/java/bjc/rgens/parser/elements/vars/ARefVariableElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/vars/ARefVariableElement.java
@@ -14,7 +14,7 @@ public class ARefVariableElement extends VariableElement {
}
public void generate(GenerationState state) {
- Rule rl = state.findRuleVar(value, state);
+ Rule rl = state.findRuleVar(value);
GenerationState newState = state.newBuf();
diff --git a/src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java
index a16503f..1facd38 100644
--- a/src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java
@@ -13,7 +13,7 @@ public class VRefVariableElement extends VariableElement {
}
public void generate(GenerationState state) {
- String strang = state.findVar(nam, state);
+ String strang = state.findVar(nam);
if(forbidSpaces && strang.contains(" ")) {
throw new GrammarException(String.format("Cannot include variable %s w/ spaces in body in rule name", nam));