Skip to content
This repository was archived by the owner on Oct 31, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,21 @@ public interface ArgumentConstraint {
* @throws ArityException when there are not enough arguments left to satisfy the constraint
* @throws ArgumentTypeException when an argument does not satisfy the constraint
*/
public <T> void check(Adapter<T> runtime, Iterator<FunctionArgument<T>> arguments);
<T> void check(Adapter<T> runtime, Iterator<FunctionArgument<T>> arguments);

/**
* @return the minimum number of arguments required.
*/
public int minArity();
int minArity();

/**
* @return the maximum number of arguments accepted.
*/
public int maxArity();
int maxArity();

/**
* @return a string representation of the types accepted. Used to construct
* user friendly error messages.
*/
public String expectedType();
String expectedType();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,31 @@

@SuppressWarnings("serial")
public class ArityException extends FunctionCallException {
public ArityException(String functionName, int minArity, int maxArity, int numArguments) {
this(functionName, minArity, maxArity, numArguments, null);
public ArityException(Function function, int numArguments) {
this(function, numArguments, null);
}

public ArityException(String functionName, int minArity, int maxArity, int numArguments, Throwable cause) {
super(createMessage(functionName, minArity, maxArity, numArguments), cause);
public ArityException(Function function, int numArguments, Throwable cause) {
super(createMessage(function, numArguments, true), cause);
}

private static String createMessage(String functionName, int minArity, int maxArity, int numArguments) {
public static String createMessage(Function function, int numArguments, boolean initialUppercase) {
int minArity = function.argumentConstraints().minArity();
int maxArity = function.argumentConstraints().maxArity();
StringBuilder buffer = new StringBuilder();
if (initialUppercase) {
buffer.append("Invalid");
} else {
buffer.append("invalid");
}
buffer.append(" arity calling \"").append(function.name()).append("\"");
if (maxArity == minArity) {
return String.format("Invalid arity calling \"%s\": expected %d but was %d", functionName, minArity, numArguments);
buffer.append(String.format(" (expected %d but was %d)", minArity, numArguments));
} else if (numArguments < minArity) {
return String.format("Invalid arity calling \"%s\": expected at least %d but was %d", functionName, minArity, numArguments);
buffer.append(String.format(" (expected at least %d but was %d)", minArity, numArguments));
} else {
return String.format("Invalid arity calling \"%s\": expected at most %d but was %d", functionName, maxArity, numArguments);
buffer.append(String.format(" (expected at most %d but was %d)", maxArity, numArguments));
}
return buffer.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ public String name() {
return name;
}

@Override
public ArgumentConstraint argumentConstraints() {
return argumentConstraints;
}

/**
* Call this function with a list of arguments.
*
Expand All @@ -121,10 +126,10 @@ protected <T> void checkArguments(Adapter<T> runtime, List<FunctionArgument<T>>
Iterator<FunctionArgument<T>> argumentIterator = arguments.iterator();
argumentConstraints.check(runtime, argumentIterator);
if (argumentIterator.hasNext()) {
throw new ArityException(name(), argumentConstraints.minArity(), argumentConstraints.maxArity(), arguments.size());
throw new ArityException(this, arguments.size());
}
} catch (ArgumentConstraints.InternalArityException e) {
throw new ArityException(name(), argumentConstraints.minArity(), argumentConstraints.maxArity(), arguments.size(), e);
throw new ArityException(this, arguments.size(), e);
} catch (ArgumentConstraints.InternalArgumentTypeException e) {
throw new ArgumentTypeException(name(), e.expectedType(), e.actualType(), e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ public interface Function {
* The name is either automatically generated from the class name, or
* explicitly specified in the constructor.
*/
public String name();
String name();

/**
* Returns the constraints to use when checking the list of arguments before
* the function is called.
*/
ArgumentConstraint argumentConstraints();

/**
* Call this function with a list of arguments.
Expand All @@ -28,5 +34,5 @@ public interface Function {
* @throws ArgumentTypeException when the function is called with arguments of the wrong type
* @throws ArityException when the function is called with the wrong number of arguments
*/
public <T> T call(Adapter<T> runtime, List<FunctionArgument<T>> arguments);
<T> T call(Adapter<T> runtime, List<FunctionArgument<T>> arguments);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import io.burt.jmespath.Expression;
import io.burt.jmespath.Adapter;
import io.burt.jmespath.function.Function;
import io.burt.jmespath.function.ArgumentConstraint;
import io.burt.jmespath.function.ArityException;
import io.burt.jmespath.util.StringEscapeHelper;
import io.burt.jmespath.util.AntlrHelper;
import io.burt.jmespath.node.NodeFactory;
Expand Down Expand Up @@ -296,6 +298,13 @@ public Node<T> visitFunctionExpression(JmesPathParser.FunctionExpressionContext
if (implementation == null) {
Token token = ctx.NAME().getSymbol();
errors.parseError(String.format("unknown function \"%s\"", name), token.getStartIndex());
} else {
ArgumentConstraint argumentConstraints = implementation.argumentConstraints();
if (n < argumentConstraints.minArity() || n > argumentConstraints.maxArity()) {
Token token = ctx.NAME().getSymbol();
String message = ArityException.createMessage(implementation, n, false);
errors.parseError(message, token.getStartIndex());
}
}
return createSequenceIfChained(nodeFactory.createFunctionCall(implementation, args));
}
Expand Down
Loading