You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@daffodil.apache.org by bt...@apache.org on 2019/12/19 19:51:53 UTC

[incubator-daffodil] branch master updated: Refactor type calculator to take advantage of DataValue type

This is an automated email from the ASF dual-hosted git repository.

btsloane pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-daffodil.git


The following commit(s) were added to refs/heads/master by this push:
     new 3808610  Refactor type calculator to take advantage of DataValue type
3808610 is described below

commit 3808610cd1354f395337b9e37116fb096b579dde
Author: Brandon Sloane <bs...@tresys.com>
AuthorDate: Mon Dec 16 10:56:49 2019 -0500

    Refactor type calculator to take advantage of DataValue type
    
    This fixes a bug where we would inadvertandly use Scala BigInts
    
    Daffodil-2188
---
 .../org/apache/daffodil/dpath/Expression.scala     |   2 +-
 .../org/apache/daffodil/dsom/ReptypeMixins.scala   |   2 +-
 .../apache/daffodil/dsom/RestrictionUnion.scala    |  33 +--
 .../org/apache/daffodil/dsom/SimpleTypes.scala     | 116 ++++-----
 .../grammar/primitives/ChoiceCombinator.scala      |  79 +++---
 .../org/apache/daffodil/cookers/Cookers.scala      |  20 +-
 .../org/apache/daffodil/util/RangeBound.scala      | 111 ---------
 .../unparsers/ExpressionEvaluatingUnparsers.scala  |  11 +-
 .../org/apache/daffodil/infoset/DataValue.scala    |   8 +-
 .../org/apache/daffodil/infoset/DataValue.scala    |  13 +-
 .../daffodil/dpath/DFDLXTypeCalcFunctions.scala    |  12 +-
 .../org/apache/daffodil/infoset/InfosetImpl.scala  |   1 +
 .../apache/daffodil/processors/RuntimeData.scala   |   4 +-
 .../daffodil/processors/TypeCalculator.scala       | 276 ++++++++++++++-------
 .../processors/parsers/ElementKindParsers.scala    |  22 +-
 .../parsers/ExpressionEvaluatingParsers.scala      |   4 +-
 .../extensions/type_calc/typeCalcFunctions.tdml    | 109 ++++++++
 .../extensions/TestInputTypeValueCalc.scala        |   1 +
 18 files changed, 481 insertions(+), 343 deletions(-)

diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dpath/Expression.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dpath/Expression.scala
index 83da2c2..673b077 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dpath/Expression.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dpath/Expression.scala
@@ -1909,7 +1909,7 @@ case class FunctionCallExpression(functionQNameString: String, expressions: List
     funcObj
   }
 
