summaryrefslogtreecommitdiff
path: root/src/main/java/bjc
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/bjc')
-rw-r--r--src/main/java/bjc/inflexion/InflectionString.java111
1 files changed, 105 insertions, 6 deletions
diff --git a/src/main/java/bjc/inflexion/InflectionString.java b/src/main/java/bjc/inflexion/InflectionString.java
index cb9e1be..486c93b 100644
--- a/src/main/java/bjc/inflexion/InflectionString.java
+++ b/src/main/java/bjc/inflexion/InflectionString.java
@@ -56,6 +56,7 @@ public class InflectionString {
* The string we attempted to parse.
*/
public final String inp;
+
/**
* The errors we encountered parsing the string.
*/
@@ -713,6 +714,108 @@ public class InflectionString {
}
}
+ /**
+ * Performs the parsing of directives from a string.
+ * @author bjculkin
+ */
+ public class DirectiveIterator implements Iterator<String> {
+ private String strang;
+ private int pos;
+
+ /**
+ * Create a new directive iterator over a string.
+ *
+ * @param strang
+ * The string to parse directives from.
+ */
+ public DirectiveIterator(String strang) {
+ this.strang = strang;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return pos < strang.length();
+ }
+
+ @Override
+ public String next() {
+ if (!hasNext()) return null;
+
+ // Directive nesting level
+ int level = 0;
+ int prevPos = pos;;
+
+ char prevChar = ' ';
+ boolean parsingVar = false;
+
+ for (pos = pos; pos < strang.length(); pos++) {
+ // Backslash escapes a character
+ if (prevChar == '\\') continue;
+
+ char c = strang.charAt(pos);
+ switch (c) {
+ case '<':
+ // Stop parsing at the start of a
+ // directive, unless the directive is
+ // the first thing in the string.
+ if (level == 0 && prevPos != pos) {
+ return strang.substring(prevPos, pos);
+ }
+ level += 1;
+ break;
+ case '>':
+ // :ErrorHandling 11/19/18
+ if (level == 0) throw new IllegalArgumentException(
+ "Attempted to close inflection directive without one open at position " + prevPos + " in string '" + strang + "', current token is '" + strang.substring(prevPos, pos) + "'");
+ // Denest a level
+ level = Math.max(0, level - 1);
+ // Stop parsing at the end of a
+ // directive.
+ if (level == 0) {
+ // Advance past the '>'
+ pos += 1;
+
+ return strang.substring(prevPos, pos);
+
+ }
+ break;
+ case '$':
+ // Ignore v-refs when inside a directive
+ if (level > 0) break;
+ // Stop parsing if this isn't at the
+ // start of a string
+ if (prevPos != pos) return strang.substring(prevPos, pos);
+ parsingVar = true;
+ break;
+ case ' ':
+ // If we're parsing a v-ref, this
+ // finishes it.
+ if (parsingVar) return strang.substring(prevPos, pos);
+ break;
+ default:
+ // Do nothing for ordinary characters
+ break;
+ }
+ }
+
+ /* @TODO 11/19/18 Ben Culkin :ErrorHandling
+ * Do something better than this exception, if possible.
+ *
+ * In the rest of the inflection string code, we use the
+ * whole 'list of errors/warnings' thing. Is there a way
+ * to do something similiar here?
+ */
+ if (level > 0) throw new IllegalArgumentException("Unclosed inflection directive, starting at position " + prevPos + " in string '" + strang + "'");
+
+ return strang.substring(prevPos, pos);
+ }
+ }
+
+ // Create an iterable from an iterator
+ private static Iterable<String> I(Iterator<String> itr) {
+ return () -> itr;
+ }
+
// Marker for finding articles to replace
private static Pattern AN_MARKER = Pattern.compile("\\{an(\\d+)\\}");
@@ -761,16 +864,14 @@ public class InflectionString {
List<String> parseErrors = new ArrayList<>();
// Split input on spaces, preserving the delimiters
- for (String strang : inp.split("(?<=\\s+)|(?=\\s+)")) {
+ // for (String strang : inp.split("(?<=\\s+)|(?=\\s+)")) {
+ for (String strang : I(new DirectiveIterator(inp))) {
InflectionDirective dir = literal("<ERRROR>");
// Variables start with $
if (strang.startsWith("$")) {
dir = variable(strang.substring(1));
dir.isVRef = true;
- // A string starting with $ can be escaped
- } else if (strang.startsWith("\\$")) {
- dir = literal(strang.substring(2));
} else if (strang.startsWith("<") && strang.endsWith(">")) {
String dirBody = strang.substring(2, strang.length() - 1);
@@ -818,8 +919,6 @@ public class InflectionString {
parseErrors.add(error(strang, curPos, "Unhandled directive type %c",
strang.charAt(1)));
}
- } else if (strang.startsWith("\\<")) {
- dir = literal(strang.substring(2));
} else {
dir = literal(strang);
}