summaryrefslogtreecommitdiff
path: root/RGens/src/main/java/bjc/rgens/server
diff options
context:
space:
mode:
authorstudent <student@student-OptiPlex-9020>2017-03-17 10:49:27 -0400
committerstudent <student@student-OptiPlex-9020>2017-03-17 10:49:27 -0400
commit0ea49dd4a52358f053c9be7138c392b16de05899 (patch)
tree802e275aaf279480ee8626136f56bfa1fbab6845 /RGens/src/main/java/bjc/rgens/server
parent36cf3a0f0604ef43ce838ff6e9a7fc4e7c299522 (diff)
Move things around, and start on new parser.
Diffstat (limited to 'RGens/src/main/java/bjc/rgens/server')
-rw-r--r--RGens/src/main/java/bjc/rgens/server/CLIArgsParser.java141
-rw-r--r--RGens/src/main/java/bjc/rgens/server/GrammarServer.java346
-rw-r--r--RGens/src/main/java/bjc/rgens/server/GrammarServerEngine.java300
-rw-r--r--RGens/src/main/java/bjc/rgens/server/ReaderState.java181
-rw-r--r--RGens/src/main/java/bjc/rgens/server/ServerGrammarReader.java326
5 files changed, 1294 insertions, 0 deletions
diff --git a/RGens/src/main/java/bjc/rgens/server/CLIArgsParser.java b/RGens/src/main/java/bjc/rgens/server/CLIArgsParser.java
new file mode 100644
index 0000000..fa0d399
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/server/CLIArgsParser.java
@@ -0,0 +1,141 @@
+package bjc.rgens.server;
+
+import java.io.File;
+
+public class CLIArgsParser {
+ public static void parseArgs(String[] args, GrammarServerEngine eng) {
+ boolean didTerminalOp = false;
+ boolean forceInteractive = false;
+
+ // @TODO report error status
+ boolean didError = false;
+
+ if(args.length < 0) return;
+
+ if(args.length == 1 && args[0].equals("--help")) {
+ // @TODO show help
+ } else {
+ for(int i = 0; i < args.length; i++) {
+ String arg = args[i];
+
+ switch(arg) {
+ case "-lc":
+ case "--load-config-file":
+ String configFileName = args[++i];
+
+ eng.doLoadConfig(configFileName);
+ break;
+ case "-lg":
+ case "--load-grammar-file":
+ String grammarFileName = args[++i];
+
+ File grammarFile = new File(grammarFileName);
+
+ String ruleName = grammarFile.getName();
+ ruleName = ruleName.substring(0, ruleName.lastIndexOf('.'));
+
+ if(!args[i+1].startsWith("-")) {
+ ruleName = args[++i];
+ }
+
+ eng.doLoadGrammar(ruleName, grammarFileName);
+
+ break;
+ case "-ll":
+ case "--load-long-file":
+ String longRuleFileName = args[++i];
+
+ File longRuleFile = new File(longRuleFileName);
+
+ String longRuleName = longRuleFile.getName();
+ longRuleName = longRuleName.substring(0, longRuleName.lastIndexOf('.'));
+
+ if(!args[i+1].startsWith("-")) {
+ longRuleName = args[++i];
+ }
+
+ eng.doLoadLongRule(longRuleName, longRuleFileName);
+
+ break;
+ case "-ge":
+ case "--generate-exported-rule":
+ String exportedRuleName = args[++i];
+
+ if(eng.hasExportedRule(exportedRuleName)) {
+ eng.doGenerateExportedRule(exportedRuleName);
+ didTerminalOp = true;
+ } else {
+ System.out.printf("Error: No exported rule named %s\n", exportedRuleName);
+ }
+ break;
+ case "-gg":
+ case "--generate-grammar-rule":
+ String grammarName = args[++i];
+
+ if(!eng.hasLoadedGrammar(grammarName)) {
+ System.out.printf("Error: No grammar named %s\n", grammarName);
+ } else {
+ String ruleToGenerate = "";
+
+ if(!args[i+1].startsWith("-")) {
+ ruleToGenerate = args[++i];
+ } else if(eng.hasInitialRule(grammarName)) {
+ ruleToGenerate = eng.getInitialRule(grammarName);
+ } else {
+ System.out.printf("Error: Grammar %s has no initial rule. A "
+ + "rule must be provided.",grammarName);
+ }
+
+ eng.doGenerateGrammar(grammarName, ruleToGenerate);
+ didTerminalOp = true;
+ }
+ break;
+ case "-st":
+ case "--stress-test":
+ String thingToTest = args[++i];
+
+ // @TODO support testing rules from grammars
+ // as well as a specified number of times
+ if(thingToTest.equals("*")) {
+ eng.doStressTest(10000);
+ } else {
+ eng.doStressTest(thingToTest, 1000);
+ }
+
+ didTerminalOp = true;
+
+ break;
+ case "-d":
+ case "--debug":
+ if(eng.debugMode) {
+ System.out.println("Warning: debug mode is already on. Use -nd or --no-debug"
+ + " to turn it off");
+ } else {
+ eng.debugMode = true;
+ }
+ break;
+ case "-nd":
+ case "--no-debug":
+ if(!eng.debugMode) {
+ System.out.println("Warning: debug mode is already off. Use -d or --debug"
+ + " to turn it on");
+ } else {
+ eng.debugMode = false;
+ }
+ break;
+ case "-i":
+ case "--interactive":
+ forceInteractive = true;
+ break;
+ default:
+ System.out.println("Error: Unrecognized argument " + arg);
+ break;
+ }
+ }
+ }
+
+ if(!forceInteractive && didTerminalOp) {
+ System.exit(didError ? 1 : 0);
+ }
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/server/GrammarServer.java b/RGens/src/main/java/bjc/rgens/server/GrammarServer.java
new file mode 100644
index 0000000..1a47de2
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/server/GrammarServer.java
@@ -0,0 +1,346 @@
+package bjc.rgens.server;
+
+import bjc.utils.funcdata.FunctionalMap;
+import bjc.utils.funcdata.IMap;
+import bjc.utils.gen.WeightedGrammar;
+
+import java.io.File;
+
+import java.util.Scanner;
+
+public class GrammarServer {
+ private Scanner scn;
+
+ private IMap<String, WeightedGrammar<String>> loadedGrammars;
+ private IMap<String, WeightedGrammar<String>> exportedRules;
+
+ private GrammarServerEngine eng;
+
+ public GrammarServer(Scanner scn) {
+ this.scn = scn;
+
+ this.loadedGrammars = new FunctionalMap<>();
+ this.exportedRules = new FunctionalMap<>();
+
+ eng = new GrammarServerEngine(loadedGrammars, exportedRules);
+
+ ServerGrammarReader.setExportedRules(exportedRules);
+ }
+
+ public static void main(String[] args) {
+ System.out.println("GrammarServer 1.0");
+
+ Scanner scn = new Scanner(System.in);
+
+ GrammarServer serv = new GrammarServer(scn);
+
+ CLIArgsParser.parseArgs(args, serv.eng);
+
+ System.out.print("Enter a command (m for help): ");
+
+ char comm = scn.nextLine().charAt(0);
+
+ while(comm != 'e') {
+ switch(comm) {
+ case 'm':
+ System.out.println("GrammarServer Commands:");
+ System.out.println("\tm: Print command help");
+ System.out.println("\te: Exit GrammarServer");
+ System.out.println("\tl: Load from file");
+ System.out.println("\ts: Show information");
+ System.out.println("\tg: Generate text");
+ break;
+ case 'g':
+ serv.generateMode();
+ break;
+ case 's':
+ serv.showMode();
+ break;
+ case 'l':
+ serv.loadMode();
+ break;
+ default:
+ System.out.println("? Unrecognized Command");
+ }
+
+ System.out.print("Enter a command (m for help): ");
+
+ comm = scn.nextLine().charAt(0);
+ }
+
+ System.out.println("GrammarServer exiting");
+ }
+
+
+
+ private void loadMode() {
+ System.out.println("Entering Load Mode");
+
+ System.out.print("(Load Mode) Enter a command (m for help): ");
+ char comm = scn.nextLine().charAt(0);
+
+ while(comm != 'e') {
+ switch(comm) {
+ case 'm':
+ System.out.println("GrammarServer Load Mode Commands");
+ System.out.println("\tm: Show command help");
+ System.out.println("\te: Exit Load Mode");
+ System.out.println("\tg: Load grammar from a file");
+ System.out.println("\tl: Load long rule from a file");
+ System.out.println("\tc: Load configuration from a file");
+ break;
+ case 'g':
+ loadGrammar();
+ break;
+ case 'c':
+ loadConfig();
+ break;
+ case 'l':
+ loadLongRule();
+ break;
+ default:
+ System.out.println("? Unrecognized Command");
+ }
+
+ System.out.print("(Load Mode) Enter a command (m for help): ");
+ comm = scn.nextLine().charAt(0);
+ }
+
+ System.out.println("Exiting Load Mode");
+ }
+
+ private void loadGrammar() {
+ System.out.print("Enter path to load grammar from: ");
+
+ String grammarPath = scn.nextLine().trim();
+
+ File grammarFile = new File(grammarPath);
+
+ String grammarName = grammarFile.getName().trim();
+
+ grammarName = grammarName.substring(0, grammarName.lastIndexOf("."));
+
+ System.out.printf("Enter grammar name or press enter for"
+ + " the default (%s): ", grammarName);
+
+ String inputName = scn.nextLine();
+
+ if(!inputName.equals("")) {
+ grammarName = inputName;
+ }
+
+ eng.doLoadGrammar(grammarName, grammarPath);
+
+ return;
+ }
+
+ private void loadLongRule() {
+ System.out.print("Enter the file to load a long rule from: ");
+
+ String fileName = scn.nextLine().trim();
+ File ruleFile = new File(fileName);
+
+ String tempName = ruleFile.getName();
+ tempName = tempName.substring(0, tempName.lastIndexOf('.'));
+
+ System.out.printf("Enter the name for the long rule (default %s): ", tempName);
+
+ String ruleName = scn.nextLine().trim();
+
+ if(ruleName.equals("")) {
+ ruleName = tempName;
+ }
+
+ eng.doLoadLongRule(ruleName, fileName);
+ }
+
+ private void loadConfig() {
+ System.out.print("Enter the file to load configuration from: ");
+
+ String fileName = scn.nextLine().trim();
+
+ eng.doLoadConfig(fileName);
+ }
+
+ private void showMode() {
+ System.out.println("Entering Show Mode");
+
+ System.out.print("(Show Mode) Enter a command (m for help): ");
+
+ char comm = scn.nextLine().charAt(0);
+
+ while(comm != 'e') {
+ switch(comm) {
+ case 'm':
+ System.out.println("GrammarServer Show Mode Commands: ");
+ System.out.println("\tm: Show command help");
+ System.out.println("\tl: Show loaded grammars");
+ System.out.println("\tr: Show rules from a grammar");
+ System.out.println("\tx: Show exported rules");
+ System.out.println("\te: Exit Show Mode");
+ break;
+ case 'r':
+ showGrammarRules();
+ break;
+ case 'x':
+ eng.doShowExportedRules();
+ break;
+ case 'l':
+ eng.doShowLoadedGrammars();
+ break;
+ default:
+ System.out.println("? Unrecognized command");
+ break;
+ }
+
+ System.out.print("(Show Mode) Enter a command (m for help): ");
+
+ comm = scn.nextLine().charAt(0);
+ }
+
+
+
+ System.out.println("Exiting Show Mode");
+ }
+
+ private void generateMode() {
+ System.out.println("Entering Generate Mode");
+
+ System.out.print("(Generate Mode) Enter a command (m for help): ");
+
+ char comm = scn.nextLine().charAt(0);
+
+ while(comm != 'e') {
+ switch(comm) {
+ case 'm':
+ System.out.println("GrammarServer Generate Mode Commands: ");
+ System.out.println("\tm: Show command help");
+ System.out.println("\tx: Generate from exported rules");
+ System.out.println("\tr: Generate from a grammar");
+ System.out.println("\te: Exit Generate Mode");
+ break;
+ case 'x':
+ generateExportedRule();
+ break;
+ case 'r':
+ generateGrammar();
+ break;
+ default:
+ System.out.println("? Unrecognized command");
+ }
+
+ System.out.print("(Generate Mode) Enter a command (m for help): ");
+
+ comm = scn.nextLine().charAt(0);
+ }
+
+ System.out.println("Exiting Generate Mode");
+ }
+
+ private void generateExportedRule() {
+ System.out.print("Enter the name of the rule to generate"
+ + " (l to list, enter to cancel): ");
+
+ String ruleName = scn.nextLine().trim();
+
+ while(true) {
+ if(ruleName.equals("")) break;
+
+ if(ruleName.equals("l")) {
+ eng.doShowExportedRules();
+ } else if (exportedRules.containsKey(ruleName)) {
+ eng.doGenerateExportedRule(ruleName);
+
+ System.out.print("Generate again from this rule? (yes/no) (yes by default): ");
+
+ String resp = scn.nextLine().trim();
+
+ if(resp.equalsIgnoreCase("yes") || resp.equals("")) {
+ continue;
+ }
+ } else {
+ System.out.println("? Unrecognized external rule");
+ }
+
+ System.out.print("Enter the name of the rule to generate"
+ + " (l to list, enter to cancel): ");
+
+ ruleName = scn.nextLine().trim();
+ }
+ }
+
+ private void generateGrammar() {
+ System.out.print("Enter the name of the grammar to generate from (l to list, enter to cancel): ");
+
+ String grammarName = scn.nextLine().trim();
+
+ while(true) {
+ if(grammarName.equals("")) break;
+
+ if(grammarName.equals("l")) {
+ eng.doShowLoadedGrammars();
+ } else if(loadedGrammars.containsKey(grammarName)) {
+ WeightedGrammar<String> currentGram = loadedGrammars.get(grammarName);
+
+ System.out.print("Enter the name of the rule to generate"
+ + " (l to list, enter to cancel): ");
+
+ String ruleName = scn.nextLine().trim();
+
+ while(true) {
+ if(ruleName.equals("")) break;
+
+ if(ruleName.equals("l")) {
+ eng.doShowGrammarRules(grammarName);
+ } else if (currentGram.hasRule(ruleName)) {
+ eng.doGenerateGrammar(currentGram, ruleName);
+
+ System.out.print("Generate again from this rule? (yes/no) (yes by default): ");
+
+ String resp = scn.nextLine().trim();
+
+ if(resp.equalsIgnoreCase("yes") || resp.equals("")) {
+ continue;
+ }
+ } else {
+ System.out.println("? Unrecognized grammar rule");
+ }
+
+ System.out.print("Enter the name of the rule to generate"
+ + " (l to list, enter to cancel): ");
+
+ ruleName = scn.nextLine().trim();
+ }
+
+ } else {
+ System.out.println("? Unrecognized grammar name");
+ }
+
+ System.out.print("Enter the name of the grammar to generate from "
+ + "(l to list, enter to cancel): ");
+
+ grammarName = scn.nextLine().trim();
+ }
+ }
+
+ private void showGrammarRules() {
+ System.out.print("Enter the name of the grammar (l to list): ");
+ String gramName = scn.nextLine().trim();
+
+ do {
+ if(gramName.equals("")) break;
+
+ if(gramName.equals("l")) {
+ eng.doShowLoadedGrammars();
+ } else if (loadedGrammars.containsKey(gramName)) {
+ eng.doShowGrammarRules(gramName);
+ break;
+ } else {
+ System.out.println("? Unrecognized grammar name");
+ }
+
+ System.out.print("Enter the name of the grammar (l to list): ");
+ gramName = scn.nextLine().trim();
+ } while(true);
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/server/GrammarServerEngine.java b/RGens/src/main/java/bjc/rgens/server/GrammarServerEngine.java
new file mode 100644
index 0000000..2f608ec
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/server/GrammarServerEngine.java
@@ -0,0 +1,300 @@
+package bjc.rgens.server;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Scanner;
+
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.funcdata.IList;
+import bjc.utils.funcdata.IMap;
+import bjc.utils.funcutils.ListUtils;
+import bjc.utils.gen.WeightedGrammar;
+
+public class GrammarServerEngine {
+ private IMap<String, WeightedGrammar<String>> loadedGrammars;
+ private IMap<String, WeightedGrammar<String>> exportedRules;
+
+ public static boolean debugMode = false;
+
+ public GrammarServerEngine(IMap<String, WeightedGrammar<String>> loadedGrammars,
+ IMap<String, WeightedGrammar<String>> exportedRules) {
+ this.loadedGrammars = loadedGrammars;
+ this.exportedRules = exportedRules;
+ }
+
+ public String getInitialRule(String grammarName) {
+ return loadedGrammars.get(grammarName).getInitialRule();
+ }
+
+ public boolean hasInitialRule(String grammarName) {
+ return loadedGrammars.get(grammarName).hasInitialRule();
+ }
+
+ public boolean hasExportedRule(String ruleName) {
+ return exportedRules.containsKey(ruleName);
+ }
+
+ public boolean hasLoadedGrammar(String grammarName) {
+ return loadedGrammars.containsKey(grammarName);
+ }
+
+ public void doLoadConfig(String fileName) {
+ File inputFile = new File(fileName);
+
+ try(FileInputStream inputStream = new FileInputStream(inputFile)) {
+ try(Scanner fle = new Scanner(inputStream)) {
+ while(fle.hasNextLine()) {
+ String line = fle.nextLine().trim();
+
+ // Handle comments
+ if(line.equals("") ||
+ line.startsWith("#") ||
+ line.startsWith("//")) {
+ continue;
+ }
+
+ // Handle mixed whitespace in input
+ line = line.replaceAll("\\s+", " ");
+
+ String path;
+ String name;
+
+ if(line.lastIndexOf(' ') != -1) {
+ path = line.substring(0, line.lastIndexOf(' '));
+ name = line.substring(line.lastIndexOf(' ') + 1, line.length());
+ } else {
+ path = line;
+
+ File pathFile = new File(path);
+ String pathName = pathFile.getName();
+
+ if(pathFile.isDirectory()) {
+ // Load all the files in the directory recursively
+ Queue<File> entries = new LinkedList<>();
+
+ for (File entry : pathFile.listFiles()) {
+ entries.add(entry);
+ }
+
+ while(!entries.isEmpty()) {
+ File entry = entries.poll();
+
+ String entryPath = entry.getName();
+
+ if(entry.isHidden()) continue;
+ if(entry.isDirectory()) {
+ for (File newEntry : entry.listFiles()) {
+ entries.add(newEntry);
+ }
+
+ continue;
+ }
+
+ name = entryPath.substring(0, entryPath.lastIndexOf('.'));
+
+ doLoadGrammarEntry(entry.toString(), name);
+ }
+
+ continue;
+ }
+
+ name = pathName.substring(0, pathName.lastIndexOf('.'));
+ }
+
+ doLoadGrammarEntry(path, name);
+ }
+ }
+ } catch(IOException ioex) {
+ System.out.printf("? Error reading configuration from file"
+ + " (reason: %s)\n", ioex.getMessage());
+ }
+ }
+
+ private void doLoadGrammarEntry(String path, String name) {
+ if(path.endsWith(".gram")) {
+ doLoadGrammar(name, path);
+ } else if(path.endsWith(".template")) {
+ System.out.println("Error: Templates are not supported yet");
+ } else if(path.endsWith(".long")) {
+ doLoadLongRule(name, path);
+ } else {
+ System.out.println("Error: Unknown filetype " +
+ path.substring(path.lastIndexOf("."), path.length()));
+ }
+ }
+
+ public void doLoadLongRule(String ruleName, String ruleFile) {
+ ruleName = "[" + ruleName + "]";
+
+ if(debugMode) {
+ System.out.printf("Loading long rule (named %s) from path %s\n",
+ ruleName, ruleFile);
+ }
+
+ try (FileInputStream inputStream = new FileInputStream(ruleFile)) {
+ try (Scanner fle = new Scanner(inputStream)) {
+ IList<IList<String>> ruleParts = new FunctionalList<>();
+
+ while(fle.hasNextLine()) {
+ ruleParts.add(new FunctionalList<>(fle.nextLine().trim().split(" ")));
+ }
+
+ WeightedGrammar<String> longGram = new WeightedGrammar<>();
+
+ longGram.addSpecialRule(ruleName, () -> ruleParts.randItem());
+ longGram.setInitialRule(ruleName);
+
+ exportedRules.put(ruleName, longGram);
+
+ if(debugMode) {
+ System.out.printf("Loaded long rule (named %s) from path %s\n",
+ ruleName, ruleFile);
+ }
+ }
+ } catch (IOException ioex) {
+ System.out.printf("Error reading long rule (%s)\n", ioex.getMessage());
+ }
+ }
+
+ public void doLoadGrammar(String grammarName, String grammarPath) {
+ if(debugMode) {
+ System.out.printf("Loading grammar (named %s) from path %s\n",
+ grammarName, grammarPath);
+ }
+
+ try (FileInputStream inputStream = new FileInputStream(grammarPath)) {
+ WeightedGrammar<String> newGram =
+ ServerGrammarReader.fromStream(inputStream).merge((gram, exports) -> {
+ for(String export : exports.toIterable()) {
+ if(debugMode) {
+ System.out.printf("\tLoaded exported rule %s from grammar %s\n",
+ export, grammarName);
+
+ if(exportedRules.containsKey(export)) {
+ System.out.printf("\tWarning: Exported rule %s from grammar %s" +
+ " shadows a pre-existing rule\n", export, grammarName);
+ }
+ }
+
+ exportedRules.put(export, gram);
+ }
+
+ return gram;
+ });
+
+ loadedGrammars.put(grammarName, newGram);
+ } catch (IOException ioex) {
+ System.out.printf("? Error reading grammar from file"
+ + " (reason: %s)\n", ioex.getMessage());
+ }
+
+ if(debugMode) {
+ System.out.printf("Loaded grammar (named %s) from path %s\n",
+ grammarName, grammarPath);
+ }
+ }
+
+ public void doGenerateExportedRule(String ruleName) {
+ String ruleResult = ListUtils.collapseTokens(
+ exportedRules.get(ruleName)
+ .generateListValues(ruleName, " "));
+
+ System.out.println("Generated Result: ");
+ System.out.println("\t" + ruleResult.replaceAll("\\s+", " "));
+ }
+
+ public void doGenerateGrammar(String currentGram, String ruleName) {
+ doGenerateGrammar(loadedGrammars.get(currentGram), ruleName);
+ }
+
+ public void doGenerateGrammar(WeightedGrammar<String> currentGram, String ruleName) {
+ String ruleResult = ListUtils.collapseTokens(
+ currentGram.generateListValues(ruleName, " "));
+
+ System.out.println("Generated Result: ");
+ System.out.println("\t" + ruleResult.replaceAll("\\s+", " "));
+ }
+
+ public void doShowExportedRules() {
+ System.out.printf("Currently exported rules (%d total):\n",
+ exportedRules.getSize());
+
+ exportedRules.forEachKey(key -> {
+ System.out.println("\t" + key);
+ });
+ }
+
+ public void doShowGrammarRules(String gramName) {
+ WeightedGrammar<String> gram = loadedGrammars.get(gramName);
+
+ IList<String> ruleNames = gram.getRuleNames();
+
+ System.out.printf("Rules for grammar %s (%d total)\n",
+ gramName, ruleNames.getSize());
+
+ ruleNames.forEach(rule -> {
+ System.out.println("\t" + rule);
+ });
+ }
+
+ public void doShowLoadedGrammars() {
+ System.out.printf("Currently loaded grammars (%d total):\n",
+ loadedGrammars.getSize());
+
+ loadedGrammars.forEachKey(key -> {
+ System.out.println("\t" + key);
+ });
+ }
+
+ public void doStressTest(int count) {
+ exportedRules.forEachKey(key -> {
+ doStressTest(key, count);
+ });
+ }
+
+ public void doStressTest(String ruleName, int count) {
+ doStressTest(exportedRules.get(ruleName), ruleName, count);
+ }
+
+ public void doStressTest(WeightedGrammar<String> gram, String ruleName, int count) {
+ if(debugMode) System.out.println("Stress-testing rule " + ruleName);
+
+ IList<String> res = new FunctionalList<>();
+ IList<String> foundTags = new FunctionalList<>();
+
+ boolean foundBroken = false;
+
+ for(int i = 0; i < count; i++) {
+ res = gram.generateListValues(ruleName, " ");
+
+ for(String tok : res.toIterable()) {
+ if(tok.matches("\\[\\S+\\]") && !foundTags.contains(tok)) {
+ System.out.println("\tWarning: Possible un-expanded rule " + tok + " found"
+ + " in expansion of " + ruleName);
+
+ doFindRule(tok);
+
+ foundBroken = true;
+
+ foundTags.add(tok);
+ }
+ }
+ }
+
+ if(debugMode) {
+ if(!foundBroken) System.out.printf("Rule %s succesfully passed stress-testing\n", ruleName);
+ else System.out.printf("Rule %s failed stress-testing\n", ruleName);
+ }
+ }
+
+ private void doFindRule(String ruleName) {
+ loadedGrammars.forEach((gramName, gram) -> {
+ if(gram.hasRule(ruleName)) {
+ System.out.printf("\t\tFound rule %s in grammar %s\n", ruleName, gramName);
+ }
+ });
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/server/ReaderState.java b/RGens/src/main/java/bjc/rgens/server/ReaderState.java
new file mode 100644
index 0000000..3f5021e
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/server/ReaderState.java
@@ -0,0 +1,181 @@
+package bjc.rgens.server;
+
+import java.util.function.Supplier;
+
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.funcdata.IList;
+import bjc.utils.gen.WeightedGrammar;
+
+/**
+ * Represents the internal state of reader
+ *
+ * @author ben
+ *
+ */
+public class ReaderState {
+ private WeightedGrammar<String> currentGrammar;
+ private String currentRule;
+ private boolean isUniform;
+
+ private IList<String> exports;
+
+ /**
+ * Create a new reader state
+ */
+ public ReaderState() {
+ currentGrammar = new WeightedGrammar<>();
+
+ // Grammars start out uniform
+ isUniform = true;
+
+ exports = new FunctionalList<>();
+ }
+
+ public void addExport(String export) {
+ exports.add(export);
+ }
+
+ public IList<String> getExports() {
+ return exports;
+ }
+
+ /**
+ * Get the rule names for the current grammar
+ *
+ * @return The rule names for the current grammar
+ */
+ public IList<String> getRuleNames() {
+ return currentGrammar.getRuleNames();
+ }
+
+ /**
+ * Check if this reader is currently in uniform mode
+ *
+ * @return Whether this grammar is in uniform mode
+ */
+ public boolean isUniform() {
+ return isUniform;
+ }
+
+ /**
+ * Set the current grammar to be the specified one
+ *
+ * @param newWorkingGrammar
+ * The new grammar to use
+ */
+ public void setCurrentGrammar(WeightedGrammar<String> newWorkingGrammar) {
+ currentGrammar = newWorkingGrammar;
+ }
+
+ /**
+ * Set the rule currently being worked on
+ *
+ * @param ruleName
+ * The rule currently being worked on
+ */
+ public void setCurrentRule(String ruleName) {
+ currentRule = ruleName;
+ }
+
+ /**
+ * Set the initial rule of this grammar
+ *
+ * @param ruleName
+ * The initial rule of this grammar
+ */
+ public void setInitialRule(String ruleName) {
+ currentGrammar.setInitialRule(ruleName);
+ }
+
+ /**
+ * Toggle this uniformity setting for this grammar
+ */
+ public void toggleUniformity() {
+ isUniform = !isUniform;
+ }
+
+ /**
+ * Add a case to the current grammar
+ *
+ * @param ruleProbability
+ * The probability for this case to occur
+ * @param ruleParts
+ * The parts that make up this case
+ */
+ public void addCase(int ruleProbability, IList<String> ruleParts) {
+ currentGrammar.addCase(currentRule, ruleProbability, ruleParts);
+ }
+
+ /**
+ * Add a special rule to the grammar
+ *
+ * @param ruleName The name of the special rule
+ * @param cse The special case for the rule
+ */
+ public void addSpecialRule(String ruleName, Supplier<IList<String>> cse) {
+ currentGrammar.addSpecialRule(ruleName, cse);
+ }
+
+ /**
+ * Start editing a new rule in the current grammar
+ *
+ * @param ruleName
+ * The name of the new rule to edit
+ */
+ public void startNewRule(String ruleName) {
+ currentGrammar.addRule(ruleName);
+
+ currentRule = ruleName;
+ }
+
+ /**
+ * Convert this package of state into a weighted grammar
+ *
+ * @return The grammar represented by this state
+ */
+ public WeightedGrammar<String> getGrammar() {
+ return currentGrammar;
+ }
+
+ /**
+ * Prefix a token onto all of the cases for the specified rule
+ *
+ * @param ruleName
+ * The rule to do prefixing on
+ * @param prefixToken
+ * The token to prefix onto each case
+ * @param additionalProbability
+ * The probability modification of the prefixed cases
+ */
+ public void prefixRule(String ruleName, String prefixToken,
+ int additionalProbability) {
+ currentGrammar.prefixRule(ruleName, prefixToken,
+ additionalProbability);
+ }
+
+ /**
+ * Delete a rule from the current grammar
+ *
+ * @param ruleName
+ * The name of the rule to delete
+ */
+ public void deleteRule(String ruleName) {
+ currentGrammar.deleteRule(ruleName);
+ }
+
+ /**
+ * Suffix a token onto all of the cases for the specified rule
+ *
+ * @param ruleName
+ * The rule to do suffixing on
+ * @param suffixToken
+ * The token to suffix onto each case
+ * @param additionalProbability
+ * The probability modification of the suffixed cases
+ */
+ public void suffixRule(String ruleName, String suffixToken,
+ int additionalProbability) {
+ currentGrammar.suffixRule(ruleName, suffixToken,
+ additionalProbability);
+ }
+}
diff --git a/RGens/src/main/java/bjc/rgens/server/ServerGrammarReader.java b/RGens/src/main/java/bjc/rgens/server/ServerGrammarReader.java
new file mode 100644
index 0000000..77b1e8b
--- /dev/null
+++ b/RGens/src/main/java/bjc/rgens/server/ServerGrammarReader.java
@@ -0,0 +1,326 @@
+package bjc.rgens.server;
+
+import com.mifmif.common.regex.Generex;
+
+import java.io.InputStream;
+import java.util.Random;
+import java.util.function.BiFunction;
+import java.util.function.Predicate;
+
+import bjc.utils.data.IPair;
+import bjc.utils.data.Pair;
+import bjc.utils.funcdata.FunctionalStringTokenizer;
+import bjc.utils.funcdata.FunctionalList;
+import bjc.utils.funcdata.FunctionalMap;
+import bjc.utils.funcdata.IList;
+import bjc.utils.funcdata.IMap;
+import bjc.utils.funcutils.ListUtils;
+import bjc.utils.gen.WeightedGrammar;
+import bjc.utils.parserutils.RuleBasedConfigReader;
+
+/**
+ * Read a grammar from a stream
+ *
+ * @author ben
+ *
+ */
+public class ServerGrammarReader {
+ static {
+ setupReader();
+
+ initPragmas();
+ }
+
+ private static RuleBasedConfigReader<ReaderState> reader;
+
+ private static Random numgen = new Random();
+
+ private static IMap<String, WeightedGrammar<String>> exportedRules;
+
+ public static void setExportedRules(IMap<String, WeightedGrammar<String>> rules) {
+ exportedRules = rules;
+ }
+
+ /**
+ * Read a grammar from a stream
+ *
+ * @param inputStream
+ * The stream to load the grammar from
+ *
+ * @return A grammar read from the stream
+ *
+ */
+ public static IPair<WeightedGrammar<String>, IList<String>>
+ fromStream(InputStream inputStream) {
+ ReaderState initialState = new ReaderState();
+
+ WeightedGrammar<String> gram = reader.fromStream(inputStream, initialState).getGrammar();
+
+ IMap<String, IList<String>> vars = new FunctionalMap<>();
+
+ Predicate<String> specialPredicate = (strang) -> {
+ if(strang.matches("\\[\\S+\\]")) {
+ return true;
+ }
+
+ return false;
+ };
+
+ BiFunction<String, WeightedGrammar<String>, IList<String>>
+ specialAction = (strang, gramm) -> {
+ return handleSpecialRule(vars, strang, gramm);
+ };
+
+ gram.configureSpecial(specialPredicate, specialAction);
+
+ IList<String> exports = initialState.getExports();
+
+ if(gram.getInitialRule() != null && !exports.contains(gram.getInitialRule())) {
+ exports.add(gram.getInitialRule());
+ }
+
+ return new Pair<>(gram, exports);
+ }
+
+ private static void initPragmas() {
+ reader.addPragma("debug", (tokenizer, state) -> {
+ debugGrammar(state);
+ });
+
+ reader.addPragma("uniform", (tokenizer, state) -> {
+ state.toggleUniformity();
+ });
+
+ reader.addPragma("initial-rule", ServerGrammarReader::initialRule);
+
+ reader.addPragma("remove-rule", ServerGrammarReader::removeRule);
+
+ reader.addPragma("prefix-with", ServerGrammarReader::prefixRule);
+ reader.addPragma("suffix-with", ServerGrammarReader::suffixRule);
+
+ reader.addPragma("regex-rule", ServerGrammarReader::handleRegexRule);
+
+ reader.addPragma("range-rule", ServerGrammarReader::handleRangeRule);
+
+ reader.addPragma("export-rule", (tokenizer, state) -> {
+ String ruleName = tokenizer.nextToken();
+
+ state.addExport(ruleName);
+ });
+ }
+
+ private static void setupReader() {
+ reader = new RuleBasedConfigReader<>(null, null, null);
+
+ reader.setStartRule((tokenizer, stateTokenPair) -> {
+ stateTokenPair.doWith((initToken, state) -> {
+ state.startNewRule(initToken);
+
+ doCase(tokenizer, state);
+ });
+ });
+
+ reader.setContinueRule((tokenizer, state) -> {
+ doCase(tokenizer, state);
+ });
+
+ reader.setEndRule((tokenizer) -> {
+ tokenizer.setCurrentRule(null);
+ });
+ }
+
+ private static void debugGrammar(ReaderState state) {
+ System.out.println("Printing rule names: ");
+
+ for (String currentRule : state.getRuleNames().toIterable()) {
+ System.out.println("\t" + currentRule);
+ }
+
+ System.out.println();
+ }
+
+ private static IList<String> handleSpecialRule(IMap<String, IList<String>> vars, String strang,
+ WeightedGrammar<String> gramm) {
+ IList<String> retList = new FunctionalList<>();
+
+ if(strang.matches("\\[\\[\\S+\\]\\]")) {
+ if(strang.matches("\\[\\[\\S+:=\\S+\\]\\]")) {
+ doDefineExpandedVariable(vars, strang, gramm);
+ } else if(strang.matches("\\[\\[\\S+=\\S+\\]\\]")) {
+ doDefineVariable(vars, strang);
+ } else if(strang.matches("\\[\\[\\S+\\]\\]")) {
+ if(GrammarServerEngine.debugMode) {
+ if(strang.contains("+"))
+ System.out.println("Double-triggering no-space rule " + strang);
+ else
+ System.out.println("Triggered alternate no-space rule " + strang);
+ }
+
+ doNoSpaceRule(strang, gramm, retList);
+ } else if (strang.contains("+")) {
+ if(GrammarServerEngine.debugMode)
+ System.out.println("Triggered alternate no-space rule " + strang);
+
+ doNoSpaceRule(strang, gramm, retList);
+ } else {
+ // @FIXME notify the user they did something wrong
+ retList.add(strang);
+ }
+ } else {
+ if(strang.matches("\\[\\$\\S+\\-\\S+\\]")) {
+ retList = doExpandVariableReference(vars, strang, gramm);
+ } else if(strang.matches("\\[\\$\\S+\\]")) {
+ String varName = strang.substring(2, strang.length());
+
+ retList = vars.get(varName);
+ } else if (exportedRules.containsKey(strang) &&
+ exportedRules.get(strang) != gramm &&
+ !gramm.hasRule(strang)) {
+ // Only pick external rules if they are both
+ // a) in a different grammar
+ // b) not shadowed in the current grammar
+ WeightedGrammar<String> exportGram = exportedRules.get(strang);
+
+ retList = exportGram.generateGenericValues(strang, (s) -> s, " ");
+ } else if (strang.contains("+")) {
+ doNoSpaceRule(strang, gramm, retList);
+ } else {
+ // @FIXME notify the user they did something wrong
+ retList.add(strang);
+ }
+ }
+
+ return retList;
+ }
+
+ private static void handleRangeRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String ruleName = tokenizer.nextToken();
+
+ int start = Integer.parseInt(tokenizer.nextToken());
+ int end = Integer.parseInt(tokenizer.nextToken());
+
+ state.addSpecialRule(ruleName, () -> {
+ int genNum = numgen.nextInt((end - start) + 1) + start;
+
+ return new FunctionalList<>(Integer.toString(genNum));
+ });
+ }
+
+ private static void handleRegexRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String ruleName = tokenizer.nextToken();
+
+ IList<String> regx = tokenizer.toList();
+ Generex regex = new Generex(ListUtils.collapseTokens(regx));
+
+ state.addSpecialRule(ruleName, () -> {
+ return new FunctionalList<>(regex.random().split(" "));
+ });
+ }
+
+ private static int readOptionalProbability(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ if (state.isUniform()) {
+ return 1;
+ }
+
+ return Integer.parseInt(tokenizer.nextToken());
+ }
+
+ private static void initialRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String initialRuleName = tokenizer.nextToken();
+
+ state.setInitialRule(initialRuleName);
+ }
+
+ private static void prefixRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String ruleName = tokenizer.nextToken();
+ String prefixToken = tokenizer.nextToken();
+
+ int additionalProbability = readOptionalProbability(tokenizer, state);
+
+ state.prefixRule(ruleName, prefixToken, additionalProbability);
+ }
+
+ private static void removeRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String ruleName = tokenizer.nextToken();
+
+ state.deleteRule(ruleName);
+ }
+
+ private static void suffixRule(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ String ruleName = tokenizer.nextToken();
+ String suffixToken = tokenizer.nextToken();
+
+ int additionalProbability = readOptionalProbability(tokenizer, state);
+
+ state.suffixRule(ruleName, suffixToken, additionalProbability);
+ }
+
+ private static void doCase(FunctionalStringTokenizer tokenizer, ReaderState state) {
+ int ruleProbability = readOptionalProbability(tokenizer, state);
+
+ state.addCase(ruleProbability, tokenizer.toList());
+ }
+
+ private static void doDefineExpandedVariable(IMap<String, IList<String>> vars, String strang, WeightedGrammar<String> gramm) {
+ String[] varParts = strang.split(":=");
+
+ String varName = varParts[0].substring(2);
+ String ruleName = varParts[1].substring(0, varParts[1].length() - 2);
+
+ IList<String> varValue = gramm.generateGenericValues(
+ ruleName, (s) -> s, " ");
+
+ vars.put(varName, varValue);
+ }
+
+ private static void doDefineVariable(IMap<String, IList<String>> vars, String strang) {
+ String[] varParts = strang.split("=");
+
+ String varName = varParts[0].substring(2);
+ String varValue = varParts[1].substring(0, varParts[1].length() - 2);
+
+ vars.put(varName, new FunctionalList<>(varValue));
+ }
+
+ private static IList<String> doExpandVariableReference(IMap<String, IList<String>> vars, String strang,
+ WeightedGrammar<String> gramm) {
+ IList<String> retList;
+ String[] varParts = strang.substring(1, strang.length()).split("-");
+
+ StringBuilder actualName = new StringBuilder("[");
+
+ for(String varPart : varParts) {
+ if(varPart.startsWith("$")) {
+ IList<String> varName = vars.get(varPart.substring(1));
+
+ if(varName.getSize() != 1) {
+ // @FIXME notify the user they did something wrong
+ }
+
+ actualName.append(varName.first() + "-");
+ } else {
+ actualName.append(varPart + "-");
+ }
+ }
+
+ // Trim trailing -
+ actualName.deleteCharAt(actualName.length() - 1);
+
+ retList = gramm.generateGenericValues(actualName.toString(), (s) -> s, " ");
+ return retList;
+ }
+
+ private static void doNoSpaceRule(String strang, WeightedGrammar<String> gramm, IList<String> retList) {
+ if(!GrammarServerEngine.debugMode) {
+ IList<String> ruleValue = gramm.generateGenericValues(
+ strang, (s) -> s.trim(), "");
+
+ retList.add(ListUtils.collapseTokens(ruleValue));
+ } else {
+ // if(!gramm.hasRule(strang))
+ // System.out.println("Warning: Possible unexpanded rule " + strang);
+
+ retList.add(strang);
+ }
+ }
+}