Partial dynamic function applications
This introduces support for partial applications on dynamic functions. The test cases are comprehensive and the implementation should be quite stable. Even though the base higher-order function implementation was based on the work of Dimitre Novatchev[0], I have chosen a different route for partial application: Novatchev's method relies on storing partially applied arguments as nodes, together with their types. The types are detected the best they can be, with accuracy varying wildly depending on whether a schema-aware processor is present. But regardless, that method would not retain node context. Sequences, however, do. By using sequences, we allow the processor to retain all type and context information perfectly without any additional work that is inaccurate, adds complexity, and likely to cause subtle problems. It will also support any types that we are unaware of. As Novatchev mentions: The argument type-detection that f:curry() uses has been implemented only for the builtin XML Schema datatypes. It will not recognize the user-defined type of an argument, which can be created by an user of a Schema-Aware (SA) XSLT 2.0 processor.[0] This is not a problem with hoxsl. [0]: http://conferences.idealliance.org/extreme/html/2006/Novatchev01/EML2006Novatchev01.htmlmaster
commit
7fd1618390
5
Makefile
5
Makefile
|
@ -19,12 +19,13 @@
|
||||||
path_src := src
|
path_src := src
|
||||||
path_test := test
|
path_test := test
|
||||||
|
|
||||||
test_in_apply_gen := $(path_test)/transform/apply-gen-test-in.xsl.apply
|
test_apply := $(path_test)/apply/partial-test.xsl.apply \
|
||||||
|
$(path_test)/transform/apply-gen-test-in.xsl.apply
|
||||||
|
|
||||||
.PHONY: check test
|
.PHONY: check test
|
||||||
|
|
||||||
test: check
|
test: check
|
||||||
check: $(test_in_apply_gen)
|
check: $(test_apply)
|
||||||
$(path_test)/runner
|
$(path_test)/runner
|
||||||
|
|
||||||
%.apply: %
|
%.apply: %
|
||||||
|
|
34
README.md
34
README.md
|
@ -15,7 +15,8 @@ functions and XSLT templates that take XSLT as input and produce XSLT
|
||||||
as output.
|
as output.
|
||||||
|
|
||||||
The system is fully tested---see the test cases for additional
|
The system is fully tested---see the test cases for additional
|
||||||
documentation as this project gets under way.
|
documentation as this project gets under way. This README will serve
|
||||||
|
as an informal manual until official documentation is produced.
|
||||||
|
|
||||||
|
|
||||||
## Higher-Order Functions
|
## Higher-Order Functions
|
||||||
|
@ -25,8 +26,8 @@ proprietary versions of their software. Others still may wish to
|
||||||
continue using XSLT 2.0.
|
continue using XSLT 2.0.
|
||||||
|
|
||||||
There are various approaches/kluges for this problem in earlier
|
There are various approaches/kluges for this problem in earlier
|
||||||
versions of XSLT; this implementation is motivated by Dimitre
|
versions of XSLT; the basis of this implementation is motivated by
|
||||||
Novatchev's work on [higher-order functions in FXSL][nova-ho].
|
Dimitre Novatchev's work on [higher-order functions in FXSL][nova-ho].
|
||||||
|
|
||||||
For example, consider an implementation of a filter function that
|
For example, consider an implementation of a filter function that
|
||||||
accepts a node set and a predicate:
|
accepts a node set and a predicate:
|
||||||
|
@ -66,6 +67,33 @@ work is needed. This can be included as part of a build process, and
|
||||||
the output included within a distribution.
|
the output included within a distribution.
|
||||||
|
|
||||||
|
|
||||||
|
### Partial Applications
|
||||||
|
Dynamic function applications using `f:apply` are partially applied if
|
||||||
|
the number of arguments provided is less than the arity of the target
|
||||||
|
function.
|
||||||
|
|
||||||
|
```xml
|
||||||
|
<!-- produces a new dynamic function of arity 5 - 3 = 2 -->
|
||||||
|
<variable name="partial"
|
||||||
|
select="f:apply( my:arity5(), 1, 2, 3 )" />
|
||||||
|
|
||||||
|
<!-- consequently, currying is supported -->
|
||||||
|
<variable name="result"
|
||||||
|
select="f:apply( f:apply( $partial, 4 ), 5 )" />
|
||||||
|
|
||||||
|
<!-- equiv = true() -->
|
||||||
|
<variable name="equiv"
|
||||||
|
select="$result
|
||||||
|
= f:apply( my:arity5(), 1, 2, 3, 4, 5 )
|
||||||
|
= my:arity5( 1, 2, 3, 4, 5 )" />
|
||||||
|
```
|
||||||
|
|
||||||
|
The implementation of partial function applications avoids the
|
||||||
|
complexity and inaccuracies of [Novatchev's approach][nova-ho] by
|
||||||
|
using only sequences, allowing arguments to retain their type and
|
||||||
|
context.
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
This program is free software: you can redistribute it and/or modify it
|
This program is free software: you can redistribute it and/or modify it
|
||||||
under the terms of the GNU General Public License as published by the Free
|
under the terms of the GNU General Public License as published by the Free
|
||||||
|
|
171
src/apply.xsl
171
src/apply.xsl
|
@ -1,4 +1,4 @@
|
||||||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<!--
|
<!--
|
||||||
Dynamic function application
|
Dynamic function application
|
||||||
|
|
||||||
|
@ -30,86 +30,73 @@
|
||||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
xmlns:f="http://www.lovullo.com/hoxsl/apply">
|
xmlns:f="http://www.lovullo.com/hoxsl/apply">
|
||||||
|
|
||||||
|
<import href="apply/partial.xsl" />
|
||||||
|
|
||||||
|
|
||||||
<function name="f:apply">
|
<function name="f:apply">
|
||||||
<param name="fnref" as="element(f:ref)" />
|
<param name="fnref" as="item()+" />
|
||||||
|
|
||||||
<apply-templates select="$fnref" mode="f:apply" />
|
<sequence select="f:partial( $fnref, () )" />
|
||||||
</function>
|
</function>
|
||||||
|
|
||||||
|
|
||||||
<function name="f:apply">
|
<function name="f:apply">
|
||||||
<param name="fnref" as="element(f:ref)" />
|
<param name="fnref" as="item()+" />
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
|
|
||||||
<apply-templates select="$fnref" mode="f:apply">
|
<sequence select="f:partial( $fnref, $arg1 )" />
|
||||||
<with-param name="arg1" select="$arg1" />
|
|
||||||
</apply-templates>
|
|
||||||
</function>
|
</function>
|
||||||
|
|
||||||
|
|
||||||
<function name="f:apply">
|
<function name="f:apply">
|
||||||
<param name="fnref" as="element(f:ref)" />
|
<param name="fnref" as="item()+" />
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
<param name="arg2" />
|
<param name="arg2" />
|
||||||
|
|
||||||
<apply-templates select="$fnref" mode="f:apply">
|
<sequence select="f:partial( $fnref,
|
||||||
<with-param name="arg1" select="$arg1" />
|
($arg1, $arg2) )" />
|
||||||
<with-param name="arg2" select="$arg2" />
|
|
||||||
</apply-templates>
|
|
||||||
</function>
|
</function>
|
||||||
|
|
||||||
|
|
||||||
<function name="f:apply">
|
<function name="f:apply">
|
||||||
<param name="fnref" as="element(f:ref)" />
|
<param name="fnref" as="item()+" />
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
<param name="arg2" />
|
<param name="arg2" />
|
||||||
<param name="arg3" />
|
<param name="arg3" />
|
||||||
|
|
||||||
<apply-templates select="$fnref" mode="f:apply">
|
<sequence select="f:partial( $fnref,
|
||||||
<with-param name="arg1" select="$arg1" />
|
($arg1, $arg2, $arg3) )" />
|
||||||
<with-param name="arg2" select="$arg2" />
|
|
||||||
<with-param name="arg3" select="$arg3" />
|
|
||||||
</apply-templates>
|
|
||||||
</function>
|
</function>
|
||||||
|
|
||||||
|
|
||||||
<function name="f:apply">
|
<function name="f:apply">
|
||||||
<param name="fnref" as="element(f:ref)" />
|
<param name="fnref" as="item()+" />
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
<param name="arg2" />
|
<param name="arg2" />
|
||||||
<param name="arg3" />
|
<param name="arg3" />
|
||||||
<param name="arg4" />
|
<param name="arg4" />
|
||||||
|
|
||||||
<apply-templates select="$fnref" mode="f:apply">
|
<sequence select="f:partial( $fnref,
|
||||||
<with-param name="arg1" select="$arg1" />
|
($arg1, $arg2, $arg3, $arg4) )" />
|
||||||
<with-param name="arg2" select="$arg2" />
|
|
||||||
<with-param name="arg3" select="$arg3" />
|
|
||||||
<with-param name="arg4" select="$arg4" />
|
|
||||||
</apply-templates>
|
|
||||||
</function>
|
</function>
|
||||||
|
|
||||||
|
|
||||||
<function name="f:apply">
|
<function name="f:apply">
|
||||||
<param name="fnref" as="element(f:ref)" />
|
<param name="fnref" as="item()+" />
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
<param name="arg2" />
|
<param name="arg2" />
|
||||||
<param name="arg3" />
|
<param name="arg3" />
|
||||||
<param name="arg4" />
|
<param name="arg4" />
|
||||||
<param name="arg5" />
|
<param name="arg5" />
|
||||||
|
|
||||||
<apply-templates select="$fnref" mode="f:apply">
|
<sequence select="f:partial( $fnref,
|
||||||
<with-param name="arg1" select="$arg1" />
|
($arg1, $arg2, $arg3, $arg4,
|
||||||
<with-param name="arg2" select="$arg2" />
|
$arg5) )" />
|
||||||
<with-param name="arg3" select="$arg3" />
|
|
||||||
<with-param name="arg4" select="$arg4" />
|
|
||||||
<with-param name="arg5" select="$arg5" />
|
|
||||||
</apply-templates>
|
|
||||||
</function>
|
</function>
|
||||||
|
|
||||||
|
|
||||||
<function name="f:apply">
|
<function name="f:apply">
|
||||||
<param name="fnref" as="element(f:ref)" />
|
<param name="fnref" as="item()+" />
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
<param name="arg2" />
|
<param name="arg2" />
|
||||||
<param name="arg3" />
|
<param name="arg3" />
|
||||||
|
@ -117,19 +104,14 @@
|
||||||
<param name="arg5" />
|
<param name="arg5" />
|
||||||
<param name="arg6" />
|
<param name="arg6" />
|
||||||
|
|
||||||
<apply-templates select="$fnref" mode="f:apply">
|
<sequence select="f:partial( $fnref,
|
||||||
<with-param name="arg1" select="$arg1" />
|
($arg1, $arg2, $arg3, $arg4,
|
||||||
<with-param name="arg2" select="$arg2" />
|
$arg5, $arg6) )" />
|
||||||
<with-param name="arg3" select="$arg3" />
|
|
||||||
<with-param name="arg4" select="$arg4" />
|
|
||||||
<with-param name="arg5" select="$arg5" />
|
|
||||||
<with-param name="arg6" select="$arg6" />
|
|
||||||
</apply-templates>
|
|
||||||
</function>
|
</function>
|
||||||
|
|
||||||
|
|
||||||
<function name="f:apply">
|
<function name="f:apply">
|
||||||
<param name="fnref" as="element(f:ref)" />
|
<param name="fnref" as="item()+" />
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
<param name="arg2" />
|
<param name="arg2" />
|
||||||
<param name="arg3" />
|
<param name="arg3" />
|
||||||
|
@ -138,20 +120,14 @@
|
||||||
<param name="arg6" />
|
<param name="arg6" />
|
||||||
<param name="arg7" />
|
<param name="arg7" />
|
||||||
|
|
||||||
<apply-templates select="$fnref" mode="f:apply">
|
<sequence select="f:partial( $fnref,
|
||||||
<with-param name="arg1" select="$arg1" />
|
($arg1, $arg2, $arg3, $arg4,
|
||||||
<with-param name="arg2" select="$arg2" />
|
$arg5, $arg6, $arg7) )" />
|
||||||
<with-param name="arg3" select="$arg3" />
|
|
||||||
<with-param name="arg4" select="$arg4" />
|
|
||||||
<with-param name="arg5" select="$arg5" />
|
|
||||||
<with-param name="arg6" select="$arg6" />
|
|
||||||
<with-param name="arg7" select="$arg7" />
|
|
||||||
</apply-templates>
|
|
||||||
</function>
|
</function>
|
||||||
|
|
||||||
|
|
||||||
<function name="f:apply">
|
<function name="f:apply">
|
||||||
<param name="fnref" as="element(f:ref)" />
|
<param name="fnref" as="item()+" />
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
<param name="arg2" />
|
<param name="arg2" />
|
||||||
<param name="arg3" />
|
<param name="arg3" />
|
||||||
|
@ -161,16 +137,9 @@
|
||||||
<param name="arg7" />
|
<param name="arg7" />
|
||||||
<param name="arg8" />
|
<param name="arg8" />
|
||||||
|
|
||||||
<apply-templates select="$fnref" mode="f:apply">
|
<sequence select="f:partial( $fnref,
|
||||||
<with-param name="arg1" select="$arg1" />
|
($arg1, $arg2, $arg3, $arg4,
|
||||||
<with-param name="arg2" select="$arg2" />
|
$arg5, $arg6, $arg7, $arg8) )" />
|
||||||
<with-param name="arg3" select="$arg3" />
|
|
||||||
<with-param name="arg4" select="$arg4" />
|
|
||||||
<with-param name="arg5" select="$arg5" />
|
|
||||||
<with-param name="arg6" select="$arg6" />
|
|
||||||
<with-param name="arg7" select="$arg7" />
|
|
||||||
<with-param name="arg8" select="$arg8" />
|
|
||||||
</apply-templates>
|
|
||||||
</function>
|
</function>
|
||||||
|
|
||||||
|
|
||||||
|
@ -195,18 +164,76 @@
|
||||||
|
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
Attempt to retrieve arity of delayed function
|
Create a reference to dynamic function @var{name} with arity
|
||||||
|
@var{arity}
|
||||||
|
|
||||||
The input must be a function reference. If the arity cannot be
|
This function @emph{does not} verify that the function @var{name}
|
||||||
determined, -1 is returned.
|
exists, nor does it verify that the provided @var{arity} is valid
|
||||||
|
for it. Further, the returned function reference will work
|
||||||
|
@emph{only with dynamic functions}—that is, an application template
|
||||||
|
is needed. See @file{transform/apply-gen.xsl} for more information
|
||||||
|
and examples.
|
||||||
-->
|
-->
|
||||||
<function name="f:arity" as="xs:decimal">
|
<function name="f:make-ref" as="element( f:ref )">
|
||||||
<param name="fnref" as="element(f:ref)" />
|
<param name="name" as="xs:QName" />
|
||||||
|
<param name="arity" as="xs:integer" />
|
||||||
|
|
||||||
<sequence select="if ( $fnref/@arity ) then
|
<variable name="ns"
|
||||||
$fnref/@arity
|
select="namespace-uri-from-QName( $name )" />
|
||||||
else
|
|
||||||
-1" />
|
<f:ref arity="{$arity}">
|
||||||
|
<element name="{$name}"
|
||||||
|
namespace="{$ns}" />
|
||||||
|
</f:ref>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Determines whether @var{fnref} represents a valid dynamic function
|
||||||
|
reference
|
||||||
|
|
||||||
|
This can be used to determine if @var{fnref} is valid as input to
|
||||||
|
other functions, some of which may produce an error if called with
|
||||||
|
an invalid dynamic function reference.
|
||||||
|
|
||||||
|
@i{Implementation details:} To be valid, @var{fnref} must:
|
||||||
|
|
||||||
|
@enumerate
|
||||||
|
@item Be an element of type @code{f:ref};
|
||||||
|
@item Have a numeric @code{@arity}; and
|
||||||
|
@item Have a child target function node.
|
||||||
|
@enumerate
|
||||||
|
-->
|
||||||
|
<function name="f:is-ref" as="xs:boolean">
|
||||||
|
<param name="fnref" as="item()*" />
|
||||||
|
|
||||||
|
<variable name="ref" select="$fnref[ 1 ]" />
|
||||||
|
|
||||||
|
<!-- for @arity check: note that NaN != NaN -->
|
||||||
|
<sequence select="$ref instance of element( f:ref )
|
||||||
|
and number( $ref/@arity ) = number( $ref/@arity )
|
||||||
|
and exists( $ref/*[ 1 ] )" />
|
||||||
|
</function>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Retrieve the QName of the target dynamic function
|
||||||
|
|
||||||
|
Usually, this would match precisely the QName of the target
|
||||||
|
function.
|
||||||
|
|
||||||
|
@i{Implementation details:} This actually represents the QName of
|
||||||
|
the @emph{application template}, which could differ from the target
|
||||||
|
function name. One reason this may be the case is to provide a
|
||||||
|
function alias.
|
||||||
|
-->
|
||||||
|
<function name="f:QName" as="xs:QName?">
|
||||||
|
<param name="fnref" as="element( f:ref )" />
|
||||||
|
|
||||||
|
<variable name="target" as="element()?"
|
||||||
|
select="$fnref/element()[ 1 ]" />
|
||||||
|
|
||||||
|
<sequence select="node-name( $target )" />
|
||||||
</function>
|
</function>
|
||||||
|
|
||||||
</stylesheet>
|
</stylesheet>
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Arity calculations on dynamic and partially applied functions
|
||||||
|
|
||||||
|
Copyright (C) 2014 LoVullo Associates, Inc.
|
||||||
|
|
||||||
|
This file is part of hoxsl.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<stylesheet version="2.0"
|
||||||
|
xmlns="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns:f="http://www.lovullo.com/hoxsl/apply">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Attempt to retrieve arity of dynamic function
|
||||||
|
|
||||||
|
The input must be a function reference. Partially applied function
|
||||||
|
references will have an arity equivalent to the remaining parameters
|
||||||
|
in the original function.
|
||||||
|
|
||||||
|
If the arity cannot be determined, -1 is returned.
|
||||||
|
-->
|
||||||
|
<function name="f:arity" as="xs:decimal">
|
||||||
|
<param name="fnref" as="element(f:ref)" />
|
||||||
|
|
||||||
|
<sequence select="if ( $fnref/@arity ) then
|
||||||
|
$fnref/@arity
|
||||||
|
else
|
||||||
|
-1" />
|
||||||
|
</function>
|
||||||
|
|
||||||
|
</stylesheet>
|
|
@ -0,0 +1,202 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Partial function application
|
||||||
|
|
||||||
|
Copyright (C) 2014 LoVullo Associates, Inc.
|
||||||
|
|
||||||
|
This file is part of hoxsl.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Partial applications may only be used with dynamic functions
|
||||||
|
(functions compatible with `f:apply').
|
||||||
|
-->
|
||||||
|
|
||||||
|
<stylesheet version="2.0"
|
||||||
|
xmlns="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns:f="http://www.lovullo.com/hoxsl/apply"
|
||||||
|
xmlns:_f="http://www.lovullo.com/hoxsl/apply/_priv">
|
||||||
|
|
||||||
|
<import href="arity.xsl" />
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Partially apply dynamic function reference @var{fnref}
|
||||||
|
|
||||||
|
When provided to @code{f:apply}, @var{fnref} will be applied with
|
||||||
|
@var{args} as its beginning argments, followed by any arguments to
|
||||||
|
`f:apply'.
|
||||||
|
|
||||||
|
Note that you usually do not have to invoke this function directly:
|
||||||
|
the dynamic function calls will handle currying/partial application
|
||||||
|
for you, which has a much more inviting syntax.
|
||||||
|
|
||||||
|
Partially applied functions may continue to be partially applied
|
||||||
|
until their parameters are exhausted. This can be used to implement
|
||||||
|
currying.
|
||||||
|
|
||||||
|
When destructuring the result of this function, note that the
|
||||||
|
returned function reference may not match @var{fnref} by reference,
|
||||||
|
as it may have been modified.
|
||||||
|
-->
|
||||||
|
<function name="f:partial" as="item()+">
|
||||||
|
<param name="fnref" as="item()+" />
|
||||||
|
<param name="args" as="item()*" />
|
||||||
|
|
||||||
|
<!-- perform type check here, not above, since we can be passed a
|
||||||
|
sequence (e.g.a partially applied function) -->
|
||||||
|
<variable name="ref"
|
||||||
|
as="element(f:ref)"
|
||||||
|
select="$fnref[ 1 ]" />
|
||||||
|
|
||||||
|
<variable name="argout" as="item()*">
|
||||||
|
<!-- include any previously applied arguments (if we're partially
|
||||||
|
applying a partial application) -->
|
||||||
|
<sequence select="remove( $fnref, 1 )" />
|
||||||
|
|
||||||
|
<!-- nested sequences are implicitly flattened, so we're not
|
||||||
|
returning a sub-sequence here -->
|
||||||
|
<sequence select="$args" />
|
||||||
|
</variable>
|
||||||
|
|
||||||
|
<variable name="argn" as="xs:decimal"
|
||||||
|
select="count( $argout )" />
|
||||||
|
|
||||||
|
<variable name="arity" as="xs:decimal"
|
||||||
|
select="f:arity( $ref )" />
|
||||||
|
|
||||||
|
<choose>
|
||||||
|
<when test="$argn eq $arity">
|
||||||
|
<sequence select="_f:apply-partial( $ref, $argout )" />
|
||||||
|
</when>
|
||||||
|
|
||||||
|
<when test="$argn gt $arity">
|
||||||
|
<apply-templates mode="f:partial-arity-error-hook"
|
||||||
|
select="$ref">
|
||||||
|
<with-param name="args" select="$argout" />
|
||||||
|
<with-param name="arity" select="$arity" />
|
||||||
|
<with-param name="argn" select="$argn" />
|
||||||
|
</apply-templates>
|
||||||
|
</when>
|
||||||
|
|
||||||
|
<otherwise>
|
||||||
|
<f:ref>
|
||||||
|
<sequence select="$ref/@*" />
|
||||||
|
|
||||||
|
<attribute name="partial"
|
||||||
|
select="count( $args )" />
|
||||||
|
|
||||||
|
<sequence select="$ref/*" />
|
||||||
|
</f:ref>
|
||||||
|
|
||||||
|
<sequence select="$argout" />
|
||||||
|
</otherwise>
|
||||||
|
</choose>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Determines whether FNREF is a partial application
|
||||||
|
|
||||||
|
You really should not rely on this for your code—it is intended for
|
||||||
|
internal use. Instead, treat partial applications opaquely as their
|
||||||
|
own functions.
|
||||||
|
-->
|
||||||
|
<function name="f:is-partial" as="xs:boolean">
|
||||||
|
<param name="fnref" as="item()+" />
|
||||||
|
|
||||||
|
<!-- if we're passed a sequence, then the function portion of the
|
||||||
|
reference is first; all others are arguments -->
|
||||||
|
<variable name="fn"
|
||||||
|
select="$fnref[ 1 ]" />
|
||||||
|
|
||||||
|
<!-- we never want to fail, so we perform our type check here rather
|
||||||
|
than using param/@as -->
|
||||||
|
<sequence select="$fn instance of element(f:ref)
|
||||||
|
and exists( $fn/@partial )
|
||||||
|
and number( $fn/@partial ) gt 0" />
|
||||||
|
</function>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Hook invoked when the number of arguments of a partial application
|
||||||
|
exceeds the parameter count of the target function
|
||||||
|
|
||||||
|
The `target' function is the root of the partial application—given
|
||||||
|
@t{Fx @arrow{} F'y @arrow{} F''z}, @t{F} is the target.
|
||||||
|
|
||||||
|
Implementations may override this hook to display their own errors,
|
||||||
|
or even handle the error and continue by returning a proper partial
|
||||||
|
application. For such implementation details, see
|
||||||
|
@file{apply/partial.xsl}.
|
||||||
|
-->
|
||||||
|
<template mode="f:partial-arity-error-hook"
|
||||||
|
match="f:ref"
|
||||||
|
priority="1">
|
||||||
|
<param name="args" as="item()*" />
|
||||||
|
<param name="arity" as="xs:decimal" />
|
||||||
|
|
||||||
|
<variable name="ref" as="element(f:ref)"
|
||||||
|
select="." />
|
||||||
|
<variable name="argn" as="xs:decimal"
|
||||||
|
select="count( $args )" />
|
||||||
|
<variable name="fn"
|
||||||
|
select="$ref/*[1]" />
|
||||||
|
<variable name="fname"
|
||||||
|
select="concat( '{', namespace-uri( $fn ), '}',
|
||||||
|
$fn/local-name() )" />
|
||||||
|
|
||||||
|
<sequence
|
||||||
|
select="error(
|
||||||
|
QName( namespace-uri-for-prefix( 'f', $ref ),
|
||||||
|
'err:PARTIAL_PARAM_OVERFLOW' ),
|
||||||
|
concat( 'Attempted partial application of ',
|
||||||
|
$fname, '#', $arity, ' with ',
|
||||||
|
$argn, ' arguments' ) )" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Apply a partial dynamic function application
|
||||||
|
|
||||||
|
This function is called automatically by @code{f:partial} when
|
||||||
|
partial application would otherwise result in the returning of a
|
||||||
|
nullary function. @emph{It performs no validations} to ensure the
|
||||||
|
integrity of the data.}
|
||||||
|
|
||||||
|
Just as @code{f:apply}, please note that @emph{up to eight arguments
|
||||||
|
are supported}. This should be enough.
|
||||||
|
-->
|
||||||
|
<function name="_f:apply-partial">
|
||||||
|
<param name="fnref" as="element(f:ref)" />
|
||||||
|
<param name="args" as="item()*" />
|
||||||
|
|
||||||
|
<variable name="fn" as="element()"
|
||||||
|
select="$fnref[ 1 ]" />
|
||||||
|
|
||||||
|
<!-- just as `f:apply', we support up to 8 arguments -->
|
||||||
|
<apply-templates select="$fn" mode="f:apply">
|
||||||
|
<with-param name="arg1" select="$args[ 1 ]" />
|
||||||
|
<with-param name="arg2" select="$args[ 2 ]" />
|
||||||
|
<with-param name="arg3" select="$args[ 3 ]" />
|
||||||
|
<with-param name="arg4" select="$args[ 4 ]" />
|
||||||
|
<with-param name="arg5" select="$args[ 5 ]" />
|
||||||
|
<with-param name="arg6" select="$args[ 6 ]" />
|
||||||
|
<with-param name="arg7" select="$args[ 7 ]" />
|
||||||
|
<with-param name="arg8" select="$args[ 8 ]" />
|
||||||
|
</apply-templates>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
</stylesheet>
|
|
@ -18,6 +18,13 @@
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
TODOs:
|
||||||
|
- Properly handle arity overloading.
|
||||||
|
- Generate functions for partial applications, so long as the target
|
||||||
|
function does not have its arity overloaded (since that would
|
||||||
|
cause currying and partial application of N>1 arguments to
|
||||||
|
potentially yield different results).
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<stylesheet version="2.0"
|
<stylesheet version="2.0"
|
||||||
|
|
|
@ -28,59 +28,86 @@
|
||||||
<import href="../src/apply.xsl" />
|
<import href="../src/apply.xsl" />
|
||||||
|
|
||||||
|
|
||||||
<template mode="f:apply" match="f:ref[ foo:fn0 ]">
|
<!-- catch errors (otherwise, we'd terminate) -->
|
||||||
<!-- return something to show that we were called properly -->
|
<template mode="f:apply"
|
||||||
<sequence select="0" />
|
match="*"
|
||||||
|
priority="2">
|
||||||
|
<foo:unknown-dyn-fun />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<template mode="f:apply" match="f:ref[ foo:fn1 ]">
|
<template mode="f:apply"
|
||||||
|
match="f:ref[ foo:fn0 ]"
|
||||||
|
priority="5">
|
||||||
|
<!-- return something to show that we were called properly -->
|
||||||
|
<foo:applied n="0" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<template mode="f:apply"
|
||||||
|
match="f:ref[ foo:fn1 ]"
|
||||||
|
priority="5">
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
|
|
||||||
<sequence select="string($arg1)" />
|
<foo:applied n="1" />
|
||||||
|
<sequence select="$arg1" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<template mode="f:apply" match="f:ref[ foo:fn2 ]">
|
<template mode="f:apply"
|
||||||
|
match="f:ref[ foo:fn2 ]"
|
||||||
|
priority="5">
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
<param name="arg2" />
|
<param name="arg2" />
|
||||||
|
|
||||||
<sequence select="concat($arg1, $arg2)" />
|
<foo:applied n="2" />
|
||||||
|
<sequence select="$arg1, $arg2" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<template mode="f:apply" match="f:ref[ foo:fn3 ]">
|
<template mode="f:apply"
|
||||||
|
match="f:ref[ foo:fn3 ]"
|
||||||
|
priority="5">
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
<param name="arg2" />
|
<param name="arg2" />
|
||||||
<param name="arg3" />
|
<param name="arg3" />
|
||||||
|
|
||||||
<sequence select="concat($arg1, $arg2, $arg3)" />
|
<foo:applied n="3" />
|
||||||
|
<sequence select="$arg1, $arg2, $arg3" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<template mode="f:apply" match="f:ref[ foo:fn4 ]">
|
<template mode="f:apply"
|
||||||
|
match="f:ref[ foo:fn4 ]"
|
||||||
|
priority="5">
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
<param name="arg2" />
|
<param name="arg2" />
|
||||||
<param name="arg3" />
|
<param name="arg3" />
|
||||||
<param name="arg4" />
|
<param name="arg4" />
|
||||||
|
|
||||||
<sequence select="concat($arg1, $arg2, $arg3, $arg4)" />
|
<foo:applied n="4" />
|
||||||
|
<sequence select="$arg1, $arg2, $arg3, $arg4" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<template mode="f:apply" match="f:ref[ foo:fn5 ]">
|
<template mode="f:apply"
|
||||||
|
match="f:ref[ foo:fn5 ]"
|
||||||
|
priority="5">
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
<param name="arg2" />
|
<param name="arg2" />
|
||||||
<param name="arg3" />
|
<param name="arg3" />
|
||||||
<param name="arg4" />
|
<param name="arg4" />
|
||||||
<param name="arg5" />
|
<param name="arg5" />
|
||||||
|
|
||||||
<sequence select="concat($arg1, $arg2, $arg3, $arg4,
|
<foo:applied n="5" />
|
||||||
$arg5)" />
|
<sequence select="$arg1, $arg2, $arg3, $arg4,
|
||||||
|
$arg5" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<template mode="f:apply" match="f:ref[ foo:fn6 ]">
|
<template mode="f:apply"
|
||||||
|
match="f:ref[ foo:fn6 ]"
|
||||||
|
priority="5">
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
<param name="arg2" />
|
<param name="arg2" />
|
||||||
<param name="arg3" />
|
<param name="arg3" />
|
||||||
|
@ -88,12 +115,15 @@
|
||||||
<param name="arg5" />
|
<param name="arg5" />
|
||||||
<param name="arg6" />
|
<param name="arg6" />
|
||||||
|
|
||||||
<sequence select="concat($arg1, $arg2, $arg3, $arg4,
|
<foo:applied n="6" />
|
||||||
$arg5, $arg6)" />
|
<sequence select="$arg1, $arg2, $arg3, $arg4,
|
||||||
|
$arg5, $arg6" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<template mode="f:apply" match="f:ref[ foo:fn7 ]">
|
<template mode="f:apply"
|
||||||
|
match="f:ref[ foo:fn7 ]"
|
||||||
|
priority="5">
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
<param name="arg2" />
|
<param name="arg2" />
|
||||||
<param name="arg3" />
|
<param name="arg3" />
|
||||||
|
@ -102,12 +132,15 @@
|
||||||
<param name="arg6" />
|
<param name="arg6" />
|
||||||
<param name="arg7" />
|
<param name="arg7" />
|
||||||
|
|
||||||
<sequence select="concat($arg1, $arg2, $arg3, $arg4,
|
<foo:applied n="7" />
|
||||||
$arg5, $arg6, $arg7)" />
|
<sequence select="$arg1, $arg2, $arg3, $arg4,
|
||||||
|
$arg5, $arg6, $arg7" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<template mode="f:apply" match="f:ref[ foo:fn8 ]">
|
<template mode="f:apply"
|
||||||
|
match="f:ref[ foo:fn8 ]"
|
||||||
|
priority="5">
|
||||||
<param name="arg1" />
|
<param name="arg1" />
|
||||||
<param name="arg2" />
|
<param name="arg2" />
|
||||||
<param name="arg3" />
|
<param name="arg3" />
|
||||||
|
@ -117,7 +150,24 @@
|
||||||
<param name="arg7" />
|
<param name="arg7" />
|
||||||
<param name="arg8" />
|
<param name="arg8" />
|
||||||
|
|
||||||
<sequence select="concat($arg1, $arg2, $arg3, $arg4,
|
<foo:applied n="8" />
|
||||||
$arg5, $arg6, $arg7, $arg8)" />
|
<sequence select="$arg1, $arg2, $arg3, $arg4,
|
||||||
|
$arg5, $arg6, $arg7, $arg8" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<function name="foo:arg8-check">
|
||||||
|
<param name="args" as="item()+" />
|
||||||
|
<param name="result" as="item()+" />
|
||||||
|
|
||||||
|
<sequence select="$result[ 1 ] instance of element( foo:applied )
|
||||||
|
and $result[ 2 ] is $args[1]
|
||||||
|
and $result[ 3 ] is $args[2]
|
||||||
|
and $result[ 4 ] is $args[3]
|
||||||
|
and $result[ 5 ] is $args[4]
|
||||||
|
and $result[ 6 ] is $args[5]
|
||||||
|
and $result[ 7 ] is $args[6]
|
||||||
|
and $result[ 8 ] is $args[7]
|
||||||
|
and $result[ 9 ] is $args[8]" />
|
||||||
|
</function>
|
||||||
</stylesheet>
|
</stylesheet>
|
||||||
|
|
583
test/apply.xspec
583
test/apply.xspec
|
@ -26,209 +26,554 @@
|
||||||
xmlns:foo="http://www.lovullo.com/_junk"
|
xmlns:foo="http://www.lovullo.com/_junk"
|
||||||
stylesheet="apply-test.xsl">
|
stylesheet="apply-test.xsl">
|
||||||
|
|
||||||
|
<variable name="foo-uri"
|
||||||
|
select="namespace-uri-for-prefix( 'foo', $args )" />
|
||||||
|
|
||||||
|
<variable name="args">
|
||||||
|
<foo:args>
|
||||||
|
<foo:arg1 />
|
||||||
|
<foo:arg2 />
|
||||||
|
<foo:arg3 />
|
||||||
|
<foo:arg4 />
|
||||||
|
<foo:arg5 />
|
||||||
|
<foo:arg6 />
|
||||||
|
<foo:arg7 />
|
||||||
|
<foo:arg8 />
|
||||||
|
</foo:args>
|
||||||
|
</variable>
|
||||||
|
|
||||||
<scenario label="f:apply">
|
<scenario label="f:apply">
|
||||||
<scenario label="applied to a function reference element">
|
<scenario label="applied to complete argument list of">
|
||||||
<variable name="arg"
|
|
||||||
select="'foo'" />
|
|
||||||
|
|
||||||
<call function="f:apply">
|
|
||||||
<param name="fnref">
|
|
||||||
<f:ref>
|
|
||||||
<foo:fn1 />
|
|
||||||
</f:ref>
|
|
||||||
</param>
|
|
||||||
<param name="arg1" select="$arg" />
|
|
||||||
</call>
|
|
||||||
|
|
||||||
<!-- our test appliaction template simply echoes back its only
|
|
||||||
argument -->
|
|
||||||
<expect label="applies application template with mode f:apply"
|
|
||||||
test="$x:result = ($arg)" />
|
|
||||||
</scenario>
|
|
||||||
|
|
||||||
|
|
||||||
<scenario label="applying">
|
|
||||||
<scenario label="nullary function">
|
<scenario label="nullary function">
|
||||||
<call function="f:apply">
|
<call function="f:apply">
|
||||||
<param name="fnref">
|
<param name="fnref"
|
||||||
<f:ref><foo:fn0 /></f:ref>
|
select="f:make-ref( QName( $foo-uri, 'fn0' ), 0 )" />
|
||||||
</param>
|
|
||||||
</call>
|
</call>
|
||||||
|
|
||||||
<expect label="passes each argument"
|
<!-- technically it applies a template -->
|
||||||
test="$x:result = 0" />
|
<expect label="applies target function"
|
||||||
|
test="$x:result[ 1 ] = foo:applied[ @n = 0 ]" />
|
||||||
</scenario>
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
<scenario label="unary function">
|
<scenario label="unary function">
|
||||||
<call function="f:apply">
|
<call function="f:apply">
|
||||||
<param name="fnref">
|
<param name="fnref"
|
||||||
<f:ref><foo:fn1 /></f:ref>
|
select="f:make-ref( QName( $foo-uri, 'fn1' ), 1 )" />
|
||||||
</param>
|
<param name="arg1" select="$args/foo:arg1" />
|
||||||
<param name="arg1" select="1" />
|
|
||||||
</call>
|
</call>
|
||||||
|
|
||||||
<expect label="passes each argument"
|
<expect label="passes each argument"
|
||||||
test="$x:result = '1'" />
|
test="$x:result[ 1 ] = foo:applied[ @n = 1 ]
|
||||||
|
and $x:result[ 2 ] is $args/foo:arg1" />
|
||||||
</scenario>
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
<scenario label="binary function">
|
<scenario label="binary function">
|
||||||
<call function="f:apply">
|
<call function="f:apply">
|
||||||
<param name="fnref">
|
<param name="fnref"
|
||||||
<f:ref><foo:fn2 /></f:ref>
|
select="f:make-ref( QName( $foo-uri, 'fn2' ), 2 )" />
|
||||||
</param>
|
<param name="arg1" select="$args/foo:arg1" />
|
||||||
<param name="arg1" select="1" />
|
<param name="arg2" select="$args/foo:arg2" />
|
||||||
<param name="arg2" select="2" />
|
|
||||||
</call>
|
</call>
|
||||||
|
|
||||||
<expect label="passes each argument"
|
<expect label="passes each argument"
|
||||||
test="$x:result = '12'" />
|
test="$x:result[ 1 ] = foo:applied[ @n = 2 ]
|
||||||
|
and $x:result[ 2 ] is $args/foo:arg1
|
||||||
|
and $x:result[ 3 ] is $args/foo:arg2" />
|
||||||
</scenario>
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
<scenario label="ternary function">
|
<scenario label="ternary function">
|
||||||
<call function="f:apply">
|
<call function="f:apply">
|
||||||
<param name="fnref">
|
<param name="fnref"
|
||||||
<f:ref><foo:fn3 /></f:ref>
|
select="f:make-ref( QName( $foo-uri, 'fn3' ), 3 )" />
|
||||||
</param>
|
<param name="arg1" select="$args/foo:arg1" />
|
||||||
<param name="arg1" select="1" />
|
<param name="arg2" select="$args/foo:arg2" />
|
||||||
<param name="arg2" select="2" />
|
<param name="arg3" select="$args/foo:arg3" />
|
||||||
<param name="arg3" select="3" />
|
|
||||||
</call>
|
</call>
|
||||||
|
|
||||||
<expect label="passes each argument"
|
<expect label="passes each argument"
|
||||||
test="$x:result = '123'" />
|
test="$x:result[ 1 ] = foo:applied[ @n = 3 ]
|
||||||
|
and $x:result[ 2 ] is $args/foo:arg1
|
||||||
|
and $x:result[ 3 ] is $args/foo:arg2
|
||||||
|
and $x:result[ 4 ] is $args/foo:arg3" />
|
||||||
</scenario>
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
<scenario label="4-ary function">
|
<scenario label="4-ary function">
|
||||||
<call function="f:apply">
|
<call function="f:apply">
|
||||||
<param name="fnref">
|
<param name="fnref"
|
||||||
<f:ref><foo:fn4 /></f:ref>
|
select="f:make-ref( QName( $foo-uri, 'fn4' ), 4 )" />
|
||||||
</param>
|
<param name="arg1" select="$args/foo:arg1" />
|
||||||
<param name="arg1" select="1" />
|
<param name="arg2" select="$args/foo:arg2" />
|
||||||
<param name="arg2" select="2" />
|
<param name="arg3" select="$args/foo:arg3" />
|
||||||
<param name="arg3" select="3" />
|
<param name="arg4" select="$args/foo:arg4" />
|
||||||
<param name="arg4" select="4" />
|
|
||||||
</call>
|
</call>
|
||||||
|
|
||||||
<expect label="passes each argument"
|
<expect label="passes each argument"
|
||||||
test="$x:result = '1234'" />
|
test="$x:result[ 1 ] = foo:applied[ @n = 4 ]
|
||||||
|
and $x:result[ 2 ] is $args/foo:arg1
|
||||||
|
and $x:result[ 3 ] is $args/foo:arg2
|
||||||
|
and $x:result[ 4 ] is $args/foo:arg3
|
||||||
|
and $x:result[ 5 ] is $args/foo:arg4" />
|
||||||
</scenario>
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
<scenario label="5-ary function">
|
<scenario label="5-ary function">
|
||||||
<call function="f:apply">
|
<call function="f:apply">
|
||||||
<param name="fnref">
|
<param name="fnref"
|
||||||
<f:ref><foo:fn5 /></f:ref>
|
select="f:make-ref( QName( $foo-uri, 'fn5' ), 5 )" />
|
||||||
</param>
|
<param name="arg1" select="$args/foo:arg1" />
|
||||||
<param name="arg1" select="1" />
|
<param name="arg2" select="$args/foo:arg2" />
|
||||||
<param name="arg2" select="2" />
|
<param name="arg3" select="$args/foo:arg3" />
|
||||||
<param name="arg3" select="3" />
|
<param name="arg4" select="$args/foo:arg4" />
|
||||||
<param name="arg4" select="4" />
|
<param name="arg5" select="$args/foo:arg5" />
|
||||||
<param name="arg5" select="5" />
|
|
||||||
</call>
|
</call>
|
||||||
|
|
||||||
<expect label="passes each argument"
|
<expect label="passes each argument"
|
||||||
test="$x:result = '12345'" />
|
test="$x:result[ 1 ] = foo:applied[ @n = 5 ]
|
||||||
|
and $x:result[ 2 ] is $args/foo:arg1
|
||||||
|
and $x:result[ 3 ] is $args/foo:arg2
|
||||||
|
and $x:result[ 4 ] is $args/foo:arg3
|
||||||
|
and $x:result[ 5 ] is $args/foo:arg4
|
||||||
|
and $x:result[ 6 ] is $args/foo:arg5" />
|
||||||
</scenario>
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
<scenario label="6-ary function">
|
<scenario label="6-ary function">
|
||||||
<call function="f:apply">
|
<call function="f:apply">
|
||||||
<param name="fnref">
|
<param name="fnref"
|
||||||
<f:ref><foo:fn6 /></f:ref>
|
select="f:make-ref( QName( $foo-uri, 'fn6' ), 6 )" />
|
||||||
</param>
|
<param name="arg1" select="$args/foo:arg1" />
|
||||||
<param name="arg1" select="1" />
|
<param name="arg2" select="$args/foo:arg2" />
|
||||||
<param name="arg2" select="2" />
|
<param name="arg3" select="$args/foo:arg3" />
|
||||||
<param name="arg3" select="3" />
|
<param name="arg4" select="$args/foo:arg4" />
|
||||||
<param name="arg4" select="4" />
|
<param name="arg5" select="$args/foo:arg5" />
|
||||||
<param name="arg5" select="5" />
|
<param name="arg6" select="$args/foo:arg6" />
|
||||||
<param name="arg6" select="6" />
|
|
||||||
</call>
|
</call>
|
||||||
|
|
||||||
<expect label="passes each argument"
|
<expect label="passes each argument"
|
||||||
test="$x:result = '123456'" />
|
test="$x:result[ 1 ] = foo:applied[ @n = 6 ]
|
||||||
|
and $x:result[ 2 ] is $args/foo:arg1
|
||||||
|
and $x:result[ 3 ] is $args/foo:arg2
|
||||||
|
and $x:result[ 4 ] is $args/foo:arg3
|
||||||
|
and $x:result[ 5 ] is $args/foo:arg4
|
||||||
|
and $x:result[ 6 ] is $args/foo:arg5
|
||||||
|
and $x:result[ 7 ] is $args/foo:arg6" />
|
||||||
</scenario>
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
<scenario label="7-ary function">
|
<scenario label="7-ary function">
|
||||||
<call function="f:apply">
|
<call function="f:apply">
|
||||||
<param name="fnref">
|
<param name="fnref"
|
||||||
<f:ref><foo:fn7 /></f:ref>
|
select="f:make-ref( QName( $foo-uri, 'fn7' ), 7 )" />
|
||||||
</param>
|
<param name="arg1" select="$args/foo:arg1" />
|
||||||
<param name="arg1" select="1" />
|
<param name="arg2" select="$args/foo:arg2" />
|
||||||
<param name="arg2" select="2" />
|
<param name="arg3" select="$args/foo:arg3" />
|
||||||
<param name="arg3" select="3" />
|
<param name="arg4" select="$args/foo:arg4" />
|
||||||
<param name="arg4" select="4" />
|
<param name="arg5" select="$args/foo:arg5" />
|
||||||
<param name="arg5" select="5" />
|
<param name="arg6" select="$args/foo:arg6" />
|
||||||
<param name="arg6" select="6" />
|
<param name="arg7" select="$args/foo:arg7" />
|
||||||
<param name="arg7" select="7" />
|
|
||||||
</call>
|
</call>
|
||||||
|
|
||||||
<expect label="passes each argument"
|
<expect label="passes each argument"
|
||||||
test="$x:result = '1234567'" />
|
test="$x:result[ 1 ] = foo:applied[ @n = 7 ]
|
||||||
|
and $x:result[ 2 ] is $args/foo:arg1
|
||||||
|
and $x:result[ 3 ] is $args/foo:arg2
|
||||||
|
and $x:result[ 4 ] is $args/foo:arg3
|
||||||
|
and $x:result[ 5 ] is $args/foo:arg4
|
||||||
|
and $x:result[ 6 ] is $args/foo:arg5
|
||||||
|
and $x:result[ 7 ] is $args/foo:arg6
|
||||||
|
and $x:result[ 8 ] is $args/foo:arg7" />
|
||||||
</scenario>
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
<scenario label="8-ary function">
|
<scenario label="8-ary function">
|
||||||
<call function="f:apply">
|
<call function="f:apply">
|
||||||
<param name="fnref">
|
<param name="fnref"
|
||||||
<f:ref><foo:fn8 /></f:ref>
|
select="f:make-ref( QName( $foo-uri, 'fn8' ), 8 )" />
|
||||||
</param>
|
<param name="arg1" select="$args/foo:arg1" />
|
||||||
<param name="arg1" select="1" />
|
<param name="arg2" select="$args/foo:arg2" />
|
||||||
<param name="arg2" select="2" />
|
<param name="arg3" select="$args/foo:arg3" />
|
||||||
<param name="arg3" select="3" />
|
<param name="arg4" select="$args/foo:arg4" />
|
||||||
<param name="arg4" select="4" />
|
<param name="arg5" select="$args/foo:arg5" />
|
||||||
<param name="arg5" select="5" />
|
<param name="arg6" select="$args/foo:arg6" />
|
||||||
<param name="arg6" select="6" />
|
<param name="arg7" select="$args/foo:arg7" />
|
||||||
<param name="arg7" select="7" />
|
<param name="arg8" select="$args/foo:arg8" />
|
||||||
<param name="arg8" select="8" />
|
|
||||||
</call>
|
</call>
|
||||||
|
|
||||||
<expect label="passes each argument"
|
<expect label="passes each argument"
|
||||||
test="$x:result = '12345678'" />
|
test="$x:result[ 1 ] = foo:applied[ @n = 8 ]
|
||||||
|
and $x:result[ 2 ] is $args/foo:arg1
|
||||||
|
and $x:result[ 3 ] is $args/foo:arg2
|
||||||
|
and $x:result[ 4 ] is $args/foo:arg3
|
||||||
|
and $x:result[ 5 ] is $args/foo:arg4
|
||||||
|
and $x:result[ 6 ] is $args/foo:arg5
|
||||||
|
and $x:result[ 7 ] is $args/foo:arg6
|
||||||
|
and $x:result[ 8 ] is $args/foo:arg7
|
||||||
|
and $x:result[ 9 ] is $args/foo:arg8" />
|
||||||
|
</scenario>
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="applied to partial argument list">
|
||||||
|
<variable name="fn8"
|
||||||
|
select="f:make-ref( QName( $foo-uri, 'fn8' ),
|
||||||
|
8 )" />
|
||||||
|
|
||||||
|
<!-- while this looks comprehensive, this really only tests
|
||||||
|
f:apply#2 -->
|
||||||
|
<scenario label="supports currying">
|
||||||
|
|
||||||
|
<call function="f:apply">
|
||||||
|
<!-- @, @ makin' you dizzy? -->
|
||||||
|
<param name="fnref"
|
||||||
|
select="f:apply(
|
||||||
|
f:apply(
|
||||||
|
f:apply(
|
||||||
|
f:apply(
|
||||||
|
f:apply(
|
||||||
|
f:apply(
|
||||||
|
f:apply(
|
||||||
|
$fn8,
|
||||||
|
$args/foo:arg1 ),
|
||||||
|
$args/foo:arg2 ),
|
||||||
|
$args/foo:arg3 ),
|
||||||
|
$args/foo:arg4 ),
|
||||||
|
$args/foo:arg5 ),
|
||||||
|
$args/foo:arg6 ),
|
||||||
|
$args/foo:arg7 )" />
|
||||||
|
|
||||||
|
<!-- the final argument that will apply the unary
|
||||||
|
partially applied function to the target 8-ary -->
|
||||||
|
<param name="arg1"
|
||||||
|
select="$args/foo:arg8" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="applies target function and binds each
|
||||||
|
argument in proper order"
|
||||||
|
test="foo:arg8-check( $args/*, $x:result )" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="with 1 argument">
|
||||||
|
<call function="f:apply">
|
||||||
|
<param name="fnref" select="$fn8" />
|
||||||
|
<param name="arg1" select="$args/foo:arg1" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="produces a partial application"
|
||||||
|
test="f:is-partial( $x:result )" />
|
||||||
|
|
||||||
|
<expect label="can complete application with arguments in
|
||||||
|
proper order"
|
||||||
|
test="foo:arg8-check(
|
||||||
|
$args/*,
|
||||||
|
f:apply( $x:result, $args/foo:arg2,
|
||||||
|
$args/foo:arg3,
|
||||||
|
$args/foo:arg4,
|
||||||
|
$args/foo:arg5,
|
||||||
|
$args/foo:arg6,
|
||||||
|
$args/foo:arg7,
|
||||||
|
$args/foo:arg8 ) )" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="with 2 arguments">
|
||||||
|
<call function="f:apply">
|
||||||
|
<param name="fnref" select="$fn8" />
|
||||||
|
<param name="arg1" select="$args/foo:arg1" />
|
||||||
|
<param name="arg2" select="$args/foo:arg2" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="produces a partial application"
|
||||||
|
test="f:is-partial( $x:result )" />
|
||||||
|
|
||||||
|
<expect label="can complete application with arguments in
|
||||||
|
proper order"
|
||||||
|
test="foo:arg8-check(
|
||||||
|
$args/*,
|
||||||
|
f:apply( $x:result, $args/foo:arg3,
|
||||||
|
$args/foo:arg4,
|
||||||
|
$args/foo:arg5,
|
||||||
|
$args/foo:arg6,
|
||||||
|
$args/foo:arg7,
|
||||||
|
$args/foo:arg8 ) )" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="with 3 arguments">
|
||||||
|
<call function="f:apply">
|
||||||
|
<param name="fnref" select="$fn8" />
|
||||||
|
<param name="arg1" select="$args/foo:arg1" />
|
||||||
|
<param name="arg2" select="$args/foo:arg2" />
|
||||||
|
<param name="arg3" select="$args/foo:arg3" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="produces a partial application"
|
||||||
|
test="f:is-partial( $x:result )" />
|
||||||
|
|
||||||
|
<expect label="can complete application with arguments in
|
||||||
|
proper order"
|
||||||
|
test="foo:arg8-check(
|
||||||
|
$args/*,
|
||||||
|
f:apply( $x:result, $args/foo:arg4,
|
||||||
|
$args/foo:arg5,
|
||||||
|
$args/foo:arg6,
|
||||||
|
$args/foo:arg7,
|
||||||
|
$args/foo:arg8 ) )" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="with 4 arguments">
|
||||||
|
<call function="f:apply">
|
||||||
|
<param name="fnref" select="$fn8" />
|
||||||
|
<param name="arg1" select="$args/foo:arg1" />
|
||||||
|
<param name="arg2" select="$args/foo:arg2" />
|
||||||
|
<param name="arg3" select="$args/foo:arg3" />
|
||||||
|
<param name="arg4" select="$args/foo:arg4" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="produces a partial application"
|
||||||
|
test="f:is-partial( $x:result )" />
|
||||||
|
|
||||||
|
<expect label="can complete application with arguments in
|
||||||
|
proper order"
|
||||||
|
test="foo:arg8-check(
|
||||||
|
$args/*,
|
||||||
|
f:apply( $x:result, $args/foo:arg5,
|
||||||
|
$args/foo:arg6,
|
||||||
|
$args/foo:arg7,
|
||||||
|
$args/foo:arg8 ) )" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="with 5 arguments">
|
||||||
|
<call function="f:apply">
|
||||||
|
<param name="fnref" select="$fn8" />
|
||||||
|
<param name="arg1" select="$args/foo:arg1" />
|
||||||
|
<param name="arg2" select="$args/foo:arg2" />
|
||||||
|
<param name="arg3" select="$args/foo:arg3" />
|
||||||
|
<param name="arg4" select="$args/foo:arg4" />
|
||||||
|
<param name="arg5" select="$args/foo:arg5" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="produces a partial application"
|
||||||
|
test="f:is-partial( $x:result )" />
|
||||||
|
|
||||||
|
<expect label="can complete application with arguments in
|
||||||
|
proper order"
|
||||||
|
test="foo:arg8-check(
|
||||||
|
$args/*,
|
||||||
|
f:apply( $x:result, $args/foo:arg6,
|
||||||
|
$args/foo:arg7,
|
||||||
|
$args/foo:arg8 ) )" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="with 6 arguments">
|
||||||
|
<call function="f:apply">
|
||||||
|
<param name="fnref" select="$fn8" />
|
||||||
|
<param name="arg1" select="$args/foo:arg1" />
|
||||||
|
<param name="arg2" select="$args/foo:arg2" />
|
||||||
|
<param name="arg3" select="$args/foo:arg3" />
|
||||||
|
<param name="arg4" select="$args/foo:arg4" />
|
||||||
|
<param name="arg5" select="$args/foo:arg5" />
|
||||||
|
<param name="arg6" select="$args/foo:arg6" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="produces a partial application"
|
||||||
|
test="f:is-partial( $x:result )" />
|
||||||
|
|
||||||
|
<expect label="can complete application with arguments in
|
||||||
|
proper order"
|
||||||
|
test="foo:arg8-check(
|
||||||
|
$args/*,
|
||||||
|
f:apply( $x:result, $args/foo:arg7,
|
||||||
|
$args/foo:arg8 ) )" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="with 7 arguments">
|
||||||
|
<call function="f:apply">
|
||||||
|
<param name="fnref" select="$fn8" />
|
||||||
|
<param name="arg1" select="$args/foo:arg1" />
|
||||||
|
<param name="arg2" select="$args/foo:arg2" />
|
||||||
|
<param name="arg3" select="$args/foo:arg3" />
|
||||||
|
<param name="arg4" select="$args/foo:arg4" />
|
||||||
|
<param name="arg5" select="$args/foo:arg5" />
|
||||||
|
<param name="arg6" select="$args/foo:arg6" />
|
||||||
|
<param name="arg7" select="$args/foo:arg7" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="produces a partial application"
|
||||||
|
test="f:is-partial( $x:result )" />
|
||||||
|
|
||||||
|
<expect label="can complete application with arguments in
|
||||||
|
proper order"
|
||||||
|
test="foo:arg8-check(
|
||||||
|
$args/*,
|
||||||
|
f:apply( $x:result, $args/foo:arg8 ) )" />
|
||||||
</scenario>
|
</scenario>
|
||||||
</scenario>
|
</scenario>
|
||||||
</scenario>
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
<scenario label="f:arity">
|
<scenario label="f:make-ref constructor">
|
||||||
<scenario label="given a proper function reference">
|
<scenario label="when called with a function QName and arity">
|
||||||
<variable name="test-arity"
|
<variable name="qname"
|
||||||
select="5" />
|
select="QName( $foo-uri, 'reftest' )" />
|
||||||
|
<variable name="arity"
|
||||||
|
select="2" />
|
||||||
|
|
||||||
<!-- test our format directly; do not rely on the
|
<call function="f:make-ref">
|
||||||
apply-gen code -->
|
<param name="name" select="$qname" />
|
||||||
<variable name="fnref">
|
<param name="arity" select="$arity" />
|
||||||
<f:ref arity="{$test-arity}">
|
</call>
|
||||||
|
|
||||||
|
<expect label="produces a dynamic function reference"
|
||||||
|
test="f:is-ref( $x:result )" />
|
||||||
|
|
||||||
|
<expect label="produces provided reference arity"
|
||||||
|
test="f:arity( $x:result ) = $arity" />
|
||||||
|
|
||||||
|
<expect label="produces reference to expected QName"
|
||||||
|
test="f:QName( $x:result ) = $qname" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="produces a valid dynamic function reference">
|
||||||
|
<call function="f:apply">
|
||||||
|
<param name="fnref"
|
||||||
|
select="f:make-ref( QName( $foo-uri, 'fn1' ),
|
||||||
|
1 )" />
|
||||||
|
<param name="arg1"
|
||||||
|
select="$args/foo:arg1" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="that can be applied using f:apply"
|
||||||
|
test="$x:result[ 1 ] = foo:applied[ @n = 1 ]
|
||||||
|
and $x:result[ 2 ] is $args/foo:arg1" />
|
||||||
|
</scenario>
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="f:is-ref predicate">
|
||||||
|
<scenario label="given a valid dynamic function reference">
|
||||||
|
<call function="f:is-ref">
|
||||||
|
<param name="fnref"
|
||||||
|
select="f:make-ref( QName( $foo-uri, 'foo' ), 0 )" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns true()"
|
||||||
|
select="true()" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="given an invalid dynamic function reference">
|
||||||
|
<call function="f:is-ref">
|
||||||
|
<param name="fnref">
|
||||||
|
<foo:bar />
|
||||||
|
</param>
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns false()"
|
||||||
|
select="false()" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="given a dynamic function reference without arity">
|
||||||
|
<call function="f:is-ref">
|
||||||
|
<param name="fnref">
|
||||||
|
<f:ref>
|
||||||
<foo:bar />
|
<foo:bar />
|
||||||
</f:ref>
|
</f:ref>
|
||||||
</variable>
|
</param>
|
||||||
|
|
||||||
<call function="f:arity">
|
|
||||||
<param name="fnref"
|
|
||||||
select="$fnref" />
|
|
||||||
</call>
|
</call>
|
||||||
|
|
||||||
<expect label="provides function arity"
|
<expect label="returns false()"
|
||||||
test="$x:result = $test-arity" />
|
select="false()" />
|
||||||
</scenario>
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
<scenario label="given a function reference with no defined arity">
|
<scenario label="given a dynamic function reference without
|
||||||
<variable name="fnref">
|
integral arity">
|
||||||
<f:ref><foo:bar /></f:ref>
|
<call function="f:is-ref">
|
||||||
</variable>
|
<param name="fnref">
|
||||||
|
<f:ref arity="moo">
|
||||||
<call function="f:arity">
|
<foo:bar />
|
||||||
<param name="fnref"
|
</f:ref>
|
||||||
select="$fnref" />
|
</param>
|
||||||
</call>
|
</call>
|
||||||
|
|
||||||
<expect label="returns -1"
|
<expect label="returns false()"
|
||||||
test="$x:result = -1" />
|
select="false()" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="given a dynamic function reference without target
|
||||||
|
node">
|
||||||
|
<call function="f:is-ref">
|
||||||
|
<param name="fnref">
|
||||||
|
<f:ref arity="0" />
|
||||||
|
</param>
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns false()"
|
||||||
|
select="false()" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="given an empty sequence">
|
||||||
|
<call function="f:is-ref">
|
||||||
|
<param name="fnref" select="()" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns false()"
|
||||||
|
select="false()" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="given a non-element">
|
||||||
|
<call function="f:is-ref">
|
||||||
|
<param name="fnref" select="5" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns false()"
|
||||||
|
select="false()" />
|
||||||
|
</scenario>
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="f:QName accessor">
|
||||||
|
<scenario label="given a valid dynamic function reference">
|
||||||
|
<variable name="foo-qname"
|
||||||
|
select="QName( $foo-uri, 'foo' )" />
|
||||||
|
|
||||||
|
<call function="f:QName">
|
||||||
|
<param name="fnref"
|
||||||
|
select="f:make-ref( $foo-qname, 0 )" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns QName"
|
||||||
|
test="$x:result instance of xs:QName" />
|
||||||
|
|
||||||
|
<expect label="returns QName of target dynamic function"
|
||||||
|
select="$foo-qname" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="given a dynamic function reference with no target
|
||||||
|
node">
|
||||||
|
<call function="f:QName">
|
||||||
|
<param name="fnref">
|
||||||
|
<f:ref arity="5" />
|
||||||
|
</param>
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns empty sequence"
|
||||||
|
select="()" />
|
||||||
</scenario>
|
</scenario>
|
||||||
</scenario>
|
</scenario>
|
||||||
</description>
|
</description>
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Tests arity calculations
|
||||||
|
|
||||||
|
Copyright (C) 2014 LoVullo Associates, Inc.
|
||||||
|
|
||||||
|
This file is part of hoxsl.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<description xmlns="http://www.jenitennison.com/xslt/xspec"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:x="http://www.jenitennison.com/xslt/xspec"
|
||||||
|
xmlns:f="http://www.lovullo.com/hoxsl/apply"
|
||||||
|
xmlns:foo="http://www.lovullo.com/_junk"
|
||||||
|
stylesheet="../../src/apply/arity.xsl">
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="f:arity">
|
||||||
|
<scenario label="given a proper function reference">
|
||||||
|
<variable name="test-arity"
|
||||||
|
select="5" />
|
||||||
|
|
||||||
|
<!-- test our format directly; do not rely on the
|
||||||
|
apply-gen code -->
|
||||||
|
<variable name="fnref">
|
||||||
|
<f:ref arity="{$test-arity}">
|
||||||
|
<foo:bar />
|
||||||
|
</f:ref>
|
||||||
|
</variable>
|
||||||
|
|
||||||
|
<call function="f:arity">
|
||||||
|
<param name="fnref"
|
||||||
|
select="$fnref" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="provides function arity"
|
||||||
|
test="$x:result = $test-arity" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="given a function reference with no defined arity">
|
||||||
|
<variable name="fnref">
|
||||||
|
<f:ref><foo:bar /></f:ref>
|
||||||
|
</variable>
|
||||||
|
|
||||||
|
<call function="f:arity">
|
||||||
|
<param name="fnref"
|
||||||
|
select="$fnref" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns -1"
|
||||||
|
test="$x:result = -1" />
|
||||||
|
</scenario>
|
||||||
|
</scenario>
|
||||||
|
</description>
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Tests partial function application
|
||||||
|
|
||||||
|
Copyright (C) 2014 LoVullo Associates, Inc.
|
||||||
|
|
||||||
|
This file is part of hoxsl.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<stylesheet version="2.0"
|
||||||
|
xmlns="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||||
|
xmlns:f="http://www.lovullo.com/hoxsl/apply"
|
||||||
|
xmlns:foo="http://www.lovullo.com/_junk">
|
||||||
|
|
||||||
|
<!-- SUT -->
|
||||||
|
<import href="../../src/apply/partial.xsl" />
|
||||||
|
|
||||||
|
<!-- numerous templates for arity tests -->
|
||||||
|
<import href="../apply-test.xsl" />
|
||||||
|
|
||||||
|
<!-- generated -->
|
||||||
|
<import href="partial-test.xsl.apply" />
|
||||||
|
|
||||||
|
|
||||||
|
<!-- the default implementation is to raise an error, which can't be
|
||||||
|
tested without XSLT 3.0 support -->
|
||||||
|
<template mode="f:partial-arity-error-hook"
|
||||||
|
match="f:ref"
|
||||||
|
priority="5">
|
||||||
|
<param name="args" as="item()*" />
|
||||||
|
<param name="arity" as="xs:decimal" />
|
||||||
|
|
||||||
|
<foo:partial-error arity="{$arity}" />
|
||||||
|
|
||||||
|
<sequence select="." />
|
||||||
|
<sequence select="$args" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<function name="foo:ternary">
|
||||||
|
<param name="x" />
|
||||||
|
<param name="y" />
|
||||||
|
<param name="z" />
|
||||||
|
|
||||||
|
<foo:ternary-applied />
|
||||||
|
<sequence select="$x, $y, $z" />
|
||||||
|
</function>
|
||||||
|
</stylesheet>
|
|
@ -0,0 +1,471 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Tests partial function application
|
||||||
|
|
||||||
|
Copyright (C) 2014 LoVullo Associates, Inc.
|
||||||
|
|
||||||
|
This file is part of hoxsl.
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<description xmlns="http://www.jenitennison.com/xslt/xspec"
|
||||||
|
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||||
|
xmlns:x="http://www.jenitennison.com/xslt/xspec"
|
||||||
|
xmlns:f="http://www.lovullo.com/hoxsl/apply"
|
||||||
|
xmlns:foo="http://www.lovullo.com/_junk"
|
||||||
|
stylesheet="partial-test.xsl">
|
||||||
|
|
||||||
|
<variable name="fnref"
|
||||||
|
select="foo:ternary()" />
|
||||||
|
|
||||||
|
<variable name="args">
|
||||||
|
<foo:parent>
|
||||||
|
<foo:a />
|
||||||
|
<foo:b />
|
||||||
|
<foo:c />
|
||||||
|
<foo:d />
|
||||||
|
<foo:e />
|
||||||
|
<foo:f />
|
||||||
|
<foo:g />
|
||||||
|
<foo:h />
|
||||||
|
</foo:parent>
|
||||||
|
</variable>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="f:partial constructor">
|
||||||
|
<scenario label="given an empty argument list">
|
||||||
|
<call function="f:partial">
|
||||||
|
<param name="fnref" select="$fnref" />
|
||||||
|
<param name="args" select="()" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns FNREF"
|
||||||
|
test="$x:result[ 1 ] = $fnref" />
|
||||||
|
|
||||||
|
<expect label="indicates that 0 arguments were partially applied"
|
||||||
|
test="$x:result/@partial = 0" />
|
||||||
|
|
||||||
|
<expect label="returns nothing else"
|
||||||
|
test="count( $x:result ) = 1" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="given arguments fewer than function param count">
|
||||||
|
<call function="f:partial">
|
||||||
|
<param name="fnref" select="$fnref" />
|
||||||
|
<param name="args" select="$args/foo:a, $args/foo:b" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns FNREF as first item in sequence"
|
||||||
|
test="$x:result[ 1 ] = $fnref" />
|
||||||
|
|
||||||
|
<expect label="indicates that N arguments were partially applied"
|
||||||
|
test="$x:result/@partial = 2" />
|
||||||
|
|
||||||
|
<expect label="returns each argument, ordered"
|
||||||
|
test="$x:result[ 2 ] is $args/foo:a
|
||||||
|
and $x:result[ 3 ] is $args/foo:b" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- our implementation can be thought of like currying -->
|
||||||
|
<scenario label="given arguments for all function params">
|
||||||
|
<call function="f:partial">
|
||||||
|
<param name="fnref" select="$fnref" />
|
||||||
|
<param name="args" select="$args/foo:a,
|
||||||
|
$args/foo:b,
|
||||||
|
$args/foo:c" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="applies target function"
|
||||||
|
test="$x:result[ 1 ]
|
||||||
|
and $x:result[ 1 ] = foo:ternary-applied" />
|
||||||
|
|
||||||
|
<expect label="applies target function with arguments, by reference"
|
||||||
|
test="$x:result[ 2 ] is $args/foo:a
|
||||||
|
and $x:result[ 3 ] is $args/foo:b
|
||||||
|
and $x:result[ 4 ] is $args/foo:c" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- partial applications should behave as their own functions -->
|
||||||
|
<scenario label="partially applying partial application, with
|
||||||
|
fewer arguments than target function arity">
|
||||||
|
<call function="f:partial">
|
||||||
|
<param name="fnref" select="f:partial( $fnref, $args/foo:a )" />
|
||||||
|
<param name="args" select="$args/foo:b" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns FNREF as first item in sequence"
|
||||||
|
test="$x:result[ 1 ] = $fnref" />
|
||||||
|
|
||||||
|
<expect label="returns arguments from both partial applications"
|
||||||
|
test="count( $x:result ) = 3" />
|
||||||
|
|
||||||
|
<expect label="arguments are ordered with previous applications
|
||||||
|
first in sequence"
|
||||||
|
test="$x:result[ 2 ] is $args/foo:a
|
||||||
|
and $x:result[ 3 ] is $args/foo:b" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="partially applying partial application, with all
|
||||||
|
arguments">
|
||||||
|
<call function="f:partial">
|
||||||
|
<param name="fnref" select="f:partial( $fnref, ($args/foo:a,
|
||||||
|
$args/foo:b) )" />
|
||||||
|
<param name="args" select="$args/foo:c" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="applies target function"
|
||||||
|
test="$x:result[ 1 ]
|
||||||
|
and $x:result[ 1 ] = foo:ternary-applied" />
|
||||||
|
|
||||||
|
<expect label="applies target function with arguments, by reference"
|
||||||
|
test="$x:result[ 2 ] is $args/foo:a
|
||||||
|
and $x:result[ 3 ] is $args/foo:b
|
||||||
|
and $x:result[ 4 ] is $args/foo:c" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- let the repitition begin (don't we wish we had macros?
|
||||||
|
...foreshadowing?) -->
|
||||||
|
<scenario label="completing partial application passes all
|
||||||
|
arguments to a target">
|
||||||
|
<scenario label="unary">
|
||||||
|
<call function="f:partial">
|
||||||
|
<param name="fnref">
|
||||||
|
<f:ref arity="1"><foo:fn1 /></f:ref>
|
||||||
|
</param>
|
||||||
|
<param name="args" select="$args/foo:a" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="applies target function"
|
||||||
|
test="$x:result[ 1 ] = foo:applied[ @n = 1 ]" />
|
||||||
|
|
||||||
|
<expect label="applies target function with arguments, by reference"
|
||||||
|
test="$x:result[ 2 ] is $args/foo:a" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="binary">
|
||||||
|
<call function="f:partial">
|
||||||
|
<param name="fnref">
|
||||||
|
<f:ref arity="2"><foo:fn2 /></f:ref>
|
||||||
|
</param>
|
||||||
|
<param name="args" select="$args/foo:a,
|
||||||
|
$args/foo:b" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="applies target function"
|
||||||
|
test="$x:result[ 1 ] = foo:applied[ @n = 2 ]" />
|
||||||
|
|
||||||
|
<expect label="applies target function with arguments, by reference"
|
||||||
|
test="$x:result[ 2 ] is $args/foo:a
|
||||||
|
and $x:result[ 3 ] is $args/foo:b" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="ternary">
|
||||||
|
<call function="f:partial">
|
||||||
|
<param name="fnref">
|
||||||
|
<f:ref arity="3"><foo:fn3 /></f:ref>
|
||||||
|
</param>
|
||||||
|
<param name="args" select="$args/foo:a,
|
||||||
|
$args/foo:b,
|
||||||
|
$args/foo:c" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="applies target function"
|
||||||
|
test="$x:result[ 1 ] = foo:applied[ @n = 3 ]" />
|
||||||
|
|
||||||
|
<expect label="applies target function with arguments, by reference"
|
||||||
|
test="$x:result[ 2 ] is $args/foo:a
|
||||||
|
and $x:result[ 3 ] is $args/foo:b
|
||||||
|
and $x:result[ 4 ] is $args/foo:c" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="4-ary">
|
||||||
|
<call function="f:partial">
|
||||||
|
<param name="fnref">
|
||||||
|
<f:ref arity="4"><foo:fn4 /></f:ref>
|
||||||
|
</param>
|
||||||
|
<param name="args" select="$args/foo:a,
|
||||||
|
$args/foo:b,
|
||||||
|
$args/foo:c,
|
||||||
|
$args/foo:d" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="applies target function"
|
||||||
|
test="$x:result[ 1 ] = foo:applied[ @n = 4 ]" />
|
||||||
|
|
||||||
|
<expect label="applies target function with arguments, by reference"
|
||||||
|
test="$x:result[ 2 ] = $args/foo:a
|
||||||
|
and $x:result[ 3 ] = $args/foo:b
|
||||||
|
and $x:result[ 4 ] = $args/foo:c
|
||||||
|
and $x:result[ 5 ] = $args/foo:d" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="5-ary">
|
||||||
|
<call function="f:partial">
|
||||||
|
<param name="fnref">
|
||||||
|
<f:ref arity="5"><foo:fn5 /></f:ref>
|
||||||
|
</param>
|
||||||
|
<param name="args" select="$args/foo:a,
|
||||||
|
$args/foo:b,
|
||||||
|
$args/foo:c,
|
||||||
|
$args/foo:d,
|
||||||
|
$args/foo:e" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="applies target function"
|
||||||
|
test="$x:result[ 1 ] = foo:applied[ @n = 5 ]" />
|
||||||
|
|
||||||
|
<expect label="applies target function with arguments, by reference"
|
||||||
|
test="$x:result[ 2 ] = $args/foo:a
|
||||||
|
and $x:result[ 3 ] = $args/foo:b
|
||||||
|
and $x:result[ 4 ] = $args/foo:c
|
||||||
|
and $x:result[ 5 ] = $args/foo:d
|
||||||
|
and $x:result[ 6 ] = $args/foo:e" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="6-ary">
|
||||||
|
<call function="f:partial">
|
||||||
|
<param name="fnref">
|
||||||
|
<f:ref arity="6"><foo:fn6 /></f:ref>
|
||||||
|
</param>
|
||||||
|
<param name="args" select="$args/foo:a,
|
||||||
|
$args/foo:b,
|
||||||
|
$args/foo:c,
|
||||||
|
$args/foo:d,
|
||||||
|
$args/foo:e,
|
||||||
|
$args/foo:f" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="applies target function"
|
||||||
|
test="$x:result[ 1 ] = foo:applied[ @n = 6 ]" />
|
||||||
|
|
||||||
|
<expect label="applies target function with arguments, by reference"
|
||||||
|
test="$x:result[ 2 ] = $args/foo:a
|
||||||
|
and $x:result[ 3 ] = $args/foo:b
|
||||||
|
and $x:result[ 4 ] = $args/foo:c
|
||||||
|
and $x:result[ 5 ] = $args/foo:d
|
||||||
|
and $x:result[ 6 ] = $args/foo:e
|
||||||
|
and $x:result[ 7 ] = $args/foo:f" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="7-ary">
|
||||||
|
<call function="f:partial">
|
||||||
|
<param name="fnref">
|
||||||
|
<f:ref arity="7"><foo:fn7 /></f:ref>
|
||||||
|
</param>
|
||||||
|
<param name="args" select="$args/foo:a,
|
||||||
|
$args/foo:b,
|
||||||
|
$args/foo:c,
|
||||||
|
$args/foo:d,
|
||||||
|
$args/foo:e,
|
||||||
|
$args/foo:f,
|
||||||
|
$args/foo:g" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="applies target function"
|
||||||
|
test="$x:result[ 1 ] = foo:applied[ @n = 7 ]" />
|
||||||
|
|
||||||
|
<expect label="applies target function with arguments, by reference"
|
||||||
|
test="$x:result[ 2 ] = $args/foo:a
|
||||||
|
and $x:result[ 3 ] = $args/foo:b
|
||||||
|
and $x:result[ 4 ] = $args/foo:c
|
||||||
|
and $x:result[ 5 ] = $args/foo:d
|
||||||
|
and $x:result[ 6 ] = $args/foo:e
|
||||||
|
and $x:result[ 7 ] = $args/foo:f
|
||||||
|
and $x:result[ 8 ] = $args/foo:g" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="8-ary">
|
||||||
|
<call function="f:partial">
|
||||||
|
<param name="fnref">
|
||||||
|
<f:ref arity="8"><foo:fn8 /></f:ref>
|
||||||
|
</param>
|
||||||
|
<param name="args" select="$args/foo:a,
|
||||||
|
$args/foo:b,
|
||||||
|
$args/foo:c,
|
||||||
|
$args/foo:d,
|
||||||
|
$args/foo:e,
|
||||||
|
$args/foo:f,
|
||||||
|
$args/foo:g,
|
||||||
|
$args/foo:h" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="applies target function"
|
||||||
|
test="$x:result[ 1 ] = foo:applied[ @n = 8 ]" />
|
||||||
|
|
||||||
|
<expect label="applies target function with arguments, by reference"
|
||||||
|
test="$x:result[ 2 ] = $args/foo:a
|
||||||
|
and $x:result[ 3 ] = $args/foo:b
|
||||||
|
and $x:result[ 4 ] = $args/foo:c
|
||||||
|
and $x:result[ 5 ] = $args/foo:d
|
||||||
|
and $x:result[ 6 ] = $args/foo:e
|
||||||
|
and $x:result[ 7 ] = $args/foo:f
|
||||||
|
and $x:result[ 8 ] = $args/foo:g
|
||||||
|
and $x:result[ 9 ] = $args/foo:h" />
|
||||||
|
</scenario>
|
||||||
|
</scenario>
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="f:is-partial predicate">
|
||||||
|
<scenario label="given a non-none">
|
||||||
|
<call function="f:is-partial">
|
||||||
|
<param name="fnref"
|
||||||
|
select="5" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns false()"
|
||||||
|
test="$x:result = false()" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="given a non-fref node">
|
||||||
|
<call function="f:is-partial">
|
||||||
|
<param name="fnref">
|
||||||
|
<foo:moo />
|
||||||
|
</param>
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns false()"
|
||||||
|
test="$x:result = false()" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- this leaks implementation details :x -->
|
||||||
|
<scenario label="given a non-fref node with spoofed attribute">
|
||||||
|
<call function="f:is-partial">
|
||||||
|
<param name="fnref">
|
||||||
|
<foo:moo partial="5" f:partial="5" />
|
||||||
|
</param>
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns false()"
|
||||||
|
test="$x:result = false()" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="given a valid fref, not partially applied">
|
||||||
|
<call function="f:is-partial">
|
||||||
|
<param name="fnref"
|
||||||
|
select="foo:ternary()" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns false()"
|
||||||
|
test="$x:result = false()" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- if partially applied with no arguments, then it may as well
|
||||||
|
not be; let's not alter the logic of callers just because it
|
||||||
|
was called with no effect -->
|
||||||
|
<scenario label="given a valid fref, partially applied with zero
|
||||||
|
arguments">
|
||||||
|
<call function="f:is-partial">
|
||||||
|
<param name="fnref"
|
||||||
|
select="f:partial( foo:ternary(), () )" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns false()"
|
||||||
|
test="$x:result = false()" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="given a valid fref, partially applied with N>0
|
||||||
|
arguments, including argument sequence">
|
||||||
|
<call function="f:is-partial">
|
||||||
|
<param name="fnref"
|
||||||
|
select="f:partial( foo:ternary(), (1, 2) )" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns true()"
|
||||||
|
test="$x:result = true()" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- caller may extract the function ref from the sequence and
|
||||||
|
assert on that -->
|
||||||
|
<scenario label="given a valid fref, partially applied with N>0
|
||||||
|
arguments, without argument sequence">
|
||||||
|
<call function="f:is-partial">
|
||||||
|
<param name="fnref"
|
||||||
|
select="f:partial( foo:ternary(), (1, 2) )[ 1 ]" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="returns true()"
|
||||||
|
test="$x:result = true()" />
|
||||||
|
</scenario>
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="f:partial-arity-error-hook mode">
|
||||||
|
<scenario label="given more arguments than target function
|
||||||
|
parameters">
|
||||||
|
<!-- see partial-test.xsl for the result sequence order -->
|
||||||
|
<call function="f:partial">
|
||||||
|
<param name="fnref" select="$fnref" />
|
||||||
|
<param name="args" select="$args/foo:a,
|
||||||
|
$args/foo:b,
|
||||||
|
$args/foo:c,
|
||||||
|
$args/foo:d" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="produces an error"
|
||||||
|
test="$x:result[ 1 ] instance of
|
||||||
|
element( foo:partial-error )" />
|
||||||
|
|
||||||
|
<expect label="provides source dynamic function reference"
|
||||||
|
test="$x:result[ 2 ] is $fnref" />
|
||||||
|
|
||||||
|
<expect label="provides arity of target (root of all partial
|
||||||
|
applications) function"
|
||||||
|
test="$x:result[ 1 ]/@arity = 3" />
|
||||||
|
|
||||||
|
<expect label="provides each argument of partial application
|
||||||
|
attempt, including excess"
|
||||||
|
test="$x:result[ 3 ] is $args/foo:a
|
||||||
|
and $x:result[ 4 ] is $args/foo:b
|
||||||
|
and $x:result[ 5 ] is $args/foo:c
|
||||||
|
and $x:result[ 6 ] is $args/foo:d" />
|
||||||
|
</scenario>
|
||||||
|
|
||||||
|
|
||||||
|
<scenario label="triggered when sum of partial applications yields
|
||||||
|
more arguments than target parameters">
|
||||||
|
<call function="f:partial">
|
||||||
|
<param name="fnref"
|
||||||
|
select="f:partial( $fnref, ($args/foo:a,
|
||||||
|
$args/foo:b) )" />
|
||||||
|
<param name="args" select="$args/foo:c,
|
||||||
|
$args/foo:d" />
|
||||||
|
</call>
|
||||||
|
|
||||||
|
<expect label="produces error with all arguments"
|
||||||
|
test="exists( foo:partial-error )
|
||||||
|
and $x:result[ 3 ] is $args/foo:a
|
||||||
|
and $x:result[ 6 ] is $args/foo:d" />
|
||||||
|
</scenario>
|
||||||
|
</scenario>
|
||||||
|
</description>
|
|
@ -73,7 +73,7 @@
|
||||||
<xsl:function name="foo:bar">
|
<xsl:function name="foo:bar">
|
||||||
<xsl:param name="a" />
|
<xsl:param name="a" />
|
||||||
<xsl:param name="b" as="xs:decimal" />
|
<xsl:param name="b" as="xs:decimal" />
|
||||||
<xsl:param name="c" />"
|
<xsl:param name="c" />
|
||||||
</xsl:function>
|
</xsl:function>
|
||||||
</xsl:stylesheet>
|
</xsl:stylesheet>
|
||||||
</context>
|
</context>
|
||||||
|
@ -187,7 +187,7 @@
|
||||||
<scenario label="f:arity">
|
<scenario label="f:arity">
|
||||||
<call function="f:arity">
|
<call function="f:arity">
|
||||||
<param name="fnref" select="foo:sub-two()" />
|
<param name="fnref" select="foo:sub-two()" />
|
||||||
</call>"
|
</call>
|
||||||
|
|
||||||
<expect label="is able to determine arity"
|
<expect label="is able to determine arity"
|
||||||
test="$x:result = 2" />
|
test="$x:result = 2" />
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 3dc0ab2e1b78dae5d31c228c22a7dd8868d5678f
|
Subproject commit 20c6b8a32f37a6511698fe89b78b82fd1aa64bd2
|
Loading…
Reference in New Issue