summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbculkin2442 <bjculkin@mix.wvu.edu>2019-07-02 16:59:14 -0400
committerbculkin2442 <bjculkin@mix.wvu.edu>2019-07-02 16:59:14 -0400
commit5a1b096b47fbcca7e9cc6a24db558128f4cdd87f (patch)
tree8e5046c58978e0fd62a2758889cf61defdd807b5
parent20000281fc88c188eb81d9d3d954119725a03ca6 (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.rp2
-rw-r--r--data/test/test6.rp8
-rw-r--r--src/main/java/bjc/everge/ControlledString.java226
-rw-r--r--src/main/java/bjc/everge/Everge.java43
-rw-r--r--src/main/java/bjc/everge/ReplError.java2
-rw-r--r--src/main/java/bjc/everge/ReplOpts.java44
-rw-r--r--src/main/java/bjc/everge/ReplPair.java414
-rw-r--r--src/main/java/bjc/everge/ReplParseException.java4
-rw-r--r--src/test/java/bjc/everge/ControlledStringTest.java42
-rw-r--r--src/test/java/bjc/everge/ReplPairTest.java2
-rw-r--r--src/test/java/bjc/everge/StringUtilsTest.java38
-rw-r--r--src/test/java/bjc/everge/TestUtils.java72
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]);
+ }
+ }
}