You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@daffodil.apache.org by mb...@apache.org on 2017/11/17 16:12:13 UTC

[4/6] incubator-daffodil git commit: Property Resolution - part of fixing schema compilation

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/SequenceGroup.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/SequenceGroup.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/SequenceGroup.scala
index ab4478c..cdc68e1 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/SequenceGroup.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/SequenceGroup.scala
@@ -48,9 +48,14 @@ import edu.illinois.ncsa.daffodil.Implicits.ns2String
 import edu.illinois.ncsa.daffodil.grammar.SequenceGrammarMixin
 import edu.illinois.ncsa.daffodil.exceptions.Assert
 import edu.illinois.ncsa.daffodil.processors.SequenceRuntimeData
-
-class Sequence(xmlArg: Node, parent: SchemaComponent, position: Int)
-  extends ModelGroup(xmlArg, parent, position)
+import edu.illinois.ncsa.daffodil.schema.annotation.props.Found
+import edu.illinois.ncsa.daffodil.schema.annotation.props.PropertyLookupResult
+
+abstract class SequenceTermBase(
+  final override val xml: Node,
+  final override val parent: SchemaComponent,
+  final override val position: Int)
+  extends ModelGroup
   with Sequence_AnnotationMixin
   with SequenceRuntimeValuedPropertiesMixin
   with SequenceGrammarMixin
@@ -59,56 +64,13 @@ class Sequence(xmlArg: Node, parent: SchemaComponent, position: Int)
   requiredEvaluations(checkIfValidUnorderedSequence)
   requiredEvaluations(modelGroupRuntimeData.preSerialization)
 
+  protected def apparentXMLChildren: Seq[Node]
+
   final override lazy val myPeers = sequencePeers
 
   final override lazy val hasDelimiters = hasInitiator || hasTerminator || hasSeparator
 
