diff options
| author | Benjamin J. Culkin <bjculkin@mix.wvu.edu> | 2020-11-11 12:29:59 -0400 |
|---|---|---|
| committer | Benjamin J. Culkin <bjculkin@mix.wvu.edu> | 2020-11-11 12:29:59 -0400 |
| commit | 80aa147aedc91356276d4346efb1ea62ea5b06f9 (patch) | |
| tree | a57c8f2ad3a7e68ba1c0a5a2bea573a8da277ab6 | |
| parent | c88c846b75dbc806db19a2e3a907bff21fd0c273 (diff) | |
| parent | e9e0ca7bfe722375e7ccb25d2bafbe395b6c6a59 (diff) | |
Merge branch 'master' of https://github.com/bculkin2442/rgens
31 files changed, 1456 insertions, 609 deletions
diff --git a/src/main/java/bjc/rgens/parser/AffixType.java b/src/main/java/bjc/rgens/parser/AffixType.java new file mode 100644 index 0000000..e591a45 --- /dev/null +++ b/src/main/java/bjc/rgens/parser/AffixType.java @@ -0,0 +1,39 @@ +package bjc.rgens.parser; + +/** + * The type of ways to affix rules. + * @author Ben Culkin + * + */ +public enum AffixType { + /** + * Prefix and suffix the rules. + */ + CIRCUMFIX, + /** + * Suffix the rules. + */ + SUFFIX, + /** + * Prefix the rules. + */ + PREFIX; + + /** + * Does this affix type perform suffixing? + * + * @return Whether this affix type performs suffixing. + */ + public boolean isSuffix() { + return this != PREFIX; + } + + /** + * Does this affix type perform prefixing? + * + * @return Whether this affix type performs prefixing. + */ + public boolean isPrefix() { + return this != SUFFIX; + } +}
\ No newline at end of file diff --git a/src/main/java/bjc/rgens/parser/ConfigLoader.java b/src/main/java/bjc/rgens/parser/ConfigLoader.java index 8daff71..8427726 100644 --- a/src/main/java/bjc/rgens/parser/ConfigLoader.java +++ b/src/main/java/bjc/rgens/parser/ConfigLoader.java @@ -40,15 +40,17 @@ public class ConfigLoader { * Load a grammar set from a configuration file. * * @param cfgFile - * The configuration file to load from. + * The configuration file to load from. + * @param lopts + * Options used during loading. * - * @return - * The grammar set created by the configuration file. + * @return The grammar set created by the configuration file. * * @throws IOException - * If something goes wrong during configuration loading. + * If something goes wrong during configuration loading. */ - public static ConfigSet fromConfigFile(Path cfgFile, LoadOptions lopts) throws IOException { + public static ConfigSet fromConfigFile(Path cfgFile, LoadOptions lopts) + throws IOException { String msg = String.format("INFO: Loading config file from path '%s'", cfgFile); ITree<String> errTree = new Tree<>(msg); @@ -60,20 +62,22 @@ public class ConfigLoader { * Load a grammar set from a configuration file. * * @param cfgFile - * The configuration file to load from. + * The configuration file to load from. + * @param lopts + * Options used during loading. * * @param errs - * A place to add errors that occur during loading. + * A place to add errors that occur during loading. * - * @return - * The grammar set created by the configuration file. + * @return The grammar set created by the configuration file. * * @throws IOException - * If something goes wrong during configuration loading. + * If something goes wrong during configuration loading. */ - public static ConfigSet fromConfigFile(Path cfgFile, LoadOptions lopts, ITree<String> errs) throws IOException { + public static ConfigSet fromConfigFile(Path cfgFile, LoadOptions lopts, + ITree<String> errs) throws IOException { lopts.cfgFile = cfgFile; - lopts.cfgSet = new ConfigSet(); + lopts.cfgSet = new ConfigSet(); /* The grammar set we're parsing into. */ lopts.gramSet = lopts.cfgSet.createGSet(lopts.defName); @@ -81,10 +85,11 @@ public class ConfigLoader { long startCFGTime = System.nanoTime(); // Get the directory that contains the config file. - if (lopts.parent == null) lopts.parent = cfgFile.getParent(); + if (lopts.parent == null) + lopts.parent = cfgFile.getParent(); int lno = 0; - try(Scanner scn = new Scanner(cfgFile)) { + try (Scanner scn = new Scanner(cfgFile)) { while (scn.hasNextLine()) { // Execute a line from the configuration file. @@ -99,18 +104,21 @@ public class ConfigLoader { String ln = scn.nextLine().trim().replaceAll("\\s+", " "); // Ignore blank/comment lines. - if (ln.equals("")) continue; - if (ln.startsWith("#")) continue; + if (ln.equals("")) + continue; + if (ln.startsWith("#")) + continue; // @TODO Ben Culkin 9/21/2019 :LineCont // We should support some sort of line // continuation ability, probably using the '\' // since that what UNIX uses in most places - ITree<String> header = new Tree<>(String.format("INFO: Processing line %d", lno)); + ITree<String> header + = new Tree<>(String.format("INFO: Processing line %d", lno)); String[] parts = StringUtils.levelSplit(ln, " ").toArray(new String[0]); - if(parts.length < 1) { + if (parts.length < 1) { // Must specify a line type // // @TODO Ben Culkin 9/21/2019 :ErrorLine @@ -138,12 +146,13 @@ public class ConfigLoader { } else { String type = parts[0]; - switch(type) { - case "load": + switch (type) { + case "load": loadConfigLine(parts, lopts, header); break; default: - String fmt = String.format("ERROR: Unknown config line type '%s'", type); + String fmt = String.format("ERROR: Unknown config line type '%s'", + type); header.addChild(fmt); } @@ -158,7 +167,9 @@ public class ConfigLoader { long cfgDur = endCFGTime - startCFGTime; if (lopts.doPerf) { - String fmt = String.format("PERF: Read config file (%d lines) from path '%s' in %d ns (%f s)", lno, cfgFile, cfgDur, cfgDur / 1000000000.0); + String fmt = String.format( + "PERF: Read config file (%d lines) from path '%s' in %d ns (%f s)", + lno, cfgFile, cfgDur, cfgDur / 1000000000.0); errs.addChild(fmt); } @@ -167,8 +178,9 @@ public class ConfigLoader { } // Load a line from a config file. - private static void loadConfigLine(String[] parts, LoadOptions lopts, ITree<String> errs) throws IOException { - if(parts.length < 2) { + private static void loadConfigLine(String[] parts, LoadOptions lopts, + ITree<String> errs) throws IOException { + if (parts.length < 2) { // Must specify the type of config object you wish to // load. // @@ -191,48 +203,50 @@ public class ConfigLoader { // Perhaps do a thing that auto-picks a plausible name // for the object based off of the file name we're // loading from? - String fmt = String.format("ERROR: Must specify a name for config object of type '%s'", tag); + String fmt = String.format( + "ERROR: Must specify a name for config object of type '%s'", tag); errs.addChild(fmt); return; } - String name = parts[2]; - - switch(tag) { - case "template": - loadTemplate(name, parts, lopts, errs); - break; - case "subset": - { - String fmt = String.format("ERROR: Sub-grammar sets aren't implemented yet"); - - /* - * @TODO Ben Culkin 9/8/17 :SubsetGrammar - * Implement subset grammars. - */ - errs.addChild(fmt); - } - case "gram": - case "grammar": - loadGrammar(name, parts, lopts, errs); - break; - case "directory": - loadDirectory(name, parts, lopts, errs); - break; - default: - String fmt = String.format("ERROR: Unrecognized config object type '%s'", tag); + String name = parts[2]; - errs.addChild(fmt); + switch (tag) { + case "template": + loadTemplate(name, parts, lopts, errs); + break; + case "subset": { + String fmt = String.format("ERROR: Sub-grammar sets aren't implemented yet"); + + /* + * @TODO Ben Culkin 9/8/17 :SubsetGrammar Implement subset grammars. + */ + errs.addChild(fmt); + } + case "gram": + case "grammar": + loadGrammar(name, parts, lopts, errs); + break; + case "directory": + loadDirectory(name, parts, lopts, errs); + break; + default: + String fmt + = String.format("ERROR: Unrecognized config object type '%s'", tag); + + errs.addChild(fmt); } } // Load a 'directory' config object, by recursively attempting to // auto-load all of the items in the directory as objects - private static void loadDirectory(String name, String[] parts, LoadOptions lopts, ITree<String> errs) throws IOException { - if(parts.length < 4) { - String fmt = String.format("ERROR: Must specify a path to load directory '%s' from", name); + private static void loadDirectory(String name, String[] parts, LoadOptions lopts, + ITree<String> errs) { + if (parts.length < 4) { + String fmt = String.format( + "ERROR: Must specify a path to load directory '%s' from", name); errs.addChild(fmt); @@ -242,12 +256,11 @@ public class ConfigLoader { Path path = Paths.get(parts[3]); /* - * Convert from configuration relative path to - * absolute path. + * Convert from configuration relative path to absolute path. */ Path dirPath = lopts.parent.resolve(path.toString()); - if(!Files.isDirectory(dirPath)) { + if (!Files.isDirectory(dirPath)) { String fmt = String.format("ERROR: '%s' is not a valid directory", dirPath); errs.addChild(fmt); @@ -255,16 +268,19 @@ public class ConfigLoader { // Create an iterator over all of the files in the // provided directory. This will also have the files for // the sub-directories added to it as well - QueuedIterator<File> dirItr = new QueuedIterator<>(dirPath.toFile().listFiles()); + QueuedIterator<File> dirItr + = new QueuedIterator<>(dirPath.toFile().listFiles()); - ITree<String> header = new Tree<>(String.format("INFO: Bulk-loading objects from directory '%s'", lopts.parent)); + ITree<String> header = new Tree<>(String.format( + "INFO: Bulk-loading objects from directory '%s'", lopts.parent)); while (dirItr.hasNext()) { File curFile = dirItr.next(); String fName = curFile.toString(); - ITree<String> kid = new Tree<>(String.format("INFO: Processing object from path '%s'", fName)); + ITree<String> kid = new Tree<>( + String.format("INFO: Processing object from path '%s'", fName)); Path oldPar = lopts.parent; @@ -290,7 +306,8 @@ public class ConfigLoader { } else if (fName.endsWith(".class")) { // These get ignored } else { - String fmt = String.format("WARN: Ignoring unknown type of file '%s'"); + String fmt = String + .format("WARN: Ignoring unknown type of file '%s'"); kid.addChild(fmt); @@ -310,16 +327,17 @@ public class ConfigLoader { } // Actually do the work of loading a 'template' object - private static void doLoadTemplate(Reader rdr, String name, LoadOptions lopts, ITree<String> errs) throws IOException { + private static void doLoadTemplate(Reader rdr, String name, LoadOptions lopts, + ITree<String> errs) throws IOException { String actName; - + long startFileTime = System.nanoTime(); GrammarTemplate template = GrammarTemplate.readTemplate(rdr, errs); template.belongsTo = lopts.cfgSet; - if(template.name == null) { - if(name == null) { + if (template.name == null) { + if (name == null) { String fmt = String.format("WARN: Using default name for template"); errs.addChild(fmt); @@ -329,7 +347,9 @@ public class ConfigLoader { actName = name; } - String fmt = String.format("INFO: Naming unnamed template off name '%s' specified in config", actName); + String fmt = String.format( + "INFO: Naming unnamed template off name '%s' specified in config", + actName); errs.addChild(fmt); template.name = actName; @@ -342,7 +362,8 @@ public class ConfigLoader { long fileTime = endFileTime - startFileTime; if (lopts.doPerf) { - String fmt = String.format("PERF: Read template %s in %d ns (%f s)", template.name, fileTime, fileTime / 1000000000.0); + String fmt = String.format("PERF: Read template %s in %d ns (%f s)", + template.name, fileTime, fileTime / 1000000000.0); errs.addChild(fmt); } @@ -355,17 +376,19 @@ public class ConfigLoader { * * Do we need to do this for templates? * - * Probably, if only to allow for some better diagnostics when - * we need them - ben, 9/21/2019 + * Probably, if only to allow for some better diagnostics when we need them - + * ben, 9/21/2019 */ - //Mark where the template came from. - //set.loadedFrom.put(template.name, path.toString()); + // Mark where the template came from. + // set.loadedFrom.put(template.name, path.toString()); } // Load a 'template' type grammar object - private static void loadTemplate(String name, String[] parts, LoadOptions lopts, ITree<String> errs) throws IOException { - if(parts.length < 4) { - String fmt = String.format("ERROR: Must specify a path to load template '%s' from", name); + private static void loadTemplate(String name, String[] parts, LoadOptions lopts, + ITree<String> errs) throws IOException { + if (parts.length < 4) { + String fmt = String.format( + "ERROR: Must specify a path to load template '%s' from", name); errs.addChild(fmt); @@ -375,23 +398,24 @@ public class ConfigLoader { Path path = Paths.get(parts[3]); /* - * Convert from configuration relative path to - * absolute path. + * Convert from configuration relative path to absolute path. */ Path convPath = lopts.parent.resolve(path.toString()); - if(!Files.exists(convPath) || Files.isDirectory(convPath)) { - String fmt = String.format("ERROR: '%s' is not a valid grammar file", convPath); + if (!Files.exists(convPath) || Files.isDirectory(convPath)) { + String fmt + = String.format("ERROR: '%s' is not a valid grammar file", convPath); errs.addChild(fmt); } else { /* Load template file. */ Reader rdr = new FileReader(convPath.toFile()); - String fmt = String.format("INFO: Loading template '%s' from '%s'", name, convPath); + String fmt = String.format("INFO: Loading template '%s' from '%s'", name, + convPath); ITree<String> kid = new Tree<>(fmt); - Path oldPar = lopts.parent; + Path oldPar = lopts.parent; lopts.parent = convPath.getParent(); try { @@ -405,14 +429,15 @@ public class ConfigLoader { } // Actually load a 'grammar' object - private static void doLoadGrammar(Reader rdr, String name, LoadOptions lopts, ITree<String> errs, Path convPath) throws IOException { + private static void doLoadGrammar(Reader rdr, String name, LoadOptions lopts, + ITree<String> errs, Path convPath) throws IOException { String actName; long startFileTime = System.nanoTime(); RGrammar gram = RGrammarParser.readGrammar(rdr, lopts, errs); - if(gram.name == null) { - if(name == null) { + if (gram.name == null) { + if (name == null) { errs.addChild("WARN: Using default name for grammar"); actName = "default-name"; @@ -420,7 +445,8 @@ public class ConfigLoader { actName = name; } - //String fmt = String.format("INFO: Naming unnamed grammar off config name '%s'", actName); + // String fmt = String.format("INFO: Naming unnamed grammar off config name + // '%s'", actName); gram.name = actName; } @@ -432,7 +458,8 @@ public class ConfigLoader { long fileTime = endFileTime - startFileTime; if (lopts.doPerf) { - String fmt = String.format("PERF: Read grammar %s in %d ns (%f s)", gram.name, fileTime, fileTime / 1000000000.0); + String fmt = String.format("PERF: Read grammar %s in %d ns (%f s)", gram.name, + fileTime, fileTime / 1000000000.0); errs.addChild(fmt); } @@ -441,16 +468,17 @@ public class ConfigLoader { lopts.gramSet.addGrammar(gram.name, gram); /* - * Mark where the grammar came - * from. + * Mark where the grammar came from. */ lopts.gramSet.loadedFrom.put(gram.name, convPath.toString()); } // Load a 'grammar' object - private static void loadGrammar(String name, String[] parts, LoadOptions lopts, ITree<String> errs) throws IOException { - if(parts.length < 4) { - String fmt = String.format("ERROR: Must provide a path to load grammar '%s' from", name); + private static void loadGrammar(String name, String[] parts, LoadOptions lopts, + ITree<String> errs) { + if (parts.length < 4) { + String fmt = String + .format("ERROR: Must provide a path to load grammar '%s' from", name); errs.addChild(fmt); @@ -460,13 +488,13 @@ public class ConfigLoader { Path path = Paths.get(parts[3]); /* - * Convert from configuration relative path to - * absolute path. + * Convert from configuration relative path to absolute path. */ Path convPath = lopts.parent.resolve(path.toString()); - if(!Files.exists(convPath) || Files.isDirectory(convPath)) { - String fmt = String.format("ERROR: '%s' is not a valid grammar file", convPath); + if (!Files.exists(convPath) || Files.isDirectory(convPath)) { + String fmt + = String.format("ERROR: '%s' is not a valid grammar file", convPath); errs.addChild(fmt); } else { @@ -480,7 +508,8 @@ public class ConfigLoader { Reader rdr = new FileReader(convPath.toFile()); - ITree<String> kid = new Tree<>(String.format("INFO: Loading grammar '%s' from '%s'", name, convPath)); + ITree<String> kid = new Tree<>(String + .format("INFO: Loading grammar '%s' from '%s'", name, convPath)); doLoadGrammar(rdr, name, lopts, kid, convPath); diff --git a/src/main/java/bjc/rgens/parser/FlatRuleCase.java b/src/main/java/bjc/rgens/parser/FlatRuleCase.java index 5055810..0cb2626 100644 --- a/src/main/java/bjc/rgens/parser/FlatRuleCase.java +++ b/src/main/java/bjc/rgens/parser/FlatRuleCase.java @@ -35,6 +35,7 @@ public class FlatRuleCase extends RuleCase { * * @return A flat rule case, with the given elements. */ + @Override public FlatRuleCase withElements(List<CaseElement> elms) { return new FlatRuleCase(elms); } diff --git a/src/main/java/bjc/rgens/parser/GenerationState.java b/src/main/java/bjc/rgens/parser/GenerationState.java index 3eab856..65ab4cd 100644 --- a/src/main/java/bjc/rgens/parser/GenerationState.java +++ b/src/main/java/bjc/rgens/parser/GenerationState.java @@ -40,22 +40,23 @@ public class GenerationState { /** * Create a new generation state. * - * The place to write output to. + * @param rw + * The place to write output to. * * @param rand - * The random number generator to use. + * The random number generator to use. * * @param vs - * The normal variables to use. + * The normal variables to use. * * @param rvs - * The rule variables to use. + * The rule variables to use. * * @param gram - * The grammar we are generating from. + * The grammar we are generating from. */ - public GenerationState(ReportWriter rw, Random rand, Map<String, String> vs, Map<String, Rule> rvs, - RGrammar gram) { + public GenerationState(ReportWriter rw, Random rand, Map<String, String> vs, + Map<String, Rule> rvs, RGrammar gram) { vars = new MapSet<>(); rlVars = new MapSet<>(); @@ -75,27 +76,24 @@ public class GenerationState { * Create a new generation state, from a given grammar. * * @param gram - * The grammar to generate from. + * The grammar to generate from. * - * @return - * A new generation state, with the provided parameters. + * @return A new generation state, with the provided parameters. */ public static GenerationState fromGrammar(RGrammar gram) { return fromGrammar(BASE, gram); } /** - * Create a new generation state, using a provided random generator and - * grammar. + * Create a new generation state, using a provided random generator and grammar. * * @param rand - * The random number generator to use. + * The random number generator to use. * * @param gram - * The grammar to generate from. + * The grammar to generate from. * - * @return - * A new generation state, with the provided parameters. + * @return A new generation state, with the provided parameters. */ public static GenerationState fromGrammar(Random rand, RGrammar gram) { ReportWriter rw = new ReportWriter(new StringWriter()); @@ -106,27 +104,28 @@ public class GenerationState { /** * Swap the grammar for the state. * - * @param gram - * The grammar to swap to. + * @param gramr + * The grammar to swap to. */ - public void swapGrammar(RGrammar gram) { - if (this.gram == gram) return; + public void swapGrammar(RGrammar gramr) { + if (this.gram == gramr) + return; - this.gram = gram; + this.gram = gramr; - rules = gram.getRules(); + rules = gramr.getRules(); - importRules = gram.getImportRules(); + importRules = gramr.getImportRules(); - vars.setCreateMap(gram.name); - rlVars.setCreateMap(gram.name); + vars.setCreateMap(gramr.name); + rlVars.setCreateMap(gramr.name); } /** * Create a copy of this generation state, writing into a fresh buffer. * * @return A generation state that is a copy of this one, but writes into a - * fresh buffer. + * fresh buffer. */ public GenerationState newBuf() { // @NOTE 9/5/18 @@ -144,28 +143,29 @@ public class GenerationState { /* * @TODO 6/5/18 Ben Culkin :ImportRefactor * - * Change this so that imports in almost all cases have to specify where - * they are importing the rule from, so as to make it clear which rules - * are imported, and which aren't + * Change this so that imports in almost all cases have to specify where they + * are importing the rule from, so as to make it clear which rules are imported, + * and which aren't */ /** * Find an instance of a rule. * * @param ruleName - * The name of the rule to look for. + * The name of the rule to look for. * * @param allowImports - * Whether or not to look for imported rules. + * Whether or not to look for imported rules. * - * @return The rule instance you were looking for, or null if none by that - * name happen to exist. + * @return The rule instance you were looking for, or null if none by that name + * happen to exist. */ public Rule findRule(String ruleName, boolean allowImports) { if (rules.containsKey(ruleName)) { return rules.get(ruleName); } - if (allowImports) return findImport(ruleName); + if (allowImports) + return findImport(ruleName); return null; } @@ -174,10 +174,10 @@ public class GenerationState { * Find an instance of an imported rule. * * @param ruleName - * The name of the rule to look for. + * The name of the rule to look for. * - * @return The rule instance you were looking for, or null if none by that - * name happen to exist. + * @return The rule instance you were looking for, or null if none by that name + * happen to exist. */ public Rule findImport(String ruleName) { if (importRules.containsKey(ruleName)) { @@ -191,16 +191,18 @@ public class GenerationState { * Define a normal variable. * * @param name - * The name to give the variable. + * The name to give the variable. * * @param val - * The value to give the variable. + * The value to give the variable. */ public void defineVar(String name, String val) { if (vars.containsKey(name)) - warn("Shadowing variable %s with value %s (old value %s)", name, val, vars.get(name)); + warn("Shadowing variable %s with value %s (old value %s)", name, val, + vars.get(name)); else if (gram.autoVars.containsKey(name)) - warn("Shadowing autovariable %s with value %s (defn. %s)", name, val, gram.autoVars.get(name)); + warn("Shadowing autovariable %s with value %s (defn. %s)", name, val, + gram.autoVars.get(name)); vars.put(name, val); } @@ -209,14 +211,15 @@ public class GenerationState { * Define a rule variable. * * @param name - * The name to give the variable. + * The name to give the variable. * * @param rle - * The value to give the variable. + * The value to give the variable. */ public void defineRuleVar(String name, Rule rle) { if (rlVars.containsKey(name)) - warn("Shadowing rule variable %s with value %s (old value %s)", name, rlVars.get(name), rle); + warn("Shadowing rule variable %s with value %s (old value %s)", name, + rlVars.get(name), rle); else if (gram.autoRlVars.containsKey(name)) warn("Shadowing rule autovariable %s with value %s (defn. %s)", name, rle, gram.autoRlVars.get(name)); @@ -228,19 +231,22 @@ public class GenerationState { * Find a variable. * * @param name - * The variable to look for. + * The variable to look for. * * @return The value of the variable. * - * @throws GrammarException If the variable isn't found, or if it was an - * auto-variable that failed to generate succesfully. + * @throws GrammarException + * If the variable isn't found, or if it was an + * auto-variable that failed to generate succesfully. */ public String findVar(String name) { - if (!vars.containsKey(name)) if (gram.autoVars.containsKey(name)) { - gram.autoVars.get(name).generate(this); - } else { - throw new GrammarException(String.format("Variable %s not defined", name)); - } + if (!vars.containsKey(name)) + if (gram.autoVars.containsKey(name)) { + gram.autoVars.get(name).generate(this); + } else { + throw new GrammarException( + String.format("Variable %s not defined", name)); + } return vars.get(name); } @@ -249,25 +255,31 @@ public class GenerationState { * Find a rule variable. * * @param name - * The variable to look for. + * The variable to look for. * * @return The value of the variable. * - * @throws GrammarException If the variable isn't found, or if it was an - * auto-variable that failed to generate succesfully. + * @throws GrammarException + * If the variable isn't found, or if it was an + * auto-variable that failed to generate succesfully. */ public Rule findRuleVar(String name) { - if (!rlVars.containsKey(name)) if (gram.autoRlVars.containsKey(name)) { - gram.autoRlVars.get(name).generate(this); - } else { - throw new GrammarException(String.format("Rule variable %s not defined", name)); - } + if (!rlVars.containsKey(name)) + if (gram.autoRlVars.containsKey(name)) { + gram.autoRlVars.get(name).generate(this); + } else { + throw new GrammarException( + String.format("Rule variable %s not defined", name)); + } return rlVars.get(name); } /** * Append the given string to our output. + * + * @param strang + * The string to append. */ public void appendContents(String strang) { try { @@ -281,7 +293,7 @@ public class GenerationState { * Replace the current contents of our output with the given string. * * @param strang - * The string to replace the output with. + * The string to replace the output with. */ public void setContents(String strang) { // @NOTE 9/5/18 @@ -312,6 +324,7 @@ public class GenerationState { /** * Get our output as a string. + * @return The contents of the state. */ public String getContents() { return contents.toString(); @@ -321,10 +334,10 @@ public class GenerationState { * Execute a find/replace on our output. * * @param find - * The pattern to look for + * The pattern to look for * * @param replace - * The string to replace occurances of 'find' with. + * The string to replace occurrences of 'find' with. */ public void findReplaceContents(String find, String replace) { setContents(getContents().replaceAll(find, replace)); diff --git a/src/main/java/bjc/rgens/parser/GrammarException.java b/src/main/java/bjc/rgens/parser/GrammarException.java index 271f717..f7aca2c 100755 --- a/src/main/java/bjc/rgens/parser/GrammarException.java +++ b/src/main/java/bjc/rgens/parser/GrammarException.java @@ -1,8 +1,7 @@ package bjc.rgens.parser; /** - * The exception thrown when something goes wrong while parsing a - * grammar. + * The exception thrown when something goes wrong while parsing a grammar. * * @author student */ @@ -16,21 +15,20 @@ public class GrammarException extends RuntimeException { * Create a new grammar exception with the specified message. * * @param msg - * The message for this exception. + * The message for this exception. */ public GrammarException(String msg) { super(msg); } /** - * Create a new grammar exception with the specified message and - * cause. + * Create a new grammar exception with the specified message and cause. * * @param msg - * The message for this exception. + * The message for this exception. * * @param cause - * The cause of this exception. + * The cause of this exception. */ public GrammarException(String msg, Exception cause) { super(msg, cause); @@ -40,7 +38,9 @@ public class GrammarException extends RuntimeException { * Create a new grammar exception with the specified message. * * @param msg - * The message for this exception. + * The message for this exception. + * @param rootMsg + * The root message for this exception */ public GrammarException(String msg, String rootMsg) { super(msg); @@ -49,14 +49,15 @@ public class GrammarException extends RuntimeException { } /** - * Create a new grammar exception with the specified message and - * cause. + * Create a new grammar exception with the specified message and cause. * * @param msg - * The message for this exception. + * The message for this exception. * * @param cause - * The cause of this exception. + * The cause of this exception. + * @param rootMsg + * The root message for this exception. */ public GrammarException(String msg, Exception cause, String rootMsg) { super(msg, cause); @@ -70,6 +71,6 @@ public class GrammarException extends RuntimeException { * @return The root cause of this exception. */ public String getRootMessage() { - return rootMessage == null? getMessage() : rootMessage; + return rootMessage == null ? getMessage() : rootMessage; } } diff --git a/src/main/java/bjc/rgens/parser/NormalRuleCase.java b/src/main/java/bjc/rgens/parser/NormalRuleCase.java index 705a118..9663815 100644 --- a/src/main/java/bjc/rgens/parser/NormalRuleCase.java +++ b/src/main/java/bjc/rgens/parser/NormalRuleCase.java @@ -39,6 +39,7 @@ public class NormalRuleCase extends RuleCase { * * @return A normal rule case with those elements. */ + @Override public NormalRuleCase withElements(List<CaseElement> elms) { return new NormalRuleCase(elms); } diff --git a/src/main/java/bjc/rgens/parser/RGrammar.java b/src/main/java/bjc/rgens/parser/RGrammar.java index 4fe1d79..612fcfe 100755 --- a/src/main/java/bjc/rgens/parser/RGrammar.java +++ b/src/main/java/bjc/rgens/parser/RGrammar.java @@ -48,6 +48,10 @@ public class RGrammar { /* The default post-processing rules to apply. */ private static final List<IPair<String, String>> builtinPostprocs; + + /** + * Should we use the built-in post-processing procedures? + */ public boolean useBuiltinPostprocs = true; /* The max distance between possible alternate rules. */ @@ -103,24 +107,19 @@ public class RGrammar { IPair<String, String> collapseDupSpaces = pair("\\s+", " "); /* Built-in post-processing steps */ - builtinPostprocs = Arrays.asList( - collapseDupSpaces, + builtinPostprocs = Arrays.asList(collapseDupSpaces, - /* - * Remove extraneous spaces around punctuation - * marks, forced by the way the language syntax - * works. + /* + * Remove extraneous spaces around punctuation marks, forced by the way + * the language syntax works. * - * This can be done in grammars, but it is quite - * tedious to do so. + * This can be done in grammars, but it is quite tedious to do so. */ - /* Handle 's */ pair(" 's ", "'s "), /* Handle opening/closing punctuation. */ - pair("([(\\[]) ", " $1"), - pair(" ([)\\]'\"])", "$1 "), + pair("([(\\[]) ", " $1"), pair(" ([)\\]'\"])", "$1 "), /* Remove spaces around series of opening/closing punctuation. */ pair("([(\\[])\\s+([(\\[])", "$1$2"), pair("([)\\]])\\s+([)\\]])", "$1$2"), @@ -132,20 +131,19 @@ public class RGrammar { collapseDupSpaces, /* Replace this once it is no longer needed. */ - pair("\\s(ish|burg|ton|ville|opolis|field|boro|dale)", "$1") - ); + pair("\\s(ish|burg|ton|ville|opolis|field|boro|dale)", "$1")); } /** * Create a new randomized grammar using the specified set of rules. * * @param ruls - * The rules to use. + * The rules to use. */ public RGrammar(Map<String, Rule> ruls) { rules = ruls; - for(Rule rl : ruls.values()) { + for (Rule rl : ruls.values()) { rl.belongsTo = this; } @@ -159,7 +157,7 @@ public class RGrammar { * checked. * * @param importedRules - * The set of imported rules to use. + * The set of imported rules to use. */ public void setImportedRules(Map<String, Rule> importedRules) { importRules = importedRules; @@ -169,7 +167,8 @@ public class RGrammar { * Generates the data structure backing rule suggestions for unknown rules. */ public void generateSuggestions() { - MutableBkTree<String> ruleSuggester = new MutableBkTree<>(new LevenshteinMetric()); + MutableBkTree<String> ruleSuggester + = new MutableBkTree<>(new LevenshteinMetric()); ruleSuggester.addAll(rules.keySet()); ruleSuggester.addAll(importRules.keySet()); @@ -181,8 +180,8 @@ public class RGrammar { * Generate a string from this grammar, starting from the specified rule. * * @param startRule - * The rule to start generating at, or null to use the initial rule - * for this grammar. + * The rule to start generating at, or null to use the initial + * rule for this grammar. * * @return A possible string from the grammar. */ @@ -194,16 +193,17 @@ public class RGrammar { * Generate a string from this grammar, starting from the specified rule. * * @param startRule - * The rule to start generating at, or null to use the initial rule for this grammar. + * The rule to start generating at, or null to use the initial + * rule for this grammar. * * @param rnd - * The random number generator to use. + * The random number generator to use. * * @param vars - * The set of variables to use. + * The set of variables to use. * * @param rlVars - * The set of rule variables to use. + * The set of rule variables to use. * * @return A possible string from the grammar. */ @@ -218,10 +218,13 @@ public class RGrammar { * Generate a string from this grammar, starting from the specified rule. * * @param startRule - * The rule to start generating at, or null to use the initial rule for this grammar. + * The rule to start generating at, or null to use the initial + * rule for this grammar. * * @param state - * The generation state. + * The generation state. + * + * @return The generated string. */ public String generate(String startRule, GenerationState state) { return generate(startRule, state, true); @@ -231,20 +234,26 @@ public class RGrammar { * Generate a string from this grammar, starting from the specified rule. * * @param startRule - * The rule to start generating at, or null to use the initial rule for this grammar. + * The rule to start generating at, or null to use the + * initial rule for this grammar. * * @param doPostprocess - * Whether or not we should perform post-processing of our output. + * Whether or not we should perform post-processing of our + * output. * * @param state - * The generation state. + * The generation state. + * + * @return The generated string. */ - public String generate(String startRule, GenerationState state, boolean doPostprocess) { + public String generate(String startRule, GenerationState state, + boolean doPostprocess) { String fromRule = startRule; if (startRule == null) { if (initialRule == null) { - throw new GrammarException("Must specify a start rule for grammars with no initial rule"); + throw new GrammarException( + "Must specify a start rule for grammars with no initial rule"); } fromRule = initialRule; @@ -254,17 +263,20 @@ public class RGrammar { } } - /* We don't search imports for the initial rule, so it will always belong to this grammar. */ + /* + * We don't search imports for the initial rule, so it will always belong to + * this grammar. + */ Rule rl = state.findRule(fromRule, false); - if(rl == null) + if (rl == null) throw new GrammarException("Could not find rule " + fromRule); rl.generate(state); String body = state.getContents(); - if(doPostprocess) { + if (doPostprocess) { body = postprocessRes(body); } @@ -275,26 +287,27 @@ public class RGrammar { private String postprocessRes(String strang) { String body = strang; - if(useBuiltinPostprocs) { - for(IPair<String, String> par : builtinPostprocs) { + if (useBuiltinPostprocs) { + for (IPair<String, String> par : builtinPostprocs) { body = body.replaceAll(par.getLeft(), par.getRight()); } } - for(IPair<String, String> par : postprocs) { + for (IPair<String, String> par : postprocs) { body = body.replaceAll(par.getLeft(), par.getRight()); } return body.trim(); } + /** * Generate a rule case. * * @param start - * The rule case to generate. + * The rule case to generate. * * @param state - * The current generation state. + * The current generation state. */ public void generateCase(RuleCase start, GenerationState state) { try { @@ -318,7 +331,8 @@ public class RGrammar { * Set the initial rule of this grammar. * * @param initRule - * The initial rule of this grammar, or null to say there is no initial rule. + * The initial rule of this grammar, or null to say there is no + * initial rule. */ public void setInitialRule(String initRule) { setInitialRule(initRule, new Tree<>()); @@ -328,10 +342,11 @@ public class RGrammar { * Set the initial rule of this grammar. * * @param initRule - * The initial rule of this grammar, or null to say there is no initial rule. + * The initial rule of this grammar, or null to say there is no + * initial rule. * * @param errs - * The tree to store errors in. + * The tree to store errors in. */ public void setInitialRule(String initRule, ITree<String> errs) { /* Passing null, nulls our initial rule. */ @@ -346,7 +361,9 @@ public class RGrammar { return; } else if (!rules.containsKey(initRule)) { - String msg = String.format("ERROR: No rule '%s' local to this grammar (%s) defined.", initRule, name); + String msg = String.format( + "ERROR: No rule '%s' local to this grammar (%s) defined.", initRule, + name); errs.addChild(msg); @@ -368,7 +385,8 @@ public class RGrammar { for (String rname : exportRules) { if (!rules.containsKey(rname)) { - String msg = String.format("No rule '%s' local to this grammar (%s) defined for export", + String msg = String.format( + "No rule '%s' local to this grammar (%s) defined for export", name, rname); throw new GrammarException(msg); @@ -388,7 +406,7 @@ public class RGrammar { * Set the rules exported by this grammar. * * @param exportedRules - * The rules exported by this grammar. + * The rules exported by this grammar. */ public void setExportedRules(Set<String> exportedRules) { exportRules = exportedRules; @@ -403,12 +421,26 @@ public class RGrammar { return rules; } + /** + * Get the rules imported into this grammar. + * + * @return The rules imported into this grammar. + */ public Map<String, Rule> getImportRules() { return importRules; } - public void setAutoVars(Map<String, CaseElement> aVars, Map<String, CaseElement> aRlVars) { - autoVars = aVars; + /** + * Set up the auto-variable sets. + * + * @param aVars + * The auto-variables to use. + * @param aRlVars + * The rule-auto-variables to use. + */ + public void setAutoVars(Map<String, CaseElement> aVars, + Map<String, CaseElement> aRlVars) { + autoVars = aVars; autoRlVars = aRlVars; } } diff --git a/src/main/java/bjc/rgens/parser/RGrammarBuilder.java b/src/main/java/bjc/rgens/parser/RGrammarBuilder.java index 820cf6b..e7e799e 100755 --- a/src/main/java/bjc/rgens/parser/RGrammarBuilder.java +++ b/src/main/java/bjc/rgens/parser/RGrammarBuilder.java @@ -32,7 +32,10 @@ public class RGrammarBuilder { private Set<String> exportedRules; /* The current initial rule. */ private String initialRule; - /* The current grammar name. */ + + /** + * The current grammar name. + */ public String name; /* Autovivify variables */ @@ -61,7 +64,18 @@ public class RGrammarBuilder { public Rule getOrCreateRule(String rName) { return getOrCreateRule(rName, new Tree<>()); } - + + /** + * Get or create a rule by the given name. + * + * @param rName + * The name of the rule. + * + * @param errs The place to put errors. + * + * @return + * The rule by that name, or a new one if none existed. + */ public Rule getOrCreateRule(String rName, ITree<String> errs) { if(rName == null) { errs.addChild("ERROR: Rule name must not be null"); @@ -132,6 +146,17 @@ public class RGrammarBuilder { // FIXME do something if errs has a result. } + /** + * Set the initial rule of the grammar. + * + * @param init + * The initial rule of the grammar. + * + * @param errs The place to put errors. + * + * @throws IllegalArgumentException + * If the rule is either not valid or not defined in the grammar. + */ public void setInitialRule(String init, ITree<String> errs) { if (init == null) { errs.addChild("init must not be null"); @@ -159,6 +184,17 @@ public class RGrammarBuilder { addExport(export, new Tree<>()); } + /** + * Add an exported rule to this grammar. + * + * @param export + * The name of the rule to export. + * + * @param errs The place to put errors. + * + * @throws IllegalArgumentException + * If the rule is either not valid or not defined in the grammar. + */ public void addExport(String export, ITree<String> errs) { if (export == null) { errs.addChild("ERROR: Export name must not be null"); @@ -225,24 +261,42 @@ public class RGrammarBuilder { affixWith(ruleName, prefixes, AffixType.CIRCUMFIX, new Tree<>()); } - public static enum AffixType { - CIRCUMFIX, - SUFFIX, - PREFIX; - - public boolean isSuffix() { - return this != PREFIX; - } - - public boolean isPrefix() { - return this != SUFFIX; - } - } - + /** + * Affix a given case element to every case of a specific rule. + * + * @param ruleName + * The rule to affix. + * + * @param affixes + * The affixes to add. + * + * @param type The type of affixing to perform. + * + * @throws IllegalArgumentException + * If the rule name is either invalid or not defined by this + * grammar, or if the prefix/suffix is invalid. + */ public void affixWith(String ruleName, List<CaseElement> affixes, AffixType type) { affixWith(ruleName, affixes, type, new Tree<>()); } + /** + * Affix a given case element to every case of a specific rule. + * + * @param ruleName + * The rule to affix. + * + * @param affixes + * The affixes to add. + * + * @param type The type of affixing to perform. + * + * @param errs The place to put errors. + * + * @throws IllegalArgumentException + * If the rule name is either invalid or not defined by this + * grammar, or if the prefix/suffix is invalid. + */ public void affixWith(String ruleName, List<CaseElement> affixes, AffixType type, ITree<String> errs) { if (ruleName == null) { errs.addChild("ERROR: Rule name must not be null"); @@ -300,10 +354,22 @@ public class RGrammarBuilder { } } + /** + * Perform despacing on a rule. + * + * @param ruleName The rule to perform despacing on. + */ public void despaceRule(String ruleName) { despaceRule(ruleName, new Tree<>(), false); } - + + /** + * Perform despacing on a rule. + * + * @param ruleName The rule to perform despacing on. + * @param errs The place to put errors. + * @param doTrace Whether or not to do tracing. + */ public void despaceRule(String ruleName, ITree<String> errs, boolean doTrace) { if (ruleName == null) { errs.addChild("ERROR: Rule name must not be null"); @@ -338,10 +404,21 @@ public class RGrammarBuilder { rules.get(ruleName).replaceCases(newCaseList); } + /** + * Set the weight for a rule. + * + * @param ruleName The rule to set the weight for. + */ public void setWeight(String ruleName) { setWeight(ruleName, new Tree<>()); } + /** + * Set the weight for a rule. + * + * @param ruleName The rule to set the weight for. + * @param errs The place to put errors. + */ public void setWeight(String ruleName, ITree<String> errs) { if (ruleName == null) { errs.addChild("ERROR: Rule name must not be null"); @@ -362,10 +439,23 @@ public class RGrammarBuilder { rules.get(ruleName).prob = Rule.ProbType.NORMAL; } + /** + * Set the rule recurrence limit. + * + * @param ruleName The name of the rule. + * @param recurLimit The limit of the number of times to recur. + */ public void setRuleRecur(String ruleName, int recurLimit) { setRuleRecur(ruleName, recurLimit, new Tree<>()); } + /** + * Set the rule recurrence limit. + * + * @param ruleName The name of the rule. + * @param recurLimit The limit of the number of times to recur. + * @param errs The place to put errors. + */ public void setRuleRecur(String ruleName, int recurLimit, ITree<String> errs) { if (ruleName == null) { errs.addChild("ERROR: Rule name must not be null"); @@ -386,10 +476,23 @@ public class RGrammarBuilder { rules.get(ruleName).recurLimit = recurLimit; } + /** + * Set probability descent on the rule. + * + * @param ruleName The name of the rule. + * @param descentFactor The amount to descend by every time. + */ public void setDescent(String ruleName, int descentFactor) { setDescent(ruleName, descentFactor, new Tree<>()); } + /** + * Set probability descent on the rule. + * + * @param ruleName The name of the rule. + * @param descentFactor The amount to descend by every time. + * @param errs Place to put errors. + */ public void setDescent(String ruleName, int descentFactor, ITree<String> errs) { if (ruleName == null) { errs.addChild("ERROR: Rule name must not be null"); @@ -413,10 +516,27 @@ public class RGrammarBuilder { rl.descentFactor = descentFactor; } + /** + * Set the binomial distribution on a rule. + * + * @param ruleName The name of the rule. + * @param target The target weighting. + * @param bound The bound for the distribution. + * @param trials The number of trials for the distribution. + */ public void setBinomial(String ruleName, int target, int bound, int trials) { setBinomial(ruleName, target, bound, trials, new Tree<>()); } + /** + * Set the binomial distribution on a rule. + * + * @param ruleName The name of the rule. + * @param target The target weighting. + * @param bound The bound for the distribution. + * @param trials The number of trials for the distribution. + * @param errs The place to put errors. + */ public void setBinomial(String ruleName, int target, int bound, int trials, ITree<String> errs) { if (ruleName == null) { errs.addChild("ERROR: Rule name must not be null"); @@ -442,18 +562,43 @@ public class RGrammarBuilder { rl.trials = trials; } - public void addAutoVar(String name, CaseElement elm) { - autoVars.put(name, elm); + /** + * Add an auto-variable. + * + * @param nam The name of the variable to add. + * @param elm The definition of the variable. + */ + public void addAutoVar(String nam, CaseElement elm) { + autoVars.put(nam, elm); } - public void addAutoRlVar(String name, CaseElement elm) { - autoRlVars.put(name, elm); + /** + * Add an auto-rule-variable. + * + * @param nam The name of the rule variable to add. + * @param elm The definition of the rule variable. + */ + public void addAutoRlVar(String nam, CaseElement elm) { + autoRlVars.put(nam, elm); } + /** + * Add a rule rejection. + * + * @param rule The name of the rule. + * @param reject The rejection for the rule. + */ public void rejectRule(String rule, String reject) { rejectRule(rule, reject, new Tree<>()); } + /** + * Add a rule rejection. + * + * @param rule The name of the rule. + * @param reject The rejection for the rule. + * @param errs The place to put errors. + */ public void rejectRule(String rule, String reject, ITree<String> errs) { if (rule == null) { errs.addChild("ERROR: Rule must not be null"); @@ -480,10 +625,25 @@ public class RGrammarBuilder { rl.addRejection(reject, errs); } + /** + * Add a find/replace to a rule. + * + * @param rule The name of the rule + * @param find The find string. + * @param replace The replace string. + */ public void findReplaceRule(String rule, String find, String replace) { findReplaceRule(rule, find, replace, new Tree<>()); } + /** + * Add a find/replace to a rule. + * + * @param rule The name of the rule + * @param find The find string. + * @param replace The replace string. + * @param errs The place to put errors. + */ public void findReplaceRule(String rule, String find, String replace, ITree<String> errs) { if (rule == null) { errs.addChild("ERROR: Rule must not be null"); diff --git a/src/main/java/bjc/rgens/parser/RGrammarLogging.java b/src/main/java/bjc/rgens/parser/RGrammarLogging.java index 4dba117..dbc36b4 100644 --- a/src/main/java/bjc/rgens/parser/RGrammarLogging.java +++ b/src/main/java/bjc/rgens/parser/RGrammarLogging.java @@ -7,14 +7,31 @@ package bjc.rgens.parser; * @author Ben Culkin */ public final class RGrammarLogging { + /** + * Log a message. + * @param msg The message to log. + * @param vars The variable for the message. + */ public static void log(String msg, Object... vars) { System.err.printf(msg, vars); } - + + /** + * Log a message, including a newline. + * @param msg The message to log. + * @param vars The variable for the message. + */ public static void logline(String msg, Object... vars) { log(msg + "\n", vars); } + /** + * Log an error, including an exception stack trace. + * + * @param ex The exception which caused this error. + * @param msg The message to log. + * @param vars The variables for the message. + */ public static void error(Exception ex, String msg, Object... vars) { logline("ERROR: " + msg, vars); @@ -24,26 +41,62 @@ public final class RGrammarLogging { logline(""); } + /** + * Log a performance message. + * + * @param msg The message to log. + * @param vars The variable for the message. + */ public static void perf(String msg, Object... vars) { logline("\tPERF: " + msg, vars); } + /** + * Log a info message. + * + * @param msg The message to log. + * @param vars The variable for the message. + */ public static void info(String msg, Object... vars) { logline("INFO: " + msg, vars); } + /** + * Log a trace message. + * + * @param msg The message to log. + * @param vars The variable for the message. + */ public static void trace(String msg, Object... vars) { logline("\t\tTRACE: " + msg, vars); } + /** + * Log a warn message. + * + * @param msg The message to log. + * @param vars The variable for the message. + */ public static void warn(String msg, Object... vars) { logline("WARN: " + msg, vars); } + /** + * Log a debug message. + * + * @param msg The message to log. + * @param vars The variable for the message. + */ public static void debug(String msg, Object... vars) { logline("\tDEBUG: " + msg, vars); } + /** + * Log a fine message. + * + * @param msg The message to log. + * @param vars The variable for the message. + */ public static void fine(String msg, Object... vars) { logline("\t\tFINE: " + msg, vars); } diff --git a/src/main/java/bjc/rgens/parser/RGrammarParser.java b/src/main/java/bjc/rgens/parser/RGrammarParser.java index bfbdb98..b25d036 100755 --- a/src/main/java/bjc/rgens/parser/RGrammarParser.java +++ b/src/main/java/bjc/rgens/parser/RGrammarParser.java @@ -6,7 +6,6 @@ import java.io.StringReader; import java.util.ArrayList; import java.util.List; -import bjc.rgens.parser.RGrammarBuilder.AffixType; import bjc.rgens.parser.elements.CaseElement; import bjc.rgens.parser.elements.ChanceCaseElement; import bjc.rgens.parser.elements.SerialCaseElement; @@ -25,7 +24,7 @@ import bjc.utils.ioutils.blocks.SimpleBlockReader; */ public class RGrammarParser { /** - * Whether we are in debug mode or not. + * Whether we are in debug mode or not. */ public static final boolean DEBUG = false; /** @@ -37,19 +36,21 @@ public class RGrammarParser { * Templates for level-dependent delimiters. */ /* Pragma block delimiter. */ - private static final String TMPL_PRAGMA_BLOCK_DELIM = "\\R\\t{%d}(?!\\t)"; + private static final String TMPL_PRAGMA_BLOCK_DELIM = "\\R\\t{%d}(?!\\t)"; /* Rule declaration block delimiter. */ private static final String TMPL_RULEDECL_BLOCK_DELIM = "\\R\\t\\t{%d}"; /* Where block delimiter. */ - private static final String TMPL_WHERE_BLOCK_DELIM = "\\R\\t{%d}(?:in|end)\\R"; + private static final String TMPL_WHERE_BLOCK_DELIM = "\\R\\t{%d}(?:in|end)\\R"; /* Top-level block delimiter. */ private static final String TMPL_TOPLEVEL_BLOCK_DELIM = "\\R\\t{%d}\\.?\\R"; - private static void doAffixWith(String body, RGrammarBuilder build, int level, AffixType afxType, ITree<String> errs) { + private static void doAffixWith(String body, RGrammarBuilder build, int level, + AffixType afxType, ITree<String> errs) { int idx = body.indexOf(" "); if (idx == -1) { - String fmt = "ERROR: Takes at least two arguments, the name of the rule to affix, then what to affix it with\n\tThis can be more than one token, to get them affixed as a group"; + String fmt + = "ERROR: Takes at least two arguments, the name of the rule to affix, then what to affix it with\n\tThis can be more than one token, to get them affixed as a group"; String msg = String.format(fmt, afxType.toString().toLowerCase()); @@ -67,7 +68,8 @@ public class RGrammarParser { build.affixWith(rName, elms, afxType, errs); } - private static void doAutoVar(List<String> bits, RGrammarBuilder build, int level, boolean isRule, ITree<String> errs) { + private static void doAutoVar(List<String> bits, RGrammarBuilder build, int level, + boolean isRule, ITree<String> errs) { if (bits.size() < 1) { String msg = "Must specify name of variable and definition to autovivify"; @@ -84,7 +86,9 @@ public class RGrammarParser { CaseElement elm = elmList.get(0); if (elmList.size() > 1) { - String msg = String.format("WARN: Ignoring %d additional elements for autovivify: %s", elmList.size(), elmList.subList(1, elmList.size())); + String msg = String.format( + "WARN: Ignoring %d additional elements for autovivify: %s", + elmList.size(), elmList.subList(1, elmList.size())); errs.addChild(msg); @@ -92,7 +96,9 @@ public class RGrammarParser { } if (!(elm instanceof VariableDefCaseElement)) { - String msg = String.format("ERROR: Autovivify expression must be a variable defn. (expr. %s)", elm); + String msg = String.format( + "ERROR: Autovivify expression must be a variable defn. (expr. %s)", + elm); errs.addChild(msg); @@ -100,10 +106,12 @@ public class RGrammarParser { } { - String name = ((VariableDefCaseElement)elm).varName; + String name = ((VariableDefCaseElement) elm).varName; - if (isRule) build.addAutoRlVar(name, elm); - else build.addAutoVar(name, elm); + if (isRule) + build.addAutoRlVar(name, elm); + else + build.addAutoVar(name, elm); } } @@ -111,15 +119,19 @@ public class RGrammarParser { * Read a {@link RGrammar} from an input stream. * * @param is - * The input stream to read from. + * The input stream to read from. + * @param lopts + * The options to use for loading. + * @param errs + * The place to put errors. * - * @return - * The grammar represented by the stream. + * @return The grammar represented by the stream. * * @throws GrammarException - * Thrown if the grammar has a syntax error. + * Thrown if the grammar has a syntax error. */ - public static RGrammar readGrammar(Reader is, LoadOptions lopts, ITree<String> errs) throws GrammarException { + public static RGrammar readGrammar(Reader is, LoadOptions lopts, ITree<String> errs) + throws GrammarException { String dlm = String.format(TMPL_TOPLEVEL_BLOCK_DELIM, 0); try (BlockReader reader = new SimpleBlockReader(dlm, is)) { @@ -129,29 +141,35 @@ public class RGrammarParser { return null; } - RGrammarBuilder build = new RGrammarBuilder(); + RGrammarBuilder build = new RGrammarBuilder(); - for(Block block : reader) { - if(lopts.doTrace) { - String msg = String.format("TRACE: Handling top-level block (%s)\n", block); + for (Block block : reader) { + if (lopts.doTrace) { + String msg = String.format("TRACE: Handling top-level block (%s)\n", + block); - errs.addChild(msg); - } + errs.addChild(msg); + } - String msg = String.format("INFO: Block %d (%d-%d) (offset %d, %d-%d)", block.blockNo, block.startLine, block.endLine, block.lineOffset, block.lineOffset + block.startLine, block.lineOffset + block.endLine); + String msg = String.format("INFO: Block %d (%d-%d) (offset %d, %d-%d)", + block.blockNo, block.startLine, block.endLine, block.lineOffset, + block.lineOffset + block.startLine, + block.lineOffset + block.endLine); - ITree<String> kid = new Tree<>(msg); + ITree<String> kid = new Tree<>(msg); - handleBlock(build, block.contents, 0, block.startLine, lopts, kid); + handleBlock(build, block.contents, 0, block.startLine, lopts, kid); - if (kid.size() > 0) errs.addChild(kid); - } + if (kid.size() > 0) + errs.addChild(kid); + } - if(lopts.doTrace) { - errs.addChild(String.format("TRACE: Ended at line %d ", reader.getBlock().endLine)); - } + if (lopts.doTrace) { + errs.addChild(String.format("TRACE: Ended at line %d ", + reader.getBlock().endLine)); + } - return build.toRGrammar(); + return build.toRGrammar(); } catch (IOException ioex) { String msg = String.format("ERROR: Unknown I/O error: %s", ioex.getMessage()); @@ -161,21 +179,24 @@ public class RGrammarParser { return null; } - /* - * Throughout these, level indicates the nesting level of that construct, - * and lineOffset indicates the total number of lines to adjust the block - * line numbers by. + /* + * Throughout these, level indicates the nesting level of that construct, and + * lineOffset indicates the total number of lines to adjust the block line + * numbers by. */ /* Handles an arbitrary block. */ - private static void handleBlock(RGrammarBuilder build, String block, int level, int lineOffset, LoadOptions lopts, ITree<String> errs) { + private static void handleBlock(RGrammarBuilder build, String block, int level, + int lineOffset, LoadOptions lopts, ITree<String> errs) { /* Discard empty blocks. */ - if (block.equals("") || block.matches("\\R")) return; + if (block.equals("") || block.matches("\\R")) + return; int typeSep = block.indexOf(' '); if (typeSep == -1) { - errs.addChild("ERROR: A block must start with a introducer, followed by a space, then the rest of the block"); + errs.addChild( + "ERROR: A block must start with a introducer, followed by a space, then the rest of the block"); } String blockType = block.substring(0, typeSep).trim(); @@ -187,7 +208,7 @@ public class RGrammarParser { } else if (blockType.equalsIgnoreCase("where")) { handleWhereBlock(block, build, level, lineOffset, lopts, errs); } else if (blockType.startsWith("#")) { - if(lopts.doTrace) { + if (lopts.doTrace) { String msg = String.format("TRACE: Handled comment block (%s)\n", block); errs.addChild(msg); @@ -198,8 +219,8 @@ public class RGrammarParser { * * @TODO 10/11/17 Ben Culkin :GrammarComment * - * Attach these to the grammar somehow so that they - * can be re-output during formatting. + * Attach these to the grammar somehow so that they can be re-output during + * formatting. */ return; } else { @@ -210,14 +231,16 @@ public class RGrammarParser { } /* Handle reading a block of pragmas. */ - private static void handlePragmaBlock(String block, RGrammarBuilder build, int level, int lineOffset, LoadOptions lopts, ITree<String> errs) { + private static void handlePragmaBlock(String block, RGrammarBuilder build, int level, + int lineOffset, LoadOptions lopts, ITree<String> errs) { String dlm = String.format(TMPL_PRAGMA_BLOCK_DELIM, level); - try (BlockReader pragmaReader = new SimpleBlockReader(dlm, new StringReader(block))) { - for(Block pragma : pragmaReader) { + try (BlockReader pragmaReader + = new SimpleBlockReader(dlm, new StringReader(block))) { + for (Block pragma : pragmaReader) { pragma.lineOffset = lineOffset; - if(lopts.doTrace) { + if (lopts.doTrace) { System.err.printf("TRACE: Handled pragma block (%s)\n", pragma); } @@ -226,41 +249,48 @@ public class RGrammarParser { int pragmaSep = pragmaContents.indexOf(' '); if (pragmaSep == -1) { - String msg = "ERROR: A pragma invocation must consist of the word pragma, followed by a space, then the body of the pragma"; + String msg + = "ERROR: A pragma invocation must consist of the word pragma, followed by a space, then the body of the pragma"; errs.addChild(msg); return; } String pragmaLeader = pragmaContents.substring(0, pragmaSep); - String pragmaBody = pragmaContents.substring(pragmaSep + 1); + String pragmaBody = pragmaContents.substring(pragmaSep + 1); if (!pragmaLeader.equalsIgnoreCase("pragma")) { - String msg = String.format("ERROR: Illegal line leader in pragma block: '%s'", pragmaLeader); + String msg = String.format( + "ERROR: Illegal line leader in pragma block: '%s'", + pragmaLeader); errs.addChild(msg); return; } - handlePragma(pragmaBody, build, level, pragma.startLine + lineOffset, lopts, errs); + handlePragma(pragmaBody, build, level, pragma.startLine + lineOffset, + lopts, errs); } } catch (IOException ioex) { - String msg = String.format("ERROR: Unknown I/O error in pragma block: %s", ioex.getMessage()); + String msg = String.format("ERROR: Unknown I/O error in pragma block: %s", + ioex.getMessage()); errs.addChild(msg); } } /* Handle an individual pragma in a block. */ - private static void handlePragma(String pragma, RGrammarBuilder build, int level, int lineOffset, LoadOptions lopts, ITree<String> errs) { + private static void handlePragma(String pragma, RGrammarBuilder build, int level, + int lineOffset, LoadOptions lopts, ITree<String> errs) { int bodySep = pragma.indexOf(' '); - if (bodySep == -1) bodySep = pragma.length(); + if (bodySep == -1) + bodySep = pragma.length(); String pragmaName = pragma.substring(0, bodySep); String pragmaBody = pragma.substring(bodySep + 1); - if(lopts.doTrace) { + if (lopts.doTrace) { String msg = String.format("TRACE: Handled pragma '%s'\n", pragmaName); errs.addChild(msg); @@ -273,242 +303,231 @@ public class RGrammarParser { ITree<String> kid = new Tree<>(fmt); switch (pragmaName) { - case "initial-rule": - { - if (bits.size() != 1) { - kid.addChild("ERROR: Must specify initial rule"); - - break; - } + case "initial-rule": { + if (bits.size() != 1) { + kid.addChild("ERROR: Must specify initial rule"); - build.setInitialRule(bits.get(0), kid); + break; } - break; - case "grammar-name": - { - if (bits.size() != 1) { - kid.addChild("ERROR: Must specify grammar name"); - break; - } + build.setInitialRule(bits.get(0), kid); + } + break; + case "grammar-name": { + if (bits.size() != 1) { + kid.addChild("ERROR: Must specify grammar name"); - build.name = bits.get(0); + break; } + + build.name = bits.get(0); + } break; - case "despace-rule": - { - if (bits.size() < 1) { - kid.addChild("ERROR: Must specify at least one rule to despace"); + case "despace-rule": { + if (bits.size() < 1) { + kid.addChild("ERROR: Must specify at least one rule to despace"); - break; - } + break; + } - for(String bit : bits) { - build.despaceRule(bit, kid, lopts.doTrace); - } + for (String bit : bits) { + build.despaceRule(bit, kid, lopts.doTrace); } + } break; - case "export-rule": - { - if(bits.size() < 1) { - kid.addChild("ERROR: Must specify rules to export"); + case "export-rule": { + if (bits.size() < 1) { + kid.addChild("ERROR: Must specify rules to export"); - break; - } + break; + } - for (String export : bits) { - build.addExport(export); - } + for (String export : bits) { + build.addExport(export); } + } break; - case "recur-limit": - { - if(bits.size() != 2) { - kid.addChild("ERROR: Takes two arguments: the name of the rule to set the limit for, and the new value of the limit"); + case "recur-limit": { + if (bits.size() != 2) { + kid.addChild( + "ERROR: Takes two arguments: the name of the rule to set the limit for, and the new value of the limit"); - break; - } - - if(!bits.get(1).matches("\\A\\d+\\Z")) { - kid.addChild("ERROR: Limit value must be an integer"); + break; + } - break; - } + if (!bits.get(1).matches("\\A\\d+\\Z")) { + kid.addChild("ERROR: Limit value must be an integer"); - build.setRuleRecur(bits.get(0), Integer.parseInt(bits.get(1)), kid); + break; } - break; - case "enable-weight": - { - if(bits.size() != 1) { - kid.addChild("ERROR: Takes one argument: the name of the rule to enable standard weighting for"); - } - build.setWeight(bits.get(0), kid); - } + build.setRuleRecur(bits.get(0), Integer.parseInt(bits.get(1)), kid); + } break; - case "enable-descent": - { - if(bits.size() != 2) { - kid.addChild("ERROR: Takes two arguments: The name of the rule to set to descent mode, and the value of the descent factor"); + case "enable-weight": { + if (bits.size() != 1) { + kid.addChild( + "ERROR: Takes one argument: the name of the rule to enable standard weighting for"); + } - break; - } + build.setWeight(bits.get(0), kid); + } + break; + case "enable-descent": { + if (bits.size() != 2) { + kid.addChild( + "ERROR: Takes two arguments: The name of the rule to set to descent mode, and the value of the descent factor"); - if(!bits.get(1).matches("\\A\\d+\\Z")) { - kid.addChild("ERROR: Factor value must be an integer"); + break; + } - break; - } + if (!bits.get(1).matches("\\A\\d+\\Z")) { + kid.addChild("ERROR: Factor value must be an integer"); - build.setDescent(bits.get(0), Integer.parseInt(bits.get(1)), kid); + break; } + + build.setDescent(bits.get(0), Integer.parseInt(bits.get(1)), kid); + } break; - case "enable-binomial": - { - // @NOTE 9/4/18 - // - // This can be kind of hard to read right off. Is there - // a format to put stuff in that looks better and is - // more readable? - - if(bits.size() != 4) { - kid.addChild("ERROR: Takes four arguments: the name of the rule to set the binomial factors for, and the three binomial parameters (target, bound, trials) (target/bound chance of success)"); - - break; - } + case "enable-binomial": { + // @NOTE 9/4/18 + // + // This can be kind of hard to read right off. Is there + // a format to put stuff in that looks better and is + // more readable? + + if (bits.size() != 4) { + kid.addChild( + "ERROR: Takes four arguments: the name of the rule to set the binomial factors for, and the three binomial parameters (target, bound, trials) (target/bound chance of success)"); + + break; + } - if(!bits.get(1).matches("\\A\\d+\\Z")) { - kid.addChild("ERROR: Target value must be an integer"); + if (!bits.get(1).matches("\\A\\d+\\Z")) { + kid.addChild("ERROR: Target value must be an integer"); - break; - } + break; + } - if(!bits.get(2).matches("\\A\\d+\\Z")) { - kid.addChild("ERROR: Bound value must be an integer"); + if (!bits.get(2).matches("\\A\\d+\\Z")) { + kid.addChild("ERROR: Bound value must be an integer"); - break; - } + break; + } - if(!bits.get(3).matches("\\A\\d+\\Z")) { - kid.addChild("ERROR: Trials value must be an integer"); + if (!bits.get(3).matches("\\A\\d+\\Z")) { + kid.addChild("ERROR: Trials value must be an integer"); - break; - } - - build.setBinomial(bits.get(0), Integer.parseInt(bits.get(1)), Integer.parseInt(bits.get(2)), Integer.parseInt(bits.get(3)), kid); + break; } - break; - case "find-replace-rule": - { - /* - * @NOTE 4/9/18 - * - * Consider if we want to replace this with something more akin - * to the `definer` feature from DiceLang. This will work fine - * in most cases, but there are some cases where you'd want the - * extra power. No examples are apparent at the moment. - */ - if(bits.size() != 3) { - kid.addChild("ERROR: Takes three arguments: the name of the rule to process, then the find/replace pair to apply after the rule has been generated."); - break; - } + build.setBinomial(bits.get(0), Integer.parseInt(bits.get(1)), + Integer.parseInt(bits.get(2)), Integer.parseInt(bits.get(3)), kid); + } + break; + case "find-replace-rule": { + /* + * @NOTE 4/9/18 + * + * Consider if we want to replace this with something more akin to the + * `definer` feature from DiceLang. This will work fine in most cases, but + * there are some cases where you'd want the extra power. No examples are + * apparent at the moment. + */ + if (bits.size() != 3) { + kid.addChild( + "ERROR: Takes three arguments: the name of the rule to process, then the find/replace pair to apply after the rule has been generated."); - build.findReplaceRule(bits.get(0), bits.get(1), bits.get(2), kid); + break; } - break; - case "reject-rule": - { - if(bits.size() != 2) { - kid.addChild("ERROR: Takes two arguments: the name of the rule to process, then the rejection pattern to apply after the rule has been generated."); - break; - } + build.findReplaceRule(bits.get(0), bits.get(1), bits.get(2), kid); + } + break; + case "reject-rule": { + if (bits.size() != 2) { + kid.addChild( + "ERROR: Takes two arguments: the name of the rule to process, then the rejection pattern to apply after the rule has been generated."); - build.rejectRule(bits.get(0), bits.get(1), kid); + break; } + + build.rejectRule(bits.get(0), bits.get(1), kid); + } break; - case "prefix-with": - { - doAffixWith(pragmaBody, build, level, AffixType.PREFIX, kid); - } + case "prefix-with": { + doAffixWith(pragmaBody, build, level, AffixType.PREFIX, kid); + } break; - case "suffix-with": - { - doAffixWith(pragmaBody, build, level, AffixType.SUFFIX, kid); - } + case "suffix-with": { + doAffixWith(pragmaBody, build, level, AffixType.SUFFIX, kid); + } break; - case "circumfix-with": - { - doAffixWith(pragmaBody, build, level, AffixType.CIRCUMFIX, kid); - } + case "circumfix-with": { + doAffixWith(pragmaBody, build, level, AffixType.CIRCUMFIX, kid); + } break; - /* - * @NOTE 9/4/18 - * - * Right now, we ignore additional elements to autovivify. Not - * sure yet if this is the desired behavior. - * - * As I see it, there are a couple of alternatives: - * - * 1) Continue what we're doing. This is simple, but seems - * somewhat inelegant. - * - * 2) Error if more than one is provided. Even simpler, but also - * seems inelegant. - * - * 3) Parse them independantly. Each element is treated as a - * seperate autovar. Seems simple, but may - * cause issues with mixing rule & nonrule - * variables, as well as naming. - * - * 4) Parse them together. Autovars are stored as cases instead - * of case elements. Also simple, but may have - * some odd corner cases, and I can't think of - * any cases where the additional power would - * be useful. - * - * - * - * - * - * - * As an additional aside, we currently error if we provide - * something that isn't a variable definition. This is because - * we pull the name for the auto-vivify variable from the - * element. If we go with option 4 above, the user will have to - * specify a name for the variable, and we should likely add - * some check when the variable is made live that it actually - * created the variable it said it would. - * - */ - case "autovivify": - { - doAutoVar(bits, build, level, false, kid); - } + /* + * @NOTE 9/4/18 + * + * Right now, we ignore additional elements to autovivify. Not sure yet if this + * is the desired behavior. + * + * As I see it, there are a couple of alternatives: + * + * 1) Continue what we're doing. This is simple, but seems somewhat inelegant. + * + * 2) Error if more than one is provided. Even simpler, but also seems + * inelegant. + * + * 3) Parse them independantly. Each element is treated as a seperate autovar. + * Seems simple, but may cause issues with mixing rule & nonrule variables, as + * well as naming. + * + * 4) Parse them together. Autovars are stored as cases instead of case + * elements. Also simple, but may have some odd corner cases, and I can't think + * of any cases where the additional power would be useful. + * + * + * + * + * + * + * As an additional aside, we currently error if we provide something that isn't + * a variable definition. This is because we pull the name for the auto-vivify + * variable from the element. If we go with option 4 above, the user will have + * to specify a name for the variable, and we should likely add some check when + * the variable is made live that it actually created the variable it said it + * would. + * + */ + case "autovivify": { + doAutoVar(bits, build, level, false, kid); + } break; - case "autovivify-rule": - { - doAutoVar(bits, build, level, true, kid); - } + case "autovivify-rule": { + doAutoVar(bits, build, level, true, kid); + } break; - default: - { - String msg = String.format("ERROR: Unknown pragma '%s'", pragmaName); + default: { + String msg = String.format("ERROR: Unknown pragma '%s'", pragmaName); - kid.addChild(msg); - } + kid.addChild(msg); + } } - if (kid.size() > 0) errs.addChild(kid); + if (kid.size() > 0) + errs.addChild(kid); } /* Handle a block of a rule declaration and one or more cases. */ - private static void handleRuleBlock(String ruleBlock, RGrammarBuilder build, int level, int lineOffset, LoadOptions lopts, ITree<String> errs) { + private static void handleRuleBlock(String ruleBlock, RGrammarBuilder build, + int level, int lineOffset, LoadOptions lopts, ITree<String> errs) { String dlm = String.format(TMPL_RULEDECL_BLOCK_DELIM, level); - try (BlockReader ruleReader = new SimpleBlockReader(dlm, new StringReader(ruleBlock))) { + try (BlockReader ruleReader + = new SimpleBlockReader(dlm, new StringReader(ruleBlock))) { ITree<String> kid = new Tree<>(); if (ruleReader.hasNextBlock()) { @@ -518,49 +537,54 @@ public class RGrammarParser { declBlock.lineOffset = lineOffset; String declContents = declBlock.contents; - Rule rl = handleRuleDecl(build, declContents, lineOffset + declBlock.startLine, kid); + Rule rl = handleRuleDecl(build, declContents, + lineOffset + declBlock.startLine, kid); // Error occured during rule processing - if (rl == null) return; + if (rl == null) + return; - for(Block block : ruleReader) { + for (Block block : ruleReader) { /* Ignore comment lines. */ - if(block.contents.trim().startsWith("#")) return; + if (block.contents.trim().startsWith("#")) + return; - handleRuleCase(block.contents, build, rl, block.startLine + lineOffset, kid); + handleRuleCase(block.contents, build, rl, + block.startLine + lineOffset, kid); } } else { /* Rule with a declaration followed by a single case. */ handleRuleDecl(build, ruleBlock, lineOffset, kid); } - if (kid.size() > 0) errs.addChild(kid); + if (kid.size() > 0) + errs.addChild(kid); } catch (IOException ex) { - String msg = String.format("ERROR: Unknown error handling rule block (%s)",ex.getMessage()); + String msg = String.format("ERROR: Unknown error handling rule block (%s)", + ex.getMessage()); errs.addChild(msg); } } /* Handle a rule declaration and its initial case. */ - private static Rule handleRuleDecl(RGrammarBuilder build, String declContents, int lineOffset, ITree<String> errs) { + private static Rule handleRuleDecl(RGrammarBuilder build, String declContents, + int lineOffset, ITree<String> errs) { int declSep = declContents.indexOf("\u2192"); if (declSep == -1) { /* - * @NOTE - * We should maybe remove support for the old - * syntax at some point. + * @NOTE We should maybe remove support for the old syntax at some point. * - * We don't want to do so so as to make inputting grammars easier, - * since that character is not easy to type on a normal keyboard, - * and takes 4 keystrokes in vim as composed to 1 for the normal - * one. + * We don't want to do so so as to make inputting grammars easier, since that + * character is not easy to type on a normal keyboard, and takes 4 keystrokes + * in vim as composed to 1 for the normal one. */ declSep = declContents.indexOf(' '); if (declSep == -1) { - String msg = "A rule must be given at least one case in its declaration, and seperated from that case by \u2192 or ' '"; + String msg + = "A rule must be given at least one case in its declaration, and seperated from that case by \u2192 or ' '"; errs.addChild(msg); @@ -581,7 +605,8 @@ public class RGrammarParser { Rule rul = build.getOrCreateRule(ruleName, errs); - if (rul == null) return null; + if (rul == null) + return null; handleRuleCase(ruleBody, build, rul, lineOffset, errs); @@ -589,7 +614,8 @@ public class RGrammarParser { } /* Handle a single case of a rule. */ - private static void handleRuleCase(String cse, RGrammarBuilder build, Rule rul, int lineOffset, ITree<String> errs) { + private static void handleRuleCase(String cse, RGrammarBuilder build, Rule rul, + int lineOffset, ITree<String> errs) { List<CaseElement> elms = new ArrayList<>(); int weights = parseElementString(cse, elms, errs); @@ -598,7 +624,8 @@ public class RGrammarParser { } /* Handle a where block (a block with local rules). */ - private static void handleWhereBlock(String block, RGrammarBuilder build, int level, int lineOffset, LoadOptions lopts, ITree<String> errs) { + private static void handleWhereBlock(String block, RGrammarBuilder build, int level, + int lineOffset, LoadOptions lopts, ITree<String> errs) { int nlIndex = block.indexOf("\\nin"); if (nlIndex == -1) { @@ -611,7 +638,8 @@ public class RGrammarParser { String whereDelim = String.format(TMPL_WHERE_BLOCK_DELIM, level); - try (BlockReader whereReader = new SimpleBlockReader(whereDelim, new StringReader(trimBlock))) { + try (BlockReader whereReader + = new SimpleBlockReader(whereDelim, new StringReader(trimBlock))) { Block whereCtx = whereReader.next(); whereCtx.lineOffset = lineOffset; @@ -619,51 +647,97 @@ public class RGrammarParser { String ctxDelim = String.format(TMPL_TOPLEVEL_BLOCK_DELIM, level + 1); try (BlockReader bodyReader = new SimpleBlockReader(ctxDelim, ctxReader)) { - //@SuppressWarnings("unused") + // @SuppressWarnings("unused") Block whereBody = whereReader.next(); whereBody.lineOffset = lineOffset + whereCtx.startLine; - String msg = String.format("UNIMPLEMENTED WHERE:\n%s\n", whereBody.contents); + String msg + = String.format("UNIMPLEMENTED WHERE:\n%s\n", whereBody.contents); errs.addChild(msg); /** - * @TODO 10/11/17 Ben Culkin :WhereBlocks - * Implement where blocks. + * @TODO 10/11/17 Ben Culkin :WhereBlocks Implement where blocks. * - * A where block has the context evaluated - * in a new context, and the body executed - * in that context. + * A where block has the context evaluated in a new context, and the + * body executed in that context. */ } } catch (IOException ioex) { - //String msg = String.format("Unknown error in where block (%s)", ioex.getMessage()); + // String msg = String.format("Unknown error in where block (%s)", + // ioex.getMessage()); } } + /** + * Parse an element string. + * + * @param cses + * The case string. + * @param elms + * The current list of case elements. + * + * @return The weight of the resulting case. + */ public static int parseElementString(String cses, List<CaseElement> elms) { return parseElementString(cses, elms, new Tree<>()); } - public static int parseElementString(String cses, List<CaseElement> elms, ITree<String> errs) { + /** + * Parse an element string. + * + * @param cses + * The case string. + * @param elms + * The current list of case elements. + * @param errs + * The place to put errors. + * + * @return The weight of the resulting case. + */ + public static int parseElementString(String cses, List<CaseElement> elms, + ITree<String> errs) { /* * @NOTE * - * This is done using String.split because using things like ( - * as groupers breaks certain grammars. Maybe it can be used if - * some sort of way to set which groupers to use is added? + * This is done using String.split because using things like ( as groupers + * breaks certain grammars. Maybe it can be used if some sort of way to set + * which groupers to use is added? * - * List<String> cseList = LevelSplitter.def.levelSplit(cses.trim(), " "); + * List<String> cseList = LevelSplitter.def.levelSplit(cses.trim(), " "); * - * return parseElementString(cseList.toArray(new String[0])); + * return parseElementString(cseList.toArray(new String[0])); */ return parseElementString(cses.split(" "), elms, errs); } + /** + * Parse an element string. + * + * @param cses + * The case elements. + * @param elms + * The current list of case elements. + * + * @return The weight of the resulting case. + */ public static int parseElementString(String[] cses, List<CaseElement> elms) { return parseElementString(cses, elms, new Tree<>()); } - public static int parseElementString(String[] cses, List<CaseElement> caseParts, ITree<String> errs) { + /** + * Parse an element string. + * + * @param cses + * The case elements. + * @param caseParts + * The current list of case elements. + * @param errs + * The place to put errors. + * + * @return The weight of the resulting case. + */ + public static int parseElementString(String[] cses, List<CaseElement> caseParts, + ITree<String> errs) { int weight = 1; int repCount = 1; @@ -681,17 +755,20 @@ public class RGrammarParser { if (partToAdd.equals("")) { /* Ignore empty parts */ continue; - } else if(partToAdd.matches("\\<\\^\\d+\\>")) { + } else if (partToAdd.matches("\\<\\^\\d+\\>")) { /* Set case weights */ weight = Integer.parseInt(partToAdd.substring(2, partToAdd.length() - 1)); - } else if(partToAdd.matches("\\<&\\d+\\>")) { - repCount = Integer.parseInt(partToAdd.substring(2, partToAdd.length() - 1)); - } else if(partToAdd.matches("\\<&\\d+\\.\\.\\d+\\>")) { - serialLower = Integer.parseInt(partToAdd.substring(2, partToAdd.indexOf("."))); - serialUpper = Integer.parseInt(partToAdd.substring(partToAdd.lastIndexOf(".") + 1, partToAdd.length() - 1)); + } else if (partToAdd.matches("\\<&\\d+\\>")) { + repCount = Integer + .parseInt(partToAdd.substring(2, partToAdd.length() - 1)); + } else if (partToAdd.matches("\\<&\\d+\\.\\.\\d+\\>")) { + serialLower = Integer + .parseInt(partToAdd.substring(2, partToAdd.indexOf("."))); + serialUpper = Integer.parseInt(partToAdd.substring( + partToAdd.lastIndexOf(".") + 1, partToAdd.length() - 1)); doSerial = true; - } else if(partToAdd.matches("\\<\\?\\d+\\>")) { + } else if (partToAdd.matches("\\<\\?\\d+\\>")) { chance = Integer.parseInt(partToAdd.substring(2, partToAdd.length() - 1)); doChance = true; @@ -699,64 +776,61 @@ public class RGrammarParser { /* * @NOTE * - * One, am I even using this feature anywhere? - * As far as I can tell, this says to apply the - * current set of case part rules to the - * previous case part. This may be useful in - * certain cases, but none come to mind at the + * One, am I even using this feature anywhere? As far as I can tell, this + * says to apply the current set of case part rules to the previous case + * part. This may be useful in certain cases, but none come to mind at the * moment. * * @PERF * - * For performance reasons, we may want to - * consider setting the chance/serial values as - * a setting on CaseElement, instead of having + * For performance reasons, we may want to consider setting the + * chance/serial values as a setting on CaseElement, instead of having * their own CaseElement type. */ CaseElement elm = caseParts.remove(caseParts.size() - 1); - if(repCount == 0) { + if (repCount == 0) { /* Skip no-reps */ } else { - if(doChance) { + if (doChance) { elm = new ChanceCaseElement(elm, chance); doChance = false; } - if(doSerial) { + if (doSerial) { elm = new SerialCaseElement(elm, serialLower, serialUpper); doSerial = false; } - for(int i = 1; i <= repCount; i++) { + for (int i = 1; i <= repCount; i++) { caseParts.add(elm); } repCount = 1; } - } else if(partToAdd.matches("\\<[^\\>]+\\>")) { + } else if (partToAdd.matches("\\<[^\\>]+\\>")) { throw new GrammarException("Unknown parser meta-rule " + partToAdd); } else { CaseElement elm = CaseElement.createElement(partToAdd); - if(repCount == 0) { + if (repCount == 0) { /* Skip no-reps */ } else { - if(doChance) { + if (doChance) { elm = new ChanceCaseElement(elm, chance); doChance = false; } - if(doSerial) { + if (doSerial) { elm = new SerialCaseElement(elm, serialLower, serialUpper); doSerial = false; } - for(int i = 1; i <= repCount; i++) { + for (int i = 1; i <= repCount; i++) { caseParts.add(elm); } diff --git a/src/main/java/bjc/rgens/parser/RGrammarSet.java b/src/main/java/bjc/rgens/parser/RGrammarSet.java index 05823ec..c87c02a 100755 --- a/src/main/java/bjc/rgens/parser/RGrammarSet.java +++ b/src/main/java/bjc/rgens/parser/RGrammarSet.java @@ -14,10 +14,19 @@ import java.util.TreeMap; * @author EVE */ public class RGrammarSet { + /** + * The name for this grammar set. + */ public String name; + /** + * The config set this grammar set belongs to. + */ public ConfigSet belongsTo; + /** + * The grammar which contains the exports of this grammar set. + */ public RGrammar exportGrammar; /* Contains all the grammars in this set. */ @@ -26,17 +35,21 @@ public class RGrammarSet { /* Contains all the exported rules from grammars. */ private Map<String, Rule> exportedRules; - /* Contains which file a grammar was loaded from. */ + /** + * Contains which file a grammar was loaded from. + */ public Map<String, String> loadedFrom; - /* @NOTE These are replaced by the logging setup */ - public static final boolean PERF = true; - /** Create a new set of randomized grammars. */ public RGrammarSet() { this(false); } + /** + * Create a new set of randomized grammars. + * + * @param orderExports Should the exports be ordered? + */ public RGrammarSet(boolean orderExports) { grammars = new HashMap<>(); diff --git a/src/main/java/bjc/rgens/parser/RegexRuleCase.java b/src/main/java/bjc/rgens/parser/RegexRuleCase.java index e124205..1cffca3 100755 --- a/src/main/java/bjc/rgens/parser/RegexRuleCase.java +++ b/src/main/java/bjc/rgens/parser/RegexRuleCase.java @@ -9,12 +9,14 @@ import java.util.List; * * Actually implement this */ +@SuppressWarnings("javadoc") public class RegexRuleCase extends RuleCase { public RegexRuleCase(List<CaseElement> elements) { super(elements); } + @Override public void generate(GenerationState state) { // TODO } diff --git a/src/main/java/bjc/rgens/parser/Rule.java b/src/main/java/bjc/rgens/parser/Rule.java index 59240bb..3ade828 100755 --- a/src/main/java/bjc/rgens/parser/Rule.java +++ b/src/main/java/bjc/rgens/parser/Rule.java @@ -21,6 +21,9 @@ import java.util.regex.PatternSyntaxException; * @author EVE */ public class Rule { + /** + * The grammar this rule belongs to. + */ public RGrammar belongsTo; /** The name of this grammar rule. */ @@ -35,26 +38,60 @@ public class Rule { * Perhaps this should be split into subclasses along prob type? I'm not * sure as to whether or not that would be a useful thing to do. */ + /** + * Type of probability to use for this rule. + * + * @author Ben Culkin + * + */ public static enum ProbType { + /** + * Normal-type probability. + */ NORMAL, + /** + * Descent-type probability. + */ DESCENDING, + /** + * Binomial-type probability. + */ BINOMIAL } + /** + * Type of probability to use for this rule. + */ public ProbType prob; // Probability vars /* Descent vars */ + /** + * Factor for probability to descend by. + */ public int descentFactor; + /* Binomial vars */ + /** + * Target for the binomial probability. + */ public int target; + /** + * Bound for the binomial probability. + */ public int bound; + /** + * Trials for the binomial probability. + */ public int trials; private List<String> rejectionPreds; private List<IPair<String, String>> findReplaces; // @TODO This default should be configurable in some way + /** + * Number of times this rule can recur. + */ public int recurLimit = 5; private int currentRecur; @@ -109,6 +146,7 @@ public class Rule { * * @param cse * The case to add. + * @param weight The weight for this case. */ public void addCase(RuleCase cse, int weight) { if (cse == null) { @@ -121,10 +159,21 @@ public class Rule { cases.addProbability(weight, cse); } + /** + * Add a rejection pattern to this rule. + * + * @param reject The rejection pattern. + */ public void addRejection(String reject) { addRejection(reject, new Tree<>()); } + /** + * Add a rejection pattern to this rule. + * + * @param reject The rejection pattern. + * @param errs The place to put errors. + */ public void addRejection(String reject, ITree<String> errs) { try { Pattern.compile(reject); @@ -135,10 +184,23 @@ public class Rule { rejectionPreds.add(reject); } + /** + * Add a find/replace pattern to this rule. + * + * @param find The find string. + * @param replace The replace string. + */ public void addFindReplace(String find, String replace) { addFindReplace(find, replace, new Tree<>()); } + /** + * Add a find/replace pattern to this rule. + * + * @param find The find string. + * @param replace The replace string. + * @param errs The place to put errors. + */ public void addFindReplace(String find, String replace, ITree<String> errs) { try { Pattern.compile(find); @@ -198,13 +260,13 @@ public class Rule { /** * Replace the current list of cases with a new one. * - * @param cases + * @param caseList * The new list of cases. */ - public void replaceCases(IList<IPair<Integer, RuleCase>> cases) { + public void replaceCases(IList<IPair<Integer, RuleCase>> caseList) { this.cases = new WeightedRandom<>(); - for(IPair<Integer, RuleCase> cse : cases) { + for(IPair<Integer, RuleCase> cse : caseList) { RuleCase cs = cse.getRight(); cs.belongsTo = this; cs.debugName = String.format("%s-%d", name, ++caseCount); @@ -250,6 +312,11 @@ public class Rule { return String.format("Rule '%s' with %d cases", name, cases.getValues().getSize()); } + /** + * Start recurring on this rule. + * + * @return Whether the recurrence rule has been exceeded. + */ public boolean doRecur() { if(currentRecur > recurLimit) return false; @@ -258,11 +325,22 @@ public class Rule { return true; } + /** + * End recurring on this rule. + */ public void endRecur() { - if(currentRecur > 0) currentRecur -= 1; - else throw new IllegalStateException("endRecur without matching doRecur"); + if(currentRecur > 0) { + currentRecur -= 1; + } else { + throw new IllegalStateException("endRecur without matching doRecur"); + } } + /** + * Get an exhaustive version of this rule. + * + * @return An exhaustive version of this rule. + */ public Rule exhaust() { Rule rl = new Rule(name); @@ -292,6 +370,11 @@ public class Rule { return rl; } + /** + * Generate this rule. + * + * @param state The generation state to use. + */ public void generate(GenerationState state) { state.swapGrammar(belongsTo); diff --git a/src/main/java/bjc/rgens/parser/RuleCase.java b/src/main/java/bjc/rgens/parser/RuleCase.java index dacb16e..3cfe81d 100755 --- a/src/main/java/bjc/rgens/parser/RuleCase.java +++ b/src/main/java/bjc/rgens/parser/RuleCase.java @@ -15,14 +15,25 @@ import java.util.List; * @author EVE */ public abstract class RuleCase { + /** + * Debugging name for this case. + */ public String debugName; + /** + * Serial number for this case. + */ public final int serial; - private static int nextSerial = 0; + /** + * The rule this case belongs to. + */ public Rule belongsTo; + /** + * The elements that make up this case. + */ public List<CaseElement> elementList; /** @@ -40,10 +51,23 @@ public abstract class RuleCase { nextSerial += 1; } + /** + * Generate this case. + * + * @param state The state to use. + */ public abstract void generate(GenerationState state); + /** + * Create a new case with a different set of elements. + * + * @param elements The elements for this case. + * + * @return The case with the same settings, but a different set of elements. + */ public abstract RuleCase withElements(List<CaseElement> elements); + @Override public String toString() { if(debugName != null) { return String.format("Case %s (#%d) of %s", debugName, serial, belongsTo); diff --git a/src/main/java/bjc/rgens/parser/elements/CaseElement.java b/src/main/java/bjc/rgens/parser/elements/CaseElement.java index 76b4efe..9fd565d 100755 --- a/src/main/java/bjc/rgens/parser/elements/CaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/CaseElement.java @@ -40,6 +40,9 @@ public abstract class CaseElement { /** The type of this element. */ public boolean spacing; + /** + * Create a new case element. + */ protected CaseElement() { this(true); } @@ -47,8 +50,8 @@ public abstract class CaseElement { /** * Create a new case element. * - * @param typ - * The type of this element. + * @param spacing + * Whether or not to allow spacing. */ protected CaseElement(boolean spacing) { this.spacing = spacing; @@ -58,7 +61,7 @@ public abstract class CaseElement { * Generate this case element. * * @param state - * The current state of generation. + * The current state of generation. */ public abstract void generate(GenerationState state); @@ -66,7 +69,7 @@ public abstract class CaseElement { * Create a case element from a string. * * @param csepart - * The string to convert. + * The string to convert. * * @return A case element representing the string. */ @@ -85,27 +88,31 @@ public abstract class CaseElement { String specialBody = csepart.substring(1, csepart.length() - 1); if (specialBody.matches("\\S+:\\S=\\S+")) { - String[] parts = LevelSplitter.def.levelSplit(specialBody, "=").toArray(new String[0]); + String[] parts = LevelSplitter.def.levelSplit(specialBody, "=") + .toArray(new String[0]); - if(parts.length != 2) { - throw new GrammarException("Colon variables must have a name and a definition"); + 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); - trace("Colon definition w/ op %d", (int)op); + trace("Colon definition w/ op %d", (int) op); // Remove the colon, plus any tacked on operator varName = varName.substring(0, varName.length() - 2); return VariableDefCaseElement.parseVariable(varName, parts[1], op, true); } else if (specialBody.matches("\\S+:=\\S+")) { - String[] parts = LevelSplitter.def.levelSplit(specialBody, "=").toArray(new String[0]); + String[] parts = LevelSplitter.def.levelSplit(specialBody, "=") + .toArray(new String[0]); - if(parts.length != 2) { - throw new GrammarException("Colon variables must have a name and a definition"); + if (parts.length != 2) { + throw new GrammarException( + "Colon variables must have a name and a definition"); } String varName = parts[0]; @@ -114,41 +121,49 @@ public abstract class CaseElement { return VariableDefCaseElement.parseVariable(varName, parts[1], ' ', true); } else if (specialBody.matches("\\S+=\\S+")) { - String[] parts = LevelSplitter.def.levelSplit(specialBody, "=").toArray(new String[0]); - if(parts.length != 2) { - throw new GrammarException("Variables must have a name and a definition"); + String[] parts = LevelSplitter.def.levelSplit(specialBody, "=") + .toArray(new String[0]); + if (parts.length != 2) { + throw new GrammarException( + "Variables must have a name and a definition"); } // Non-colon variables can't take an operator - return VariableDefCaseElement.parseVariable(parts[0], parts[1], (char)0, false); + 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)); + throw new IllegalArgumentException( + String.format("Unknown special case part '%s'", specialBody)); } } else if (csepart.matches("\\[\\S+\\]")) { String rawCase = csepart.substring(1, csepart.length() - 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)); + 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 = LevelSplitter.def.levelSplit(rawCase, "||").toArray(new String[0]); + } else if (rawCase.contains("||")) { + String[] elms = LevelSplitter.def.levelSplit(rawCase, "||") + .toArray(new String[0]); return new InlineRuleCaseElement(elms); - } else if(rawCase.contains("|")) { + } else if (rawCase.contains("|")) { throw new GrammarException("Inline rule using | found, they use || now"); - // String[] elms = LevelSplitter.def.levelSplit(rawCase, "|").toArray(new String[0]); + // String[] elms = LevelSplitter.def.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 if (csepart.startsWith("%") && !csepart.equals("%")) { + return new RuleCaseElement(csepart); } else { return new LiteralCaseElement(csepart); } diff --git a/src/main/java/bjc/rgens/parser/elements/InlineRuleCaseElement.java b/src/main/java/bjc/rgens/parser/elements/InlineRuleCaseElement.java index 66fbb96..6f3d889 100644 --- a/src/main/java/bjc/rgens/parser/elements/InlineRuleCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/InlineRuleCaseElement.java @@ -13,13 +13,33 @@ import bjc.utils.ioutils.LevelSplitter; import java.util.ArrayList; import java.util.List; +/** + * Case element for an inline rule. + * + * @author Ben Culkin + * + */ public class InlineRuleCaseElement extends CaseElement { + /** + * The elements for this case element. + */ public final WeightedRandom<CaseElement> elements; + /** + * Create a new inline rule case element. + * + * @param parts The parts of this case element. + */ public InlineRuleCaseElement(String... parts) { this(new Tree<>(), parts); } + /** + * Create a new inline rule case element. + * + * @param errs The place to store errors in. + * @param parts The parts of this case element. + */ public InlineRuleCaseElement(ITree<String> errs, String... parts) { super(true); @@ -43,6 +63,7 @@ public class InlineRuleCaseElement extends CaseElement { } } + @Override 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 c5e5c6f..170794e 100755 --- a/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/LitVariableCaseElement.java @@ -2,11 +2,24 @@ package bjc.rgens.parser.elements; import bjc.rgens.parser.GenerationState; +/** + * A case element that defines a literal variable. + * + * @author Ben Culkin + * + */ public class LitVariableCaseElement extends VariableDefCaseElement { + /** + * Create a new case element for a literal variable. + * + * @param name The name for the case element. + * @param def The definition for the case element. + */ public LitVariableCaseElement(String name, String def) { super(name, def); } + @Override public void generate(GenerationState state) { state.defineVar(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 2621ee6..54c6454 100644 --- a/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/LiteralCaseElement.java @@ -2,15 +2,29 @@ package bjc.rgens.parser.elements; import bjc.rgens.parser.GenerationState; +/** + * Case element that appends a literal. + * @author Ben Culkin + * + */ public class LiteralCaseElement extends CaseElement { + /** + * The value for this element. + */ public String val; + /** + * Create a new case element. + * + * @param val The value to append. + */ public LiteralCaseElement(String val) { super(true); this.val = val; } + @Override public void generate(GenerationState state) { state.appendContents(val); } diff --git a/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java b/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java index bd73f1b..2d3a771 100755 --- a/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/RangeCaseElement.java @@ -2,10 +2,28 @@ package bjc.rgens.parser.elements; import bjc.rgens.parser.GenerationState; +/** + * Case element which generates a range of random numbers. + * + * @author Ben Culkin + * + */ public class RangeCaseElement extends CaseElement { + /** + * The beginning point for this range. + */ public final int begin; + + /** + * The ending point for this range. + */ public final int end; + /** + * Create a new range case element. + * @param beg The beginning point for the range. + * @param en The ending point for the range. + */ public RangeCaseElement(int beg, int en) { super(true); @@ -13,6 +31,7 @@ public class RangeCaseElement extends CaseElement { end = en; } + @Override public void generate(GenerationState state) { int val = state.rnd.nextInt(end - begin); val += begin; diff --git a/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java b/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java index 1a2cf85..7fe6603 100755 --- a/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/RuleCaseElement.java @@ -8,48 +8,81 @@ import bjc.rgens.parser.RGrammar; import bjc.rgens.parser.Rule; import bjc.rgens.parser.elements.vars.VariableElement; +/** + * Case element which references a rule. + * + * @author Ben Culkin + * + */ public class RuleCaseElement extends CaseElement { + /** + * The elements for this rule. + */ public List<VariableElement> elements; + /** + * Create a new case element to reference a rule. + * + * @param vl + * The text of the reference. + */ public RuleCaseElement(String vl) { super(true); this.elements = VariableElement.parseElementString(vl); } + /** + * Create a new case element to reference a rule. + * + * @param vl + * The text of the reference. + * @param elements + * The elements of the reference. + */ public RuleCaseElement(String vl, List<VariableElement> elements) { super(true); this.elements = elements; } + @Override public void generate(GenerationState state) { GenerationState newState = state.newBuf(); boolean inName = false; - for(VariableElement elm : elements) { + for (VariableElement elm : elements) { elm.generate(newState); - if(inName == false) inName = elm.forbidSpaces; + if (inName == false) + inName = elm.forbidSpaces; } String body = newState.getContents(); - if(inName) { + if (inName) { doGenerate(String.format("[%s]", body), state); } else { state.appendContents(body); } } + /** + * Do the generation of a rule element. + * + * @param acName + * The name of the rule to generation. + * @param state + * The generation state. + */ protected void doGenerate(String acName, GenerationState state) { GenerationState newState = state.newBuf(); Rule rl; String actName = acName; - + if (actName.startsWith("[^")) { actName = "[" + actName.substring(2); @@ -58,12 +91,11 @@ public class RuleCaseElement extends CaseElement { rl = state.findRule(actName, true); } - if(rl != null) { + if (rl != null) { RGrammar destGrammar = rl.belongsTo; newState.swapGrammar(destGrammar); - /* - * Don't postprocess the string, we should only do that - * once. + /* + * Don't postprocess the string, we should only do that once. */ String res = destGrammar.generate(actName, newState, false); newState.setContents(res); @@ -74,17 +106,17 @@ public class RuleCaseElement extends CaseElement { * 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); - } - */ + * 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); diff --git a/src/main/java/bjc/rgens/parser/elements/RuleVariableCaseElement.java b/src/main/java/bjc/rgens/parser/elements/RuleVariableCaseElement.java index 923b56c..5806e39 100644 --- a/src/main/java/bjc/rgens/parser/elements/RuleVariableCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/RuleVariableCaseElement.java @@ -6,15 +6,32 @@ import bjc.rgens.parser.GenerationState; import bjc.rgens.parser.GrammarException; import bjc.rgens.parser.Rule; +/** + * Case element which creates a rule variable. + * + * @author Ben Culkin + * + */ public class RuleVariableCaseElement extends VariableDefCaseElement { + /** + * Whether or not this is an exhaustive variable. + */ public final boolean exhaust; + /** + * Create a case element which creates a rule variable. + * + * @param varName The name of the variable. + * @param varDef The definition of the variable. + * @param exhaust Whether or not this is an exhaustive variable. + */ public RuleVariableCaseElement(String varName, String varDef, boolean exhaust) { super(varName, varDef); this.exhaust = exhaust; } + @Override public void generate(GenerationState state) { Rule rl = state.findRule(varDef, true); diff --git a/src/main/java/bjc/rgens/parser/elements/SerialCaseElement.java b/src/main/java/bjc/rgens/parser/elements/SerialCaseElement.java index 195ba4f..3d15e8c 100644 --- a/src/main/java/bjc/rgens/parser/elements/SerialCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/SerialCaseElement.java @@ -2,12 +2,35 @@ package bjc.rgens.parser.elements; import bjc.rgens.parser.GenerationState; +/** + * Case element which is generated one or more times. + * + * @author Ben Culkin + * + */ public class SerialCaseElement extends CaseElement { + /** + * The case element to repeat. + */ public final CaseElement rep; + /** + * The lower bound of times to repeat. + */ public final int lower; + + /** + * The upper bound of times to repeat. + */ public final int upper; + /** + * Create a new repeating case element. + * + * @param rep The case element to repeat. + * @param lower The lower bound of times to repeat. + * @param upper The upper bound of times to repeat. + */ public SerialCaseElement(CaseElement rep, int lower, int upper) { super(rep.spacing); @@ -17,6 +40,7 @@ public class SerialCaseElement extends CaseElement { this.upper = upper; } + @Override public void generate(GenerationState state) { int num = state.rnd.nextInt(upper - lower) + lower; diff --git a/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java b/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java index 00441c0..2aa720d 100755 --- a/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/StringCaseElement.java @@ -1,11 +1,26 @@ package bjc.rgens.parser.elements; +/** + * Case element which writes a string. + * + * @author Ben Culkin + * + */ public abstract class StringCaseElement extends CaseElement { + /** + * String written by this element. + */ public final String val; - + + /** + * Create a new string inserting case element. + * + * @param vl + * The string to insert. + */ protected StringCaseElement(String vl) { super(true); - + val = vl; } @@ -33,7 +48,7 @@ public abstract class StringCaseElement extends CaseElement { return false; return true; } - + @Override public String toString() { return val; diff --git a/src/main/java/bjc/rgens/parser/elements/VariableDefCaseElement.java b/src/main/java/bjc/rgens/parser/elements/VariableDefCaseElement.java index 37a12b6..23659c7 100755 --- a/src/main/java/bjc/rgens/parser/elements/VariableDefCaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/VariableDefCaseElement.java @@ -2,6 +2,12 @@ package bjc.rgens.parser.elements; import bjc.rgens.parser.GrammarException; +/** + * Variable defining case element. + * + * @author Ben Culkin + * + */ public abstract class VariableDefCaseElement extends CaseElement { /** * The name of the variable this element defines. @@ -13,6 +19,14 @@ public abstract class VariableDefCaseElement extends CaseElement { */ public final String varDef; + /** + * Create a variable defining case element. + * + * @param name + * The name of the variable. + * @param def + * The definition of the variable. + */ public VariableDefCaseElement(String name, String def) { super(false); @@ -51,16 +65,33 @@ public abstract class VariableDefCaseElement extends CaseElement { return true; } - public static CaseElement parseVariable(String varName, String varDef, char op, boolean colon) { - if(varName.startsWith("$")) { + /** + * Parse a variable reference. + * + * @param varName + * The variable name. + * @param varDef + * The variable definition. + * @param op + * Unused as of yet. + * @param colon + * Whether the colon was present in the declaration. + * + * @return A case element which declares the variable. + */ + 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); + if (colon) + return new ExpVariableCaseElement(varName.substring(1), varDef); return new LitVariableCaseElement(varName.substring(1), varDef); - } else if(varName.startsWith("@")) { + } else if (varName.startsWith("@")) { return new RuleVariableCaseElement(varName.substring(1), varDef, colon); } else { - throw new GrammarException("Unrecognized declaration sigil " + varName.charAt(0)); + throw new GrammarException( + "Unrecognized declaration sigil " + varName.charAt(0)); } } } diff --git a/src/main/java/bjc/rgens/parser/elements/vars/LiteralVariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/LiteralVariableElement.java index e7415f5..595397b 100644 --- a/src/main/java/bjc/rgens/parser/elements/vars/LiteralVariableElement.java +++ b/src/main/java/bjc/rgens/parser/elements/vars/LiteralVariableElement.java @@ -2,15 +2,31 @@ package bjc.rgens.parser.elements.vars; import bjc.rgens.parser.GenerationState; +/** + * Case element which references a literal variable. + * + * @author Ben Culkin + * + */ public class LiteralVariableElement extends VariableElement { + /** + * The name for the variable. + */ public String val; + /** + * Create a case element which references a literal variable. + * + * @param forbidSpaces Whether to forbid spaces in the result. + * @param val The name of the literal variable. + */ public LiteralVariableElement(boolean forbidSpaces, String val) { super(forbidSpaces); this.val = val; } + @Override public void generate(GenerationState state) { state.appendContents(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 index e81e9f8..4001b93 100644 --- a/src/main/java/bjc/rgens/parser/elements/vars/RRefVariableElement.java +++ b/src/main/java/bjc/rgens/parser/elements/vars/RRefVariableElement.java @@ -4,15 +4,30 @@ import bjc.rgens.parser.GenerationState; import bjc.rgens.parser.GrammarException; import bjc.rgens.parser.Rule; +/** + * Rule reference variable element. + * @author Ben Culkin + * + */ public class RRefVariableElement extends VariableElement { + /** + * The name of the rule to reference. + */ public String value; + /** + * Create a new rule-reference variable element. + * + * @param forbidSpaces Whether to forbid spaces or not. + * @param val The rule to reference. + */ public RRefVariableElement(boolean forbidSpaces, String val) { super(forbidSpaces); value = val; } + @Override public void generate(GenerationState state) { Rule rl = state.findRule(value, true); diff --git a/src/main/java/bjc/rgens/parser/elements/vars/TRefVariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/TRefVariableElement.java index c753dfe..efd9007 100644 --- a/src/main/java/bjc/rgens/parser/elements/vars/TRefVariableElement.java +++ b/src/main/java/bjc/rgens/parser/elements/vars/TRefVariableElement.java @@ -7,6 +7,7 @@ import bjc.rgens.parser.GenerationState; * * finish when template vars are implemented. */ +@SuppressWarnings("javadoc") public class TRefVariableElement extends VariableElement { public String value; @@ -16,6 +17,7 @@ public class TRefVariableElement extends VariableElement { value = val; } + @Override public void generate(GenerationState state) { /* if(!state.rlVars.containsKey(val)) { diff --git a/src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java index e65d876..cdead80 100644 --- a/src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java +++ b/src/main/java/bjc/rgens/parser/elements/vars/VRefVariableElement.java @@ -3,15 +3,30 @@ package bjc.rgens.parser.elements.vars; import bjc.rgens.parser.GenerationState; import bjc.rgens.parser.GrammarException; +/** + * Variable reference variable element. + * + * @author Ben Culkin + * + */ public class VRefVariableElement extends VariableElement { + /** + * The name of the variable to element. + */ public final String nam; + /** + * Create a new variable referencing variable element. + * @param forbidSpaces Whether or not to forbid spaces in the element. + * @param nam The name of the variable. + */ public VRefVariableElement(boolean forbidSpaces, String nam) { super(forbidSpaces); this.nam = nam; } + @Override public void generate(GenerationState state) { String strang = state.findVar(nam); diff --git a/src/main/java/bjc/rgens/parser/elements/vars/VariableElement.java b/src/main/java/bjc/rgens/parser/elements/vars/VariableElement.java index eb36af8..c73e249 100644 --- a/src/main/java/bjc/rgens/parser/elements/vars/VariableElement.java +++ b/src/main/java/bjc/rgens/parser/elements/vars/VariableElement.java @@ -7,30 +7,73 @@ import bjc.rgens.parser.GenerationState; import bjc.rgens.parser.GrammarException; import bjc.utils.ioutils.LevelSplitter; +/** + * Case element which references a variable. + * + * @author Ben Culkin + * + */ public abstract class VariableElement { + /** + * Whether or not to forbid spaces in this element. + */ public boolean forbidSpaces; + /** + * Create a new variable element. + * + * @param forbidSpacing + * Whether spacing should be forbidden in this element. + */ protected VariableElement(boolean forbidSpacing) { forbidSpaces = forbidSpacing; } + /** + * Generate this element. + * + * @param state + * The state of generation. + */ public abstract void generate(GenerationState state); + /** + * Parse a variable element from a string. + * + * @param varElm + * The string to parse. + * + * @return The variable elements which make up the string. + */ public static List<VariableElement> parseElementString(String varElm) { boolean forbidSpaces = LevelSplitter.def.levelContains(varElm, "-", "+"); String[] parts; - if(forbidSpaces) { - parts = LevelSplitter.def.levelSplit(varElm, true, "-", "+").toArray(new String[0]); + if (forbidSpaces) { + parts = LevelSplitter.def.levelSplit(varElm, true, "-", "+") + .toArray(new String[0]); } else { - parts = new String[] { varElm }; + parts = new String[] { + varElm + }; } return parseElementString(forbidSpaces, parts); } - public static List<VariableElement> parseElementString(boolean forbidSpaces, String... parts) { + /** + * Parse a string of variable elements. + * + * @param forbidSpaces + * Whether or not to forbid spacing in this variable. + * @param parts + * The parts to parse into variable elements. + * + * @return The variable elements from the string. + */ + public static List<VariableElement> parseElementString(boolean forbidSpaces, + String... parts) { List<VariableElement> elms = new ArrayList<>(parts.length); VariableElement prevElement = null; @@ -44,23 +87,26 @@ public abstract class VariableElement { VariableElement elm = null; - if(part.startsWith("$")) { + 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"); + 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, String.format("[%s]", part.substring(1))); + elm = new RRefVariableElement(forbidSpaces, + String.format("[%s]", part.substring(1))); } else if (part.startsWith("/")) { throw new GrammarException("Template variables aren't implemented yet"); } else { - if(prevElement != null && prevElement instanceof LiteralVariableElement) { + if (prevElement != null + && prevElement instanceof LiteralVariableElement) { /* Aggregate chain literals together */ - ((LiteralVariableElement)prevElement).val += part; + ((LiteralVariableElement) prevElement).val += part; } else { - if(part.contains(" ")) { + if (part.contains(" ")) { elm = new LiteralVariableElement(false, part); } else { elm = new LiteralVariableElement(true, part); @@ -68,7 +114,7 @@ public abstract class VariableElement { } } - if(elm != null) { + if (elm != null) { elms.add(elm); prevElement = elm; diff --git a/src/main/java/bjc/rgens/parser/templates/LiteralTemplateElement.java b/src/main/java/bjc/rgens/parser/templates/LiteralTemplateElement.java index 6fa69f1..6bd8b9f 100644 --- a/src/main/java/bjc/rgens/parser/templates/LiteralTemplateElement.java +++ b/src/main/java/bjc/rgens/parser/templates/LiteralTemplateElement.java @@ -19,7 +19,10 @@ public class LiteralTemplateElement extends TemplateElement { * Create a new literal template element. * * @param val - * The string to insert. + * The string to insert. + * + * @param errs + * The place to put errors. */ public LiteralTemplateElement(String val, ITree<String> errs) { super(true); diff --git a/src/main/java/bjc/rgens/parser/templates/TemplateElement.java b/src/main/java/bjc/rgens/parser/templates/TemplateElement.java index 2d0724b..effd964 100644 --- a/src/main/java/bjc/rgens/parser/templates/TemplateElement.java +++ b/src/main/java/bjc/rgens/parser/templates/TemplateElement.java @@ -2,14 +2,38 @@ package bjc.rgens.parser.templates; import bjc.rgens.parser.GenerationState; +/** + * Abstract element of a template. + * + * @author Ben Culkin + * + */ public abstract class TemplateElement { + /** + * Whether or not to handle spacing. + */ public boolean spacing; + /** + * The template this element belongs to. + */ public GrammarTemplate belongsTo; + /** + * Create a new template element. + * + * @param spacing + * Whether or not to handle spacing. + */ protected TemplateElement(boolean spacing) { this.spacing = spacing; } + /** + * Generate this template element. + * + * @param state + * The state for the generation. + */ public abstract void generate(GenerationState state); } |
