Address PR feedback
This commit is contained in:
parent
57319b2d89
commit
b572658c5f
|
@ -2,6 +2,6 @@
|
|||
|
||||
This is an implementation of a [JMESPath](https://jmespath.org/) parser
|
||||
written in Java. It's not intended to be used at runtime and does not include
|
||||
an interpreter. It doesn't implement functions. Its goal is to parser
|
||||
an interpreter. It doesn't implement functions. Its goal is to parse
|
||||
JMESPath expressions, perform static analysis on them, and provide an AST
|
||||
that can be used for code generation.
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
package software.amazon.smithy.jmespath;
|
||||
|
||||
import software.amazon.smithy.jmespath.ast.AndExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ComparisonExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ComparatorExpression;
|
||||
import software.amazon.smithy.jmespath.ast.CurrentExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ExpressionReferenceExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ExpressionTypeExpression;
|
||||
import software.amazon.smithy.jmespath.ast.FieldExpression;
|
||||
import software.amazon.smithy.jmespath.ast.FilterProjectionExpression;
|
||||
import software.amazon.smithy.jmespath.ast.FlattenExpression;
|
||||
|
@ -41,11 +41,11 @@ import software.amazon.smithy.jmespath.ast.Subexpression;
|
|||
*/
|
||||
public interface ExpressionVisitor<T> {
|
||||
|
||||
T visitComparison(ComparisonExpression expression);
|
||||
T visitComparator(ComparatorExpression expression);
|
||||
|
||||
T visitCurrentNode(CurrentExpression expression);
|
||||
|
||||
T visitExpressionReference(ExpressionReferenceExpression expression);
|
||||
T visitExpressionType(ExpressionTypeExpression expression);
|
||||
|
||||
T visitFlatten(FlattenExpression expression);
|
||||
|
||||
|
|
|
@ -19,6 +19,10 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
import software.amazon.smithy.jmespath.ast.LiteralExpression;
|
||||
|
||||
/**
|
||||
* Defines the positional arguments, variadic arguments, and return value
|
||||
* of JMESPath functions.
|
||||
*/
|
||||
final class FunctionDefinition {
|
||||
|
||||
@FunctionalInterface
|
||||
|
@ -57,7 +61,7 @@ final class FunctionDefinition {
|
|||
if (type == RuntimeType.ANY || arg.getType() == RuntimeType.ANY) {
|
||||
return null;
|
||||
} else if (arg.getType() == RuntimeType.ARRAY) {
|
||||
List<Object> values = arg.asArrayValue();
|
||||
List<Object> values = arg.expectArrayValue();
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
LiteralExpression element = LiteralExpression.from(values.get(i));
|
||||
if (element.getType() != type) {
|
||||
|
|
|
@ -537,7 +537,7 @@ final class Lexer {
|
|||
// Backtrack for positioning.
|
||||
position--;
|
||||
column--;
|
||||
return parseString().value.asStringValue();
|
||||
return parseString().value.expectStringValue();
|
||||
case '{':
|
||||
return parseJsonObject();
|
||||
case '[':
|
||||
|
@ -546,7 +546,7 @@ final class Lexer {
|
|||
// Backtrack.
|
||||
position--;
|
||||
column--;
|
||||
return parseNumber().value.asNumberValue();
|
||||
return parseNumber().value.expectNumberValue();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -587,7 +587,7 @@ final class Lexer {
|
|||
}
|
||||
|
||||
while (!eof() && peek() != '`') {
|
||||
String key = parseString().value.asStringValue();
|
||||
String key = parseString().value.expectStringValue();
|
||||
ws();
|
||||
expect(':');
|
||||
ws();
|
||||
|
|
|
@ -18,20 +18,33 @@ package software.amazon.smithy.jmespath;
|
|||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Contains the result of {@link JmespathExpression#lint}.
|
||||
*/
|
||||
public final class LinterResult {
|
||||
|
||||
public final RuntimeType returnType;
|
||||
public final Set<ExpressionProblem> problems;
|
||||
private final RuntimeType returnType;
|
||||
private final Set<ExpressionProblem> problems;
|
||||
|
||||
public LinterResult(RuntimeType returnType, Set<ExpressionProblem> problems) {
|
||||
this.returnType = returnType;
|
||||
this.problems = problems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the statically known return type of the expression.
|
||||
*
|
||||
* @return Returns the return type of the expression.
|
||||
*/
|
||||
public RuntimeType getReturnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of problems in the expression.
|
||||
*
|
||||
* @return Returns the detected problems.
|
||||
*/
|
||||
public Set<ExpressionProblem> getProblems() {
|
||||
return problems;
|
||||
}
|
||||
|
|
|
@ -20,10 +20,10 @@ import java.util.LinkedHashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import software.amazon.smithy.jmespath.ast.AndExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ComparatorExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ComparatorType;
|
||||
import software.amazon.smithy.jmespath.ast.ComparisonExpression;
|
||||
import software.amazon.smithy.jmespath.ast.CurrentExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ExpressionReferenceExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ExpressionTypeExpression;
|
||||
import software.amazon.smithy.jmespath.ast.FieldExpression;
|
||||
import software.amazon.smithy.jmespath.ast.FilterProjectionExpression;
|
||||
import software.amazon.smithy.jmespath.ast.FlattenExpression;
|
||||
|
@ -69,7 +69,6 @@ final class Parser {
|
|||
TokenType.OR,
|
||||
TokenType.AND,
|
||||
TokenType.PIPE,
|
||||
TokenType.LPAREN,
|
||||
TokenType.FLATTEN,
|
||||
TokenType.FILTER,
|
||||
TokenType.EQUAL,
|
||||
|
@ -77,7 +76,10 @@ final class Parser {
|
|||
TokenType.GREATER_THAN,
|
||||
TokenType.GREATER_THAN_EQUAL,
|
||||
TokenType.LESS_THAN,
|
||||
TokenType.LESS_THAN_EQUAL
|
||||
TokenType.LESS_THAN_EQUAL,
|
||||
// While not found in the led() method, a led LPAREN is handled
|
||||
// when parsing a nud identifier because it creates a function.
|
||||
TokenType.LPAREN
|
||||
};
|
||||
|
||||
private final String expression;
|
||||
|
@ -113,9 +115,9 @@ final class Parser {
|
|||
if (iterator.peek().type == TokenType.LPAREN) {
|
||||
iterator.expect(TokenType.LPAREN);
|
||||
List<JmespathExpression> arguments = parseList(TokenType.RPAREN);
|
||||
return new FunctionExpression(token.value.asStringValue(), arguments, token.line, token.column);
|
||||
return new FunctionExpression(token.value.expectStringValue(), arguments, token.line, token.column);
|
||||
} else {
|
||||
return new FieldExpression(token.value.asStringValue(), token.line, token.column);
|
||||
return new FieldExpression(token.value.expectStringValue(), token.line, token.column);
|
||||
}
|
||||
case STAR: // Example: *
|
||||
return parseWildcardObject(new CurrentExpression(token.line, token.column));
|
||||
|
@ -129,7 +131,7 @@ final class Parser {
|
|||
return parseFlatten(new CurrentExpression(token.line, token.column));
|
||||
case EXPREF: // Example: sort_by(@, &foo)
|
||||
JmespathExpression expressionRef = expression(token.type.lbp);
|
||||
return new ExpressionReferenceExpression(expressionRef, token.line, token.column);
|
||||
return new ExpressionTypeExpression(expressionRef, token.line, token.column);
|
||||
case NOT: // Example: !foo
|
||||
JmespathExpression notNode = expression(token.type.lbp);
|
||||
return new NotExpression(notNode, token.line, token.column);
|
||||
|
@ -227,7 +229,7 @@ final class Parser {
|
|||
switch (next.type) {
|
||||
case NUMBER:
|
||||
iterator.expect(TokenType.NUMBER);
|
||||
parts[pos] = next.value.asNumberValue().intValue();
|
||||
parts[pos] = next.value.expectNumberValue().intValue();
|
||||
iterator.expectPeek(TokenType.COLON, TokenType.RBRACKET);
|
||||
break;
|
||||
case RBRACKET:
|
||||
|
@ -301,7 +303,7 @@ final class Parser {
|
|||
Token key = iterator.expect(TokenType.IDENTIFIER);
|
||||
iterator.expect(TokenType.COLON);
|
||||
JmespathExpression value = expression(0);
|
||||
entries.put(key.value.asStringValue(), value);
|
||||
entries.put(key.value.expectStringValue(), value);
|
||||
|
||||
if (iterator.expectPeek(TokenType.RBRACE, TokenType.COMMA).type == TokenType.COMMA) {
|
||||
iterator.expect(TokenType.COMMA);
|
||||
|
@ -363,7 +365,7 @@ final class Parser {
|
|||
int line = iterator.line();
|
||||
int column = iterator.column();
|
||||
JmespathExpression rhs = expression(TokenType.EQUAL.lbp);
|
||||
return new ComparisonExpression(comparatorType, lhs, rhs, line, column);
|
||||
return new ComparatorExpression(comparatorType, lhs, rhs, line, column);
|
||||
}
|
||||
|
||||
// Parses the right hand side of a ".".
|
||||
|
|
|
@ -16,19 +16,148 @@
|
|||
package software.amazon.smithy.jmespath;
|
||||
|
||||
import java.util.Locale;
|
||||
import software.amazon.smithy.jmespath.ast.ComparatorType;
|
||||
import software.amazon.smithy.jmespath.ast.LiteralExpression;
|
||||
|
||||
public enum RuntimeType {
|
||||
STRING,
|
||||
NUMBER,
|
||||
BOOLEAN,
|
||||
NULL,
|
||||
ARRAY,
|
||||
OBJECT,
|
||||
EXPRESSION_REFERENCE,
|
||||
ANY;
|
||||
|
||||
STRING {
|
||||
@Override
|
||||
public LiteralExpression compare(LiteralExpression left, LiteralExpression right, ComparatorType comparator) {
|
||||
if (left.getType() != right.getType()) {
|
||||
return LiteralExpression.BOOLEAN;
|
||||
}
|
||||
switch (comparator) {
|
||||
case EQUAL:
|
||||
return new LiteralExpression(left.expectStringValue().equals(right.expectStringValue()));
|
||||
case NOT_EQUAL:
|
||||
return new LiteralExpression(!left.expectStringValue().equals(right.expectStringValue()));
|
||||
default:
|
||||
return LiteralExpression.NULL;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
NUMBER {
|
||||
@Override
|
||||
public LiteralExpression compare(LiteralExpression left, LiteralExpression right, ComparatorType comparator) {
|
||||
if (left.getType() != right.getType()) {
|
||||
return LiteralExpression.BOOLEAN;
|
||||
}
|
||||
double comparison = left.expectNumberValue().doubleValue() - right.expectNumberValue().doubleValue();
|
||||
switch (comparator) {
|
||||
case EQUAL:
|
||||
return new LiteralExpression(comparison == 0);
|
||||
case NOT_EQUAL:
|
||||
return new LiteralExpression(comparison != 0);
|
||||
case GREATER_THAN:
|
||||
return new LiteralExpression(comparison > 0);
|
||||
case GREATER_THAN_EQUAL:
|
||||
return new LiteralExpression(comparison >= 0);
|
||||
case LESS_THAN:
|
||||
return new LiteralExpression(comparison < 0);
|
||||
case LESS_THAN_EQUAL:
|
||||
return new LiteralExpression(comparison <= 0);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unreachable comparator " + comparator);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
BOOLEAN {
|
||||
@Override
|
||||
public LiteralExpression compare(LiteralExpression left, LiteralExpression right, ComparatorType comparator) {
|
||||
if (left.getType() != right.getType()) {
|
||||
return LiteralExpression.BOOLEAN;
|
||||
}
|
||||
switch (comparator) {
|
||||
case EQUAL:
|
||||
return new LiteralExpression(left.expectBooleanValue() == right.expectBooleanValue());
|
||||
case NOT_EQUAL:
|
||||
return new LiteralExpression(left.expectBooleanValue() != right.expectBooleanValue());
|
||||
default:
|
||||
return LiteralExpression.NULL;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
NULL {
|
||||
@Override
|
||||
public LiteralExpression compare(LiteralExpression left, LiteralExpression right, ComparatorType comparator) {
|
||||
if (left.getType() != right.getType()) {
|
||||
return LiteralExpression.BOOLEAN;
|
||||
}
|
||||
switch (comparator) {
|
||||
case EQUAL:
|
||||
return new LiteralExpression(true);
|
||||
case NOT_EQUAL:
|
||||
return new LiteralExpression(false);
|
||||
default:
|
||||
return LiteralExpression.NULL;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ARRAY {
|
||||
@Override
|
||||
public LiteralExpression compare(LiteralExpression left, LiteralExpression right, ComparatorType comparator) {
|
||||
if (left.getType() != right.getType()) {
|
||||
return LiteralExpression.BOOLEAN;
|
||||
}
|
||||
switch (comparator) {
|
||||
case EQUAL:
|
||||
return new LiteralExpression(left.expectArrayValue().equals(right.expectArrayValue()));
|
||||
case NOT_EQUAL:
|
||||
return new LiteralExpression(!left.expectArrayValue().equals(right.expectArrayValue()));
|
||||
default:
|
||||
return LiteralExpression.NULL;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
OBJECT {
|
||||
@Override
|
||||
public LiteralExpression compare(LiteralExpression left, LiteralExpression right, ComparatorType comparator) {
|
||||
if (left.getType() != right.getType()) {
|
||||
return LiteralExpression.BOOLEAN;
|
||||
}
|
||||
switch (comparator) {
|
||||
case EQUAL:
|
||||
return new LiteralExpression(left.expectObjectValue().equals(right.expectObjectValue()));
|
||||
case NOT_EQUAL:
|
||||
return new LiteralExpression(!left.expectObjectValue().equals(right.expectObjectValue()));
|
||||
default:
|
||||
return LiteralExpression.NULL;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
EXPRESSION {
|
||||
@Override
|
||||
public LiteralExpression compare(LiteralExpression left, LiteralExpression right, ComparatorType comparator) {
|
||||
if (left.getType() != right.getType()) {
|
||||
return LiteralExpression.BOOLEAN;
|
||||
} else {
|
||||
return LiteralExpression.NULL;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
ANY {
|
||||
@Override
|
||||
public LiteralExpression compare(LiteralExpression left, LiteralExpression right, ComparatorType comparator) {
|
||||
// Just assume any kind of ANY comparison is satisfied.
|
||||
return new LiteralExpression(true);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString().toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
public abstract LiteralExpression compare(
|
||||
LiteralExpression left,
|
||||
LiteralExpression right,
|
||||
ComparatorType comparator);
|
||||
}
|
||||
|
|
|
@ -35,10 +35,10 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import software.amazon.smithy.jmespath.ast.AndExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ComparatorExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ComparatorType;
|
||||
import software.amazon.smithy.jmespath.ast.ComparisonExpression;
|
||||
import software.amazon.smithy.jmespath.ast.CurrentExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ExpressionReferenceExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ExpressionTypeExpression;
|
||||
import software.amazon.smithy.jmespath.ast.FieldExpression;
|
||||
import software.amazon.smithy.jmespath.ast.FilterProjectionExpression;
|
||||
import software.amazon.smithy.jmespath.ast.FlattenExpression;
|
||||
|
@ -76,17 +76,17 @@ final class TypeChecker implements ExpressionVisitor<LiteralExpression> {
|
|||
FUNCTIONS.put("length", new FunctionDefinition(
|
||||
NUMBER, oneOf(RuntimeType.STRING, RuntimeType.ARRAY, RuntimeType.OBJECT)));
|
||||
// TODO: Support expression reference return type validation?
|
||||
FUNCTIONS.put("map", new FunctionDefinition(ARRAY, isType(RuntimeType.EXPRESSION_REFERENCE), isArray));
|
||||
FUNCTIONS.put("map", new FunctionDefinition(ARRAY, isType(RuntimeType.EXPRESSION), isArray));
|
||||
// TODO: support array<X|Y>
|
||||
FUNCTIONS.put("max", new FunctionDefinition(NUMBER, isArray));
|
||||
FUNCTIONS.put("max_by", new FunctionDefinition(NUMBER, isArray, isType(RuntimeType.EXPRESSION_REFERENCE)));
|
||||
FUNCTIONS.put("max_by", new FunctionDefinition(NUMBER, isArray, isType(RuntimeType.EXPRESSION)));
|
||||
FUNCTIONS.put("merge", new FunctionDefinition(OBJECT, Collections.emptyList(), isType(RuntimeType.OBJECT)));
|
||||
FUNCTIONS.put("min", new FunctionDefinition(NUMBER, isArray));
|
||||
FUNCTIONS.put("min_by", new FunctionDefinition(NUMBER, isArray, isType(RuntimeType.EXPRESSION_REFERENCE)));
|
||||
FUNCTIONS.put("min_by", new FunctionDefinition(NUMBER, isArray, isType(RuntimeType.EXPRESSION)));
|
||||
FUNCTIONS.put("not_null", new FunctionDefinition(ANY, Collections.singletonList(isAny), isAny));
|
||||
FUNCTIONS.put("reverse", new FunctionDefinition(ARRAY, oneOf(RuntimeType.ARRAY, RuntimeType.STRING)));
|
||||
FUNCTIONS.put("sort", new FunctionDefinition(ARRAY, isArray));
|
||||
FUNCTIONS.put("sort_by", new FunctionDefinition(ARRAY, isArray, isType(RuntimeType.EXPRESSION_REFERENCE)));
|
||||
FUNCTIONS.put("sort_by", new FunctionDefinition(ARRAY, isArray, isType(RuntimeType.EXPRESSION)));
|
||||
FUNCTIONS.put("starts_with", new FunctionDefinition(BOOLEAN, isString, isString));
|
||||
FUNCTIONS.put("sum", new FunctionDefinition(NUMBER, listOfType(RuntimeType.NUMBER)));
|
||||
FUNCTIONS.put("to_array", new FunctionDefinition(ARRAY, isAny));
|
||||
|
@ -106,92 +106,16 @@ final class TypeChecker implements ExpressionVisitor<LiteralExpression> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public LiteralExpression visitComparison(ComparisonExpression expression) {
|
||||
public LiteralExpression visitComparator(ComparatorExpression expression) {
|
||||
LiteralExpression left = expression.getLeft().accept(this);
|
||||
LiteralExpression right = expression.getRight().accept(this);
|
||||
LiteralExpression result = left.getType().compare(left, right, expression.getComparator());
|
||||
|
||||
// Different types always cause a comparison to not match.
|
||||
if (left.getType() != right.getType()) {
|
||||
return BOOLEAN;
|
||||
if (result.getType() == RuntimeType.NULL) {
|
||||
badComparator(expression, left.getType(), expression.getComparator());
|
||||
}
|
||||
|
||||
// I'm so sorry for the following code.
|
||||
switch (left.getType()) {
|
||||
case STRING:
|
||||
switch (expression.getComparator()) {
|
||||
case EQUAL:
|
||||
return new LiteralExpression(left.asStringValue().equals(right.asStringValue()));
|
||||
case NOT_EQUAL:
|
||||
return new LiteralExpression(!left.asStringValue().equals(right.asStringValue()));
|
||||
default:
|
||||
badComparator(expression, left.getType(), expression.getComparator());
|
||||
return NULL;
|
||||
}
|
||||
case NUMBER:
|
||||
double comparison = left.asNumberValue().doubleValue() - right.asNumberValue().doubleValue();
|
||||
switch (expression.getComparator()) {
|
||||
case EQUAL:
|
||||
return new LiteralExpression(comparison == 0);
|
||||
case NOT_EQUAL:
|
||||
return new LiteralExpression(comparison != 0);
|
||||
case GREATER_THAN:
|
||||
return new LiteralExpression(comparison > 0);
|
||||
case GREATER_THAN_EQUAL:
|
||||
return new LiteralExpression(comparison >= 0);
|
||||
case LESS_THAN:
|
||||
return new LiteralExpression(comparison < 0);
|
||||
case LESS_THAN_EQUAL:
|
||||
return new LiteralExpression(comparison <= 0);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unreachable comparator " + expression.getComparator());
|
||||
}
|
||||
case BOOLEAN:
|
||||
switch (expression.getComparator()) {
|
||||
case EQUAL:
|
||||
return new LiteralExpression(left.asBooleanValue() == right.asBooleanValue());
|
||||
case NOT_EQUAL:
|
||||
return new LiteralExpression(left.asBooleanValue() != right.asBooleanValue());
|
||||
default:
|
||||
badComparator(expression, left.getType(), expression.getComparator());
|
||||
return NULL;
|
||||
}
|
||||
case NULL:
|
||||
switch (expression.getComparator()) {
|
||||
case EQUAL:
|
||||
return new LiteralExpression(true);
|
||||
case NOT_EQUAL:
|
||||
return new LiteralExpression(false);
|
||||
default:
|
||||
badComparator(expression, left.getType(), expression.getComparator());
|
||||
return NULL;
|
||||
}
|
||||
case ARRAY:
|
||||
switch (expression.getComparator()) {
|
||||
case EQUAL:
|
||||
return new LiteralExpression(left.asArrayValue().equals(right.asArrayValue()));
|
||||
case NOT_EQUAL:
|
||||
return new LiteralExpression(!left.asArrayValue().equals(right.asArrayValue()));
|
||||
default:
|
||||
badComparator(expression, left.getType(), expression.getComparator());
|
||||
return NULL;
|
||||
}
|
||||
case EXPRESSION_REFERENCE:
|
||||
badComparator(expression, left.getType(), expression.getComparator());
|
||||
return NULL;
|
||||
case OBJECT:
|
||||
switch (expression.getComparator()) {
|
||||
case EQUAL:
|
||||
return new LiteralExpression(left.asObjectValue().equals(right.asObjectValue()));
|
||||
case NOT_EQUAL:
|
||||
return new LiteralExpression(!left.asObjectValue().equals(right.asObjectValue()));
|
||||
default:
|
||||
badComparator(expression, left.getType(), expression.getComparator());
|
||||
return NULL;
|
||||
}
|
||||
default: // ANY
|
||||
// Just assume any kind of ANY comparison is satisfied.
|
||||
return new LiteralExpression(true);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -200,7 +124,7 @@ final class TypeChecker implements ExpressionVisitor<LiteralExpression> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public LiteralExpression visitExpressionReference(ExpressionReferenceExpression expression) {
|
||||
public LiteralExpression visitExpressionType(ExpressionTypeExpression expression) {
|
||||
// Expression references are late bound, so the type is only known
|
||||
// when the reference is used in a function.
|
||||
expression.getExpression().accept(new TypeChecker(knownFunctionType, problems));
|
||||
|
@ -220,10 +144,10 @@ final class TypeChecker implements ExpressionVisitor<LiteralExpression> {
|
|||
|
||||
// Perform the actual flattening.
|
||||
List<Object> flattened = new ArrayList<>();
|
||||
for (Object value : result.asArrayValue()) {
|
||||
for (Object value : result.expectArrayValue()) {
|
||||
LiteralExpression element = LiteralExpression.from(value);
|
||||
if (element.isArrayValue()) {
|
||||
flattened.addAll(element.asArrayValue());
|
||||
flattened.addAll(element.expectArrayValue());
|
||||
} else if (!element.isNullValue()) {
|
||||
flattened.add(element);
|
||||
}
|
||||
|
@ -240,7 +164,7 @@ final class TypeChecker implements ExpressionVisitor<LiteralExpression> {
|
|||
} else {
|
||||
danger(expression, String.format(
|
||||
"Object field '%s' does not exist in object with properties %s",
|
||||
expression.getName(), current.asObjectValue().keySet()));
|
||||
expression.getName(), current.expectObjectValue().keySet()));
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -325,7 +249,7 @@ final class TypeChecker implements ExpressionVisitor<LiteralExpression> {
|
|||
LiteralExpression leftResult = expression.getLeft().accept(this);
|
||||
|
||||
// If LHS is not an array, then just do basic checks on RHS using ANY + ARRAY.
|
||||
if (!leftResult.isArrayValue() || leftResult.asArrayValue().isEmpty()) {
|
||||
if (!leftResult.isArrayValue() || leftResult.expectArrayValue().isEmpty()) {
|
||||
if (leftResult.getType() != RuntimeType.ANY && !leftResult.isArrayValue()) {
|
||||
danger(expression, "Array projection performed on " + leftResult.getType());
|
||||
}
|
||||
|
@ -335,7 +259,7 @@ final class TypeChecker implements ExpressionVisitor<LiteralExpression> {
|
|||
} else {
|
||||
// LHS is an array, so do the projection.
|
||||
List<Object> result = new ArrayList<>();
|
||||
for (Object value : leftResult.asArrayValue()) {
|
||||
for (Object value : leftResult.expectArrayValue()) {
|
||||
TypeChecker checker = new TypeChecker(LiteralExpression.from(value), problems);
|
||||
result.add(expression.getRight().accept(checker).getValue());
|
||||
}
|
||||
|
@ -359,7 +283,7 @@ final class TypeChecker implements ExpressionVisitor<LiteralExpression> {
|
|||
|
||||
// LHS is an object, so do the projection.
|
||||
List<Object> result = new ArrayList<>();
|
||||
for (Object value : leftResult.asObjectValue().values()) {
|
||||
for (Object value : leftResult.expectObjectValue().values()) {
|
||||
TypeChecker checker = new TypeChecker(LiteralExpression.from(value), problems);
|
||||
result.add(expression.getRight().accept(checker).getValue());
|
||||
}
|
||||
|
@ -372,7 +296,7 @@ final class TypeChecker implements ExpressionVisitor<LiteralExpression> {
|
|||
LiteralExpression leftResult = expression.getLeft().accept(this);
|
||||
|
||||
// If LHS is not an array or is empty, then just do basic checks on RHS using ANY + ARRAY.
|
||||
if (!leftResult.isArrayValue() || leftResult.asArrayValue().isEmpty()) {
|
||||
if (!leftResult.isArrayValue() || leftResult.expectArrayValue().isEmpty()) {
|
||||
if (!leftResult.isArrayValue() && leftResult.getType() != RuntimeType.ANY) {
|
||||
danger(expression, "Filter projection performed on " + leftResult.getType());
|
||||
}
|
||||
|
@ -385,7 +309,7 @@ final class TypeChecker implements ExpressionVisitor<LiteralExpression> {
|
|||
|
||||
// It's a non-empty array, perform the actual filter.
|
||||
List<Object> result = new ArrayList<>();
|
||||
for (Object value : leftResult.asArrayValue()) {
|
||||
for (Object value : leftResult.expectArrayValue()) {
|
||||
LiteralExpression literalValue = LiteralExpression.from(value);
|
||||
TypeChecker rightVisitor = new TypeChecker(literalValue, problems);
|
||||
LiteralExpression comparisonValue = expression.getComparison().accept(rightVisitor);
|
||||
|
|
|
@ -21,6 +21,8 @@ import software.amazon.smithy.jmespath.JmespathExpression;
|
|||
/**
|
||||
* And expression where both sides must return truthy values. The second
|
||||
* truthy value becomes the result of the expression.
|
||||
*
|
||||
* @see <a href="https://jmespath.org/specification.html#and-expressions">And Expressions</a>
|
||||
*/
|
||||
public final class AndExpression extends BinaryExpression {
|
||||
|
||||
|
|
|
@ -22,16 +22,18 @@ import software.amazon.smithy.jmespath.JmespathExpression;
|
|||
/**
|
||||
* Compares the left and right expression using a comparator,
|
||||
* resulting in a boolean value.
|
||||
*
|
||||
* @see <a href="https://jmespath.org/specification.html#filter-expressions">Comparator expression as defined in Filter Expressions</a>
|
||||
*/
|
||||
public final class ComparisonExpression extends BinaryExpression {
|
||||
public final class ComparatorExpression extends BinaryExpression {
|
||||
|
||||
private final ComparatorType comparator;
|
||||
|
||||
public ComparisonExpression(ComparatorType comparator, JmespathExpression left, JmespathExpression right) {
|
||||
public ComparatorExpression(ComparatorType comparator, JmespathExpression left, JmespathExpression right) {
|
||||
this(comparator, left, right, 1, 1);
|
||||
}
|
||||
|
||||
public ComparisonExpression(
|
||||
public ComparatorExpression(
|
||||
ComparatorType comparator,
|
||||
JmespathExpression left,
|
||||
JmespathExpression right,
|
||||
|
@ -44,7 +46,7 @@ public final class ComparisonExpression extends BinaryExpression {
|
|||
|
||||
@Override
|
||||
public <T> T accept(ExpressionVisitor<T> visitor) {
|
||||
return visitor.visitComparison(this);
|
||||
return visitor.visitComparator(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,10 +62,10 @@ public final class ComparisonExpression extends BinaryExpression {
|
|||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (!(o instanceof ComparisonExpression)) {
|
||||
} else if (!(o instanceof ComparatorExpression)) {
|
||||
return false;
|
||||
}
|
||||
ComparisonExpression that = (ComparisonExpression) o;
|
||||
ComparatorExpression that = (ComparatorExpression) o;
|
||||
return getLeft().equals(that.getLeft())
|
||||
&& getRight().equals(that.getRight())
|
||||
&& getComparator().equals(that.getComparator());
|
|
@ -18,7 +18,7 @@ package software.amazon.smithy.jmespath.ast;
|
|||
/**
|
||||
* A comparator in a comparison expression.
|
||||
*/
|
||||
public enum ComparatorType {
|
||||
public enum ComparatorType {
|
||||
|
||||
EQUAL("=="),
|
||||
NOT_EQUAL("!="),
|
||||
|
|
|
@ -20,6 +20,8 @@ import software.amazon.smithy.jmespath.JmespathExpression;
|
|||
|
||||
/**
|
||||
* Gets the current node.
|
||||
*
|
||||
* <a href="https://jmespath.org/specification.html#current-node">current-node</a>
|
||||
*/
|
||||
public final class CurrentExpression extends JmespathExpression {
|
||||
|
||||
|
|
|
@ -22,23 +22,25 @@ import software.amazon.smithy.jmespath.JmespathExpression;
|
|||
/**
|
||||
* Contains a reference to an expression that can be run zero or more
|
||||
* times by a function.
|
||||
*
|
||||
* @see <a href="https://jmespath.org/specification.html#data-types">Data types</a>
|
||||
*/
|
||||
public final class ExpressionReferenceExpression extends JmespathExpression {
|
||||
public final class ExpressionTypeExpression extends JmespathExpression {
|
||||
|
||||
private final JmespathExpression expression;
|
||||
|
||||
public ExpressionReferenceExpression(JmespathExpression expression) {
|
||||
public ExpressionTypeExpression(JmespathExpression expression) {
|
||||
this(expression, 1, 1);
|
||||
}
|
||||
|
||||
public ExpressionReferenceExpression(JmespathExpression expression, int line, int column) {
|
||||
public ExpressionTypeExpression(JmespathExpression expression, int line, int column) {
|
||||
super(line, column);
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(ExpressionVisitor<T> visitor) {
|
||||
return visitor.visitExpressionReference(this);
|
||||
return visitor.visitExpressionType(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -54,10 +56,10 @@ public final class ExpressionReferenceExpression extends JmespathExpression {
|
|||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
} else if (!(o instanceof ExpressionReferenceExpression)) {
|
||||
} else if (!(o instanceof ExpressionTypeExpression)) {
|
||||
return false;
|
||||
}
|
||||
ExpressionReferenceExpression that = (ExpressionReferenceExpression) o;
|
||||
ExpressionTypeExpression that = (ExpressionTypeExpression) o;
|
||||
return expression.equals(that.expression);
|
||||
}
|
||||
|
|
@ -21,6 +21,11 @@ import software.amazon.smithy.jmespath.JmespathExpression;
|
|||
|
||||
/**
|
||||
* Gets a field by name from an object.
|
||||
*
|
||||
* <p>This AST node is created for identifiers. For example,
|
||||
* {@code foo} creates a {@code FieldExpression}.
|
||||
*
|
||||
* @see <a href="https://jmespath.org/specification.html#identifiers">Identifiers</a>
|
||||
*/
|
||||
public final class FieldExpression extends JmespathExpression {
|
||||
|
||||
|
|
|
@ -19,6 +19,16 @@ import java.util.Objects;
|
|||
import software.amazon.smithy.jmespath.ExpressionVisitor;
|
||||
import software.amazon.smithy.jmespath.JmespathExpression;
|
||||
|
||||
/**
|
||||
* A projection that filters values using a comparison.
|
||||
*
|
||||
* <p>A filter projection executes the left AST expression, expects it to
|
||||
* return an array of values, passes each result of the left expression to
|
||||
* a {@link ComparatorExpression}, and yields any value from the comparison
|
||||
* expression that returns {@code true} to the right AST expression.
|
||||
*
|
||||
* @see <a href="https://jmespath.org/specification.html#filter-expressions">Filter Expressions</a>
|
||||
*/
|
||||
public final class FilterProjectionExpression extends JmespathExpression {
|
||||
|
||||
private final JmespathExpression comparison;
|
||||
|
|
|
@ -21,6 +21,8 @@ import software.amazon.smithy.jmespath.JmespathExpression;
|
|||
|
||||
/**
|
||||
* Flattens the wrapped expression into an array.
|
||||
*
|
||||
* @see <a href="https://jmespath.org/specification.html#flatten-operator">Flatten Operator</a>
|
||||
*/
|
||||
public final class FlattenExpression extends JmespathExpression {
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ import software.amazon.smithy.jmespath.JmespathExpression;
|
|||
|
||||
/**
|
||||
* Executes a function by name using a list of argument expressions.
|
||||
*
|
||||
* @see <a href="https://jmespath.org/specification.html#functions-expressions">Function Expressions</a>
|
||||
*/
|
||||
public final class FunctionExpression extends JmespathExpression {
|
||||
|
||||
|
|
|
@ -20,8 +20,13 @@ import software.amazon.smithy.jmespath.ExpressionVisitor;
|
|||
import software.amazon.smithy.jmespath.JmespathExpression;
|
||||
|
||||
/**
|
||||
* Gets a specific element by zero-based index. Use -1 to get the
|
||||
* last element in an array.
|
||||
* Gets a specific element by zero-based index.
|
||||
*
|
||||
* <p>Use a negative index to get an element from the end of the array
|
||||
* (e.g., -1 is used to get the last element of the array). If an
|
||||
* array element does not exist, a {@code null} value is returned.
|
||||
*
|
||||
* @see <a href="https://jmespath.org/specification.html#index-expressions">Index Expressions</a>
|
||||
*/
|
||||
public final class IndexExpression extends JmespathExpression {
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ public final class LiteralExpression extends JmespathExpression {
|
|||
} else if (isNullValue()) {
|
||||
return RuntimeType.NULL;
|
||||
} else if (this == EXPREF) {
|
||||
return RuntimeType.EXPRESSION_REFERENCE;
|
||||
return RuntimeType.EXPRESSION;
|
||||
} else {
|
||||
return RuntimeType.ANY;
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ public final class LiteralExpression extends JmespathExpression {
|
|||
* @return Returns the object field value.
|
||||
*/
|
||||
public LiteralExpression getObjectField(String name) {
|
||||
Map<String, Object> values = asObjectValue();
|
||||
Map<String, Object> values = expectObjectValue();
|
||||
return values.containsKey(name)
|
||||
? new LiteralExpression(values.get(name))
|
||||
: new LiteralExpression(null);
|
||||
|
@ -169,7 +169,7 @@ public final class LiteralExpression extends JmespathExpression {
|
|||
* @return Returns true if the object contains the given key.
|
||||
*/
|
||||
public boolean hasObjectField(String name) {
|
||||
return asObjectValue().containsKey(name);
|
||||
return expectObjectValue().containsKey(name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -182,7 +182,7 @@ public final class LiteralExpression extends JmespathExpression {
|
|||
* @return Returns the array value.
|
||||
*/
|
||||
public LiteralExpression getArrayIndex(int index) {
|
||||
List<Object> values = asArrayValue();
|
||||
List<Object> values = expectArrayValue();
|
||||
|
||||
if (index < 0) {
|
||||
index = values.size() + index;
|
||||
|
@ -253,7 +253,7 @@ public final class LiteralExpression extends JmespathExpression {
|
|||
* @return Returns the string value.
|
||||
* @throws JmespathException if the value is not a string.
|
||||
*/
|
||||
public String asStringValue() {
|
||||
public String expectStringValue() {
|
||||
if (value instanceof String) {
|
||||
return (String) value;
|
||||
}
|
||||
|
@ -267,7 +267,7 @@ public final class LiteralExpression extends JmespathExpression {
|
|||
* @return Returns the number value.
|
||||
* @throws JmespathException if the value is not a number.
|
||||
*/
|
||||
public Number asNumberValue() {
|
||||
public Number expectNumberValue() {
|
||||
if (value instanceof Number) {
|
||||
return (Number) value;
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ public final class LiteralExpression extends JmespathExpression {
|
|||
* @return Returns the boolean value.
|
||||
* @throws JmespathException if the value is not a boolean.
|
||||
*/
|
||||
public boolean asBooleanValue() {
|
||||
public boolean expectBooleanValue() {
|
||||
if (value instanceof Boolean) {
|
||||
return (Boolean) value;
|
||||
}
|
||||
|
@ -296,7 +296,7 @@ public final class LiteralExpression extends JmespathExpression {
|
|||
* @throws JmespathException if the value is not an array.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Object> asArrayValue() {
|
||||
public List<Object> expectArrayValue() {
|
||||
try {
|
||||
return (List<Object>) value;
|
||||
} catch (ClassCastException e) {
|
||||
|
@ -311,7 +311,7 @@ public final class LiteralExpression extends JmespathExpression {
|
|||
* @throws JmespathException if the value is not an object.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> asObjectValue() {
|
||||
public Map<String, Object> expectObjectValue() {
|
||||
try {
|
||||
return (Map<String, Object>) value;
|
||||
} catch (ClassCastException e) {
|
||||
|
@ -328,16 +328,16 @@ public final class LiteralExpression extends JmespathExpression {
|
|||
switch (getType()) {
|
||||
case ANY: // just assume it's true.
|
||||
case NUMBER: // number is always true
|
||||
case EXPRESSION_REFERENCE: // references are always true
|
||||
case EXPRESSION: // references are always true
|
||||
return true;
|
||||
case STRING:
|
||||
return !asStringValue().isEmpty();
|
||||
return !expectStringValue().isEmpty();
|
||||
case ARRAY:
|
||||
return !asArrayValue().isEmpty();
|
||||
return !expectArrayValue().isEmpty();
|
||||
case OBJECT:
|
||||
return !asObjectValue().isEmpty();
|
||||
return !expectObjectValue().isEmpty();
|
||||
case BOOLEAN:
|
||||
return asBooleanValue();
|
||||
return expectBooleanValue();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -22,13 +22,15 @@ import software.amazon.smithy.jmespath.JmespathExpression;
|
|||
|
||||
/**
|
||||
* Creates an object using key-value pairs.
|
||||
*
|
||||
* @see <a href="https://jmespath.org/specification.html#multiselect-hash">MultiSelect Hash</a>
|
||||
*/
|
||||
public final class MultiSelectHashExpression extends JmespathExpression {
|
||||
|
||||
private final Map<String, JmespathExpression> expressions;
|
||||
|
||||
public MultiSelectHashExpression(Map<String, JmespathExpression> entries) {
|
||||
this(entries, 1, 1);
|
||||
public MultiSelectHashExpression(Map<String, JmespathExpression> expressions) {
|
||||
this(expressions, 1, 1);
|
||||
}
|
||||
|
||||
public MultiSelectHashExpression(Map<String, JmespathExpression> expressions, int line, int column) {
|
||||
|
|
|
@ -22,6 +22,8 @@ import software.amazon.smithy.jmespath.JmespathExpression;
|
|||
|
||||
/**
|
||||
* Selects one or more values into a created array.
|
||||
*
|
||||
* @see <a href="https://jmespath.org/specification.html#multiselect-list">MultiSelect List</a>
|
||||
*/
|
||||
public final class MultiSelectListExpression extends JmespathExpression {
|
||||
|
||||
|
|
|
@ -26,8 +26,8 @@ public final class NotExpression extends JmespathExpression {
|
|||
|
||||
private final JmespathExpression expression;
|
||||
|
||||
public NotExpression(JmespathExpression wrapped) {
|
||||
this(wrapped, 1, 1);
|
||||
public NotExpression(JmespathExpression expression) {
|
||||
this(expression, 1, 1);
|
||||
}
|
||||
|
||||
public NotExpression(JmespathExpression expression, int line, int column) {
|
||||
|
|
|
@ -20,6 +20,13 @@ import software.amazon.smithy.jmespath.JmespathExpression;
|
|||
|
||||
/**
|
||||
* A projection of object values.
|
||||
*
|
||||
* <p>If the left AST expression does not return an object, then the
|
||||
* result of the projection is a {@code null} value. Otherwise, the
|
||||
* object values are each yielded to the right AST expression,
|
||||
* building up a list of results.
|
||||
*
|
||||
* @see <a href="https://jmespath.org/specification.html#wildcard-expressions">Wildcard Expressions</a>
|
||||
*/
|
||||
public final class ObjectProjectionExpression extends ProjectionExpression {
|
||||
|
||||
|
|
|
@ -20,6 +20,8 @@ import software.amazon.smithy.jmespath.JmespathExpression;
|
|||
|
||||
/**
|
||||
* Or expression that returns the expression that returns a truthy value.
|
||||
*
|
||||
* @see <a href="https://jmespath.org/specification.html#or-expressions">Or Expressions</a>
|
||||
*/
|
||||
public final class OrExpression extends BinaryExpression {
|
||||
|
||||
|
|
|
@ -21,6 +21,11 @@ import software.amazon.smithy.jmespath.JmespathExpression;
|
|||
/**
|
||||
* Iterates over each element in the array returned from the left expression,
|
||||
* passes it to the right expression, and returns the aggregated results.
|
||||
*
|
||||
* <p>This AST node is created when parsing expressions like {@code [*]},
|
||||
* {@code []}, and {@code [1:1]}.
|
||||
*
|
||||
* @see <a href="https://jmespath.org/specification.html#wildcard-expressions">Wildcard Expressions</a>
|
||||
*/
|
||||
public class ProjectionExpression extends BinaryExpression {
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@ import software.amazon.smithy.jmespath.JmespathExpression;
|
|||
/**
|
||||
* Represents a slice expression, containing an optional zero-based
|
||||
* start offset, zero-based stop offset, and step.
|
||||
*
|
||||
* @see <a href="https://jmespath.org/specification.html#slices">Slices</a>
|
||||
*/
|
||||
public final class SliceExpression extends JmespathExpression {
|
||||
|
||||
|
|
|
@ -20,6 +20,12 @@ import software.amazon.smithy.jmespath.JmespathExpression;
|
|||
|
||||
/**
|
||||
* Visits the left expression and passes its result to the right expression.
|
||||
*
|
||||
* <p>This AST node is used for both sub-expressions and pipe-expressions in
|
||||
* the JMESPath specification.
|
||||
*
|
||||
* @see <a href="https://jmespath.org/specification.html#subexpressions">SubExpressions</a>
|
||||
* @see <a href="https://jmespath.org/specification.html#pipe-expressions">Pipe expressions</a>
|
||||
*/
|
||||
public final class Subexpression extends BinaryExpression {
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ public class LexerTest {
|
|||
|
||||
Token token = tokens.next();
|
||||
assertThat(token.type, equalTo(TokenType.IDENTIFIER));
|
||||
assertThat(token.value.asStringValue(), equalTo("foo_123_FOO"));
|
||||
assertThat(token.value.expectStringValue(), equalTo("foo_123_FOO"));
|
||||
assertThat(token.line, equalTo(1));
|
||||
assertThat(token.column, equalTo(1));
|
||||
|
||||
|
@ -66,7 +66,7 @@ public class LexerTest {
|
|||
|
||||
assertThat(tokens, hasSize(4));
|
||||
assertThat(tokens.get(0).type, equalTo(TokenType.IDENTIFIER));
|
||||
assertThat(tokens.get(0).value.asStringValue(), equalTo("foo"));
|
||||
assertThat(tokens.get(0).value.expectStringValue(), equalTo("foo"));
|
||||
assertThat(tokens.get(0).line, equalTo(1));
|
||||
assertThat(tokens.get(0).column, equalTo(1));
|
||||
|
||||
|
@ -75,7 +75,7 @@ public class LexerTest {
|
|||
assertThat(tokens.get(1).column, equalTo(4));
|
||||
|
||||
assertThat(tokens.get(2).type, equalTo(TokenType.IDENTIFIER));
|
||||
assertThat(tokens.get(2).value.asStringValue(), equalTo("bar"));
|
||||
assertThat(tokens.get(2).value.expectStringValue(), equalTo("bar"));
|
||||
assertThat(tokens.get(2).line, equalTo(1));
|
||||
assertThat(tokens.get(2).column, equalTo(5));
|
||||
|
||||
|
@ -90,7 +90,7 @@ public class LexerTest {
|
|||
|
||||
assertThat(tokens, hasSize(2));
|
||||
assertThat(tokens.get(0).type, equalTo(TokenType.LITERAL));
|
||||
assertThat(tokens.get(0).value.asArrayValue(), equalTo(Arrays.asList(1.0, true, false, null, -2.0, "hi")));
|
||||
assertThat(tokens.get(0).value.expectArrayValue(), equalTo(Arrays.asList(1.0, true, false, null, -2.0, "hi")));
|
||||
assertThat(tokens.get(0).line, equalTo(1));
|
||||
assertThat(tokens.get(0).column, equalTo(1));
|
||||
|
||||
|
@ -110,7 +110,7 @@ public class LexerTest {
|
|||
|
||||
assertThat(tokens, hasSize(2));
|
||||
assertThat(tokens.get(0).type, equalTo(TokenType.LITERAL));
|
||||
assertThat(tokens.get(0).value.asArrayValue(), empty());
|
||||
assertThat(tokens.get(0).value.expectArrayValue(), empty());
|
||||
assertThat(tokens.get(0).line, equalTo(1));
|
||||
assertThat(tokens.get(0).column, equalTo(1));
|
||||
|
||||
|
@ -149,7 +149,7 @@ public class LexerTest {
|
|||
|
||||
assertThat(tokens, hasSize(2));
|
||||
assertThat(tokens.get(0).type, equalTo(TokenType.LITERAL));
|
||||
Map<String, Object> obj = tokens.get(0).value.asObjectValue();
|
||||
Map<String, Object> obj = tokens.get(0).value.expectObjectValue();
|
||||
assertThat(obj.entrySet(), hasSize(2));
|
||||
assertThat(obj.keySet(), contains("foo", "bar"));
|
||||
assertThat(obj.get("foo"), equalTo(true));
|
||||
|
@ -168,7 +168,7 @@ public class LexerTest {
|
|||
|
||||
assertThat(tokens, hasSize(2));
|
||||
assertThat(tokens.get(0).type, equalTo(TokenType.LITERAL));
|
||||
assertThat(tokens.get(0).value.asObjectValue().entrySet(), empty());
|
||||
assertThat(tokens.get(0).value.expectObjectValue().entrySet(), empty());
|
||||
assertThat(tokens.get(0).line, equalTo(1));
|
||||
assertThat(tokens.get(0).column, equalTo(1));
|
||||
|
||||
|
@ -227,7 +227,7 @@ public class LexerTest {
|
|||
|
||||
assertThat(tokens, hasSize(2));
|
||||
assertThat(tokens.get(0).type, equalTo(TokenType.LITERAL));
|
||||
assertThat(tokens.get(0).value.asStringValue(), equalTo("`"));
|
||||
assertThat(tokens.get(0).value.expectStringValue(), equalTo("`"));
|
||||
assertThat(tokens.get(0).line, equalTo(1));
|
||||
assertThat(tokens.get(0).column, equalTo(1));
|
||||
|
||||
|
@ -249,12 +249,12 @@ public class LexerTest {
|
|||
|
||||
assertThat(tokens, hasSize(3));
|
||||
assertThat(tokens.get(0).type, equalTo(TokenType.IDENTIFIER));
|
||||
assertThat(tokens.get(0).value.asStringValue(), equalTo("foo"));
|
||||
assertThat(tokens.get(0).value.expectStringValue(), equalTo("foo"));
|
||||
assertThat(tokens.get(0).line, equalTo(1));
|
||||
assertThat(tokens.get(0).column, equalTo(1));
|
||||
|
||||
assertThat(tokens.get(1).type, equalTo(TokenType.IDENTIFIER));
|
||||
assertThat(tokens.get(1).value.asStringValue(), equalTo(""));
|
||||
assertThat(tokens.get(1).value.expectStringValue(), equalTo(""));
|
||||
assertThat(tokens.get(1).line, equalTo(1));
|
||||
assertThat(tokens.get(1).column, equalTo(7));
|
||||
|
||||
|
@ -274,7 +274,7 @@ public class LexerTest {
|
|||
|
||||
assertThat(tokens, hasSize(2));
|
||||
assertThat(tokens.get(0).type, equalTo(TokenType.IDENTIFIER));
|
||||
assertThat(tokens.get(0).value.asStringValue(), equalTo("\" \n \t \r \f \b / \\ "));
|
||||
assertThat(tokens.get(0).value.expectStringValue(), equalTo("\" \n \t \r \f \b / \\ "));
|
||||
assertThat(tokens.get(0).line, equalTo(1));
|
||||
assertThat(tokens.get(0).column, equalTo(1));
|
||||
|
||||
|
@ -289,7 +289,7 @@ public class LexerTest {
|
|||
|
||||
assertThat(tokens, hasSize(2));
|
||||
assertThat(tokens.get(0).type, equalTo(TokenType.IDENTIFIER));
|
||||
assertThat(tokens.get(0).value.asStringValue(), equalTo("\n\n"));
|
||||
assertThat(tokens.get(0).value.expectStringValue(), equalTo("\n\n"));
|
||||
assertThat(tokens.get(0).line, equalTo(1));
|
||||
assertThat(tokens.get(0).column, equalTo(1));
|
||||
|
||||
|
@ -479,17 +479,17 @@ public class LexerTest {
|
|||
|
||||
assertThat(tokens, hasSize(4));
|
||||
assertThat(tokens.get(0).type, equalTo(TokenType.NUMBER));
|
||||
assertThat(tokens.get(0).value.asNumberValue().doubleValue(), equalTo(123.0));
|
||||
assertThat(tokens.get(0).value.expectNumberValue().doubleValue(), equalTo(123.0));
|
||||
assertThat(tokens.get(0).line, equalTo(1));
|
||||
assertThat(tokens.get(0).column, equalTo(1));
|
||||
|
||||
assertThat(tokens.get(1).type, equalTo(TokenType.NUMBER));
|
||||
assertThat(tokens.get(1).value.asNumberValue().doubleValue(), equalTo(-1.0));
|
||||
assertThat(tokens.get(1).value.expectNumberValue().doubleValue(), equalTo(-1.0));
|
||||
assertThat(tokens.get(1).line, equalTo(1));
|
||||
assertThat(tokens.get(1).column, equalTo(5));
|
||||
|
||||
assertThat(tokens.get(2).type, equalTo(TokenType.NUMBER));
|
||||
assertThat(tokens.get(2).value.asNumberValue().doubleValue(), equalTo(0.0));
|
||||
assertThat(tokens.get(2).value.expectNumberValue().doubleValue(), equalTo(0.0));
|
||||
assertThat(tokens.get(2).line, equalTo(1));
|
||||
assertThat(tokens.get(2).column, equalTo(8));
|
||||
|
||||
|
@ -519,12 +519,12 @@ public class LexerTest {
|
|||
|
||||
assertThat(tokens, hasSize(3));
|
||||
assertThat(tokens.get(0).type, equalTo(TokenType.NUMBER));
|
||||
assertThat(tokens.get(0).value.asNumberValue().doubleValue(), equalTo(0.0));
|
||||
assertThat(tokens.get(0).value.expectNumberValue().doubleValue(), equalTo(0.0));
|
||||
assertThat(tokens.get(0).line, equalTo(1));
|
||||
assertThat(tokens.get(0).column, equalTo(1));
|
||||
|
||||
assertThat(tokens.get(1).type, equalTo(TokenType.IDENTIFIER));
|
||||
assertThat(tokens.get(1).value.asStringValue(), equalTo("a"));
|
||||
assertThat(tokens.get(1).value.expectStringValue(), equalTo("a"));
|
||||
assertThat(tokens.get(1).line, equalTo(1));
|
||||
assertThat(tokens.get(1).column, equalTo(4));
|
||||
|
||||
|
@ -539,12 +539,12 @@ public class LexerTest {
|
|||
|
||||
assertThat(tokens, hasSize(3));
|
||||
assertThat(tokens.get(0).type, equalTo(TokenType.NUMBER));
|
||||
assertThat(tokens.get(0).value.asNumberValue().doubleValue(), equalTo(123.009e12));
|
||||
assertThat(tokens.get(0).value.expectNumberValue().doubleValue(), equalTo(123.009e12));
|
||||
assertThat(tokens.get(0).line, equalTo(1));
|
||||
assertThat(tokens.get(0).column, equalTo(1));
|
||||
|
||||
assertThat(tokens.get(1).type, equalTo(TokenType.NUMBER));
|
||||
assertThat(tokens.get(1).value.asNumberValue().doubleValue(), equalTo(-001.109e-12));
|
||||
assertThat(tokens.get(1).value.expectNumberValue().doubleValue(), equalTo(-001.109e-12));
|
||||
assertThat(tokens.get(1).line, equalTo(1));
|
||||
assertThat(tokens.get(1).column, equalTo(13));
|
||||
|
||||
|
@ -564,17 +564,17 @@ public class LexerTest {
|
|||
|
||||
assertThat(tokens, hasSize(4));
|
||||
assertThat(tokens.get(0).type, equalTo(TokenType.LITERAL));
|
||||
assertThat(tokens.get(0).value.asStringValue(), equalTo("foo"));
|
||||
assertThat(tokens.get(0).value.expectStringValue(), equalTo("foo"));
|
||||
assertThat(tokens.get(0).line, equalTo(1));
|
||||
assertThat(tokens.get(0).column, equalTo(1));
|
||||
|
||||
assertThat(tokens.get(1).type, equalTo(TokenType.LITERAL));
|
||||
assertThat(tokens.get(1).value.asStringValue(), equalTo("foo's"));
|
||||
assertThat(tokens.get(1).value.expectStringValue(), equalTo("foo's"));
|
||||
assertThat(tokens.get(1).line, equalTo(1));
|
||||
assertThat(tokens.get(1).column, equalTo(7));
|
||||
|
||||
assertThat(tokens.get(2).type, equalTo(TokenType.LITERAL));
|
||||
assertThat(tokens.get(2).value.asStringValue(), equalTo("foo\\a"));
|
||||
assertThat(tokens.get(2).value.expectStringValue(), equalTo("foo\\a"));
|
||||
assertThat(tokens.get(2).line, equalTo(1));
|
||||
assertThat(tokens.get(2).column, equalTo(16));
|
||||
|
||||
|
@ -589,7 +589,7 @@ public class LexerTest {
|
|||
|
||||
assertThat(tokens, hasSize(2));
|
||||
assertThat(tokens.get(0).type, equalTo(TokenType.LITERAL));
|
||||
assertThat(tokens.get(0).value.asStringValue(), equalTo(""));
|
||||
assertThat(tokens.get(0).value.expectStringValue(), equalTo(""));
|
||||
assertThat(tokens.get(0).line, equalTo(1));
|
||||
assertThat(tokens.get(0).column, equalTo(1));
|
||||
|
||||
|
|
|
@ -27,9 +27,9 @@ import org.junit.jupiter.api.Assertions;
|
|||
import org.junit.jupiter.api.Test;
|
||||
import software.amazon.smithy.jmespath.ast.AndExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ComparatorType;
|
||||
import software.amazon.smithy.jmespath.ast.ComparisonExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ComparatorExpression;
|
||||
import software.amazon.smithy.jmespath.ast.CurrentExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ExpressionReferenceExpression;
|
||||
import software.amazon.smithy.jmespath.ast.ExpressionTypeExpression;
|
||||
import software.amazon.smithy.jmespath.ast.FieldExpression;
|
||||
import software.amazon.smithy.jmespath.ast.FilterProjectionExpression;
|
||||
import software.amazon.smithy.jmespath.ast.FlattenExpression;
|
||||
|
@ -149,7 +149,7 @@ public class ParserTest {
|
|||
@Test
|
||||
public void parsesNudAmpersand() {
|
||||
assertThat(JmespathExpression.parse("&foo[1]"), equalTo(
|
||||
new ExpressionReferenceExpression(
|
||||
new ExpressionTypeExpression(
|
||||
new Subexpression(
|
||||
new FieldExpression("foo"),
|
||||
new IndexExpression(1)))));
|
||||
|
@ -169,7 +169,7 @@ public class ParserTest {
|
|||
assertThat(JmespathExpression.parse("[?foo == `true`]"), equalTo(
|
||||
new FilterProjectionExpression(
|
||||
new CurrentExpression(),
|
||||
new ComparisonExpression(
|
||||
new ComparatorExpression(
|
||||
ComparatorType.EQUAL,
|
||||
new FieldExpression("foo"),
|
||||
new LiteralExpression(true)),
|
||||
|
@ -182,7 +182,7 @@ public class ParserTest {
|
|||
assertThat(JmespathExpression.parse("[?foo " + type + " `true`]"), equalTo(
|
||||
new FilterProjectionExpression(
|
||||
new CurrentExpression(),
|
||||
new ComparisonExpression(
|
||||
new ComparatorExpression(
|
||||
type,
|
||||
new FieldExpression("foo"),
|
||||
new LiteralExpression(true)),
|
||||
|
@ -295,7 +295,7 @@ public class ParserTest {
|
|||
assertThat(JmespathExpression.parse("a[?b > c].d"), equalTo(
|
||||
new FilterProjectionExpression(
|
||||
new FieldExpression("a"),
|
||||
new ComparisonExpression(
|
||||
new ComparatorExpression(
|
||||
ComparatorType.GREATER_THAN,
|
||||
new FieldExpression("b"),
|
||||
new FieldExpression("c")),
|
||||
|
@ -319,7 +319,7 @@ public class ParserTest {
|
|||
new FieldExpression("a"),
|
||||
new FilterProjectionExpression(
|
||||
new CurrentExpression(),
|
||||
new ComparisonExpression(
|
||||
new ComparatorExpression(
|
||||
ComparatorType.EQUAL,
|
||||
new FieldExpression("foo"),
|
||||
new FieldExpression("bar")),
|
||||
|
|
|
@ -22,8 +22,6 @@ public class RunnerTest {
|
|||
for (ExpressionProblem problem : expression.lint().getProblems()) {
|
||||
if (problem.severity == ExpressionProblem.Severity.ERROR) {
|
||||
Assertions.fail("Did not expect an ERROR for line: " + line + "\n" + problem);
|
||||
} else {
|
||||
System.out.println(problem);
|
||||
}
|
||||
}
|
||||
} catch (JmespathException e) {
|
||||
|
@ -54,7 +52,7 @@ public class RunnerTest {
|
|||
return line;
|
||||
}
|
||||
})
|
||||
.map(line -> Lexer.tokenize(line).next().value.asStringValue())
|
||||
.map(line -> Lexer.tokenize(line).next().value.expectStringValue())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -328,7 +328,7 @@ public class TypeCheckerTest {
|
|||
|
||||
@Test
|
||||
public void cannotCompareExpref() {
|
||||
assertThat(check("(&foo) == (&foo)"), contains("[WARNING] Invalid comparator '==' for expression_reference (1:11)"));
|
||||
assertThat(check("(&foo) == (&foo)"), contains("[WARNING] Invalid comparator '==' for expression (1:11)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -39,14 +39,14 @@ public class LiteralExpressionTest {
|
|||
public void throwsWhenNotString() {
|
||||
LiteralExpression node = new LiteralExpression(10);
|
||||
|
||||
Assertions.assertThrows(JmespathException.class, node::asStringValue);
|
||||
Assertions.assertThrows(JmespathException.class, node::expectStringValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsAsString() {
|
||||
LiteralExpression node = new LiteralExpression("foo");
|
||||
|
||||
node.asStringValue();
|
||||
node.expectStringValue();
|
||||
assertThat(node.isStringValue(), is(true));
|
||||
assertThat(node.isNullValue(), is(false)); // not null
|
||||
assertThat(node.getType(), equalTo(RuntimeType.STRING));
|
||||
|
@ -56,14 +56,14 @@ public class LiteralExpressionTest {
|
|||
public void throwsWhenNotArray() {
|
||||
LiteralExpression node = new LiteralExpression("hi");
|
||||
|
||||
Assertions.assertThrows(JmespathException.class, node::asArrayValue);
|
||||
Assertions.assertThrows(JmespathException.class, node::expectArrayValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsAsArray() {
|
||||
LiteralExpression node = new LiteralExpression(Collections.emptyList());
|
||||
|
||||
node.asArrayValue();
|
||||
node.expectArrayValue();
|
||||
assertThat(node.isArrayValue(), is(true));
|
||||
assertThat(node.getType(), equalTo(RuntimeType.ARRAY));
|
||||
}
|
||||
|
@ -82,14 +82,14 @@ public class LiteralExpressionTest {
|
|||
public void throwsWhenNotNumber() {
|
||||
LiteralExpression node = new LiteralExpression("hi");
|
||||
|
||||
Assertions.assertThrows(JmespathException.class, node::asNumberValue);
|
||||
Assertions.assertThrows(JmespathException.class, node::expectNumberValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsAsNumber() {
|
||||
LiteralExpression node = new LiteralExpression(10);
|
||||
|
||||
node.asNumberValue();
|
||||
node.expectNumberValue();
|
||||
assertThat(node.isNumberValue(), is(true));
|
||||
assertThat(node.getType(), equalTo(RuntimeType.NUMBER));
|
||||
}
|
||||
|
@ -98,14 +98,14 @@ public class LiteralExpressionTest {
|
|||
public void throwsWhenNotBoolean() {
|
||||
LiteralExpression node = new LiteralExpression("hi");
|
||||
|
||||
Assertions.assertThrows(JmespathException.class, node::asBooleanValue);
|
||||
Assertions.assertThrows(JmespathException.class, node::expectBooleanValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsAsBoolean() {
|
||||
LiteralExpression node = new LiteralExpression(true);
|
||||
|
||||
node.asBooleanValue();
|
||||
node.expectBooleanValue();
|
||||
assertThat(node.isBooleanValue(), is(true));
|
||||
assertThat(node.getType(), equalTo(RuntimeType.BOOLEAN));
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ public class LiteralExpressionTest {
|
|||
public void getsAsBoxedBoolean() {
|
||||
LiteralExpression node = new LiteralExpression(new Boolean(true));
|
||||
|
||||
node.asBooleanValue();
|
||||
node.expectBooleanValue();
|
||||
assertThat(node.isBooleanValue(), is(true));
|
||||
}
|
||||
|
||||
|
@ -122,21 +122,21 @@ public class LiteralExpressionTest {
|
|||
public void throwsWhenNotMap() {
|
||||
LiteralExpression node = new LiteralExpression("hi");
|
||||
|
||||
Assertions.assertThrows(JmespathException.class, node::asObjectValue);
|
||||
Assertions.assertThrows(JmespathException.class, node::expectObjectValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getsAsMap() {
|
||||
LiteralExpression node = new LiteralExpression(Collections.emptyMap());
|
||||
|
||||
node.asObjectValue();
|
||||
node.expectObjectValue();
|
||||
assertThat(node.isObjectValue(), is(true));
|
||||
assertThat(node.getType(), equalTo(RuntimeType.OBJECT));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void expressionReferenceTypeIsExpref() {
|
||||
assertThat(LiteralExpression.EXPREF.getType(), equalTo(RuntimeType.EXPRESSION_REFERENCE));
|
||||
assertThat(LiteralExpression.EXPREF.getType(), equalTo(RuntimeType.EXPRESSION));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Reference in New Issue