-  protected final def annotationFactory(node: Node): Option[DFDLAnnotation] = {
-    node match {
-      case <dfdl:sequence>{ contents @ _* }</dfdl:sequence> => Some(new DFDLSequence(node, this))
-      case _ => annotationFactoryForDFDLStatement(node, this)
-    }
-  }
-
-  protected final def emptyFormatFactory = new DFDLSequence(newDFDLAnnotationXML("sequence"), this)
-  protected final def isMyFormatAnnotation(a: DFDLAnnotation) = a.isInstanceOf[DFDLSequence]
-
-  // The dfdl:hiddenGroupRef property cannot be scoped, nor defaulted. It's really a special
-  // attribute, not a format property in the usual sense.
-  // So we retrieve it by this lower-level mechanism which only combines short and long form.
-  //
-  // FIXME: must call findPropertyOption so that it gets a context back which
-  // allows resolution of a QName using the right scope.
-  final lazy val hiddenGroupRefOption = getPropertyOption("hiddenGroupRef")
-
-  /**
-   * We're hidden if we're inside something hidden, or we're explicitly a
-   * hidden group reference (sequence with hiddenGroupRef property)
-   */
-  final override lazy val isHidden = {
-    val res = hiddenGroupRefOption match {
-      case Some(_) => true
-      case None => someEnclosingComponent.isHidden
-    }
-    res
-  }
-
-  private lazy val <sequence>{ apparentXMLChildren @ _* }</sequence> = xml
-
-  final def xmlChildren = LV('xmlChildren) {
-    hiddenGroupRefOption match {
-      case Some(qname) => {
-        schemaDefinitionUnless(apparentXMLChildren.length == 0, "A sequence with hiddenGroupRef cannot have children.")
-        // synthesize a group reference here.
-        val contextScope = xml.asInstanceOf[Elem].scope
-        val hgr = {
-          (<xs:group xmlns:xs={ XMLUtils.xsdURI } ref={ qname }/>).copy(scope = contextScope)
-        }
-        List(hgr)
-      }
-      case None => apparentXMLChildren
-    }
-  }.value
+  protected def hiddenGroupRefOption: PropertyLookupResult
 
   final lazy val hasStaticallyRequiredInstances = {
     // true if there are syntactic features
@@ -118,16 +80,16 @@ class Sequence(xmlArg: Node, parent: SchemaComponent, position: Int)
   }
 
   final override def hasKnownRequiredSyntax = LV('hasKnownRequiredSyntax) {
-    lazy val memberHasRequiredSyntax = groupMembersNoRefs.exists(_.hasKnownRequiredSyntax)
+    lazy val memberHasRequiredSyntax = groupMembers.exists(_.hasKnownRequiredSyntax)
     lazy val prefixOrPostfixAndStaticallyRequiredInstance =
-      groupMembersNoRefs.filter { _.isRepresented }.exists { _.hasStaticallyRequiredInstances } &&
+      groupMembers.filter { _.isRepresented }.exists { _.hasStaticallyRequiredInstances } &&
         (hasPrefixSep || hasPostfixSep)
     lazy val infixAnd2OrMoreStaticallyRequiredInstances =
-      groupMembersNoRefs.filter { m => m.isRepresented && m.hasStaticallyRequiredInstances }.length > 1 && hasInfixSep
+      groupMembers.filter { m => m.isRepresented && m.hasStaticallyRequiredInstances }.length > 1 && hasInfixSep
     lazy val sepAndArryaWith2OrMoreStaticallyRequiredInstances =
-      groupMembersNoRefs.filter { m =>
+      groupMembers.filter { m =>
         m.isRepresented && m.hasStaticallyRequiredInstances && (m match {
-          case e: LocalElementBase => e.minOccurs > 1
+          case e: ElementBase => e.minOccurs > 1
           case _ => false
         })
       }.length > 0 && hasSeparator
@@ -153,9 +115,9 @@ class Sequence(xmlArg: Node, parent: SchemaComponent, position: Int)
   }
 
   private def checkMembersHaveValidOccursCountKind: Unit = {
-    val validChildren: Seq[LocalElementBase] =
+    val validChildren: Seq[ElementBase] =
       groupMembers.filter { m => m.isInstanceOf[LocalElementDecl] || m.isInstanceOf[ElementRef]
-      }.map(_.asInstanceOf[LocalElementBase])
+      }.map(_.asInstanceOf[ElementBase])
 
     val invalidChildren = validChildren.filter(e => {
       if (e.minOccurs == 0 | !e.isScalar) {
@@ -203,7 +165,8 @@ class Sequence(xmlArg: Node, parent: SchemaComponent, position: Int)
 
   def checkHiddenSequenceIsDefaultableOrOVC: Unit = {
     if (this.isHidden) {
-      val nonDefaultableOrOVC = this.childrenInHiddenGroupNotDefaultableOrOVC
+      val nonDefaultableOrOVC =
+        this.childrenInHiddenGroupNotDefaultableOrOVC
       if (nonDefaultableOrOVC.length > 0) {
         this.SDE("Element(s) of hidden group must define dfdl:outputValueCalc:\n%s", nonDefaultableOrOVC.mkString("\n"))
       }
@@ -260,7 +223,7 @@ class Sequence(xmlArg: Node, parent: SchemaComponent, position: Int)
 
     // Constructs a sequence of choice using newContent
     val newXML = {
-      xmlArg match {
+      xml match {
         case Elem(prefix, "sequence", attrs, scope, content @ _*) => Elem(prefix, "sequence", attrs, scope, true, newContent: _*)
         case other => other
       }
@@ -296,6 +259,70 @@ class Sequence(xmlArg: Node, parent: SchemaComponent, position: Int)
 
 }
 
+/**
+ * Captures concepts associated with definitions of Sequence groups.
+ *
+ * Used by GlobalSequenceGroupDef and local Sequence, but not by SequenceGroupRef.
+ * Used on objects that can carry DFDLSequence annotation objects.
+ */
+trait SequenceDefMixin
+  extends AnnotatedSchemaComponent
+  with GroupDefLike {
+
+  protected final def isMyFormatAnnotation(a: DFDLAnnotation) = a.isInstanceOf[DFDLSequence]
+
+  protected final def annotationFactory(node: Node): Option[DFDLAnnotation] = {
+    node match {
+      case <dfdl:sequence>{ contents @ _* }</dfdl:sequence> => Some(new DFDLSequence(node, this))
+      case _ => annotationFactoryForDFDLStatement(node, this)
+    }
+  }
+
+  protected final def emptyFormatFactory = new DFDLSequence(newDFDLAnnotationXML("sequence"), this)
+
+  final lazy val <sequence>{ apparentXMLChildren @ _* }</sequence> = (xml \\ "sequence")(0)
+
+  final def xmlChildren = apparentXMLChildren
+
+  // The dfdl:hiddenGroupRef property cannot be scoped, nor defaulted. It's really a special
+  // attribute, not a format property in the usual sense.
+  // So we retrieve it by this lower-level mechanism which only combines short and long form.
+  //
+  final lazy val hiddenGroupRefOption =
+    findPropertyOptionThisComponentOnly("hiddenGroupRef")
+
+}
+
+/**
+ * Represents a local sequence definition.
+ */
+class Sequence(xmlArg: Node, parent: SchemaComponent, position: Int)
+  extends SequenceTermBase(xmlArg, parent, position)
+  with SequenceDefMixin {
+
+  requiredEvaluations(checkHiddenGroupRefHasNoChildren)
+
+  override lazy val optReferredToComponent = None
+
+  private lazy val checkHiddenGroupRefHasNoChildren = {
+    if (hiddenGroupRefOption.isDefined) {
+      val axc = apparentXMLChildren
+      val len = axc.length
+      schemaDefinitionUnless(len == 0, "A sequence with hiddenGroupRef cannot have children.")
+    }
+  }
+
+  final lazy val hiddenGroupRefXML = LV('hiddenGroupRefXML) {
+    val Found(qname, _, _, _) = hiddenGroupRefOption
+    // synthesize a group reference here.
+    val contextScope = xml.asInstanceOf[Elem].scope
+    val hgr = {
+      (<xs:group xmlns:xs={ XMLUtils.xsdURI } ref={ qname }/>).copy(scope = contextScope)
+    }
+    hgr
+  }.value
+}
+
 final class UnorderedSequence(xmlArg: Node, xmlContents: Seq[Node], parent: SchemaComponent, position: Int)
   extends Sequence(xmlArg, parent, position) {
   // A shell, the actual XML representation is passed in

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/SimpleTypes.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/SimpleTypes.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/SimpleTypes.scala
index 3f84b91..1e61aec 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/SimpleTypes.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/SimpleTypes.scala
@@ -43,6 +43,16 @@ trait TypeBase {
   def optRestriction: Option[Restriction] = None
   def optUnion: Option[Union] = None
   def typeNode: NodeInfo.AnyType.Kind
+
+}
+
+trait NonPrimTypeMixin {
+  def elementDecl: ElementDeclMixin
+
+  def elementBase: ElementBase = elementDecl match {
+    case eb: ElementBase => eb
+    case ged: GlobalElementDecl => ged.elementRef
+  }
 }
 
 sealed trait SimpleTypeBase extends TypeBase {
@@ -122,15 +132,14 @@ object PrimitiveType {
 
 }
 
-abstract class SimpleTypeDefBase(xmlArg: Node, override val parent: SchemaComponent)
-  extends AnnotatedSchemaComponent(xmlArg, parent)
+abstract class SimpleTypeDefBase(xml: Node, parent: SchemaComponent)
+  extends AnnotatedSchemaComponentImpl(xml, parent)
   with SimpleTypeBase
-  with DFDLStatementMixin
+  with NonPrimTypeMixin
+  with ProvidesDFDLStatementMixin
   with OverlapCheckMixin {
 
-  requiredEvaluations(if (element.isSimpleType) simpleTypeRuntimeData.preSerialization)
-
-  def element: ElementBase
+  requiredEvaluations(if (elementDecl.isSimpleType) simpleTypeRuntimeData.preSerialization)
 
   override def typeNode = primType
 
@@ -141,25 +150,14 @@ abstract class SimpleTypeDefBase(xmlArg: Node, override val parent: SchemaCompon
     res
   }
 
+  /**
+   * Exclusive of self.
+   */
   final lazy val bases: Seq[SimpleTypeDefBase] =
     if (restrictions.isEmpty) Nil
     else restrictions.tail.map { _.simpleType }
 
-  private lazy val sTypeNonDefault: Seq[ChainPropProvider] = bases.reverse.map { _.nonDefaultFormatChain }
-  private lazy val sTypeDefault: Seq[ChainPropProvider] = bases.reverse.map { _.defaultFormatChain }
-
-  // want a QueueSet i.e., fifo order if iterated, but duplicates
-  // kept out of the set. Will simulate by calling distinct.
-  def nonDefaultPropertySources = LV('nonDefaultPropertySources) {
-    val seq = (this.nonDefaultFormatChain +: sTypeNonDefault).distinct
-    checkNonOverlap(seq)
-    seq
-  }.value
-
-  def defaultPropertySources = LV('defaultPropertySources) {
-    val seq = (this.defaultFormatChain +: sTypeDefault).distinct
-    seq
-  }.value
+  override final def optReferredToComponent = optRestriction.flatMap { _.optBaseDef }
 
   protected final def emptyFormatFactory = new DFDLSimpleType(newDFDLAnnotationXML("simpleType"), this)
 
@@ -168,7 +166,7 @@ abstract class SimpleTypeDefBase(xmlArg: Node, override val parent: SchemaCompon
   protected final def annotationFactory(node: Node): Option[DFDLAnnotation] = {
     node match {
       case <dfdl:simpleType>{ contents @ _* }</dfdl:simpleType> => Some(new DFDLSimpleType(node, this))
-      case _ => annotationFactoryForDFDLStatement(node, this)
+      case _ => annotationFactoryForDFDLStatement(node, elementBase)
     }
   }
 
@@ -183,33 +181,6 @@ abstract class SimpleTypeDefBase(xmlArg: Node, override val parent: SchemaCompon
     }
   }
 
-  /**
-   * Combine our statements with those of our base def (if there is one)
-   *
-   * The order is important here. I.e., we FIRST put in each list those from our base. Then our own local ones.
-   */
-  final lazy val statements: Seq[DFDLStatement] =
-    bases.flatMap { _.statements } ++ localStatements
-
-  private lazy val optBaseDef = optRestriction.flatMap { _.optBaseDef }
-
-  // TODO: refactor into shared code for combining all the annotations in the resolved set of annotations
-  // for a particular annotation point, checking that there is only one format annotation, that
-  // asserts and discriminators are properly excluding each-other, etc.
-  // Code should be sharable for many kinds of annotation points, perhaps specialized for groups, complex type
-  // elements, and simple type elements.
-  //
-  // See JIRA issue DFDL-481
-  final lazy val newVariableInstanceStatements: Seq[DFDLNewVariableInstance] =
-    optBaseDef.map { _.newVariableInstanceStatements }.getOrElse(Seq.empty) ++ localNewVariableInstanceStatements
-  final lazy val (discriminatorStatements, assertStatements) = checkDiscriminatorsAssertsDisjoint(combinedDiscrims, combinedAsserts)
-  private lazy val combinedAsserts: Seq[DFDLAssert] = optBaseDef.map { _.assertStatements }.getOrElse(Nil) ++ localAssertStatements
-  private lazy val combinedDiscrims: Seq[DFDLDiscriminator] = optBaseDef.map { _.discriminatorStatements }.getOrElse(Nil) ++ localDiscriminatorStatements
-
-  final lazy val setVariableStatements: Seq[DFDLSetVariable] = {
-    val combinedSvs = optBaseDef.map { _.setVariableStatements }.getOrElse(Nil) ++ localSetVariableStatements
-    checkDistinctVariableNames(combinedSvs)
-  }
   def toOpt[R <: AnyRef](b: Boolean, v: => R) = Misc.boolToOpt(b, v)
 
   lazy val simpleTypeRuntimeData: SimpleTypeRuntimeData = {
@@ -219,7 +190,7 @@ abstract class SimpleTypeDefBase(xmlArg: Node, override val parent: SchemaCompon
       diagnosticDebugName,
       path,
       namespaces,
-      element.simpleType.primType,
+      primType,
       noFacetChecks,
       //
       // TODO: Cleanup code: really these should all have been option types
@@ -250,29 +221,13 @@ abstract class SimpleTypeDefBase(xmlArg: Node, override val parent: SchemaCompon
     }.getOrElse(true)
 }
 
-sealed abstract class SimpleTypeDefFactory(xml: Node, schemaDocumentArg: SchemaDocument)
-  extends SchemaComponentFactory(xml, schemaDocumentArg) {
-
-}
-
-final class LocalSimpleTypeDefFactory(xmlArg: Node, schemaDocumentArg: SchemaDocument)
-  extends SimpleTypeDefFactory(xmlArg, schemaDocumentArg)
-  with LocalNonElementComponentMixin {
-
-  def forElement(element: ElementBase) =
-    new LocalSimpleTypeDef(this, element)
-
-}
-
 final class LocalSimpleTypeDef(
-  val factory: LocalSimpleTypeDefFactory,
-  elementArg: ElementBase)
-  extends SimpleTypeDefBase(factory.xml, elementArg)
+  xmlArg: Node, elementArg: ElementDeclMixin)
+  extends SimpleTypeDefBase(xmlArg, elementArg)
   with LocalNonElementComponentMixin
   with NestingLexicalMixin {
 
-  override def term = element
-  override lazy val element = elementArg
+  override lazy val elementDecl = elementArg
 
   /**
    * For anonymous simple type def, uses the base name, or primitive type name
@@ -303,13 +258,13 @@ final class LocalSimpleTypeDef(
  */
 
 final class GlobalSimpleTypeDefFactory(xmlArg: Node, schemaDocumentArg: SchemaDocument)
-  extends SimpleTypeDefFactory(xmlArg, schemaDocumentArg)
+  extends SchemaComponentFactory(xmlArg, schemaDocumentArg)
   with GlobalNonElementComponentMixin {
 
   /**
    * Create a private instance for this element's use.
    */
-  def forElement(element: ElementBase) = new GlobalSimpleTypeDef(None, this, Some(element))
+  def forElement(elementDecl: ElementDeclMixin) = new GlobalSimpleTypeDef(None, this, Some(elementDecl))
   def forDerivedType(derivedType: SimpleTypeDefBase) = new GlobalSimpleTypeDef(Some(derivedType), this, None)
 
 }
@@ -320,12 +275,12 @@ final class GlobalSimpleTypeDefFactory(xmlArg: Node, schemaDocumentArg: SchemaDo
 final class GlobalSimpleTypeDef(
   derivedType: Option[SimpleTypeDefBase],
   val factory: GlobalSimpleTypeDefFactory,
-  val referringElement: Option[ElementBase])
+  val referringElement: Option[ElementDeclMixin])
   extends SimpleTypeDefBase(factory.xml, factory.schemaDocument)
   with GlobalNonElementComponentMixin
   with NestingTraversesToReferenceMixin {
 
-  override def term = element
+  // override def term = element
 
   override lazy val referringComponent: Option[SchemaComponent] =
     (derivedType, referringElement) match {
@@ -334,9 +289,9 @@ final class GlobalSimpleTypeDef(
       case _ => Assert.impossible("SimpleType must either have a derivedType or an element. Not both.")
     }
 
-  override lazy val element: ElementBase = referringComponent match {
-    case Some(dt: SimpleTypeDefBase) => dt.element
-    case Some(e: ElementBase) => e
+  override lazy val elementDecl: ElementDeclMixin = referringComponent match {
+    case Some(dt: SimpleTypeDefBase) => dt.elementDecl
+    case Some(e: ElementDeclMixin) => e
     case _ => Assert.invariantFailed("unexpected referringComponent")
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/Term.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/Term.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/Term.scala
index 1b7fae3..fad0853 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/Term.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/Term.scala
@@ -33,8 +33,6 @@
 package edu.illinois.ncsa.daffodil.dsom
 
 import java.util.UUID
-import scala.xml.Node
-import scala.xml._
 import edu.illinois.ncsa.daffodil.exceptions.Assert
 import edu.illinois.ncsa.daffodil.processors.TermRuntimeData
 import edu.illinois.ncsa.daffodil.grammar.TermGrammarMixin
@@ -43,19 +41,28 @@ import java.lang.{ Integer => JInt }
 import edu.illinois.ncsa.daffodil.schema.annotation.props.Found
 import edu.illinois.ncsa.daffodil.schema.annotation.props.gen.NilKind
 
-/////////////////////////////////////////////////////////////////
-// Groups System
-/////////////////////////////////////////////////////////////////
-
-// A term is content of a group
-abstract class Term(xmlArg: Node, parentArg: SchemaComponent, val position: Int)
-  extends AnnotatedSchemaComponent(xmlArg, parentArg)
+/**
+ * Term, and what is and isn't a Term, is a key concept in DSOM.
+ *
+ * From elements, ElementRef and LocalElementDecl are Term. A GlobalElementDecl is *not* a Term.
+ * From sequences, Sequence and SequenceGroupRef are Term. GlobalSequenceGroupDef is *not* a Term.
+ * From choices, Choice and ChoiceGroupRef are Term. GlobalChoiceGroupDef is *not* a Term.
+ *
+ * Terms are the things we actually generate parsers/unparsers for. Non-Terms just
+ * contribute information used by Terms.
+ */
+trait Term
+  extends AnnotatedSchemaComponent
+  with ResolvesProperties
+  with ResolvesDFDLStatementMixin
   with TermRuntimeValuedPropertiesMixin
   with TermGrammarMixin
   with DelimitedRuntimeValuedPropertiesMixin
   with InitiatedTerminatedMixin
   with TermEncodingMixin {
 
+  def position: Int
+
   def optIgnoreCase: Option[YesNo] = {
     val ic = cachePropertyOption("ignoreCase")
     ic match {
@@ -64,8 +71,6 @@ abstract class Term(xmlArg: Node, parentArg: SchemaComponent, val position: Int)
     }
   }
 
-  override final def term = this
-
   /**
    * A scalar means has no dimension. Exactly one occurrence.
    *
@@ -115,15 +120,6 @@ abstract class Term(xmlArg: Node, parentArg: SchemaComponent, val position: Int)
 
   def elementChildren: Seq[ElementBase]
 
-  override lazy val dpathCompileInfo =
-    new DPathCompileInfo(
-      enclosingComponent.map { _.dpathCompileInfo },
-      variableMap,
-      namespaces,
-      path,
-      schemaFileLocation,
-      tunable)
-
   /**
    * An integer which is the alignment of this term. This takes into account the
    * representation, type, charset encoding and alignment-related properties.
@@ -153,6 +149,9 @@ abstract class Term(xmlArg: Node, parentArg: SchemaComponent, val position: Int)
    * base class. This is to make it clear
    * we're not talking about the XML structures inside the XML parent (which might
    * include annotations, etc.
+   *
+   * For elements this is Nil for simple types, a single model group for
+   * complex types. For model groups there can be more children.
    */
   def termChildren: Seq[Term]
 
@@ -166,9 +165,8 @@ abstract class Term(xmlArg: Node, parentArg: SchemaComponent, val position: Int)
 
   lazy val someEnclosingComponent = enclosingComponent.getOrElse(Assert.invariantFailed("All terms except a root element have an enclosing component."))
 
-  lazy val referredToComponent = this // override in ElementRef and GroupRef
-
-  lazy val isRepresented = true // overridden by elements, which might have inputValueCalc turning this off
+  /** Overridden as false for elements with dfdl:inputValueCalc property. */
+  lazy val isRepresented = true
 
   /**
    * nearestEnclosingSequence
@@ -182,36 +180,36 @@ abstract class Term(xmlArg: Node, parentArg: SchemaComponent, val position: Int)
    * This is why we have to have the GlobalXYZDefFactory stuff. Because this kind of back
    * pointer (contextual sensitivity) prevents sharing.
    */
-  final lazy val nearestEnclosingSequence: Option[Sequence] = enclosingTerm match {
+  final lazy val nearestEnclosingSequence: Option[SequenceTermBase] = enclosingTerm match {
     case None => None
-    case Some(s: Sequence) => Some(s)
+    case Some(s: SequenceTermBase) => Some(s)
     case Some(_) => enclosingTerm.get.nearestEnclosingSequence
   }
 
-  final lazy val nearestEnclosingChoiceBeforeSequence: Option[Choice] = enclosingTerm match {
+  final lazy val nearestEnclosingChoiceBeforeSequence: Option[ChoiceTermBase] = enclosingTerm match {
     case None => None
-    case Some(s: Sequence) => None
-    case Some(c: Choice) => Some(c)
+    case Some(s: SequenceTermBase) => None
+    case Some(c: ChoiceTermBase) => Some(c)
     case Some(_) => enclosingTerm.get.nearestEnclosingChoiceBeforeSequence
   }
 
-  final lazy val nearestEnclosingUnorderedSequence: Option[Sequence] = enclosingTerm match {
+  final lazy val nearestEnclosingUnorderedSequence: Option[SequenceTermBase] = enclosingTerm match {
     case None => None
-    case Some(s: Sequence) if !s.isOrdered => Some(s)
+    case Some(s: SequenceTermBase) if !s.isOrdered => Some(s)
     case Some(_) => enclosingTerm.get.nearestEnclosingUnorderedSequence
   }
 
-  final lazy val nearestEnclosingUnorderedSequenceBeforeSequence: Option[Sequence] = enclosingTerm match {
+  final lazy val nearestEnclosingUnorderedSequenceBeforeSequence: Option[SequenceTermBase] = enclosingTerm match {
     case None => None
-    case Some(s: Sequence) if !s.isOrdered => Some(s)
-    case Some(s: Sequence) => None
+    case Some(s: SequenceTermBase) if !s.isOrdered => Some(s)
+    case Some(s: SequenceTermBase) => None
     case Some(_) => enclosingTerm.get.nearestEnclosingUnorderedSequence
   }
 
   final lazy val inChoiceBeforeNearestEnclosingSequence: Boolean = enclosingTerm match {
     case None => false
-    case Some(s: Sequence) => false
-    case Some(c: Choice) => true
+    case Some(s: SequenceTermBase) => false
+    case Some(c: ChoiceTermBase) => true
     case Some(_) => enclosingTerm.get.inChoiceBeforeNearestEnclosingSequence
   }
 
@@ -221,47 +219,6 @@ abstract class Term(xmlArg: Node, parentArg: SchemaComponent, val position: Int)
     case Some(_) => enclosingTerm.get.nearestEnclosingElement
   }
 
-  final lazy val nearestEnclosingElementNotRef: Option[ElementBase] = nearestEnclosingElement match {
-    case None => None
-    case Some(er: ElementRef) => er.nearestEnclosingElement // can't be an element ref again
-    case x => x
-  }
-
-  protected final def thisTermNoRefs: Term = LV('thisTermNoRefs) {
-    val es = nearestEnclosingSequence
-
-    val thisTerm = this match {
-      case eRef: ElementRef => eRef.referencedElement
-      // case gd: GlobalGroupDef => gd.thisTermNoRefs // TODO: scala 2.10 compiler says this line is impossible.
-      case gb: GroupBase if gb.enclosingTerm.isDefined => {
-        // We're a group.  We need to determine what we're enclosed by.
-        gb.enclosingTerm.get match {
-          case encGRef: GroupRef => {
-            // We're enclosed by a GroupRef.  We need to retrieve
-            // what encloses that GroupRef
-
-            val res = encGRef.enclosingTerm match {
-              case None => encGRef.group
-              case Some(encTerm) => encTerm.thisTermNoRefs
-            }
-            //encGRef.thisTerm
-            res
-          }
-          case encGB: GroupBase if es.isDefined && encGB == es.get => {
-            // We're an immediate child of the nearestEnclosingSequence
-            // therefore we just return our self as the Term
-            this
-          }
-          case e: LocalElementBase => e // Immediate enclosed by LocalElementBase, return it.
-          case _ => gb.group
-        }
-      }
-      case gb: GroupBase => gb.group
-      case x => x
-    }
-    thisTerm
-  }.value
-
   /**
    * We want to determine if we're in an unordered sequence
    * at any point along our parents.
@@ -281,22 +238,16 @@ abstract class Term(xmlArg: Node, parentArg: SchemaComponent, val position: Int)
 
   final lazy val immediatelyEnclosingModelGroup: Option[ModelGroup] = {
     val res = parent match {
-      case c: Choice => Some(c)
-      case s: Sequence => Some(s)
+      case c: ChoiceTermBase => Some(c)
+      case s: SequenceTermBase => Some(s)
       case d: SchemaDocument => {
-        // we're a global object. Our parent is a schema document
-        // so follow backpointers to whatever is referencing us.
-        this match {
-          case ge: GlobalElementDecl => ge.elementRef match {
-            case None => {
-              // we are root. So there is no enclosing model group at all
-              None
-            }
-            case Some(er) => er.immediatelyEnclosingModelGroup
-          }
-        }
+        // we must be the Root elementRef
+        Assert.invariant(this.isInstanceOf[Root])
+        None
       }
-      case gdd: GlobalGroupDef => gdd.groupRef.immediatelyEnclosingModelGroup
+      case gr: GroupRef => gr.asModelGroup.immediatelyEnclosingModelGroup
+      case gdd: GlobalGroupDef => gdd.groupRef.asModelGroup.immediatelyEnclosingModelGroup
+      case ged: GlobalElementDecl => ged.elementRef.immediatelyEnclosingModelGroup
       case ct: ComplexTypeBase => {
         None
         // The above formerly was ct.element.immediatelyEnclosingModelGroup,
@@ -311,16 +262,19 @@ abstract class Term(xmlArg: Node, parentArg: SchemaComponent, val position: Int)
   final lazy val positionInNearestEnclosingSequence: Int = {
     val res =
       if (enclosingComponent == nearestEnclosingSequence) position
+      else if (this.isInstanceOf[Root]) 1
       else {
         enclosingComponent match {
           case Some(term: Term) => term.positionInNearestEnclosingSequence
           case Some(ct: ComplexTypeBase) => {
-            val ctElem = ct.element
-            val ctPos = ctElem.positionInNearestEnclosingSequence
+            val ctPos = ct.elementDecl match {
+              case eb: ElementBase => eb.positionInNearestEnclosingSequence
+              case ged: GlobalElementDecl => ged.elementRef.positionInNearestEnclosingSequence
+            }
             ctPos
           }
-          case Some(ggd: GlobalGroupDef) => ggd.groupRef.positionInNearestEnclosingSequence
-          case _ => Assert.invariantFailed("unable to compute position in nearest enclosing sequence")
+          case Some(ggd: GlobalGroupDef) => ggd.groupRef.asModelGroup.positionInNearestEnclosingSequence
+          case x => Assert.invariantFailed("For " + this + " unable to compute position in nearest enclosing sequence. The enclosingComponent was " + x)
         }
       }
     res
@@ -332,7 +286,7 @@ abstract class Term(xmlArg: Node, parentArg: SchemaComponent, val position: Int)
 
   final lazy val allSiblings: Seq[Term] = {
     val res = nearestEnclosingSequence.map { enc =>
-      val allSiblings = enc.groupMembers.map { _.referredToComponent }
+      val allSiblings = enc.groupMembers
       allSiblings
     }
     res.getOrElse(Nil)
@@ -420,17 +374,19 @@ abstract class Term(xmlArg: Node, parentArg: SchemaComponent, val position: Int)
   def isKnownRequiredElement = false
   def hasKnownRequiredSyntax = false
 
-  // Returns a tuple, where the first item in the tuple is the list of sibling
-  // terms that could appear before this. The second item in the tuple is a
-  // One(parent) if all siblings are optional or this element has no prior siblings
+  /**
+   * Returns a tuple, where the first item in the tuple is the list of sibling
+   * terms that could appear before this. The second item in the tuple is a
+   * One(parent) if all siblings are optional or this element has no prior siblings
+   */
   lazy val potentialPriorTerms: (Seq[Term], Option[Term]) = {
     val (potentialPrior, parent) = enclosingTerm match {
       case None => (Seq(), None)
       case Some(eb: ElementBase) => (Seq(), Some(eb))
-      case Some(ch: Choice) => (Seq(), Some(ch))
-      case Some(sq: Sequence) if !sq.isOrdered => (sq.groupMembersNoRefs, Some(sq))
-      case Some(sq: Sequence) if sq.isOrdered => {
-        val previousTerms = sq.groupMembersNoRefs.takeWhile { _ != this }
+      case Some(ch: ChoiceTermBase) => (Seq(), Some(ch))
+      case Some(sq: SequenceTermBase) if !sq.isOrdered => (sq.groupMembers, Some(sq))
+      case Some(sq: SequenceTermBase) if sq.isOrdered => {
+        val previousTerms = sq.groupMembers.takeWhile { _ != this }
         if (previousTerms.isEmpty) {
           // first child of seq, the seq is the only previous term
           (Seq(), Some(sq))
@@ -473,14 +429,18 @@ abstract class Term(xmlArg: Node, parentArg: SchemaComponent, val position: Int)
    */
   lazy val childrenInHiddenGroupNotDefaultableOrOVC: Seq[ElementBase] = {
     // this should only be called on hidden elements
-    Assert.invariant(this.isHidden)
+    val isH = isHidden
+    Assert.invariant(isH)
 
     val res = this match {
-      case s: Sequence => {
-        s.groupMembersNoRefs.flatMap { _.childrenInHiddenGroupNotDefaultableOrOVC }
+      case s: SequenceTermBase => {
+        s.groupMembers.flatMap { member =>
+          val res = member.childrenInHiddenGroupNotDefaultableOrOVC
+          res
+        }
       }
-      case c: Choice => {
-        val branches = c.groupMembersNoRefs.map { _.childrenInHiddenGroupNotDefaultableOrOVC }
+      case c: ChoiceTermBase => {
+        val branches = c.groupMembers.map { _.childrenInHiddenGroupNotDefaultableOrOVC }
         val countFullyDefaultableOrOVCBranches = branches.count { _.length == 0 }
         if (countFullyDefaultableOrOVCBranches == 0) {
           c.SDE("xs:choice inside a hidden group must contain a branch with all children having the dfdl:outputValueCalc property set.")
@@ -525,11 +485,226 @@ abstract class Term(xmlArg: Node, parentArg: SchemaComponent, val position: Int)
       case mg: ModelGroup => {
         val modelGroupCouldHaveSuspensions =
           commonCouldHaveSuspensions ||
-            mg.groupMembersNoRefs.exists { _.couldHaveSuspensions }
+            mg.groupMembers.exists { _.couldHaveSuspensions }
 
         modelGroupCouldHaveSuspensions
       }
     }
   }
 
+  final lazy val possibleNextTerms: Seq[Term] = LV('possibleNextTerms) {
+    val es = this.nearestEnclosingSequence
+    val eus = this.nearestEnclosingUnorderedSequenceBeforeSequence
+    val ec = this.nearestEnclosingChoiceBeforeSequence
+
+    val enclosingUnorderedGroup = {
+      (ec, eus) match {
+        case (None, None) => None
+        case (Some(choice), _) => Some(choice)
+        case (None, Some(uoSeq)) => Some(uoSeq)
+      }
+    }
+    val listOfNextTerm = (enclosingUnorderedGroup, es) match {
+      case (None, None) => Seq.empty
+      case (Some(unorderedGroup), _) => {
+        // We're in a choice or unordered sequence
+        //
+        // List must be all of our peers since (as well as our self)
+        // we could be followed by any of them plus
+        // whatever follows the unordered group.
+        val peersCouldBeNext = unorderedGroup.groupMembers
+
+        val termsUntilFirstRequiredTerm = peersCouldBeNext ++ unorderedGroup.possibleNextTerms
+        termsUntilFirstRequiredTerm
+      }
+      case (None, Some(oSeq)) => {
+        // We're in an ordered sequence
+
+        val termsUntilFirstRequiredTerm =
+          isDeclaredLastInSequence match {
+            case true => oSeq.possibleNextTerms
+            case false => {
+
+              val members = oSeq.groupMembers
+
+              val selfAndAfter = members.dropWhile(m => m ne this)
+              val after = selfAndAfter.drop(1)
+              val nextMember = after.headOption
+
+              val nextMembers =
+                nextMember match {
+                  case Some(e: ElementBase) if e.isOptional => Seq(e) ++ e.possibleNextTerms
+                  case Some(e: ElementBase) => Seq(e)
+                  case Some(mg: ModelGroup) => Seq(mg)
+                  case None => Nil // Assert.impossibleCase
+                }
+              nextMembers
+            }
+          }
+        termsUntilFirstRequiredTerm
+      }
+    }
+    listOfNextTerm
+  }.value
+
+  final def isDeclaredLastInSequence = LV('isDeclaredLastInSequence) {
+    val es = nearestEnclosingSequence
+    // how do we determine what child node we are? We search.
+    // TODO: better structure for O(1) answer to this.
+    es match {
+      case None => Assert.invariantFailed("We are not in a sequence therefore isDeclaredLastInSequence is an invalid question.")
+      case Some(s) => {
+        val members = s.groupMembers
+        if (members.last eq this) true // we want object identity comparison here, not equality.
+        else false
+      }
+    }
+  }.value
+
+  protected def possibleFirstChildTerms: Seq[Term]
+
+  /*
+   * Returns list of Elements that could be the first child in the infoset of this model group or element.
+   */
+  final def possibleFirstChildElementsInInfoset: Seq[ElementBase] = LV('possibleFirstChildElementsInInfoset) {
+    val pfct = possibleFirstChildTerms
+    val firstChildren = pfct.flatMap {
+      case e: ElementBase if e.isHidden => Nil
+      case e: ElementBase => Seq(e)
+      case s: SequenceTermBase if s.isHidden => Nil
+      case mg: ModelGroup => mg.possibleFirstChildElementsInInfoset
+    }
+    firstChildren.distinct
+  }.value
+
+  /*
+   * Returns a list of Elements that could follow this Term, including
+   * siblings, children of siblings, and siblings of the parent and their children.
+   *
+   * What stops this is when the end of an enclosing element has to be next.
+   */
+  final def possibleNextChildElementsInInfoset: Seq[ElementBase] = LV('possibleNextChildElementsInInfoset) {
+    val arrayNext = if (isArray) Seq(this.asInstanceOf[ElementBase]) else Nil
+
+    val nextSiblingElements = {
+      val poss = possibleNextSiblingTerms
+      val res = poss.flatMap {
+        possible =>
+          possible match {
+            case e: ElementBase => Seq(e)
+            case mg: ModelGroup => mg.possibleFirstChildElementsInInfoset
+          }
+      }
+      res
+    }
+
+    val nextParentElts = nextParentElements
+    val res = arrayNext ++ nextSiblingElements ++ nextParentElts
+    res
+  }.value
+
+  def nextParentElements: Seq[ElementBase]
+
+  protected def couldBeLastElementInModelGroup: Boolean
+
+  /*
+   * Returns a list of sibling Terms that could follow this term. This will not
+   * return any children of sibling Terms, or any siblings of the parent.
+   */
+  final def possibleNextSiblingTerms: Seq[Term] = LV('possibleNextSiblingTerms) {
+    val et = enclosingTerm
+    val listOfNextTerm = et match {
+      case None => Nil // root element, has no siblings
+      case Some(e: ElementBase) => Nil // complex element, cannot have another model group other than this one
+      case Some(c: ChoiceTermBase) => Nil // in choice, no other siblings could come after this one
+      case Some(s: SequenceTermBase) if !s.isOrdered => s.groupMembers // unorderd sequence, all siblings (and myself) could be next
+      case Some(s: SequenceTermBase) => {
+        // in a sequence, the next term could be any later sibling that is not
+        // or does not have a required element, up to and including the first
+        // term that is/has a required element
+        //        def isOutputValueCalc(term: Term) =
+        //          term match { case eb: ElementBase if eb.isOutputValueCalc => true; case _ => false }
+        val selfAndAllNextSiblings = s.groupMembers.dropWhile(_ != this)
+        val allNextSiblings = if (selfAndAllNextSiblings.length > 0) selfAndAllNextSiblings.tail else Nil
+        val nextSiblings = allNextSiblings // .dropWhile(isOutputValueCalc(_))
+        val (optional, firstRequiredAndLater) = nextSiblings.span {
+          case e: ElementBase => e.canBeAbsentFromUnparseInfoset
+          case mg: ModelGroup => !mg.mustHaveRequiredElement
+        }
+        optional ++ firstRequiredAndLater.take(1)
+      }
+    }
+    listOfNextTerm
+  }.value
+
+  /**
+   * Set of elements referenced from an expression in the scope of this term.
+   *
+   * Specific to certain function call contexts e.g., only elements referenced
+   * by dfdl:valueLength or dfdl:contentLength.
+   *
+   * Separated by parser/unparser since parsers have to derive from
+   * dfdl:inputValueCalc, and must include discriminators and assert test
+   * expressions. Unparsers must derive from dfdl:outputValueCalc and exclude
+   * discriminators and asserts. Both must include setVariable/newVariableInstance,
+   * and property expressions are nearly the same. There are some unparser-specfic
+   * properties that take runtime-valued expressions - dfdl:outputNewLine is
+   * one example.
+   */
+  final lazy val contentLengthParserReferencedElementInfos: Set[DPathElementCompileInfo] = {
+    val propRefs = propertyContentReferencedElementInfos
+    val stmtRefs = statementContentParserReferencedElementInfos
+    val calcRefs = calcContentParserReferencedElementInfos
+    val locRefs = propRefs ++ stmtRefs ++ calcRefs
+    val res = realChildren.foldLeft(locRefs) { (s, i) => s.union(i.contentLengthParserReferencedElementInfos) }
+    res
+  }
+
+  /**
+   * Any element referenced from an expression in the scope of this term
+   * is in this set.
+   */
+  final lazy val contentLengthUnparserReferencedElementInfos: Set[DPathElementCompileInfo] = {
+    val propRefs = propertyContentReferencedElementInfos
+    val stmtRefs = statementContentUnparserReferencedElementInfos
+    val calcRefs = calcContentUnparserReferencedElementInfos
+    val locRefs = propRefs ++ stmtRefs ++ calcRefs
+    val res = realChildren.foldLeft(locRefs) { (s, i) => s.union(i.contentLengthUnparserReferencedElementInfos) }
+    res
+  }
+
+  /**
+   * Any element referenced from an expression in the scope of this term
+   * is in this set.
+   */
+  final lazy val valueLengthParserReferencedElementInfos: Set[DPathElementCompileInfo] = {
+    val propRefs = propertyValueReferencedElementInfos
+    val stmtRefs = statementValueParserReferencedElementInfos
+    val calcRefs = calcValueParserReferencedElementInfos
+    val locRefs = propRefs ++ stmtRefs ++ calcRefs
+    val res = realChildren.foldLeft(locRefs) { (s, i) => s.union(i.valueLengthParserReferencedElementInfos) }
+    res
+  }
+
+  /**
+   * Any element referenced from an expression in the scope of this term
+   * is in this set.
+   */
+  final lazy val valueLengthUnparserReferencedElementInfos: Set[DPathElementCompileInfo] = {
+    val propRefs = propertyValueReferencedElementInfos
+    val stmtRefs = statementValueUnparserReferencedElementInfos
+    val calcRefs = calcValueUnparserReferencedElementInfos
+    val locRefs = propRefs ++ stmtRefs ++ calcRefs
+    val res = realChildren.foldLeft(locRefs) { (s, i) => s.union(i.valueLengthUnparserReferencedElementInfos) }
+    res
+  }
+
+  private lazy val realChildren: Seq[Term] = {
+    this match {
+      case mg: ModelGroup => mg.groupMembers.asInstanceOf[Seq[Term]]
+      case eb: ElementBase if (eb.isComplexType) => Seq(eb.complexType.group)
+      case eb: ElementBase => Seq()
+    }
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/TermEncodingMixin.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/TermEncodingMixin.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/TermEncodingMixin.scala
index bdb55a7..4dd1f96 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/TermEncodingMixin.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/TermEncodingMixin.scala
@@ -38,6 +38,11 @@ import edu.illinois.ncsa.daffodil.schema.annotation.props.gen.EncodingErrorPolic
 import edu.illinois.ncsa.daffodil.processors.KnownEncodingMixin
 import edu.illinois.ncsa.daffodil.io.NonByteSizeCharset
 
+/**
+ * Captures concepts around dfdl:encoding property and Terms.
+ *
+ * Just factored out into a trait for isolation of related code.
+ */
 trait TermEncodingMixin extends KnownEncodingMixin { self: Term =>
 
   requiredEvaluations(encodingInfo.preSerialization)
@@ -114,9 +119,6 @@ trait TermEncodingMixin extends KnownEncodingMixin { self: Term =>
         mg.hasNoSkipRegions &&
           hasTextAlignment
       }
-      case gr: GroupRef => {
-        gr.group.isLocallyTextOnly
-      }
     }
     res
   }

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/package.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/package.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/package.scala
new file mode 100644
index 0000000..4391be1
--- /dev/null
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/dsom/package.scala
@@ -0,0 +1,101 @@
+package edu.illinois.ncsa.daffodil
+
+/**
+ * DSOM - DFDL Schema Object Model
+ *
+ * ==Overview==
+ * DSOM is the abstract syntax "tree" of a DFDL schema. It is not actually a tree, it is
+ * a graph, as there are back-pointers, and shared objects.
+ *
+ * A schema is made up of [[SchemaComponent]] objects. A [[SchemaSet]] is a collection of
+ * [[Schema]]. A schema is a collection of [[SchemaDocument]] that have a common
+ * namespace. The [[SchemaSet]] is the
+ * ultimate root of all the objects in a compilation unit. The [[Term]] class is the
+ * base for everything that can have a representation in the data stream. .
+ *
+ * Many [[SchemaComponent]] carry DFDL annotations; hence, [[AnnotatedSchemaComponent]]
+ * is a key base trait.
+ *
+ * ==UML Class Diagram==
+ *
+ * See the
+ * [[https://cwiki.apache.org/confluence/display/DAFFODIL/DFDL+Schema+Object+Model+%28DSOM%29+with+UML
+ * Daffodil Wiki]]
+ * for class diagrams.
+ *
+ * ==Terminology==
+ *
+ * Parsing - in this description we are talking about the Daffodil Schema Compiler.
+ * So when we refer to "parsing" the XML, we are referring
+ * to the recursive descent walk of the DFDL schema, with that schema represented as Scala's
+ * `scala.xml.Node` objects. Strictly speaking, the string text in files of the DFDL
+ * schema's XML is already parsed into Scala's `scala.xml.Node` objects, but
+ * it is the walk through that structure constructing the DSOM tree/graph that we
+ * refer to as "parsing" the DFDL schema.
+ *
+ * ==Principles of Operation==
+ *
+ * === Constructing the DSOM Graph===
+ *
+ * The DSOM object graph must be constructed by looking at only the XML without
+ * examining any DFDL annotations. The DSOM structure is required in order to
+ * implement DFDL's scoping rules for finding annotations including both
+ * properties (like dfdl:byteOrder) and statements (like dfdl:assert); hence,
+ * one must have the DSOM graph before one can begin
+ * accessing DFDL annotations or you end up in cycles/stack-overflows.
+ *
+ * This requires a careful consideration of class/trait members and methods that
+ * are used when constructing the DSOM graph, and those used after the DSOM
+ * graph has been created, in order to compile it into the runtime data structures.
+ *
+ * There are a few exceptions to the above. The dfdl:hiddenGroupRef attribute is one such. It
+ * must be local to the [[Sequence]] object, and has implications for the parsing
+ * of the XML as it implies there should be no children of that xs:sequence.
+ * Since it is not scoped, the DSOM graph is not needed in order to access it.
+ * Only the local [[Sequence]] object and it's [[DFDLSequence]] annotation object.
+ * The [[AnnotatedSchemaComponent]] trait provides methods for this local-only
+ * property lookup.
+ *
+ * The DSOM object graph is also needed in order to issue good diagnostic
+ * messages from the compiler; hence, Daffodil validates the DFDL schema before
+ * parsing it into the DSOM graph. Careful consideration must be given if a
+ * SchemaDefinitionError (SDE) is issued while constructing the DSOM graph.
+ *
+ * If you run into stack-overflows while the DSOM graph is being constructed, the
+ * above is a common cause of them, as the SDE diagnostic messaging uses DSOM graph
+ * information to construct context information about the error for inclusion
+ * in the messages. If the DSOM graph is still being constructed at that time, then
+ * this can be circular.
+ *
+ * ===Using the DSOM Graph===
+ *
+ * DSOM supports Daffodil schema compilation by way of the
+ * `OOLAG` pattern which
+ * is an object oriented way of using the
+ * [[https://en.wikipedia.org/wiki/Attribute_grammar attribute grammars]] compiler technique.
+ *
+ * Many attributes (in the attribute grammar sense, nothing to do with XML attributes)
+ * are simply Scala lazy val definitions, but some are declared as OOLAG
+ * attributes (using `edu.illinois.ncsa.daffodil.oolag.OOLAG.OOLAGHost.LV`) which
+ * provides for gathering of multiple diagnostic messages (`SchemaDefinitionError`)
+ * before abandoning compilation.
+ *
+ * DFDL schema compilation largely occurs by evaluating lazy val members of DSOM
+ * objects. These include the members of the grammar traits
+ * (@see [[edu.illinois.ncsa.daffodil.grammar]] package), which are mixed
+ * in to the appropriate DSOM traits/classes.
+ *
+ * ===FAQ===
+ * Q: Why invent this? Why not use XSOM, or the Apache XML Schema library?
+ *
+ * A:We had trouble with other XML-schema libraries for
+ * lack of adequate support for annotations, non-native attributes, and schema
+ * documents as first class objects. So DSOM is specific to Daffodil Basically these
+ * libraries are more about implementing XML Schema and validation, and not so
+ * much about a complex language built on the annotations of the schema. DSOM
+ * is really mostly about the annotations.
+ *
+ */
+package object dsom {
+  // This package object is just for scaladoc
+}

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/AlignedMixin.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/AlignedMixin.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/AlignedMixin.scala
index 08bfa01..eba81ac 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/AlignedMixin.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/AlignedMixin.scala
@@ -40,8 +40,7 @@ import edu.illinois.ncsa.daffodil.schema.annotation.props.gen.LengthKind
 import edu.illinois.ncsa.daffodil.schema.annotation.props.gen.LengthUnits
 import edu.illinois.ncsa.daffodil.util.Math
 import edu.illinois.ncsa.daffodil.io.NonByteSizeCharset
-
-
+import edu.illinois.ncsa.daffodil.dsom.Root
 
 case class AlignmentMultipleOf(nBits: Long) {
   def *(that: AlignmentMultipleOf) = AlignmentMultipleOf(Math.gcd(nBits, that.nBits))
@@ -53,14 +52,12 @@ trait LengthApprox {
   val nBits: Long
   def +(that: LengthApprox): LengthApprox = (this, that) match {
     case (l: LengthExact, r: LengthExact) => LengthExact(l.nBits + r.nBits)
-    case (l, r) =>  LengthMultipleOf(Math.gcd(l.nBits, r.nBits))
+    case (l, r) => LengthMultipleOf(Math.gcd(l.nBits, r.nBits))
   }
 }
 case class LengthExact(nBits: Long) extends LengthApprox
 case class LengthMultipleOf(nBits: Long) extends LengthApprox
 
-
-
 trait AlignedMixin extends GrammarMixin { self: Term =>
 
   /**
@@ -84,7 +81,7 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
         true
       else
         false
-    } else if (this.rootElement.get.isScannable)
+    } else if (this.rootElementRef.get.isScannable)
       true
     else
       false
@@ -98,7 +95,7 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
         true
       else
         false
-    } else if (this.rootElement.get.isScannable)
+    } else if (this.rootElementRef.get.isScannable)
       true
     else
       false
@@ -106,7 +103,6 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
 
   final lazy val hasNoSkipRegions = leadingSkip == 0 && trailingSkip == 0
 
-
   private lazy val alignmentApprox: AlignmentMultipleOf = {
     AlignmentMultipleOf(alignmentValueInBits.toLong)
   }
@@ -134,7 +130,7 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
   }
 
   private lazy val priorAlignmentApprox: AlignmentMultipleOf = {
-    if (enclosingComponent.isEmpty) {
+    if (this.isInstanceOf[Root]) {
       AlignmentMultipleOf(0) // root is aligned with anything
     } else {
       val (priorSibs, parent) = potentialPriorTerms
@@ -175,7 +171,7 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
         } else {
           Seq()
         }
-          
+
       val priorAlignmentsApprox = priorSibs.map(_.endingAlignmentApprox) ++ parent.map(_.contentStartAlignment).toSeq ++ arraySelfAlignment
       priorAlignmentsApprox.reduce(_ * _)
     }
@@ -233,8 +229,7 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
                 // multiple of 8
                 LengthMultipleOf(8)
               }
-            }
-            else eb.lengthUnits match {
+            } else eb.lengthUnits match {
               case LengthUnits.Bits => LengthMultipleOf(1)
               case LengthUnits.Bytes => LengthMultipleOf(8)
               case LengthUnits.Characters => encodingLengthApprox
@@ -242,8 +237,8 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
           }
           case LengthKind.Delimited => encodingLengthApprox
           case LengthKind.Pattern => encodingLengthApprox
-          case LengthKind.EndOfParent => LengthMultipleOf(1)// NYI
-          case LengthKind.Prefixed => LengthMultipleOf(1)// NYI
+          case LengthKind.EndOfParent => LengthMultipleOf(1) // NYI
+          case LengthKind.Prefixed => LengthMultipleOf(1) // NYI
         }
       }
     }
@@ -266,10 +261,10 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
       val isSkipRegionByteLength = (leadingSkipInBits % 8 == 0) && (trailingSkipInBits % 8 == 0)
 
       val isByteLength = this match {
-        case mg: ModelGroup => mg.groupMembersNoRefs.forall { _.isKnownToBeByteAlignedAndByteLength }
+        case mg: ModelGroup => mg.groupMembers.forall { _.isKnownToBeByteAlignedAndByteLength }
         case eb: ElementBase => {
           val isSelfByteSizeEncoding = eb.charsetEv.optConstant.map { !_.charset.isInstanceOf[NonByteSizeCharset] }.getOrElse(false)
-          val isSelfByteLength = 
+          val isSelfByteLength =
             if (eb.isComplexType && eb.lengthKind == LengthKind.Implicit) {
               eb.complexType.group.isKnownToBeByteAlignedAndByteLength
             } else {

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ChoiceGrammarMixin.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ChoiceGrammarMixin.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ChoiceGrammarMixin.scala
index 55e8986..5309307 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ChoiceGrammarMixin.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ChoiceGrammarMixin.scala
@@ -32,10 +32,10 @@
 
 package edu.illinois.ncsa.daffodil.grammar
 
-import edu.illinois.ncsa.daffodil.dsom.Choice
+import edu.illinois.ncsa.daffodil.dsom.ChoiceTermBase
 import edu.illinois.ncsa.daffodil.grammar.primitives.ChoiceCombinator
 
-trait ChoiceGrammarMixin extends GrammarMixin { self: Choice =>
+trait ChoiceGrammarMixin extends GrammarMixin { self: ChoiceTermBase =>
 
   override lazy val groupContent = prod("choiceContent") {
     ChoiceCombinator(this, alternatives)

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ElementBaseGrammarMixin.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ElementBaseGrammarMixin.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ElementBaseGrammarMixin.scala
index a5f3f2f..1bc9909 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ElementBaseGrammarMixin.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ElementBaseGrammarMixin.scala
@@ -37,7 +37,6 @@ import edu.illinois.ncsa.daffodil.processors._
 import edu.illinois.ncsa.daffodil.schema.annotation.props.gen._
 import edu.illinois.ncsa.daffodil.dpath.NodeInfo.PrimType
 import edu.illinois.ncsa.daffodil.dsom.InitiatedTerminatedMixin
-import edu.illinois.ncsa.daffodil.dsom.SimpleTypeBase
 import edu.illinois.ncsa.daffodil.dsom.ElementBase
 import java.lang.{ Long => JLong }
 import edu.illinois.ncsa.daffodil.dpath.NodeInfo
@@ -414,7 +413,7 @@ trait ElementBaseGrammarMixin
   protected lazy val elementUnused = new ElementUnused(context)
 
   /**
-   * provided by LocalElementBase for array considerations, and GlobalElementDecl - scalar only
+   * provided by ElementBase for array considerations, and GlobalElementDecl - scalar only
    */
   protected def allowedValue: Gram
   //
@@ -657,11 +656,7 @@ trait ElementBaseGrammarMixin
     ConvertTextCombinator(this, stringValue, ConvertTextBooleanPrim(this))
   }
 
-  // shorthand
-  final lazy val primType = {
-    val res = typeDef.asInstanceOf[SimpleTypeBase].primType
-    res
-  }
+  def primType: PrimType
 
   protected final lazy val value = prod("value", isSimpleType) {
     // TODO: Consider issues with matching a stopValue. Can't say isScalar here because
@@ -1025,7 +1020,7 @@ trait ElementBaseGrammarMixin
 
   private lazy val elementRightFraming = prod("elementRightFraming") { TrailingSkipRegion(this) }
 
-  protected final lazy val enclosedElement = prod("enclosedElement") {
+  protected lazy val enclosedElement = prod("enclosedElement") {
     //
     // not isScalar, because this is reused inside arrays
     // that is, we're counting on reusuing this production for array elements

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ElementDeclGrammarMixin.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ElementDeclGrammarMixin.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ElementDeclGrammarMixin.scala
index 31ad470..0ae7f8e 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ElementDeclGrammarMixin.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ElementDeclGrammarMixin.scala
@@ -33,11 +33,11 @@
 package edu.illinois.ncsa.daffodil.grammar
 
 import edu.illinois.ncsa.daffodil.grammar.primitives.UnicodeByteOrderMark
-import edu.illinois.ncsa.daffodil.dsom.GlobalElementDecl
+import edu.illinois.ncsa.daffodil.dsom.Root
 
-trait GlobalElementDeclGrammarMixin
+trait RootGrammarMixin
   extends LocalElementGrammarMixin // can be repeating if not root
-  { self: GlobalElementDecl =>
+  { self: Root =>
 
   final lazy val document = prod("document") {
     schemaDefinitionUnless(isScalar, "The document element cannot be an array.")
@@ -45,4 +45,5 @@ trait GlobalElementDeclGrammarMixin
   }
 
   private def documentElement = enclosedElement
+
 }

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ElementReferenceGrammarMixin.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ElementReferenceGrammarMixin.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ElementReferenceGrammarMixin.scala
index beb84be..71c2659 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ElementReferenceGrammarMixin.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ElementReferenceGrammarMixin.scala
@@ -32,10 +32,8 @@
 
 package edu.illinois.ncsa.daffodil.grammar
 
-import edu.illinois.ncsa.daffodil.dsom.ElementRef
+import edu.illinois.ncsa.daffodil.dsom.AbstractElementRef
 
-trait ElementReferenceGrammarMixin { self: ElementRef =>
-
-  final override lazy val termContentBody = self.referencedElement.termContentBody
+trait ElementReferenceGrammarMixin { self: AbstractElementRef =>
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/Grammar.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/Grammar.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/Grammar.scala
index e1d43b8..e123489 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/Grammar.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/Grammar.scala
@@ -120,7 +120,17 @@ class SeqComp private (context: SchemaComponent, children: Seq[Gram]) extends Bi
     else new SeqCompParser(context.runtimeData, parserChildren.toArray)
   }
 
-  lazy val unparserChildren = children.filter(x => !x.isEmpty && (x.forWhat != ForParser)).map { _.unparser }.filterNot { _.isInstanceOf[NadaUnparser] }
+  lazy val unparserChildren = {
+    val unparserKeptChildren =
+      children.filter(
+        x =>
+          !x.isEmpty && (x.forWhat != ForParser))
+    val unparsers =
+      unparserKeptChildren.map { x =>
+        x.unparser
+      }.filterNot { _.isInstanceOf[NadaUnparser] }
+    unparsers
+  }
 
   final override lazy val unparser = {
     if (unparserChildren.isEmpty) new NadaUnparser(context.runtimeData)

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/GrammarMixins.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/GrammarMixins.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/GrammarMixins.scala
index 5cf6e96..f8afb1e 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/GrammarMixins.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/GrammarMixins.scala
@@ -37,8 +37,6 @@ import edu.illinois.ncsa.daffodil.grammar.primitives.ComplexTypeCombinator
 
 trait GroupRefGrammarMixin extends GrammarMixin { self: GroupRef =>
 
-  override lazy val termContentBody = self.group.termContentBody
-
 }
 
 /////////////////////////////////////////////////////////////////
@@ -50,6 +48,6 @@ trait ComplexTypeBaseGrammarMixin extends GrammarMixin { self: ComplexTypeBase =
   override protected final def grammarContext = this
 
   lazy val mainGrammar = prod("mainGrammar") {
-    ComplexTypeCombinator(this, modelGroup.group.asChildOfComplexType)
+    ComplexTypeCombinator(this, group.asChildOfComplexType)
   }
 }

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/GrammarTerm.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/GrammarTerm.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/GrammarTerm.scala
index 374606d..ca1aa63 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/GrammarTerm.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/GrammarTerm.scala
@@ -37,7 +37,7 @@ import edu.illinois.ncsa.daffodil.processors.parsers.Parser
 import edu.illinois.ncsa.daffodil.processors.unparsers.Unparser
 import edu.illinois.ncsa.daffodil.grammar.primitives.Nada
 import edu.illinois.ncsa.daffodil.dsom.SchemaComponent
-import edu.illinois.ncsa.daffodil.oolag.OOLAG.OOLAGHost
+import edu.illinois.ncsa.daffodil.oolag.OOLAG.OOLAGHostImpl
 import edu.illinois.ncsa.daffodil.compiler.ParserOrUnparser
 import edu.illinois.ncsa.daffodil.util.Misc
 import edu.illinois.ncsa.daffodil.compiler.BothParserAndUnparser
@@ -55,7 +55,7 @@ trait HasNoUnparser {
  * because this one has to actually be operationalized.
  */
 abstract class Gram(contextArg: SchemaComponent)
-  extends OOLAGHost(contextArg) {
+  extends OOLAGHostImpl(contextArg) {
 
   final def SDE(str: String, args: Any*): Nothing = context.SDE(str, args: _*)
   final def SDW(str: String, args: Any*): Unit = context.SDW(str, args: _*)

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/HasStatementsGrammarMixin.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/HasStatementsGrammarMixin.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/HasStatementsGrammarMixin.scala
index dc1c6d2..03744c2 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/HasStatementsGrammarMixin.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/HasStatementsGrammarMixin.scala
@@ -32,10 +32,9 @@
 
 package edu.illinois.ncsa.daffodil.grammar
 
-import edu.illinois.ncsa.daffodil.dsom.DFDLStatementMixin
 import edu.illinois.ncsa.daffodil.dsom.Term
 
-trait HasStatementsGrammarMixin extends GrammarMixin { self: Term with DFDLStatementMixin =>
+trait HasStatementsGrammarMixin extends GrammarMixin { self: Term =>
 
   private lazy val statementGrams = statements.map { _.gram }
   // TODO: statements (but specifically not newVariableInstance) can appear on simple type definitions as well as terms.

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/LocalElementGrammarMixin.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/LocalElementGrammarMixin.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/LocalElementGrammarMixin.scala
index e3e412d..84a2db3 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/LocalElementGrammarMixin.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/LocalElementGrammarMixin.scala
@@ -33,7 +33,7 @@
 package edu.illinois.ncsa.daffodil.grammar
 import edu.illinois.ncsa.daffodil.schema.annotation.props._
 import edu.illinois.ncsa.daffodil.schema.annotation.props.gen._
-import edu.illinois.ncsa.daffodil.dsom.LocalElementBase
+import edu.illinois.ncsa.daffodil.dsom.ElementBase
 import edu.illinois.ncsa.daffodil.equality._; object ENoWarn2 { EqualitySuppressUnusedImportWarning() }
 import edu.illinois.ncsa.daffodil.grammar.primitives.StopValue
 import edu.illinois.ncsa.daffodil.grammar.primitives.NotStopValue
@@ -47,11 +47,8 @@ import edu.illinois.ncsa.daffodil.grammar.primitives.OccursCountExpression
 import edu.illinois.ncsa.daffodil.grammar.primitives.OptionalCombinator
 import edu.illinois.ncsa.daffodil.grammar.primitives.ArrayCombinator
 
-trait LocalElementGrammarMixin extends GrammarMixin { self: LocalElementBase =>
+trait LocalElementGrammarMixin extends GrammarMixin { self: ElementBase =>
 
-  /**
-   * further overridden in ElementRefGrammarMixin
-   */
   override lazy val termContentBody = prod("termContentBody") { // override in ElementRef
     (if (isScalar) enclosedElement else recurrance)
   }

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ModelGroupGrammarMixin.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ModelGroupGrammarMixin.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ModelGroupGrammarMixin.scala
index 1447d2c..66c8865 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ModelGroupGrammarMixin.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/ModelGroupGrammarMixin.scala
@@ -35,13 +35,13 @@ package edu.illinois.ncsa.daffodil.grammar
 import edu.illinois.ncsa.daffodil.schema.annotation.props.gen._
 import edu.illinois.ncsa.daffodil.dsom.InitiatedTerminatedMixin
 import edu.illinois.ncsa.daffodil.dsom.ModelGroup
-import edu.illinois.ncsa.daffodil.dsom.Sequence
-import edu.illinois.ncsa.daffodil.dsom.Choice
 import edu.illinois.ncsa.daffodil.grammar.primitives.TrailingSkipRegion
 import edu.illinois.ncsa.daffodil.grammar.primitives.LeadingSkipRegion
 import edu.illinois.ncsa.daffodil.grammar.primitives.AlignmentFill
 import edu.illinois.ncsa.daffodil.grammar.primitives.DelimiterStackCombinatorSequence
 import edu.illinois.ncsa.daffodil.grammar.primitives.DelimiterStackCombinatorChoice
+import edu.illinois.ncsa.daffodil.dsom.SequenceTermBase
+import edu.illinois.ncsa.daffodil.dsom.ChoiceTermBase
 
 trait ModelGroupGrammarMixin
   extends InitiatedTerminatedMixin
@@ -78,8 +78,8 @@ trait ModelGroupGrammarMixin
         ) {
         val content = initiatorRegion ~ groupContent ~ terminatorRegion
         self match {
-          case c: Choice => DelimiterStackCombinatorChoice(c, content)
-          case s: Sequence => DelimiterStackCombinatorSequence(s, content)
+          case c: ChoiceTermBase => DelimiterStackCombinatorChoice(c, content)
+          case s: SequenceTermBase => DelimiterStackCombinatorSequence(s, content)
         }
       } else { groupContent }
 

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/SequenceGrammarMixin.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/SequenceGrammarMixin.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/SequenceGrammarMixin.scala
index 5c6ac4e..383cf53 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/SequenceGrammarMixin.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/SequenceGrammarMixin.scala
@@ -32,10 +32,10 @@
 
 package edu.illinois.ncsa.daffodil.grammar
 import edu.illinois.ncsa.daffodil.schema.annotation.props.gen._
-import edu.illinois.ncsa.daffodil.dsom.Sequence
 import edu.illinois.ncsa.daffodil.grammar.primitives.SequenceCombinator
+import edu.illinois.ncsa.daffodil.dsom.SequenceTermBase
 
-trait SequenceGrammarMixin extends GrammarMixin { self: Sequence =>
+trait SequenceGrammarMixin extends GrammarMixin { self: SequenceTermBase =>
 
   final override lazy val groupContent = prod("groupContent") {
     self.sequenceKind match {

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/package.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/package.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/package.scala
new file mode 100644
index 0000000..0deae3a
--- /dev/null
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/package.scala
@@ -0,0 +1,104 @@
+package edu.illinois.ncsa.daffodil
+
+/**
+ * Grammar Mixins for Schema Compilation
+ *
+ * DFDL is defined using a data syntax grammar. Daffodil compiles a DFDL schema
+ * into runtime data structures using a technique that tries to be faithful to
+ * this notion of a data syntax grammar. The exact data syntax grammar used
+ * in the DFDL specification is not really suitable to base an implementation on,
+ * but where possible we have named the grammar production rules, and terminals of
+ * the grammar consistently with the DFDL specification.
+ *
+ * The grammar rules are members of the DSOM traits/classes that use a
+ * grammar notation, organized as grammar rules the applicability of which
+ * is controlled by boolean test guard expressions.
+ *
+ * In addition to the grammar rules, these mixins contain the methods that analzye
+ * the DFDL schema with its DFDL annotations, to determine whether the grammar
+ * rule is applicable. Most optimizations in the Daffodil schema compiler are
+ * implemented by way of a grammar rule or [[Terminal]] which is included or
+ * excluded (aka guarded) by an optimization.
+ *
+ * The grammar rule mixins all inherit from the [[Gram]] trait which provides
+ * operators for expressing the rules. The concrete classes are the
+ * terminals of the grammar (instances of [[Terminal]]) and these
+ * are either primitives or combinators. The primitves and combinators are
+ * defined in the [[edu.illinois.ncsa.daffodil.grammar.primitives]] package.
+ *
+ * This all works very much like Scala's `scala.util.parsing.combinator` library,
+ * which is described in the [[http://www.artima.com/pins1ed/ Programming in Scala]] book
+ * in the [[http://www.artima.com/pins1ed/combinator-parsing.html chapter on Combinator Parsing]].
+ * However, Daffodil's grammar adds the notion of rich predicate guards controlling
+ * the rules, and of course the result of the grammar is an entirely different
+ * data structure. But but the way rules are expressed and use of operators
+ * like "`~`" and "`||`" to create a little grammar composition language are similar.
+ *
+ * It is best to illustrate how the grammar works by an example drawn from model groups.
+ * This example no longer matches the code of the actual implementation, but
+ * illustrates the ideas behind the grammar:
+ * @example
+ * {{{
+ * trait ModelGroupMixin extends ... {
+ *
+ * lazy val modelGroup = groupLeftFraming ~ groupContent ~ groupRightFraming
+ *
+ * lazy val groupLeftFraming = LeadingSkipRegion(this) ~ AlignmentFill(this)
+ *
+ * lazy val groupRightFraming = TrailingSkipRegion(this)
+ * }
+ * }}}
+ * Non-terminals of the data syntax grammar are ordinary lazy val members named
+ * beginning with lower case letter. Terminals of the grammar are classes
+ * and so are named beginning with an upper case letter.
+ *
+ * A terminal like `LeadingSkipRegion` will optimize itself out by evaluating a
+ * guard predicate test. Basically, if the DFDL schema has a `dfdl:leadingSkip`
+ * property of '0', then the `LeadingSkipRegion` of the data syntax grammar is zero
+ * width, so this terminal defines itself so that the `isEmpty` method returns
+ * `true`. That enables the "`~`" operator to see that it has an empty grammar term
+ * on it's left, hence, the "`~`" operator can reduce to just the right grammar term.
+ *
+ * The right grammar term, `AlignmentFill`, requires a much more sophisticated
+ * analysis of the schema and properties, but ultimately could also decide that
+ * it is not needed, and so `isEmpty`. Then the "`~`" operator will see that both sides are
+ * empty and it itself is then empty. That allows the modelGroup rule to recognize that
+ * for this DFDL schema there is no `groupLeftFraming`.
+ *
+ * The net result of this is all the grammar regions that are not applicable disappear
+ * from the grammar. What is left is a nest of combinators and primitives suitable
+ * for this specific DFDL schema's runtime to be generated.
+ *
+ * Lazy evaluation and by-name argument passing insure that this occurs without
+ * evaluating any irrelevant grammar rules.
+ *
+ * At the end, the schema compiler generates a parser or unparser instance
+ * by "asking" the now-optimized grammar data structure for a parser or unparser.
+ * This means really by invoking the corresponding
+ * method (`parser()` or `unparser()`) on the grammar object.
+ * Recursively each combinator constructs an instance of
+ * a class that implements
+ * `edu.illinois.ncsa.daffodil.processors.parsers.Parser` (or
+ * `edu.illinois.ncsa.daffodil.processors.unparsers.Unparser`)
+ * and that instance recursively calls the parsers (or unparsers) generated
+ * from the parts of the grammar which did not optimize themselves away.
+ * Primitves construct atomic primitive parsers (and unparsers) for things like
+ * delimiters, alignment regions, or simple type values.
+ *
+ * ==Futures==
+ *
+ * Many grammar rules are defined as instances of the [[Prod]] class using the `prod` method.
+ * This is not strictly speaking needed (the example above doesn't use it), but is intended
+ * to define named extension points in the grammar for a future DFDL extension
+ * capability. The idea is that the named productions would be the places
+ * where external extensions to the grammar would be examined and utilized to
+ * augment the internal grammar rule definitions. These externally defined productions
+ * could then incorporate into the grammar, new externally defined primitives,
+ * or possibly even combinators, which ultimately generate calls to externally
+ * defined parser (or unparser) instances.
+ *
+ * Currently the use of `prod` is ad-hoc and haphazard.
+ */
+package object grammar {
+  // This object exists for scaladoc purposes.
+}

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/Primitives.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/Primitives.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/Primitives.scala
index fc3c2bc..7baaf30 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/Primitives.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/Primitives.scala
@@ -37,7 +37,7 @@ import edu.illinois.ncsa.daffodil.grammar.Terminal
 import edu.illinois.ncsa.daffodil.grammar.HasNoUnparser
 
 abstract class Primitive(e: Term, guard: Boolean = false)
-    extends Terminal(e, guard) {
+  extends Terminal(e, guard) {
   override def toString = "Prim[" + name + "]"
 }
 
@@ -45,14 +45,14 @@ abstract class Primitive(e: Term, guard: Boolean = false)
  * For stubbing out primitives that are placeholders
  */
 abstract class UnimplementedPrimitive(e: Term, guard: Boolean = false)
-    extends Primitive(e, guard)
-    with HasNoUnparser {
+  extends Primitive(e, guard)
+  with HasNoUnparser {
   override final lazy val parser = hasNoParser
 }
 
 // base stub classes
 
-case class NoValue(e: GlobalElementDecl, guard: Boolean = true) extends UnimplementedPrimitive(e, guard)
+// case class NoValue(e: GlobalElementDecl, guard: Boolean = true) extends UnimplementedPrimitive(e, guard)
 
 case class SaveInputStream(e: ElementBase, guard: Boolean = true) extends UnimplementedPrimitive(e, guard)
 
@@ -66,4 +66,4 @@ case class StopValue(e: ElementBase with LocalElementMixin) extends Unimplemente
 
 case class TheDefaultValue(e: ElementBase) extends UnimplementedPrimitive(e, e.isDefaultable)
 
-case class UnicodeByteOrderMark(e: GlobalElementDecl) extends UnimplementedPrimitive(e, false)
+case class UnicodeByteOrderMark(e: Root) extends UnimplementedPrimitive(e, false)

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesDelimiters.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesDelimiters.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesDelimiters.scala
index 0b16b6d..138f000 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesDelimiters.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesDelimiters.scala
@@ -172,7 +172,7 @@ case class Initiator(e: Term) extends DelimiterText(e, e) {
   Assert.invariant(e.hasInitiator)
   val delimiterType: DelimiterTextType.Type = DelimiterTextType.Initiator
 }
-case class Separator(s: Sequence, t: Term) extends DelimiterText(s, t) {
+case class Separator(s: SequenceTermBase, t: Term) extends DelimiterText(s, t) {
   Assert.invariant(s.hasSeparator)
   val delimiterType: DelimiterTextType.Type = DelimiterTextType.Separator
 }

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesElementKinds.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesElementKinds.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesElementKinds.scala
index 04459ae..b2a94ef 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesElementKinds.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesElementKinds.scala
@@ -62,7 +62,7 @@ import edu.illinois.ncsa.daffodil.cookers.ChoiceBranchKeyCooker
 
 object ENoWarn3 { EqualitySuppressUnusedImportWarning() }
 
-case class DelimiterStackCombinatorSequence(sq: Sequence, body: Gram) extends Terminal(sq, !body.isEmpty) {
+case class DelimiterStackCombinatorSequence(sq: SequenceTermBase, body: Gram) extends Terminal(sq, !body.isEmpty) {
   lazy val pInit = if (sq.initiatorParseEv.isKnownNonEmpty) One(sq.initiatorParseEv) else Nope
   lazy val pSep = if (sq.separatorParseEv.isKnownNonEmpty) One(sq.separatorParseEv) else Nope
   lazy val pTerm = if (sq.terminatorParseEv.isKnownNonEmpty) One(sq.terminatorParseEv) else Nope
@@ -76,7 +76,7 @@ case class DelimiterStackCombinatorSequence(sq: Sequence, body: Gram) extends Te
   override lazy val unparser: DaffodilUnparser = new DelimiterStackUnparser(uInit, uSep, uTerm, sq.runtimeData, body.unparser)
 }
 
-case class DelimiterStackCombinatorChoice(ch: Choice, body: Gram) extends Terminal(ch, !body.isEmpty) {
+case class DelimiterStackCombinatorChoice(ch: ChoiceTermBase, body: Gram) extends Terminal(ch, !body.isEmpty) {
   lazy val pInit = if (ch.initiatorParseEv.isKnownNonEmpty) One(ch.initiatorParseEv) else Nope
   lazy val pTerm = if (ch.terminatorParseEv.isKnownNonEmpty) One(ch.terminatorParseEv) else Nope
 
@@ -113,7 +113,7 @@ case class DynamicEscapeSchemeCombinatorElement(e: ElementBase, body: Gram) exte
   override lazy val unparser: DaffodilUnparser = new DynamicEscapeSchemeUnparser(schemeUnparseOpt.get, e.runtimeData, body.unparser)
 }
 
-case class ComplexTypeCombinator(ct: ComplexTypeBase, body: Gram) extends Terminal(ct.element, !body.isEmpty) {
+case class ComplexTypeCombinator(ct: ComplexTypeBase, body: Gram) extends Terminal(ct.elementDecl, !body.isEmpty) {
 
   override def isEmpty = body.isEmpty
 
@@ -123,13 +123,24 @@ case class ComplexTypeCombinator(ct: ComplexTypeBase, body: Gram) extends Termin
     new ComplexTypeUnparser(ct.runtimeData, body.unparser)
 }
 
-case class SequenceCombinator(sq: Sequence, rawTerms: Seq[Gram])
-  extends Terminal(sq, !rawTerms.filterNot { _.isEmpty }.isEmpty) {
+case class SequenceCombinator(sq: SequenceTermBase, rawTerms: Seq[Gram])
+  extends Terminal(sq, true) {
+
+  override lazy val isEmpty = {
+    val rt = rawTerms
+    val frt = rt.filterNot { _.isEmpty }
+    val res = frt.isEmpty
+    res
+  }
 
   private val mt: Gram = EmptyGram
   lazy val body = rawTerms.foldRight(mt) { _ ~ _ }
+
   lazy val terms = rawTerms.filterNot { _.isEmpty }
-  lazy val unparsers = terms.map { _.unparser }.toVector
+
+  lazy val unparsers = terms.map { term =>
+    term.unparser
+  }.toVector
 
   lazy val parser: DaffodilParser = new SequenceCombinatorParser(sq.termRuntimeData, body.parser)
 
@@ -167,7 +178,7 @@ case class OptionalCombinator(e: ElementBase, body: Gram) extends Terminal(e, !b
  * need to determine which branch of the choice to take at runtime. This
  * unparser uses a Map to make the determination based on the element seen.
  */
-case class ChoiceCombinator(ch: Choice, alternatives: Seq[Gram]) extends Terminal(ch, !alternatives.isEmpty) {
+case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: Seq[Gram]) extends Terminal(ch, !alternatives.isEmpty) {
   lazy val parser: DaffodilParser = {
     if (!ch.isDirectDispatch) {
       val folded = alternatives.map { gf => gf }.foldRight(EmptyGram.asInstanceOf[Gram]) { _ | _ }
@@ -224,7 +235,7 @@ case class ChoiceCombinator(ch: Choice, alternatives: Seq[Gram]) extends Termina
       // this call is necessary since it will throw an SDE if no choice branch
       // was defaultable
       ch.childrenInHiddenGroupNotDefaultableOrOVC
-      val defaultableBranches = ch.groupMembersNoRefs.filter { _.childrenInHiddenGroupNotDefaultableOrOVC.length == 0 }
+      val defaultableBranches = ch.groupMembers.filter { _.childrenInHiddenGroupNotDefaultableOrOVC.length == 0 }
       Assert.invariant(defaultableBranches.length > 0)
       if (defaultableBranches.length > 1) {
         SDW("xs:choice inside a hidden group has unparse ambiguity: multiple branches exist with all children either defaulable or have the dfdl:outputValueCalc property set. The first branch will be chosen during unparse. Defaultable branches are:\n%s",

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesExpressions.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesExpressions.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesExpressions.scala
index 36d0d14..db992a5 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesExpressions.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesExpressions.scala
@@ -270,7 +270,7 @@ case class InputValueCalc(e: ElementBase,
 //  }
 //}
 
-abstract class AssertPatternPrimBase(decl: AnnotatedSchemaComponent, stmt: DFDLAssertionBase)
+abstract class AssertPatternPrimBase(decl: Term, stmt: DFDLAssertionBase)
   extends Terminal(decl, true) {
 
   lazy val eName = decl.diagnosticDebugName
@@ -286,22 +286,22 @@ abstract class AssertPatternPrimBase(decl: AnnotatedSchemaComponent, stmt: DFDLA
   override def unparser: DaffodilUnparser = Assert.invariantFailed("should not request unparser for asserts/discriminators")
 }
 
-case class AssertPatternPrim(decl: AnnotatedSchemaComponent, stmt: DFDLAssert)
-  extends AssertPatternPrimBase(decl, stmt) {
+case class AssertPatternPrim(term: Term, stmt: DFDLAssert)
+  extends AssertPatternPrimBase(term, stmt) {
 
   val kindString = "AssertPatternPrim"
 
   lazy val parser: DaffodilParser = {
-    new AssertPatternParser(eName, kindString, decl.term.termRuntimeData, testPattern, stmt.message)
+    new AssertPatternParser(eName, kindString, term.termRuntimeData, testPattern, stmt.message)
   }
 
 }
 
-case class DiscriminatorPatternPrim(decl: AnnotatedSchemaComponent, stmt: DFDLAssertionBase)
-  extends AssertPatternPrimBase(decl, stmt) {
+case class DiscriminatorPatternPrim(term: Term, stmt: DFDLAssertionBase)
+  extends AssertPatternPrimBase(term, stmt) {
 
   val kindString = "DiscriminatorPatternPrim"
 
-  lazy val parser: DaffodilParser = new DiscriminatorPatternParser(testPattern, eName, kindString, decl.term.termRuntimeData, stmt.message)
+  lazy val parser: DaffodilParser = new DiscriminatorPatternParser(testPattern, eName, kindString, term.termRuntimeData, stmt.message)
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-daffodil/blob/89517717/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesUnorderedSequence.scala
----------------------------------------------------------------------
diff --git a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesUnorderedSequence.scala b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesUnorderedSequence.scala
index 9f4f22a..469a453 100644
--- a/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesUnorderedSequence.scala
+++ b/daffodil-core/src/main/scala/edu/illinois/ncsa/daffodil/grammar/primitives/PrimitivesUnorderedSequence.scala
@@ -36,7 +36,7 @@ import edu.illinois.ncsa.daffodil.grammar.Gram
 import edu.illinois.ncsa.daffodil.exceptions.Assert
 import edu.illinois.ncsa.daffodil.dsom.ElementBase
 import edu.illinois.ncsa.daffodil.dsom.Term
-import edu.illinois.ncsa.daffodil.dsom.Sequence
+import edu.illinois.ncsa.daffodil.dsom.SequenceTermBase
 import edu.illinois.ncsa.daffodil.grammar.UnaryGram
 import edu.illinois.ncsa.daffodil.grammar.HasNoUnparser
 import edu.illinois.ncsa.daffodil.processors.ElementRuntimeData
@@ -47,15 +47,15 @@ object UnorderedSequence {
     // mandatory little optimization here. If there are no statements (most common case), then let's
     // shortcut and just use the guts parser.
 
-    Assert.usageErrorUnless(context.isInstanceOf[Sequence], "The context passed to UnorderedSequence must be a Sequence.")
+    Assert.usageErrorUnless(context.isInstanceOf[SequenceTermBase], "The context passed to UnorderedSequence must be a Sequence.")
 
-    val ctxt = context.asInstanceOf[Sequence]
+    val ctxt = context.asInstanceOf[SequenceTermBase]
 
     new UnorderedSequence(ctxt, eGram)
   }
 }
 
-class UnorderedSequence private (context: Sequence, eGramArg: => Gram) // private to force use of the object as factory
+class UnorderedSequence private (context: SequenceTermBase, eGramArg: => Gram) // private to force use of the object as factory
   extends UnaryGram(context, eGramArg) with HasNoUnparser {
 
   lazy val eGram = eGramArg // once only
@@ -67,7 +67,7 @@ class UnorderedSequence private (context: Sequence, eGramArg: => Gram) // privat
   val sortOrder = {
     val members = context.groupMembers.map(t => {
       t match {
-        case s: Sequence => s.groupMembers
+        case s: SequenceTermBase => s.groupMembers
         case _ => Seq(t)
       }
     }).flatten