diff options
Diffstat (limited to 'base/src/main/java/bjc/utils/ioutils')
13 files changed, 522 insertions, 186 deletions
diff --git a/base/src/main/java/bjc/utils/ioutils/format/CLFormatter.java b/base/src/main/java/bjc/utils/ioutils/format/CLFormatter.java index 1605a75..9e01ca6 100644 --- a/base/src/main/java/bjc/utils/ioutils/format/CLFormatter.java +++ b/base/src/main/java/bjc/utils/ioutils/format/CLFormatter.java @@ -24,33 +24,33 @@ import static bjc.utils.misc.PropertyDB.getRegex; * */ public class CLFormatter { - private static final String prefixParam = getRegex("clFormatPrefix"); - - private static final String formatMod = getRegex("clFormatModifier"); - - private static final String prefixList = applyFormat("delimSeparatedList", prefixParam, ","); - + private static final String prefixParam = getRegex("clFormatPrefix"); + private static final String formatMod = getRegex("clFormatModifier"); private static final String directiveName = getRegex("clFormatName"); - private static final String formatDirective = applyFormat("clFormatDirective", prefixList, formatMod, - directiveName); + private static final String prefixList = applyFormat("delimSeparatedList", prefixParam, ","); + private static final String formatDirective = applyFormat("clFormatDirective", prefixList, formatMod, directiveName); + private static final Pattern pFormatDirective = Pattern.compile(formatDirective); private static Map<String, Directive> builtinDirectives; - - private Map<String, Directive> extraDirectives; + private Map<String, Directive> extraDirectives; static { builtinDirectives = new HashMap<>(); builtinDirectives.put("A", new AestheticDirective()); + // @NOTE 9/6/18 + // + // This is just an alias, not the actual S directive + builtinDirectives.put("S", new AestheticDirective()); builtinDirectives.put("C", new CharacterDirective()); - builtinDirectives.put("B", new NumberDirective(-1, 2)); - builtinDirectives.put("O", new NumberDirective(-1, 8)); - builtinDirectives.put("D", new NumberDirective(-1, 10)); - builtinDirectives.put("X", new NumberDirective(-1, 16)); + builtinDirectives.put("B", new NumberDirective(-1, 2, 'B')); + builtinDirectives.put("O", new NumberDirective(-1, 8, 'O')); + builtinDirectives.put("D", new NumberDirective(-1, 10, 'D')); + builtinDirectives.put("X", new NumberDirective(-1, 16, 'X')); builtinDirectives.put("R", new RadixDirective()); @@ -58,13 +58,15 @@ public class CLFormatter { builtinDirectives.put("%", new LiteralDirective("\n", '%')); builtinDirectives.put("|", new LiteralDirective("\f", '|')); - builtinDirectives.put("~", new LiteralDirective("~", '~')); + builtinDirectives.put("~", new LiteralDirective("~", '~')); + builtinDirectives.put("?", new RecursiveDirective()); builtinDirectives.put("*", new GotoDirective()); builtinDirectives.put("^", new EscapeDirective()); builtinDirectives.put("[", new ConditionalDirective()); builtinDirectives.put("{", new IterationDirective()); + builtinDirectives.put("(", new CaseDirective()); builtinDirectives.put("T", new TabulateDirective()); } @@ -103,7 +105,7 @@ public class CLFormatter { /* Put the parameters where we can easily handle them. */ Tape<Object> tParams = new SingleTape<>(params); - doFormatString(format, rw, tParams); + doFormatString(format, rw, tParams, true); return rw.toString(); } @@ -123,7 +125,7 @@ public class CLFormatter { /* Put the parameters where we can easily handle them. */ Tape<Object> tParams = new SingleTape<>(params); - doFormatString(format, rw, tParams); + doFormatString(format, rw, tParams, true); return rw.toString(); } @@ -141,7 +143,7 @@ public class CLFormatter { /* Put the parameters where we can easily handle them. */ Tape<Object> tParams = new SingleTape<>(params); - doFormatString(format, rw, tParams); + doFormatString(format, rw, tParams, true); } /** @@ -159,7 +161,7 @@ public class CLFormatter { /* Put the parameters where we can easily handle them. */ Tape<Object> tParams = new SingleTape<>(params); - doFormatString(format, rw, tParams); + doFormatString(format, rw, tParams, true); } /** @@ -175,7 +177,7 @@ public class CLFormatter { * @param tParams * The parameters to use. */ - public void doFormatString(String format, ReportWriter rw, Tape<Object> tParams) throws IOException { + public void doFormatString(String format, ReportWriter rw, Tape<Object> tParams, boolean isToplevel) throws IOException { Matcher dirMatcher = pFormatDirective.matcher(format); // We need this StringBuffer to use appendReplacement and stuff @@ -185,90 +187,96 @@ public class CLFormatter { // ourselves. StringBuffer sb = new StringBuffer(); - while(dirMatcher.find()) { - dirMatcher.appendReplacement(sb, ""); - rw.writeBuffer(sb); - - String dirName = dirMatcher.group("name"); - String dirFunc = dirMatcher.group("funcname"); - String dirMods = dirMatcher.group("modifiers"); - String dirParams = dirMatcher.group("params"); - - if(dirMods == null) dirMods = ""; - if(dirParams == null) dirParams = ""; - - String[] splitPars = dirParams.split("(?<!'),"); - CLParameters arrParams = CLParameters.fromDirective(splitPars, tParams); - - CLModifiers mods = CLModifiers.fromString(dirMods); - - Object item = tParams.item(); - if(dirName == null && dirFunc != null) { - /* - * @TODO implement user-called functions. - */ - continue; - } - - if(extraDirectives.containsKey(dirName)) { - extraDirectives.get(dirName).format(rw, item, mods, arrParams, tParams, dirMatcher, - this); - - continue; + boolean doTail = true; + try { + while(dirMatcher.find()) { + dirMatcher.appendReplacement(sb, ""); + rw.writeBuffer(sb); + + String dirName = dirMatcher.group("name"); + String dirFunc = dirMatcher.group("funcname"); + String dirMods = dirMatcher.group("modifiers"); + String dirParams = dirMatcher.group("params"); + + if(dirMods == null) dirMods = ""; + if(dirParams == null) dirParams = ""; + + CLParameters arrParams = CLParameters.fromDirective(dirParams, tParams); + + CLModifiers mods = CLModifiers.fromString(dirMods); + + Object item = tParams.item(); + + if(dirName == null && dirFunc != null) { + /* + * @TODO implement user-called functions. + */ + continue; + } + + if(extraDirectives.containsKey(dirName)) { + extraDirectives.get(dirName).format(rw, item, mods, arrParams, tParams, dirMatcher, + this); + + continue; + } + + if(builtinDirectives.containsKey(dirName)) { + // System.err.printf("Executing directive %s (%s) (%d to %d) from string %s\n", dirName, dirMatcher.group(), dirMatcher.start(), dirMatcher.end(), format); + + builtinDirectives.get(dirName).format(rw, + item, mods, arrParams, tParams, dirMatcher, this); + + continue; + } + + if(dirName == null) dirName = "<null>"; + + switch(dirName) { + case "]": + throw new IllegalArgumentException("Found conditional-end outside of conditional."); + case ";": + throw new IllegalArgumentException( + "Found seperator outside of block."); + case "}": + throw new IllegalArgumentException("Found iteration-end outside of iteration"); + case "<": + case ">": + throw new IllegalArgumentException("Layout-control directives aren't implemented yet."); + case "F": + case "E": + case "G": + case "$": + /* @TODO implement floating point directives. */ + throw new IllegalArgumentException("Floating-point directives aren't implemented yet."); + case "W": + /* + * @TODO figure out if we want to implement + * someting for these directives instead of + * punting. + */ + throw new IllegalArgumentException("S and W aren't implemented. Use A instead"); + case "P": + throw new IllegalArgumentException("These directives aren't implemented yet"); + case ")": + throw new IllegalArgumentException("Case-conversion end outside of case conversion"); + case "\n": + /* + * Ignored newline. + */ + break; + default: + String msg = String.format("Unknown format directive '%s'", dirName); + throw new IllegalArgumentException(msg); + } } + } catch (EscapeException eex) { + if (!isToplevel) throw eex; - if(builtinDirectives.containsKey(dirName)) { - builtinDirectives.get(dirName).format(rw, item, mods, arrParams, tParams, dirMatcher, - this); - - continue; - } - - if(dirName == null) dirName = "<null>"; - - switch(dirName) { - case "]": - throw new IllegalArgumentException("Found conditional-end outside of conditional."); - case ";": - throw new IllegalArgumentException( - "Found seperator outside of block."); - case "}": - throw new IllegalArgumentException("Found iteration-end outside of iteration"); - case "<": - case ">": - throw new IllegalArgumentException("Layout-control directives aren't implemented yet."); - case "F": - case "E": - case "G": - case "$": - /* @TODO implement floating point directives. */ - throw new IllegalArgumentException("Floating-point directives aren't implemented yet."); - case "S": - case "W": - /* - * @TODO figure out if we want to implement - * someting for these directives instead of - * punting. - */ - throw new IllegalArgumentException("S and W aren't implemented. Use A instead"); - case "?": - case "(": - case "P": - throw new IllegalArgumentException("These directives aren't implemented yet"); - case ")": - throw new IllegalArgumentException("Case-conversion end outside of case conversion"); - case "\n": - /* - * Ignored newline. - */ - break; - default: - String msg = String.format("Unknown format directive '%s'", dirName); - throw new UnknownFormatConversionException(msg); - } + doTail = false; } - dirMatcher.appendTail(sb); + if (doTail) dirMatcher.appendTail(sb); rw.writeBuffer(sb); } } diff --git a/base/src/main/java/bjc/utils/ioutils/format/CLModifiers.java b/base/src/main/java/bjc/utils/ioutils/format/CLModifiers.java index 0625ff8..68127b6 100644 --- a/base/src/main/java/bjc/utils/ioutils/format/CLModifiers.java +++ b/base/src/main/java/bjc/utils/ioutils/format/CLModifiers.java @@ -15,6 +15,14 @@ public class CLModifiers { * Whether the colon mod is on. */ public final boolean colonMod; + /** + * Whether the dollar mod is on. + */ + public final boolean dollarMod; + /** + * Whether the star mod is on. + */ + public final boolean starMod; /** * Create a new set of CL modifiers. @@ -23,10 +31,14 @@ public class CLModifiers { * The state of the at mod. * @param colon * The state of the colon mod. + * @param dollar + * The state of the dollar mod. */ - public CLModifiers(boolean at, boolean colon) { - atMod = at; - colonMod = colon; + public CLModifiers(boolean at, boolean colon, boolean dollar, boolean star) { + atMod = at; + colonMod = colon; + dollarMod = dollar; + starMod = star; } /** @@ -37,13 +49,18 @@ public class CLModifiers { * @return A set of modifiers matching the string. */ public static CLModifiers fromString(String modString) { - boolean atMod = false; - boolean colonMod = false; + boolean atMod = false; + boolean colonMod = false; + boolean dollarMod = false; + boolean starMod = false; + if(modString != null) { - atMod = modString.contains("@"); - colonMod = modString.contains(":"); + atMod = modString.contains("@"); + colonMod = modString.contains(":"); + dollarMod = modString.contains("$"); + starMod = modString.contains("*"); } - return new CLModifiers(atMod, colonMod); + return new CLModifiers(atMod, colonMod, dollarMod, starMod); } -}
\ No newline at end of file +} diff --git a/base/src/main/java/bjc/utils/ioutils/format/CLParameters.java b/base/src/main/java/bjc/utils/ioutils/format/CLParameters.java index 2588446..bde7a7d 100644 --- a/base/src/main/java/bjc/utils/ioutils/format/CLParameters.java +++ b/base/src/main/java/bjc/utils/ioutils/format/CLParameters.java @@ -44,10 +44,33 @@ public class CLParameters { * * @return A set of CL parameters. */ - public static CLParameters fromDirective(String[] params, Tape<Object> dirParams) { + public static CLParameters fromDirective(String unsplit, Tape<Object> dirParams) { + List<String> lParams = new ArrayList<>(); + StringBuilder currParm = new StringBuilder(); + + char prevChar = ' '; + + for (int i = 0; i < unsplit.length(); i++) { + char c = unsplit.charAt(i); + + if (c == ',' && prevChar != '\'') { + lParams.add(currParm.toString()); + + currParm = new StringBuilder(); + } else { + currParm.append(c); + } + + prevChar = c; + } + lParams.add(currParm.toString()); + List<String> parameters = new ArrayList<>(); - for(String param : params) { + if (lParams.size() == 1 && lParams.get(0).equals("")) + return new CLParameters(parameters.toArray(new String[0])); + + for(String param : lParams) { if(param.equalsIgnoreCase("V")) { Object par = dirParams.item(); boolean succ = dirParams.right(); @@ -73,7 +96,9 @@ public class CLParameters { throw new IllegalArgumentException( "Incorrect type of parameter for V inline parameter"); } - } else if(param.equals("#")) { + } else if (param.equals("#")) { + parameters.add(Integer.toString(dirParams.size() - dirParams.position())); + } else if (param.equals("%")) { parameters.add(Integer.toString(dirParams.position())); } else { parameters.add(param); @@ -119,9 +144,14 @@ public class CLParameters { public char getChar(int idx, String paramName, char directive) { String param = params[idx]; + if (param.length() == 1) { + // Punt in the case we have a slightly malformed issue + return param.charAt(0); + } + if(!param.startsWith("'")) { throw new IllegalArgumentException( - String.format("Invalid %s %s to %c directive", paramName, param, directive)); + String.format("Invalid %s \"%s\" to %c directive", paramName, param, directive)); } return param.charAt(1); @@ -166,7 +196,7 @@ public class CLParameters { try { return Integer.parseInt(param); } catch(NumberFormatException nfex) { - String msg = String.format("Invalid %s %s to %c directive", paramName, param, directive); + String msg = String.format("Invalid %s \"%s\" to %c directive", paramName, param, directive); IllegalArgumentException iaex = new IllegalArgumentException(msg); iaex.initCause(nfex); @@ -174,4 +204,21 @@ public class CLParameters { throw iaex; } } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder("["); + + for (int i = 0; i < params.length; i++) { + if (i != 0) sb.append(", "); + + sb.append("\""); + sb.append(params[i]); + sb.append("\""); + } + + sb.append("]"); + + return sb.toString(); + } } diff --git a/base/src/main/java/bjc/utils/ioutils/format/directives/AestheticDirective.java b/base/src/main/java/bjc/utils/ioutils/format/directives/AestheticDirective.java index 4276f40..9bad6d7 100644 --- a/base/src/main/java/bjc/utils/ioutils/format/directives/AestheticDirective.java +++ b/base/src/main/java/bjc/utils/ioutils/format/directives/AestheticDirective.java @@ -21,6 +21,7 @@ public class AestheticDirective implements Directive { @Override public void format(ReportWriter rw, Object item, CLModifiers mods, CLParameters params, Tape<Object> tParams, Matcher dirMatcher, CLFormatter fmt) throws IOException { + // System.err.printf("Aesthetic directive with item \"%s\" and params: %s\n", item, tParams); CLFormatter.checkItem(item, 'A'); int mincol = 0, colinc = 1, minpad = 0; diff --git a/base/src/main/java/bjc/utils/ioutils/format/directives/CaseDirective.java b/base/src/main/java/bjc/utils/ioutils/format/directives/CaseDirective.java new file mode 100644 index 0000000..728bb43 --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/format/directives/CaseDirective.java @@ -0,0 +1,117 @@ + +package bjc.utils.ioutils.format.directives; + +import bjc.utils.esodata.Tape; +import bjc.utils.ioutils.format.*; +import bjc.utils.ioutils.ReportWriter; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.IllegalFormatConversionException; +import java.util.List; +import java.util.logging.Logger; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class CaseDirective implements Directive { + private static final Pattern wordPattern = Pattern.compile("(\\w+)(\\b*)"); + + @Override + public void format(ReportWriter rw, Object item, CLModifiers mods, CLParameters params, Tape<Object> tParams, + Matcher dirMatcher, CLFormatter fmt) throws IOException { + StringBuffer condBody = new StringBuffer(); + + int nestLevel = 1; + + while (dirMatcher.find()) { + /* Process a list of clauses. */ + String dirName = dirMatcher.group("name"); + + if (dirName != null) { + /* Append everything up to this directive. */ + dirMatcher.appendReplacement(condBody, ""); + + if (dirName.equals("(")) { + if (nestLevel > 0) { + condBody.append(dirMatcher.group()); + } + + nestLevel += 1; + } else if (Directive.isOpening(dirName)) { + nestLevel += 1; + + condBody.append(dirMatcher.group()); + } else if (dirName.equals(")")) { + nestLevel = Math.max(0, nestLevel - 1); + + /* End the iteration. */ + if (nestLevel == 0) break; + } else if (Directive.isClosing(dirName)) { + nestLevel = Math.max(0, nestLevel - 1); + } else { + /* Not a special directive. */ + condBody.append(dirMatcher.group()); + } + } + } + + String frmt = condBody.toString(); + + ReportWriter nrw = rw.duplicate(new StringWriter()); + + fmt.doFormatString(frmt, nrw, tParams, false); + + String strang = nrw.toString(); + + if (mods.colonMod && mods.atMod) { + strang = strang.toUpperCase(); + } else if (mods.colonMod) { + Matcher mat = wordPattern.matcher(strang); + + StringBuffer sb = new StringBuffer(); + while(!mat.find()) { + mat.appendReplacement(sb, ""); + + String word = mat.group(1); + + word = word.substring(0, 1).toUpperCase() + word.substring(1); + + sb.append(word); + sb.append(mat.group(2)); + } + + mat.appendTail(sb); + + strang = sb.toString(); + } else if (mods.atMod) { + Matcher mat = wordPattern.matcher(strang); + + StringBuffer sb = new StringBuffer(); + boolean doCap = true; + while(!mat.find()) { + mat.appendReplacement(sb, ""); + + String word = mat.group(1); + + if (doCap) { + doCap = false; + + word = word.substring(0, 1).toUpperCase() + word.substring(1); + } + + sb.append(word); + sb.append(mat.group(2)); + } + + mat.appendTail(sb); + + strang = sb.toString(); + + } else { + strang = strang.toLowerCase(); + } + + rw.write(strang); + } +} diff --git a/base/src/main/java/bjc/utils/ioutils/format/directives/ConditionalDirective.java b/base/src/main/java/bjc/utils/ioutils/format/directives/ConditionalDirective.java index 71d9e7d..ed0b39b 100644 --- a/base/src/main/java/bjc/utils/ioutils/format/directives/ConditionalDirective.java +++ b/base/src/main/java/bjc/utils/ioutils/format/directives/ConditionalDirective.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.IllegalFormatConversionException; import java.util.List; +import java.util.logging.Logger; import java.util.regex.Matcher; /** @@ -17,6 +18,7 @@ import java.util.regex.Matcher; * */ public class ConditionalDirective implements Directive { + private static Logger LOG = Logger.getLogger(ConditionalDirective.class.getName()); @Override public void format(ReportWriter rw, Object item, CLModifiers mods, CLParameters arrParams, @@ -24,42 +26,75 @@ public class ConditionalDirective implements Directive { StringBuffer condBody = new StringBuffer(); List<String> clauses = new ArrayList<>(); - String defClause = null; + + String defClause = null; boolean isDefault = false; + int nestLevel = 1; + while (dirMatcher.find()) { /* Process a list of clauses. */ String dirName = dirMatcher.group("name"); String dirMods = dirMatcher.group("modifiers"); + //System.err.printf("Found conditional directive %s with %s mods and level %d\n", dirName, dirMods, nestLevel); if (dirName != null) { /* Append everything up to this directive. */ dirMatcher.appendReplacement(condBody, ""); - if (dirName.equals("]")) { - /* End the conditional. */ - String clause = condBody.toString(); - if (isDefault) { - defClause = clause; - } else { + if (dirName.equals("[")) { + if (nestLevel > 0) { + condBody.append(dirMatcher.group()); + } + nestLevel += 1; + } else if (Directive.isOpening(dirName)) { + nestLevel += 1; + + condBody.append(dirMatcher.group()); + } else if (dirName.equals("]")) { + nestLevel = Math.max(0, nestLevel - 1); + + if (nestLevel == 0) { + /* End the conditional. */ + String clause = condBody.toString(); + // System.err.printf("Found clause \"%s]\"\n", clause); + condBody = new StringBuffer(); + + if (isDefault) { + defClause = clause; + } clauses.add(clause); + + break; + } else { + /* Not a special directive. */ + condBody.append(dirMatcher.group()); } + } else if (Directive.isClosing(dirName)) { + nestLevel = Math.max(0, nestLevel - 1); - break; + condBody.append(dirMatcher.group()); } else if (dirName.equals(";")) { - /* End the clause. */ - String clause = condBody.toString(); - if (isDefault) { - defClause = clause; - } else { + if (nestLevel == 1) { + /* End the clause. */ + String clause = condBody.toString(); + // System.err.printf("Found clause \"%s;\"\n", clause); + condBody = new StringBuffer(); + + if (isDefault) { + defClause = clause; + } clauses.add(clause); - } - /* - * Mark the next clause as the default. - */ - if (dirMods.contains(":")) { - isDefault = true; + /* + * Mark the next clause as the default. + */ + if (dirMods.contains(":")) { + isDefault = true; + } + } else { + /* Not a special directive. */ + condBody.append(dirMatcher.group()); } } else { /* Not a special directive. */ @@ -67,18 +102,21 @@ public class ConditionalDirective implements Directive { } } } + + if (mods.starMod && clauses.size() > 0) defClause = clauses.get(0); - Object par = formatParams.item(); try { if (mods.colonMod) { formatParams.right(); - if (par == null) { - throw new IllegalArgumentException("No parameter provided for [ directive."); - } else if (!(par instanceof Boolean)) { - throw new IllegalFormatConversionException('[', par.getClass()); + boolean res = false; + if (item == null) { + //throw new IllegalArgumentException("No parameter provided for [ directive."); + } else if (!(item instanceof Boolean)) { + throw new IllegalFormatConversionException('[', item.getClass()); + } else { + res = (Boolean) item; } - boolean res = (Boolean) par; String frmt; if (res) @@ -86,17 +124,21 @@ public class ConditionalDirective implements Directive { else frmt = clauses.get(0); - fmt.doFormatString(frmt, rw, formatParams); + fmt.doFormatString(frmt, rw, formatParams, false); } else if (mods.atMod) { - if (par == null) { - throw new IllegalArgumentException("No parameter provided for [ directive."); - } else if (!(par instanceof Boolean)) { - throw new IllegalFormatConversionException('[', par.getClass()); + boolean res = false; + if (item == null) { + // throw new IllegalArgumentException("No parameter provided for [ directive."); + } else if (item instanceof Integer) { + if ((Integer)item != 0) res = true; + } else if (item instanceof Boolean) { + res = (Boolean) item; + } else { + throw new IllegalFormatConversionException('[', item.getClass()); } - boolean res = (Boolean) par; if (res) { - fmt.doFormatString(clauses.get(0), rw, formatParams); + fmt.doFormatString(clauses.get(0), rw, formatParams, false); } else { formatParams.right(); } @@ -105,21 +147,33 @@ public class ConditionalDirective implements Directive { if (arrParams.length() >= 1) { res = arrParams.getInt(0, "conditional choice", '['); } else { - if (par == null) { + if (item == null) { throw new IllegalArgumentException("No parameter provided for [ directive."); - } else if (!(par instanceof Number)) { - throw new IllegalFormatConversionException('[', par.getClass()); + } else if (!(item instanceof Number)) { + throw new IllegalFormatConversionException('[', item.getClass()); } - res = ((Number) par).intValue(); + res = ((Number) item).intValue(); formatParams.right(); } - if (res < 0 || res > clauses.size()) { - if (defClause != null) - fmt.doFormatString(defClause, rw, formatParams); + if (mods.dollarMod) res -= 1; + + // System.err.printf("Attempting selection of clause %d of %d (%s) (default %s)\n", + // res, clauses.size(), clauses, defClause); + if (clauses.size() == 0 || res < 0 || res >= clauses.size()) { + // System.err.printf("Selecting default clause (res %d, max %d): %s\n", res, clauses.size(), defClause); + // int clauseNo = 0; + // for (String clause : clauses) { + // System.err.printf("... clause %d: %s\n", ++clauseNo, clause); + // } + + if (defClause != null) fmt.doFormatString(defClause, rw, formatParams, false); } else { - fmt.doFormatString(clauses.get(res), rw, formatParams); + String frmt = clauses.get(res); + + // System.out.printf("Selecting clause %d of %d (params %s): %s\n", res, clauses.size(), formatParams, frmt); + fmt.doFormatString(frmt, rw, formatParams, false); } } } catch (EscapeException eex) { diff --git a/base/src/main/java/bjc/utils/ioutils/format/directives/Directive.java b/base/src/main/java/bjc/utils/ioutils/format/directives/Directive.java index ad9c34c..61abfc1 100644 --- a/base/src/main/java/bjc/utils/ioutils/format/directives/Directive.java +++ b/base/src/main/java/bjc/utils/ioutils/format/directives/Directive.java @@ -37,4 +37,36 @@ public interface Directive { */ public void format(ReportWriter rw, Object item, CLModifiers mods, CLParameters arrParams, Tape<Object> tParams, Matcher dirMatcher, CLFormatter fmt) throws IOException; + + public static boolean isOpening(String str) { + return isOpening(str.charAt(0)); + } + + public static boolean isOpening(char dir) { + switch(dir) { + case '(': + case '<': + case '[': + case '{': + return true; + default: + return false; + } + } + + public static boolean isClosing(String str) { + return isClosing(str.charAt(0)); + } + + public static boolean isClosing(char dir) { + switch(dir) { + case ')': + case '>': + case ']': + case '}': + return true; + default: + return false; + } + } } diff --git a/base/src/main/java/bjc/utils/ioutils/format/directives/EscapeDirective.java b/base/src/main/java/bjc/utils/ioutils/format/directives/EscapeDirective.java index 5badff0..74488ed 100644 --- a/base/src/main/java/bjc/utils/ioutils/format/directives/EscapeDirective.java +++ b/base/src/main/java/bjc/utils/ioutils/format/directives/EscapeDirective.java @@ -21,28 +21,35 @@ public class EscapeDirective implements Directive { Tape<Object> formatParams, Matcher dirMatcher, CLFormatter fmt) { boolean shouldExit; + if (mods.dollarMod) formatParams.right(); + switch(params.length()) { case 0: - shouldExit = formatParams.size() == 0; + shouldExit = formatParams.atEnd(); break; case 1: int num = params.getInt(0, "condition count", '^'); + shouldExit = num == 0; break; case 2: - int left = params.getInt(0, "left-hand condition", '^'); + int left = params.getInt(0, "left-hand condition", '^'); int right = params.getInt(1, "right-hand condition", '^'); + shouldExit = left == right; break; case 3: default: - int low = params.getInt(0, "lower-bound condition", '^'); - int mid = params.getInt(1, "interval condition", '^'); + int low = params.getInt(0, "lower-bound condition", '^'); + int mid = params.getInt(1, "interval condition", '^'); int high = params.getInt(2, "upper-bound condition", '^'); + shouldExit = (low <= mid) && (mid <= high); break; } + if (mods.dollarMod) formatParams.left(); + /* At negates it. */ if(mods.atMod) shouldExit = !shouldExit; diff --git a/base/src/main/java/bjc/utils/ioutils/format/directives/GeneralNumberDirective.java b/base/src/main/java/bjc/utils/ioutils/format/directives/GeneralNumberDirective.java index ccf01d8..3eb741e 100644 --- a/base/src/main/java/bjc/utils/ioutils/format/directives/GeneralNumberDirective.java +++ b/base/src/main/java/bjc/utils/ioutils/format/directives/GeneralNumberDirective.java @@ -38,10 +38,10 @@ public abstract class GeneralNumberDirective implements Directive { */ int commaInterval = 0; char commaChar = ','; - if (params.length() >= (argidx + 3)) { - commaChar = params.getCharDefault((argidx + 3), "comma character", 'R', ' '); - } if (params.length() >= (argidx + 4)) { + commaChar = params.getCharDefault((argidx + 3), "comma character", 'R', ','); + } + if (params.length() >= (argidx + 5)) { commaInterval = params.getIntDefault((argidx + 4), "comma interval", 'R', 0); } diff --git a/base/src/main/java/bjc/utils/ioutils/format/directives/IterationDirective.java b/base/src/main/java/bjc/utils/ioutils/format/directives/IterationDirective.java index 97e392e..2ce6309 100644 --- a/base/src/main/java/bjc/utils/ioutils/format/directives/IterationDirective.java +++ b/base/src/main/java/bjc/utils/ioutils/format/directives/IterationDirective.java @@ -36,18 +36,18 @@ public class IterationDirective implements Directive { dirMatcher.appendReplacement(condBody, ""); if (dirName.equals("}")) { - /* End the iteration. */ break; + } else { + /* Not a special directive. */ + condBody.append(dirMatcher.group()); } - - /* Not a special directive. */ - condBody.append(dirMatcher.group()); } } String frmt = condBody.toString(); Object iter = item; + // System.err.printf("Iteration format \"%s\" (iter %s)\n", frmt, item); if (frmt.equals("")) { /* Grab an argument. */ if (!(item instanceof String)) { @@ -86,25 +86,29 @@ public class IterationDirective implements Directive { Tape<Object> nParams = new SingleTape<>(nitr); try { - fmt.doFormatString(frmt, rw, nParams); + fmt.doFormatString(frmt, rw, nParams, false); } catch (EscapeException eex) { if (eex.endIteration) { - if (tParams.atEnd()) throw eex; + if (tParams.atEnd()) { + throw eex; + } } } - iter = tParams.right(); + tParams.right(); + iter = tParams.item(); } while (tParams.position() < tParams.size()); } catch (EscapeException eex) { } } else if (mods.atMod) { try { - while (tParams.position() < tParams.size()) { - if (numItr > maxItr) break; - numItr += 1; + while (!tParams.atEnd()) { + // System.err.printf("Iterating with format \"%s\"\n", frmt); + if (numItr > maxItr) break; + numItr += 1; - fmt.doFormatString(frmt, rw, tParams); - } + fmt.doFormatString(frmt, rw, tParams, false); + } } catch (EscapeException eex) { if (eex.endIteration) throw new UnsupportedOperationException("Colon mod not allowed on escape marker without colon mod on iteration"); @@ -133,13 +137,12 @@ public class IterationDirective implements Directive { Tape<Object> nParams = new SingleTape<>(nitr); try { - fmt.doFormatString(frmt, rw, nParams); + fmt.doFormatString(frmt, rw, nParams, false); } catch (EscapeException eex) { if(eex.endIteration && !itr.hasNext()) throw eex; } } - } - catch (EscapeException eex) { + } catch (EscapeException eex) { } } else { if (!(item instanceof Iterable<?>)) { @@ -149,16 +152,13 @@ public class IterationDirective implements Directive { try { @SuppressWarnings("unchecked") Iterable<Object> itr = (Iterable<Object>) item; - Tape<Object> nParams = new SingleTape<>(itr); - while (nParams.position() < nParams.size()) { - if (numItr > maxItr) - break; + while (!nParams.atEnd()) { + if (numItr > maxItr) break; numItr += 1; - fmt.doFormatString(frmt, rw, nParams); - + fmt.doFormatString(frmt, rw, nParams, false); } } catch (EscapeException eex) { if (eex.endIteration) diff --git a/base/src/main/java/bjc/utils/ioutils/format/directives/NumberDirective.java b/base/src/main/java/bjc/utils/ioutils/format/directives/NumberDirective.java index 763665d..88b3e7e 100644 --- a/base/src/main/java/bjc/utils/ioutils/format/directives/NumberDirective.java +++ b/base/src/main/java/bjc/utils/ioutils/format/directives/NumberDirective.java @@ -26,21 +26,25 @@ public class NumberDirective extends GeneralNumberDirective { * @param radix * The radix of the number to use. */ - public NumberDirective(int argidx, int radix) { + public NumberDirective(int argidx, int radix, char directive) { this.argidx = argidx; this.radix = radix; + + this.directive = directive; } private int argidx; private int radix; + private char directive; + @Override public void format(ReportWriter rw, Object item, CLModifiers mods, CLParameters params, Tape<Object> tParams, Matcher dirMatcher, CLFormatter fmt) throws IOException { - CLFormatter.checkItem(item, 'B'); + CLFormatter.checkItem(item, directive); if (!(item instanceof Number)) { - throw new IllegalFormatConversionException('B', item.getClass()); + throw new IllegalFormatConversionException(directive, item.getClass()); } long val = ((Number) item).longValue(); diff --git a/base/src/main/java/bjc/utils/ioutils/format/directives/RecursiveDirective.java b/base/src/main/java/bjc/utils/ioutils/format/directives/RecursiveDirective.java new file mode 100644 index 0000000..44a25ad --- /dev/null +++ b/base/src/main/java/bjc/utils/ioutils/format/directives/RecursiveDirective.java @@ -0,0 +1,49 @@ +package bjc.utils.ioutils.format.directives; + +import bjc.utils.esodata.SingleTape; +import bjc.utils.esodata.Tape; +import bjc.utils.ioutils.format.*; +import bjc.utils.ioutils.ReportWriter; +import java.util.IllegalFormatConversionException; + +import java.io.IOException; +import java.util.regex.Matcher; + +public class RecursiveDirective implements Directive { + public void format(ReportWriter rw, Object arg, CLModifiers mods, CLParameters params, Tape<Object> tParams, + Matcher dirMatcher, CLFormatter fmt) throws IOException { + tParams.right(); + + CLFormatter.checkItem(arg, '?'); + + if (mods.atMod) { + if (!(arg instanceof String)) + throw new IllegalFormatConversionException('?', arg.getClass()); + + try { + fmt.doFormatString((String)arg, rw, tParams, true); + } catch (EscapeException eex) { + if (eex.endIteration) + throw new UnsupportedOperationException("Colon mod not allowed on escape marker without colon mod on iteration"); + } + } else { + if (tParams.atEnd()) + throw new IllegalArgumentException("? directive requires two format parameters"); + + Object o = tParams.item(); + tParams.right(); + + if (!(o instanceof Iterable)) + throw new IllegalFormatConversionException('?', o.getClass()); + + Iterable<Object> itb = (Iterable<Object>)o; + Tape<Object> newParams = new SingleTape<>(itb); + + try { + fmt.doFormatString((String)arg, rw, newParams, true); + } catch (EscapeException eex) { + throw new UnsupportedOperationException("Colon mod not allowed on escape marker without colon mod on iteration"); + } + } + } +} diff --git a/base/src/main/java/bjc/utils/ioutils/format/directives/TabulateDirective.java b/base/src/main/java/bjc/utils/ioutils/format/directives/TabulateDirective.java index 7775904..d9136f2 100644 --- a/base/src/main/java/bjc/utils/ioutils/format/directives/TabulateDirective.java +++ b/base/src/main/java/bjc/utils/ioutils/format/directives/TabulateDirective.java @@ -14,7 +14,7 @@ public class TabulateDirective implements Directive { // Unsupported feature. // // I can't really make out what this is supposed to do from the - // documentation, but I suspect that it depends of font glyph + // documentation, but I suspect that it depends on font glyph // size, not character positions if (mods.colonMod) { throw new UnsupportedOperationException("Colon mod is not supported for T directive"); |
