Search in sources :

Example 6 with SequenceType

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;
}
Also used : QName(org.exist.dom.QName) ArrayList(java.util.ArrayList) SequenceType(org.exist.xquery.value.SequenceType)

Example 7 with SequenceType

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);
}
Also used : Sequence(org.exist.xquery.value.Sequence) SequenceType(org.exist.xquery.value.SequenceType) Item(org.exist.xquery.value.Item) Test(org.junit.Test)

Example 8 with SequenceType

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();
        }
    }
}
Also used : AttributesImpl(org.xml.sax.helpers.AttributesImpl) FunctionParameterSequenceType(org.exist.xquery.value.FunctionParameterSequenceType) SequenceType(org.exist.xquery.value.SequenceType) FunctionParameterSequenceType(org.exist.xquery.value.FunctionParameterSequenceType) FunctionReturnSequenceType(org.exist.xquery.value.FunctionReturnSequenceType)

Example 9 with SequenceType

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;
}
Also used : AttributesImpl(org.xml.sax.helpers.AttributesImpl) FunctionReturnSequenceType(org.exist.xquery.value.FunctionReturnSequenceType) QName(org.exist.dom.QName) SequenceType(org.exist.xquery.value.SequenceType) FunctionParameterSequenceType(org.exist.xquery.value.FunctionParameterSequenceType) FunctionReturnSequenceType(org.exist.xquery.value.FunctionReturnSequenceType) Map(java.util.Map)

Example 10 with SequenceType

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;
}
Also used : Sequence(org.exist.xquery.value.Sequence) SequenceType(org.exist.xquery.value.SequenceType)

Aggregations

SequenceType (org.exist.xquery.value.SequenceType)11 FunctionParameterSequenceType (org.exist.xquery.value.FunctionParameterSequenceType)6 FunctionReturnSequenceType (org.exist.xquery.value.FunctionReturnSequenceType)5 ArrayList (java.util.ArrayList)3 QName (org.exist.dom.QName)3 Sequence (org.exist.xquery.value.Sequence)3 AttributesImpl (org.xml.sax.helpers.AttributesImpl)3 Map (java.util.Map)2 HashMap (java.util.HashMap)1 org.exist.xquery (org.exist.xquery)1 FunctionReference (org.exist.xquery.value.FunctionReference)1 Item (org.exist.xquery.value.Item)1 ValueSequence (org.exist.xquery.value.ValueSequence)1 Sequence (org.exquery.xquery.Sequence)1 TypedArgumentValue (org.exquery.xquery.TypedArgumentValue)1 Test (org.junit.Test)1