use of org.exist.xquery.value.SequenceType in project exist by eXist-db.
the class FunctionFactory method wrap.
/**
* Wrap a function call into a user defined function.
* This is used to handle dynamic function calls or partial
* function applications on built in functions.
*
* @param context current context
* @param call the function call to be wrapped
* @return a new function call referencing an inline function
* @throws XPathException in case of a static error
*/
public static FunctionCall wrap(XQueryContext context, Function call) throws XPathException {
final int argCount = call.getArgumentCount();
final QName[] variables = new QName[argCount];
final List<Expression> innerArgs = new ArrayList<>(argCount);
final List<Expression> wrapperArgs = new ArrayList<>(argCount);
final FunctionSignature signature = call.getSignature();
// the parameters of the newly created inline function:
final List<SequenceType> newParamTypes = new ArrayList<>();
final SequenceType[] paramTypes = signature.getArgumentTypes();
for (int i = 0; i < argCount; i++) {
final Expression param = call.getArgument(i);
wrapperArgs.add(param);
QName varName = new QName("vp" + i, XMLConstants.NULL_NS_URI);
variables[i] = varName;
final VariableReference ref = new VariableReference(context, varName);
innerArgs.add(ref);
// overloaded functions like concat may have an arbitrary number of arguments
if (i < paramTypes.length) {
newParamTypes.add(paramTypes[i]);
} else // overloaded function: add last sequence type
{
newParamTypes.add(paramTypes[paramTypes.length - 1]);
}
}
final SequenceType[] newParamArray = newParamTypes.toArray(new SequenceType[0]);
final FunctionSignature newSignature = new FunctionSignature(signature);
newSignature.setArgumentTypes(newParamArray);
final UserDefinedFunction func = new UserDefinedFunction(context, newSignature);
for (final QName varName : variables) {
func.addVariable(varName);
}
call.setArguments(innerArgs);
func.setFunctionBody(call);
final FunctionCall wrappedCall = new FunctionCall(context, func);
wrappedCall.setArguments(wrapperArgs);
return wrappedCall;
}
use of org.exist.xquery.value.SequenceType in project exist by eXist-db.
the class DeferredFunctionCallTest method ensure_argumentsToDeferredFunctionCall_AreNotLost_AfterReset_And_BeforeEval.
/**
* resetState() make be called on the UserDefinedFunction of a DeferredFunctionCall
* before the function is eval'd, this is because the evaluation is deferred!
* resetState() clears the currentArguments to the function, however for a deferred
* function call we must ensure that we still have these when eval() is called
* otherwise we will get an NPE!
*
* This test tries to prove that eval can be called after resetState without
* causing problems for a DeferredFunctionCall
*
* The test implementation, due to the nature of the code under test, is rather horrible
* and mostly consists of tightly coupled mocking code making it very brittle.
* The interesting aspect of this test case is at the bottom of the function itself.
*/
@Test
public void ensure_argumentsToDeferredFunctionCall_AreNotLost_AfterReset_And_BeforeEval() throws XPathException {
// mocks for FunctionCall constructor
XQueryContext mockContext = EasyMock.createNiceMock(XQueryContext.class);
// mocks for evalFunction()
Sequence mockContextSequence = EasyMock.createMock(Sequence.class);
Item mockContextItem = EasyMock.createMock(Item.class);
Sequence[] mockSeq = { Sequence.EMPTY_SEQUENCE };
int nextExpressionId = 1234;
SequenceType[] mockArgumentTypes = { new SequenceType(Type.NODE, Cardinality.EMPTY_SEQUENCE) };
// mock for functionDef
FunctionSignature mockFunctionSignature = EasyMock.createMock(FunctionSignature.class);
SequenceType mockReturnType = EasyMock.createMock(SequenceType.class);
LocalVariable mockMark = EasyMock.createMock(LocalVariable.class);
Expression mockExpression = EasyMock.createMock(Expression.class);
// expectations for UserDefinedFunction constructor
expect(mockContext.nextExpressionId()).andReturn(nextExpressionId++);
expect(mockExpression.simplify()).andReturn(mockExpression);
// expectations for FunctionCall constructor
expect(mockContext.nextExpressionId()).andReturn(nextExpressionId++);
// expectations for FunctionCall.setFunction
expect(mockFunctionSignature.getReturnType()).andReturn(mockReturnType);
expect(mockReturnType.getCardinality()).andReturn(Cardinality.ZERO_OR_MORE);
expect(mockReturnType.getPrimaryType()).andReturn(Type.NODE).times(4);
expect(mockContext.nextExpressionId()).andReturn(nextExpressionId++);
// expectations for functionCall.evalFunction
expect(mockContext.isProfilingEnabled()).andReturn(false);
// expectations for DeferredFunctionCallImpl.setup
expect(mockFunctionSignature.getReturnType()).andReturn(mockReturnType);
expect(mockReturnType.getCardinality()).andReturn(Cardinality.ZERO_OR_MORE);
expect(mockReturnType.getPrimaryType()).andReturn(Type.NODE).times(4);
expect(mockContext.nextExpressionId()).andReturn(nextExpressionId++);
// expectations for DeferredFunctionCall.execute
mockContext.pushDocumentContext();
mockContext.functionStart(mockFunctionSignature);
mockContext.stackEnter((Expression) anyObject());
expect(mockContext.declareVariableBinding((LocalVariable) anyObject())).andReturn(null);
expect(mockFunctionSignature.getArgumentTypes()).andReturn(mockArgumentTypes);
expect(mockExpression.eval(null, null)).andReturn(Sequence.EMPTY_SEQUENCE);
mockExpression.resetState(true);
mockContext.stackLeave((Expression) anyObject());
mockContext.functionEnd();
mockContext.popDocumentContext();
replay(mockContext, mockFunctionSignature, mockReturnType, mockExpression);
UserDefinedFunction userDefinedFunction = new UserDefinedFunction(mockContext, mockFunctionSignature);
userDefinedFunction.addVariable("testParam");
userDefinedFunction.setFunctionBody(mockExpression);
FunctionCall functionCall = new FunctionCall(mockContext, userDefinedFunction);
// ensure DeferredFunction
functionCall.setRecursive(true);
/**
* this is the interesting bit **
*/
// 1) Call reset, this should set current arguments to null
functionCall.resetState(true);
// ensure DeferredFunction
functionCall.setRecursive(true);
// 2) check UserDefinedFunction.currentArguments == null
assertNull(userDefinedFunction.getCurrentArguments());
// so the currentArguments have been set to null, but deferredFunction should have its own copy
// 3) Call functionCall.eval, if we dont get an NPE on reading currentArguments, then success :-)
DeferredFunctionCall dfc = (DeferredFunctionCall) functionCall.evalFunction(mockContextSequence, mockContextItem, mockSeq);
dfc.execute();
/**
* end interesting bit **
*/
verify(mockContext, mockFunctionSignature, mockReturnType, mockExpression);
}
use of org.exist.xquery.value.SequenceType in project exist by eXist-db.
the class InspectFunctionHelper method writeParameters.
private static void writeParameters(final FunctionSignature sig, final MemTreeBuilder builder) {
final SequenceType[] arguments = sig.getArgumentTypes();
if (arguments != null) {
final AttributesImpl attribs = new AttributesImpl();
for (final SequenceType type : arguments) {
attribs.clear();
attribs.addAttribute("", "type", "type", "CDATA", Type.getTypeName(type.getPrimaryType()));
attribs.addAttribute("", "cardinality", "cardinality", "CDATA", type.getCardinality().getHumanDescription());
if (type instanceof FunctionParameterSequenceType) {
attribs.addAttribute("", "var", "var", "CDATA", ((FunctionParameterSequenceType) type).getAttributeName());
}
builder.startElement(ARGUMENT_QNAME, attribs);
if (type instanceof FunctionParameterSequenceType) {
builder.characters(((FunctionParameterSequenceType) type).getDescription());
}
builder.endElement();
}
}
}
use of org.exist.xquery.value.SequenceType in project exist by eXist-db.
the class InspectFunctionHelper method generateDocs.
/**
* Generate an XML fragment containing information about the function identified by its signature.
*
* @param sig the signature of the function to describe
* @param func the function implementation. If provided, the method will also inspect the function body
* and list all functions called from the current function.
* @param builder builder used to create the XML
* @return nodeNr of the generated element
* @throws XPathException in case of dynamic error
*/
public static int generateDocs(final FunctionSignature sig, final UserDefinedFunction func, final MemTreeBuilder builder) throws XPathException {
XQDocHelper.parse(sig);
final AttributesImpl attribs = new AttributesImpl();
attribs.addAttribute("", "name", "name", "CDATA", sig.getName().toString());
attribs.addAttribute("", "module", "module", "CDATA", sig.getName().getNamespaceURI());
final int nodeNr = builder.startElement(FUNCTION_QNAME, attribs);
writeParameters(sig, builder);
final SequenceType returnType = sig.getReturnType();
if (returnType != null) {
attribs.clear();
attribs.addAttribute("", "type", "type", "CDATA", Type.getTypeName(returnType.getPrimaryType()));
attribs.addAttribute("", "cardinality", "cardinality", "CDATA", returnType.getCardinality().getHumanDescription());
builder.startElement(RETURN_QNAME, attribs);
if (returnType instanceof FunctionReturnSequenceType) {
final FunctionReturnSequenceType type = (FunctionReturnSequenceType) returnType;
builder.characters(type.getDescription());
}
builder.endElement();
}
writeAnnotations(sig, builder);
if (sig.getDescription() != null) {
builder.startElement(DESCRIPTION_QNAME, null);
builder.characters(sig.getDescription());
builder.endElement();
}
final Map<String, String> metadata = sig.getMetadata();
if (metadata != null) {
for (final Map.Entry<String, String> meta : metadata.entrySet()) {
builder.startElement(new QName(meta.getKey(), XMLConstants.NULL_NS_URI), null);
builder.characters(meta.getValue());
builder.endElement();
}
}
if (sig.isDeprecated()) {
builder.startElement(DEPRECATED_QNAME, null);
builder.characters(sig.getDeprecated());
builder.endElement();
}
if (func != null) {
generateDependencies(func, builder);
}
builder.endElement();
return nodeNr;
}
use of org.exist.xquery.value.SequenceType in project exist by eXist-db.
the class TypeswitchExpression method eval.
public Sequence eval(Sequence contextSequence, Item contextItem) throws XPathException {
if (contextItem != null) {
contextSequence = contextItem.toSequence();
}
final Sequence opSeq = operand.eval(contextSequence);
Sequence result = null;
final LocalVariable mark = context.markLocalVariables(false);
try {
for (int i = 0; i < cases.size() && result == null; i++) {
final Case next = cases.get(i);
for (SequenceType type : next.types) {
if (checkType(type, opSeq)) {
if (next.variable != null) {
final LocalVariable var = new LocalVariable(next.variable);
var.setSequenceType(type);
var.setValue(opSeq);
var.setContextDocs(operand.getContextDocSet());
var.checkType();
context.declareVariableBinding(var);
}
result = next.returnClause.eval(contextSequence);
break;
}
}
}
if (result == null) {
if (defaultClause.variable != null) {
final LocalVariable var = new LocalVariable(defaultClause.variable);
var.setValue(opSeq);
var.setContextDocs(operand.getContextDocSet());
context.declareVariableBinding(var);
}
result = defaultClause.returnClause.eval(contextSequence);
}
} finally {
context.popLocalVariables(mark, result);
}
return result;
}
Aggregations