summaryrefslogtreecommitdiff
path: root/src/main/java/bjc/rgens/parser/RGrammarSet.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/bjc/rgens/parser/RGrammarSet.java')
-rwxr-xr-xsrc/main/java/bjc/rgens/parser/RGrammarSet.java290
1 files changed, 290 insertions, 0 deletions
diff --git a/src/main/java/bjc/rgens/parser/RGrammarSet.java b/src/main/java/bjc/rgens/parser/RGrammarSet.java
new file mode 100755
index 0000000..975510a
--- /dev/null
+++ b/src/main/java/bjc/rgens/parser/RGrammarSet.java
@@ -0,0 +1,290 @@
+package bjc.rgens.parser;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Scanner;
+import java.util.Set;
+
+/**
+ * Represents a set of grammars that can share rules via exports.
+ *
+ * @author EVE
+ */
+public class RGrammarSet {
+ /* Contains all the grammars in this set. */
+ private Map<String, RGrammar> grammars;
+
+ /* Contains all the exported rules from grammars. */
+ private Map<String, RGrammar> exportedRules;
+
+ /* Contains which export came from which grammar. */
+ private Map<String, String> exportFrom;
+
+ /* Contains which file a grammar was loaded from. */
+ private Map<String, String> loadedFrom;
+
+ /** Create a new set of randomized grammars. */
+ public RGrammarSet() {
+ grammars = new HashMap<>();
+
+ exportedRules = new HashMap<>();
+
+ exportFrom = new HashMap<>();
+ loadedFrom = new HashMap<>();
+ }
+
+ /**
+ * Add a grammar to this grammar set.
+ *
+ * @param grammarName
+ * The name of the grammar to add.
+ *
+ * @param gram
+ * The grammar to add.
+ *
+ * @throws IllegalArgumentException
+ * If the grammar name is invalid.
+ */
+ public void addGrammar(String grammarName, RGrammar gram) {
+ /* Make sure a grammar is valid. */
+ if (grammarName == null) {
+ throw new NullPointerException("Grammar name must not be null");
+ } else if (gram == null) {
+ throw new NullPointerException("Grammar must not be null");
+ } else if (grammarName.equals("")) {
+ throw new IllegalArgumentException("The empty string is not a valid grammar name");
+ }
+
+ grammars.put(grammarName, gram);
+
+ /* Process exports from the grammar. */
+ for (Rule export : gram.getExportedRules()) {
+ exportedRules.put(export.name, gram);
+
+ exportFrom.put(export.name, grammarName);
+ }
+
+ /* Add exports to grammar. */
+ gram.setImportedRules(exportedRules);
+ }
+
+ /**
+ * Get a grammar from this grammar set.
+ *
+ * @param grammarName
+ * The name of the grammar to get.
+ *
+ * @return
+ * The grammar with that name.
+ *
+ * @throws IllegalArgumentException
+ * If the grammar name is invalid or not present in this set.
+ */
+ public RGrammar getGrammar(String grammarName) {
+ /* Check arguments. */
+ if (grammarName == null) {
+ throw new NullPointerException("Grammar name must not be null");
+ } else if (grammarName.equals("")) {
+ throw new IllegalArgumentException("The empty string is not a valid grammar name");
+ } else if (!grammars.containsKey(grammarName)) {
+ String msg = String.format("No grammar with name '%s' found", grammarName);
+
+ throw new IllegalArgumentException(msg);
+ }
+
+ return grammars.get(grammarName);
+ }
+
+ /**
+ * Get the grammar a rule was exported from.
+ *
+ * @param exportName
+ * The name of the exported rule.
+ *
+ * @return
+ * The grammar the exported rule came from.
+ *
+ * @throws IllegalArgumentException
+ * If the export name is invalid or not present in this set.
+ */
+ public RGrammar getExportSource(String exportName) {
+ /* Check arguments. */
+ if (exportName == null) {
+ throw new NullPointerException("Export name must not be null");
+ } else if (exportName.equals("")) {
+ throw new IllegalArgumentException("The empty string is not a valid rule name");
+ } else if (!exportedRules.containsKey(exportName)) {
+ String msg = String.format("No export with name '%s' defined", exportName);
+ throw new IllegalArgumentException(msg);
+ }
+
+ return exportedRules.get(exportName);
+ }
+
+ /**
+ * Get the source of an exported rule.
+ *
+ * This will often be a grammar name, but is not required to be one.
+ *
+ * @param exportName
+ * The name of the exported rule.
+ *
+ * @return
+ * The source of an exported rule.
+ *
+ * @throws IllegalArgumentException
+ * If the exported rule is invalid or not present in this set.
+ */
+ public String exportedFrom(String exportName) {
+ /* Check arguments. */
+ if (exportName == null) {
+ throw new NullPointerException("Export name must not be null");
+ } else if (exportName.equals("")) {
+ throw new IllegalArgumentException("The empty string is not a valid rule name");
+ } else if (!exportedRules.containsKey(exportName)) {
+ String msg = String.format("No export with name '%s' defined", exportName);
+
+ throw new IllegalArgumentException(msg);
+ }
+
+ return exportFrom.getOrDefault(exportName, "Unknown");
+ }
+
+ /**
+ * Get the source of an grammar
+ *
+ * This will often be a file name, but is not required to be one.
+ *
+ * @param grammarName
+ * The name of the exported grammar.
+ *
+ * @return
+ * The source of an exported grammar.
+ *
+ * @throws IllegalArgumentException
+ * If the exported grammar is invalid or not present in this set.
+ */
+ public String loadedFrom(String grammarName) {
+ /* Check arguments. */
+ if (grammarName == null) {
+ throw new NullPointerException("Grammar name must not be null");
+ } else if (grammarName.equals("")) {
+ throw new IllegalArgumentException("The empty string is not a valid grammar name");
+ } else if (grammarName.equals("unknown")) {
+ return grammarName;
+ } else if (!grammars.containsKey(grammarName)) {
+ String msg = String.format("No grammar with name '%s' defined", grammarName);
+ throw new IllegalArgumentException(msg);
+ }
+
+ return loadedFrom.getOrDefault(grammarName, "Unknown");
+ }
+
+ /**
+ * Get the names of all the grammars in this set.
+ *
+ * @return
+ * The names of all the grammars in this set.
+ */
+ public Set<String> getGrammars() {
+ return grammars.keySet();
+ }
+
+ /**
+ * Get the names of all the exported rules in this set.
+ *
+ * @return
+ * The names of all the exported rules in this set.
+ */
+ public Set<String> getExportedRules() {
+ return exportedRules.keySet();
+ }
+
+ /**
+ * Load a grammar set from a configuration file.
+ *
+ * @param cfgFile
+ * The configuration file to load from.
+ *
+ * @return
+ * The grammar set created by the configuration file.
+ *
+ * @throws IOException
+ * If something goes wrong during configuration loading.
+ */
+ public static RGrammarSet fromConfigFile(Path cfgFile) throws IOException {
+ /* The grammar set to hand back. */
+ RGrammarSet set = new RGrammarSet();
+
+ /* Get the directory that contains the config file. */
+ Path cfgParent = cfgFile.getParent();
+
+ try(Scanner scn = new Scanner(cfgFile)) {
+ /* Execute lines from the configuration file. */
+ while (scn.hasNextLine()) {
+ String ln = scn.nextLine().trim();
+
+ /* Ignore blank/comment lines. */
+ if (ln.equals("")) continue;
+
+ if (ln.startsWith("#")) continue;
+
+ /* Handle mixed whitespace. */
+ ln = ln.replaceAll("\\s+", " ");
+
+ /*
+ * Get the place where the name of the grammar
+ * ends.
+ */
+ int nameIdx = ln.indexOf(" ");
+ if (nameIdx == -1) {
+ throw new GrammarException("Must specify a name for a loaded grammar");
+ }
+
+ /* Name and path of grammar. */
+ String name = ln.substring(0, nameIdx);
+ Path path = Paths.get(ln.substring(nameIdx).trim());
+
+ /*
+ * Convert from configuration relative path to
+ * absolute path.
+ */
+ Path convPath = cfgParent.resolve(path.toString());
+
+ //if(Files.isDirectory(convPath)) {
+ // /* @TODO implement subset grammars */
+ // throw new GrammarException("Sub-grammar sets aren't implemented yet");
+ //} else if (convPath.getFileName().endsWith(".gram")) {
+ /* Load grammar file. */
+ try {
+ BufferedReader fis = Files.newBufferedReader(convPath);
+ RGrammar gram = RGrammarParser.readGrammar(fis);
+ fis.close();
+
+ /* Add grammar to the set. */
+ set.addGrammar(name, gram);
+
+ /*
+ * Mark where the grammar came
+ * from.
+ */
+ set.loadedFrom.put(name, path.toString());
+ } catch (GrammarException gex) {
+ String msg = String.format("Error loading file '%s'", path);
+ throw new GrammarException(msg, gex);
+ }
+ //} else {
+ // String msg = String.format("Unrecognized file type '%s'", convPath.getFileName());
+ // throw new GrammarException(msg);
+ //}
+ }
+ }
+
+ return set;
+ }
+}