From d86cbcbabc4b251956bd2c5bf4dfa459a00bb239 Mon Sep 17 00:00:00 2001 From: bculkin2442 Date: Tue, 18 Jun 2019 17:44:32 -0400 Subject: Lots of frontend work --- src/main/java/bjc/everge/ReplPair.java | 641 ++++++++++++++++++++------------- 1 file changed, 390 insertions(+), 251 deletions(-) (limited to 'src/main/java/bjc/everge/ReplPair.java') diff --git a/src/main/java/bjc/everge/ReplPair.java b/src/main/java/bjc/everge/ReplPair.java index 4f6b2ad..6acc6ad 100644 --- a/src/main/java/bjc/everge/ReplPair.java +++ b/src/main/java/bjc/everge/ReplPair.java @@ -13,6 +13,8 @@ import java.util.function.UnaryOperator; */ public class ReplPair implements Comparable, UnaryOperator { private int lno; + private int stage; + private StageStatus stat = StageStatus.BOTH; /** * The priority for this replacement. @@ -35,8 +37,6 @@ public class ReplPair implements Comparable, UnaryOperator { */ public String replace; - private StageStatus stat = StageStatus.BOTH; - /** * Create a new blank replacement pair. */ @@ -136,11 +136,7 @@ public class ReplPair implements Comparable, UnaryOperator { List rplPar = readList(detals, scn, errList); if (errList.size() != 0) { - String errString; - if (errList.size() == 0) errString = "An error"; - else errString = "Errors"; - - throw new IllegalArgumentException(String.format("%s occured parsing replacement pairs:\n%s", errString, errList)); + throw new ReplParseException("", errList); } return rplPar; @@ -165,17 +161,8 @@ public class ReplPair implements Comparable, UnaryOperator { public static List readList(List detals, Scanner scn, List errs, ReplOpts ropts) { - int lno = 0; - int pno = 0; - - int defPrior = ropts.defPrior; - int defStage = ropts.defStage; - - boolean defMulti = ropts.defMulti; - - StageStatus defStatus = ropts.defStatus; - - boolean isDebug = ropts.isDebug; + IntHolder lno = new IntHolder(); + IntHolder pno = new IntHolder(); List> stages = new ArrayList<>(); stages.add(new ArrayList()); @@ -183,7 +170,7 @@ public class ReplPair implements Comparable, UnaryOperator { // For every line in the source... while (scn.hasNextLine()) { String name = scn.nextLine().trim(); - lno += 1; + lno.incr(); // If its commented or blank, skip it if (name.equals("")) continue; @@ -191,188 +178,24 @@ public class ReplPair implements Comparable, UnaryOperator { // Global control. Process it. if (name.startsWith("|//")) { - name = name.substring(3); - - // Split out each control - String[] bits = name.split(";"); - - for (String bit : bits) { - String bitHead = bit.toUpperCase(); - String bitBody = bit; - - int idx = bit.indexOf('/'); - if (idx != -1) { - bitHead = bit.substring(0, idx).toUpperCase(); - bitBody = bit.substring(idx + 1); - } - - switch (bitHead) { - case "P": - try { - defPrior = 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 "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)); - - break; - } - defStage = 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 "MT": - defMulti = true; - break; - case "MF": - defMulti = false; - break; - case "M": - defMulti = Boolean.parseBoolean(bitBody); - break; - case "I": - defStatus = StageStatus.INTERNAL; - break; - case "E": - defStatus = StageStatus.EXTERNAL; - break; - case "B": - defStatus = StageStatus.BOTH; - break; - case "DT": - isDebug = true; - break; - case "DF": - isDebug = false; - break; - case "D": - isDebug = Boolean.parseBoolean(bitBody); - break; - default: - errs.add(new ReplError(lno, pno, String.format("Invalid control name '%s'", bitHead), name)); - break; - } - } + readGlobal(name, scn, errs, ropts, lno, pno); continue; } ReplPair rp = new ReplPair(); - rp.priority = defPrior; - rp.stat = defStatus; - rp.lno = lno; - - int stage = defStage; - boolean isMulti = defMulti; - - // Name has attached controls, process them. - if (name.startsWith("//")) { - name = name.substring(2); - - int idx = name.indexOf("//"); - if (idx == -1) { - String msg = "Did not find control terminator (//) in name where it should be"; - - errs.add(new ReplError(lno, pno, msg, name)); - continue; - } + rp.priority = ropts.defPrior; + rp.stat = ropts.defStatus; + rp.lno = lno.get(); + rp.stage = ropts.defStage; - String contName = name.substring(0, idx); - String actName = name.substring(idx + 2); + boolean isMulti = ropts.defMulti; - // Split out each control - String[] bits = contName.split(";"); - - for (String bit : bits) { - String bitHead = bit.toUpperCase(); - String bitBody = bit; - - idx = bit.indexOf('/'); - if (idx != -1) { - bitHead = bit.substring(0, idx).toUpperCase(); - bitBody = bit.substring(idx + 1); - } - - switch (bitHead) { - case "N": - rp.name = bitBody; - break; - 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 "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)); - - break; - } - 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 "MT": - isMulti = true; - break; - case "MF": - isMulti = false; - break; - case "M": - isMulti = Boolean.parseBoolean(bitBody); - break; - case "I": - rp.stat = StageStatus.INTERNAL; - break; - case "E": - rp.stat = StageStatus.EXTERNAL; - break; - case "B": - rp.stat = StageStatus.BOTH; - break; - default: - errs.add(new ReplError(lno, pno, String.format("Unknown control name '%s'", bitHead), name)); - break; - } - } - - // Multi-line name with a trailer - if (isMulti) { - String tmp = actName; - - while (tmp.endsWith("\\")) { - boolean incNL = tmp.endsWith("|\\"); - - if (!scn.hasNextLine()) break; - - tmp = scn.nextLine().trim(); - - if (tmp.equals("")) continue; - if (tmp.startsWith("#")) continue; - - actName = String.format("%s%s%s", actName, incNL ? "\n" : "", tmp); - } - } - - name = actName; + { + String tmpName = readName(name, scn, errs, rp, ropts, lno, pno); + if (tmpName == null) continue; + name = tmpName; } rp.find = name; @@ -380,60 +203,67 @@ public class ReplPair implements Comparable, UnaryOperator { // We started to process the pair, mark it as being // started - pno += 1; + pno.incr(); String body = null; // Read in the next uncommented line do { - if (!scn.hasNextLine()) { - String msg = - "Ran out of input looking for replacement body for raw name " + name; - - errs.add(new ReplError(lno, pno, msg, null)); - break; - } + if (!scn.hasNextLine()) break; body = scn.nextLine().trim(); - lno += 1; + lno.incr(); } while (body.startsWith("#")); - isMulti = defMulti; + if (body == null) { + String msg = + "Ran out of input looking for replacement body for raw name '" + name + "'"; + + errs.add(new ReplError(lno, pno, msg, null)); + break; + } + + isMulti = ropts.defMulti; // Body has attached controls, process them. if (body.startsWith("//")) { body = body.substring(2); - int idx = body.indexOf("//"); - if (idx == -1) { + 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 = body.substring(0, idx); - String actBody = body.substring(idx + 2); + String contBody = bodyBits[0]; + String actBody = bodyBits[1]; // Split out each control - String[] bits = actBody.split(";"); + String[] bits = StringUtils.escapeSplit("|", ";", actBody); for (String bit : bits) { String bitHead = bit.toUpperCase(); String bitBody = bit; - idx = bit.indexOf('/'); - if (idx != -1) { - bitHead = bit.substring(0, idx).toUpperCase(); - bitBody = bit.substring(idx + 1); + String[] bots = StringUtils.escapeSplit("|", "/", bit); + if (bots.length > 1) { + bitHead = bots[0].toUpperCase(); + bitBody = bots[1]; } switch (bitHead) { + 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; @@ -443,48 +273,37 @@ public class ReplPair implements Comparable, UnaryOperator { } } - // Multi-line name with a trailer - if (isMulti) { - String tmp = actBody; - - while (tmp.endsWith("\\")) { - boolean incNL = tmp.endsWith("|\\"); - - if (!scn.hasNextLine()) break; - - tmp = scn.nextLine().trim(); - - if (tmp.startsWith("#")) continue; - - actBody = String.format("%s%s%s", actBody, incNL ? "\n" : "", tmp); - } - } - body = actBody; } + if (isMulti) { + String tmp = readMultiLine(body, scn, ropts, errs, "body", lno); + if (tmp == null) continue; + body = tmp; + } + rp.replace = body; List stageList = null; - if (stage == 0 || stages.size() < (stage - 1)) { - stageList = stages.get(stage); + if (rp.stage == 0 || stages.size() < (rp.stage - 1)) { + stageList = stages.get(rp.stage); if (stageList == null) { stageList = new ArrayList<>(); - stages.add(stage, stageList); + stages.add(rp.stage, stageList); } } else { - for (int i = stages.size(); i <= stage; i++) { + for (int i = stages.size(); i <= rp.stage; i++) { stages.add(new ArrayList<>()); } - stageList = stages.get(stage); + stageList = stages.get(rp.stage); } - if (isDebug) { - System.err.printf("\t[DEBUG] Stage %d: Added %s\n\t\tContents: %s\n", - stage, rp, stageList); + if (ropts.isTrace) { + ropts.errStream.printf("\t[DEBUG] Stage %d: Added %s\n\t\tContents: %s\n", + rp.stage, rp, stageList); } stageList.add(rp); @@ -492,11 +311,11 @@ public class ReplPair implements Comparable, UnaryOperator { // Special-case one-stage processing. if (stages.size() == 1) { - if (isDebug) System.err.printf("\t[DEBUG] Executing single-stage bypass\n"); + if (ropts.isTrace) ropts.errStream.printf("\t[DEBUG] Executing single-stage bypass\n"); for (ReplPair rp : stages.iterator().next()) { if (rp.stat == StageStatus.INTERNAL) { - if (isDebug) System.err.printf("\t[DEBUG] Excluding internal RP %s\n", rp); + if (ropts.isTrace) ropts.errStream.printf("\t[DEBUG] Excluding internal RP %s\n", rp); continue; } @@ -513,14 +332,14 @@ public class ReplPair implements Comparable, UnaryOperator { List tmpList = new ArrayList<>(); tmpList.addAll(detals); - if (isDebug) System.err.printf("\t[DEBUG] Stages: %s\n", stages); + if (ropts.isTrace) ropts.errStream.printf("\t[DEBUG] Stages: %s\n", stages); int procStg = 0; for (List stageList : stages) { procStg += 1; List curStage = new ArrayList<>(); - if (isDebug) System.err.printf("\t[DEBUG] Staging stage %d of %d: %s\n", + if (ropts.isTrace) ropts.errStream.printf("\t[DEBUG] Staging stage %d of %d: %s\n", procStg, stageList.size(), stageList); for (ReplPair rp : stageList) { @@ -529,8 +348,8 @@ public class ReplPair implements Comparable, UnaryOperator { for (ReplPair curPar : tmpList) { String tmp = rp.replace.replaceAll(curPar.find, curPar.replace); - if (isDebug && !rp.replace.equals(tmp)) { - System.err.printf("\t[DEBUG] Staged '%s' -> '%s'\t%s\n", + if (ropts.isTrace && !rp.replace.equals(tmp)) { + ropts.errStream.printf("\t[DEBUG] Staged '%s' -> '%s'\t%s\n", rp.replace, tmp, curPar); } @@ -539,15 +358,15 @@ public class ReplPair implements Comparable, UnaryOperator { // If we're external; add straight to the output if (rp.stat == StageStatus.EXTERNAL) { - if (isDebug) { - System.err.printf("\t[DEBUG] Skipped external for staging: %s\n", + if (ropts.isTrace) { + ropts.errStream.printf("\t[DEBUG] Skipped external for staging: %s\n", rp); } detals.add(rp); } else { - if (isDebug) { - System.err.printf("\t[DEBUG] Added to stage %d: %s\n\t\tContents: %s\n", + if (ropts.isTrace) { + ropts.errStream.printf("\t[DEBUG] Added to stage %d: %s\n\t\tContents: %s\n", procStg, rp, curStage); } @@ -562,7 +381,7 @@ public class ReplPair implements Comparable, UnaryOperator { // Copy over to output, excluding internals for (ReplPair rp : tmpList) { if (rp.stat == StageStatus.INTERNAL) { - if (isDebug) System.err.printf("\t[DEBUG] Excluded internal: %s\n", rp); + if (ropts.isTrace) ropts.errStream.printf("\t[DEBUG] Excluded internal: %s\n", rp); continue; } @@ -572,13 +391,51 @@ public class ReplPair implements Comparable, UnaryOperator { detals.sort(null); - if (isDebug) { - System.err.printf("\t[DEBUG] Final output: %s\n", detals); + if (ropts.isTrace) { + ropts.errStream.printf("\t[DEBUG] Final output: %s\n", detals); } return detals; } + private static String readMultiLine(String lead, Scanner src, ReplOpts ropts, + List errs, String typ, IntHolder lno) { + String tmp = lead; + + if (ropts.isTrace && tmp.endsWith("\\")) + ropts.errStream.printf("\t[TRACE] Starting multi-line parse for %s '%s'\n", typ, tmp); + + boolean didMulti = tmp.endsWith("\\"); + while (tmp.endsWith("\\")) { + boolean incNL = tmp.endsWith("|\\"); + + if (!src.hasNextLine()) break; + + String nxt = src.nextLine().trim(); + lno.incr(); + + if (nxt.startsWith("#")) continue; + + String nlStr = incNL ? "\n" : ""; + + if (tmp.endsWith("\\")) { + if (incNL) { + tmp = tmp.substring(0, tmp.length() - 2); + } else { + tmp = tmp.substring(0, tmp.length() - 1); + } + } + + tmp = String.format("%s%s%s", tmp, nlStr, nxt); + } + + if (ropts.isTrace && didMulti) + ropts.errStream.printf("\t[TRACE] Finished multi-line parse for %s:\n%s\n.\n", + typ, tmp); + + return tmp; + } + @Override public String apply(String inp) { return inp.replaceAll(find, replace); @@ -592,11 +449,293 @@ public class ReplPair implements Comparable, UnaryOperator { return String.format("%ss/%s/%s/p(%d)", nameStr, find, replace, priority); } - + @Override public int compareTo(ReplPair rp) { if (this.priority == rp.priority) return this.lno - rp.lno; 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 + + return true; + } + + private static String readName(String nam, Scanner scn, List errs, + ReplPair rp, ReplOpts ropts, IntHolder lno, IntHolder pno) { + String name = nam; + + boolean isMulti = ropts.defMulti; + + // Name has attached controls, process them. + if (name.startsWith("//")) { + name = name.substring(2); + + String[] nameBits = StringUtils.escapeSplit("|", "//", name); + + if (nameBits.length < 2) { + String msg = "Did not find control terminator (//) in name where it should be"; + + 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); + + if (bots.length > 1) { + bitHead = bots[0].toUpperCase(); + bitBody = bots[1]; + } + + 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)); + + break; + } + 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; + } + + 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; + } + } + + return name; + } + + private static void readGlobal(String nam, Scanner scn, List errs, + ReplOpts ropts, IntHolder lno, IntHolder pno) { + String name = nam.substring(3); + + // 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) { + case "PRIORITY": + case "PRIOR": + case "P": + try { + int tmp = Integer.parseInt(bitBody); + ropts.defPrior = tmp; + } 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)); + break; + } + ropts.defStage = 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": + ropts.defMulti = true; + break; + case "MULTIFALSE": + case "MULTIF": + case "MF": + ropts.defMulti = false; + break; + case "MULTI": + case "M": + ropts.defMulti = Boolean.parseBoolean(bitBody); + break; + case "INTERNAL": + case "INT": + case "I": + ropts.defStatus = StageStatus.INTERNAL; + break; + case "EXTERNAL": + case "EXT": + case "E": + ropts.defStatus = StageStatus.EXTERNAL; + break; + case "BOTH": + case "B": + ropts.defStatus = StageStatus.BOTH; + break; + case "DEBUGTRUE": + case "DEBUGT": + case "DT": + ropts.isDebug = true; + break; + case "DEBUGFALSE": + case "DEBUGF": + case "DF": + ropts.isDebug = false; + break; + case "DEBUG": + case "D": + ropts.isDebug = Boolean.parseBoolean(bitBody); + break; + case "TRACETRUE": + case "TRACET": + case "TT": + ropts.isTrace = true; + break; + case "TRACEFALSE": + case "TRACEF": + case "TF": + ropts.isTrace = false; + break; + case "TRACE": + case "T": + ropts.isTrace = Boolean.parseBoolean(bitBody); + break; + case "PERFTRUE": + case "PERFT": + case "PRFT": + ropts.isPerf = true; + break; + case "PERFFALSE": + case "PERFF": + case "PRFF": + ropts.isPerf = false; + break; + case "PERF": + case "PRF": + ropts.isPerf = Boolean.parseBoolean(bitBody); + break; + default: + { + String msg = String.format("Invalid global control name '%s'", bitHead); + ReplError err = new ReplError(lno, pno, msg, name); + errs.add(err); + } + break; + } + + if (ropts.isTrace) + ropts.errStream.printf("\t[TRACE] Processed global control '%s':'%s'\n", + bitHead, bitBody); + } + + return; + } } -- cgit v1.2.3