summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Culkin <scorpress@gmail.com>2022-08-16 23:05:19 -0400
committerBen Culkin <scorpress@gmail.com>2022-08-16 23:05:19 -0400
commitbdce1524bf06679573ed1875196bf43f4664fe91 (patch)
tree4c270949f5fdfa984479785c2a57026fddbedecb
parentfc9a76f62faef95912d4cf4906f229ccd909d2dc (diff)
General cleanup
-rw-r--r--src/main/java/bjc/inflexion/DirectiveIterator.java128
-rw-r--r--src/main/java/bjc/inflexion/DirectiveType.java45
-rw-r--r--src/main/java/bjc/inflexion/InflectionDirective.java291
-rw-r--r--src/main/java/bjc/inflexion/InflectionFormatException.java83
-rw-r--r--src/main/java/bjc/inflexion/InflectionML.java4
-rw-r--r--src/main/java/bjc/inflexion/InflectionString.java805
-rw-r--r--src/main/java/bjc/inflexion/NounOptions.java96
-rw-r--r--src/main/java/bjc/inflexion/NumericOptions.java248
-rw-r--r--src/main/java/bjc/inflexion/Options.java26
-rw-r--r--src/test/java/bjc/inflexion/InflectionMLTest.java8
10 files changed, 936 insertions, 798 deletions
diff --git a/src/main/java/bjc/inflexion/DirectiveIterator.java b/src/main/java/bjc/inflexion/DirectiveIterator.java
new file mode 100644
index 0000000..9fbed79
--- /dev/null
+++ b/src/main/java/bjc/inflexion/DirectiveIterator.java
@@ -0,0 +1,128 @@
+/**
+ * (C) Copyright 2022 Benjamin Culkin.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package bjc.inflexion;
+
+import java.util.Iterator;
+
+/**
+ * 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 < 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 similar here?
+ */
+ if (level > 0)
+ throw new IllegalArgumentException(
+ "Unclosed inflection directive, starting at position " + prevPos
+ + " in string '" + strang + "'");
+
+ return strang.substring(prevPos, pos);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/bjc/inflexion/DirectiveType.java b/src/main/java/bjc/inflexion/DirectiveType.java
new file mode 100644
index 0000000..51be06b
--- /dev/null
+++ b/src/main/java/bjc/inflexion/DirectiveType.java
@@ -0,0 +1,45 @@
+/**
+ * (C) Copyright 2022 Benjamin Culkin.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package bjc.inflexion;
+
+/**
+ * The type of the directive in the inflection string.
+ *
+ * @author bjculkin
+ *
+ */
+public enum DirectiveType {
+ /**
+ * A literal string. Not inflected in any way.
+ */
+ LITERAL,
+ /**
+ * A variable reference. Not inflected in any way.
+ */
+ VARIABLE,
+ /**
+ * Sets the current number.
+ */
+ NUMERIC,
+ /**
+ * Prints an inflected noun.
+ */
+ NOUN,
+ /**
+ * Represents a sequence of directives.
+ */
+ SEQ
+} \ No newline at end of file
diff --git a/src/main/java/bjc/inflexion/InflectionDirective.java b/src/main/java/bjc/inflexion/InflectionDirective.java
new file mode 100644
index 0000000..27183c0
--- /dev/null
+++ b/src/main/java/bjc/inflexion/InflectionDirective.java
@@ -0,0 +1,291 @@
+/**
+ * (C) Copyright 2022 Benjamin Culkin.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package bjc.inflexion;
+
+import static java.util.Arrays.asList;
+
+import java.util.List;
+
+/**
+ * Represents a directive in a inflection string.
+ *
+ * @author bjculkin
+ *
+ */
+public final class InflectionDirective {
+ /**
+ * Emit error message
+ *
+ * @param dir The directive causing the error
+ * @param curPos The position in the string
+ * @param i The current index
+ * @param msg The detail message
+ * @param props Properties for the detail message.
+ *
+ * @return A properly formatted error message
+ */
+ public static String error(String dir, int curPos, int i, String msg,
+ Object... props) {
+ return String.format(
+ "%s (at position %d in %s directive starting at position %d)",
+ String.format(msg, props), curPos + i, dir, curPos);
+ }
+
+ /**
+ * The type of the directive.
+ */
+ public final DirectiveType type;
+
+ /**
+ * The string value of the directive.
+ *
+ * Currently, set for literals and variable references, as well as nouns.
+ */
+ public String litString;
+
+ /**
+ * The integer value of the directive.
+ *
+ * Currently set for numeric values.
+ */
+ public int numNumber;
+
+ /**
+ * Is this directives body referencing a variable instead of a literal?
+ */
+ public boolean isVRef = false;
+
+ /**
+ * The options for a directive.
+ */
+ public Options opts;
+
+ /**
+ * The directives contained in a sequence.
+ */
+ public List<InflectionDirective> listDir;
+
+ /**
+ * Create a new inflection directive.
+ *
+ * @param type
+ * The type of the directive.
+ */
+ public InflectionDirective(DirectiveType type) {
+ this.type = type;
+
+ switch (type) {
+ default:
+ throw new IllegalArgumentException(
+ "Unhandled or wrong arguments (none) for directive type " + type);
+ }
+ }
+
+ /**
+ * Create a new inflection directive.
+ *
+ * @param type
+ * The type of the directive.
+ * @param strang
+ * The string value for the directive.
+ */
+ public InflectionDirective(DirectiveType type, String strang) {
+ this.type = type;
+
+ // Set default options.
+ switch (type) {
+ case NUMERIC:
+ this.opts = new NumericOptions();
+ break;
+ case NOUN:
+ this.opts = new NounOptions();
+ break;
+ default:
+ // No options for these types
+ }
+
+ switch (type) {
+ case LITERAL:
+ case VARIABLE:
+ case NUMERIC: // Reference to a numeric variable
+ case NOUN:
+ this.litString = strang;
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Unhandled or wrong arguments (1 string) for directive type "
+ + type);
+
+ }
+ }
+
+ /**
+ * Create a new inflection directive.
+ *
+ * @param type
+ * The type of the directive.
+ * @param num
+ * The number value for the directive.
+ */
+ public InflectionDirective(DirectiveType type, int num) {
+ this.type = type;
+
+ switch (type) {
+ case NUMERIC:
+ this.numNumber = num;
+ this.opts = new NumericOptions();
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Unhandled or wrong arguments (1 number) for directive type "
+ + type);
+
+ }
+ }
+
+ /**
+ * Create a new inflection directive.
+ *
+ * @param type
+ * The type of the directive.
+ * @param listDir
+ * The directive list value for the directive.
+ */
+ public InflectionDirective(DirectiveType type,
+ List<InflectionDirective> listDir) {
+ this.type = type;
+
+ switch (type) {
+ case SEQ:
+ this.listDir = listDir;
+ break;
+ default:
+ throw new IllegalArgumentException(
+ "Unhandled or wrong arguments (1 list of directives) for directive type "
+ + type);
+
+ }
+ }
+
+ /**
+ * Create a new literal directive.
+ *
+ * @param strang
+ * The literal string the directive represents.
+ * @return A literal directive for the given string.
+ */
+ public static InflectionDirective literal(String strang) {
+ return new InflectionDirective(DirectiveType.LITERAL, strang);
+ }
+
+ /**
+ * Create a new variable directive.
+ *
+ * @param strang
+ * The name of the variable to interpolate into the string.
+ * @return A directive that says to interpolate the given value.
+ */
+ public static InflectionDirective variable(String strang) {
+ return new InflectionDirective(DirectiveType.VARIABLE, strang);
+ }
+
+ /**
+ * Create a new numeric directive.
+ *
+ * @param num
+ * The value of the directive,
+ * @return A directive that sets the current number to the specific value.
+ */
+ public static InflectionDirective numeric(int num) {
+ return new InflectionDirective(DirectiveType.NUMERIC, num);
+ }
+
+ /**
+ * Create a new numeric directive.
+ *
+ * @param strang
+ * The name of a variable that holds the value of the directive,
+ * @return A directive that sets the current number to the specific value.
+ */
+ public static InflectionDirective numeric(String strang) {
+ return new InflectionDirective(DirectiveType.NUMERIC, strang);
+ }
+
+ /**
+ * Create a new noun directive.
+ *
+ * @param strang
+ * The noun, or the name of the variable for the noun.
+ * @return A directive that inflects the specified noun.
+ */
+ public static InflectionDirective noun(String strang) {
+ return new InflectionDirective(DirectiveType.NOUN, strang);
+ }
+
+ /**
+ * Create a sequenced set of directives.
+ *
+ * @param list
+ * The directives to sequence.
+ * @return A sequence directive.
+ */
+ public static InflectionDirective seq(List<InflectionDirective> list) {
+ return new InflectionDirective(DirectiveType.SEQ, list);
+ }
+
+ /**
+ * Create a sequenced set of directives.
+ *
+ * @param arr
+ * The directives to sequence.
+ * @return A sequence directive.
+ */
+ public static InflectionDirective seq(InflectionDirective... arr) {
+ return new InflectionDirective(DirectiveType.SEQ, asList(arr));
+ }
+
+ /**
+ * Set the numeric options for this directive.
+ *
+ * @param numOpts
+ * The numeric options of the directive.
+ * @return The directive.
+ */
+ public InflectionDirective options(NumericOptions numOpts) {
+ if (type != DirectiveType.NUMERIC)
+ throw new IllegalArgumentException(
+ "Directive type " + type + " does not take numeric options");
+ this.opts = numOpts;
+
+ return this;
+ }
+
+ /**
+ * Set the noun options for this directive.
+ *
+ * @param nounOpts
+ * The noun options of the directive.
+ * @return The directive.
+ */
+ public InflectionDirective options(NounOptions nounOpts) {
+ if (type != DirectiveType.NOUN)
+ throw new IllegalArgumentException(
+ "Directive type " + type + " does not take noun options");
+ this.opts = nounOpts;
+
+ return this;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/bjc/inflexion/InflectionFormatException.java b/src/main/java/bjc/inflexion/InflectionFormatException.java
new file mode 100644
index 0000000..f4b4329
--- /dev/null
+++ b/src/main/java/bjc/inflexion/InflectionFormatException.java
@@ -0,0 +1,83 @@
+/**
+ * (C) Copyright 2022 Benjamin Culkin.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package bjc.inflexion;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Exception thrown if the string we are attempting to compile has invalid
+ * syntax.
+ *
+ * @author bjculkin
+ *
+ */
+public class InflectionFormatException extends RuntimeException {
+ private static final long serialVersionUID = -5306003088746525691L;
+
+ /**
+ * The string we attempted to parse.
+ */
+ public final String inp;
+
+ /**
+ * The errors we encountered parsing the string.
+ */
+ public final List<String> parseErrors;
+
+ /**
+ * Create a new format exception.
+ *
+ * @param inp
+ * The string we are attempting to compile
+ * @param parseErrors
+ * The errors we encountered parsing the string.
+ */
+ public InflectionFormatException(String inp, List<String> parseErrors) {
+ this.inp = inp;
+ // Can't modify the list of parse errors.
+ this.parseErrors = Collections.unmodifiableList(parseErrors);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Throwable#toString()
+ */
+ @Override
+ public String toString() {
+ boolean doBrief = false;
+
+ if (doBrief)
+ return String.format("Encountered %d errors attempting to parse string %s",
+ parseErrors.size(), inp);
+
+ StringBuilder sb = new StringBuilder(parseErrors.size());
+ sb.append("Encountered errors attempting to parse the following string:\n\t");
+ sb.append(inp);
+ sb.append("\nErrors:");
+ for (int i = 0; i < parseErrors.size(); i++) {
+ String msg = parseErrors.get(i);
+ sb.append("\n\t");
+ sb.append(msg);
+ }
+ sb.append("\n(total of ");
+ sb.append(parseErrors.size());
+ sb.append(" errors)");
+
+ return sb.toString();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/bjc/inflexion/InflectionML.java b/src/main/java/bjc/inflexion/InflectionML.java
index 34b534a..ae74c2e 100644
--- a/src/main/java/bjc/inflexion/InflectionML.java
+++ b/src/main/java/bjc/inflexion/InflectionML.java
@@ -103,7 +103,8 @@ public class InflectionML {
final Set<String> optionSet = new HashSet<>();
- boolean doCaseFold = false;
+ char ch = command.charAt(0);
+ boolean doCaseFold = Character.isUpperCase(ch);
final Map<Character, Integer> numOpts = new HashMap<>();
numOpts.put('w', 11);
@@ -265,6 +266,7 @@ public class InflectionML {
"Count setter must take a number as a parameter", nfex);
}
break;
+ case "n":
case "N":
final Noun noun = nounDB.getNoun(text);
diff --git a/src/main/java/bjc/inflexion/InflectionString.java b/src/main/java/bjc/inflexion/InflectionString.java
index 5c87771..1d739c3 100644
--- a/src/main/java/bjc/inflexion/InflectionString.java
+++ b/src/main/java/bjc/inflexion/InflectionString.java
@@ -14,16 +14,11 @@
*/
package bjc.inflexion;
-import static bjc.inflexion.InflectionString.InflectionDirective.literal;
-import static bjc.inflexion.InflectionString.InflectionDirective.noun;
-import static bjc.inflexion.InflectionString.InflectionDirective.numeric;
-import static bjc.inflexion.InflectionString.InflectionDirective.variable;
-import static java.util.Arrays.asList;
+import static bjc.inflexion.InflectionDirective.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
@@ -31,8 +26,6 @@ import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-import bjc.inflexion.InflectionString.InflectionDirective.NounOptions;
-import bjc.inflexion.InflectionString.InflectionDirective.NumericOptions;
import bjc.inflexion.nouns.Noun;
import bjc.inflexion.nouns.Nouns;
import bjc.inflexion.nouns.Prepositions;
@@ -44,786 +37,6 @@ import bjc.inflexion.nouns.Prepositions;
*
*/
public class InflectionString {
- /**
- * Exception thrown if the string we are attempting to compile has invalid
- * syntax.
- *
- * @author bjculkin
- *
- */
- public class InflectionFormatException extends RuntimeException {
- private static final long serialVersionUID = -5306003088746525691L;
-
- /**
- * The string we attempted to parse.
- */
- public final String inp;
-
- /**
- * The errors we encountered parsing the string.
- */
- public final List<String> parseErrors;
-
- /**
- * Create a new format exception.
- *
- * @param inp
- * The string we are attempting to compile
- * @param parseErrors
- * The errors we encountered parsing the string.
- */
- public InflectionFormatException(String inp, List<String> parseErrors) {
- this.inp = inp;
- // Can't modify the list of parse errors.
- this.parseErrors = Collections.unmodifiableList(parseErrors);
- }
-
- /*
- * (non-Javadoc)
- *
- * @see java.lang.Throwable#toString()
- */
- @Override
- public String toString() {
- boolean doBrief = false;
-
- if (doBrief)
- return String.format("Encountered %d errors attempting to parse string %s",
- parseErrors.size(), inp);
-
- StringBuilder sb = new StringBuilder(parseErrors.size());
- sb.append("Encountered errors attempting to parse the following string:\n\t");
- sb.append(inp);
- sb.append("\nErrors:");
- for (int i = 0; i < parseErrors.size(); i++) {
- String msg = parseErrors.get(i);
- sb.append("\n\t");
- sb.append(msg);
- }
- sb.append("\n(total of ");
- sb.append(parseErrors.size());
- sb.append(" errors)");
-
- return sb.toString();
- }
- }
-
- /**
- * Represents a directive in a inflection string.
- *
- * @author bjculkin
- *
- */
- public static final class InflectionDirective {
- /**
- * The type of the directive in the inflection string.
- *
- * @author bjculkin
- *
- */
- public static enum DirectiveType {
- /**
- * A literal string. Not inflected in any way.
- */
- LITERAL,
- /**
- * A variable reference. Not inflected in any way.
- */
- VARIABLE,
- /**
- * Sets the current number.
- */
- NUMERIC,
- /**
- * Prints an inflected noun.
- */
- NOUN,
- /**
- * Represents a sequence of directives.
- */
- SEQ
- }
-
- /**
- * Empty base class for directive options.
- *
- * @author bjculkin
- *
- */
- public static class Options {
- // Empty Base Class
- }
-
- /**
- * Options for a numeric directive.
- *
- * @author bjculkin
- *
- */
- public static class NumericOptions extends Options {
- /**
- * Increment the numeric value before doing anything with it.
- *
- * Corresponds to the 'i' option.
- */
- public boolean increment;
- /**
- * Amount to increase the value by.
- *
- * Attached to the 'i' option.
- */
- public int incrementAmt = 1;
-
- /**
- * Treat zero as singular.
- *
- * Doesn't correspond directly to the 's' option, but splitting between
- * singular zero and using 'no' for zero is useful.
- */
- public boolean singular;
-
- /**
- * Print zero as 'no'.
- *
- * Corresponds to 'n' option.
- */
- public boolean zeroNo;
-
- /**
- * Print 'a'/'an' for one.
- *
- * Corresponds to 'a' option.
- */
- public boolean article;
-
- /**
- * Don't print any text.
- *
- * Corresponds to 'd' option.
- */
- public boolean nonPrint;
-
- /**
- * Print the number as a cardinal.
- *
- * Corresponds to 'w' option.
- */
- public boolean cardinal;
- /**
- * Threshold for when to stop printing the number as a cardinal.
- *
- * Attached to the 'w' and 'o' options.
- */
- public int cardinalThresh = 11;
-
- /**
- * Print the number as an ordinal.
- *
- * Corresponds to the 'o' option.
- */
- public boolean ordinal;
- /**
- * Threshold for when to stop printing the number as an ordinal.
- *
- * If the current count is greater than 'cardinalThresh', ordinals like 1st
- * and 2nd will be printed instead of first and second.
- *
- * Attached to the 'o' option.
- */
- public int ordinalThresh = Integer.MAX_VALUE;
-
- /**
- * Summarize a number.
- *
- * Corresponds to the 'f' option.
- */
- public boolean summarize;
-
- /**
- * Mark the summarization as occurring at the end of the string, regardless of
- * its current position.
- */
- public boolean atEnd = false;
-
- /**
- * Create a new set of numeric options from a string.
- *
- * @param options
- * The string to create options from.
- * @param curPos
- * The current position into the string.
- * @param parseErrors
- * The current list of parsing errors.
- */
- public NumericOptions(String options, int curPos, List<String> parseErrors) {
- if (options.equals(""))
- return;
-
- char prevOption = ' ';
- StringBuilder currNum = new StringBuilder();
-
- boolean doingCaseFolding = false;
-
- for (int i = 0; i < options.length(); i++) {
- char ci = options.charAt(i);
-
- if (Character.isDigit(ci) || ci == '-' || ci == '+') {
- currNum.append(ci);
-
- continue;
- }
-
- if (doingCaseFolding && Character.isLowerCase(ci)) {
- continue;
- } else if (Character.isUpperCase(ci)) {
- doingCaseFolding = true;
-
- ci = Character.toLowerCase(ci);
- }
-
- if (currNum.length() > 0) {
- parseNumericParam(curPos, parseErrors, prevOption, currNum, i);
-
- currNum = new StringBuilder();
- }
-
- switch (ci) {
- case 'n':
- zeroNo = true;
- break;
- case 's':
- singular = true;
- break;
- case 'a':
- article = true;
- break;
- case 'w':
- cardinal = true;
- break;
- case 'o':
- ordinal = true;
- break;
- case 'f':
- summarize = true;
- break;
- case 'e':
- article = true;
- singular = true;
- zeroNo = true;
- cardinal = true;
- break;
- case 'i':
- increment = true;
- break;
- case 'd':
- nonPrint = true;
- break;
- default:
- parseErrors.add(error(curPos, i, "Unhandled option %c", ci));
- }
-
- prevOption = ci;
- }
-
- if (currNum.length() > 0) {
- parseNumericParam(curPos, parseErrors, prevOption, currNum,
- options.length() - 1);
-
- currNum = new StringBuilder();
- }
- }
-
- /**
- * Create a blank set of numeric options.
- */
- public NumericOptions() {
- }
-
- private void parseNumericParam(int curPos, List<String> parseErrors,
- char prevOption, StringBuilder currNum, int i) {
- int nVal = 0;
- try {
- nVal = Integer.parseInt(currNum.toString());
- } catch (NumberFormatException nfex) {
- parseErrors.add(error(curPos, i,
- "Improperly formatted numeric parameter %s to option '%c'",
- currNum.toString(), prevOption));
- }
- switch (prevOption) {
- case 'w':
- cardinalThresh = nVal;
- break;
- case 'o':
- ordinalThresh = nVal;
- break;
- case 'f':
- if (nVal == 1) {
- atEnd = true;
- } else if (nVal == 0) {
- atEnd = false;
- } else {
- parseErrors.add(error(curPos, i,
- "'f' parameter only takes parameters of zero or one, not %d",
- nVal));
- }
- break;
- case 'i':
- incrementAmt = nVal;
- break;
- default:
- parseErrors.add(error(curPos, i,
- "Option '%c' does not take a numeric parameter (value %s)",
- prevOption, currNum));
- }
- }
-
- // Emit error message
- private static String error(int curPos, int i, String msg, Object... props) {
- return InflectionDirective.error("#", curPos, i, msg, props);
- }
- }
-
- /**
- * Options for a noun directive.
- *
- * @author bjculkin
- *
- */
- public static class NounOptions extends Options {
- /**
- * Use the classical inflection for the noun.
- */
- public boolean classical;
-
- /**
- * Inflect as plural, regardless of current count.
- */
- public boolean plural;
-
- /**
- * Inflect as singular, regardless of current count.
- */
- public boolean singular;
-
- /**
- * Create a new set of noun options from a string.
- *
- * @param options
- * The string to create options from.
- * @param curPos
- * The current position into the string.
- * @param parseErrors
- * The current list of parsing errors.
- */
- public NounOptions(String options, int curPos, List<String> parseErrors) {
- if (options.equals(""))
- return;
-
- boolean doingCaseFolding = false;
-
- for (int i = 0; i < options.length(); i++) {
- char ci = options.charAt(i);
-
- if (doingCaseFolding && Character.isLowerCase(ci)) {
- continue;
- } else if (Character.isUpperCase(ci)) {
- doingCaseFolding = true;
-
- ci = Character.toLowerCase(ci);
- }
-
- switch (ci) {
- case 'c':
- classical = true;
- break;
- case 'p':
- plural = true;
- break;
- case 's':
- singular = true;
- break;
- default:
- parseErrors.add(error(curPos, i, "Unhandled option %c", ci));
- }
- }
- }
-
- /**
- * Create an empty set of noun options.
- */
- public NounOptions() {
- }
-
- // Emit error message
- private static String error(int curPos, int i, String msg, Object... props) {
- return InflectionDirective.error("N", curPos, i, msg, props);
- }
- }
-
- // Emit error message
- private static String error(String dir, int curPos, int i, String msg,
- Object... props) {
- return String.format(
- "%s (at position %d in %s directive starting at position %d)",
- String.format(msg, props), curPos + i, dir, curPos);
- }
-
- /**
- * The type of the directive.
- */
- public final DirectiveType type;
-
- /**
- * The string value of the directive.
- *
- * Currently, set for literals and variable references, as well as nouns.
- */
- public String litString;
-
- /**
- * The integer value of the directive.
- *
- * Currently set for numeric values.
- */
- public int numNumber;
-
- /**
- * Is this directives body referencing a variable instead of a literal?
- */
- public boolean isVRef = false;
-
- /**
- * The options for a directive.
- */
- public Options opts;
-
- /**
- * The directives contained in a sequence.
- */
- public List<InflectionDirective> listDir;
-
- /**
- * Create a new inflection directive.
- *
- * @param type
- * The type of the directive.
- */
- public InflectionDirective(DirectiveType type) {
- this.type = type;
-
- switch (type) {
- default:
- throw new IllegalArgumentException(
- "Unhandled or wrong arguments (none) for directive type " + type);
- }
- }
-
- /**
- * Create a new inflection directive.
- *
- * @param type
- * The type of the directive.
- * @param strang
- * The string value for the directive.
- */
- public InflectionDirective(DirectiveType type, String strang) {
- this.type = type;
-
- // Set default options.
- switch (type) {
- case NUMERIC:
- this.opts = new NumericOptions();
- break;
- case NOUN:
- this.opts = new NounOptions();
- break;
- default:
- // No options for these types
- }
-
- switch (type) {
- case LITERAL:
- case VARIABLE:
- case NUMERIC: // Reference to a numeric variable
- case NOUN:
- this.litString = strang;
- break;
- default:
- throw new IllegalArgumentException(
- "Unhandled or wrong arguments (1 string) for directive type "
- + type);
-
- }
- }
-
- /**
- * Create a new inflection directive.
- *
- * @param type
- * The type of the directive.
- * @param num
- * The number value for the directive.
- */
- public InflectionDirective(DirectiveType type, int num) {
- this.type = type;
-
- switch (type) {
- case NUMERIC:
- this.numNumber = num;
- this.opts = new NumericOptions();
- break;
- default:
- throw new IllegalArgumentException(
- "Unhandled or wrong arguments (1 number) for directive type "
- + type);
-
- }
- }
-
- /**
- * Create a new inflection directive.
- *
- * @param type
- * The type of the directive.
- * @param listDir
- * The directive list value for the directive.
- */
- public InflectionDirective(DirectiveType type,
- List<InflectionDirective> listDir) {
- this.type = type;
-
- switch (type) {
- case SEQ:
- this.listDir = listDir;
- break;
- default:
- throw new IllegalArgumentException(
- "Unhandled or wrong arguments (1 list of directives) for directive type "
- + type);
-
- }
- }
-
- /**
- * Create a new literal directive.
- *
- * @param strang
- * The literal string the directive represents.
- * @return A literal directive for the given string.
- */
- public static InflectionDirective literal(String strang) {
- return new InflectionDirective(DirectiveType.LITERAL, strang);
- }
-
- /**
- * Create a new variable directive.
- *
- * @param strang
- * The name of the variable to interpolate into the string.
- * @return A directive that says to interpolate the given value.
- */
- public static InflectionDirective variable(String strang) {
- return new InflectionDirective(DirectiveType.VARIABLE, strang);
- }
-
- /**
- * Create a new numeric directive.
- *
- * @param num
- * The value of the directive,
- * @return A directive that sets the current number to the specific value.
- */
- public static InflectionDirective numeric(int num) {
- return new InflectionDirective(DirectiveType.NUMERIC, num);
- }
-
- /**
- * Create a new numeric directive.
- *
- * @param strang
- * The name of a variable that holds the value of the directive,
- * @return A directive that sets the current number to the specific value.
- */
- public static InflectionDirective numeric(String strang) {
- return new InflectionDirective(DirectiveType.NUMERIC, strang);
- }
-
- /**
- * Create a new noun directive.
- *
- * @param strang
- * The noun, or the name of the variable for the noun.
- * @return A directive that inflects the specified noun.
- */
- public static InflectionDirective noun(String strang) {
- return new InflectionDirective(DirectiveType.NOUN, strang);
- }
-
- /**
- * Create a sequenced set of directives.
- *
- * @param list
- * The directives to sequence.
- * @return A sequence directive.
- */
- public static InflectionDirective seq(List<InflectionDirective> list) {
- return new InflectionDirective(DirectiveType.SEQ, list);
- }
-
- /**
- * Create a sequenced set of directives.
- *
- * @param arr
- * The directives to sequence.
- * @return A sequence directive.
- */
- public static InflectionDirective seq(InflectionDirective... arr) {
- return new InflectionDirective(DirectiveType.SEQ, asList(arr));
- }
-
- /**
- * Set the numeric options for this directive.
- *
- * @param numOpts
- * The numeric options of the directive.
- * @return The directive.
- */
- public InflectionDirective options(NumericOptions numOpts) {
- if (type != DirectiveType.NUMERIC)
- throw new IllegalArgumentException(
- "Directive type " + type + " does not take numeric options");
- this.opts = numOpts;
-
- return this;
- }
-
- /**
- * Set the noun options for this directive.
- *
- * @param nounOpts
- * The noun options of the directive.
- * @return The directive.
- */
- public InflectionDirective options(NounOptions nounOpts) {
- if (type != DirectiveType.NOUN)
- throw new IllegalArgumentException(
- "Directive type " + type + " does not take noun options");
- this.opts = nounOpts;
-
- return this;
- }
- }
-
- /**
- * 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 < 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;
@@ -896,19 +109,24 @@ public class InflectionString {
dir.isVRef = true;
} else if (strang.startsWith("<") && strang.endsWith(">")) {
String dirBody = strang.substring(2, strang.length() - 1);
+ char dirName = strang.charAt(1);
int idx = dirBody.indexOf(":");
if (idx == -1)
parseErrors.add(error(strang, curPos, "Missing body for %c directive",
- strang.charAt(1)));
+ dirName));
String options = dirBody.substring(0, idx);
dirBody = dirBody.substring(idx + 1);
- switch (strang.charAt(1)) {
+ boolean startFold = false;
+ if (Character.isUpperCase(dirName)) {
+ startFold = true;
+ }
+ switch (dirName) {
case '#': {
NumericOptions numOpts
- = new NumericOptions(options, curPos, parseErrors);
+ = new NumericOptions(options, curPos, startFold, parseErrors);
if (dirBody.startsWith("$")) {
dir = numeric(dirBody.substring(1));
@@ -926,8 +144,9 @@ public class InflectionString {
dir.options(numOpts);
}
break;
+ case 'n':
case 'N': {
- NounOptions nounOpts = new NounOptions(options, curPos, parseErrors);
+ NounOptions nounOpts = new NounOptions(options, curPos, startFold, parseErrors);
if (dirBody.startsWith("$")) {
dir = noun(dirBody.substring(1));
@@ -941,7 +160,7 @@ public class InflectionString {
break;
default:
parseErrors.add(error(strang, curPos, "Unhandled directive type %c",
- strang.charAt(1)));
+ dirName));
}
} else {
dir = literal(strang);
diff --git a/src/main/java/bjc/inflexion/NounOptions.java b/src/main/java/bjc/inflexion/NounOptions.java
new file mode 100644
index 0000000..273e700
--- /dev/null
+++ b/src/main/java/bjc/inflexion/NounOptions.java
@@ -0,0 +1,96 @@
+/**
+ * (C) Copyright 2022 Benjamin Culkin.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package bjc.inflexion;
+
+import java.util.List;
+
+/**
+ * Options for a noun directive.
+ *
+ * @author bjculkin
+ *
+ */
+public class NounOptions extends Options {
+ /**
+ * Use the classical inflection for the noun.
+ */
+ public boolean classical;
+
+ /**
+ * Inflect as plural, regardless of current count.
+ */
+ public boolean plural;
+
+ /**
+ * Inflect as singular, regardless of current count.
+ */
+ public boolean singular;
+
+ /**
+ * Create a new set of noun options from a string.
+ *
+ * @param options
+ * The string to create options from.
+ * @param curPos
+ * The current position into the string.
+ * @param startFold Whether to start with folding on
+ * @param parseErrors
+ * The current list of parsing errors.
+ */
+ public NounOptions(String options, int curPos, boolean startFold, List<String> parseErrors) {
+ if (options.equals(""))
+ return;
+
+ boolean doingCaseFolding = startFold;
+
+ for (int i = 0; i < options.length(); i++) {
+ char ci = options.charAt(i);
+
+ if (doingCaseFolding && Character.isLowerCase(ci)) {
+ continue;
+ } else if (Character.isUpperCase(ci)) {
+ doingCaseFolding = true;
+
+ ci = Character.toLowerCase(ci);
+ }
+
+ switch (ci) {
+ case 'c':
+ classical = true;
+ break;
+ case 'p':
+ plural = true;
+ break;
+ case 's':
+ singular = true;
+ break;
+ default:
+ parseErrors.add(error(curPos, i, "Unhandled option %c", ci));
+ }
+ }
+ }
+
+ /**
+ * Create an empty set of noun options.
+ */
+ public NounOptions() {
+ }
+
+ // Emit error message
+ private static String error(int curPos, int i, String msg, Object... props) {
+ return InflectionDirective.error("N", curPos, i, msg, props);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/bjc/inflexion/NumericOptions.java b/src/main/java/bjc/inflexion/NumericOptions.java
new file mode 100644
index 0000000..179c669
--- /dev/null
+++ b/src/main/java/bjc/inflexion/NumericOptions.java
@@ -0,0 +1,248 @@
+/**
+ * (C) Copyright 2022 Benjamin Culkin.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package bjc.inflexion;
+
+import java.util.List;
+
+/**
+ * Options for a numeric directive.
+ *
+ * @author bjculkin
+ *
+ */
+public class NumericOptions extends Options {
+ /**
+ * Increment the numeric value before doing anything with it.
+ *
+ * Corresponds to the 'i' option.
+ */
+ public boolean increment;
+ /**
+ * Amount to increase the value by.
+ *
+ * Attached to the 'i' option.
+ */
+ public int incrementAmt = 1;
+
+ /**
+ * Treat zero as singular.
+ *
+ * Doesn't correspond directly to the 's' option, but splitting between
+ * singular zero and using 'no' for zero is useful.
+ */
+ public boolean singular;
+
+ /**
+ * Print zero as 'no'.
+ *
+ * Corresponds to 'n' option.
+ */
+ public boolean zeroNo;
+
+ /**
+ * Print 'a'/'an' for one.
+ *
+ * Corresponds to 'a' option.
+ */
+ public boolean article;
+
+ /**
+ * Don't print any text.
+ *
+ * Corresponds to 'd' option.
+ */
+ public boolean nonPrint;
+
+ /**
+ * Print the number as a cardinal.
+ *
+ * Corresponds to 'w' option.
+ */
+ public boolean cardinal;
+ /**
+ * Threshold for when to stop printing the number as a cardinal.
+ *
+ * Attached to the 'w' and 'o' options.
+ */
+ public int cardinalThresh = 11;
+
+ /**
+ * Print the number as an ordinal.
+ *
+ * Corresponds to the 'o' option.
+ */
+ public boolean ordinal;
+ /**
+ * Threshold for when to stop printing the number as an ordinal.
+ *
+ * If the current count is greater than 'cardinalThresh', ordinals like 1st
+ * and 2nd will be printed instead of first and second.
+ *
+ * Attached to the 'o' option.
+ */
+ public int ordinalThresh = Integer.MAX_VALUE;
+
+ /**
+ * Summarize a number.
+ *
+ * Corresponds to the 'f' option.
+ */
+ public boolean summarize;
+
+ /**
+ * Mark the summarization as occurring at the end of the string, regardless of
+ * its current position.
+ */
+ public boolean atEnd = false;
+
+ /**
+ * Create a new set of numeric options from a string.
+ *
+ * @param options
+ * The string to create options from.
+ * @param curPos
+ * The current position into the string.
+ * @param startFold Whether to start with folding on
+ * @param parseErrors
+ * The current list of parsing errors.
+ */
+ public NumericOptions(String options, int curPos, boolean startFold, List<String> parseErrors) {
+ if (options.equals(""))
+ return;
+
+ char prevOption = ' ';
+ StringBuilder currNum = new StringBuilder();
+
+ boolean doingCaseFolding = startFold;
+
+ for (int i = 0; i < options.length(); i++) {
+ char ci = options.charAt(i);
+
+ if (Character.isDigit(ci) || ci == '-' || ci == '+') {
+ currNum.append(ci);
+
+ continue;
+ }
+
+ if (doingCaseFolding && Character.isLowerCase(ci)) {
+ continue;
+ } else if (Character.isUpperCase(ci)) {
+ doingCaseFolding = true;
+
+ ci = Character.toLowerCase(ci);
+ }
+
+ if (currNum.length() > 0) {
+ parseNumericParam(curPos, parseErrors, prevOption, currNum, i);
+
+ currNum = new StringBuilder();
+ }
+
+ switch (ci) {
+ case 'n':
+ zeroNo = true;
+ break;
+ case 's':
+ singular = true;
+ break;
+ case 'a':
+ article = true;
+ break;
+ case 'w':
+ cardinal = true;
+ break;
+ case 'o':
+ ordinal = true;
+ break;
+ case 'f':
+ summarize = true;
+ break;
+ case 'e':
+ article = true;
+ singular = true;
+ zeroNo = true;
+ cardinal = true;
+ break;
+ case 'i':
+ increment = true;
+ break;
+ case 'd':
+ nonPrint = true;
+ break;
+ default:
+ parseErrors.add(error(curPos, i, "Unhandled option %c", ci));
+ }
+
+ prevOption = ci;
+ }
+
+ if (currNum.length() > 0) {
+ parseNumericParam(curPos, parseErrors, prevOption, currNum,
+ options.length() - 1);
+
+ currNum = new StringBuilder();
+ }
+ }
+
+ /**
+ * Create a blank set of numeric options.
+ */
+ public NumericOptions() {
+ }
+
+ private void parseNumericParam(int curPos, List<String> parseErrors,
+ char prevOption, StringBuilder currNum, int i) {
+ int nVal = 0;
+ try {
+ nVal = Integer.parseInt(currNum.toString());
+ } catch (NumberFormatException nfex) {
+ parseErrors.add(error(curPos, i,
+ "Improperly formatted numeric parameter %s to option '%c'",
+ currNum.toString(), prevOption));
+ }
+ switch (prevOption) {
+ case 'w':
+ cardinalThresh = nVal;
+ break;
+ case 'o':
+ ordinalThresh = nVal;
+ break;
+ case 'f':
+ if (nVal == 1) {
+ atEnd = true;
+ } else if (nVal == 0) {
+ atEnd = false;
+ } else {
+ parseErrors.add(error(curPos, i,
+ "'f' parameter only takes parameters of zero or one, not %d",
+ nVal));
+ }
+ break;
+ case 'i':
+ incrementAmt = nVal;
+ break;
+ default:
+ parseErrors.add(error(curPos, i,
+ "Option '%c' does not take a numeric parameter (value %s)",
+ prevOption, currNum));
+ }
+ }
+
+ // Emit error message
+ private static String error(int curPos, int i, String msg, Object... props) {
+ return InflectionDirective.error("#", curPos, i, msg, props);
+ }
+} \ No newline at end of file
diff --git a/src/main/java/bjc/inflexion/Options.java b/src/main/java/bjc/inflexion/Options.java
new file mode 100644
index 0000000..1cbdaa7
--- /dev/null
+++ b/src/main/java/bjc/inflexion/Options.java
@@ -0,0 +1,26 @@
+/**
+ * (C) Copyright 2022 Benjamin Culkin.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package bjc.inflexion;
+
+/**
+ * Empty base class for directive options.
+ *
+ * @author bjculkin
+ *
+ */
+public class Options {
+ // Empty Base Class
+} \ No newline at end of file
diff --git a/src/test/java/bjc/inflexion/InflectionMLTest.java b/src/test/java/bjc/inflexion/InflectionMLTest.java
index 54ee170..663859a 100644
--- a/src/test/java/bjc/inflexion/InflectionMLTest.java
+++ b/src/test/java/bjc/inflexion/InflectionMLTest.java
@@ -77,7 +77,7 @@ public class InflectionMLTest {
pair("Found a few matches", 4), pair("Found several matches", 8),
pair("Found many matches", 11));
- assertInflects("Searching for <Np:items>....found <#f1:%d>",
+ assertInflects("Searching for <np:items>....found <#f1:%d>",
pair("Searching for items....found none", 0),
pair("Searching for items....found one", 1),
pair("Searching for items....found a couple", 2),
@@ -109,7 +109,7 @@ public class InflectionMLTest {
pair("7 corpuses found", 7, "corpuses"),
pair("7 brothers found", 7, "brothers"));
- assertInflects("<#:%d> <Nc:%s> found", pair("7 maxima found", 7, "maximum"),
+ assertInflects("<#:%d> <nc:%s> found", pair("7 maxima found", 7, "maximum"),
pair("7 formulae found", 7, "formula"),
pair("7 corpora found", 7, "corpus"),
pair("7 brethren found", 7, "brother"));
@@ -190,7 +190,7 @@ public class InflectionMLTest {
// FIXME Don't require spaces to mark out directives.
// - Ben Culkin, 10/28/18
- assertCInflects("Searching for <Np:items> ....found <#f1:$1>",
+ assertCInflects("Searching for <np:items> ....found <#f1:$1>",
pair("Searching for items ....found none", 0),
pair("Searching for items ....found one", 1),
pair("Searching for items ....found a couple", 2),
@@ -222,7 +222,7 @@ public class InflectionMLTest {
pair("7 corpuses found", 7, "corpuses"),
pair("7 brothers found", 7, "brothers"));
- assertCInflects("<#:$1> <Nc:$2> found", pair("7 maxima found", 7, "maximum"),
+ assertCInflects("<#:$1> <nc:$2> found", pair("7 maxima found", 7, "maximum"),
pair("7 formulae found", 7, "formula"),
pair("7 corpora found", 7, "corpus"),
pair("7 brethren found", 7, "brother"));