-  def lookupTypeCalculator(typeCalcExpr: Expression, requiresParse: Boolean, requiresUnparse: Boolean): TypeCalculator[AnyRef, AnyRef] = {
+  def lookupTypeCalculator(typeCalcExpr: Expression, requiresParse: Boolean, requiresUnparse: Boolean): TypeCalculator = {
     /*
      * Every function that currently uses this defines the type calculator
      * as their first arguement.
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ReptypeMixins.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ReptypeMixins.scala
index bb160c2..53ff0a3 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ReptypeMixins.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/ReptypeMixins.scala
@@ -58,7 +58,7 @@ trait HasOptRepTypeMixin {
     case Some(x: SimpleTypeDefBase) => Some(x)
     case _ => None
   }
-  def optRepValueSet: Option[RepValueSet[AnyRef]]
+  def optRepValueSet: Option[RepValueSet]
 
   def optRepTypeElement: Option[RepTypeQuasiElementDecl]
 
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/RestrictionUnion.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/RestrictionUnion.scala
index d3f8315..f7d0f2a 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/RestrictionUnion.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/RestrictionUnion.scala
@@ -17,7 +17,7 @@
 
 package org.apache.daffodil.dsom
 
-import java.math.BigInteger
+import java.math.{BigInteger => JBigInt}
 import org.apache.daffodil.exceptions.ThrowsSDE
 import org.apache.daffodil.exceptions.UnsuppressableException
 import scala.xml.Node
@@ -35,7 +35,10 @@ import org.apache.daffodil.util.Maybe
 import org.apache.daffodil.dsom.FacetTypes.ElemFacets
 import org.apache.daffodil.dsom.FacetTypes.FacetValue
 import org.apache.daffodil.processors.RepValueSet
-import org.apache.daffodil.util.RangeBound
+import org.apache.daffodil.processors.RangeBound
+import org.apache.daffodil.infoset.DataValue
+import org.apache.daffodil.infoset.DataValue.DataValuePrimitiveNullable
+import org.apache.daffodil.infoset.DataValue.DataValueBigInt
 
 /**
  * A schema component for simple type restrictions
@@ -175,17 +178,17 @@ final class Restriction(xmlArg: Node, val simpleTypeDef: SimpleTypeDefBase)
 
   lazy val enumerations: Seq[EnumerationDefFactory] = (xml \ "enumeration").map(new EnumerationDefFactory(_, simpleTypeDef))
 
-  lazy val facetValueSet: RepValueSet[AnyRef] = {
-    val initAns: (RangeBound[BigInt], RangeBound[BigInt]) = (new RangeBound(Maybe.Nope, false), new RangeBound(Maybe.Nope, false))
+  lazy val facetValueSet: RepValueSet = {
+    val initAns: (RangeBound, RangeBound) = (new RangeBound(DataValue.NoValue, false), new RangeBound(DataValue.NoValue, false))
     val range = combinedBaseFacets.foldLeft(initAns)({
       case (acc, (facetType, facetValue)) =>
-        lazy val valueAsBigInt = BigInt(facetValue)
+        lazy val valueAsBigInt:DataValueBigInt = new JBigInt(facetValue)
         val (maybeBound, isMax, isInclusive) = facetType match {
-          case Facet.maxExclusive => (Maybe(valueAsBigInt), true, false)
-          case Facet.maxInclusive => (Maybe(valueAsBigInt), true, true)
-          case Facet.minExclusive => (Maybe(valueAsBigInt), false, false)
-          case Facet.minInclusive => (Maybe(valueAsBigInt), false, true)
-          case _ => (Maybe.Nope, false, false)
+          case Facet.maxExclusive => (valueAsBigInt, true, false)
+          case Facet.maxInclusive => (valueAsBigInt, true, true)
+          case Facet.minExclusive => (valueAsBigInt, false, false)
+          case Facet.minInclusive => (valueAsBigInt, false, true)
+          case _ => (DataValue.NoValue, false, false)
         }
         if (maybeBound.isEmpty) {
           acc
@@ -207,10 +210,10 @@ final class Restriction(xmlArg: Node, val simpleTypeDef: SimpleTypeDefBase)
           }
         }
     })
-    RepValueSetCompiler.compile(Seq(), Seq(range.asInstanceOf[(RangeBound[AnyRef], RangeBound[AnyRef])]))
+    RepValueSetCompiler.compile(Seq(), Seq(range.asInstanceOf[(RangeBound, RangeBound)]))
   }
 
-  lazy val repValueSet: RepValueSet[AnyRef] = {
+  lazy val repValueSet: RepValueSet = {
     val subsets = enumerations.map(_.optRepValueSet).filter(_.isDefined).map(_.get)
     if (subsets.length != 0 && subsets.length != enumerations.length) {
       SDE("If one enumeration value defines a repValue, then all must define a repValue")
@@ -226,7 +229,7 @@ final class Restriction(xmlArg: Node, val simpleTypeDef: SimpleTypeDefBase)
 
   lazy val optRepValueSet = if (repValueSet.isEmpty) None else Some(repValueSet)
 
-  lazy val logicalValueSet: RepValueSet[AnyRef] = {
+  lazy val logicalValueSet: RepValueSet = {
     val subsets = enumerations.map(_.logicalValueSet)
     val fromEnums = subsets.fold(RepValueSetCompiler.empty)((a, b) => a.merge(b))
     if (enumerations.length > 0) {
@@ -237,7 +240,7 @@ final class Restriction(xmlArg: Node, val simpleTypeDef: SimpleTypeDefBase)
     }
   }
 
-  lazy val optLogicalValueSet: Option[RepValueSet[AnyRef]] = if (logicalValueSet.isEmpty) None else Some(logicalValueSet)
+  lazy val optLogicalValueSet: Option[RepValueSet] = if (logicalValueSet.isEmpty) None else Some(logicalValueSet)
 }
 
 /**
@@ -487,7 +490,7 @@ sealed trait TypeChecks { self: Restriction =>
   protected def isInUnsignedXXXRange(value: java.math.BigDecimal, numBits: Int, typeName: String): Boolean = {
     Assert.usage(numBits <= 64, "isInUnsignedXXXRange: numBits must be <= 64.")
     // val min = java.math.BigDecimal.ZERO
-    val max = new java.math.BigDecimal(BigInteger.ONE.shiftLeft(numBits)).subtract(new java.math.BigDecimal(1))
+    val max = new java.math.BigDecimal(JBigInt.ONE.shiftLeft(numBits)).subtract(new java.math.BigDecimal(1))
     val isNegative = value.signum == -1
     if (isNegative) return false
     val checkMax = value.compareTo(max)
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SimpleTypes.scala b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SimpleTypes.scala
index d80245d..393a21f 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SimpleTypes.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/dsom/SimpleTypes.scala
@@ -17,40 +17,35 @@
 
 package org.apache.daffodil.dsom
 
+import java.math.{ BigInteger => JBigInt }
+
 import scala.xml.Node
-import org.apache.daffodil.exceptions.Assert
-import org.apache.daffodil.dpath.NodeInfo.PrimType
+
+import org.apache.daffodil.cookers.IntRangeCooker
+import org.apache.daffodil.cookers.RepValueCooker
 import org.apache.daffodil.dpath.NodeInfo
-import org.apache.daffodil.processors.SimpleTypeRuntimeData
-import org.apache.daffodil.util.Misc
-import org.apache.daffodil.schema.annotation.props.gen.Enumeration_AnnotationMixin
-import org.apache.daffodil.schema.annotation.props.PropertyLookupResult
-import org.apache.daffodil.ExecutionMode
-import org.apache.daffodil.schema.annotation.props.Found
-import org.apache.daffodil.xml.QName
-import org.apache.daffodil.schema.annotation.props.NotFound
-import org.apache.daffodil.processors.RepValueSet
+import org.apache.daffodil.dpath.NodeInfo.PrimType
+import org.apache.daffodil.exceptions.Assert
+import org.apache.daffodil.processors.IdentifyTypeCalculator
 import org.apache.daffodil.processors.RepValueSet
+import org.apache.daffodil.processors.RepValueSetCompiler
+import org.apache.daffodil.processors.SimpleTypeRuntimeData
 import org.apache.daffodil.processors.TypeCalculator
 import org.apache.daffodil.processors.TypeCalculatorCompiler
-import org.apache.daffodil.processors.RepValueSetCompiler
-import org.apache.daffodil.dpath.NodeInfo.Numeric
-import org.apache.daffodil.dpath.NodeInfo.PrimType.UnsignedInt
-import org.apache.daffodil.cookers.RepValueCooker
-import org.apache.daffodil.cookers.RepValueCooker
-import scala.xml.Elem
-import scala.xml.MetaData
-import scala.xml.UnprefixedAttribute
-import scala.xml.Null
-import org.apache.daffodil.util.Maybe
+import org.apache.daffodil.schema.annotation.props.Found
+import org.apache.daffodil.util.Misc
 import org.apache.daffodil.xml.GlobalQName
+import org.apache.daffodil.xml.QName
 import org.apache.daffodil.xml.XMLUtils
-import scala.xml.NamespaceBinding
-import org.apache.daffodil.processors.IdentifyTypeCalculator
-import org.apache.daffodil.xml.NS
-import org.apache.daffodil.exceptions.SchemaFileLocation
-import org.apache.daffodil.cookers.IntRangeCooker
-import org.apache.daffodil.util.RangeBound
+import org.apache.daffodil.infoset.DataValue.DataValuePrimitive
+import org.apache.daffodil.processors.RangeBound
+import org.apache.daffodil.util.Maybe.One
+import org.apache.daffodil.infoset.DataValue.DataValuePrimitiveNullable
+import org.apache.daffodil.infoset.DataValue
+import org.apache.daffodil.infoset.DataValue.DataValuePrimitive
+import org.apache.daffodil.infoset.DataValue.DataValueBigInt
+import org.apache.daffodil.infoset.DataValue.DataValueBigInt
+import org.apache.daffodil.infoset.DataValue.DataValueString
 import org.apache.daffodil.infoset.DataValue.DataValuePrimitive
 
 trait TypeBase {
@@ -80,9 +75,9 @@ sealed trait HasRepValueAttributes extends AnnotatedSchemaComponent
   {
 
   def optRepType: Option[SimpleTypeBase]
-  def optRepValueSet: Option[RepValueSet[AnyRef]]
+  def optRepValueSet: Option[RepValueSet]
 
-  lazy val (repValuesAttrCooked: Seq[AnyRef], repValueRangesAttrCooked: Seq[(RangeBound[BigInt], RangeBound[BigInt])]) =
+  lazy val (repValuesAttrCooked:Seq[DataValuePrimitive], repValueRangesAttrCooked:Seq[(RangeBound,RangeBound)]) =
     optRepType match {
       case Some(repType) => {
         val repValueSetRaw = findPropertyOption("repValues").toOption
@@ -91,12 +86,16 @@ sealed trait HasRepValueAttributes extends AnnotatedSchemaComponent
         repType.primType match {
           case PrimType.String => {
             if (repValueRangesRaw.size > 0) SDE("repValueRanges set when using a string repType")
-            val repValueSetCooked = repValueSetRaw.map(RepValueCooker.convertConstant(_, this, false))
+            val repValueSetCooked = repValueSetRaw.flatMap(RepValueCooker.convertConstant(_, this, false)).map(DataValue.toDataValue)
             (repValueSetCooked, Seq())
           }
           case _: NodeInfo.Integer.Kind => {
-            val ans1 = repValueSetRaw.map(BigInt(_))
-            val ans2 = IntRangeCooker.convertConstant(repValueRangesRaw, this, false)
+            val ans1 = repValueSetRaw.map(new JBigInt(_):DataValueBigInt)
+            val ans2 = IntRangeCooker.convertConstant(repValueRangesRaw, this, false).map({case (lower, upper) =>
+              (new RangeBound(lower,true), new RangeBound(upper, true))
+            }
+            
+            )
             (ans1, ans2)
           }
           case x => SDE("repType must be either String or Integer type")
@@ -105,9 +104,9 @@ sealed trait HasRepValueAttributes extends AnnotatedSchemaComponent
       case None => (Seq(), Seq())
     }
 
-  lazy val optRepValueSetFromAttribute: Option[RepValueSet[AnyRef]] = optRepType.flatMap(repType => {
+  lazy val optRepValueSetFromAttribute: Option[RepValueSet] = optRepType.flatMap(repType => {
 
-    val ans = RepValueSetCompiler.compile(repValuesAttrCooked, repValueRangesAttrCooked.asInstanceOf[Seq[(RangeBound[AnyRef], RangeBound[AnyRef])]])
+    val ans = RepValueSetCompiler.compile(repValuesAttrCooked, repValueRangesAttrCooked.asInstanceOf[Seq[(RangeBound, RangeBound)]])
     if (ans.isEmpty) None else Some(ans)
 
   })
@@ -315,12 +314,12 @@ abstract class SimpleTypeDefBase(xml: Node, lexicalParent: SchemaComponent)
   lazy val optInputTypeCalc = findPropertyOption("inputTypeCalc")
   lazy val optOutputTypeCalc = findPropertyOption("outputTypeCalc")
 
-  lazy val optTypeCalculator: Option[TypeCalculator[AnyRef, AnyRef]] = LV('optTypeCalculator) {
+  lazy val optTypeCalculator: Option[TypeCalculator] = LV('optTypeCalculator) {
     optRepType.flatMap(repType => {
       val srcType = repType.primType
       val dstType = primType
 
-      val fromRestriction: Option[TypeCalculator[AnyRef, AnyRef]] = optRestriction.flatMap({ restriction =>
+      val fromRestriction: Option[TypeCalculator] = optRestriction.flatMap({ restriction =>
         val enumerations = restriction.enumerations.filter(_.optRepValueSet.isDefined)
         if (enumerations.isEmpty) {
           /*
@@ -334,16 +333,19 @@ abstract class SimpleTypeDefBase(xml: Node, lexicalParent: SchemaComponent)
           if (enumerations.size != restriction.enumerations.size) {
             SDE("If one enumeration value defines a repValue, then all must define a repValue")
           }
-          val terms = enumerations.map(enum => (enum.optRepValueSet.get, enum.canonicalRepValue.get, enum.enumValueCooked.getAnyRef))
+          val terms = enumerations.map(enum => {
+            Assert.invariant(enum.canonicalRepValue.isDefined)
+            (enum.optRepValueSet.get, enum.canonicalRepValue.getNonNullable, enum.enumValueCooked)
+          })
           Some(TypeCalculatorCompiler.compileKeysetValue(terms, srcType, dstType))
         }
       })
-      val fromUnion: Option[TypeCalculator[AnyRef, AnyRef]] = optUnion.map({ union =>
-        val subCalculators: Seq[(RepValueSet[AnyRef], RepValueSet[AnyRef], TypeCalculator[AnyRef, AnyRef])] =
+      val fromUnion: Option[TypeCalculator] = optUnion.map({ union =>
+        val subCalculators: Seq[(RepValueSet, RepValueSet, TypeCalculator)] =
           union.unionMemberTypes.map(subType => (subType.optRepValueSet.get, subType.optLogicalValueSet.get, subType.optTypeCalculator.get))
         TypeCalculatorCompiler.compileUnion(subCalculators)
       })
-      val fromExpression: Option[TypeCalculator[AnyRef, AnyRef]] = {
+      val fromExpression: Option[TypeCalculator] = {
         /*
          * This is a minefield for circular dependencies.
          * In order to compile expressions involve many typeCalc functions,
@@ -384,7 +386,7 @@ abstract class SimpleTypeDefBase(xml: Node, lexicalParent: SchemaComponent)
         case (Some(x), None, None) => Some(x)
         case (None, Some(x), None) => Some(x)
         case (None, None, Some(x)) => SDE("Usage of inputTypeCalc and outputTypeCalc requires an empty xs:restriction to determine the base type.")
-        case (Some(x), _, Some(y)) if x.isInstanceOf[IdentifyTypeCalculator[AnyRef]] => Some(y)
+        case (Some(x), _, Some(y)) if x.isInstanceOf[IdentifyTypeCalculator] => Some(y)
         case (None, None, None) => {
           if (dstType != srcType) {
             val repTypeName = optRepTypeDef match {
@@ -404,7 +406,7 @@ abstract class SimpleTypeDefBase(xml: Node, lexicalParent: SchemaComponent)
       }
 
       ans match {
-        case Some(idt: IdentifyTypeCalculator[AnyRef]) => {
+        case Some(idt: IdentifyTypeCalculator) => {
           if (srcType != dstType) {
             SDE("Identity transform requires that the basetype and reptype have a common primitive type")
           }
@@ -465,17 +467,17 @@ abstract class SimpleTypeDefBase(xml: Node, lexicalParent: SchemaComponent)
     fromSelf.orElse(fromUnion)
   }.toOption.flatten
 
-  override lazy val optRepValueSet: Option[RepValueSet[AnyRef]] = optRepTypeDef.flatMap(repType => {
+  override lazy val optRepValueSet: Option[RepValueSet] = optRepTypeDef.flatMap(repType => {
     val primType: PrimType = repType.primType
 
-    val fromRestriction: Option[RepValueSet[AnyRef]] = optRestriction.flatMap(_.optRepValueSet)
-    val fromUnion: Option[RepValueSet[AnyRef]] = {
+    val fromRestriction: Option[RepValueSet] = optRestriction.flatMap(_.optRepValueSet)
+    val fromUnion: Option[RepValueSet] = {
       val componentTypes = optUnion.map(_.unionMemberTypes).getOrElse(Seq())
       val componentValueSets = componentTypes.flatMap(_.optRepValueSet)
       val ans = componentValueSets.fold(RepValueSetCompiler.empty)((a, b) => a.merge(b))
       if (ans.isEmpty) None else Some(ans)
     }
-    val fromSelf: Option[RepValueSet[AnyRef]] = optRepValueSetFromAttribute
+    val fromSelf: Option[RepValueSet] = optRepValueSetFromAttribute
 
     (fromRestriction, fromUnion, fromSelf) match {
       case (None, None, None) => None
@@ -489,9 +491,9 @@ abstract class SimpleTypeDefBase(xml: Node, lexicalParent: SchemaComponent)
 
   })
 
-  lazy val optLogicalValueSet: Option[RepValueSet[AnyRef]] = {
-    val fromRestriction: Option[RepValueSet[AnyRef]] = optRestriction.map(_.logicalValueSet)
-    val fromUnion: Option[RepValueSet[AnyRef]] = optUnion.map(union => {
+  lazy val optLogicalValueSet: Option[RepValueSet] = {
+    val fromRestriction: Option[RepValueSet] = optRestriction.map(_.logicalValueSet)
+    val fromUnion: Option[RepValueSet] = optUnion.map(union => {
       val subsets = union.unionMemberTypes.map(_.optLogicalValueSet).filter(_.isDefined).map(_.get)
       subsets.fold(RepValueSetCompiler.empty)((a, b) => a.merge(b))
     })
@@ -567,16 +569,16 @@ final class EnumerationDefFactory(
   lazy val enumValueRaw: String = (xml \ "@value").head.text
   lazy val enumValueCooked: DataValuePrimitive = parentType.primType.fromXMLString(enumValueRaw)
 
-  override lazy val optRepValueSet: Option[RepValueSet[AnyRef]] = optRepValueSetFromAttribute
-  lazy val logicalValueSet: RepValueSet[AnyRef] = RepValueSetCompiler.compile(Seq(enumValueCooked.getAnyRef), Seq())
-  lazy val canonicalRepValue: Option[AnyRef] = {
-    val ans1 = repValuesAttrCooked.headOption
-    val ans2 = repValueRangesAttrCooked.headOption.map(_._1).flatMap(asBound => {
+  override lazy val optRepValueSet: Option[RepValueSet] = optRepValueSetFromAttribute
+  lazy val logicalValueSet: RepValueSet = RepValueSetCompiler.compile(Seq(enumValueCooked), Seq())
+  lazy val canonicalRepValue: DataValuePrimitiveNullable = {
+    val ans1 = repValuesAttrCooked.headOption.getOrElse(DataValue.NoValue)
+    val ans2 = repValueRangesAttrCooked.headOption.map(_._1).map(asBound => {
       //TODO, currently, if the first repValue comes from an exclusive restriction we cannot
       //infer a canonical repValue
-      if (asBound.isInclusive) (Some(asBound.maybeBound.get)) else None
-    })
-    val ans = ans1.orElse(ans2)
+      if (asBound.isInclusive) asBound.maybeBound else DataValue.NoValue
+    }).getOrElse(DataValue.NoValue)
+    val ans = if(ans1.isDefined) ans1 else ans2
     Assert.invariant(ans.isDefined == optRepValueSet.isDefined)
     ans
   }
diff --git a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/ChoiceCombinator.scala b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/ChoiceCombinator.scala
index e20b8f9..30e7b3b 100644
--- a/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/ChoiceCombinator.scala
+++ b/daffodil-core/src/main/scala/org/apache/daffodil/grammar/primitives/ChoiceCombinator.scala
@@ -17,27 +17,29 @@
 
 package org.apache.daffodil.grammar.primitives
 
-import org.apache.daffodil.grammar.Terminal
+import scala.util.Failure
+import scala.util.Success
+import scala.util.Try
+
+import org.apache.daffodil.api.WarnID
+import org.apache.daffodil.cookers.ChoiceBranchKeyCooker
+import org.apache.daffodil.cookers.IntRangeCooker
 import org.apache.daffodil.dsom._
+import org.apache.daffodil.dsom.ChoiceTermBase
+import org.apache.daffodil.equality._
+import org.apache.daffodil.exceptions.Assert
+import org.apache.daffodil.grammar.Gram
+import org.apache.daffodil.grammar.Terminal
 import org.apache.daffodil.processors.parsers._
 import org.apache.daffodil.processors.unparsers._
-import org.apache.daffodil.grammar.Gram
-import org.apache.daffodil.exceptions.Assert
-import org.apache.daffodil.cookers.ChoiceBranchKeyCooker
-import org.apache.daffodil.api.WarnID
-import org.apache.daffodil.equality._
-import org.apache.daffodil.schema.annotation.props.gen.ChoiceLengthKind
 import org.apache.daffodil.schema.annotation.props.gen.ChoiceKeyKindType
-import org.apache.daffodil.dsom.ChoiceTermBase
-import scala.util.Try
-import scala.util.Failure
-import scala.util.Success
-import scala.math.BigInt
-import org.apache.daffodil.cookers.RepValueCooker
-import org.apache.daffodil.util.Maybe
+import org.apache.daffodil.schema.annotation.props.gen.ChoiceLengthKind
 import org.apache.daffodil.util.MaybeInt
-import org.apache.daffodil.util.RangeBound
-import org.apache.daffodil.cookers.IntRangeCooker
+
+import java.math.{ BigInteger => JBigInt }
+import org.apache.daffodil.processors.RangeBound
+import org.apache.daffodil.util.Maybe.One
+import org.apache.daffodil.infoset.DataValue.DataValueString
 
 /*
  * The purpose of the ChoiceCombinator (and the parsers it creates) is to
@@ -85,11 +87,11 @@ case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: Seq[Gram])
       }
     } else {
       //Verify that every alternative has some form of branch key
-      alternatives.map{ alt =>
+      alternatives.map { alt =>
         val keyTerm = alt.context.asInstanceOf[Term]
         val hasBranchKey = keyTerm.findPropertyOption("choiceBranchKey").isDefined
         val hasBranchKeyRanges = keyTerm.findPropertyOption("choiceBranchKeyRanges").isDefined
-        if(!hasBranchKey && !hasBranchKeyRanges && ch.defaultableChoiceBranchKeyKind != ChoiceKeyKindType.ByType){
+        if (!hasBranchKey && !hasBranchKeyRanges && ch.defaultableChoiceBranchKeyKind != ChoiceKeyKindType.ByType) {
           keyTerm.SDE("Neither dfdl:choiceBranchKey nor dfdlx:choiceBranchKeyRanges is defined.")
         }
       }
@@ -102,16 +104,16 @@ case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: Seq[Gram])
               val st = keyTerm_.simpleType
               val aa = st.optRepValueSet
               val repValueSet = keyTerm_.simpleType.optRepValueSet.get
-              val ans = repValueSet.valueSet.toSeq.map(_.toString).mkString(" ")
+              val ans = repValueSet.valueSet.toSeq.map(_.getAnyRef.toString).mkString(" ")
               ans
             }
-            case ChoiceKeyKindType.Explicit | ChoiceKeyKindType.Implicit   => keyTerm.findPropertyOption("choiceBranchKey").toOption.getOrElse("")
+            case ChoiceKeyKindType.Explicit | ChoiceKeyKindType.Implicit => keyTerm.findPropertyOption("choiceBranchKey").toOption.getOrElse("")
             case ChoiceKeyKindType.Speculative => Assert.invariantFailed("Cannot have choiceKeyKind==speculative with direct dispatch")
           }
         val cbks = {
-          if(uncookedBranchKeys.isEmpty){
+          if (uncookedBranchKeys.isEmpty) {
             List()
-          }else{
+          } else {
             ChoiceBranchKeyCooker.convertConstant(uncookedBranchKeys, ch.runtimeData, forUnparse = false)
           }
         }
@@ -120,21 +122,26 @@ case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: Seq[Gram])
 
       //[(minKeyValue, maxKeyValue, parser, isRepresented)]
       //Since there is not a choiceBranchKeyRanges attribute, this can only currently be populated by repType
-      val dispatchBranchKeyRangeTuples: Seq[(RangeBound[BigInt], RangeBound[BigInt], Parser, Boolean)] = alternatives.flatMap { alt =>
+      val dispatchBranchKeyRangeTuples: Seq[(RangeBound, RangeBound, Parser, Boolean)] = alternatives.flatMap { alt =>
         val keyTerm = alt.context.asInstanceOf[Term]
-        val branchKeyRanges:Seq[(RangeBound[BigInt],RangeBound[BigInt])] = ch.defaultableChoiceBranchKeyKind match {
+        val branchKeyRanges: Seq[(RangeBound, RangeBound)] = ch.defaultableChoiceBranchKeyKind match {
           case ChoiceKeyKindType.ByType => {
             val keyTerm_ = keyTerm.asInstanceOf[ElementBase]
-            keyTerm_.simpleType.optRepValueSet.get.valueRanges.toSeq.map(x=>{
-              val x_ = x.asInstanceOf[(RangeBound[BigInt],RangeBound[BigInt])]
-              (x_._1,x_._2)
+            keyTerm_.simpleType.optRepValueSet.get.valueRanges.toSeq.map(x => {
+              val x_ = x.asInstanceOf[(RangeBound, RangeBound)]
+              (x_._1, x_._2)
+            })
+          }
+          case ChoiceKeyKindType.Explicit | ChoiceKeyKindType.Implicit => {
+            val bounds = IntRangeCooker.convertConstant(keyTerm.findPropertyOption("choiceBranchKeyRanges").toOption.getOrElse(""), context, false)
+            bounds.map({
+              case (lowerBound, upperBound) =>
+                (new RangeBound(lowerBound, true), new RangeBound(upperBound, true))
             })
           }
-          case ChoiceKeyKindType.Explicit | ChoiceKeyKindType.Implicit    => 
-            IntRangeCooker.convertConstant(keyTerm.findPropertyOption("choiceBranchKeyRanges").toOption.getOrElse(""), context, false)
           case ChoiceKeyKindType.Speculative => Assert.invariantFailed("Cannot have choiceKeyKind==speculative with direct dispatch")
         }
-        branchKeyRanges.toSeq.map(x=>(x._1, x._2, alt.parser, alt.context.enclosingTerm.get.isRepresented))
+        branchKeyRanges.toSeq.map(x => (x._1, x._2, alt.parser, alt.context.enclosingTerm.get.isRepresented))
       }
 
       // check for duplicate branch keys
@@ -142,9 +149,9 @@ case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: Seq[Gram])
       // we don't see enough distinct ranges on a single element for this to be an issue
       // Additionally, at this point, the keys could be comming from either the choiceBranchKey family of attributes
       // or the repValue family of attributes
-      val (branchKeyAttribute, branchKeyRangeAttribute) = ch.defaultableChoiceBranchKeyKind match{
-        case ChoiceKeyKindType.ByType => ("dfdlx:repValues","dfdlx:repValueRanges")
-        case ChoiceKeyKindType.Explicit | ChoiceKeyKindType.Implicit => ("dfdl:choiceBranchKey","dfdlx:choiceBranchKeyRanges")
+      val (branchKeyAttribute, branchKeyRangeAttribute) = ch.defaultableChoiceBranchKeyKind match {
+        case ChoiceKeyKindType.ByType => ("dfdlx:repValues", "dfdlx:repValueRanges")
+        case ChoiceKeyKindType.Explicit | ChoiceKeyKindType.Implicit => ("dfdl:choiceBranchKey", "dfdlx:choiceBranchKeyRanges")
         case ChoiceKeyKindType.Speculative => Assert.invariantFailed("Cannot have choiceKeyKind==speculative with direct dispatch")
       }
       val groupedByKey = dispatchBranchKeyValueTuples.groupBy(_._1)
@@ -153,12 +160,12 @@ case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: Seq[Gram])
           if (kvs.length > 1) {
             SDE(
               "%s value (%s) is not unique across all branches of a direct dispatch choice. Offending branches are:\n%s",
-              branchKeyAttribute, k, 
+              branchKeyAttribute, k,
               kvs.map(_._2.context.runtimeData).map(rd => rd.diagnosticDebugName + " " + rd.schemaFileLocation.locationDescription).mkString("- ", "\n- ", ""))
           }
           Try(k.toLong) match {
             case Success(v) => {
-              val asBigInt = BigInt(v)
+              val asBigInt = JBigInt.valueOf(v)
               val conflictingRanges = dispatchBranchKeyRangeTuples.filter({ case (min, max, _, _) => min.testAsLower(asBigInt) && max.testAsUpper(asBigInt) })
               if (conflictingRanges.length > 0) {
                 SDE(
@@ -197,7 +204,7 @@ case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: Seq[Gram])
         (parser, isRepresented)
       })
       val serializableMap: Map[String, (Parser, Boolean)] = dispatchBranchKeyMap.map(identity)
-      val serializableKeyRangeMap: Vector[(RangeBound[BigInt], RangeBound[BigInt], Parser, Boolean)] = dispatchBranchKeyRangeTuples.toVector.map(identity)
+      val serializableKeyRangeMap: Vector[(RangeBound, RangeBound, Parser, Boolean)] = dispatchBranchKeyRangeTuples.toVector.map(identity)
 
       ch.defaultableChoiceDispatchKeyKind match {
         case ChoiceKeyKindType.ByType =>
diff --git a/daffodil-lib/src/main/scala/org/apache/daffodil/cookers/Cookers.scala b/daffodil-lib/src/main/scala/org/apache/daffodil/cookers/Cookers.scala
index 0d8592e..63c142a 100644
--- a/daffodil-lib/src/main/scala/org/apache/daffodil/cookers/Cookers.scala
+++ b/daffodil-lib/src/main/scala/org/apache/daffodil/cookers/Cookers.scala
@@ -17,8 +17,8 @@
 
 package org.apache.daffodil.cookers
 
-import org.apache.daffodil.util.RangeBound
-import org.apache.daffodil.util.RangeBound.Range
+import java.math.{ BigInteger => JBigInt }
+
 import org.apache.daffodil.exceptions.ThrowsSDE
 import org.apache.daffodil.util.Maybe
 
@@ -90,20 +90,18 @@ object RepValueCooker extends ListOfStringLiteralNonEmptyNoCharClassEntitiesNoBy
 
 object UpperCaseTokenCooker extends UpperCaseToken
 
-object IntRangeCooker extends Converter[String, Seq[Range[BigInt]]] {
-  protected def convert(input: String, context: ThrowsSDE, forUnparse: Boolean): Seq[Range[BigInt]] = {
-    def run(xs: Seq[String]): Seq[(RangeBound[BigInt], RangeBound[BigInt])] = {
+object IntRangeCooker extends Converter[String, Seq[(JBigInt, JBigInt)]] {
+  protected def convert(input: String, context: ThrowsSDE, forUnparse: Boolean): Seq[(JBigInt, JBigInt)] = {
+    def run(xs: Seq[String]): Seq[(JBigInt, JBigInt)] = {
       xs match {
         case Seq() => Seq()
         case a +: b +: rest => {
-          val a2 = BigInt(a)
-          val b2 = BigInt(b)
-          if (a2.compare(b2) > 0) {
+          val a2 = new JBigInt(a)
+          val b2 = new JBigInt(b)
+          if (a2.compareTo(b2) > 0) {
             context.SDE("min value (%s) is greater than max value (%s)", a2, b2)
           }
-          val a3 = new RangeBound(Maybe(a2), true)
-          val b3 = new RangeBound(Maybe(b2), true)
-          (a3, b3) +: run(rest)
+          (a2, b2) +: run(rest)
         }
       }
     }
diff --git a/daffodil-lib/src/main/scala/org/apache/daffodil/util/RangeBound.scala b/daffodil-lib/src/main/scala/org/apache/daffodil/util/RangeBound.scala
deleted file mode 100644
index 5a1f8e7..0000000
--- a/daffodil-lib/src/main/scala/org/apache/daffodil/util/RangeBound.scala
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.daffodil.util
-
-import java.lang.{ Long => JLong }
-import org.apache.daffodil.exceptions.Assert
-import org.apache.daffodil.cookers.Converter
-import org.apache.daffodil.exceptions.ThrowsSDE
-import org.apache.daffodil.util.RangeBound.Range
-
-object RangeBound {
-  type Range[A <: AnyRef] = (RangeBound[A], RangeBound[A])
-}
-
-class RangeBound[A <: AnyRef](val maybeBound: Maybe[A], val isInclusive: Boolean)
-  extends Serializable {
-
-  lazy val isEmpty = maybeBound.isEmpty
-  lazy val isDefined = maybeBound.isDefined
-
-  override def toString(): String = {
-    if (maybeBound.isDefined) {
-      maybeBound.get.toString + "_" + (if (isInclusive) "inclusive" else "exclusive")
-    } else {
-      "Nope"
-    }
-  }
-
-  def intersectsWithOtherBounds(lower: RangeBound[A], upper: RangeBound[A]): Boolean = {
-    if (maybeBound.isEmpty) {
-      false
-    } else {
-      val bound = maybeBound.get
-      val inBounds = lower.testAsLower(bound) && upper.testAsUpper(bound)
-      val atBoundery = maybeBound == lower.maybeBound || maybeBound == upper.maybeBound
-      inBounds && (isInclusive || !atBoundery)
-    }
-  }
-
-  /*
-   * It should be the case that x is either a BigInt, or a Long
-   */
-
-  def testAsLower(x: A): Boolean = {
-    if (maybeBound.isEmpty) {
-      true
-    } else {
-      if (isInclusive) {
-        le(maybeBound.get, x)
-      } else {
-        lt(maybeBound.get, x)
-      }
-    }
-  }
-  def testAsUpper(x: A): Boolean = {
-    if (maybeBound.isEmpty) {
-      true
-    } else {
-      val bound = maybeBound.get
-      if (isInclusive) {
-        le(x, maybeBound.get)
-      } else {
-        lt(x, maybeBound.get)
-      }
-    }
-  }
-
-  private def le(x: A, y: A): Boolean = {
-    if (x.isInstanceOf[BigInt] && y.isInstanceOf[BigInt]) {
-      x.asInstanceOf[BigInt] <= y.asInstanceOf[BigInt]
-    } else if (x.isInstanceOf[JLong] && y.isInstanceOf[JLong]) {
-      x.asInstanceOf[JLong] <= y.asInstanceOf[JLong]
-    } else if (x.isInstanceOf[BigInt] && y.isInstanceOf[JLong]) {
-      x.asInstanceOf[BigInt] <= BigInt(y.asInstanceOf[JLong])
-    } else if (x.isInstanceOf[JLong] && y.isInstanceOf[BigInt]) {
-      BigInt(x.asInstanceOf[JLong]) <= y.asInstanceOf[BigInt]
-    } else {
-      Assert.invariantFailed("Illegal type passed to RangeBound.le")
-    }
-  }
-
-  private def lt(x: A, y: A): Boolean = {
-    if (x.isInstanceOf[BigInt] && y.isInstanceOf[BigInt]) {
-      x.asInstanceOf[BigInt] < y.asInstanceOf[BigInt]
-    } else if (x.isInstanceOf[JLong] && y.isInstanceOf[JLong]) {
-      x.asInstanceOf[JLong] < y.asInstanceOf[JLong]
-    } else if (x.isInstanceOf[BigInt] && y.isInstanceOf[JLong]) {
-      x.asInstanceOf[BigInt] < BigInt(y.asInstanceOf[JLong])
-    } else if (x.isInstanceOf[JLong] && y.isInstanceOf[BigInt]) {
-      BigInt(x.asInstanceOf[JLong]) < y.asInstanceOf[BigInt]
-    } else {
-      Assert.invariantFailed("Illegal type passed to RangeBound.lt")
-    }
-  }
-
-}
\ No newline at end of file
diff --git a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/ExpressionEvaluatingUnparsers.scala b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/ExpressionEvaluatingUnparsers.scala
index 5ee6d19..62cb5b4 100644
--- a/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/ExpressionEvaluatingUnparsers.scala
+++ b/daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/processors/unparsers/ExpressionEvaluatingUnparsers.scala
@@ -111,7 +111,7 @@ class NewVariableInstanceEndUnparser(override val context: RuntimeData)
   }
 }
 
