daffodil-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From GitBox <...@apache.org>
Subject [GitHub] [incubator-daffodil] mbeckerle commented on a change in pull request #289: Daffodil 2192 warnings - nextElementResolver rewrite
Date Fri, 22 Nov 2019 00:28:33 GMT
mbeckerle commented on a change in pull request #289: Daffodil 2192 warnings - nextElementResolver
rewrite
URL: https://github.com/apache/incubator-daffodil/pull/289#discussion_r349384663
 
 

 ##########
 File path: daffodil-core/src/main/scala/org/apache/daffodil/dsom/Term.scala
 ##########
 @@ -789,6 +811,183 @@ trait Term
     res
   }.value
 
+  /*
+   * Returns a Closed or Open list of posslble elements that could follow this Term, within
its
+   * lexically enclosing model group.
+   *
+   * Does not follow backpointers from group defs to group refs.
+   *
+   * It is ok, and has no negative impact on sharing for a Term to reference
+   * its lexically enclosing model group.
+   *
+   * Within the lexically enclosing model group, if that group is a sequence, then
+   * this computation involves subsequent siblings, children of those siblings.
+   */
+
+  lazy val possibleNextLexicalSiblingStreamingUnparserElements: PossibleNextElements = {
+    val res = this match {
+      // Quasi elements are used for type-value calc, and for prefixed lengths
+      // we never consider them for streaming unparsing. They are never present as events.
+      // Nor should they ever be used as the source of next-event information.
+      case qe: QuasiElementDeclBase =>
+        DoNotUse // never resolve siblings. These shouldn't pull unparser events ever
+      //
+      // For a sequence, the possible next siblings elements excludes children of
+      // the sequence itself. This is because we only use this list to find things that
+      // are AFTER the sequence itself. The contents of the sequence itself are
+      // going to be handled by the "self" cases for elements and choices.
+      // So we use just the following siblings.
+      //
+      // In the actual runtime, this information is never on top of the dynamic context
+      // stack. It is always down at least one on the stack. It is only used when the
+      // term itself has not provided a match to the incoming event, and we need to
+      // see if things following the term provide a match.
+      //
+      case stb: SequenceTermBase =>
+        followingLexicalSiblingStreamingUnparserElements
+      case _ =>
+        possibleSelfPlusNextLexicalSiblingStreamingUnparserElements
+    }
+    res
+  }
+
+  private lazy val possibleSelfPlusNextLexicalSiblingStreamingUnparserElements: PossibleNextElements
=
+    LV('possibleNextLexicalSiblingStreamingUnparserElements) {
+      val thisItself: PossibleNextElements = this match {
+        //
+        // An array may be required in the infoset, but the array
+        // may also be terminated by finding the next element after the array,
+        // so we get closed only if required and not an array.
+        //
+        case eb: ElementBase if (eb.isRequiredStreamingUnparserEvent) =>
+          Closed(Seq(PNE(eb, true)))
+        case eb: ElementBase =>
+          Open(Seq(PNE(eb, false)))
+        case ctb: ChoiceTermBase => {
+          val individualBranchPossibles = ctb.groupMembers.map {
+            _.possibleSelfPlusNextLexicalSiblingStreamingUnparserElements
+          }
+          //
+          // If all branches are closed, then the overall set will be
+          // closed for the whole choice. Some element from the choice will
+          // have to appear next. But no specific individual one is required.
+          //
+          val allBranchesClosed =
+            individualBranchPossibles.forall {
+              case c: Closed => true
+              case o: Open => false
+              case DoNotUse => Assert.invariantFailed("should never be DoNotUse")
+            }
+          //
+          // Individual possible next elements (aka sibs) come from
+          // various branches. Within those branches they may be required to appear
+          // in the stream of events, but as alternatives of a choice, none of
+          // them are specifically required, because you could always be
+          // unparsing some other branch.
+          // So in the PNE we override them to have false for
+          // the overrideIsRequiredStreamingUnparserEvent.
+          //
+          val allSibsAsOptional = individualBranchPossibles.flatMap { poss =>
+            poss.pnes.map {
+              case PNE(eb, true) =>
+                PNE(eb, false)
+              case ok @ PNE(eb, false) =>
+                ok
+            }
+          }
+          val res: PossibleNextElements =
+            if (allBranchesClosed) {
+              Closed(allSibsAsOptional)
+            } else {
+              Open(allSibsAsOptional)
+            }
+          res
+        }
+        case stb: SequenceTermBase => {
+          //
+          // This case only applies to when we are analyzing a sequence, but it is
+          // being considered as contributing possible elements that are after the
+          // end of a Term.
+          //
+          // In this case, we DO recursively walk into the sequence's own children
+          //
+          val subTerms = stb.groupMembers
+          val res =
+            subTerms.map { _.possibleSelfPlusNextLexicalSiblingStreamingUnparserElements
}.headOption
+          res.getOrElse(Open(Nil))
+        }
+      }
+      val res: PossibleNextElements = (thisItself, followingLexicalSiblingStreamingUnparserElements)
match {
+        case (Closed(pnes1), poss2) => Closed(pnes1) // thisItself is closed, you'll never
look at the following.
+        case (Open(pnes1), Closed(Nil)) => Open(pnes1) // case of Open(...) followed by
end of complex element.
+        case (poss1, Closed(pnes2)) => Closed((poss1.pnes ++ pnes2).distinct)
+        case (poss1, poss2) => Open((poss1.pnes ++ poss2.pnes).distinct)
+      }
+      res
+    }.value
+
+  /**
+   * Computes the possible next elements after a term, not including any that
+   * the term itself may have as possibilities.
+   */
+  private lazy val followingLexicalSiblingStreamingUnparserElements: PossibleNextElements
=
+    LV('followingLexicalSiblingStreamingUnparserElements) {
+      Assert.invariant(optLexicalParent.isDefined)
+      val lexicalParent = optLexicalParent.get
+      lexicalParent match {
+        case parentSeqDef: SequenceDefMixin => {
+          //
+          // start after this term in the lexically enclosing sequence siblings
+          //
+          val sibTerms = parentSeqDef.groupMembers.drop(position)
+          //
+          // compute what is possible for each of them.
+          //
+          val sibPossibles = sibTerms.map { _.possibleSelfPlusNextLexicalSiblingStreamingUnparserElements
}
+          //
+          // split the possibles at the first closed set,
+          // including the first closed one, if there are any closed ones
+          //
+          val (opens, closedAndAfter) = sibPossibles.span { _.isInstanceOf[Open] }
+          val optClosed = closedAndAfter.headOption
+          val possibleFromSibs = opens ++ optClosed
+          val hasClosed = optClosed.isDefined
 
 Review comment:
   I think it's clearer if I just rename optClosed to optFirstClosed, and possibleFromSibs
to opensPlusFirstClosed

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

Mime
View raw message