From 05c9922b30cd0dcd2a452673c2e155215d074b19 Mon Sep 17 00:00:00 2001 From: "Benjamin J. Culkin" Date: Tue, 5 Jun 2018 22:09:23 -0300 Subject: 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 --- src/main/java/bjc/rgens/parser/ConfigLoader.java | 13 ++-- src/main/java/bjc/rgens/parser/ConfigSet.java | 2 + .../java/bjc/rgens/parser/GenerationState.java | 27 +++++--- .../java/bjc/rgens/parser/GrammarTemplate.java | 23 ------- src/main/java/bjc/rgens/parser/RGrammar.java | 25 ++++---- src/main/java/bjc/rgens/parser/RGrammarSet.java | 25 ++++---- src/main/java/bjc/rgens/parser/RGrammarTest.java | 27 ++++++++ src/main/java/bjc/rgens/parser/Rule.java | 26 +++++++- src/main/java/bjc/rgens/parser/RuleCase.java | 2 +- .../bjc/rgens/parser/elements/CaseElement.java | 50 +++------------ .../parser/elements/ExpVariableCaseElement.java | 6 +- .../bjc/rgens/parser/elements/RuleCaseElement.java | 10 +-- .../parser/elements/RuleVarRefCaseElement.java | 21 +----- .../parser/elements/RuleVariableCaseElement.java | 8 +-- .../rgens/parser/elements/VariableCaseElement.java | 15 +++++ .../rgens/parser/templates/GrammarTemplate.java | 75 ++++++++++++++++++++++ .../parser/templates/LiteralTemplateElement.java | 17 +++++ .../parser/templates/LiveTemplateElement.java | 60 +++++++++++++++++ .../rgens/parser/templates/TemplateElement.java | 27 ++++++++ 19 files changed, 322 insertions(+), 137 deletions(-) delete mode 100644 src/main/java/bjc/rgens/parser/GrammarTemplate.java create mode 100644 src/main/java/bjc/rgens/parser/templates/GrammarTemplate.java create mode 100644 src/main/java/bjc/rgens/parser/templates/LiteralTemplateElement.java create mode 100644 src/main/java/bjc/rgens/parser/templates/LiveTemplateElement.java create mode 100644 src/main/java/bjc/rgens/parser/templates/TemplateElement.java (limited to 'src/main/java/bjc') 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 grammars; public final Map 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 rules; /** The rules imported from other grammars. */ - public Map importRules; + public Map importRules; /** The current set of variables. */ public Map vars; - public Map> rlVars; + public Map 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 vs, - Map> rvs, RGrammar gram) { + Map 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 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 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 lines; - - public GrammarTemplate(List lines) { - this.lines = lines; - } - - public static GrammarTemplate readTemplate(Reader rdr) { - List 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 rules; /* The rules imported from other grammars. */ - private Map importRules; + private Map importRules; /* The rules exported from this grammar. */ private Set exportRules; /* The initial rule of this grammar. */ @@ -75,6 +75,10 @@ public class RGrammar { */ public RGrammar(Map 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 importedRules) { + public void setImportedRules(Map 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 vars, - Map> rlVars) { + Map 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 getImportRules() { + public Map 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 grammars; /* Contains all the exported rules from grammars. */ - private Map exportedRules; - - /* Contains which export came from which grammar. */ - private Map exportFrom; + private Map exportedRules; /* Contains which file a grammar was loaded from. */ public Map 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 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 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 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 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 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 elements; + + public boolean doSpacing = true; + + public GrammarTemplate(List 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 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 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 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> 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 elms = (FunctionalList)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 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); +} -- cgit v1.2.3