summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin J. Culkin <bjculkin@mix.wvu.edu>2018-06-05 22:09:23 -0300
committerBenjamin J. Culkin <bjculkin@mix.wvu.edu>2018-06-05 22:09:23 -0300
commit05c9922b30cd0dcd2a452673c2e155215d074b19 (patch)
tree80f2cc1cfd239761f3d74d20159f780c1673781b
parentf25d1062a56a81b17348b799e6d4d7e1dc12a1cc (diff)
Templates pt. 3
Templates should now work, though there is no syntax to reference them from rules yet In addition, several internal things have been changed so as to improve code quality
-rw-r--r--src/main/java/bjc/rgens/parser/ConfigLoader.java13
-rw-r--r--src/main/java/bjc/rgens/parser/ConfigSet.java2
-rw-r--r--src/main/java/bjc/rgens/parser/GenerationState.java27
-rw-r--r--src/main/java/bjc/rgens/parser/GrammarTemplate.java23
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/RGrammar.java25
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/RGrammarSet.java25
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/RGrammarTest.java27
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/Rule.java26
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/RuleCase.java2
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/elements/CaseElement.java50
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java6
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/elements/RuleCaseElement.java10
-rw-r--r--src/main/java/bjc/rgens/parser/elements/RuleVarRefCaseElement.java21
-rw-r--r--src/main/java/bjc/rgens/parser/elements/RuleVariableCaseElement.java8
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/elements/VariableCaseElement.java15
-rw-r--r--src/main/java/bjc/rgens/parser/templates/GrammarTemplate.java75
-rw-r--r--src/main/java/bjc/rgens/parser/templates/LiteralTemplateElement.java17
-rw-r--r--src/main/java/bjc/rgens/parser/templates/LiveTemplateElement.java60
-rw-r--r--src/main/java/bjc/rgens/parser/templates/TemplateElement.java27
19 files changed, 322 insertions, 137 deletions
diff --git a/src/main/java/bjc/rgens/parser/ConfigLoader.java b/src/main/java/bjc/rgens/parser/ConfigLoader.java
index f3028fe..4cad368 100644
--- a/src/main/java/bjc/rgens/parser/ConfigLoader.java
+++ b/src/main/java/bjc/rgens/parser/ConfigLoader.java
@@ -7,6 +7,8 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Scanner;
+import bjc.rgens.parser.templates.GrammarTemplate;
+
public class ConfigLoader {
/**
* Load a grammar set from a configuration file.
@@ -62,7 +64,7 @@ public class ConfigLoader {
switch(type) {
case "load":
- loadConfigLine(ln, set, cfgParent);
+ loadConfigLine(ln, cfgSet, set, cfgParent);
break;
default:
throw new GrammarException("Unknown config line type " + type);
@@ -91,8 +93,7 @@ public class ConfigLoader {
return cfgSet;
}
- private static void loadConfigLine(String ln, RGrammarSet set, Path cfgParent) throws IOException {
-
+ private static void loadConfigLine(String ln, ConfigSet cfgSet, RGrammarSet set, Path cfgParent) throws IOException {
/*
* Get the place where the tag ID ends
*/
@@ -134,6 +135,8 @@ public class ConfigLoader {
BufferedReader fis = Files.newBufferedReader(convPath);
GrammarTemplate template = GrammarTemplate.readTemplate(fis);
+ template.belongsTo = cfgSet;
+
if(template.name == null) {
System.err.printf("\tINFO: Naming unnamed template loaded from %s off config name '%s'\n",
convPath, name);
@@ -148,10 +151,10 @@ public class ConfigLoader {
long fileTime = endFileTime - startFileTime;
System.err.printf("\tPERF: Read template %s (from %s) in %d ns (%f s)\n",
- gram.name, convPath, fileTime, fileTime / 1000000000.0);
+ template.name, convPath, fileTime, fileTime / 1000000000.0);
/* Add grammar to the set. */
- cfgSet.templates.put(name, gram);
+ cfgSet.templates.put(name, template);
/*
* @NOTE
diff --git a/src/main/java/bjc/rgens/parser/ConfigSet.java b/src/main/java/bjc/rgens/parser/ConfigSet.java
index 968cc69..8945a0f 100644
--- a/src/main/java/bjc/rgens/parser/ConfigSet.java
+++ b/src/main/java/bjc/rgens/parser/ConfigSet.java
@@ -3,6 +3,8 @@ package bjc.rgens.parser;
import java.util.HashMap;
import java.util.Map;
+import bjc.rgens.parser.templates.GrammarTemplate;
+
public class ConfigSet {
public final Map<String, RGrammarSet> grammars;
public final Map<String, GrammarTemplate> templates;
diff --git a/src/main/java/bjc/rgens/parser/GenerationState.java b/src/main/java/bjc/rgens/parser/GenerationState.java
index 38a25d5..f5cbc60 100644
--- a/src/main/java/bjc/rgens/parser/GenerationState.java
+++ b/src/main/java/bjc/rgens/parser/GenerationState.java
@@ -3,6 +3,7 @@ package bjc.rgens.parser;
import bjc.utils.data.IPair;
import bjc.utils.data.Pair;
+import java.util.HashMap;
import java.util.Map;
import java.util.Random;
@@ -21,11 +22,13 @@ public class GenerationState {
/** The rules of the grammar. */
public Map<String, Rule> rules;
/** The rules imported from other grammars. */
- public Map<String, RGrammar> importRules;
+ public Map<String, Rule> importRules;
/** The current set of variables. */
public Map<String, String> vars;
- public Map<String, IPair<RGrammar, Rule>> rlVars;
+ public Map<String, Rule> rlVars;
+
+ private static final Random BASE = new Random();
/**
* Create a new generation state.
@@ -40,7 +43,7 @@ public class GenerationState {
* The variables to use.
*/
public GenerationState(StringBuilder cont, Random rand, Map<String, String> vs,
- Map<String, IPair<RGrammar, Rule>> rvs, RGrammar gram) {
+ Map<String, Rule> rvs, RGrammar gram) {
contents = cont;
rnd = rand;
vars = vs;
@@ -52,6 +55,14 @@ public class GenerationState {
this.importRules = gram.getImportRules();
}
+ public static GenerationState fromGrammar(RGrammar gram) {
+ return fromGrammar(BASE, gram);
+ }
+
+ public static GenerationState fromGrammar(Random rand, RGrammar gram) {
+ return new GenerationState(new StringBuilder(), rand, new HashMap<>(), new HashMap<>(), gram);
+ }
+
public void swapGrammar(RGrammar gram) {
if(this.gram == gram) return;
@@ -73,9 +84,9 @@ public class GenerationState {
* they are importing the rule from, so as to make it clear which rules
* are imported, and which aren't
*/
- public IPair<RGrammar, Rule> findRule(String ruleName, boolean allowImports) {
+ public Rule findRule(String ruleName, boolean allowImports) {
if(rules.containsKey(ruleName)) {
- return new Pair<>(gram, rules.get(ruleName));
+ return rules.get(ruleName);
}
if(allowImports) return findImport(ruleName);
@@ -83,11 +94,9 @@ public class GenerationState {
return null;
}
- public IPair<RGrammar, Rule> findImport(String ruleName) {
+ public Rule findImport(String ruleName) {
if(importRules.containsKey(ruleName)) {
- RGrammar imp = importRules.get(ruleName);
-
- return new Pair<>(imp, imp.rules.get(ruleName));
+ return importRules.get(ruleName);
}
return null;
diff --git a/src/main/java/bjc/rgens/parser/GrammarTemplate.java b/src/main/java/bjc/rgens/parser/GrammarTemplate.java
deleted file mode 100644
index 1bd5c53..0000000
--- a/src/main/java/bjc/rgens/parser/GrammarTemplate.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package bjc.rgens.parser;
-
-import java.io.Reader;
-import java.util.ArrayList;
-import java.util.List;
-
-public class GrammarTemplate {
- public String name;
-
- public final List<String> lines;
-
- public GrammarTemplate(List<String> lines) {
- this.lines = lines;
- }
-
- public static GrammarTemplate readTemplate(Reader rdr) {
- List<String> lines = new ArrayList<>();
-
- GrammarTemplate template = new GrammarTemplate(lines);
-
- return template;
- }
-}
diff --git a/src/main/java/bjc/rgens/parser/RGrammar.java b/src/main/java/bjc/rgens/parser/RGrammar.java
index 5ca26a4..d523479 100755
--- a/src/main/java/bjc/rgens/parser/RGrammar.java
+++ b/src/main/java/bjc/rgens/parser/RGrammar.java
@@ -58,7 +58,7 @@ public class RGrammar {
/* The rules of the grammar. */
public Map<String, Rule> rules;
/* The rules imported from other grammars. */
- private Map<String, RGrammar> importRules;
+ private Map<String, Rule> importRules;
/* The rules exported from this grammar. */
private Set<String> exportRules;
/* The initial rule of this grammar. */
@@ -75,6 +75,10 @@ public class RGrammar {
*/
public RGrammar(Map<String, Rule> ruls) {
rules = ruls;
+
+ for(Rule rl : ruls.values()) {
+ rl.belongsTo = this;
+ }
}
/**
@@ -86,7 +90,7 @@ public class RGrammar {
* @param importedRules
* The set of imported rules to use.
*/
- public void setImportedRules(Map<String, RGrammar> importedRules) {
+ public void setImportedRules(Map<String, Rule> importedRules) {
importRules = importedRules;
}
@@ -131,7 +135,7 @@ public class RGrammar {
* @return A possible string from the grammar.
*/
public String generate(String startRule, Random rnd, Map<String, String> vars,
- Map<String, IPair<RGrammar, Rule>> rlVars) {
+ Map<String, Rule> rlVars) {
return generate(startRule, new GenerationState(new StringBuilder(), rnd, vars, rlVars, this));
}
@@ -164,20 +168,13 @@ public class RGrammar {
* We don't search imports, so it will always belong to this
* grammar.
*/
- Rule rl = state.findRule(fromRule, false).getRight();
+ Rule rl = state.findRule(fromRule, false);
+
if(rl == null)
throw new GrammarException("Could not find rule " + rl.name);
- if(rl.doRecur()) {
- RuleCase start = rl.getCase(state.rnd);
- System.err.printf("\tFINE: Generating %s (from %s in %s)\n", start, fromRule, name);
+ rl.generate(state);
- generateCase(start, state);
-
- rl.endRecur();
- } else {
- throw new RecurLimitException("Rule recurrence limit exceeded");
- }
/*
* @NOTE
*
@@ -326,7 +323,7 @@ public class RGrammar {
return rules;
}
- public Map<String, RGrammar> getImportRules() {
+ public Map<String, Rule> getImportRules() {
return importRules;
}
}
diff --git a/src/main/java/bjc/rgens/parser/RGrammarSet.java b/src/main/java/bjc/rgens/parser/RGrammarSet.java
index a192da7..b110d21 100755
--- a/src/main/java/bjc/rgens/parser/RGrammarSet.java
+++ b/src/main/java/bjc/rgens/parser/RGrammarSet.java
@@ -15,14 +15,13 @@ public class RGrammarSet {
public ConfigSet belongsTo;
+ public RGrammar exportGrammar;
+
/* Contains all the grammars in this set. */
private Map<String, RGrammar> grammars;
/* Contains all the exported rules from grammars. */
- private Map<String, RGrammar> exportedRules;
-
- /* Contains which export came from which grammar. */
- private Map<String, String> exportFrom;
+ private Map<String, Rule> exportedRules;
/* Contains which file a grammar was loaded from. */
public Map<String, String> loadedFrom;
@@ -36,8 +35,9 @@ public class RGrammarSet {
exportedRules = new TreeMap<>();
- exportFrom = new HashMap<>();
loadedFrom = new HashMap<>();
+
+ exportGrammar = new RGrammar(exportedRules);
}
/**
@@ -68,11 +68,9 @@ public class RGrammarSet {
/* Process exports from the grammar. */
for (Rule export : gram.getExportedRules()) {
if(exportedRules.containsKey(export.name))
- System.err.printf("WARN: Shadowing rule %s in %s from %s\n", export.name, exportFrom.get(export.name), grammarName);
+ System.err.printf("WARN: Shadowing rule %s in %s from %s\n", export.name, export.belongsTo.name, grammarName);
- exportedRules.put(export.name, gram);
-
- exportFrom.put(export.name, grammarName);
+ exportedRules.put(export.name, export);
if(DEBUG)
System.err.printf("\t\tDEBUG: %s (%d cases) exported from %s\n", export.name, export.getCases().getSize(), grammarName);
@@ -132,7 +130,7 @@ public class RGrammarSet {
throw new IllegalArgumentException(msg);
}
- return exportedRules.get(exportName);
+ return exportedRules.get(exportName).belongsTo;
}
/**
@@ -161,7 +159,12 @@ public class RGrammarSet {
throw new IllegalArgumentException(msg);
}
- return exportFrom.getOrDefault(exportName, "Unknown");
+ String nm = exportedRules.get(exportName).belongsTo.name;
+ if(nm == null) {
+ return "Unknown";
+ }
+
+ return nm;
}
/**
diff --git a/src/main/java/bjc/rgens/parser/RGrammarTest.java b/src/main/java/bjc/rgens/parser/RGrammarTest.java
index 25f76e7..8193fa3 100755
--- a/src/main/java/bjc/rgens/parser/RGrammarTest.java
+++ b/src/main/java/bjc/rgens/parser/RGrammarTest.java
@@ -1,10 +1,13 @@
package bjc.rgens.parser;
+import bjc.rgens.parser.templates.GrammarTemplate;
+
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Random;
/**
* Test for new grammar syntax.
@@ -29,6 +32,10 @@ public class RGrammarTest {
for(RGrammarSet gramSet : cfgSet.grammars.values()) {
testGrammarSet(gramSet);
}
+
+ for(GrammarTemplate template : cfgSet.templates.values()) {
+ testTemplate(template, cfgSet.grammars.get("default"));
+ }
} catch (IOException ioex) {
ioex.printStackTrace();
} catch (URISyntaxException urisex) {
@@ -36,6 +43,26 @@ public class RGrammarTest {
}
}
+ private static void testTemplate(GrammarTemplate template, RGrammarSet set) {
+ System.out.printf("Generating for template %s\n", template);
+
+ Random rnd = new Random();
+
+ for(int i = 0; i < 10; i++) {
+ GenerationState state = GenerationState.fromGrammar(rnd, set.exportGrammar);
+
+ template.generate(state);
+
+ String res = state.contents.toString();
+
+ if(res.length() > 120) {
+ System.out.printf("\t\n\tContents: %s\n\t\n", res);
+ } else {
+ System.out.printf("\tContents: %s\n", res);
+ }
+ }
+ }
+
private static void testGrammarSet(RGrammarSet gramSet) {
/* Generate rule suggestions for all the grammars in the set. */
for (String gramName : gramSet.getGrammars()) {
diff --git a/src/main/java/bjc/rgens/parser/Rule.java b/src/main/java/bjc/rgens/parser/Rule.java
index 06dedac..ac67158 100755
--- a/src/main/java/bjc/rgens/parser/Rule.java
+++ b/src/main/java/bjc/rgens/parser/Rule.java
@@ -13,6 +13,8 @@ import java.util.Random;
* @author EVE
*/
public class Rule {
+ public RGrammar belongsTo;
+
/** The name of this grammar rule. */
public String name;
@@ -83,7 +85,7 @@ public class Rule {
throw new NullPointerException("Case must not be null");
}
- cse.belongsTo = name;
+ cse.belongsTo = this;
cse.debugName = String.format("%s-%d", name, serial);
serial += 1;
@@ -143,7 +145,7 @@ public class Rule {
for(IPair<Integer, RuleCase> cse : cases) {
RuleCase cs = cse.getRight();
- cs.belongsTo = name;
+ cs.belongsTo = this;
cs.debugName = String.format("%s-%d", name, serial);
serial += 1;
@@ -203,6 +205,8 @@ public class Rule {
public Rule exhaust() {
Rule rl = new Rule(name);
+ rl.belongsTo = belongsTo;
+
rl.cases = cases.exhaustible();
rl.prob = prob;
@@ -219,4 +223,22 @@ public class Rule {
return rl;
}
+
+ public void generate(GenerationState state) {
+ state.swapGrammar(belongsTo);
+
+ if(doRecur()) {
+ RuleCase cse = getCase(state.rnd);
+
+ System.err.printf("\tFINE: Generating %s (from %s)\n", cse, belongsTo.name);
+
+ belongsTo.generateCase(cse, state);
+
+ endRecur();
+ }
+
+ if(name.contains("+")) {
+ state.contents = new StringBuilder(state.contents.toString().replaceAll("\\s+", ""));
+ }
+ }
}
diff --git a/src/main/java/bjc/rgens/parser/RuleCase.java b/src/main/java/bjc/rgens/parser/RuleCase.java
index 3481f37..369c588 100755
--- a/src/main/java/bjc/rgens/parser/RuleCase.java
+++ b/src/main/java/bjc/rgens/parser/RuleCase.java
@@ -37,7 +37,7 @@ public abstract class RuleCase {
/** The type of this case. */
public final CaseType type;
- public String belongsTo;
+ public Rule belongsTo;
/**
* The list of element values for this case.
diff --git a/src/main/java/bjc/rgens/parser/elements/CaseElement.java b/src/main/java/bjc/rgens/parser/elements/CaseElement.java
index d86d2d3..68f5368 100755
--- a/src/main/java/bjc/rgens/parser/elements/CaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/CaseElement.java
@@ -79,54 +79,20 @@ public abstract class CaseElement {
//System.out.printf("\t\tTRACE: special body is '%s'\n", specialBody);
- if (specialBody.matches("\\$\\S+:=\\S+")) {
- /* Handle expanding variable definitions. */
+ if (specialBody.matches("\\S+:=\\S+")) {
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);
- }
-
- /* Trim $ */
- return new ExpVariableCaseElement(parts[0].substring(1), 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);
+ if(parts.length != 2) {
+ throw new GrammarException("Colon variables must have a name and a definition");
}
- /* Trim $ */
- return new LitVariableCaseElement(parts[0].substring(1), parts[1]);
- } else if (specialBody.matches("\\@\\S+:=\\S+")) {
- /* Handle exhaustible rule variable definitions. */
- String[] parts = specialBody.split(":=");
-
- if (parts.length != 2) {
- String msg = "Rule variables must be a name and a definition, seperated by =";
-
- throw new GrammarException(msg);
- }
-
- /* Trim $ */
- return new RuleVariableCaseElement(parts[0].substring(1), parts[1], true);
- } else if (specialBody.matches("\\@\\S+=\\S+")) {
- /* Handle rule variable definitions. */
+ return VariableCaseElement.parseVariable(parts[0], parts[1], true);
+ } else if (specialBody.matches("\\S+=\\S+")) {
String[] parts = specialBody.split("=");
-
- if (parts.length != 2) {
- String msg = "Rule variables must be a name and a definition, seperated by =";
-
- throw new GrammarException(msg);
+ if(parts.length != 2) {
+ throw new GrammarException("Variables must have a name and a definition");
}
- /* Trim $ */
- return new RuleVariableCaseElement(parts[0].substring(1), parts[1], false);
+ return VariableCaseElement.parseVariable(parts[0], parts[1], false);
} else if (specialBody.matches("empty")) {
/* Literal blank, for empty cases. */
return new BlankCaseElement();
diff --git a/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java
index ae85139..3972e7a 100755
--- a/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java
@@ -18,10 +18,10 @@ public class ExpVariableCaseElement extends VariableCaseElement {
public void generate(GenerationState state) {
GenerationState newState = state.newBuf();
- IPair<RGrammar, Rule> par = state.findRule(varDef, true);
+ Rule rl = state.findRule(varDef, true);
- if(par != null) {
- RGrammar destGrammar = par.getLeft();
+ if(rl != null) {
+ RGrammar destGrammar = rl.belongsTo;
newState.swapGrammar(destGrammar);
String res = destGrammar.generate(varDef, state);
diff --git a/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java b/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java
index 3e3d182..e0c847a 100755
--- a/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java
@@ -26,18 +26,18 @@ public abstract class RuleCaseElement extends StringCaseElement {
protected void doGenerate(String actName, GenerationState state) {
GenerationState newState = state.newBuf();
- IPair<RGrammar, Rule> par;
+ Rule rl;
if (actName.startsWith("[^")) {
actName = "[" + actName.substring(2);
- par = state.findImport(actName);
+ rl = state.findImport(actName);
} else {
- par = state.findRule(actName, true);
+ rl = state.findRule(actName, true);
}
- if(par != null) {
- RGrammar destGrammar = par.getLeft();
+ if(rl != null) {
+ RGrammar destGrammar = rl.belongsTo;
newState.swapGrammar(destGrammar);
String res = destGrammar.generate(actName, newState);
diff --git a/src/main/java/bjc/rgens/parser/elements/RuleVarRefCaseElement.java b/src/main/java/bjc/rgens/parser/elements/RuleVarRefCaseElement.java
index a7be1bb..3192558 100644
--- a/src/main/java/bjc/rgens/parser/elements/RuleVarRefCaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/RuleVarRefCaseElement.java
@@ -19,29 +19,14 @@ public class RuleVarRefCaseElement extends StringCaseElement {
throw new GrammarException("No rule variable named " + val);
}
- IPair<RGrammar, Rule> par = state.rlVars.get(val);
+ Rule rl = state.rlVars.get(val);
GenerationState newState = state.newBuf();
- newState.swapGrammar(par.getLeft());
- if(par.getRight().doRecur()) {
- RuleCase cse = par.getRight().getCase(state.rnd);
- System.err.printf("\tFINE: Generating %s (from %s)\n", cse, par.getRight().name);
-
- par.getLeft().generateCase(cse, newState);
-
- par.getRight().endRecur();
- } else {
- throw new RecurLimitException("Rule recurrence limit exceeded");
- }
+ rl.generate(newState);
String res = newState.contents.toString();
- if (par.getRight().name.contains("+")) {
- /* Rule names with pluses in them get space-flattened */
- state.contents.append(res.replaceAll("\\s+", ""));
- } else {
- state.contents.append(res);
- }
+ 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
index fa1783f..cbd8ce1 100644
--- a/src/main/java/bjc/rgens/parser/elements/RuleVariableCaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/RuleVariableCaseElement.java
@@ -18,17 +18,17 @@ public class RuleVariableCaseElement extends VariableCaseElement {
}
public void generate(GenerationState state) {
- IPair<RGrammar, Rule> par = state.findRule(varDef, true);
+ Rule rl = state.findRule(varDef, true);
- if(par == null) {
+ if(rl == null) {
throw new GrammarException("Can't create variable referencing non-existent rule " + varDef);
}
if(exhaust) {
- par = new Pair<>(par.getLeft(), par.getRight().exhaust());
+ rl = rl.exhaust();
}
- state.rlVars.put(varName, par);
+ state.rlVars.put(varName, rl);
if(exhaust) {
System.err.printf("\t\tFINE: Defined exhausted rulevar '%s' ('%s')\n", varName, varDef);
diff --git a/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java
index 63abe16..a2c15a7 100755
--- a/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java
+++ b/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java
@@ -1,5 +1,7 @@
package bjc.rgens.parser.elements;
+import bjc.rgens.parser.GrammarException;
+
public abstract class VariableCaseElement extends CaseElement {
public static enum VariableType {
NORMAL,
@@ -66,4 +68,17 @@ public abstract class VariableCaseElement extends CaseElement {
return String.format("{$%s=%s}", varName, varDef);
}
}
+
+ public static CaseElement parseVariable(String varName, String varDef, 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 {
+ throw new GrammarException("Unrecognized declaration sigil " + varName.charAt(0));
+ }
+ }
}
diff --git a/src/main/java/bjc/rgens/parser/templates/GrammarTemplate.java b/src/main/java/bjc/rgens/parser/templates/GrammarTemplate.java
new file mode 100644
index 0000000..a257fbd
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/templates/GrammarTemplate.java
@@ -0,0 +1,75 @@
+package bjc.rgens.parser.templates;
+
+import bjc.rgens.parser.ConfigSet;
+import bjc.rgens.parser.GenerationState;
+
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+public class GrammarTemplate {
+ public ConfigSet belongsTo;
+
+ public String name;
+
+ public final List<TemplateElement> elements;
+
+ public boolean doSpacing = true;
+
+ public GrammarTemplate(List<TemplateElement> elements) {
+ this.elements = elements;
+ }
+
+ public void generate(GenerationState state) {
+ for(TemplateElement element : elements) {
+ element.generate(state);
+
+ if(doSpacing && element.type.spacing)
+ state.contents.append("\n");
+ }
+ }
+
+ public static GrammarTemplate readTemplate(Reader rdr) {
+ List<TemplateElement> elements = new ArrayList<>();
+ GrammarTemplate template = new GrammarTemplate(elements);
+
+ Scanner scn = new Scanner(rdr);
+ scn.useDelimiter("\\R");
+
+ int lno = 0;
+ while(scn.hasNextLine()) {
+ String ln = scn.nextLine();
+ lno += 1;
+
+ switch(ln.charAt(0)) {
+ case '#':
+ // Ignore comments
+ break;
+ case '/':
+ handlePragma(elements, template, ln.substring(1));
+ break;
+ default:
+ handleLine(elements, template, ln);
+ }
+ }
+
+
+ return template;
+ }
+
+ private static void handleLine(List<TemplateElement> elements, GrammarTemplate template, String ln) {
+ if(ln.matches("^.*?\\$@.+?@\\$.*$")) {
+ /*
+ * Handle live templates
+ */
+ elements.add(new LiveTemplateElement(ln));
+ } else {
+ elements.add(new LiteralTemplateElement(ln));
+ }
+ }
+
+ private static void handlePragma(List<TemplateElement> elements, GrammarTemplate template, String ln) {
+
+ }
+}
diff --git a/src/main/java/bjc/rgens/parser/templates/LiteralTemplateElement.java b/src/main/java/bjc/rgens/parser/templates/LiteralTemplateElement.java
new file mode 100644
index 0000000..19ebbc2
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/templates/LiteralTemplateElement.java
@@ -0,0 +1,17 @@
+package bjc.rgens.parser.templates;
+
+import bjc.rgens.parser.GenerationState;
+
+public class LiteralTemplateElement extends TemplateElement {
+ public final String val;
+
+ public LiteralTemplateElement(String val) {
+ super(ElementType.LITERAL);
+
+ this.val = val;
+ }
+
+ public void generate(GenerationState state) {
+ state.contents.append(val);
+ }
+}
diff --git a/src/main/java/bjc/rgens/parser/templates/LiveTemplateElement.java b/src/main/java/bjc/rgens/parser/templates/LiveTemplateElement.java
new file mode 100644
index 0000000..2487c83
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/templates/LiveTemplateElement.java
@@ -0,0 +1,60 @@
+package bjc.rgens.parser.templates;
+
+import bjc.utils.data.BooleanToggle;
+import bjc.utils.funcdata.FunctionalList;
+
+import bjc.rgens.parser.GenerationState;
+import bjc.rgens.parser.RGrammarParser;
+import bjc.rgens.parser.elements.CaseElement;
+import bjc.rgens.parser.elements.LiteralCaseElement;
+
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class LiveTemplateElement extends TemplateElement {
+ private static final Pattern INSERT_PAT = Pattern.compile("\\$@(.+?)@\\$");
+
+ public final List<List<CaseElement>> elements;
+
+ public LiveTemplateElement(String val) {
+ super(ElementType.TEMPLATE);
+
+ elements = new ArrayList<>();
+
+ Matcher mat = INSERT_PAT.matcher(val);
+ StringBuffer sb = new StringBuffer();
+
+ while(mat.find()) {
+ mat.appendReplacement(sb, "");
+ String body = mat.group(1);
+
+ FunctionalList<CaseElement> elms = (FunctionalList<CaseElement>)RGrammarParser.parseElementString(body).getLeft();
+
+ elements.add(Arrays.asList(new LiteralCaseElement(sb.toString())));
+ elements.add(elms.getInternal());
+
+ sb = new StringBuffer();
+ }
+
+ mat.appendTail(sb);
+ elements.add(Arrays.asList(new LiteralCaseElement(sb.toString())));
+ }
+
+ public void generate(GenerationState state) {
+ BooleanToggle bt = new BooleanToggle(false);
+
+ for(List<CaseElement> elmList : elements) {
+ boolean doSpacing = bt.get();
+
+ for(CaseElement elm : elmList) {
+ elm.generate(state);
+
+ if(doSpacing && elm.type.spacing)
+ state.contents.append(" ");
+ }
+ }
+ }
+}
diff --git a/src/main/java/bjc/rgens/parser/templates/TemplateElement.java b/src/main/java/bjc/rgens/parser/templates/TemplateElement.java
new file mode 100644
index 0000000..dc123f3
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/templates/TemplateElement.java
@@ -0,0 +1,27 @@
+package bjc.rgens.parser.templates;
+
+import bjc.rgens.parser.GenerationState;
+
+public abstract class TemplateElement {
+ public static enum ElementType {
+ LITERAL(true),
+ TEMPLATE(true),
+ PRAGMA(false);
+
+ public final boolean spacing;
+
+ private ElementType(boolean spacing) {
+ this.spacing = spacing;
+ }
+ }
+
+ public final ElementType type;
+
+ public GrammarTemplate belongsTo;
+
+ protected TemplateElement(ElementType type) {
+ this.type = type;
+ }
+
+ public abstract void generate(GenerationState state);
+}