diff options
| author | bculkin2442 <bjculkin@mix.wvu.edu> | 2019-07-02 16:59:14 -0400 |
|---|---|---|
| committer | bculkin2442 <bjculkin@mix.wvu.edu> | 2019-07-02 16:59:14 -0400 |
| commit | 5a1b096b47fbcca7e9cc6a24db558128f4cdd87f (patch) | |
| tree | 8e5046c58978e0fd62a2758889cf61defdd807b5 | |
| parent | 20000281fc88c188eb81d9d3d954119725a03ca6 (diff) | |
Convert to using ControlledString
All of the places that parse controls now use ControlledString instead
of doing their own stuff. -\(o-o)/-
| -rw-r--r-- | data/test/test5.rp | 2 | ||||
| -rw-r--r-- | data/test/test6.rp | 8 | ||||
| -rw-r--r-- | src/main/java/bjc/everge/ControlledString.java | 226 | ||||
| -rw-r--r-- | src/main/java/bjc/everge/Everge.java | 43 | ||||
| -rw-r--r-- | src/main/java/bjc/everge/ReplError.java | 2 | ||||
| -rw-r--r-- | src/main/java/bjc/everge/ReplOpts.java | 44 | ||||
| -rw-r--r-- | src/main/java/bjc/everge/ReplPair.java | 414 | ||||
| -rw-r--r-- | src/main/java/bjc/everge/ReplParseException.java | 4 | ||||
| -rw-r--r-- | src/test/java/bjc/everge/ControlledStringTest.java | 42 | ||||
| -rw-r--r-- | src/test/java/bjc/everge/ReplPairTest.java | 2 | ||||
| -rw-r--r-- | src/test/java/bjc/everge/StringUtilsTest.java | 38 | ||||
| -rw-r--r-- | src/test/java/bjc/everge/TestUtils.java | 72 |
12 files changed, 592 insertions, 305 deletions
diff --git a/data/test/test5.rp b/data/test/test5.rp index f2c4dc8..2ee18ce 100644 --- a/data/test/test5.rp +++ b/data/test/test5.rp @@ -1,5 +1,5 @@ # Basic explicit priority test -//p/-1//ab +//P/-1//ab d a diff --git a/data/test/test6.rp b/data/test/test6.rp index 07a7923..34fd9dd 100644 --- a/data/test/test6.rp +++ b/data/test/test6.rp @@ -1,16 +1,16 @@ # Basic staging test |//tf;df -//s/1//a +//S/1//a b b c -//s/2//x +//S/2//x y1 -//s/1;i//1 +//S/1;I//1 2 -//e;p/2//y1 +//E;P/2//y1 z diff --git a/src/main/java/bjc/everge/ControlledString.java b/src/main/java/bjc/everge/ControlledString.java index a14a535..c05e3a4 100644 --- a/src/main/java/bjc/everge/ControlledString.java +++ b/src/main/java/bjc/everge/ControlledString.java @@ -1,5 +1,7 @@ package bjc.everge; +import java.util.Arrays; + /** * Represents a string with a set of control flags attached to it. * @@ -51,8 +53,167 @@ public class ControlledString { name = nam; args = ars; } + + /** + * Get the count of arguments this control has. + * + * @return The number of arguments to this control. + */ + public int count() { + return args.length; + } + + /** + * Get an argument from the control. + * + * @param i The index of the argument to get. + * @return The argument at that position. + */ + public String get(int i) { + if (i < 0) { + String msg = String.format("Control argument index must be greater than 0 (was %d)", i); + + throw new IllegalArgumentException(msg); + } + + if (i > args.length) { + String msg = String.format("Control argument index must be less than %d (was %d)", + args.length, i); + + throw new IllegalArgumentException(msg); + } + + return args[i]; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(name); + + if (args != null && args.length > 0) { + sb.append("/"); + + for (String arg : args) { + sb.append(arg); + sb.append(";"); + } + } + + return sb.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(args); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { return true; } + if (obj == null) { return false; } + if (getClass() != obj.getClass()) { return false; } + + Control other = (Control) obj; + + if (name == null) { + if (other.name != null) { return false; } + } else if (!name.equals(other.name)) { return false; } + + boolean isArged = args != null && args.length > 0; + boolean oIsArged = other.args != null && other.args.length > 0; + + if (isArged && !oIsArged) { return false; } + if (!isArged && oIsArged) { return false; } + + if (isArged && oIsArged) { + return Arrays.equals(args, other.args); + } + + return true; + } + + /** + * Convenient static constructor for static imports. + * + * @param nam + * The name of the control. + * @param ars + * The arguments to the control. + * @return A control with the right parameters. + */ + public static Control C(String nam, String... ars) { + return new Control(nam, ars); + } } + + /** + * Parameter class for defining how to parse a ControlledString. + * + * @author Ben Culkin + */ + public static class ParseStrings { + /** + * The indicator for separating controls from the regular string. + */ + public String contInd; + /** + * The indicator for separating individual controls. + */ + public String contSep; + + /** + * The indicator for separating arguments to a control. + */ + public String contArg; + + /** + * The indicator for escaping any of the indicators (including itself) + */ + public String contEsc; + + /** + * Create a new set of parse strings. + * + * @param contInd + * The control indicator. + * @param contSep + * The control separator. + * @param contArg + * The argument separator. + * @param contEsc + * The control escape. + */ + public ParseStrings(String contInd, String contSep, String contArg, String contEsc) { + this.contInd = contInd; + this.contSep = contSep; + this.contArg = contArg; + this.contEsc = contEsc; + } + + /** + * Convenient static constructor. + * + * @param contInd + * The control indicator. + * @param contSep + * The control separator. + * @param contArg + * The argument separator. + * @param contEsc + * The control escape. + * @return A new set of control strings. + */ + public static ParseStrings PS(String contInd, String contSep, String contArg, String contEsc) { + return new ParseStrings(contInd, contSep, contArg, contEsc); + } + } + /** * The string the controls apply to. */ @@ -93,7 +254,7 @@ public class ControlledString { public ControlledString(String strung, Control... controls) { strang = strung; - controls = controls; + this.controls = controls; } /** @@ -106,56 +267,51 @@ public class ControlledString { } /** - * Parse a controlled string from a regular string. + * Get the count of controls. * - * The controls must be parsed from the beginning of the string, and are indicated by occurances - * of contInd that bracket them from the string. The individual controls are delimited by - * instances of contSep, with arguments to them being separated by occurances of contArg. + * @return The number of controls for this string. + */ + public int count() { + return controls.length; + } + + /** + * Parse a controlled string from a regular string. * - * Each of those separators (which must be regular strings, not regexes or anything) may be - * escaped by preceeding them with a copy of contEsc. + * The controls must be parsed from the beginning of the string. * * @param lne - * The string to parse frmo. - * @param contInd - * The indicator for whether or not there are controls. - * @param contSep - * The separator of individual controls. - * @param contArg - * The separator of control arguments. - * @param contEsc - * The escape string for each of the separators/indicators. - * + * The string to parse from. + * @param strangs + * The object to read the strings from * @return A parsed control string. */ - public static ControlledString parse(String lne, String contInd, String contSep, - String contArg, String contEsc) + public static ControlledString parse(String lne, ParseStrings strangs) { - if (!lne.startsWith(contInd)) { + if (!lne.startsWith(strangs.contInd)) { return new ControlledString(lne); } - String tmp = lne.substring(2); - - String[] bits = StringUtils.escapeSplit(contEsc, contInd, lne); + String[] bits = StringUtils.escapeSplit(strangs.contEsc, strangs.contInd, lne); if (bits.length < 2) { String msg = "Did not find control terminator (%s) where it should be"; - msg = String.format(msg, contInd); + msg = String.format(msg, strangs.contInd); throw new IllegalArgumentException(msg); - } + } ControlledString cs = new ControlledString(bits[0]); + if (bits.length > 2) cs.strang = bits[2]; - bits = StringUtils.escapeSplit(contEsc, contSep, bits[1]); + bits = StringUtils.escapeSplit(strangs.contEsc, strangs.contSep, bits[1]); cs.controls = new Control[bits.length]; for (int i = 0; i < bits.length; i++) { String bit = bits[i]; - String[] bots = StringUtils.escapeSplit(contEsc, contArg, bit); + String[] bots = StringUtils.escapeSplit(strangs.contEsc, strangs.contArg, bit); Control cont = new Control(bots[0]); @@ -175,4 +331,20 @@ public class ControlledString { return cs; } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + + sb.append("//"); + + for (Control cont : controls) { + sb.append(cont); + } + + sb.append("//"); + sb.append(strang); + + return sb.toString(); + } } diff --git a/src/main/java/bjc/everge/Everge.java b/src/main/java/bjc/everge/Everge.java index 9b5a235..5ba9e4b 100644 --- a/src/main/java/bjc/everge/Everge.java +++ b/src/main/java/bjc/everge/Everge.java @@ -1,29 +1,16 @@ package bjc.everge; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.PrintStream; +import java.io.*; import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; +import java.nio.file.*; -import java.util.ArrayList; -import java.util.Deque; -import java.util.LinkedList; -import java.util.List; -import java.util.Scanner; +import java.util.*; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.concurrent.locks.*; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; +import java.util.regex.*; /** * Everge front-end application. @@ -77,7 +64,13 @@ public class Everge { private ReadWriteLock argLock = new ReentrantReadWriteLock(); // Input/output streams + /** + * Stream to use for normal output. + */ public PrintStream outStream = System.out; + /** + * Stream to use for error output. + */ public PrintStream errStream = System.err; /** @@ -226,8 +219,8 @@ public class Everge { { String msg = String.format( - "[ERROR] Encountered errors parsing data file'%s'\n", - argBody); + "[ERROR] Encountered %s parsing data file'%s'\n", + errString, argBody); sb.append(msg); } @@ -348,13 +341,13 @@ public class Everge { String msg = String.format("[ERROR] File '%s' is not readable\n", fle); errs.add(msg); return false; - } else { - byte[] inp = Files.readAllBytes(pth); + } - String strang = new String(inp, Charset.forName("UTF-8")); + byte[] inp = Files.readAllBytes(pth); - processString(strang); - } + String strang = new String(inp, Charset.forName("UTF-8")); + + processString(strang); } else if (inputStat == InputStatus.LINE) { try (FileInputStream fis = new FileInputStream(fle); Scanner scn = new Scanner(fis)) { while(scn.hasNextLine()) { diff --git a/src/main/java/bjc/everge/ReplError.java b/src/main/java/bjc/everge/ReplError.java index 6e58539..c86ec0e 100644 --- a/src/main/java/bjc/everge/ReplError.java +++ b/src/main/java/bjc/everge/ReplError.java @@ -7,7 +7,7 @@ package bjc.everge; */ public class ReplError { /** - * The line the error occured on. + * The line the error occurred on. */ public int line; /** diff --git a/src/main/java/bjc/everge/ReplOpts.java b/src/main/java/bjc/everge/ReplOpts.java index 1ddfc79..85765d5 100644 --- a/src/main/java/bjc/everge/ReplOpts.java +++ b/src/main/java/bjc/everge/ReplOpts.java @@ -45,26 +45,32 @@ public class ReplOpts { public PrintStream outStream = System.out; public PrintStream errStream = System.err; - @Override - public boolean equals(Object o) { - if (o == null) return false; - - if (!getClass().equals(o.getClass())) return false; - - ReplOpts ro = (ReplOpts)o; - - if (isPerf != ro.isPerf) return false; - - if (isDebug != ro.isDebug) return false; - if (isTrace != ro.isTrace) return false; - - if (defPrior != ro.defPrior) return false; - if (defStage != ro.defStage) return false; - if (defMulti != ro.defMulti) return false; - - if (defStatus != ro.defStatus) return false; - + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + (defMulti ? 1231 : 1237); + result = prime * result + defPrior; + result = prime * result + defStage; + result = prime * result + ((defStatus == null) ? 0 : defStatus.hashCode()); + result = prime * result + (isDebug ? 1231 : 1237); + result = prime * result + (isPerf ? 1231 : 1237); + result = prime * result + (isTrace ? 1231 : 1237); + return result; + } + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + ReplOpts other = (ReplOpts) obj; + if (defMulti != other.defMulti) return false; + if (defPrior != other.defPrior) return false; + if (defStage != other.defStage) return false; + if (defStatus != other.defStatus) return false; + if (isDebug != other.isDebug) return false; + if (isPerf != other.isPerf) return false; + if (isTrace != other.isTrace) return false; return true; } } diff --git a/src/main/java/bjc/everge/ReplPair.java b/src/main/java/bjc/everge/ReplPair.java index 5242df6..da6f6eb 100644 --- a/src/main/java/bjc/everge/ReplPair.java +++ b/src/main/java/bjc/everge/ReplPair.java @@ -7,6 +7,7 @@ import java.util.Scanner; import java.util.function.UnaryOperator; import bjc.everge.ControlledString.Control; +import bjc.everge.ControlledString.ParseStrings; /** * String pairs for replacements. @@ -248,37 +249,12 @@ public class ReplPair implements Comparable<ReplPair>, UnaryOperator<String> { } isMulti = ropts.defMulti; - + + ControlledString cs = getControls(body, errs, ropts, lno, pno, "body"); // Body has attached controls, process them. - if (body.startsWith("//")) { - body = body.substring(2); - - String[] bodyBits = StringUtils.escapeSplit("|", "//", body); - if (bodyBits.length < 2) { - String msg = - "Did not find control terminator (//) in body where it should be"; - - errs.add(new ReplError(lno, pno, msg, body)); - continue; - } - - String contBody = bodyBits[0]; - String actBody = bodyBits[1]; - - // Split out each control - String[] bits = StringUtils.escapeSplit("|", ";", actBody); - - for (String bit : bits) { - String bitHead = bit.toUpperCase(); - String bitBody = bit; - - String[] bots = StringUtils.escapeSplit("|", "/", bit); - if (bots.length > 1) { - bitHead = bots[0].toUpperCase(); - bitBody = bots[1]; - } - - switch (bitHead) { + if (cs.hasControls()) { + for (Control cont : cs.controls) { + switch (cont.name) { case "MULTITRUE": case "MULTIT": case "MT": @@ -291,15 +267,23 @@ public class ReplPair implements Comparable<ReplPair>, UnaryOperator<String> { break; case "MULTI": case "M": - isMulti = Boolean.parseBoolean(bitBody); + if (cont.count() != 1) { + String errMsg = String.format("Expected one multi flag (got %d)", cont.count()); + errs.add(new ReplError(lno, pno, errMsg, body)); + } else { + isMulti = Boolean.parseBoolean(cont.get(0)); + } break; default: - errs.add(new ReplError(lno, pno, String.format("Invalid control name '%s'", bitHead), body)); + { + String errMsg = String.format("Invalid control name '%s'", cont.name); + errs.add(new ReplError(lno, pno, errMsg, body)); + } break; } } - body = actBody; + body = cs.strang; } if (isMulti) { @@ -473,7 +457,7 @@ public class ReplPair implements Comparable<ReplPair>, UnaryOperator<String> { if (!find.equals(name)) nameStr = String.format("(%s)", name); - return String.format("%ss/%s/%s/p(%d)", nameStr, find, replace, priority); + return String.format("%ss/(%s)/(%s)/p(%d)", nameStr, find, replace, priority); } @Override @@ -482,140 +466,162 @@ public class ReplPair implements Comparable<ReplPair>, UnaryOperator<String> { return rp.priority - this.priority; } - + @Override - public boolean equals(Object o) { - if (o == null) return false; - - if (!getClass().equals(o.getClass())) return false; - - ReplPair ro = (ReplPair)o; - - if (!find.equals(ro.find)) return false; - // lno is not a field we consider for equality - if (!name.equals(ro.name)) return false; - if (priority != ro.priority) return false; - if (!replace.equals(ro.name)) return false; - // stat is not a field we consider for equality + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((find == null) ? 0 : find.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + priority; + result = prime * result + ((replace == null) ? 0 : replace.hashCode()); + result = prime * result + stage; + return result; + } + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null) return false; + if (getClass() != obj.getClass()) return false; + ReplPair other = (ReplPair) obj; + if (find == null) { + if (other.find != null) return false; + } else if (!find.equals(other.find)) return false; + if (name == null) { + if (other.name != null) return false; + } else if (!name.equals(other.name)) return false; + if (priority != other.priority) return false; + if (replace == null) { + if (other.replace != null) return false; + } else if (!replace.equals(other.replace)) return false; + if (stage != other.stage) return false; return true; } private static String readName(String nam, Scanner scn, List<ReplError> errs, ReplPair rp, ReplOpts ropts, IntHolder lno, IntHolder pno) { - String name = nam; + ControlledString cs = getControls(nam, errs, ropts, lno, pno, "name"); boolean isMulti = ropts.defMulti; - // Name has attached controls, process them. - if (name.startsWith("//")) { - name = name.substring(2); - - String[] nameBits = StringUtils.escapeSplit("|", "//", name); + String name = cs.strang; - if (nameBits.length < 2) { - String msg = "Did not find control terminator (//) in name where it should be"; + if (cs.hasControls()) { + for (Control cont : cs.controls) { + switch (cont.name) { + case "NAME": + case "N": + if (cont.count() != 1) { + String errMsg = String.format("One name argument was expected (got %d)", + cont.count()); - errs.add(new ReplError(lno, pno, msg, name)); - return null; - } - - String contName = nameBits[0]; - String actName = nameBits[1]; - - // Split out each control - String[] bits = StringUtils.escapeSplit("|", ";", contName); - - for (String bit : bits) { - String bitHead = bit.toUpperCase(); - String bitBody = bit; - - String[] bots = StringUtils.escapeSplit("|", "/", bit); + errs.add(new ReplError(lno, pno, errMsg, nam)); + } else { + rp.name = cont.get(0); + } + break; + case "PRIORITY": + case "PRIOR": + case "P": + try { + if (cont.count() != 1) { + String errMsg = String.format("One priority argument was expected (got %d", + cont.count()); + + errs.add(new ReplError(lno, pno, errMsg, nam)); + } else { + rp.priority = Integer.parseInt(cont.get(0)); + } + } catch (NumberFormatException nfex) { + String errMsg = String.format("'%s' is not a valid priority (must be an integer)", + cont.get(0)); + + errs.add(new ReplError(lno, pno, errMsg, nam)); + } + break; + case "STAGE": + case "S": + try { + if (cont.count() != 1) { + String errMsg = String.format("One stage argument was expected (got %d", + cont.count()); + + errs.add(new ReplError(lno, pno, errMsg, nam)); + } else { + int tmpStage = Integer.parseInt(cont.get(0)); + if (tmpStage < 0) { + String errMsg = String.format("'%s' is not a valid stage (must be a positive integer)", + cont.get(0)); + errs.add(new ReplError(lno, pno, errMsg, nam)); + + break; + } + rp.stage = tmpStage; + } + } catch (NumberFormatException nfex) { + String errMsg = String.format("'%s' is not a valid stage (must be a positive integer)", + cont.get(0)); + + errs.add(new ReplError(lno, pno, errMsg, nam)); + } + break; + case "MULTITRUE": + case "MULTIT": + case "MT": + isMulti = true; + break; + case "MULTIFALSE": + case "MULTIF": + case "MF": + isMulti = false; + break; + case "MULTI": + case "M": + if (cont.count() != 1) { + String errMsg = String.format("One multi-flag argument was expected (got %d", + cont.count()); - if (bots.length > 1) { - bitHead = bots[0].toUpperCase(); - bitBody = bots[1]; - } + errs.add(new ReplError(lno, pno, errMsg, nam)); + } else { + isMulti = Boolean.parseBoolean(cont.get(0)); + } + break; + case "INTERNAL": + case "INT": + case "I": + rp.stat = StageStatus.INTERNAL; + break; + case "EXTERNAL": + case "EXT": + case "E": + rp.stat = StageStatus.EXTERNAL; + break; + case "BOTH": + case "B": + rp.stat = StageStatus.BOTH; + break; + default: + { + String errMsg = String.format("Unknown control name '%s' for name '%s'", + cont.name, nam); - switch (bitHead) { - case "NAME": - case "N": - rp.name = bitBody; - break; - case "PRIORITY": - case "PRIOR": - case "P": - try { - rp.priority = Integer.parseInt(bitBody); - } catch (NumberFormatException nfex) { - String errMsg = String.format("'%s' is not a valid priority (must be an integer)", bitBody); - errs.add(new ReplError(lno, pno, errMsg, name)); - } - break; - case "STAGE": - case "S": - try { - int tmpStage = Integer.parseInt(bitBody); - if (tmpStage < 0) { - String errMsg = String.format("'%s' is not a valid stage (must be a positive integer)", bitBody); - errs.add(new ReplError(lno, pno, errMsg, name)); + ReplError erd = new ReplError(lno, pno, errMsg, nam); - break; + errs.add(erd); } - rp.stage = tmpStage; - } catch (NumberFormatException nfex) { - String errMsg = String.format("'%s' is not a valid stage (must be a positive integer)", bitBody); - errs.add(new ReplError(lno, pno, errMsg, name)); - } - break; - case "MULTITRUE": - case "MULTIT": - case "MT": - isMulti = true; - break; - case "MULTIFALSE": - case "MULTIF": - case "MF": - isMulti = false; - break; - case "MULTI": - case "M": - isMulti = Boolean.parseBoolean(bitBody); - break; - case "INTERNAL": - case "INT": - case "I": - rp.stat = StageStatus.INTERNAL; - break; - case "EXTERNAL": - case "EXT": - case "E": - rp.stat = StageStatus.EXTERNAL; - break; - case "BOTH": - case "B": - rp.stat = StageStatus.BOTH; - break; - default: - { - ReplError erd = new ReplError(lno, pno, - String.format("Unknown control name '%s' for name '%s'", - bitHead, name), name); - - errs.add(erd); - } - break; + break; } - - name = actName; } - // Multi-line name with a trailer - if (isMulti) { - String tmp = readMultiLine(name, scn, ropts, errs, "name", lno); - if (tmp == null) return null; - name = tmp; - } + name = cs.strang; + } + + // Multi-line name with a trailer + if (isMulti) { + String tmp = readMultiLine(name, scn, ropts, errs, "name", lno); + if (tmp == null) return null; + name = tmp; } return name; @@ -623,59 +629,56 @@ public class ReplPair implements Comparable<ReplPair>, UnaryOperator<String> { private static void readGlobal(String nam, Scanner scn, List<ReplError> errs, ReplOpts ropts, IntHolder lno, IntHolder pno) { - String name = nam.substring(3); + ControlledString cs = getControls(nam.substring(1), errs, ropts, lno, pno, "global"); - // Split out each control - String[] bits = StringUtils.escapeSplit("|", ";", name); - if (ropts.isTrace) { - ropts.errStream.printf("\t[TRACE] Split control bits are: \n"); - for (String bit : bits) { - ropts.errStream.printf("%s, ", bit); - } - ropts.errStream.println(); - } - for (String bit : bits) { - String bitHead = bit.toUpperCase(); - String bitBody = bit; - - String[] bots = StringUtils.escapeSplit("|", "/", bit); - if (bots.length > 1) { - bitHead = bots[0]; - bitBody = bots[1]; - } - - switch (bitHead) { + for (Control cont : cs.controls) { + switch (cont.name) { case "PRIORITY": case "PRIOR": case "P": try { - int tmp = Integer.parseInt(bitBody); - ropts.defPrior = tmp; + if (cont.count() != 1) { + String errMsg = String.format("Must specify 1 priority (%d specified)", + cont.count()); + + errs.add(new ReplError(lno, pno, errMsg, nam)); + } else { + int tmp = Integer.parseInt(cont.get(0)); + ropts.defPrior = tmp; + } } catch (NumberFormatException nfex) { String errMsg = String.format("'%s' is not a valid priority (must be an integer)", - bitBody); + cont.get(0)); - errs.add(new ReplError(lno, pno, errMsg, name)); + errs.add(new ReplError(lno, pno, errMsg, nam)); } break; case "STAGE": case "S": try { - int tmpStage = Integer.parseInt(bitBody); + if (cont.count() != 1) { + String errMsg = String.format("Must specify 1 stage (%d specified)", + cont.count()); - if (tmpStage < 0) { - String errMsg = String.format("'%s' is not a valid stage (must be a positive integer)", - bitBody); + errs.add(new ReplError(lno, pno, errMsg, nam)); + } else { + int tmpStage = Integer.parseInt(cont.get(0)); - errs.add(new ReplError(lno, pno, errMsg, name)); - break; + if (tmpStage < 0) { + String errMsg = String.format("'%s' is not a valid stage (must be a positive integer)", + cont.get(0)); + + errs.add(new ReplError(lno, pno, errMsg, nam)); + break; + } + + ropts.defStage = tmpStage; } - ropts.defStage = tmpStage; } catch (NumberFormatException nfex) { String errMsg = String.format("'%s' is not a valid stage (must be a positive integer)", - bitBody); + cont.get(0)); - errs.add(new ReplError(lno, pno, errMsg, name)); + errs.add(new ReplError(lno, pno, errMsg, nam)); } break; case "MULTITRUE": @@ -690,7 +693,14 @@ public class ReplPair implements Comparable<ReplPair>, UnaryOperator<String> { break; case "MULTI": case "M": - ropts.defMulti = Boolean.parseBoolean(bitBody); + if (cont.count() != 1) { + String errMsg = String.format("Must specify 1 multi-flag (%d specified)", + cont.count()); + + errs.add(new ReplError(lno, pno, errMsg, nam)); + } else { + ropts.defMulti = Boolean.parseBoolean(cont.get(0)); + } break; case "INTERNAL": case "INT": @@ -718,7 +728,14 @@ public class ReplPair implements Comparable<ReplPair>, UnaryOperator<String> { break; case "DEBUG": case "D": - ropts.isDebug = Boolean.parseBoolean(bitBody); + if (cont.count() != 1) { + String errMsg = String.format("Must specify 1 debug flag (%d specified)", + cont.count()); + + errs.add(new ReplError(lno, pno, errMsg, nam)); + } else { + ropts.isDebug = Boolean.parseBoolean(cont.get(0)); + } break; case "TRACETRUE": case "TRACET": @@ -732,7 +749,14 @@ public class ReplPair implements Comparable<ReplPair>, UnaryOperator<String> { break; case "TRACE": case "T": - ropts.isTrace = Boolean.parseBoolean(bitBody); + if (cont.count() != 1) { + String errMsg = String.format("Must specify 1 trace flag (%d specified)", + cont.count()); + + errs.add(new ReplError(lno, pno, errMsg, nam)); + } else { + ropts.isTrace = Boolean.parseBoolean(cont.get(0)); + } break; case "PERFTRUE": case "PERFT": @@ -746,20 +770,26 @@ public class ReplPair implements Comparable<ReplPair>, UnaryOperator<String> { break; case "PERF": case "PRF": - ropts.isPerf = Boolean.parseBoolean(bitBody); + if (cont.count() != 1) { + String errMsg = String.format("Must specify 1 perf. flag (%d specified)", + cont.count()); + + errs.add(new ReplError(lno, pno, errMsg, nam)); + } else { + ropts.isPerf = Boolean.parseBoolean(cont.get(0)); + } break; default: { - String msg = String.format("Invalid global control name '%s'", bitHead); - ReplError err = new ReplError(lno, pno, msg, name); + String msg = String.format("Invalid global control name '%s'", cont.name); + ReplError err = new ReplError(lno, pno, msg, nam); errs.add(err); } break; } if (ropts.isTrace) - ropts.errStream.printf("\t[TRACE] Processed global control '%s':'%s'\n", - bitHead, bitBody); + ropts.errStream.printf("\t[TRACE] Processed global control '%s'\n", cont); } return; @@ -769,7 +799,7 @@ public class ReplPair implements Comparable<ReplPair>, UnaryOperator<String> { ReplOpts ropts, IntHolder lno, IntHolder pno, String type) { try { - return ControlledString.parse(lne, "//", ";", "/", "|"); + return ControlledString.parse(lne, new ParseStrings("//", ";", "/", "|")); } catch (IllegalArgumentException iaex) { String msg = "Did not find control terminator (//) in %s where it should be"; msg = String.format(msg, type); diff --git a/src/main/java/bjc/everge/ReplParseException.java b/src/main/java/bjc/everge/ReplParseException.java index 0091b83..9473b71 100644 --- a/src/main/java/bjc/everge/ReplParseException.java +++ b/src/main/java/bjc/everge/ReplParseException.java @@ -4,6 +4,10 @@ import java.util.ArrayList; import java.util.List; public class ReplParseException extends RuntimeException { + /** + * Serialization ID. + */ + private static final long serialVersionUID = 4752304282380556849L; public List<ReplError> errs; public ReplParseException(String msg) { diff --git a/src/test/java/bjc/everge/ControlledStringTest.java b/src/test/java/bjc/everge/ControlledStringTest.java new file mode 100644 index 0000000..8d76354 --- /dev/null +++ b/src/test/java/bjc/everge/ControlledStringTest.java @@ -0,0 +1,42 @@ +package bjc.everge; + +import bjc.everge.ControlledString.Control; + +import org.junit.Test; + +import static bjc.everge.ControlledString.Control.C; +import static bjc.everge.TestUtils.*; + +import static org.junit.Assert.*; + +/** + * Test for ControlledString. + * + * @author Ben Culkin + */ +public class ControlledStringTest { + @Test + public void testNoControls() { + assertIsControl("a", "a"); + assertIsControl("abc", "abc"); + } + + @Test + public void testSimpleControls() { + assertIsControl("//a//", "", C("a")); + assertIsControl("//a;b//", "", C("a"), C("b")); + assertIsControl("//a;b;c//", "", C("a"), C("b"), C("c")); + } + + @Test + public void testArgedControls() { + assertIsControl("//a/b//", "", C("a", "b")); + assertIsControl("//a/b;c//", "", C("a", "b"), C("c")); + assertIsControl("//a/b;c/1/2//", "", C("a", "b"), C("c", "1", "2")); + } + + @Test + public void testMixedControls() { + assertIsControl("//a//b", "b", C("a")); + } +} diff --git a/src/test/java/bjc/everge/ReplPairTest.java b/src/test/java/bjc/everge/ReplPairTest.java index 7c87160..8edb42e 100644 --- a/src/test/java/bjc/everge/ReplPairTest.java +++ b/src/test/java/bjc/everge/ReplPairTest.java @@ -52,7 +52,7 @@ public class ReplPairTest { @Test public void testReplaceExpOrder() { - assertMultiReplace("data/test/test5.rp", "a", "a", "aa", "ab"); + assertMultiReplace(false, "data/test/test5.rp", "a", "a", "aa", "ab"); } @Test diff --git a/src/test/java/bjc/everge/StringUtilsTest.java b/src/test/java/bjc/everge/StringUtilsTest.java index b20e074..bba5e11 100644 --- a/src/test/java/bjc/everge/StringUtilsTest.java +++ b/src/test/java/bjc/everge/StringUtilsTest.java @@ -6,8 +6,15 @@ import java.util.List; import org.junit.Test; +import static bjc.everge.TestUtils.*; + import static org.junit.Assert.*; +/** + * Test for StringUtils. + * + * @author Ben Culkin + */ public class StringUtilsTest { @Test public void testNullSplit() { @@ -48,35 +55,4 @@ public class StringUtilsTest { assertSplitsTo("a/", "|", "/", "a"); } - private void assertSplitsTo(String inp, String esc, String splat, String... right) { - assertSplitsTo(false, inp, esc, splat, right); - } - - private void assertSplitsTo(boolean doLog, String inp, String esc, String splat, String... right) { - try { - if (doLog) StringUtils.isDebug = true; - - String[] lst = StringUtils.escapeSplit(esc, splat, inp); - - if (doLog) { - System.err.printf("[TRACE] Returned "); - - for (String str : lst) { - System.err.printf("(%s) ", str); - } - - System.err.println(); - } - - assertArrayEquals(right, lst); - } catch (Exception ex) { - System.err.println("EXCEPTION"); - ex.printStackTrace(); - System.err.println(); - - assertTrue(false); - } finally { - if (doLog) StringUtils.isDebug = false; - } - } } diff --git a/src/test/java/bjc/everge/TestUtils.java b/src/test/java/bjc/everge/TestUtils.java index 2b9dc8d..e30a74e 100644 --- a/src/test/java/bjc/everge/TestUtils.java +++ b/src/test/java/bjc/everge/TestUtils.java @@ -1,5 +1,8 @@ package bjc.everge; +import bjc.everge.ControlledString.Control; +import bjc.everge.ControlledString.ParseStrings; + import java.io.FileInputStream; import java.io.IOException; @@ -61,8 +64,13 @@ public class TestUtils { } public static void assertMultiReplace(boolean logRep, String fle, String... inps) { - if (inps.length < 2) throw new IllegalArgumentException("ERROR: Must provide at least two strings to assertMultiReplace"); - if (inps.length % 2 != 0) throw new IllegalArgumentException("ERROR: Odd number of strings passed to assertMultiReplace"); + if (inps.length < 2) { + throw new IllegalArgumentException("ERROR: Must provide at least two strings to assertMultiReplace"); + } + + if (inps.length % 2 != 0) { + throw new IllegalArgumentException("ERROR: Odd number of strings passed to assertMultiReplace"); + } List<ReplPair> lrp = null; @@ -98,7 +106,9 @@ public class TestUtils { } public static void assertReplacesTo(boolean logRep, String right, List<ReplPair> rps, String inp) { - if (logRep) System.err.printf("\t[LOG] Checking '%s' -> '%s'\n", inp, right); + if (logRep) { + System.err.printf("\t[LOG] Checking '%s' -> '%s'\n", inp, right); + } String tmp = inp; @@ -107,9 +117,63 @@ public class TestUtils { tmp = rp.apply(tmp); - if (logRep) System.err.printf("\t[LOG] '%s' -> '%s'\t%s\n", oldTmp, tmp, rp); + if (logRep) { + System.err.printf("\t\t[LOG-STEP] '%s' -> '%s'\t%s\n", oldTmp, tmp, rp); + } } assertEquals(right, tmp); } + + public static void assertSplitsTo(String inp, String esc, String splat, String... right) { + assertSplitsTo(false, inp, esc, splat, right); + } + + public static void assertSplitsTo(boolean doLog, String inp, String esc, String splat, String... right) { + try { + if (doLog) StringUtils.isDebug = true; + + String[] lst = StringUtils.escapeSplit(esc, splat, inp); + + if (doLog) { + System.err.printf("[TRACE] Returned "); + + for (String str : lst) { + System.err.printf("(%s) ", str); + } + + System.err.println(); + } + + assertArrayEquals(right, lst); + } catch (Exception ex) { + System.err.println("EXCEPTION"); + ex.printStackTrace(); + System.err.println(); + + assertTrue(false); + } finally { + if (doLog) StringUtils.isDebug = false; + } + } + + public static void assertIsControl(String inp, String strang, Control... args) { + assertIsControl(false, inp, strang, args); + } + + public static void assertIsControl(boolean doLog, String inp, String strang, Control... args) { + ControlledString cs = ControlledString.parse(inp, new ParseStrings("//", ";", "/", "|")); + + if (doLog) { + System.err.printf("[LOG] CS: %s\n", cs); + } + + assertEquals(strang, cs.strang); + + assertEquals("array length mismatch:", args.length, cs.count()); + + for (int i = 0; i < args.length; i++) { + assertEquals("array value mismatch:", args[i], cs.controls[i]); + } + } } |
