Address PR feedback

This commit is contained in:
Michael Dowling 2020-11-02 23:53:16 -08:00 committed by Michael Dowling
parent 57319b2d89
commit b572658c5f
32 changed files with 332 additions and 204 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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) {

View File

@ -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();

View File

@ -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;
}

View File

@ -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 ".".

View File

@ -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);
}

View File

@ -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);

View File

@ -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 {

View File

@ -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());

View File

@ -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("!="),

View File

@ -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 {

View File

@ -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);
}

View File

@ -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 {

View File

@ -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;

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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;
}

View File

@ -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) {

View File

@ -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 {

View File

@ -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) {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {

View File

@ -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));

View File

@ -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")),

View File

@ -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());
}
}

View File

@ -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

View File

@ -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