diff options
Diffstat (limited to 'src/main/java/bjc/rgens/parser/elements')
19 files changed, 618 insertions, 80 deletions
diff --git a/src/main/java/bjc/rgens/parser/elements/BlankCaseElement.java b/src/main/java/bjc/rgens/parser/elements/BlankCaseElement.java index 7229e92..66ff310 100644..100755 --- a/src/main/java/bjc/rgens/parser/elements/BlankCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/BlankCaseElement.java @@ -1,5 +1,7 @@ package bjc.rgens.parser.elements; +import bjc.rgens.parser.GenerationState; + public class BlankCaseElement extends LiteralCaseElement { public BlankCaseElement() { super(""); diff --git a/src/main/java/bjc/rgens/parser/elements/CaseElement.java b/src/main/java/bjc/rgens/parser/elements/CaseElement.java index d74ab52..a44ef6c 100644..100755 --- a/src/main/java/bjc/rgens/parser/elements/CaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/CaseElement.java @@ -1,17 +1,16 @@ package bjc.rgens.parser.elements; +import bjc.utils.funcutils.StringUtils; + +import bjc.rgens.parser.GenerationState; import bjc.rgens.parser.GrammarException; -/* - * @TODO 10/11/17 Ben Culkin :CaseElementSplit Split this into multiple - * subclasses based off of a value of ElementType. - */ /** * A element in a rule case. * * @author EVE */ -public class CaseElement { +public abstract class CaseElement { /** * The possible types of an element. * @@ -19,27 +18,27 @@ public class CaseElement { */ public static enum ElementType { /** An element that represents a literal string. */ - LITERAL, + LITERAL(true), /** An element that represents a rule reference. */ - RULEREF, + RULEREF(true), /** An element that represents a random range. */ - RANGE, + RANGE(true), /** An element that represents a variable that stores a string. */ - VARDEF, - /** - * An element that represents a variable that stores the result of generating a - * rule. - */ - EXPVARDEF; - } + VARIABLE(false); - /* Regexps for marking rule types. */ - private static final String SPECIAL_CASELEM = "\\{[^}]+\\}"; - private static final String REFER_CASELEM = "\\[[^\\]]+\\]"; - private static final String RANGE_CASELM = "\\[\\d+\\.\\.\\d+\\]"; + public final boolean spacing; + + private ElementType(boolean spacing) { + this.spacing = spacing; + } + } /** The type of this element. */ - public final ElementType type; + public boolean spacing; + + protected CaseElement() { + this(true); + } /** * Create a new case element. @@ -47,17 +46,17 @@ public class CaseElement { * @param typ * The type of this element. */ - protected CaseElement(ElementType typ) { - type = typ; + protected CaseElement(boolean spacing) { + this.spacing = spacing; } - @Override - public String toString() { - switch (type) { - default: - return String.format("Unknown type '%s'", type); - } - } + /** + * Generate this case element. + * + * @param state + * The current state of generation. + */ + public abstract void generate(GenerationState state); /** * Create a case element from a string. @@ -72,52 +71,80 @@ public class CaseElement { throw new NullPointerException("Case part cannot be null"); } - if (csepart.matches(SPECIAL_CASELEM)) { - /* Handle special cases. */ + if (csepart.matches("\\(\\S+\\)")) { + return createElement(csepart.substring(1, csepart.length() - 1)); + } else if (csepart.matches("\\{\\S+\\}")) { + /* + * Handle special case elements. + * + */ String specialBody = csepart.substring(1, csepart.length() - 1); - System.out.printf("\t\tTRACE: special body is '%s'\n", specialBody); + if (specialBody.matches("\\S+:\\S=\\S+")) { + String[] parts = StringUtils.levelSplit(specialBody, "=").toArray(new String[0]); - if (specialBody.matches("\\S+:=\\S+")) { - /* Handle expanding variable definitions. */ - String[] parts = specialBody.split(":="); + if(parts.length != 2) { + throw new GrammarException("Colon variables must have a name and a definition"); + } + + String varName = parts[0]; + + char op = varName.charAt(varName.length() - 1); + + System.err.printf("\t\tTRACE: Colon definition w/ op %d", (int)op); - if (parts.length != 2) { - String msg = "Expanded variables must be a name and a definition, seperated by :="; + // Remove the colon, plus any tacked on operator + varName = varName.substring(0, varName.length() - 2); - throw new GrammarException(msg); + return VariableDefCaseElement.parseVariable(varName, parts[1], op, true); + } else if (specialBody.matches("\\S+:=\\S+")) { + String[] parts = StringUtils.levelSplit(specialBody, "=").toArray(new String[0]); + + if(parts.length != 2) { + throw new GrammarException("Colon variables must have a name and a definition"); } - return new ExpVariableCaseElement(parts[0], parts[1]); - } else if (specialBody.matches("\\S+=\\S+")) { - /* Handle regular variable definitions. */ - String[] parts = specialBody.split("="); + String varName = parts[0]; - if (parts.length != 2) { - String msg = "Variables must be a name and a definition, seperated by ="; + varName = varName.substring(0, varName.length() - 1); - throw new GrammarException(msg); + return VariableDefCaseElement.parseVariable(varName, parts[1], ' ', true); + } else if (specialBody.matches("\\S+=\\S+")) { + String[] parts = specialBody.split("="); + if(parts.length != 2) { + throw new GrammarException("Variables must have a name and a definition"); } - return new LitVariableCaseElement(parts[0], parts[1]); - } else if (specialBody.matches("{empty}")) { + // Non-colon variables can't take an operator + return VariableDefCaseElement.parseVariable(parts[0], parts[1], (char)0, false); + } else if (specialBody.matches("empty")) { /* Literal blank, for empty cases. */ return new BlankCaseElement(); } else { throw new IllegalArgumentException(String.format("Unknown special case part '%s'", specialBody)); } - } else if (csepart.matches(REFER_CASELEM)) { - if (csepart.matches(RANGE_CASELM)) { - /* Handle ranges */ - String rawRange = csepart.substring(1, csepart.length() - 1); + } else if (csepart.matches("\\[\\S+\\]")) { + String rawCase = csepart.substring(1, csepart.length() - 1); - int firstNum = Integer.parseInt(rawRange.substring(0, rawRange.indexOf('.'))); - int secondNum = Integer.parseInt(rawRange.substring(rawRange.lastIndexOf('.') + 1)); + if (rawCase.matches("\\d+\\.{2}\\d+")) { + int firstNum = Integer.parseInt(rawCase.substring(0, rawCase.indexOf('.'))); + int secondNum = Integer.parseInt(rawCase.substring(rawCase.lastIndexOf('.') + 1)); return new RangeCaseElement(firstNum, secondNum); - } + } else if(rawCase.contains("||")) { + String[] elms = StringUtils.levelSplit(rawCase, "||").toArray(new String[0]); - return new RuleCaseElement(csepart); + return new InlineRuleCaseElement(elms); + } else if(rawCase.contains("|")) { + throw new GrammarException("\t\tERROR: Inline rule using | found, they use || now"); + + // String[] elms = StringUtils.levelSplit(rawCase, "|").toArray(new String[0]); + // return new InlineRuleCaseElement(elms); + } else { + return new RuleCaseElement(rawCase); + } + } else if(csepart.startsWith("%") && !csepart.equals("%")) { + return new RuleCaseElement(csepart); } else { return new LiteralCaseElement(csepart); } @@ -127,7 +154,7 @@ public class CaseElement { public int hashCode() { final int prime = 31; int result = 1; - result = prime * result + ((type == null) ? 0 : type.hashCode()); + result = prime * result + (spacing ? 0 : 2); return result; } @@ -140,8 +167,8 @@ public class CaseElement { if (getClass() != obj.getClass()) return false; CaseElement other = (CaseElement) obj; - if (type != other.type) + if (spacing != other.spacing) return false; return true; } -}
\ No newline at end of file +} diff --git a/src/main/java/bjc/rgens/parser/elements/ChanceCaseElement.java b/src/main/java/bjc/rgens/parser/elements/ChanceCaseElement.java new file mode 100644 index 0000000..483a103 --- /dev/null +++ b/src/main/java/bjc/rgens/parser/elements/ChanceCaseElement.java @@ -0,0 +1,20 @@ +package bjc.rgens.parser.elements; + +import bjc.rgens.parser.GenerationState; + +public class ChanceCaseElement extends CaseElement { + public final CaseElement elm; + + public int chance; + + public ChanceCaseElement(CaseElement elm, int chance) { + super(elm.spacing); + + this.elm = elm; + this.chance = chance; + } + + public void generate(GenerationState state) { + if(state.rnd.nextInt(chance) == 0) elm.generate(state); + } +} diff --git a/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java index 30925e2..e58d073 100644..100755 --- a/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java @@ -1,7 +1,40 @@ package bjc.rgens.parser.elements; -public class ExpVariableCaseElement extends VariableCaseElement { +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 ExpVariableCaseElement extends VariableDefCaseElement { public ExpVariableCaseElement(String name, String def) { - super(name, def, true); + super(name, def); + } + + @Override + public void generate(GenerationState state) { + GenerationState newState = state.newBuf(); + + Rule rl = state.findRule(varDef, true); + + if(rl != null) { + RGrammar destGrammar = rl.belongsTo; + newState.swapGrammar(destGrammar); + /* + * Don't post-process the string, we should only do that + * once. + */ + String res = destGrammar.generate(varDef, state, false); + + newState.contents = new StringBuilder(res); + } else { + String msg = String.format("No rule '%s' defined", varDef); + throw new GrammarException(msg); + } + + state.vars.put(varName, newState.contents.toString()); } } diff --git a/src/main/java/bjc/rgens/parser/elements/InlineRuleCaseElement.java b/src/main/java/bjc/rgens/parser/elements/InlineRuleCaseElement.java new file mode 100644 index 0000000..917dd33 --- /dev/null +++ b/src/main/java/bjc/rgens/parser/elements/InlineRuleCaseElement.java @@ -0,0 +1,41 @@ +package bjc.rgens.parser.elements; + +import bjc.rgens.parser.GenerationState; +import bjc.rgens.parser.RGrammarParser; + +import bjc.utils.data.IPair; +import bjc.utils.funcdata.FunctionalList; +import bjc.utils.funcdata.IList; +import bjc.utils.funcutils.StringUtils; +import bjc.utils.gen.WeightedRandom; + +public class InlineRuleCaseElement extends CaseElement { + public final WeightedRandom<CaseElement> elements; + + public InlineRuleCaseElement(String... parts) { + super(true); + + this.elements = new WeightedRandom<>(); + + for(String part : parts) { + String[] partArr; + + if(StringUtils.levelContains(part, "|")) { + partArr = StringUtils.levelSplit(part, "||").toArray(new String[0]); + } else { + partArr = new String[] {part}; + } + + IPair<IList<CaseElement>, Integer> par = RGrammarParser.parseElementString(partArr); + int prob = par.getRight(); + + for(CaseElement elm : par.getLeft()) { + elements.addProbability(prob, elm); + } + } + } + + public void generate(GenerationState state) { + elements.generateValue(state.rnd).generate(state); + } +} diff --git a/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java index 11035b1..3c6ba98 100644..100755 --- a/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java @@ -1,7 +1,13 @@ package bjc.rgens.parser.elements; -public class LitVariableCaseElement extends VariableCaseElement { +import bjc.rgens.parser.GenerationState; + +public class LitVariableCaseElement extends VariableDefCaseElement { public LitVariableCaseElement(String name, String def) { - super(name, def, false); + super(name, def); + } + + public void generate(GenerationState state) { + state.vars.put(varName, varDef); } } diff --git a/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java b/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java index d96a32d..6e0f8fd 100644 --- a/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java @@ -1,7 +1,17 @@ package bjc.rgens.parser.elements; -public class LiteralCaseElement extends StringCaseElement { - public LiteralCaseElement(String vl) { - super(vl, true); +import bjc.rgens.parser.GenerationState; + +public class LiteralCaseElement extends CaseElement { + public String val; + + public LiteralCaseElement(String val) { + super(true); + + this.val = val; + } + + public void generate(GenerationState state) { + state.contents.append(val); } } diff --git a/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java b/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java index d98bc61..e877dd1 100644..100755 --- a/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java @@ -1,16 +1,25 @@ package bjc.rgens.parser.elements; +import bjc.rgens.parser.GenerationState; + public class RangeCaseElement extends CaseElement { public final int begin; public final int end; public RangeCaseElement(int beg, int en) { - super(ElementType.RANGE); + super(true); begin = beg; end = en; } + public void generate(GenerationState state) { + int val = state.rnd.nextInt(end - begin); + val += begin; + + state.contents.append(val); + } + @Override public int hashCode() { final int prime = 31; diff --git a/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java b/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java index f4d3512..f13dbdb 100644..100755 --- a/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java @@ -1,7 +1,103 @@ package bjc.rgens.parser.elements; -public class RuleCaseElement extends StringCaseElement { +import bjc.utils.data.IPair; +import bjc.utils.data.Pair; + +import bjc.rgens.parser.*; +import bjc.rgens.parser.elements.vars.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class RuleCaseElement extends CaseElement { + public List<VariableElement> elements; + public RuleCaseElement(String vl) { - super(vl, false); + super(true); + + this.elements = VariableElement.parseElementString(vl); + } + + public RuleCaseElement(String vl, List<VariableElement> elements) { + super(true); + + this.elements = elements; + } + + public void generate(GenerationState state) { + GenerationState newState = state.newBuf(); + + boolean inName = false; + + for(VariableElement elm : elements) { + elm.generate(newState); + + if(inName == false) inName = elm.forbidSpaces; + } + + String body = newState.contents.toString(); + + if(inName) { + doGenerate(String.format("[%s]", body), state); + } else { + state.contents.append(body); + } + } + + protected void doGenerate(String actName, GenerationState state) { + GenerationState newState = state.newBuf(); + + Rule rl; + + if (actName.startsWith("[^")) { + actName = "[" + actName.substring(2); + + rl = state.findImport(actName); + } else { + rl = state.findRule(actName, true); + } + + if(rl != null) { + RGrammar destGrammar = rl.belongsTo; + newState.swapGrammar(destGrammar); + /* + * Don't postprocess the string, we should only do that + * once. + */ + String res = destGrammar.generate(actName, newState, false); + newState.contents = new StringBuilder(res); + } else { + /* + * @TODO 5/29/18 Ben Culkin :RuleSuggesting + * + * Re-get this working again. + */ + /* + if (ruleSearcher != null) { + Set<Match<? extends String>> results = ruleSearcher.search(actName, MAX_DISTANCE); + + String[] resArray = results.stream().map(Match::getMatch).toArray((i) -> new String[i]); + + String msg = String.format("No rule '%s' defined (perhaps you meant %s?)", actName, + StringUtils.toEnglishList(resArray, false)); + + throw new GrammarException(msg); + } + */ + + String msg = String.format("No rule '%s' defined", actName); + throw new GrammarException(msg); + } + + String res = newState.contents.toString(); + + if (actName.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..29b6fc9 --- /dev/null +++ b/src/main/java/bjc/rgens/parser/elements/RuleVariableCaseElement.java @@ -0,0 +1,39 @@ +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 VariableDefCaseElement { + public final boolean exhaust; + + public RuleVariableCaseElement(String varName, String varDef, boolean exhaust) { + super(varName, varDef); + + this.exhaust = exhaust; + } + + public void generate(GenerationState state) { + Rule rl = state.findRule(varDef, true); + + if(rl == null) { + throw new GrammarException("Can't create variable referencing non-existent rule " + varDef); + } + + if(exhaust) { + rl = rl.exhaust(); + } + + state.rlVars.put(varName, rl); + + if(exhaust) { + System.err.printf("\t\tFINE: Defined exhausted rulevar '%s' ('%s')\n", varName, varDef); + } else { + System.err.printf("\t\tFINE: Defined rulevar '%s' ('%s')\n", varName, varDef); + } + } +} diff --git a/src/main/java/bjc/rgens/parser/elements/SerialCaseElement.java b/src/main/java/bjc/rgens/parser/elements/SerialCaseElement.java new file mode 100644 index 0000000..348cfbb --- /dev/null +++ b/src/main/java/bjc/rgens/parser/elements/SerialCaseElement.java @@ -0,0 +1,30 @@ +package bjc.rgens.parser.elements; + +import bjc.rgens.parser.GenerationState; + +public class SerialCaseElement extends CaseElement { + public final CaseElement rep; + + public final int lower; + public final int upper; + + public SerialCaseElement(CaseElement rep, int lower, int upper) { + super(rep.spacing); + + this.rep = rep; + + this.lower = lower; + this.upper = upper; + } + + public void generate(GenerationState state) { + int num = state.rnd.nextInt(upper - lower) + lower; + + for(int i = 0; i < num; i++) { + rep.generate(state); + + if(rep.spacing) + state.contents.append(" "); + } + } +} diff --git a/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java b/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java index 0e64fd3..00441c0 100644..100755 --- a/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java @@ -1,10 +1,10 @@ package bjc.rgens.parser.elements; -public class StringCaseElement extends CaseElement { +public abstract class StringCaseElement extends CaseElement { public final String val; - protected StringCaseElement(String vl, boolean isLiteral) { - super(isLiteral ? ElementType.LITERAL : ElementType.RULEREF); + protected StringCaseElement(String vl) { + super(true); val = vl; } diff --git a/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/VariableDefCaseElement.java index 920445a..37a12b6 100644..100755 --- a/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/VariableDefCaseElement.java @@ -1,6 +1,8 @@ package bjc.rgens.parser.elements; -public class VariableCaseElement extends CaseElement { +import bjc.rgens.parser.GrammarException; + +public abstract class VariableDefCaseElement extends CaseElement { /** * The name of the variable this element defines. */ @@ -11,8 +13,8 @@ public class VariableCaseElement extends CaseElement { */ public final String varDef; - public VariableCaseElement(String name, String def, boolean isExp) { - super(isExp ? ElementType.EXPVARDEF : ElementType.VARDEF); + public VariableDefCaseElement(String name, String def) { + super(false); varName = name; varDef = def; @@ -35,7 +37,7 @@ public class VariableCaseElement extends CaseElement { return false; if (getClass() != obj.getClass()) return false; - VariableCaseElement other = (VariableCaseElement) obj; + VariableDefCaseElement other = (VariableDefCaseElement) obj; if (varDef == null) { if (other.varDef != null) return false; @@ -49,12 +51,16 @@ public class VariableCaseElement extends CaseElement { return true; } - @Override - public String toString() { - if (type == ElementType.VARDEF) { - return String.format("{%s:=%s}", varName, varDef); + public static CaseElement parseVariable(String varName, String varDef, char op, 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 { - return String.format("{%s=%s}", varName, varDef); + throw new GrammarException("Unrecognized declaration sigil " + varName.charAt(0)); } } } diff --git a/src/main/java/bjc/rgens/parser/elements/vars/ARefVariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/ARefVariableElement.java new file mode 100644 index 0000000..a4bb730 --- /dev/null +++ b/src/main/java/bjc/rgens/parser/elements/vars/ARefVariableElement.java @@ -0,0 +1,31 @@ +package bjc.rgens.parser.elements.vars; + +import bjc.rgens.parser.GenerationState; +import bjc.rgens.parser.GrammarException; +import bjc.rgens.parser.Rule; + +public class ARefVariableElement extends VariableElement { + public String value; + + public ARefVariableElement(String val) { + super(false); + + value = val; + } + + public void generate(GenerationState state) { + if(!state.rlVars.containsKey(value)) { + throw new GrammarException("No rule variable named " + value); + } + + Rule rl = state.rlVars.get(value); + + GenerationState newState = state.newBuf(); + + rl.generate(newState); + + String res = newState.contents.toString(); + + state.contents.append(res); + } +} diff --git a/src/main/java/bjc/rgens/parser/elements/vars/LiteralVariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/LiteralVariableElement.java new file mode 100644 index 0000000..cf33c66 --- /dev/null +++ b/src/main/java/bjc/rgens/parser/elements/vars/LiteralVariableElement.java @@ -0,0 +1,17 @@ +package bjc.rgens.parser.elements.vars; + +import bjc.rgens.parser.GenerationState; + +public class LiteralVariableElement extends VariableElement { + public String val; + + public LiteralVariableElement(boolean forbidSpaces, String val) { + super(forbidSpaces); + + this.val = val; + } + + public void generate(GenerationState state) { + state.contents.append(val); + } +} diff --git a/src/main/java/bjc/rgens/parser/elements/vars/RRefVariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/RRefVariableElement.java new file mode 100644 index 0000000..d731d64 --- /dev/null +++ b/src/main/java/bjc/rgens/parser/elements/vars/RRefVariableElement.java @@ -0,0 +1,31 @@ +package bjc.rgens.parser.elements.vars; + +import bjc.rgens.parser.GenerationState; +import bjc.rgens.parser.GrammarException; +import bjc.rgens.parser.Rule; + +public class RRefVariableElement extends VariableElement { + public String value; + + public RRefVariableElement(boolean forbidSpaces, String val) { + super(forbidSpaces); + + value = val; + } + + public void generate(GenerationState state) { + Rule rl = state.findRule(value, true); + + GenerationState newState = state.newBuf(); + + rl.generate(newState); + + String res = newState.contents.toString(); + + if(forbidSpaces && res.contains(" ")) { + throw new GrammarException("Spaces not allowed in this context (rule-reference %s)"); + } + + state.contents.append(res); + } +} diff --git a/src/main/java/bjc/rgens/parser/elements/vars/TRefVariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/TRefVariableElement.java new file mode 100644 index 0000000..a33d78c --- /dev/null +++ b/src/main/java/bjc/rgens/parser/elements/vars/TRefVariableElement.java @@ -0,0 +1,42 @@ +package bjc.rgens.parser.elements.vars; + +import bjc.rgens.parser.GenerationState; +import bjc.rgens.parser.GrammarException; +import bjc.rgens.parser.templates.GrammarTemplate; + +/* + * @TODO + * + * finish when template vars are implemented. + */ +public class TRefVariableElement extends VariableElement { + public String value; + + public TRefVariableElement(boolean forbidSpaces, String val) { + super(forbidSpaces); + + value = val; + } + + public void generate(GenerationState state) { + /* + if(!state.rlVars.containsKey(val)) { + throw new GrammarException("No rule variable named " + val); + } + + Rule rl = state.rlVars.get(val); + + GenerationState newState = state.newBuf(); + + rl.generate(newState); + + String res = newState.contents.toString(); + + if(forbidSpaces && res.contains(" ")) { + throw new GrammarException("Spaces not allowed in this context (rule-var %s)"); + } + + return res; + */ + } +} diff --git a/src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java new file mode 100644 index 0000000..b19f785 --- /dev/null +++ b/src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java @@ -0,0 +1,27 @@ +package bjc.rgens.parser.elements.vars; + +import bjc.rgens.parser.GenerationState; +import bjc.rgens.parser.GrammarException; + +public class VRefVariableElement extends VariableElement { + public final String nam; + + public VRefVariableElement(boolean forbidSpaces, String nam) { + super(forbidSpaces); + + this.nam = nam; + } + + public void generate(GenerationState state) { + if (!state.vars.containsKey(nam)) { + throw new GrammarException(String.format("No variable '%s' defined", nam)); + } + + String strang = state.vars.get(nam); + if(forbidSpaces && strang.contains(" ")) { + throw new GrammarException(String.format("Cannot include variable %s w/ spaces in body in rule name", nam)); + } + + state.contents.append(strang); + } +} diff --git a/src/main/java/bjc/rgens/parser/elements/vars/VariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/VariableElement.java new file mode 100644 index 0000000..19c1e2c --- /dev/null +++ b/src/main/java/bjc/rgens/parser/elements/vars/VariableElement.java @@ -0,0 +1,71 @@ +package bjc.rgens.parser.elements.vars; + +import bjc.utils.funcutils.StringUtils; + +import bjc.rgens.parser.GenerationState; +import bjc.rgens.parser.GrammarException; + +import java.util.ArrayList; +import java.util.List; + +public abstract class VariableElement { + public boolean forbidSpaces; + + protected VariableElement(boolean forbidSpacing) { + forbidSpaces = forbidSpacing; + } + + public abstract void generate(GenerationState state); + + public static List<VariableElement> parseElementString(String varElm) { + boolean forbidSpaces = StringUtils.levelContains(varElm, "-", "+"); + + String[] parts; + + if(forbidSpaces) { + parts = StringUtils.levelSplit(varElm, true, "-", "+").toArray(new String[0]); + } else { + parts = new String[] { varElm }; + } + + return parseElementString(forbidSpaces, parts); + } + + public static List<VariableElement> parseElementString(boolean forbidSpaces, String... parts) { + List<VariableElement> elms = new ArrayList<>(parts.length); + + VariableElement prevElement = null; + + for (String part : parts) { + VariableElement elm = null; + + if(part.startsWith("$")) { + elm = new VRefVariableElement(forbidSpaces, part.substring(1)); + } else if (part.startsWith("@")) { + if(forbidSpaces) + throw new GrammarException("Arrays references aren't allowed in rule names"); + + elm = new ARefVariableElement(part.substring(1)); + } else if (part.startsWith("%")) { + elm = new RRefVariableElement(forbidSpaces, part.substring(1)); + } else if (part.startsWith("/")) { + throw new GrammarException("Template variables aren't implemented yet"); + } else { + if(prevElement != null && prevElement instanceof LiteralVariableElement) { + /* Aggregate chain literals together */ + ((LiteralVariableElement)prevElement).val += part; + } else { + elm = new LiteralVariableElement(forbidSpaces, part); + } + } + + if(elm != null) { + elms.add(elm); + + prevElement = elm; + } + } + + return elms; + } +} |