-class TypeValueCalcUnparser(typeCalculator: TypeCalculator[AnyRef, AnyRef], repTypeUnparser: Unparser, e: ElementRuntimeData, repTypeRuntimeData: ElementRuntimeData)
+class TypeValueCalcUnparser(typeCalculator: TypeCalculator, repTypeUnparser: Unparser, e: ElementRuntimeData, repTypeRuntimeData: ElementRuntimeData)
   extends CombinatorUnparser(e) {
 
   override def childProcessors: Vector[Unparser] = Vector(repTypeUnparser)
@@ -124,12 +124,13 @@ class TypeValueCalcUnparser(typeCalculator: TypeCalculator[AnyRef, AnyRef], repT
 
     val currentSimple = ustate.currentInfosetNode.asSimple
 
-    val logicalValue: DataValuePrimitiveNullable = currentSimple.dataValue
-    Assert.invariant(logicalValue.isDefined)
+    val logicalValueNullable = currentSimple.dataValue
+    Assert.invariant(logicalValueNullable.isDefined)
+    val logicalValue=logicalValueNullable.getNonNullable
     val logicalValueType = currentSimple.erd.optPrimType.get
     val repTypeValue: DataValuePrimitiveNullable = {
-      val ans = typeCalculator.outputTypeCalcUnparse(ustate, e, logicalValue.getAnyRef, logicalValueType)
-      DataValue.unsafeFromMaybeAnyRef(ans)
+      val ans = typeCalculator.outputTypeCalcUnparse(ustate, e, logicalValue.getNonNullable, logicalValueType)
+      ans
     }
 
     val origInfosetElement = ustate.currentInfosetNode
diff --git a/daffodil-runtime1/src/main/scala-2.11/org/apache/daffodil/infoset/DataValue.scala b/daffodil-runtime1/src/main/scala-2.11/org/apache/daffodil/infoset/DataValue.scala
index 84bbf93..9ebeb7c 100644
--- a/daffodil-runtime1/src/main/scala-2.11/org/apache/daffodil/infoset/DataValue.scala
+++ b/daffodil-runtime1/src/main/scala-2.11/org/apache/daffodil/infoset/DataValue.scala
@@ -71,7 +71,7 @@ sealed trait DataValuePrimitiveType
  * allow for automatic upcasting between these types where appropriate.
  *
  */
-final class DataValue[+T <: AnyRef, +X <: AnyRef] private (val v: T) extends AnyVal {
+final class DataValue[+T <: AnyRef, +X <: AnyRef] private (val v: T) extends AnyVal with Serializable{
   @inline def isEmpty = DataValue.NoValue.v eq v
   @inline def isDefined = !isEmpty
   @inline def value = v
@@ -99,8 +99,8 @@ final class DataValue[+T <: AnyRef, +X <: AnyRef] private (val v: T) extends Any
   @inline def getString = v.asInstanceOf[JString]
   @inline def getURI = v.asInstanceOf[URI]
 
-  @inline def getNonNullable = this.asInstanceOf[DataValue[T, X with NonNullable]]
-  @inline def getNullablePrimitive = this.asInstanceOf[DataValue.DataValuePrimitiveNullable]
+  @inline def getNonNullable:DataValue[T, X with NonNullable] = new DataValue(v)
+  @inline def getNullablePrimitive:DataValue.DataValuePrimitiveNullable = new DataValue(v)
 
   @inline def getOptionAnyRef = {
     if (isEmpty) {
@@ -248,6 +248,6 @@ object DataValue {
   }
 }
 
-class BoxedByteArray(val v: Array[Byte]) {
+class BoxedByteArray(val v: Array[Byte]) extends Serializable {
 
 }
\ No newline at end of file
diff --git a/daffodil-runtime1/src/main/scala-2.12/org/apache/daffodil/infoset/DataValue.scala b/daffodil-runtime1/src/main/scala-2.12/org/apache/daffodil/infoset/DataValue.scala
index c264e3b..f33d8d9 100644
--- a/daffodil-runtime1/src/main/scala-2.12/org/apache/daffodil/infoset/DataValue.scala
+++ b/daffodil-runtime1/src/main/scala-2.12/org/apache/daffodil/infoset/DataValue.scala
@@ -67,7 +67,7 @@ sealed trait DataValuePrimitiveType
  * allow for automatic upcasting between these types where appropriate.
  *
  */
-final class DataValue[+T <: AnyRef, +X <: AnyRef] private (val v: T) extends AnyVal {
+final class DataValue[+T <: AnyRef, +X <: AnyRef] private (val v: T) extends AnyVal with Serializable {
   @inline def isEmpty = DataValue.NoValue.v eq v
   @inline def isDefined = !isEmpty
   @inline def value = v
@@ -89,8 +89,8 @@ final class DataValue[+T <: AnyRef, +X <: AnyRef] private (val v: T) extends Any
   @inline def getString = v.asInstanceOf[JString]
   @inline def getURI = v.asInstanceOf[URI]
 
-  @inline def getNonNullable = this.asInstanceOf[DataValue[T, X with NonNullable]]
-  @inline def getNullablePrimitive = this.asInstanceOf[DataValue.DataValuePrimitiveNullable]
+  @inline def getNonNullable:DataValue[T, X with NonNullable] = new DataValue(v)
+  @inline def getNullablePrimitive:DataValue.DataValuePrimitiveNullable = new DataValue(v)
 
   @inline def getOptionAnyRef = {
     if (isEmpty) {
@@ -183,6 +183,13 @@ object DataValue {
     } else {
       NoValue
     }
+  }  
+  @inline def unsafeFromOptionAnyRef(v: Option[AnyRef]) = {
+    if (v.isDefined) {
+      new DataValue(v.get)
+    } else {
+      NoValue
+    }
   }
 
   val NoValue: DataValueEmpty = new DataValue(null)
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/dpath/DFDLXTypeCalcFunctions.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/dpath/DFDLXTypeCalcFunctions.scala
index c3bcc35..d181cea 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/dpath/DFDLXTypeCalcFunctions.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/dpath/DFDLXTypeCalcFunctions.scala
@@ -19,26 +19,27 @@ package org.apache.daffodil.dpath
 
 import org.apache.daffodil.infoset.DataValue.DataValuePrimitive
 import org.apache.daffodil.processors.TypeCalculator
+import org.apache.daffodil.exceptions.Assert
 
-case class DFDLXInputTypeCalc(typedRecipes: List[(CompiledDPath, NodeInfo.Kind)], calc: TypeCalculator[AnyRef, AnyRef])
+case class DFDLXInputTypeCalc(typedRecipes: List[(CompiledDPath, NodeInfo.Kind)], calc: TypeCalculator)
   extends FNTwoArgs(typedRecipes.map(_._1)) {
 
   val srcType = typedRecipes(1)._2
 
   override def computeValue(arg1: DataValuePrimitive, arg2: DataValuePrimitive, dstate: DState): DataValuePrimitive = {
-    calc.inputTypeCalcRun(dstate, arg2.getAnyRef, srcType)
+    calc.inputTypeCalcRun(dstate, arg2, srcType)
     dstate.currentValue.getNonNullable
   }
 
 }
 
-case class DFDLXOutputTypeCalc(typedRecipes: List[(CompiledDPath, NodeInfo.Kind)], calc: TypeCalculator[AnyRef, AnyRef])
+case class DFDLXOutputTypeCalc(typedRecipes: List[(CompiledDPath, NodeInfo.Kind)], calc: TypeCalculator)
   extends FNTwoArgs(typedRecipes.map(_._1)) {
 
   val srcType = typedRecipes(1)._2
 
   def computeValue(arg1: DataValuePrimitive, arg2: DataValuePrimitive, dstate: DState): DataValuePrimitive = {
-    calc.outputTypeCalcRun(dstate, arg2.getAnyRef, srcType)
+    calc.outputTypeCalcRun(dstate, arg2, srcType)
     dstate.currentValue.getNonNullable
   }
 }
@@ -62,7 +63,8 @@ case class DFDLXOutputTypeCalcNextSibling(a: CompiledDPath, b: NodeInfo.Kind) ex
     val primType = nextSibling.erd.optPrimType.get
 
     val x = nextSibling.dataValue
-    typeCalculator.outputTypeCalcRun(dstate, x.getAnyRef, primType)
+    Assert.invariant(x.isDefined)
+    typeCalculator.outputTypeCalcRun(dstate, x.getNonNullable, primType)
   }
 }
 
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/InfosetImpl.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/InfosetImpl.scala
index cafb663..23c1fab 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/InfosetImpl.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/infoset/InfosetImpl.scala
@@ -1119,6 +1119,7 @@ sealed class DISimple(override val erd: ElementRuntimeData)
     // for converting to XML, or for debugging print statements.
     //
     val nodeKind = erd.optPrimType.get
+    val y = x.getAnyRef
     x.getAnyRef match {
       case xs: String => {
         if (nodeKind.isInstanceOf[NodeInfo.String.Kind]) {
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/RuntimeData.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/RuntimeData.scala
index eb71513..cec73b9 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/RuntimeData.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/RuntimeData.scala
@@ -246,8 +246,8 @@ final class SimpleTypeRuntimeData(
   @TransientParam unionMemberTypesArg: => Seq[SimpleTypeRuntimeData],
   @TransientParam unqualifiedPathStepPolicyArg: => UnqualifiedPathStepPolicy,
   @TransientParam repTypeRuntimeDataArg: => Option[SimpleTypeRuntimeData],
-  @TransientParam repValueSetArg: => Option[RepValueSet[AnyRef]],
-  @TransientParam typeCalculatorArg: => Option[TypeCalculator[AnyRef, AnyRef]],
+  @TransientParam repValueSetArg: => Option[RepValueSet],
+  @TransientParam typeCalculatorArg: => Option[TypeCalculator],
   @TransientParam optRepPrimTypeArg: => Option[PrimType])
   extends NonTermRuntimeData(variableMapArg, schemaFileLocationArg, diagnosticDebugNameArg,
     pathArg, namespacesArg, unqualifiedPathStepPolicyArg) {
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/TypeCalculator.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/TypeCalculator.scala
index 0121cc1..b611113 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/TypeCalculator.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/TypeCalculator.scala
@@ -25,18 +25,19 @@ import org.apache.daffodil.dpath.NodeInfo
 import org.apache.daffodil.dsom.CompiledExpression
 import org.apache.daffodil.exceptions.Assert
 import org.apache.daffodil.infoset.DataValue
+import org.apache.daffodil.infoset.DataValue.DataValuePrimitive
 import org.apache.daffodil.infoset.DataValue.DataValuePrimitiveNullable
 import org.apache.daffodil.processors.parsers.PState
 import org.apache.daffodil.processors.parsers.ParseError
 import org.apache.daffodil.processors.unparsers.UState
 import org.apache.daffodil.util.Maybe
 import org.apache.daffodil.util.Maybe.One
+import org.apache.daffodil.util.Numbers
 import org.apache.daffodil.util.PreSerialization
-import org.apache.daffodil.util.RangeBound
 import org.apache.daffodil.util.TransientParam
 import org.apache.daffodil.xml.QNameBase
 
-abstract class TypeCalculator[A <: AnyRef, B <: AnyRef](val srcType: NodeInfo.Kind, val dstType: NodeInfo.Kind)
+abstract class TypeCalculator(val srcType: NodeInfo.Kind, val dstType: NodeInfo.Kind)
   extends PreSerialization {
   type Error = String
 
@@ -54,10 +55,11 @@ abstract class TypeCalculator[A <: AnyRef, B <: AnyRef](val srcType: NodeInfo.Ki
    *      and a second interface to evaluate subexpressions which accepts a DState
    */
 
-  def inputTypeCalc(x: A, xType: NodeInfo.Kind): (Maybe[B], Maybe[Error])
-  def outputTypeCalc(x: B, xType: NodeInfo.Kind): (Maybe[A], Maybe[Error])
+  def inputTypeCalc(x: DataValuePrimitive, xType: NodeInfo.Kind): (DataValuePrimitiveNullable, Maybe[Error])
+  def outputTypeCalc(x: DataValuePrimitive, xType: NodeInfo.Kind): (DataValuePrimitiveNullable, Maybe[Error])
 
-  def inputTypeCalcParse(pstate: PState, context: RuntimeData, x: A, xType: NodeInfo.Kind): DataValuePrimitiveNullable = {
+  def inputTypeCalcParse(pstate: PState, context: RuntimeData, x_in: DataValuePrimitive, xType: NodeInfo.Kind): DataValuePrimitiveNullable = {
+    val x = normalizeArg(x_in, xType)
     val (ans, err) = inputTypeCalc(x, xType)
     Assert.invariant(ans.isDefined ^ err.isDefined)
 
@@ -66,15 +68,10 @@ abstract class TypeCalculator[A <: AnyRef, B <: AnyRef](val srcType: NodeInfo.Ki
       pstate.setFailed(diag)
     }
 
-    //In event of an error, we still want to return Maybe.Nope, which happens
-    //to be what ans would have
-    if(ans.isDefined){
-      DataValue.unsafeFromAnyRef(ans.get)
-    }else{
-      DataValue.NoValue
-    }
+    ans
   }
-  def outputTypeCalcUnparse(ustate: UState, context: RuntimeData, x: B, xType: NodeInfo.Kind): Maybe[A] = {
+  def outputTypeCalcUnparse(ustate: UState, context: RuntimeData, x_in: DataValuePrimitive, xType: NodeInfo.Kind): DataValuePrimitiveNullable = {
+    val x = normalizeArg(x_in, xType)
     val (ans, err) = outputTypeCalc(x, xType)
     Assert.invariant(ans.isDefined ^ err.isDefined)
 
@@ -92,7 +89,8 @@ abstract class TypeCalculator[A <: AnyRef, B <: AnyRef](val srcType: NodeInfo.Ki
    * It appears that dpath expressions actually throw errors.
    * See the definition of DAFError
    */
-  def inputTypeCalcRun(dstate: DState, x: A, xType: NodeInfo.Kind): Unit = {
+  def inputTypeCalcRun(dstate: DState, x_in: DataValuePrimitive, xType: NodeInfo.Kind): Unit = {
+    val x = normalizeArg(x_in, xType)
     val context = dstate.runtimeData.get
     val (ans, err) = inputTypeCalc(x, xType)
     Assert.invariant(ans.isDefined ^ err.isDefined)
@@ -103,10 +101,11 @@ abstract class TypeCalculator[A <: AnyRef, B <: AnyRef](val srcType: NodeInfo.Ki
       //      throw FNErrorFunctionException(Maybe(context.schemaFileLocation), dstate.contextLocation, err.get)
     }
 
-    dstate.setCurrentValue(DataValue.unsafeFromAnyRef(ans.get))
+    dstate.setCurrentValue(ans)
 
   }
-  def outputTypeCalcRun(dstate: DState, x: B, xType: NodeInfo.Kind): Unit = {
+  def outputTypeCalcRun(dstate: DState, x_in: DataValuePrimitive, xType: NodeInfo.Kind): Unit = {
+    val x = normalizeArg(x_in, xType)
     val context = dstate.runtimeData.get
     val (ans, err) = outputTypeCalc(x, xType)
     Assert.invariant(ans.isDefined ^ err.isDefined)
@@ -116,7 +115,7 @@ abstract class TypeCalculator[A <: AnyRef, B <: AnyRef](val srcType: NodeInfo.Ki
       throw diag
     }
 
-    dstate.setCurrentValue(DataValue.unsafeFromAnyRef(ans.get))
+    dstate.setCurrentValue(ans)
 
   }
 
@@ -125,67 +124,85 @@ abstract class TypeCalculator[A <: AnyRef, B <: AnyRef](val srcType: NodeInfo.Ki
 
   @throws(classOf[java.io.IOException])
   final private def writeObject(out: java.io.ObjectOutputStream): Unit = serializeObject(out)
+
+  /*
+   * In theory, this normalizeArg method should not be nessasary. We know at compile time what
+   * types a given calculator is defined in terms of, so the compiler should insert any conversion
+   * nessasary so that the type being passed in is what the calculator was defined in terms of.
+   * In practice, we are not doing that. Instead, we convert all numeric types to JBigInt.
+   */
+  protected def normalizeArg(x: DataValuePrimitive, xType: NodeInfo.Kind): DataValuePrimitive = {
+    if (xType == NodeInfo.String) {
+      x
+    } else {
+      Numbers.asBigInt(x.getAnyRef)
+    }
+  }
 }
 
-class KeysetValueTypeCalculatorOrdered[A <: AnyRef, B <: AnyRef](valueMap: HashMap[A, B], rangeTable: Seq[(RangeBound[A], RangeBound[A], B)], unparseMap: HashMap[B, A],
+/*
+ * We define valueMap in terms of AnyRef instead of DataValuePrimitive, because HashMap is polymorphic,
+ * so using DataValuePrimitive would trigger boxing
+ */
+class KeysetValueTypeCalculatorOrdered(valueMap: HashMap[DataValuePrimitive, DataValuePrimitive], rangeTable: Seq[(RangeBound, RangeBound, DataValuePrimitive)], unparseMap: HashMap[DataValuePrimitive, DataValuePrimitive],
   srcType: NodeInfo.Kind, dstType: NodeInfo.Kind)
-  extends TypeCalculator[A, B](srcType, dstType) {
+  extends TypeCalculator(srcType, dstType) {
 
-  override def inputTypeCalc(x: A, xType: NodeInfo.Kind): (Maybe[B], Maybe[Error]) = {
+  override def inputTypeCalc(x: DataValuePrimitive, xType: NodeInfo.Kind): (DataValuePrimitiveNullable, Maybe[Error]) = {
     if (valueMap.contains(x)) {
-      (One(valueMap.get(x).get), Maybe.Nope)
+      (valueMap.get(x).get, Maybe.Nope)
     } else {
-      val ans1: Option[(RangeBound[A], RangeBound[A], B)] = rangeTable.find({
+      val ans1: Option[(RangeBound, RangeBound, DataValuePrimitiveNullable)] = rangeTable.find({
         case (min, max, _) => {
           min.testAsLower(x) && max.testAsUpper(x)
         }
       })
       ans1 match {
         case None => {
-          (Maybe.Nope, One(s"Key ${x} not found in keyset-value mapping"))
+          (DataValue.NoValue, One(s"Key ${x} not found in keyset-value mapping"))
         }
-        case Some((_, _, v)) => (Maybe(v), Maybe.Nope)
+        case Some((_, _, v)) => (v, Maybe.Nope)
       }
     }
   }
 
-  override def outputTypeCalc(x: B, xType: NodeInfo.Kind): (Maybe[A], Maybe[Error]) = {
+  override def outputTypeCalc(x: DataValuePrimitive, xType: NodeInfo.Kind): (DataValuePrimitiveNullable, Maybe[Error]) = {
     unparseMap.get(x) match {
-      case Some(v) => (Maybe(v), Maybe.Nope)
-      case None => (Maybe.Nope, One(s"Value ${x} not found in keyset-value mapping"))
+      case Some(v) => (v, Maybe.Nope)
+      case None => (DataValue.NoValue, One(s"Value ${x} not found in keyset-value mapping"))
     }
   }
 
 }
 
-class KeysetValueTypeCalculatorUnordered[A <: AnyRef, B <: AnyRef](valueMap: HashMap[A, B], unparseMap: HashMap[B, A], srcType: NodeInfo.Kind, dstType: NodeInfo.Kind)
-  extends TypeCalculator[A, B](srcType, dstType) {
+class KeysetValueTypeCalculatorUnordered(valueMap: HashMap[DataValuePrimitive, DataValuePrimitive], unparseMap: HashMap[DataValuePrimitive, DataValuePrimitive], srcType: NodeInfo.Kind, dstType: NodeInfo.Kind)
+  extends TypeCalculator(srcType, dstType) {
 
-  override def inputTypeCalc(x: A, xType: NodeInfo.Kind): (Maybe[B], Maybe[Error]) = {
+  override def inputTypeCalc(x: DataValuePrimitive, xType: NodeInfo.Kind): (DataValuePrimitiveNullable, Maybe[Error]) = {
     if (valueMap.contains(x)) {
       valueMap.get(x) match {
-        case Some(a) => (Maybe(a), Maybe.Nope)
-        case None => (Maybe.Nope, One(s"Value ${x} not found in keyset-value mapping"))
+        case Some(a) => (a, Maybe.Nope)
+        case None => (DataValue.NoValue, One(s"Value ${x} not found in keyset-value mapping"))
       }
     } else {
-      (Maybe.Nope, One(s"Key ${x} not found in keyset-value mapping"))
+      (DataValue.NoValue, One(s"Key ${x} not found in keyset-value mapping"))
 
     }
   }
-  override def outputTypeCalc(x: B, xType: NodeInfo.Kind): (Maybe[A], Maybe[Error]) = {
+  override def outputTypeCalc(x: DataValuePrimitive, xType: NodeInfo.Kind): (DataValuePrimitiveNullable, Maybe[Error]) = {
     unparseMap.get(x) match {
-      case Some(v) => (Maybe(v), Maybe.Nope)
-      case None => (Maybe.Nope, One(s"Value ${x} not found in keyset-value mapping"))
+      case Some(v) => (v, Maybe.Nope)
+      case None => (DataValue.NoValue, One(s"Value ${x} not found in keyset-value mapping"))
     }
   }
 
 }
 
-class ExpressionTypeCalculator[A <: AnyRef, B <: AnyRef](
-  @TransientParam maybeInputTypeCalcArg: => Maybe[ CompiledExpression[B]],
-  @TransientParam maybeOutputTypeCalcArg: => Maybe[CompiledExpression[A]],
+class ExpressionTypeCalculator(
+  @TransientParam maybeInputTypeCalcArg: => Maybe[CompiledExpression[AnyRef]],
+  @TransientParam maybeOutputTypeCalcArg: => Maybe[CompiledExpression[AnyRef]],
   srcType: NodeInfo.Kind, dstType: NodeInfo.Kind)
-  extends TypeCalculator[A, B](srcType, dstType) {
+  extends TypeCalculator(srcType, dstType) {
 
   override def supportsParse = maybeInputTypeCalcArg.isDefined
   override def supportsUnparse = maybeOutputTypeCalcArg.isDefined
@@ -211,46 +228,46 @@ class ExpressionTypeCalculator[A <: AnyRef, B <: AnyRef](
 
   //TODO, pass x into DPath state
 
-  override def inputTypeCalc(x: A, xType: NodeInfo.Kind): (Maybe[B], Maybe[Error]) =
+  override def inputTypeCalc(x: DataValuePrimitive, xType: NodeInfo.Kind): (DataValuePrimitiveNullable, Maybe[Error]) =
     Assert.invariantFailed("inputTypeCalc not implemented on ExpressionTypeCalculator. Call the more specialized forms directly")
-  override def outputTypeCalc(x: B, xType: NodeInfo.Kind): (Maybe[A], Maybe[Error]) =
+  override def outputTypeCalc(x: DataValuePrimitive, xType: NodeInfo.Kind): (DataValuePrimitiveNullable, Maybe[Error]) =
     Assert.invariantFailed("outputTypeCalc not implemented on ExpressionTypeCalculator. Call the more specialized forms directly")
 
-  override def inputTypeCalcParse(state: PState, context: RuntimeData, x: A, xType: NodeInfo.Kind): DataValuePrimitiveNullable = {
+  override def inputTypeCalcParse(state: PState, context: RuntimeData, x: DataValuePrimitive, xType: NodeInfo.Kind): DataValuePrimitiveNullable = {
     val dstate = state.dState
     val oldRepValue = dstate.repValue
     val oldLogicalValue = dstate.logicalValue
-    dstate.repValue = DataValue.unsafeFromAnyRef(x)
+    dstate.repValue = x
     dstate.logicalValue = DataValue.NoValue
 
     val ans = Maybe(maybeInputTypeCalc.get.evaluate(state))
 
     dstate.repValue = oldRepValue
     dstate.logicalValue = oldLogicalValue
-    if(ans.isDefined){
+    if (ans.isDefined) {
       DataValue.unsafeFromAnyRef(ans.get)
-    }else{
+    } else {
       DataValue.NoValue;
     }
   }
-  override def outputTypeCalcUnparse(state: UState, context: RuntimeData, x: B, xType: NodeInfo.Kind): Maybe[A] = {
+  override def outputTypeCalcUnparse(state: UState, context: RuntimeData, x: DataValuePrimitive, xType: NodeInfo.Kind): DataValuePrimitiveNullable = {
     val dstate = state.dState
     val oldRepValue = dstate.repValue
     val oldLogicalValue = dstate.logicalValue
     dstate.repValue = DataValue.NoValue
-    dstate.logicalValue = DataValue.unsafeFromAnyRef(x)
+    dstate.logicalValue = x
 
-    val ans = Maybe(maybeOutputTypeCalc.get.evaluate(state))
+    val ans = maybeOutputTypeCalc.get.evaluate(state)
 
     dstate.repValue = oldRepValue
     dstate.logicalValue = oldLogicalValue
-    ans
+    DataValue.unsafeFromAnyRef(ans)
   }
 
-  override def inputTypeCalcRun(dstate: DState, x: A, xType: NodeInfo.Kind): Unit = {
+  override def inputTypeCalcRun(dstate: DState, x: DataValuePrimitive, xType: NodeInfo.Kind): Unit = {
     val oldRepValue = dstate.repValue
     val oldLogicalValue = dstate.logicalValue
-    dstate.repValue = DataValue.unsafeFromAnyRef(x)
+    dstate.repValue = x
     dstate.logicalValue = DataValue.NoValue
 
     maybeInputTypeCalc.get.run(dstate)
@@ -259,11 +276,11 @@ class ExpressionTypeCalculator[A <: AnyRef, B <: AnyRef](
     dstate.logicalValue = oldLogicalValue
 
   }
-  override def outputTypeCalcRun(dstate: DState, x: B, xType: NodeInfo.Kind): Unit = {
+  override def outputTypeCalcRun(dstate: DState, x: DataValuePrimitive, xType: NodeInfo.Kind): Unit = {
     val oldRepValue = dstate.repValue
     val oldLogicalValue = dstate.logicalValue
     dstate.repValue = DataValue.NoValue
-    dstate.logicalValue = DataValue.unsafeFromAnyRef(x)
+    dstate.logicalValue = x
 
     maybeOutputTypeCalc.get.run(dstate)
 
@@ -272,31 +289,32 @@ class ExpressionTypeCalculator[A <: AnyRef, B <: AnyRef](
   }
 }
 
-class IdentifyTypeCalculator[A <: AnyRef](srcType: NodeInfo.Kind) extends TypeCalculator[A, A](srcType, srcType) {
-  override def inputTypeCalc(x: A, xType: NodeInfo.Kind): (Maybe[A], Maybe[Error]) = (Maybe(x), Maybe.Nope)
-  override def outputTypeCalc(x: A, xType: NodeInfo.Kind): (Maybe[A], Maybe[Error]) = (Maybe(x), Maybe.Nope)
+class IdentifyTypeCalculator(srcType: NodeInfo.Kind) extends TypeCalculator(srcType, srcType) {
+  override def inputTypeCalc(x: DataValuePrimitive, xType: NodeInfo.Kind): (DataValuePrimitiveNullable, Maybe[Error]) = (x, Maybe.Nope)
+  override def outputTypeCalc(x: DataValuePrimitive, xType: NodeInfo.Kind): (DataValuePrimitiveNullable, Maybe[Error]) = (x, Maybe.Nope)
 }
 
-class UnionTypeCalculator[A <: AnyRef, B <: AnyRef](subCalculators: Seq[(RepValueSet[A], RepValueSet[B], TypeCalculator[A, B])], srcType: NodeInfo.Kind, dstType: NodeInfo.Kind)
-  extends TypeCalculator[A, B](srcType, dstType) {
+class UnionTypeCalculator(subCalculators: Seq[(RepValueSet, RepValueSet, TypeCalculator)], srcType: NodeInfo.Kind, dstType: NodeInfo.Kind)
+  extends TypeCalculator(srcType, dstType) {
   //TODO, it may be worth it to pre-compute a hash table for direct dispatch,
   //Similar to how keyset-value works
-  override def inputTypeCalc(x: A, xType: NodeInfo.Kind): (Maybe[B], Maybe[Error]) = {
+  override def inputTypeCalc(x: DataValuePrimitive, xType: NodeInfo.Kind): (DataValuePrimitiveNullable, Maybe[Error]) = {
     val subCalcSeq = subCalculators.filter(sub => sub._1.contains(x))
     Assert.invariant(subCalcSeq.length <= 1)
     if (subCalcSeq.isEmpty) {
-      (Maybe.Nope, One(s"Key ${x} does not match any component of this simpleType union"))
+      (DataValue.NoValue, One(s"Key ${x} does not match any component of this simpleType union"))
     } else {
       val subCalc = subCalcSeq.head._3
       subCalc.inputTypeCalc(x, xType)
     }
   }
 
-  override def outputTypeCalc(x: B, xType: NodeInfo.Kind): (Maybe[A], Maybe[Error]) = {
+  override def outputTypeCalc(x_in: DataValuePrimitive, xType: NodeInfo.Kind): (DataValuePrimitiveNullable, Maybe[Error]) = {
+    val x = normalizeArg(x_in, xType)
     val subCalcSeq = subCalculators.filter(sub => sub._2.contains(x))
     Assert.invariant(subCalcSeq.length <= 1)
     if (subCalcSeq.isEmpty) {
-      (Maybe.Nope, One(s"Key ${x} does not match the logical values from any component of this union."))
+      (DataValue.NoValue, One(s"Key ${x} does not match the logical values from any component of this union."))
     } else {
       val subCalc = subCalcSeq.head._3
       subCalc.outputTypeCalc(x, xType)
@@ -309,8 +327,8 @@ class UnionTypeCalculator[A <: AnyRef, B <: AnyRef](subCalculators: Seq[(RepValu
  * Since we can inherit the restriction from xsd facets, we also need to be able to support an
  * aribitrary subset of: minInclusive, minExclusive, maxInclusive, and maxExclusive
  */
-class RepValueSet[A <: AnyRef](val valueSet: HashSet[A], val valueRanges: Set[(RangeBound[A], RangeBound[A])]) extends Serializable {
-  def contains(x: A): Boolean = {
+class RepValueSet(val valueSet: HashSet[DataValuePrimitive], val valueRanges: Set[(RangeBound, RangeBound)]) extends Serializable {
+  def contains(x: DataValuePrimitive): Boolean = {
     val ans1 = valueSet.contains(x)
     if (ans1) {
       ans1
@@ -322,7 +340,7 @@ class RepValueSet[A <: AnyRef](val valueSet: HashSet[A], val valueRanges: Set[(R
     }
   }
 
-  def merge(other: RepValueSet[A]): RepValueSet[A] = {
+  def merge(other: RepValueSet): RepValueSet = {
     val valueSet_ = valueSet ++ other.valueSet
     val valueRanges_ = valueRanges ++ other.valueRanges
     new RepValueSet(valueSet_, valueRanges_)
@@ -336,38 +354,41 @@ class RepValueSet[A <: AnyRef](val valueSet: HashSet[A], val valueRanges: Set[(R
 //We should check if we can safely convert them to Long
 
 object RepValueSetCompiler {
-  def compile[A <: AnyRef](valueSet: Seq[A], valuesRanges: Seq[(RangeBound[A], RangeBound[A])]): RepValueSet[A] = {
+  def compile(valueSet: Seq[DataValuePrimitive], valuesRanges: Seq[(RangeBound, RangeBound)]): RepValueSet = {
     val hashSet = HashSet.empty ++ valueSet
     val rangeSet = Set.empty ++ valuesRanges.filter(x => x._1.isDefined || x._2.isDefined)
     new RepValueSet(hashSet, rangeSet)
   }
-  def empty[A <: AnyRef]: RepValueSet[A] = compile(Seq.empty, Seq.empty)
+  def empty: RepValueSet = compile(Seq.empty, Seq.empty)
 }
 
 object TypeCalculatorCompiler {
 
-  type TypeCalcMap = Map[QNameBase, TypeCalculator[AnyRef, AnyRef]]
+  type TypeCalcMap = Map[QNameBase, TypeCalculator]
 
   // mappings: [(keySet, canonicalKey, value)]
-  def compileKeysetValue[A <: AnyRef, B <: AnyRef](mappings: Seq[(RepValueSet[A], A, B)], srcType: NodeInfo.Kind, dstType: NodeInfo.Kind): TypeCalculator[A, B] = {
+  def compileKeysetValue(
+    mappings: Seq[(RepValueSet, DataValuePrimitive, DataValuePrimitive)],
+    srcType: NodeInfo.Kind,
+    dstType: NodeInfo.Kind): TypeCalculator = {
     Assert.invariant(!mappings.isEmpty)
 
     /*
      * We need to cast to HashMap, because the type of HashMap.++ returns a generic Map
      * HashMap.+ returns a HashMap, so we can avoid the case by doing the fold ourself
      */
-    val valueMap: HashMap[A, B] = (HashMap.empty ++ mappings.flatMap(x => {
+    val valueMap: HashMap[DataValuePrimitive, DataValuePrimitive] = (HashMap.empty ++ mappings.flatMap(x => {
       val (keySet, _, value) = x
       keySet.valueSet.map((_, value))
-    })).asInstanceOf[HashMap[A, B]]
-    val rangeTable: Seq[(RangeBound[A], RangeBound[A], B)] = mappings.flatMap(x => {
+    })).asInstanceOf[HashMap[DataValuePrimitive, DataValuePrimitive]]
+    val rangeTable: Seq[(RangeBound, RangeBound, DataValuePrimitive)] = mappings.flatMap(x => {
       val (keySet, _, value) = x
       keySet.valueRanges.map({ case (min, max) => (min, max, value) })
     })
-    val unparseMap: HashMap[B, A] = (HashMap.empty ++ mappings.map(x => {
+    val unparseMap: HashMap[DataValuePrimitive, DataValuePrimitive] = (HashMap.empty ++ mappings.map(x => {
       val (_, canonicalKey, value) = x
       (value, canonicalKey)
-    })).asInstanceOf[HashMap[B, A]]
+    })).asInstanceOf[HashMap[DataValuePrimitive, DataValuePrimitive]]
 
     /*
      * Type erasure makes dispatching based on if we have an ordered keyset or not difficult
@@ -387,18 +408,18 @@ object TypeCalculatorCompiler {
    * While this technically overload that function, to avoid confusion, we are giving it a different
    * name entirely.
    */
-  def compileTypeCalculatorFromExpression[A <: AnyRef, B <: AnyRef](
-    optInputTypeCalc: => Option[CompiledExpression[B]],
-    optOutputTypeCalc: => Option[CompiledExpression[A]],
-    srcType: NodeInfo.Kind, dstType: NodeInfo.Kind): ExpressionTypeCalculator[A, B] = {
-    lazy val maybeInputType: Maybe[CompiledExpression[B]] = optInputTypeCalc.map(Maybe(_)).getOrElse(Maybe.Nope)
-    lazy val maybeOutputType: Maybe[CompiledExpression[A]] = optOutputTypeCalc.map(Maybe(_)).getOrElse(Maybe.Nope)
+  def compileTypeCalculatorFromExpression(
+    optInputTypeCalc: => Option[CompiledExpression[AnyRef]],
+    optOutputTypeCalc: => Option[CompiledExpression[AnyRef]],
+    srcType: NodeInfo.Kind, dstType: NodeInfo.Kind): ExpressionTypeCalculator = {
+    lazy val maybeInputType: Maybe[CompiledExpression[AnyRef]] = optInputTypeCalc.map(Maybe(_)).getOrElse(Maybe.Nope)
+    lazy val maybeOutputType: Maybe[CompiledExpression[AnyRef]] = optOutputTypeCalc.map(Maybe(_)).getOrElse(Maybe.Nope)
     new ExpressionTypeCalculator(maybeInputType, maybeOutputType, srcType, dstType)
   }
-  def compileIdentity[A <: AnyRef](srcType: NodeInfo.Kind): TypeCalculator[A, A] = new IdentifyTypeCalculator(srcType)
+  def compileIdentity(srcType: NodeInfo.Kind): TypeCalculator = new IdentifyTypeCalculator(srcType)
 
   //subCalculators: Seq[(repValues, logicalValues, subCalc)]
-  def compileUnion[A <: AnyRef, B <: AnyRef](subCalculators: Seq[(RepValueSet[A], RepValueSet[B], TypeCalculator[A, B])]): TypeCalculator[A, B] = {
+  def compileUnion(subCalculators: Seq[(RepValueSet, RepValueSet, TypeCalculator)]): TypeCalculator = {
     //TODO, in some cases, it may be possible to merge some subCalculators
     //It may also be possible to compute a direct dispatch table
     val types = subCalculators.map(x => (x._3.srcType, x._3.dstType))
@@ -412,3 +433,92 @@ object TypeCalculatorCompiler {
   }
 
 }
+
+object Range {
+  type Range = (RangeBound, RangeBound)
+  def inclusive(lower:DataValuePrimitiveNullable, upper:DataValuePrimitiveNullable):Range={
+    val lower_ = new RangeBound(lower,true)
+    val upper_ = new RangeBound(upper,true)
+    (lower_,upper_)
+  }
+}
+
+/*
+ * This would be a good example of why we might want DataValue to have a more rich
+ * hierarchy. In theory, RangeBound could be defined in term of a DataValueNumeric type,
+ * from which all of the numeric types extend. In practice, getting complicated DataValue hierarchies to work
+ * turns out to be annoyingly finicky, and so may not be worth the benifit.
+ * 
+ * Additionally, in the current implementation, all instance of RangeBound actually use JBigInt.
+ * This is because most of the current type calculator implementation is based on casting all numeric types
+ * to BigInt, instead of trying to keep track of what types we would be expecting at runtime.
+ */
+class RangeBound(val maybeBound: DataValuePrimitiveNullable, val isInclusive: Boolean)
+  extends Serializable {
+
+  lazy val isEmpty = maybeBound.isEmpty
+  lazy val isDefined = maybeBound.isDefined
+
+  override def toString(): String = {
+    if (maybeBound.isDefined) {
+      maybeBound.getAnyRef.toString + "_" + (if (isInclusive) "inclusive" else "exclusive")
+    } else {
+      "Nope"
+    }
+  }
+
+  def intersectsWithOtherBounds(lower: RangeBound, upper: RangeBound): Boolean = {
+    if (maybeBound.isEmpty) {
+      false
+    } else {
+      val bound = maybeBound.getNonNullable
+      val inBounds = lower.testAsLower(bound) && upper.testAsUpper(bound)
+      val atBoundery = maybeBound == lower.maybeBound || maybeBound == upper.maybeBound
+      inBounds && (isInclusive || !atBoundery)
+    }
+  }
+
+  /*
+   * It should be the case that x is either a JJBigInt, or a Long
+   */
+
+  def testAsLower(x: DataValuePrimitive): Boolean = {
+    if (maybeBound.isEmpty) {
+      true
+    } else {
+      val bound = maybeBound.getNonNullable
+      if (isInclusive) {
+        le(bound, x)
+      } else {
+        lt(bound, x)
+      }
+    }
+  }
+  def testAsUpper(x: DataValuePrimitive): Boolean = {
+    if (maybeBound.isEmpty) {
+      true
+    } else {
+      val bound = maybeBound.getNonNullable
+      if (isInclusive) {
+        le(x, bound)
+      } else {
+        lt(x, bound)
+      }
+    }
+  }
+
+  private def le(x: DataValuePrimitive, y: DataValuePrimitive): Boolean = {
+    val x2 = Numbers.asBigInt(x.getAnyRef)
+    val y2 = Numbers.asBigInt(y.getAnyRef)
+
+    x2.compareTo(y2) <= 0
+  }
+
+  private def lt(x: DataValuePrimitive, y: DataValuePrimitive): Boolean = {
+    val x2 = Numbers.asBigInt(x.getAnyRef)
+    val y2 = Numbers.asBigInt(y.getAnyRef)
+
+    x2.compareTo(y2) < 0
+  }
+
+}
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ElementKindParsers.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ElementKindParsers.scala
index 0e686bd..03cbf5b 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ElementKindParsers.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ElementKindParsers.scala
@@ -17,11 +17,19 @@
 
 package org.apache.daffodil.processors.parsers
 
-import org.apache.daffodil.processors._
+import java.math.{ BigInteger => JBigInt }
+
+import org.apache.daffodil.exceptions.Assert
+import org.apache.daffodil.processors.ChoiceDispatchKeyEv
+import org.apache.daffodil.processors.DelimiterParseEv
+import org.apache.daffodil.processors.ElementRuntimeData
+import org.apache.daffodil.processors.EscapeSchemeParseEv
+import org.apache.daffodil.processors.RangeBound
+import org.apache.daffodil.processors.RuntimeData
+import org.apache.daffodil.processors.Success
+import org.apache.daffodil.processors.TermRuntimeData
 import org.apache.daffodil.util.LogLevel
 import org.apache.daffodil.util.Maybe
-import org.apache.daffodil.exceptions.Assert
-import org.apache.daffodil.util.RangeBound
 
 class ComplexTypeParser(rd: RuntimeData, bodyParser: Parser)
   extends CombinatorParser(rd) {
@@ -125,7 +133,7 @@ class DynamicEscapeSchemeParser(
 
 abstract class ChoiceDispatchCombinatorParserBase(rd: TermRuntimeData, 
                                                   dispatchBranchKeyMap: Map[String, (Parser, Boolean)], 
-                                                  dispatchKeyRangeMap:Vector[(RangeBound[BigInt],RangeBound[BigInt],Parser, Boolean)])
+                                                  dispatchKeyRangeMap:Vector[(RangeBound,RangeBound,Parser, Boolean)])
   extends CombinatorParser(rd) {
   override def nom = "ChoiceDispatch"
 
@@ -179,7 +187,7 @@ abstract class ChoiceDispatchCombinatorParserBase(rd: TermRuntimeData,
           } else{
             if(!dispatchKeyRangeMap.isEmpty){
               try{
-                val keyAsBigInt = BigInt(key)
+                val keyAsBigInt = new JBigInt(key)
                 val optAns1= dispatchKeyRangeMap.find({case(min,max,_,_) => min.testAsLower(keyAsBigInt) && max.testAsUpper(keyAsBigInt)})
                 optAns1.map({case(_,_,parser,isRepresented)=>(parser,isRepresented)})
               } catch{
@@ -243,13 +251,13 @@ abstract class ChoiceDispatchCombinatorParserBase(rd: TermRuntimeData,
 }
 
 class ChoiceDispatchCombinatorParser(rd: TermRuntimeData, dispatchKeyEv: ChoiceDispatchKeyEv, 
-  dispatchBranchKeyMap: Map[String, (Parser, Boolean)], dispatchKeyRangeMap:Vector[(RangeBound[BigInt],RangeBound[BigInt],Parser, Boolean)])
+  dispatchBranchKeyMap: Map[String, (Parser, Boolean)], dispatchKeyRangeMap:Vector[(RangeBound,RangeBound,Parser, Boolean)])
   extends ChoiceDispatchCombinatorParserBase(rd, dispatchBranchKeyMap, dispatchKeyRangeMap) {
   override def computeDispatchKey(pstate: PState): Maybe[String] = Maybe(dispatchKeyEv.evaluate(pstate))
 }
 
 class ChoiceDispatchCombinatorKeyByTypeParser(rd: TermRuntimeData, repTypeParser: Parser, repTypeRuntimeData: ElementRuntimeData, 
-                                              dispatchBranchKeyMap: Map[String, (Parser, Boolean)], dispatchKeyRangeMap:Vector[(RangeBound[BigInt],RangeBound[BigInt],Parser, Boolean)])
+                                              dispatchBranchKeyMap: Map[String, (Parser, Boolean)], dispatchKeyRangeMap:Vector[(RangeBound,RangeBound,Parser, Boolean)])
   extends ChoiceDispatchCombinatorParserBase(rd, dispatchBranchKeyMap, dispatchKeyRangeMap)
   with WithDetachedParser {
 
diff --git a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ExpressionEvaluatingParsers.scala b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ExpressionEvaluatingParsers.scala
index 8f56a49..c217db0 100644
--- a/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ExpressionEvaluatingParsers.scala
+++ b/daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/ExpressionEvaluatingParsers.scala
@@ -124,7 +124,7 @@ trait WithDetachedParser {
   }
 }
 
-class TypeValueCalcParser(typeCalculator: TypeCalculator[AnyRef, AnyRef], repTypeParser: Parser, e: ElementRuntimeData, repTypeRuntimeData: ElementRuntimeData)
+class TypeValueCalcParser(typeCalculator: TypeCalculator, repTypeParser: Parser, e: ElementRuntimeData, repTypeRuntimeData: ElementRuntimeData)
   extends CombinatorParser(e)
   with WithDetachedParser {
   override lazy val childProcessors = Vector(repTypeParser)
@@ -136,7 +136,7 @@ class TypeValueCalcParser(typeCalculator: TypeCalculator[AnyRef, AnyRef], repTyp
     pstate.dataProc.get.ssrd
     if (pstate.processorStatus == Success) {
       Assert.invariant(repValue.isDefined)
-      val logicalValue: DataValuePrimitiveNullable = typeCalculator.inputTypeCalcParse(pstate, context, repValue.getAnyRef, repValueType)
+      val logicalValue: DataValuePrimitiveNullable = typeCalculator.inputTypeCalcParse(pstate, context, repValue.getNonNullable, repValueType)
       if (pstate.processorStatus == Success) {
         Assert.invariant(logicalValue.isDefined)
         pstate.simpleElement.setDataValue(logicalValue)
diff --git a/daffodil-test/src/test/resources/org/apache/daffodil/extensions/type_calc/typeCalcFunctions.tdml b/daffodil-test/src/test/resources/org/apache/daffodil/extensions/type_calc/typeCalcFunctions.tdml
index 8a4d856..eb32046 100644
--- a/daffodil-test/src/test/resources/org/apache/daffodil/extensions/type_calc/typeCalcFunctions.tdml
+++ b/daffodil-test/src/test/resources/org/apache/daffodil/extensions/type_calc/typeCalcFunctions.tdml
@@ -109,6 +109,38 @@
 
   <xs:element name="abstractIntToStringByKeyset_01" type="xs:string" dfdl:inputValueCalc="{dfdlx:inputTypeCalc('AbstractIntToStringByKeyset',0)}"/>
 
+  <xs:element name="sparse_enum01">
+    <xs:complexType>
+     <xs:sequence>
+       <xs:element name="byte" maxOccurs="unbounded" dfdl:occursCountKind="parsed">
+         <xs:complexType>
+           <xs:sequence>
+             <xs:element name="raw" type="tns:uint8"/>
+             <xs:choice dfdl:choiceDispatchKey="{ xs:string(ex:raw) }">
+               <xs:sequence dfdl:choiceBranchKey="15" dfdlx:choiceBranchKeyRanges="1 3">
+                 <xs:element name="enum" type="tns:sparse_lookup" dfdl:inputValueCalc="{ (dfdlx:inputTypeCalc('tns:sparse_lookup', (../ex:raw))) }"/>
+               </xs:sequence>
+               <xs:sequence dfdl:choiceBranchKey="0" dfdlx:choiceBranchKeyRanges="4 14 16 255">
+                 <xs:element name="undefined" type="xs:int" dfdl:inputValueCalc="{ ../ex:raw }"/>
+               </xs:sequence>
+             </xs:choice>
+           </xs:sequence>
+         </xs:complexType>
+       </xs:element>
+     </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+
+  <xs:simpleType name="sparse_lookup" dfdlx:repType="xs:integer">
+    <xs:restriction base="xs:string">
+      <xs:enumeration value="one" dfdlx:repValues="1"/>
+      <xs:enumeration value="two" dfdlx:repValues="2"/>
+      <xs:enumeration value="three" dfdlx:repValues="3"/>
+      <xs:enumeration value="fifteen" dfdlx:repValues="15"/>
+    </xs:restriction>
+  </xs:simpleType>
+
+
   </tdml:defineSchema>
 
   <tdml:parserTestCase name="inputTypeCalcInt_01"
@@ -281,5 +313,82 @@
     </tdml:infoset>
   </tdml:parserTestCase>
 
+  <tdml:parserTestCase name="sparse_enum_01"
+    root="sparse_enum01" model="inputTypeCalc-Embedded.dfdl.xsd" description="Extensions - inputTypeCalc keysetValue transform">
+
+    <tdml:document>
+    <tdml:documentPart type="byte"><![CDATA[
+    00
+    01
+    02
+    03
+    04
+    05
+    0d
+    0e
+    0f
+    10
+    fe
+    ff
+    ]]>
+    </tdml:documentPart>
+    </tdml:document>
+    <tdml:infoset>
+      <tdml:dfdlInfoset xmlns:xs="http://www.w3.org/2001/XMLSchema"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+        <sparse_enum01>
+          <byte>
+            <raw>0</raw>
+            <undefined>0</undefined>
+          </byte>
+          <byte>
+            <raw>1</raw>
+            <enum>one</enum>
+          </byte>
+          <byte>
+            <raw>2</raw>
+            <enum>two</enum>
+          </byte>
+          <byte>
+            <raw>3</raw>
+            <enum>three</enum>
+          </byte>
+          <byte>
+            <raw>4</raw>
+            <undefined>4</undefined>
+          </byte>
+          <byte>
+            <raw>5</raw>
+            <undefined>5</undefined>
+          </byte>
+          <byte>
+            <raw>13</raw>
+            <undefined>13</undefined>
+          </byte>
+          <byte>
+            <raw>14</raw>
+            <undefined>14</undefined>
+          </byte>
+          <byte>
+            <raw>15</raw>
+            <enum>fifteen</enum>
+          </byte>
+          <byte>
+            <raw>16</raw>
+            <undefined>16</undefined>
+          </byte>
+          <byte>
+            <raw>254</raw>
+            <undefined>254</undefined>
+          </byte>
+          <byte>
+            <raw>255</raw>
+            <undefined>255</undefined>
+          </byte>
+        </sparse_enum01>
+      </tdml:dfdlInfoset>
+    </tdml:infoset>
+  </tdml:parserTestCase>
+
 
 </tdml:testSuite>
diff --git a/daffodil-test/src/test/scala/org/apache/daffodil/extensions/TestInputTypeValueCalc.scala b/daffodil-test/src/test/scala/org/apache/daffodil/extensions/TestInputTypeValueCalc.scala
index 30c66a7..4f175ea 100644
--- a/daffodil-test/src/test/scala/org/apache/daffodil/extensions/TestInputTypeValueCalc.scala
+++ b/daffodil-test/src/test/scala/org/apache/daffodil/extensions/TestInputTypeValueCalc.scala
@@ -76,6 +76,7 @@ class TestInputTypeValueCalc {
   @Test def test_outputTypeCalcNextSiblingInt_01() { fnRunner.runOneTest("outputTypeCalcNextSiblingInt_01") }
   @Test def test_outputTypeCalcNextSiblingString_01() { fnRunner.runOneTest("outputTypeCalcNextSiblingString_01") }
   @Test def test_abstractIntToStringByKeyset_01() { fnRunner.runOneTest("abstractIntToStringByKeyset_01") }
+  @Test def test_sparse_enum_01() { fnRunner.runOneTest("sparse_enum_01") }
 
   @Test def test_typeCalcDispatch_typeError_01() { fnErrRunner.runOneTest("typeCalcDispatch_typeError_01") }
   @Test def test_typeCalcDispatch_typeError_02() { fnErrRunner.runOneTest("typeCalcDispatch_typeError_02") }