diff options
| author | Benjamin J. Culkin <bjculkin@mix.wvu.edu> | 2018-06-03 19:27:43 -0300 |
|---|---|---|
| committer | Benjamin J. Culkin <bjculkin@mix.wvu.edu> | 2018-06-03 19:27:43 -0300 |
| commit | a13f1f396d28c0b900a10bede57f30be3a35003a (patch) | |
| tree | 4e358ecff1c794bb8691e985528f5640eefd415e /src/main/java/bjc/rgens | |
| parent | c524f46dbd6a460b7374690244888a001023d3af (diff) | |
Enable multi-prefixing/suffixing
You can now provide multiple prefix/suffix elements, and all of the
permutations of them will be applied.
For example, providing the elements A & B, will yield the following
permutations
* A
* B
* A B
* B A
Diffstat (limited to 'src/main/java/bjc/rgens')
| -rwxr-xr-x | src/main/java/bjc/rgens/parser/RGrammar.java | 2 | ||||
| -rwxr-xr-x | src/main/java/bjc/rgens/parser/RGrammarBuilder.java | 107 | ||||
| -rwxr-xr-x | src/main/java/bjc/rgens/parser/RGrammarParser.java | 24 | ||||
| -rwxr-xr-x | src/main/java/bjc/rgens/parser/RGrammarSet.java | 21 | ||||
| -rwxr-xr-x | src/main/java/bjc/rgens/parser/elements/CaseElement.java | 2 |
5 files changed, 118 insertions, 38 deletions
diff --git a/src/main/java/bjc/rgens/parser/RGrammar.java b/src/main/java/bjc/rgens/parser/RGrammar.java index 4e21279..0c572a7 100755 --- a/src/main/java/bjc/rgens/parser/RGrammar.java +++ b/src/main/java/bjc/rgens/parser/RGrammar.java @@ -208,7 +208,7 @@ public class RGrammar { */ body = body.replaceAll("\\s(ish|burg|ton|ville|opolis|field|boro|dale)", "$1"); - return body; + return body.trim(); } /** diff --git a/src/main/java/bjc/rgens/parser/RGrammarBuilder.java b/src/main/java/bjc/rgens/parser/RGrammarBuilder.java index fc679f1..3aa220a 100755 --- a/src/main/java/bjc/rgens/parser/RGrammarBuilder.java +++ b/src/main/java/bjc/rgens/parser/RGrammarBuilder.java @@ -3,11 +3,16 @@ package bjc.rgens.parser; import bjc.rgens.parser.elements.CaseElement; import bjc.utils.funcdata.FunctionalList; import bjc.utils.funcdata.IList; +import bjc.utils.funcutils.ListUtils; +import bjc.utils.funcutils.SetUtils; import static bjc.rgens.parser.RuleCase.CaseType.*; +import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; +import java.util.LinkedList; import java.util.Map; import java.util.Set; @@ -136,7 +141,7 @@ public class RGrammarBuilder { * If the rule name is either invalid or not defined by this * grammar, or if the suffix is invalid. */ - public void suffixWith(String ruleName, String suffix) { + public void suffixWith(String ruleName, String... suffixes) { if (ruleName == null) { throw new NullPointerException("Rule name must not be null"); } else if (ruleName.equals("")) { @@ -147,19 +152,27 @@ public class RGrammarBuilder { throw new IllegalArgumentException(msg); } - CaseElement element = CaseElement.createElement(suffix); + Set<CaseElement> elements = new HashSet<>(suffixes.length); + for(String suffix : suffixes) { + elements.add(CaseElement.createElement(suffix)); + } + + List<List<CaseElement>> suffixLists = powerList(elements); FunctionalList<RuleCase> newCases = new FunctionalList<>(); IList<RuleCase> caseList = rules.get(ruleName).getCases(); for (RuleCase ruleCase : caseList) { + for(List<CaseElement> suffixList : suffixLists) { FunctionalList<CaseElement> newCase = new FunctionalList<>(); for(CaseElement elm : ruleCase.getElements()) { newCase.add(elm); } - newCase.add(element); + for(CaseElement element : suffixList) { + newCase.add(element); + } /* * @NOTE :AffixCasing @@ -168,6 +181,7 @@ public class RGrammarBuilder { * existing case type? */ newCases.add(new NormalRuleCase(newCase)); + } } @@ -189,7 +203,7 @@ public class RGrammarBuilder { * If the rule name is either invalid or not defined by this * grammar, or if the prefix is invalid. */ - public void prefixWith(String ruleName, String prefix) { + public void prefixWith(String ruleName, String... prefixes) { if (ruleName == null) { throw new NullPointerException("Rule name must not be null"); } else if (ruleName.equals("")) { @@ -200,27 +214,36 @@ public class RGrammarBuilder { throw new IllegalArgumentException(msg); } - CaseElement element = CaseElement.createElement(prefix); + Set<CaseElement> elements = new HashSet<>(prefixes.length); + for(String prefix : prefixes) { + elements.add(CaseElement.createElement(prefix)); + } + + List<List<CaseElement>> prefixLists = powerList(elements); FunctionalList<RuleCase> newCases = new FunctionalList<>(); IList<RuleCase> caseList = rules.get(ruleName).getCases(); for (RuleCase ruleCase : caseList) { - FunctionalList<CaseElement> newCase = new FunctionalList<>(); - - newCase.add(element); - - for(CaseElement elm : ruleCase.getElements()) { - newCase.add(elm); + for(List<CaseElement> prefixList : prefixLists) { + FunctionalList<CaseElement> newCase = new FunctionalList<>(); + + for(CaseElement elm: prefixList) { + newCase.add(elm); + } + + for(CaseElement elm : ruleCase.getElements()) { + newCase.add(elm); + } + + /* + * @NOTE :AffixCasing + * + * Is this correct, or should we be mirroring the + * existing case type? + */ + newCases.add(new NormalRuleCase(newCase)); } - - /* - * @NOTE :AffixCasing - * - * Is this correct, or should we be mirroring the - * existing case type? - */ - newCases.add(new NormalRuleCase(newCase)); } @@ -269,6 +292,52 @@ public class RGrammarBuilder { } rules.get(rule).replaceCases(newCaseList); + } + + private static <T> List<List<T>> powerList(Set<T> elements) { + /* + * Fast-case the most common usage + */ + if(elements.size() == 1) { + List<List<T>> ret = new LinkedList<>(); + + List<T> curr = new ArrayList<>(elements.size()); + for(T elem : elements) { + curr.add(elem); + } + + ret.add(curr); + + return ret; + } + + Set<Set<T>> powerSet = SetUtils.powerSet(elements); + + List<List<T>> list = new LinkedList<>(); + + for(Set<T> set : powerSet) { + /* + * Skip empty sets + */ + if(set.size() == 0) continue; + + List<T> stor = new ArrayList<>(set.size()); + + for(T elm : set) { + stor.add(elm); + } + + for(List<T> permute : ListUtils.permuteList(stor)) { + System.err.printf("\tTRACE: generated permute "); + for(T elm : permute) { + System.err.printf("%s ", elm); + } + System.err.println(); + + list.add(permute); + } + } + return list; } } diff --git a/src/main/java/bjc/rgens/parser/RGrammarParser.java b/src/main/java/bjc/rgens/parser/RGrammarParser.java index 5a09ca8..438688d 100755 --- a/src/main/java/bjc/rgens/parser/RGrammarParser.java +++ b/src/main/java/bjc/rgens/parser/RGrammarParser.java @@ -3,6 +3,8 @@ package bjc.rgens.parser; import bjc.rgens.parser.elements.CaseElement; import bjc.utils.funcdata.FunctionalList; import bjc.utils.funcdata.IList; +import bjc.utils.funcutils.ListUtils; +import bjc.utils.funcutils.SetUtils; import bjc.utils.funcutils.TriConsumer; import bjc.utils.ioutils.blocks.Block; import bjc.utils.ioutils.blocks.BlockReader; @@ -10,8 +12,13 @@ import bjc.utils.ioutils.blocks.SimpleBlockReader; import java.io.Reader; import java.io.StringReader; +import java.util.Arrays; +import java.util.ArrayList; +import java.util.List; +import java.util.LinkedList; import java.util.HashMap; import java.util.Map; +import java.util.Set; /** * Reads {@link RGrammar} from a input stream. @@ -89,25 +96,25 @@ public class RGrammarParser { pragmas.put("suffix-with", (body, build, level) -> { String[] parts = body.trim().split(" "); - if (parts.length != 2) { - String msg = "Suffix-with pragma takes two arguments, the name of the rule to suffix, then what to suffix it with"; + if (parts.length < 2) { + String msg = "Suffix-with pragma takes at least two arguments, the name of the rule to suffix, then what to suffix it with\n\tThis can be more than one token, to get them suffixed as a group"; throw new GrammarException(msg); } - build.suffixWith(parts[0], parts[1]); + build.suffixWith(parts[0], Arrays.copyOfRange(parts, 1, parts.length)); }); pragmas.put("prefix-with", (body, build, level) -> { String[] parts = body.trim().split(" "); - if (parts.length != 2) { - String msg = "Prefix-with pragma takes two arguments, the name of the rule to prefix, then what to prefix it with"; + if (parts.length < 2) { + String msg = "Prefix-with pragma takes at least two arguments, the name of the rule to prefix, then what to prefix it with\n\tThis can be more than one token, to get them prefixed as a group"; throw new GrammarException(msg); } - build.prefixWith(parts[0], parts[1]); + build.prefixWith(parts[0], Arrays.copyOfRange(parts, 1, parts.length)); }); } @@ -175,7 +182,7 @@ public class RGrammarParser { handleRuleBlock(block, build, level); } else if (blockType.equalsIgnoreCase("where")) { handleWhereBlock(block, build, level); - } else if (blockType.equalsIgnoreCase("#")) { + } else if (blockType.startsWith("#")) { if(DEBUG) System.err.printf("Handled comment block (%s)\n", block); /* @@ -353,7 +360,7 @@ public class RGrammarParser { /* Handle a where block (a block with local rules). */ private static void handleWhereBlock(String block, RGrammarBuilder build, int level) throws GrammarException { - int nlIndex = block.indexOf("\\n"); + int nlIndex = block.indexOf("\\nin"); if (nlIndex == -1) { throw new GrammarException("Where block must be a context followed by a body"); @@ -375,6 +382,7 @@ public class RGrammarParser { @SuppressWarnings("unused") Block whereBody = whereReader.next(); + System.err.printf("\tUNIMPLEMENTED WHERE:\n%s\n", whereBody.contents); /** * @TODO 10/11/17 Ben Culkin :WhereBlocks * Implement where blocks. diff --git a/src/main/java/bjc/rgens/parser/RGrammarSet.java b/src/main/java/bjc/rgens/parser/RGrammarSet.java index 975510a..c797b8c 100755 --- a/src/main/java/bjc/rgens/parser/RGrammarSet.java +++ b/src/main/java/bjc/rgens/parser/RGrammarSet.java @@ -7,6 +7,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; +import java.util.TreeMap; import java.util.Scanner; import java.util.Set; @@ -34,7 +35,7 @@ public class RGrammarSet { exportedRules = new HashMap<>(); - exportFrom = new HashMap<>(); + exportFrom = new TreeMap<>(); loadedFrom = new HashMap<>(); } @@ -256,14 +257,16 @@ public class RGrammarSet { */ 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")) { + if(Files.isDirectory(convPath)) { + /* @TODO implement subset grammars */ + throw new GrammarException("Sub-grammar sets aren't implemented yet"); + } else if (convPath.getFileName().toString().endsWith(".gram")) { /* Load grammar file. */ try { + BufferedReader fis = Files.newBufferedReader(convPath); RGrammar gram = RGrammarParser.readGrammar(fis); + fis.close(); /* Add grammar to the set. */ @@ -278,10 +281,10 @@ public class RGrammarSet { 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); - //} + } else { + String msg = String.format("Unrecognized file type '%s'", convPath.getFileName()); + throw new GrammarException(msg); + } } } diff --git a/src/main/java/bjc/rgens/parser/elements/CaseElement.java b/src/main/java/bjc/rgens/parser/elements/CaseElement.java index 54c673f..785ac1a 100755 --- a/src/main/java/bjc/rgens/parser/elements/CaseElement.java +++ b/src/main/java/bjc/rgens/parser/elements/CaseElement.java @@ -85,7 +85,7 @@ public abstract class CaseElement { */ String specialBody = csepart.substring(1, csepart.length() - 1); - System.out.printf("\t\tTRACE: special body is '%s'\n", specialBody); + //System.out.printf("\t\tTRACE: special body is '%s'\n", specialBody); if (specialBody.matches("\\S+:=\\S+")) { /* Handle expanding variable definitions. */ |
