diff options
Diffstat (limited to 'src/main/java/bjc')
8 files changed, 155 insertions, 30 deletions
diff --git a/src/main/java/bjc/rgens/parser/GenerationState.java b/src/main/java/bjc/rgens/parser/GenerationState.java index 78fce96..5e2b449 100644 --- a/src/main/java/bjc/rgens/parser/GenerationState.java +++ b/src/main/java/bjc/rgens/parser/GenerationState.java @@ -1,5 +1,8 @@ package bjc.rgens.parser; +import bjc.utils.data.IPair; +import bjc.utils.data.Pair; + import java.util.Map; import java.util.Random; @@ -33,7 +36,7 @@ public class GenerationState { */ /** The current set of variables. */ public Map<String, String> vars; - public Map<String, Rule> rlVars; + public Map<String, IPair<RGrammar, Rule>> rlVars; /** * Create a new generation state. @@ -47,7 +50,8 @@ public class GenerationState { * @param vs * The variables to use. */ - public GenerationState(StringBuilder cont, Random rand, Map<String, String> vs, Map<String, Rule> rvs, RGrammar gram) { + public GenerationState(StringBuilder cont, Random rand, Map<String, String> vs, + Map<String, IPair<RGrammar, Rule>> rvs, RGrammar gram) { contents = cont; rnd = rand; vars = vs; diff --git a/src/main/java/bjc/rgens/parser/RGrammar.java b/src/main/java/bjc/rgens/parser/RGrammar.java index 6b17173..1b68c80 100755 --- a/src/main/java/bjc/rgens/parser/RGrammar.java +++ b/src/main/java/bjc/rgens/parser/RGrammar.java @@ -1,11 +1,14 @@ package bjc.rgens.parser; +import bjc.utils.data.IPair; +import bjc.utils.data.Pair; +import bjc.utils.funcutils.StringUtils; + import bjc.rgens.parser.elements.CaseElement; import bjc.rgens.parser.elements.LiteralCaseElement; import bjc.rgens.parser.elements.RangeCaseElement; import bjc.rgens.parser.elements.RuleCaseElement; import bjc.rgens.parser.elements.VariableCaseElement; -import bjc.utils.funcutils.StringUtils; import java.util.HashMap; import java.util.HashSet; @@ -126,7 +129,8 @@ public class RGrammar { * * @return A possible string from the grammar. */ - public String generate(String startRule, Random rnd, Map<String, String> vars, Map<String, Rule> rlVars) { + public String generate(String startRule, Random rnd, Map<String, String> vars, + Map<String, IPair<RGrammar, Rule>> rlVars) { return generate(startRule, new GenerationState(new StringBuilder(), rnd, vars, rlVars, this)); } diff --git a/src/main/java/bjc/rgens/parser/elements/CaseElement.java b/src/main/java/bjc/rgens/parser/elements/CaseElement.java index 103c00a..5263d03 100755 --- a/src/main/java/bjc/rgens/parser/elements/CaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/CaseElement.java @@ -22,12 +22,7 @@ public abstract class CaseElement { /** An element that represents a random range. */ RANGE(true), /** An element that represents a variable that stores a string. */ - VARDEF(false), - /** - * An element that represents a variable that stores the result of generating a - * rule. - */ - EXPVARDEF(false); + VARIABLE(false); public final boolean spacing; @@ -36,9 +31,6 @@ public abstract class CaseElement { } } - /* Regexps for marking rule types. */ - private static final String RANGE_CASELM = "\\[\\d+\\.\\.\\d+\\]"; - /** The type of this element. */ public final ElementType type; @@ -80,7 +72,7 @@ public abstract class CaseElement { if (csepart.matches("\\{[^}]+\\}")) { /* - * Handle special cases. + * Handle special case elements. * */ String specialBody = csepart.substring(1, csepart.length() - 1); @@ -97,13 +89,8 @@ public abstract class CaseElement { throw new GrammarException(msg); } - /* - * @NOTE - * - * This should maybe check that parts[1] is a - * valid rule name, since it gets used as one. - */ - return new ExpVariableCaseElement(parts[0], parts[1]); + /* Trim $ */ + return new ExpVariableCaseElement(parts[0].substring(1), parts[1]); } else if (specialBody.matches("\\$\\S+=\\S+")) { /* Handle regular variable definitions. */ String[] parts = specialBody.split("="); @@ -114,7 +101,32 @@ public abstract class CaseElement { throw new GrammarException(msg); } - return new LitVariableCaseElement(parts[0], parts[1]); + /* Trim $ */ + return new LitVariableCaseElement(parts[0].substring(1), parts[1]); + } else if (specialBody.matches("\\@\\S+=\\S+")) { + /* Handle 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], false); + } 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("empty")) { /* Literal blank, for empty cases. */ return new BlankCaseElement(); @@ -151,6 +163,9 @@ public abstract class CaseElement { } return new VariableRuleReference(csepart); + } else if(csepart.contains("@")) { + // Trim @ + return new RuleVarRefCaseElement(csepart.substring(1)); } else { return new NormalRuleReference(csepart); } @@ -160,7 +175,7 @@ public abstract class CaseElement { System.err.printf("\tTRACE: short ref to %s (%s)\n", rName, csepart); return new NormalRuleReference(rName); - } else{ + } else { return new LiteralCaseElement(csepart); } } diff --git a/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java index 58c5479..455fce6 100755 --- a/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java @@ -9,7 +9,7 @@ import bjc.rgens.parser.RuleCase; public class ExpVariableCaseElement extends VariableCaseElement { public ExpVariableCaseElement(String name, String def) { - super(name, def, true); + super(name, def, VariableType.EXPAND); } @Override diff --git a/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java index 91b8a2b..cd44ccb 100755 --- a/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java @@ -4,7 +4,7 @@ import bjc.rgens.parser.GenerationState; public class LitVariableCaseElement extends VariableCaseElement { public LitVariableCaseElement(String name, String def) { - super(name, def, false); + super(name, def, VariableType.NORMAL); } public void generate(GenerationState state) { diff --git a/src/main/java/bjc/rgens/parser/elements/RuleVarRefCaseElement.java b/src/main/java/bjc/rgens/parser/elements/RuleVarRefCaseElement.java new file mode 100644 index 0000000..a7be1bb --- /dev/null +++ b/src/main/java/bjc/rgens/parser/elements/RuleVarRefCaseElement.java @@ -0,0 +1,47 @@ +package bjc.rgens.parser.elements; + +import bjc.utils.data.IPair; + +import bjc.rgens.parser.GenerationState; +import bjc.rgens.parser.GrammarException; +import bjc.rgens.parser.RecurLimitException; +import bjc.rgens.parser.RGrammar; +import bjc.rgens.parser.Rule; +import bjc.rgens.parser.RuleCase; + +public class RuleVarRefCaseElement extends StringCaseElement { + public RuleVarRefCaseElement(String vl) { + super(vl, false); + } + + public void generate(GenerationState state) { + if(!state.rlVars.containsKey(val)) { + throw new GrammarException("No rule variable named " + val); + } + + IPair<RGrammar, Rule> par = 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"); + } + + 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); + } + } +} diff --git a/src/main/java/bjc/rgens/parser/elements/RuleVariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/RuleVariableCaseElement.java new file mode 100644 index 0000000..55a1c1e --- /dev/null +++ b/src/main/java/bjc/rgens/parser/elements/RuleVariableCaseElement.java @@ -0,0 +1,46 @@ +package bjc.rgens.parser.elements; + +import bjc.utils.data.IPair; +import bjc.utils.data.Pair; + +import bjc.rgens.parser.GrammarException; +import bjc.rgens.parser.GenerationState; +import bjc.rgens.parser.Rule; +import bjc.rgens.parser.RGrammar; + +public class RuleVariableCaseElement extends VariableCaseElement { + public final boolean exhaust; + + public RuleVariableCaseElement(String varName, String varDef, boolean exhaust) { + super(varName, varDef, VariableType.RULE); + + this.exhaust = exhaust; + } + + public void generate(GenerationState state) { + Rule rl; + RGrammar grm; + + if(state.rules.containsKey(varDef)) { + rl = state.rules.get(varDef); + grm = state.gram; + } else if(state.importRules.containsKey(varDef)) { + grm = state.importRules.get(varDef); + rl = grm.getRules().get(varDef); + } else { + throw new GrammarException("Can't create variable referencing non-existent rule " + varDef); + } + + + if(exhaust) rl = rl.exhaust(); + + if(state.rlVars.containsKey(varName)) { + IPair<RGrammar, Rule> par = state.rlVars.get(varName); + + System.err.printf("WARN: Shadowing rule variable '%s' (%s with %s)\n", + varName, par.getRight().name, rl.name); + } + + state.rlVars.put(varName, new Pair<>(grm, rl)); + } +} diff --git a/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java index 3e691d9..63abe16 100755 --- a/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java @@ -1,6 +1,11 @@ package bjc.rgens.parser.elements; public abstract class VariableCaseElement extends CaseElement { + public static enum VariableType { + NORMAL, + EXPAND, + RULE + } /** * The name of the variable this element defines. */ @@ -11,11 +16,15 @@ public abstract class VariableCaseElement extends CaseElement { */ public final String varDef; - public VariableCaseElement(String name, String def, boolean isExp) { - super(isExp ? ElementType.EXPVARDEF : ElementType.VARDEF); + public final VariableType varType; + + public VariableCaseElement(String name, String def, VariableType varType) { + super(ElementType.VARIABLE); varName = name; varDef = def; + + this.varType = varType; } @Override @@ -51,10 +60,10 @@ public abstract class VariableCaseElement extends CaseElement { @Override public String toString() { - if (type == ElementType.VARDEF) { - return String.format("{%s:=%s}", varName, varDef); + if (type == ElementType.VARIABLE) { + return String.format("{$%s:=%s}", varName, varDef); } else { - return String.format("{%s=%s}", varName, varDef); + return String.format("{$%s=%s}", varName, varDef); } } } |
