diff options
Diffstat (limited to 'src/main/java/bjc/rgens/parser/elements')
8 files changed, 219 insertions, 23 deletions
diff --git a/src/main/java/bjc/rgens/parser/elements/CaseElement.java b/src/main/java/bjc/rgens/parser/elements/CaseElement.java index d74ab52..522de7a 100755 --- a/src/main/java/bjc/rgens/parser/elements/CaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/CaseElement.java @@ -1,17 +1,14 @@ package bjc.rgens.parser.elements; +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. * @@ -34,8 +31,6 @@ public class CaseElement { } /* 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+\\]"; /** The type of this element. */ @@ -53,13 +48,18 @@ public class CaseElement { @Override public String toString() { - switch (type) { - default: - return String.format("Unknown type '%s'", type); - } + 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. * * @param csepart @@ -72,8 +72,11 @@ public class CaseElement { throw new NullPointerException("Case part cannot be null"); } - if (csepart.matches(SPECIAL_CASELEM)) { - /* Handle special cases. */ + if (csepart.matches("\\{[^}]+\\}")) { + /* + * Handle special cases. + * + */ String specialBody = csepart.substring(1, csepart.length() - 1); System.out.printf("\t\tTRACE: special body is '%s'\n", specialBody); @@ -88,6 +91,12 @@ public 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]); } else if (specialBody.matches("\\S+=\\S+")) { /* Handle regular variable definitions. */ @@ -100,23 +109,28 @@ public class CaseElement { } return new LitVariableCaseElement(parts[0], parts[1]); - } else if (specialBody.matches("{empty}")) { + } 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("\\[[^\\]]+\\]")) { + 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+\\.\\.\\d+")) { + int firstNum = Integer.parseInt(rawCase.substring(0, rawCase.indexOf('.'))); + int secondNum = Integer.parseInt(rawCase.substring(rawCase.lastIndexOf('.') + 1)); return new RangeCaseElement(firstNum, secondNum); } + /* + * @NOTE + * + * Once the rule element execution has been refactored, + * pass rawCase instead. + */ return new RuleCaseElement(csepart); } else { return new LiteralCaseElement(csepart); @@ -144,4 +158,4 @@ public class CaseElement { return false; return true; } -}
\ No newline at end of file +} diff --git a/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java index 30925e2..8598fbd 100755 --- a/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/ExpVariableCaseElement.java @@ -1,7 +1,45 @@ package bjc.rgens.parser.elements; +import bjc.rgens.parser.GenerationState; +import bjc.rgens.parser.GrammarException; +import bjc.rgens.parser.RGrammar; +import bjc.rgens.parser.RuleCase; + public class ExpVariableCaseElement extends VariableCaseElement { public ExpVariableCaseElement(String name, String def) { super(name, def, true); } + + @Override + public void generate(GenerationState state) { + GenerationState newState = state.newBuf(); + + if (state.rules.containsKey(varDef)) { + RuleCase destCase = state.rules.get(varDef).getCase(); + + state.gram.generateCase(destCase, newState); + } else if (state.importRules.containsKey(varDef)) { + RGrammar destGrammar = state.importRules.get(varDef); + + newState.swapGrammar(destGrammar); + + String res = destGrammar.generate(varDef, state); + + /* + * @NOTE + * + * :Postprocessing + * + * This is because generate() returns a processed + * string, but modifies the passed in StringBuilder. + */ + 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/LitVariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java index 11035b1..91b8a2b 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; +import bjc.rgens.parser.GenerationState; + public class LitVariableCaseElement extends VariableCaseElement { public LitVariableCaseElement(String name, String def) { super(name, def, false); } + + 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..18c3482 100755 --- a/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java @@ -1,7 +1,14 @@ package bjc.rgens.parser.elements; +import bjc.rgens.parser.GenerationState; + public class LiteralCaseElement extends StringCaseElement { public LiteralCaseElement(String vl) { super(vl, true); } + + @Override + 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..7cebde9 100755 --- a/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java @@ -1,5 +1,7 @@ package bjc.rgens.parser.elements; +import bjc.rgens.parser.GenerationState; + public class RangeCaseElement extends CaseElement { public final int begin; public final int end; @@ -11,6 +13,13 @@ public class RangeCaseElement extends CaseElement { 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..d91bebc 100755 --- a/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java @@ -1,7 +1,129 @@ package bjc.rgens.parser.elements; +import bjc.rgens.parser.*; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + public class RuleCaseElement extends StringCaseElement { + private static Pattern NAMEVAR_PATTERN = Pattern.compile("\\$(\\w+)"); + public RuleCaseElement(String vl) { super(vl, false); } + + @Override + public void generate(GenerationState state) { + /* + * @NOTE + * + * :VarRefactor + * + * Figure out if this can be refactored in some way. + */ + String refersTo = val; + + GenerationState newState = state.newBuf(); + + if (refersTo.contains("$")) { + /* Parse variables */ + String refBody = refersTo.substring(1, refersTo.length() - 1); + + if (refBody.contains("-")) { + /* Handle dependent rule names. */ + StringBuffer nameBuffer = new StringBuffer(); + + Matcher nameMatcher = NAMEVAR_PATTERN.matcher(refBody); + + while (nameMatcher.find()) { + String var = nameMatcher.group(1); + + if (!state.vars.containsKey(var)) { + String msg = String.format("No variable '%s' defined", var); + throw new GrammarException(msg); + } + + String name = state.vars.get(var); + + if (name.contains(" ")) { + throw new GrammarException("Variables substituted into names cannot contain spaces"); + } else if (name.equals("")) { + throw new GrammarException("Variables substituted into names cannot be empty"); + } + + nameMatcher.appendReplacement(nameBuffer, name); + } + + nameMatcher.appendTail(nameBuffer); + + refersTo = "[" + nameBuffer.toString() + "]"; + } else { + /* Handle string references. */ + if (refBody.equals("$")) { + throw new GrammarException("Cannot refer to unnamed variables"); + } + + String key = refBody.substring(1); + + if (!state.vars.containsKey(key)) { + String msg = String.format("No variable '%s' defined", key); + throw new GrammarException(msg); + } + + state.contents.append(state.vars.get(key)); + + return; + } + } + + if (refersTo.startsWith("[^")) { + refersTo = "[" + refersTo.substring(2); + + RGrammar dst = state.importRules.get(refersTo); + + newState.swapGrammar(dst); + + /* :Postprocessing */ + newState.contents = new StringBuilder(dst.generate(refersTo, state.rnd, state.vars)); + } else if (state.rules.containsKey(refersTo)) { + RuleCase cse = state.rules.get(refersTo).getCase(state.rnd); + + state.gram.generateCase(cse, newState); + } else if (state.importRules.containsKey(refersTo)) { + RGrammar dst = state.importRules.get(refersTo); + + newState.swapGrammar(dst); + + /* :Postprocessing */ + newState.contents = new StringBuilder(dst.generate(refersTo, state.rnd, state.vars)); + } else { + /* + * @TODO 5/29/18 Ben Culkin :RuleSuggesting + * + * Re-get this working again. + */ + /* + if (ruleSearcher != null) { + Set<Match<? extends String>> results = ruleSearcher.search(refersTo, 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?)", refersTo, + StringUtils.toEnglishList(resArray, false)); + + throw new GrammarException(msg); + } + */ + + String msg = String.format("No rule '%s' defined", refersTo); + throw new GrammarException(msg); + } + + if (refersTo.contains("+")) { + /* Rule names with pluses in them get space-flattened */ + state.contents.append(newState.contents.toString().replaceAll("\\s+", "")); + } else { + state.contents.append(newState.contents.toString()); + } + } } diff --git a/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java b/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java index 0e64fd3..61ad48a 100755 --- a/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java @@ -1,6 +1,6 @@ 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) { diff --git a/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java index 920445a..3e691d9 100755 --- a/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/VariableCaseElement.java @@ -1,6 +1,6 @@ package bjc.rgens.parser.elements; -public class VariableCaseElement extends CaseElement { +public abstract class VariableCaseElement extends CaseElement { /** * The name of the variable this element defines. */ |
