diff options
Diffstat (limited to 'clformat/src')
11 files changed, 225 insertions, 25 deletions
diff --git a/clformat/src/main/java/bjc/utils/ioutils/format/CLFormatter.java b/clformat/src/main/java/bjc/utils/ioutils/format/CLFormatter.java index f45b3e8..56c64f6 100644 --- a/clformat/src/main/java/bjc/utils/ioutils/format/CLFormatter.java +++ b/clformat/src/main/java/bjc/utils/ioutils/format/CLFormatter.java @@ -22,6 +22,11 @@ import static bjc.utils.funcutils.IteratorUtils.I; * @author Ben Culkin */ public class CLFormatter { + /** + * Set this to true to enable additional debug output. + */ + public boolean DEBUG; + // Built-in formatting directives private static Map<String, Directive> builtinDirectives; diff --git a/clformat/src/main/java/bjc/utils/ioutils/format/CLParameters.java b/clformat/src/main/java/bjc/utils/ioutils/format/CLParameters.java index 8711a2b..498d9d5 100644 --- a/clformat/src/main/java/bjc/utils/ioutils/format/CLParameters.java +++ b/clformat/src/main/java/bjc/utils/ioutils/format/CLParameters.java @@ -2,7 +2,8 @@ package bjc.utils.ioutils.format; import java.util.*; -import bjc.utils.esodata.*; +import bjc.esodata.AbbrevMap2; +import bjc.utils.esodata.Tape; import bjc.utils.parserutils.*; /** @@ -19,12 +20,19 @@ public class CLParameters { private CLValue[] params; private Set<String> abbrevWords; - private AbbrevMap nameAbbrevs; + private AbbrevMap2 nameAbbrevs; private Map<String, CLValue> namedParams; private Map<String, Integer> nameIndices; /** + * Create a new set of blank CL format parameters. + */ + public CLParameters() { + this(new CLValue[0], new HashMap<>()); + } + + /** * Create a new set of CL format parameters with unnamed values. * * @param params @@ -60,7 +68,7 @@ public class CLParameters { this.nameIndices = new HashMap<>(); abbrevWords = new HashSet<>(); - nameAbbrevs = new AbbrevMap(); + nameAbbrevs = new AbbrevMap2(); refreshAbbrevs(); } @@ -77,14 +85,14 @@ public class CLParameters { if (abbrevWords.contains(key)) continue; abbrevWords.add(key); - nameAbbrevs.addWords(key); + nameAbbrevs.add(key); } for (String key : nameIndices.keySet()) { if (abbrevWords.contains(key)) continue; abbrevWords.add(key); - nameAbbrevs.addWords(key); + nameAbbrevs.add(key); } } @@ -93,7 +101,7 @@ public class CLParameters { if (abbrevWords.contains(key)) return; abbrevWords.add(key); - nameAbbrevs.addWords(key); + nameAbbrevs.add(key); } /** @@ -236,7 +244,8 @@ public class CLParameters { } } - String paramName = param.substring(0, nameIdx); + // Trim off the 'hash' indicator + String paramName = param.substring(1, nameIdx); String paramVal = param.substring(nameIdx + 1); CLValue actVal = parseParam(paramVal); @@ -289,30 +298,31 @@ public class CLParameters { public CLValue resolveKey(String key) { String ucKey = key.toUpperCase(); - if (!abbrevWords.contains(ucKey)) refreshAbbrev(ucKey); - - String[] keys = nameAbbrevs.deabbrev(ucKey); + Set<String> keys = nameAbbrevs.deabbrevAll(ucKey); // We didn't find a parameter that could have been that. Create an appropriate and useful // error message. - if (keys.length > 1) { + if (keys.size() > 1) { StringBuilder sb = new StringBuilder(); sb.append("Ambiguous parameter name \""); sb.append(ucKey); sb.append("\". Could've meant: "); - for (int i = 0; i < keys.length; i++) { + boolean isFirst = true; + for (String possKey : keys) { + if (!isFirst) sb.append(", "); + if (isFirst) isFirst = false; + sb.append("\""); - sb.append(keys[i]); + sb.append(possKey); sb.append("\""); - if (i < keys.length - 1) sb.append(", "); } sb.append("."); throw new IllegalArgumentException(sb.toString()); } - String actKey = keys[0]; + String actKey = keys.iterator().next(); if (namedParams.containsKey(actKey)) { return namedParams.get(actKey); diff --git a/clformat/src/main/java/bjc/utils/ioutils/format/CLPattern.java b/clformat/src/main/java/bjc/utils/ioutils/format/CLPattern.java index 9e697f9..86fbc30 100644 --- a/clformat/src/main/java/bjc/utils/ioutils/format/CLPattern.java +++ b/clformat/src/main/java/bjc/utils/ioutils/format/CLPattern.java @@ -26,7 +26,7 @@ public class CLPattern { static { SimpleProperties props = new SimpleProperties(); - try (InputStream is = CLFormatter.class.getResourceAsStream("/formats.sprop")) { + try (InputStream is = CLFormatter.class.getResourceAsStream("/clformat.sprop")) { props.loadFrom(is, false); } catch (IOException ioex) { // WELP, we failed. Bail diff --git a/clformat/src/main/java/bjc/utils/ioutils/format/CLTokenizer.java b/clformat/src/main/java/bjc/utils/ioutils/format/CLTokenizer.java index 04bbae4..4d5529b 100644 --- a/clformat/src/main/java/bjc/utils/ioutils/format/CLTokenizer.java +++ b/clformat/src/main/java/bjc/utils/ioutils/format/CLTokenizer.java @@ -10,6 +10,8 @@ import java.util.regex.*; * */ public class CLTokenizer implements Iterator<Decree> { + public static boolean DEBUG = false; + /* * Internal class for a tokenizer that returns a specific set of tokens. */ @@ -26,12 +28,16 @@ public class CLTokenizer implements Iterator<Decree> { @Override public boolean hasNext() { - return body.hasNext(); + boolean nxt = body.hasNext(); + + return nxt; } @Override public Decree next() { - return body.next(); + Decree nxt = body.next(); + + return nxt; } } @@ -83,7 +89,9 @@ public class CLTokenizer implements Iterator<Decree> { @Override public boolean hasNext() { - return !mat.hitEnd(); + boolean nxt = !mat.hitEnd(); + + return nxt; } @Override @@ -180,6 +188,7 @@ public class CLTokenizer implements Iterator<Decree> { */ public GroupDecree nextGroup(Decree openedWith, String desiredClosing, String clauseSep) { GroupDecree newGroup = new GroupDecree(); + newGroup.opening = openedWith; if (!hasNext()) throw new NoSuchElementException("No decrees available"); @@ -192,7 +201,6 @@ public class CLTokenizer implements Iterator<Decree> { do { curDecree = next(); - // @TODO handle nesting & such if (curDecree.isLiteral) { curClause.addChild(curDecree); } else if (nestingLevel == 1) { @@ -201,8 +209,13 @@ public class CLTokenizer implements Iterator<Decree> { newGroup.addChild(curClause); newGroup.closing = curDecree; + if (DEBUG) { + System.err.printf("[TRACE] Closing with %s\n", curDecree); + } + break; } else if (clauseSep != null && curDecree.isNamed(clauseSep)) { + if (DEBUG) System.err.printf("[TRACE] Clause separator %s\n", curDecree); curClause.terminator = curDecree; newGroup.addChild(curClause); diff --git a/clformat/src/main/java/bjc/utils/ioutils/format/CLValue.java b/clformat/src/main/java/bjc/utils/ioutils/format/CLValue.java index 1fa440c..30e21d4 100644 --- a/clformat/src/main/java/bjc/utils/ioutils/format/CLValue.java +++ b/clformat/src/main/java/bjc/utils/ioutils/format/CLValue.java @@ -144,6 +144,11 @@ class NullValue implements CLValue { public String getValue(Tape<Object> params) { return null; } + + @Override + public String toString() { + return String.format("NullValue []"); + } } class PercValue implements CLValue { @@ -151,6 +156,11 @@ class PercValue implements CLValue { public String getValue(Tape<Object> params) { return Integer.toString(params.position()); } + + @Override + public String toString() { + return String.format("PercValue []"); + } } class HashValue implements CLValue { @@ -158,6 +168,11 @@ class HashValue implements CLValue { public String getValue(Tape<Object> params) { return (Integer.toString(params.size() - params.position())); } + + @Override + public String toString() { + return String.format("HashValue []"); + } } class VValue implements CLValue { @@ -190,6 +205,11 @@ class VValue implements CLValue { throw new IllegalArgumentException(msg); } } + + @Override + public String toString() { + return String.format("VValue []"); + } } class LiteralValue implements CLValue { @@ -211,7 +231,13 @@ class LiteralValue implements CLValue { * @param params * The parameters passed to the directive. */ + @Override public String getValue(Tape<Object> params) { return val; } + + @Override + public String toString() { + return String.format("LiteralValue [val=%s]", val); + } } diff --git a/clformat/src/main/java/bjc/utils/ioutils/format/ClauseDecree.java b/clformat/src/main/java/bjc/utils/ioutils/format/ClauseDecree.java index 6965634..4188e03 100644 --- a/clformat/src/main/java/bjc/utils/ioutils/format/ClauseDecree.java +++ b/clformat/src/main/java/bjc/utils/ioutils/format/ClauseDecree.java @@ -1,5 +1,8 @@ package bjc.utils.ioutils.format; +import bjc.utils.ioutils.*; + +import java.io.*; import java.util.*; /** @@ -70,6 +73,24 @@ public class ClauseDecree { @Override public String toString() { - return String.format("ClauseDecree [body=%s, terminator=%s]", body, terminator); + try (ReportWriter rw = new ReportWriter()) { + String term = "<null>"; + if (terminator != null) term = terminator.toString(); + + rw.write("ClauseDecree (terminator " + term.toString() + ")"); + rw.indent(); + rw.write("\n"); + + for (Decree kid : body) { + rw.write("Child: " + kid.toString() + "\n"); + } + + rw.dedent(); + + return rw.toString(); + } catch (IOException ioex) { + return "<IOEXCEPTION>"; + } + // return String.format("ClauseDecree [body=%s, terminator=%s]", body, terminator); } } diff --git a/clformat/src/main/java/bjc/utils/ioutils/format/Decree.java b/clformat/src/main/java/bjc/utils/ioutils/format/Decree.java index cefe785..7900f2c 100644 --- a/clformat/src/main/java/bjc/utils/ioutils/format/Decree.java +++ b/clformat/src/main/java/bjc/utils/ioutils/format/Decree.java @@ -124,7 +124,7 @@ public class Decree { @Override public String toString() { - return String.format("Decree [name=%s, isLiteral=%s, isUserCall=%s, parameters=%s, modifiers=%s]", name, + return String.format("Decree [name='%s', isLiteral=%s, isUserCall=%s, parameters=%s, modifiers='%s']", name, isLiteral, isUserCall, parameters, modifiers); } } diff --git a/clformat/src/main/java/bjc/utils/ioutils/format/GroupDecree.java b/clformat/src/main/java/bjc/utils/ioutils/format/GroupDecree.java index cf124bc..b3ae69b 100644 --- a/clformat/src/main/java/bjc/utils/ioutils/format/GroupDecree.java +++ b/clformat/src/main/java/bjc/utils/ioutils/format/GroupDecree.java @@ -1,5 +1,8 @@ package bjc.utils.ioutils.format; +import bjc.utils.ioutils.*; + +import java.io.*; import java.util.*; /** @@ -107,7 +110,29 @@ public class GroupDecree implements Iterable<ClauseDecree> { @Override public String toString() { - return String.format("GroupDecree [opening=%s, closing=%s, body=%s]", opening, closing, body); + try (ReportWriter rw = new ReportWriter()) { + String open = "<null>"; + String close = "<null>"; + + if (opening != null) open = opening.toString(); + if (closing != null) close = closing.toString(); + + rw.write("GroupDecree (opening " + open + ") (closing " + close + ")"); + rw.indent(); + rw.write("\n"); + + int idx = 0; + for (ClauseDecree clause : body) { + rw.write("Clause " + idx++ + ": " + clause.toString() + "\n"); + } + + rw.dedent(); + + return rw.toString(); + } catch (IOException ioex) { + return "<IOEXCEPTION>"; + } + // return String.format("GroupDecree [opening=%s, closing=%s, body=%s]", opening, closing, body); } @Override diff --git a/clformat/src/main/java/bjc/utils/ioutils/format/directives/ConditionalDirective.java b/clformat/src/main/java/bjc/utils/ioutils/format/directives/ConditionalDirective.java index b61eb7b..2eb5e4c 100644 --- a/clformat/src/main/java/bjc/utils/ioutils/format/directives/ConditionalDirective.java +++ b/clformat/src/main/java/bjc/utils/ioutils/format/directives/ConditionalDirective.java @@ -10,8 +10,9 @@ import bjc.utils.ioutils.format.*; /** * Implements the [ directive. * - * This does varying sorts of conditional dispatches on which string to use for formatting, allowing - * it to be based off of general conditions in varying ways. + * This does varying sorts of conditional dispatches on which string to use for + * formatting, allowing it to be based off of general conditions in varying + * ways. * * @author Ben Culkin */ diff --git a/clformat/src/test/java/bjc/utils/test/ioutils/CLFormatterTest.java b/clformat/src/test/java/bjc/utils/test/ioutils/CLFormatterTest.java index ea1b818..09faaa9 100644 --- a/clformat/src/test/java/bjc/utils/test/ioutils/CLFormatterTest.java +++ b/clformat/src/test/java/bjc/utils/test/ioutils/CLFormatterTest.java @@ -99,12 +99,26 @@ public class CLFormatterTest { } @Test + public void testNestLists() { + String fmtStr = "~#[ none~;~A~;~A ~#[ hallo thar ~] ~]"; + + //CLTokenizer.DEBUG = true; + fmt.DEBUG = true; + assertEquals("none", format(fmtStr)); + fmt.DEBUG = false; + //CLTokenizer.DEBUG = false; + } + + //@Test public void testListPrinting() { // Test printing a list // String fmtStr = "Items:~#[ none~; ~A~; ~A and ~A~:;~@{~#[~; and~] ~A~^,~}~]."; String fmtStr = "Items:~#[ none~; ~A~; ~A and ~A~:;~@{~#*[ ~A,~; and ~A~; ~A~]~}~]."; + fmt.DEBUG = true; assertEquals("Items: none.", format(fmtStr)); + fmt.DEBUG = false; + assertEquals("Items: foo.", format(fmtStr, "foo")); assertEquals("Items: foo and bar.", format(fmtStr, "foo", "bar")); assertEquals("Items: foo, bar and baz.", format(fmtStr, "foo", "bar", "baz")); diff --git a/clformat/src/test/java/bjc/utils/test/ioutils/CLParametersTest.java b/clformat/src/test/java/bjc/utils/test/ioutils/CLParametersTest.java new file mode 100644 index 0000000..f065bed --- /dev/null +++ b/clformat/src/test/java/bjc/utils/test/ioutils/CLParametersTest.java @@ -0,0 +1,85 @@ +package bjc.utils.test.ioutils; + +import bjc.utils.esodata.*; +import bjc.utils.ioutils.format.*; + +import org.junit.*; + +import static bjc.utils.ioutils.format.CLParameters.fromDirective; +import static org.junit.Assert.*; + +@SuppressWarnings("javadoc") +public class CLParametersTest { + @Test + public void testBlankParams() { + CLParameters params = new CLParameters(); + + assertEquals("Blank parameters have 0 length", 0, params.length()); + } + + @Test + public void testBasicParsing() { + Tape<Object> scratch = new SingleTape<>(); + + { + CLParameters params = fromDirective(""); + assertEquals("A blank string gives blank parameters", 0, params.length()); + } + + { + CLParameters params = fromDirective("1,2"); + assertEquals("Positionals are counted right", 2, params.length()); + + CLValue val1 = params.getByIndex(0); + CLValue val2 = params.getByIndex(1); + + assertEquals("First integer reads correctly", "1", val1.getValue(scratch)); + assertEquals("Second integer reads correctly", "2", val2.getValue(scratch)); + } + + { + CLParameters params = fromDirective("'a,\"abc\""); + assertEquals("Chars/strings are counted right", 2, params.length()); + + CLValue val1 = params.getByIndex(0); + CLValue val2 = params.getByIndex(1); + + assertEquals("Character reads correctly", "'a", val1.getValue(scratch)); + assertEquals("String reads correctly", "abc", val2.getValue(scratch)); + } + + { + CLParameters params = fromDirective("1,2,3"); + params.mapIndices("arg1","arrg2","arg3"); + + CLValue val1 = params.resolveKey("arg1"); + CLValue val2 = params.resolveKey("arr"); + CLValue val3 = params.resolveKey("arg3"); + + assertNotNull("1st arg not null", val1); + assertNotNull("2nd arg not null", val2); + assertNotNull("3rd arg not null", val3); + + assertEquals("Named parameter works right", "1", val1.getValue(scratch)); + assertEquals("Parameter abbreviation works", "2", val2.getValue(scratch)); + assertEquals("Last named param works", "3", val3.getValue(scratch)); + } + + { + CLParameters params = fromDirective("#arg1:1,#arg2;3,4"); + params.mapIndices("altarg2", "arg3"); + + CLValue val1 = params.resolveKey("arg1"); + CLValue val2 = params.resolveKey("altarg"); + CLValue val3 = params.resolveKey("arg3"); + + assertNotNull("1st arg not null", val1); + assertNotNull("2nd arg not null", val2); + assertNotNull("3rd arg not null", val3); + + assertEquals("Non-indexed name parameters work", "1", val1.getValue(scratch)); + assertEquals("Indexed name parameters work", "3", val2.getValue(scratch)); + assertEquals("Mixed parameters work", "4", val3.getValue(scratch)); + } + } +} |
