stevedlawrence commented on code in PR #1137:
URL: https://github.com/apache/daffodil/pull/1137#discussion_r1446439958
##########
daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala:
##########
@@ -2295,6 +2295,18 @@ abstract class FunctionCallBase(
res
}
+ final def checkArgArray(): Unit = {
+ lazy val isArray = expressions.head match {
+ case rpe: RelativePathExpression => rpe.steps.last.isArray
+ case rpe: RootPathExpression => rpe.steps.last.isArray
Review Comment:
Can these two be combined into this?
```scala
case pe: PathExpression => pe.steps.last.isArray
```
I think these are the only classes that extend that base class?
Also, is `isArray` sufficient? I know optional elements (i.e. minOccurs=0
maxOccurs=1) are represented in the infoset as an array, but sometimes aren't
considered as actual arrays in other parts of the code. I'm not sure if the
StepExpression isArray handles that? I think we want `fn:count` to still work
on optional elements?
##########
daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala:
##########
@@ -2295,6 +2295,18 @@ abstract class FunctionCallBase(
res
}
+ final def checkArgArray(): Unit = {
+ lazy val isArray = expressions.head match {
+ case rpe: RelativePathExpression => rpe.steps.last.isArray
+ case rpe: RootPathExpression => rpe.steps.last.isArray
+ case _ => true
Review Comment:
One thing to consider is this doesn't catch expressions like this:
```xquery
fn:count(if (some_condition) then /some/path else /some/other/path)
```
I think that's legal and I think would be considered invalid because of this
case.
I'm not sure if there's a good way to check that all branches of a
subexpression result in an array. We must be able to get some basic information
since we can statically check that all branches have the same type. I think we
do that via `inherentType`, but I'm not sure the result would return
information about being an array or not. Maybe this is just a limitation of our
checking and it's good enough? And if someone whats the above, they would need
to do something like this:
```xquery
if (some_condition) then fn:count(/some/path) else fn:count(/some/other/path)
```
##########
daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala:
##########
@@ -2295,6 +2295,18 @@ abstract class FunctionCallBase(
res
}
+ final def checkArgArray(): Unit = {
+ lazy val isArray = expressions.head match {
Review Comment:
This `checkArgArray` function is only used for `fn:count`, which only has
one argument so it's fine to just check `expressions.head`, but without knowing
that it could be confusing why this only checks head and not all of the
function arguments. I wonder if this could be made more generic somehow? Maybe
it takes an index into the expressions list and checks that that specific
expression is an array? And then the usage in FnCountExpr would be
`checkArgArray(0)`? Or maybe it takes an actual expression, so the usage would
be `checkArgArray(args(0))`? I'm not sure if a similar check we do somewhere
else that we could copy the pattern from?
##########
daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/DState.scala:
##########
@@ -215,45 +218,26 @@ case class DState(
def booleanValue: Boolean = currentValue.getBoolean
def longValue: Long = asLong(currentValue.getAnyRef)
+
def intValue: Int = longValue.toInt
+
def doubleValue: Double = asDouble(currentValue.getAnyRef)
def integerValue: JBigInt = asBigInt(currentValue.getAnyRef)
+
def decimalValue: JBigDecimal = asBigDecimal(currentValue.getAnyRef)
+
def stringValue: String = currentValue.getString
def isNilled: Boolean = currentElement.isNilled
- private def isAnArray(): Boolean = {
- if (!currentNode.isInstanceOf[DIArray]) {
- Assert.invariant(errorOrWarn.isDefined)
- if (currentNode.isInstanceOf[DIElement]) {
- errorOrWarn.get.SDW(
- WarnID.PathNotToArray,
- "The specified path to element %s is not to an array. Suggest using
fn:exists instead.",
- currentElement.name,
- )
- } else {
- errorOrWarn.get.SDW(
- WarnID.PathNotToArray,
- "The specified path is not to an array. Suggest using fn:exists
instead.",
- )
- }
- false
- } else {
- true
- }
- }
-
Review Comment:
So this is an 100% static check now? Nice! It might be worth adding a
comment to the `arrayLength` and `finalArrayLength` functions that we must
statically know current dpath result is an array, otherwise these might return
some weird results or throw an exception. They are currently only used by
FNCount so it should be safe, but if another function ever uses those we need
to make sure they are doing the checkArgArray thing.
##########
daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_functions/Functions.tdml:
##########
@@ -11390,6 +11417,110 @@
</tdml:infoset>
</tdml:unparserTestCase>
+ <!--
+ Test Name: count_12
+ Schema: XPathFunctions
+ Root: count07
+ Purpose: This test demonstrates the count() function works as
expected
+ when parsing an array of scalars
+ -->
+
+ <tdml:parserTestCase name="count_12" root="count07"
+ model="XPathFunctions" description="Section 23 - Functions - fn:count -
DFDL-23-122R">
+ <tdml:document>
+ <tdml:documentPart type="byte">00 00 00 01 00 00 00
02</tdml:documentPart>
+ </tdml:document>
+ <tdml:infoset>
+ <tdml:dfdlInfoset>
+ <ex:count07 xmlns:ex="http://example.com">
+ <ex:int>1</ex:int>
+ <ex:int>2</ex:int>
+ <ex:count>2</ex:count>
+ </ex:count07>
+ </tdml:dfdlInfoset>
+ </tdml:infoset>
+ </tdml:parserTestCase>
+
+ <!--
+ Test Name: count_13
+ Schema: XPathFunctions
+ Root: count08
+ Purpose: This test demonstrates the count() function works as
expected
+ when parsing a unique scalar element
+ -->
+
+ <tdml:parserTestCase name="count_13" root="count08" roundTrip="true"
+ model="XPathFunctions" description="Section 23 -
Functions - fn:count - DFDL-23-122R">
+ <tdml:document>
+ <tdml:documentPart type="byte">00 00 00 01</tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>fn:count</tdml:error>
+ <tdml:error>array</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+ <!--
+ Test Name: count_14
+ Schema: XPathFunctions
+ Root: count09
+ Purpose: This test demonstrates the count() function works as
expected
+ when parsing an optional element
+ -->
+
+ <tdml:parserTestCase name="count_14" root="count09" roundTrip="true"
+ model="XPathFunctions" description="Section 23 -
Functions - fn:count - DFDL-23-122R">
+ <tdml:document>
+ <tdml:documentPart type="byte">00 00 00 01</tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>fn:count</tdml:error>
+ <tdml:error>array</tdml:error>
+ </tdml:errors>
Review Comment:
Agreed, I think that is the correct behavior. Only minOccurs=maxOccurs=1
should trigger the SDE.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]