aboutsummaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/search/yql/ParameterListParser.java
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@gmail.com>2022-01-05 16:46:27 +0100
committerJon Bratseth <bratseth@gmail.com>2022-01-05 16:46:27 +0100
commit6ba07dc78811818b32c12af35456ea16c3ea46f4 (patch)
tree6b19f61cf32b13775e4d4a5d3f39248c7400b4c1 /container-search/src/main/java/com/yahoo/search/yql/ParameterListParser.java
parentfcce4873d66e5e5140fa470a22cbb3e752159ea2 (diff)
Support an external list of terms in term list operators
Diffstat (limited to 'container-search/src/main/java/com/yahoo/search/yql/ParameterListParser.java')
-rw-r--r--container-search/src/main/java/com/yahoo/search/yql/ParameterListParser.java204
1 files changed, 204 insertions, 0 deletions
diff --git a/container-search/src/main/java/com/yahoo/search/yql/ParameterListParser.java b/container-search/src/main/java/com/yahoo/search/yql/ParameterListParser.java
new file mode 100644
index 00000000000..5a609f0025b
--- /dev/null
+++ b/container-search/src/main/java/com/yahoo/search/yql/ParameterListParser.java
@@ -0,0 +1,204 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.search.yql;
+
+import com.yahoo.prelude.query.WeightedSetItem;
+
+import java.util.Arrays;
+
+/**
+ * Parser of parameter lists on the form {key:value, key:value} or [[key,value], [key,value], ...]
+ *
+ * @author bratseth
+ */
+class ParameterListParser {
+
+ public static void addItemsFromString(String string, WeightedSetItem out) {
+ var s = new ParsableString(string);
+ switch (s.peek()) {
+ case '[' : addArrayItems(s, out); break;
+ case '{' : addMapItems(s, out); break;
+ default : throw new IllegalArgumentException("Expected a string starting by '[' or '{', " +
+ "but was '" + s.peek() + "'");
+ }
+ }
+
+ private static void addArrayItems(ParsableString s, WeightedSetItem out) {
+ s.pass('[');
+ while (s.peek() != ']') {
+ s.pass('[');
+ long key = s.longTo(s.position(','));
+ s.pass(',');
+ int value = s.intTo(s.position(']'));
+ s.pass(']');
+ out.addToken(key, value);
+ s.passOptional(',');
+ if (s.atEnd()) throw new IllegalArgumentException("Expected an array ending by ']'");
+ }
+ s.pass(']');
+ }
+
+ private static void addMapItems(ParsableString s, WeightedSetItem out) {
+ s.pass('{');
+ while (s.peek() != '}') {
+ String key;
+ if (s.passOptional('\'')) {
+ key = s.stringTo(s.position('\''));
+ s.pass('\'');
+ }
+ else if (s.passOptional('"')) {
+ key = s.stringTo(s.position('"'));
+ s.pass('"');
+ }
+ else {
+ key = s.stringTo(s.position(':')).trim();
+ }
+ s.pass(':');
+ int value = s.intTo(s.position(',','}'));
+ out.addToken(key, value);
+ s.passOptional(',');
+ if (s.atEnd()) throw new IllegalArgumentException("Expected a map ending by '}'");
+ }
+ s.pass('}');
+ }
+
+ private static class ParsableString {
+
+ int position = 0;
+ String s;
+
+ ParsableString(String s) {
+ this.s = s;
+ }
+
+ /**
+ * Returns the next non-space character or UNASSIGNED if we have reached the end of the string.
+ * The current position is not changed.
+ */
+ char peek() {
+ int localPosition = position;
+ while (localPosition < s.length()) {
+ char nextChar = s.charAt(localPosition++);
+ if (!Character.isSpaceChar(nextChar))
+ return nextChar;
+ }
+ return Character.UNASSIGNED;
+ }
+
+ /**
+ * Verifies that the next non-space character is the given and moves the position past it.
+ *
+ * @throws IllegalArgumentException if the next non-space character is not the given character
+ */
+ void pass(char character) {
+ while (position < s.length()) {
+ char nextChar = s.charAt(position++);
+ if (!Character.isSpaceChar(nextChar)) {
+ if (nextChar == character)
+ return;
+ else
+ throw new IllegalArgumentException("Expected '" + character + "' at position " + (position-1) +
+ " but got '" + nextChar + "'");
+ }
+ }
+ throw new IllegalArgumentException("Expected '" + character + "' at position " + (position-1) +
+ " but reached the end");
+ }
+
+ /**
+ * Checks if the next non-space character is the given and moves the position past it if so.
+ * Does not change the position otherwise.
+ *
+ * @return true if the next non-space character was the given character
+ */
+ boolean passOptional(char character) {
+ int localPosition = position;
+ while (localPosition < s.length()) {
+ char nextChar = s.charAt(localPosition++);
+ if (!Character.isSpaceChar(nextChar)) {
+ if (nextChar == character) {
+ position = localPosition;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns the position of the next occurrence of any of the given characters.
+ *
+ * @throws IllegalArgumentException if there are no further occurrences of any of the given characters
+ */
+ int position(char ... characters) {
+ int localPosition = position;
+ while (localPosition < s.length()) {
+ char nextChar = s.charAt(localPosition);
+ for (char character : characters)
+ if (nextChar == character) return localPosition;
+ localPosition++;
+ }
+ throw new IllegalArgumentException("Expected one of " + Arrays.toString(characters) + " after " + position);
+ }
+
+ boolean atEnd() {
+ return position >= s.length();
+ }
+
+ /**
+ * Returns the string value from the current to the given position, and moves the current
+ * position to the next character.
+ *
+ * @throws IllegalArgumentException if end is beyond the last position of the string
+ */
+ String stringTo(int end) {
+ try {
+ String value = s.substring(position, end);
+ position = end;
+ return value;
+ }
+ catch (IndexOutOfBoundsException e) {
+ throw new IllegalArgumentException(end + " is larger than the size of the string, " + s.length());
+ }
+ }
+
+ /**
+ * Returns the int value from the current to the given position, and moves the current
+ * position to the next character.
+ *
+ * @throws IllegalArgumentException if the string cannot be parsed to an int or end is larger than the string
+ */
+ int intTo(int end) {
+ int start = position;
+ String value = stringTo(end);
+ try {
+ return Integer.parseInt(value.trim());
+ }
+ catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Expected an integer between positions " + start + " and " + end +
+ ", but got " + value);
+ }
+ }
+
+ /**
+ * Returns the long value from the current to the given position, and moves the current
+ * position to the next character.
+ *
+ * @throws IllegalArgumentException if the string cannot be parsed to a long or end is larger than the string
+ */
+ long longTo(int end) {
+ int start = position;
+ String value = stringTo(end);
+ try {
+ return Long.parseLong(value.trim());
+ }
+ catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Expected an integer between positions " + start + " and " + end +
+ ", but got " + value);
+ }
+ }
+
+ }
+
+}