This is an automated email from the ASF dual-hosted git repository.
olabusayo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/daffodil.git
The following commit(s) were added to refs/heads/main by this push:
new fe6646f31 Add support for dfdl:checkRangeInclusive/checkRangeExclusive
functions
fe6646f31 is described below
commit fe6646f317ed10d4efce31ae5214c5ccaadacc72
Author: olabusayoT <[email protected]>
AuthorDate: Thu Mar 28 13:26:12 2024 -0400
Add support for dfdl:checkRangeInclusive/checkRangeExclusive functions
- add implementation for checkRangeInclusive/Exclusive in Expressions and
DFDLFunctions
- create case class ComparisonOp instead of the 6-tuple for the forType Map
value
- add ComparisonOps.forType lazy val map and use in ComparisonExpression,
RepTypeMixin and DFDLCheckRangeExpr
- add tests for checkRangeInclusive/Exclusive for numeric types and
non-numeric types
- add unittest to test out usage exceptions for hexBinary comparisons
DAFFODIL-1515
---
.../apache/daffodil/core/dpath/Expression.scala | 184 +++++------
.../daffodil/core/grammar/RepTypeMixin.scala | 42 +--
.../daffodil/runtime1/dpath/ComparisonOps.scala | 190 +++++++++++
.../daffodil/runtime1/dpath/DFDLFunctions.scala | 23 ++
.../section23/dfdl_expressions/expressions.tdml | 353 +++++++++++++++++++++
.../dfdl_expressions/TestDFDLExpressions2.scala | 82 +++++
6 files changed, 728 insertions(+), 146 deletions(-)
diff --git
a/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala
b/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala
index bbd90c4f3..4bfbf177e 100644
---
a/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala
+++
b/daffodil-core/src/main/scala/org/apache/daffodil/core/dpath/Expression.scala
@@ -258,117 +258,23 @@ case class ComparisonExpression(op: String, adds:
List[Expression])
with BooleanExpression {
lazy val compareOp: CompareOpBase = {
- import NodeInfo.PrimType._
- import NodeInfo.ArrayIndex
- (op, convergedArgType) match {
- case ("<", _) => subsetError("Unsupported operation '%s'. Use 'lt'
instead.", op)
- case (">", _) => subsetError("Unsupported operation '%s'. Use 'gt'
instead.", op)
- case ("<=", _) => subsetError("Unsupported operation '%s'. Use 'le'
instead.", op)
- case (">=", _) => subsetError("Unsupported operation '%s'. Use 'ge'
instead.", op)
- case ("=", _) => subsetError("Unsupported operation '%s'. Use 'eq'
instead.", op)
- case ("!=", _) => subsetError("Unsupported operation '%s'. Use 'ne'
instead.", op)
-
- case ("eq", HexBinary) => EQ_CompareByteArray
- case ("ne", HexBinary) => NE_CompareByteArray
- case ("eq", _) => EQ_Compare
- case ("ne", _) => NE_Compare
-
- case ("lt", Boolean) => LT_Boolean
- case ("gt", Boolean) => GT_Boolean
- case ("le", Boolean) => LE_Boolean
- case ("ge", Boolean) => GE_Boolean
-
- case ("lt", Date) => LT_Date
- case ("gt", Date) => GT_Date
- case ("le", Date) => LE_Date
- case ("ge", Date) => GE_Date
-
- case ("lt", Time) => LT_Time
- case ("gt", Time) => GT_Time
- case ("le", Time) => LE_Time
- case ("ge", Time) => GE_Time
-
- case ("lt", DateTime) => LT_DateTime
- case ("gt", DateTime) => GT_DateTime
- case ("le", DateTime) => LE_DateTime
- case ("ge", DateTime) => GE_DateTime
-
- case ("lt", String) => LT_String
- case ("gt", String) => GT_String
- case ("le", String) => LE_String
- case ("ge", String) => GE_String
-
- case ("lt", Decimal) => LT_Decimal
- case ("gt", Decimal) => GT_Decimal
- case ("le", Decimal) => LE_Decimal
- case ("ge", Decimal) => GE_Decimal
-
- case ("lt", Integer) => LT_Integer
- case ("gt", Integer) => GT_Integer
- case ("le", Integer) => LE_Integer
- case ("ge", Integer) => GE_Integer
-
- case ("lt", NonNegativeInteger) => LT_NonNegativeInteger
- case ("gt", NonNegativeInteger) => GT_NonNegativeInteger
- case ("le", NonNegativeInteger) => LE_NonNegativeInteger
- case ("ge", NonNegativeInteger) => GE_NonNegativeInteger
-
- case ("lt", UnsignedLong) => LT_UnsignedLong
- case ("gt", UnsignedLong) => GT_UnsignedLong
- case ("le", UnsignedLong) => LE_UnsignedLong
- case ("ge", UnsignedLong) => GE_UnsignedLong
-
- case ("lt", Long) => LT_Long
- case ("gt", Long) => GT_Long
- case ("le", Long) => LE_Long
- case ("ge", Long) => GE_Long
-
- case ("lt", UnsignedInt) => LT_UnsignedInt
- case ("gt", UnsignedInt) => GT_UnsignedInt
- case ("le", UnsignedInt) => LE_UnsignedInt
- case ("ge", UnsignedInt) => GE_UnsignedInt
-
- case ("lt", ArrayIndex) => LT_UnsignedInt
- case ("gt", ArrayIndex) => GT_UnsignedInt
- case ("le", ArrayIndex) => LE_UnsignedInt
- case ("ge", ArrayIndex) => GE_UnsignedInt
-
- case ("lt", Int) => LT_Int
- case ("gt", Int) => GT_Int
- case ("le", Int) => LE_Int
- case ("ge", Int) => GE_Int
-
- case ("lt", UnsignedShort) => LT_UnsignedShort
- case ("gt", UnsignedShort) => GT_UnsignedShort
- case ("le", UnsignedShort) => LE_UnsignedShort
- case ("ge", UnsignedShort) => GE_UnsignedShort
-
- case ("lt", Short) => LT_Short
- case ("gt", Short) => GT_Short
- case ("le", Short) => LE_Short
- case ("ge", Short) => GE_Short
-
- case ("lt", UnsignedByte) => LT_UnsignedByte
- case ("gt", UnsignedByte) => GT_UnsignedByte
- case ("le", UnsignedByte) => LE_UnsignedByte
- case ("ge", UnsignedByte) => GE_UnsignedByte
-
- case ("lt", Byte) => LT_Byte
- case ("gt", Byte) => GT_Byte
- case ("le", Byte) => LE_Byte
- case ("ge", Byte) => GE_Byte
-
- case ("lt", Float) => LT_Float
- case ("gt", Float) => GT_Float
- case ("le", Float) => LE_Float
- case ("ge", Float) => GE_Float
-
- case ("lt", Double) => LT_Double
- case ("gt", Double) => GT_Double
- case ("le", Double) => LE_Double
- case ("ge", Double) => GE_Double
-
- case _ => subsetError("Unsupported operation '%s' on type %s.", op,
convergedArgType)
+ val comparisonOps = ComparisonOps.forType(convergedArgType)
+ import NodeInfo.PrimType.HexBinary
+ op match {
+ case "<" => subsetError("Unsupported operation '%s'. Use 'lt' instead.",
op)
+ case ">" => subsetError("Unsupported operation '%s'. Use 'gt' instead.",
op)
+ case "<=" => subsetError("Unsupported operation '%s'. Use 'le'
instead.", op)
+ case ">=" => subsetError("Unsupported operation '%s'. Use 'ge'
instead.", op)
+ case "=" => subsetError("Unsupported operation '%s'. Use 'eq' instead.",
op)
+ case "!=" => subsetError("Unsupported operation '%s'. Use 'ne'
instead.", op)
+ case "eq" => comparisonOps.eq
+ case "ne" => comparisonOps.ne
+ case "lt" if convergedArgType != HexBinary => comparisonOps.lt
+ case "gt" if convergedArgType != HexBinary => comparisonOps.gt
+ case "le" if convergedArgType != HexBinary => comparisonOps.le
+ case "ge" if convergedArgType != HexBinary => comparisonOps.ge
+ case _ =>
+ subsetError(s"Unsupported operation '$op' on type $convergedArgType.")
}
}
@@ -2016,6 +1922,12 @@ case class FunctionCallExpression(functionQNameString:
String, expressions: List
case (RefQName(_, "checkConstraints", DFDL), args) => {
DFDLCheckConstraintsExpr(functionQNameString, functionQName, args)
}
+ case (RefQName(_, "checkRangeInclusive", DFDL), args) => {
+ DFDLCheckRangeExpr(functionQNameString, functionQName, args,
isExclusive = false)
+ }
+ case (RefQName(_, "checkRangeExclusive", DFDL), args) => {
+ DFDLCheckRangeExpr(functionQNameString, functionQName, args,
isExclusive = true)
+ }
case (RefQName(_, "decodeDFDLEntities", DFDL), args) => {
FNOneArgExpr(
functionQNameString,
@@ -3041,6 +2953,56 @@ case class DFDLCheckConstraintsExpr(
}
+case class DFDLCheckRangeExpr(
+ nameAsParsed: String,
+ fnQName: RefQName,
+ args: List[Expression],
+ isExclusive: Boolean,
+) extends FunctionCallBase(nameAsParsed, fnQName, args) {
+
+ lazy val List(arg1, arg2, arg3) = { checkArgCount(3); args }
+
+ override lazy val children = args
+
+ override lazy val compiledDPath = {
+ val argDPath = arg1.compiledDPath
+ val rangeFrom = arg2.compiledDPath
+ val rangeTo = arg3.compiledDPath
+ val c = conversions
+ val comparisonOps = ComparisonOps.forType(convergedArgType)
+ val compare = if (isExclusive) comparisonOps.lt else comparisonOps.le
+ val res = new CompiledDPath(DFDLCheckRange(argDPath, rangeFrom, rangeTo,
compare) +: c)
+ res
+ }
+
+ // we set the calculation to a lazy val so it's evaluated only once for each
+ // call to targetTypeForSubexpression since we don't care about the specific
+ // value of subexpr in targetTypeForSubexpression, and we need all 3 sub
+ // expressions to come to the right target target for the args
+ lazy val convergedArgType: NodeInfo.Kind = {
+ import NodeInfo._
+ val targetType = (arg1.inherentType, arg2.inherentType, arg3.inherentType)
match {
+ case (testType: Numeric.Kind, minType: Numeric.Kind, maxType:
Numeric.Kind) => {
+ val rangeType =
+ NodeInfoUtils.generalizeArgTypesForComparisonOp(nameAsParsed,
minType, maxType)
+ val targetType =
+ NodeInfoUtils.generalizeArgTypesForComparisonOp(nameAsParsed,
testType, rangeType)
+ targetType
+ }
+ case (test, min, max) =>
+ SDE(s"Cannot call $nameAsParsed with non-numeric types: $test, $min,
$max")
+ }
+ targetType
+ }
+
+ override def targetTypeForSubexpression(subexpr: Expression): NodeInfo.Kind
= {
+ convergedArgType
+ }
+
+ override lazy val inherentType: NodeInfo.Kind = NodeInfo.Boolean
+
+}
+
/**
* Really this just delegates anything bottom-up to the contained expression
* and anything top-down to the parent
diff --git
a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/RepTypeMixin.scala
b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/RepTypeMixin.scala
index d16b07b33..d55df71dd 100644
---
a/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/RepTypeMixin.scala
+++
b/daffodil-core/src/main/scala/org/apache/daffodil/core/grammar/RepTypeMixin.scala
@@ -25,26 +25,7 @@ import org.apache.daffodil.core.dsom.ElementBase
import org.apache.daffodil.core.dsom.GlobalSimpleTypeDef
import org.apache.daffodil.core.dsom.RepTypeQuasiElementDecl
import org.apache.daffodil.lib.exceptions.Assert
-import org.apache.daffodil.runtime1.dpath.LE_Byte
-import org.apache.daffodil.runtime1.dpath.LE_Int
-import org.apache.daffodil.runtime1.dpath.LE_Integer
-import org.apache.daffodil.runtime1.dpath.LE_Long
-import org.apache.daffodil.runtime1.dpath.LE_NonNegativeInteger
-import org.apache.daffodil.runtime1.dpath.LE_Short
-import org.apache.daffodil.runtime1.dpath.LE_UnsignedByte
-import org.apache.daffodil.runtime1.dpath.LE_UnsignedInt
-import org.apache.daffodil.runtime1.dpath.LE_UnsignedLong
-import org.apache.daffodil.runtime1.dpath.LE_UnsignedShort
-import org.apache.daffodil.runtime1.dpath.LT_Byte
-import org.apache.daffodil.runtime1.dpath.LT_Int
-import org.apache.daffodil.runtime1.dpath.LT_Integer
-import org.apache.daffodil.runtime1.dpath.LT_Long
-import org.apache.daffodil.runtime1.dpath.LT_NonNegativeInteger
-import org.apache.daffodil.runtime1.dpath.LT_Short
-import org.apache.daffodil.runtime1.dpath.LT_UnsignedByte
-import org.apache.daffodil.runtime1.dpath.LT_UnsignedInt
-import org.apache.daffodil.runtime1.dpath.LT_UnsignedLong
-import org.apache.daffodil.runtime1.dpath.LT_UnsignedShort
+import org.apache.daffodil.runtime1.dpath.ComparisonOps
import org.apache.daffodil.runtime1.dpath.NodeInfo
import org.apache.daffodil.runtime1.dpath.NumberCompareOp
import org.apache.daffodil.runtime1.infoset.DataValue.DataValueNumber
@@ -100,21 +81,12 @@ trait RepTypeMixin { self: ElementBase =>
repTypeCompareLT: NumberCompareOp,
repTypeCompareLE: NumberCompareOp,
) = LV('repTypeComparers) {
- repTypeElementDecl.primType match {
- case NodeInfo.Integer => (LT_Integer, LE_Integer)
- case NodeInfo.Long => (LT_Long, LE_Long)
- case NodeInfo.Int => (LT_Int, LE_Int)
- case NodeInfo.Short => (LT_Short, LE_Short)
- case NodeInfo.Byte => (LT_Byte, LE_Byte)
- case NodeInfo.NonNegativeInteger => (LT_NonNegativeInteger,
LE_NonNegativeInteger)
- case NodeInfo.UnsignedLong => (LT_UnsignedLong, LE_UnsignedLong)
- case NodeInfo.UnsignedInt => (LT_UnsignedInt, LE_UnsignedInt)
- case NodeInfo.UnsignedShort => (LT_UnsignedShort, LE_UnsignedShort)
- case NodeInfo.UnsignedByte => (LT_UnsignedByte, LE_UnsignedByte)
- // $COVERAGE-OFF$
- case _ => Assert.invariantFailed("repType should only be an integer
type")
- // $COVERAGE-ON$
- }
+ Assert.invariant(
+ repTypeElementDecl.primType.isSubtypeOf(NodeInfo.Integer),
+ "repType should only be an integer type",
+ )
+ val comparisonOps = ComparisonOps.forType(repTypeElementDecl.primType)
+ (comparisonOps.lt, comparisonOps.le)
}.value
lazy val (
diff --git
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/ComparisonOps.scala
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/ComparisonOps.scala
index 84e9a323f..08e30a391 100644
---
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/ComparisonOps.scala
+++
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/ComparisonOps.scala
@@ -17,10 +17,176 @@
package org.apache.daffodil.runtime1.dpath
+import org.apache.daffodil.lib.exceptions.Assert
import org.apache.daffodil.lib.util.Numbers._
+import org.apache.daffodil.runtime1.dpath.NodeInfo.PrimType
import org.apache.daffodil.runtime1.infoset.DataValue.DataValueBool
import org.apache.daffodil.runtime1.infoset.DataValue.DataValuePrimitive
+/**
+ * Case class used for ordering the return of the appropriate comparison
operations for each primitive kind
+ * @param eq represents the equality comparison
+ * @param ne represents the unequality comparison
+ * @param lt represents the less than comparison
+ * @param le represents the less than or equal to comparison
+ * @param gt represents the greater than comparison
+ * @param ge represents the greater than or equal to comparison
+ */
+case class ComparisonOp(
+ eq: CompareOpBase,
+ ne: CompareOpBase,
+ lt: CompareOpBase,
+ le: CompareOpBase,
+ gt: CompareOpBase,
+ ge: CompareOpBase,
+)
+
+/**
+ * ComparisonOps.forType represents a map with key of NodeInfo.Kind and the
value of the above ComparisonOp case class, which
+ * is a 6 param object containing the appropriate comparison object for the
NodeInfo.Kind
+ *
+ * To use, you can call the forType map using an argument targetType, which
queries the Map using the key targetType
+ * then use the returned object to select the ComparisonOpBase of interest
+ *
+ * @example {{{
+ * val compOps = ComparisonOps.forType(targetType)
+ * val res = compOps.lt.operate(x, y)
+ * res
+ * }}}
+ *
+ */
+object ComparisonOps {
+ lazy val forType: Map[NodeInfo.Kind, ComparisonOp] = {
+ Map(
+ PrimType.Boolean -> ComparisonOp(
+ EQ_Compare,
+ NE_Compare,
+ LT_Boolean,
+ LE_Boolean,
+ GT_Boolean,
+ GE_Boolean,
+ ),
+ PrimType.Integer -> ComparisonOp(
+ EQ_Compare,
+ NE_Compare,
+ LT_Integer,
+ LE_Integer,
+ GT_Integer,
+ GE_Integer,
+ ),
+ PrimType.Date -> ComparisonOp(EQ_Compare, NE_Compare, LT_Date, LE_Date,
GT_Date, GE_Date),
+ PrimType.Time -> ComparisonOp(EQ_Compare, NE_Compare, LT_Time, LE_Time,
GT_Time, GE_Time),
+ PrimType.DateTime -> ComparisonOp(
+ EQ_Compare,
+ NE_Compare,
+ LT_DateTime,
+ LE_DateTime,
+ GT_DateTime,
+ GE_DateTime,
+ ),
+ PrimType.String -> ComparisonOp(
+ EQ_Compare,
+ NE_Compare,
+ LT_String,
+ LE_String,
+ GT_String,
+ GE_String,
+ ),
+ PrimType.Decimal -> ComparisonOp(
+ EQ_Compare,
+ NE_Compare,
+ LT_Decimal,
+ LE_Decimal,
+ GT_Decimal,
+ GE_Decimal,
+ ),
+ PrimType.NonNegativeInteger -> ComparisonOp(
+ EQ_Compare,
+ NE_Compare,
+ LT_NonNegativeInteger,
+ LE_NonNegativeInteger,
+ GT_NonNegativeInteger,
+ GE_NonNegativeInteger,
+ ),
+ PrimType.UnsignedLong -> ComparisonOp(
+ EQ_Compare,
+ NE_Compare,
+ LT_UnsignedLong,
+ LE_UnsignedLong,
+ GT_UnsignedLong,
+ GE_UnsignedLong,
+ ),
+ PrimType.Long -> ComparisonOp(EQ_Compare, NE_Compare, LT_Long, LE_Long,
GT_Long, GE_Long),
+ PrimType.UnsignedInt -> ComparisonOp(
+ EQ_Compare,
+ NE_Compare,
+ LT_UnsignedInt,
+ LE_UnsignedInt,
+ GT_UnsignedInt,
+ GE_UnsignedInt,
+ ),
+ NodeInfo.ArrayIndex -> ComparisonOp(
+ EQ_Compare,
+ NE_Compare,
+ LT_UnsignedInt,
+ LE_UnsignedInt,
+ GT_UnsignedInt,
+ GE_UnsignedInt,
+ ),
+ PrimType.Int -> ComparisonOp(EQ_Compare, NE_Compare, LT_Int, LE_Int,
GT_Int, GE_Int),
+ PrimType.UnsignedShort -> ComparisonOp(
+ EQ_Compare,
+ NE_Compare,
+ LT_UnsignedShort,
+ LE_UnsignedShort,
+ GT_UnsignedShort,
+ GE_UnsignedShort,
+ ),
+ PrimType.Short -> ComparisonOp(
+ EQ_Compare,
+ NE_Compare,
+ LT_Short,
+ LE_Short,
+ GT_Short,
+ GE_Short,
+ ),
+ PrimType.UnsignedByte -> ComparisonOp(
+ EQ_Compare,
+ NE_Compare,
+ LT_UnsignedByte,
+ LE_UnsignedByte,
+ GT_UnsignedByte,
+ GE_UnsignedByte,
+ ),
+ PrimType.Byte -> ComparisonOp(EQ_Compare, NE_Compare, LT_Byte, LE_Byte,
GT_Byte, GE_Byte),
+ PrimType.Float -> ComparisonOp(
+ EQ_Compare,
+ NE_Compare,
+ LT_Float,
+ LE_Float,
+ GT_Float,
+ GE_Float,
+ ),
+ PrimType.Double -> ComparisonOp(
+ EQ_Compare,
+ NE_Compare,
+ LT_Double,
+ LE_Double,
+ GT_Double,
+ GE_Double,
+ ),
+ PrimType.HexBinary -> ComparisonOp(
+ EQ_CompareByteArray,
+ NE_CompareByteArray,
+ LT_ByteArray,
+ LE_ByteArray,
+ GT_ByteArray,
+ GE_ByteArray,
+ ),
+ )
+ }
+}
+
case object EQ_Compare extends CompareOpBase {
def operate(v1: DataValuePrimitive, v2: DataValuePrimitive): DataValueBool =
{
val res = v1 == v2
@@ -35,6 +201,30 @@ case object EQ_CompareByteArray extends CompareOpBase {
}
}
+case object LT_ByteArray extends CompareOpBase {
+ def operate(v1: DataValuePrimitive, v2: DataValuePrimitive): DataValueBool =
{
+ Assert.usageError("Unsupported operation LT on Byte Array")
+ }
+}
+
+case object LE_ByteArray extends CompareOpBase {
+ def operate(v1: DataValuePrimitive, v2: DataValuePrimitive): DataValueBool =
{
+ Assert.usageError("Unsupported operation LE on Byte Array")
+ }
+}
+
+case object GT_ByteArray extends CompareOpBase {
+ def operate(v1: DataValuePrimitive, v2: DataValuePrimitive): DataValueBool =
{
+ Assert.usageError("Unsupported operation GT on Byte Array")
+ }
+}
+
+case object GE_ByteArray extends CompareOpBase {
+ def operate(v1: DataValuePrimitive, v2: DataValuePrimitive): DataValueBool =
{
+ Assert.usageError("Unsupported operation GE on Byte Array")
+ }
+}
+
case object NE_Compare extends CompareOpBase {
def operate(v1: DataValuePrimitive, v2: DataValuePrimitive): DataValueBool =
{
val res = v1 != v2
diff --git
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/DFDLFunctions.scala
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/DFDLFunctions.scala
index 94784e741..145a8533c 100644
---
a/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/DFDLFunctions.scala
+++
b/daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/dpath/DFDLFunctions.scala
@@ -39,6 +39,29 @@ case class DFDLCheckConstraints(recipe: CompiledDPath)
extends RecipeOpWithSubRe
}
}
+case class DFDLCheckRange(
+ dataRecipe: CompiledDPath,
+ minRecipe: CompiledDPath,
+ maxRecipe: CompiledDPath,
+ compare: CompareOpBase,
+) extends RecipeOpWithSubRecipes(dataRecipe, minRecipe, maxRecipe) {
+ override def run(dstate: DState): Unit = {
+ val saved = dstate.currentNode
+ dataRecipe.run(dstate)
+ val dataVal = dstate.currentValue.getNonNullable
+ dstate.setCurrentNode(saved)
+ minRecipe.run(dstate)
+ val minVal = dstate.currentValue.getNonNullable
+ dstate.setCurrentNode(saved)
+ maxRecipe.run(dstate)
+ val maxVal = dstate.currentValue.getNonNullable
+
+ val res =
+ compare.operate(minVal, dataVal).getBoolean && compare.operate(dataVal,
maxVal).getBoolean
+ dstate.setCurrentValue(res)
+ }
+}
+
case class DFDLDecodeDFDLEntities(recipe: CompiledDPath, argType:
NodeInfo.Kind)
extends FNOneArg(recipe, argType) {
override def computeValue(str: DataValuePrimitive, dstate: DState):
DataValueString = {
diff --git
a/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions.tdml
b/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions.tdml
index 140479e89..a20b94a17 100644
---
a/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions.tdml
+++
b/daffodil-test/src/test/resources/org/apache/daffodil/section23/dfdl_expressions/expressions.tdml
@@ -7684,4 +7684,357 @@ blastoff
<tdml:infoset><tdml:dfdlInfoset><add01>4</add01></tdml:dfdlInfoset></tdml:infoset>
</tdml:parserTestCase>
+ <tdml:defineSchema name="DFDLCheckRange">
+ <xs:include
schemaLocation="/org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
+ <dfdl:format ref="ex:GeneralFormat" />
+ <xs:element name="literalMinMax_int">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="data" dfdl:lengthKind="explicit" dfdl:length="1"
type="xs:integer"/>
+ <xs:element name="isInRangeInc" type="xs:boolean"
+ dfdl:inputValueCalc="{
dfdl:checkRangeInclusive(../ex:data, 0, 8) }"/>
+ <xs:element name="isInRangeExc" type="xs:boolean"
+ dfdl:inputValueCalc="{
dfdl:checkRangeExclusive(../ex:data, 0, 8) }"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="expMinMax_double">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:sequence dfdl:separatorPosition="infix" dfdl:separator="|">
+ <xs:element name="data" dfdl:lengthKind="delimited"
type="xs:double"/>
+ <xs:element name="min" dfdl:lengthKind="delimited"
type="xs:double"/>
+ <xs:element name="max" dfdl:lengthKind="delimited"
type="xs:double"/>
+ </xs:sequence>
+ <xs:element name="isInRangeInc" type="xs:boolean"
+ dfdl:inputValueCalc="{
dfdl:checkRangeInclusive(../ex:data, ../ex:min, ../ex:max) }"/>
+ <xs:element name="isInRangeExc" type="xs:boolean"
+ dfdl:inputValueCalc="{
dfdl:checkRangeExclusive(../ex:data, ../ex:min, ../ex:max) }"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="expMinMax_float">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:sequence dfdl:separatorPosition="infix" dfdl:separator="|">
+ <xs:element name="data" dfdl:lengthKind="delimited"
type="xs:float"/>
+ <xs:element name="min" dfdl:lengthKind="delimited"
type="xs:float"/>
+ <xs:element name="max" dfdl:lengthKind="delimited"
type="xs:float"/>
+ </xs:sequence>
+ <xs:element name="isInRangeInc" type="xs:boolean"
+ dfdl:inputValueCalc="{
dfdl:checkRangeInclusive(../ex:data, ../ex:min, ../ex:max) }"/>
+ <xs:element name="isInRangeExc" type="xs:boolean"
+ dfdl:inputValueCalc="{
dfdl:checkRangeExclusive(../ex:data, ../ex:min, ../ex:max) }"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="expMinMax_decimal">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:sequence dfdl:separatorPosition="infix" dfdl:separator="|">
+ <xs:element name="data" dfdl:lengthKind="delimited"
type="xs:decimal"/>
+ <xs:element name="min" dfdl:lengthKind="delimited"
type="xs:decimal"/>
+ <xs:element name="max" dfdl:lengthKind="delimited"
type="xs:decimal"/>
+ </xs:sequence>
+ <xs:element name="isInRangeInc" type="xs:boolean"
+ dfdl:inputValueCalc="{
dfdl:checkRangeInclusive(../ex:data, ../ex:min, ../ex:max) }"/>
+ <xs:element name="isInRangeExc" type="xs:boolean"
+ dfdl:inputValueCalc="{
dfdl:checkRangeExclusive(../ex:data, ../ex:min, ../ex:max) }"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="expMinMax_mixedIntAndFloat">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:sequence dfdl:separatorPosition="infix" dfdl:separator="|">
+ <xs:element name="data" dfdl:lengthKind="delimited"
type="xs:integer"/>
+ <xs:element name="min" dfdl:lengthKind="delimited"
type="xs:float"/>
+ <xs:element name="max" dfdl:lengthKind="delimited"
type="xs:float"/>
+ </xs:sequence>
+ <xs:element name="isInRangeInc" type="xs:boolean"
+ dfdl:inputValueCalc="{
dfdl:checkRangeInclusive(../ex:data, ../ex:min, ../ex:max) }"/>
+ <xs:element name="isInRangeExc" type="xs:boolean"
+ dfdl:inputValueCalc="{
dfdl:checkRangeExclusive(../ex:data, ../ex:min, ../ex:max) }"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="expMinMax_string_inc">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:sequence dfdl:separatorPosition="infix" dfdl:separator="|">
+ <xs:element name="data" dfdl:lengthKind="delimited"
type="xs:string"/>
+ <xs:element name="min" dfdl:lengthKind="delimited"
type="xs:string"/>
+ <xs:element name="max" dfdl:lengthKind="delimited"
type="xs:string"/>
+ </xs:sequence>
+ <xs:element name="isInRangeInc" type="xs:boolean"
+ dfdl:inputValueCalc="{
dfdl:checkRangeInclusive(../ex:data, ../ex:min, ../ex:max) }"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="expMinMax_string_exc">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:sequence dfdl:separatorPosition="infix" dfdl:separator="|">
+ <xs:element name="data" dfdl:lengthKind="delimited"
type="xs:string"/>
+ <xs:element name="min" dfdl:lengthKind="delimited"
type="xs:string"/>
+ <xs:element name="max" dfdl:lengthKind="delimited"
type="xs:string"/>
+ </xs:sequence>
+ <xs:element name="isInRangeExc" type="xs:boolean"
+ dfdl:inputValueCalc="{
dfdl:checkRangeExclusive(../ex:data, ../ex:min, ../ex:max) }"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+
+ </tdml:defineSchema>
+
+ <tdml:parserTestCase name="DFDLCheckRange_01" validation="on"
+ root="literalMinMax_int" model="DFDLCheckRange">
+ <tdml:document>8</tdml:document>
+ <tdml:infoset>
+ <tdml:dfdlInfoset>
+ <literalMinMax_int>
+ <data>8</data>
+ <isInRangeInc>true</isInRangeInc>
+ <isInRangeExc>false</isInRangeExc>
+ </literalMinMax_int>
+ </tdml:dfdlInfoset>
+ </tdml:infoset>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="DFDLCheckRange_02" validation="on"
+ root="expMinMax_double" model="DFDLCheckRange">
+ <tdml:document>2.3|2.3|2.5</tdml:document>
+ <tdml:infoset>
+ <tdml:dfdlInfoset>
+ <expMinMax_double>
+ <data>2.3</data>
+ <min>2.3</min>
+ <max>2.5</max>
+ <isInRangeInc>true</isInRangeInc>
+ <isInRangeExc>false</isInRangeExc>
+ </expMinMax_double>
+ </tdml:dfdlInfoset>
+ </tdml:infoset>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="DFDLCheckRange_03" validation="on"
+ root="expMinMax_float" model="DFDLCheckRange">
+ <tdml:document>2.5|2.3|2.5</tdml:document>
+ <tdml:infoset>
+ <tdml:dfdlInfoset>
+ <expMinMax_float>
+ <data>2.5</data>
+ <min>2.3</min>
+ <max>2.5</max>
+ <isInRangeInc>true</isInRangeInc>
+ <isInRangeExc>false</isInRangeExc>
+ </expMinMax_float>
+ </tdml:dfdlInfoset>
+ </tdml:infoset>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="DFDLCheckRange_04" validation="on"
+ root="expMinMax_decimal" model="DFDLCheckRange">
+ <tdml:document>2.5|2.3|2.5</tdml:document>
+ <tdml:infoset>
+ <tdml:dfdlInfoset>
+ <expMinMax_decimal>
+ <data>2.5</data>
+ <min>2.3</min>
+ <max>2.5</max>
+ <isInRangeInc>true</isInRangeInc>
+ <isInRangeExc>false</isInRangeExc>
+ </expMinMax_decimal>
+ </tdml:dfdlInfoset>
+ </tdml:infoset>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="DFDLCheckRange_05" validation="on"
+ root="expMinMax_mixedIntAndFloat"
model="DFDLCheckRange">
+ <tdml:document>1|1.9|2.5</tdml:document>
+ <tdml:infoset>
+ <tdml:dfdlInfoset>
+ <expMinMax_mixedIntAndFloat>
+ <data>1</data>
+ <min>1.9</min>
+ <max>2.5</max>
+ <isInRangeInc>false</isInRangeInc>
+ <isInRangeExc>false</isInRangeExc>
+ </expMinMax_mixedIntAndFloat>
+ </tdml:dfdlInfoset>
+ </tdml:infoset>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="DFDLCheckRange_06" validation="on"
+ root="literalMinMax_int" model="DFDLCheckRange">
+ <tdml:document>9</tdml:document>
+ <tdml:infoset>
+ <tdml:dfdlInfoset>
+ <literalMinMax_int>
+ <data>9</data>
+ <isInRangeInc>false</isInRangeInc>
+ <isInRangeExc>false</isInRangeExc>
+ </literalMinMax_int>
+ </tdml:dfdlInfoset>
+ </tdml:infoset>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="DFDLCheckRange_07" validation="on"
+ root="expMinMax_string_inc" model="DFDLCheckRange">
+ <tdml:document>2|1.9|2.5</tdml:document>
+
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>Cannot call dfdl:checkRangeInclusive</tdml:error>
+ <tdml:error>with non-numeric types</tdml:error>
+ <tdml:error>string, string, string</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="DFDLCheckRange_08" validation="on"
+ root="expMinMax_string_exc" model="DFDLCheckRange">
+ <tdml:document>2|1.9|2.5</tdml:document>
+
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>Cannot call dfdl:checkRangeExclusive</tdml:error>
+ <tdml:error>with non-numeric types</tdml:error>
+ <tdml:error>string, string, string</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+
+ <tdml:defineSchema name="HexBinaryComparisons">
+ <xs:include
schemaLocation="/org/apache/daffodil/xsd/DFDLGeneralFormat.dfdl.xsd"/>
+ <dfdl:format ref="ex:GeneralFormat" />
+ <xs:element name="equalsNotEquals">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="data1" dfdl:lengthKind="explicit" dfdl:length="2"
type="xs:hexBinary"/>
+ <xs:element name="data2" dfdl:lengthKind="explicit" dfdl:length="2"
type="xs:hexBinary"/>
+ <xs:element name="equals" type="xs:boolean"
+ dfdl:inputValueCalc="{ ../ex:data1 eq ../ex:data2 }"/>
+ <xs:element name="notEquals" type="xs:boolean"
+ dfdl:inputValueCalc="{ ../ex:data1 ne ../ex:data2 }"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="lessThan">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="data1" dfdl:lengthKind="explicit" dfdl:length="2"
type="xs:hexBinary"/>
+ <xs:element name="data2" dfdl:lengthKind="explicit" dfdl:length="2"
type="xs:hexBinary"/>
+ <xs:element name="lt" type="xs:boolean"
+ dfdl:inputValueCalc="{ ../ex:data1 lt ../ex:data2 }"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="lessThanOrEquals">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="data1" dfdl:lengthKind="explicit" dfdl:length="2"
type="xs:hexBinary"/>
+ <xs:element name="data2" dfdl:lengthKind="explicit" dfdl:length="2"
type="xs:hexBinary"/>
+ <xs:element name="le" type="xs:boolean"
+ dfdl:inputValueCalc="{ ../ex:data1 le ../ex:data2 }"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="greaterThan">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="data1" dfdl:lengthKind="explicit" dfdl:length="2"
type="xs:hexBinary"/>
+ <xs:element name="data2" dfdl:lengthKind="explicit" dfdl:length="2"
type="xs:hexBinary"/>
+ <xs:element name="gt" type="xs:boolean"
+ dfdl:inputValueCalc="{ ../ex:data1 gt ../ex:data2 }"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+
+ <xs:element name="greaterThanOrEquals">
+ <xs:complexType>
+ <xs:sequence>
+ <xs:element name="data1" dfdl:lengthKind="explicit" dfdl:length="2"
type="xs:hexBinary"/>
+ <xs:element name="data2" dfdl:lengthKind="explicit" dfdl:length="2"
type="xs:hexBinary"/>
+ <xs:element name="ge" type="xs:boolean"
+ dfdl:inputValueCalc="{ ../ex:data1 ge ../ex:data2 }"/>
+ </xs:sequence>
+ </xs:complexType>
+ </xs:element>
+ </tdml:defineSchema>
+
+ <tdml:parserTestCase name="hexBinaryComparison_01" validation="on"
+ root="equalsNotEquals" model="HexBinaryComparisons">
+ <tdml:document>
+ <tdml:documentPart type="byte">deadbeef</tdml:documentPart>
+ </tdml:document>
+ <tdml:infoset>
+ <tdml:dfdlInfoset>
+ <equalsNotEquals>
+ <data1>DEAD</data1>
+ <data2>BEEF</data2>
+ <equals>false</equals>
+ <notEquals>true</notEquals>
+ </equalsNotEquals>
+ </tdml:dfdlInfoset>
+ </tdml:infoset>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="hexBinaryComparison_02" validation="on"
+ root="lessThan" model="HexBinaryComparisons">
+ <tdml:document>
+ <tdml:documentPart type="byte">deadbeef</tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>Unsupported operation 'lt'</tdml:error>
+ <tdml:error>on type hexBinary</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="hexBinaryComparison_03" validation="on"
+ root="lessThanOrEquals" model="HexBinaryComparisons">
+ <tdml:document>
+ <tdml:documentPart type="byte">deadbeef</tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>Unsupported operation 'le'</tdml:error>
+ <tdml:error>on type hexBinary</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="hexBinaryComparison_04" validation="on"
+ root="greaterThan" model="HexBinaryComparisons">
+ <tdml:document>
+ <tdml:documentPart type="byte">deadbeef</tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>Unsupported operation 'gt'</tdml:error>
+ <tdml:error>on type hexBinary</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
+ <tdml:parserTestCase name="hexBinaryComparison_05" validation="on"
+ root="greaterThanOrEquals" model="HexBinaryComparisons">
+ <tdml:document>
+ <tdml:documentPart type="byte">deadbeef</tdml:documentPart>
+ </tdml:document>
+ <tdml:errors>
+ <tdml:error>Schema Definition Error</tdml:error>
+ <tdml:error>Unsupported operation 'ge'</tdml:error>
+ <tdml:error>on type hexBinary</tdml:error>
+ </tdml:errors>
+ </tdml:parserTestCase>
+
</tdml:testSuite>
diff --git
a/daffodil-test/src/test/scala/org/apache/daffodil/section23/dfdl_expressions/TestDFDLExpressions2.scala
b/daffodil-test/src/test/scala/org/apache/daffodil/section23/dfdl_expressions/TestDFDLExpressions2.scala
index 6988e4c70..1ae315299 100644
---
a/daffodil-test/src/test/scala/org/apache/daffodil/section23/dfdl_expressions/TestDFDLExpressions2.scala
+++
b/daffodil-test/src/test/scala/org/apache/daffodil/section23/dfdl_expressions/TestDFDLExpressions2.scala
@@ -17,9 +17,13 @@
package org.apache.daffodil.section23.dfdl_expressions
+import org.apache.daffodil.lib.Implicits.intercept
+import org.apache.daffodil.lib.exceptions.UsageException
import org.apache.daffodil.tdml.Runner
import org.junit.AfterClass
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
import org.junit.Test
object TestDFDLExpressions2 {
@@ -135,6 +139,84 @@ class TestDFDLExpressions2 {
@Test def test_idiv18(): Unit = { runner.runOneTest("idiv18") }
@Test def test_idiv19(): Unit = { runner.runOneTest("idiv19") }
@Test def test_idiv20(): Unit = { runner.runOneTest("idiv20") }
+ @Test def test_DFDLCheckRange_01(): Unit = {
+ runner.runOneTest("DFDLCheckRange_01")
+ }
+
+ @Test def test_DFDLCheckRange_02(): Unit = {
+ runner.runOneTest("DFDLCheckRange_02")
+ }
+
+ @Test def test_DFDLCheckRange_03(): Unit = {
+ runner.runOneTest("DFDLCheckRange_03")
+ }
+
+ @Test def test_DFDLCheckRange_04(): Unit = {
+ runner.runOneTest("DFDLCheckRange_04")
+ }
+
+ @Test def test_DFDLCheckRange_05(): Unit = {
+ runner.runOneTest("DFDLCheckRange_05")
+ }
+
+ @Test def test_DFDLCheckRange_06(): Unit = {
+ runner.runOneTest("DFDLCheckRange_06")
+ }
+
+ @Test def test_DFDLCheckRange_07(): Unit = {
+ runner.runOneTest("DFDLCheckRange_07")
+ }
+
+ @Test def test_DFDLCheckRange_08(): Unit = {
+ runner.runOneTest("DFDLCheckRange_08")
+ }
+
+ @Test def test_hexBinaryComparison_01(): Unit = {
+ runner.runOneTest("hexBinaryComparison_01")
+ }
+
+ @Test def test_hexBinaryComparison_02(): Unit = {
+ runner.runOneTest("hexBinaryComparison_02")
+ }
+ @Test def test_hexBinaryComparison_03(): Unit = {
+ runner.runOneTest("hexBinaryComparison_03")
+ }
+ @Test def test_hexBinaryComparison_04(): Unit = {
+ runner.runOneTest("hexBinaryComparison_04")
+ }
+ @Test def test_hexBinaryComparison_05(): Unit = {
+ runner.runOneTest("hexBinaryComparison_05")
+ }
+
+ @Test def test_hexBinaryComparison_06(): Unit = {
+ import org.apache.daffodil.runtime1.dpath.ComparisonOps
+ import org.apache.daffodil.runtime1.dpath.NodeInfo
+ val compOps = ComparisonOps.forType(NodeInfo.HexBinary)
+
+ val ba1 = Array[Byte](0xde.toByte, 0xad.toByte)
+ val ba2 = Array[Byte](0xbe.toByte, 0xef.toByte)
+
+ val eEQ = compOps.eq.operate(ba1, ba2).getBoolean
+ val eNE = compOps.ne.operate(ba1, ba2).getBoolean
+ val eLT = intercept[UsageException] {
+ compOps.lt.operate(ba1, ba2)
+ }
+ val eLE = intercept[UsageException] {
+ compOps.le.operate(ba1, ba2)
+ }
+ val eGT = intercept[UsageException] {
+ compOps.gt.operate(ba1, ba2)
+ }
+ val eGE = intercept[UsageException] {
+ compOps.ge.operate(ba1, ba2)
+ }
+ assertFalse(eEQ)
+ assertTrue(eNE)
+ assertTrue(eLT.getMessage.contains("Unsupported operation LT"))
+ assertTrue(eLE.getMessage.contains("Unsupported operation LE"))
+ assertTrue(eGT.getMessage.contains("Unsupported operation GT"))
+ assertTrue(eGE.getMessage.contains("Unsupported operation GE"))
+ }
@Test def test_add01(): Unit = { runner.runOneTest("add01") }