summaryrefslogtreecommitdiff
path: root/src/main/java
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 /src/main/java
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
Diffstat (limited to 'src/main/java')
-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);
+}