You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@daffodil.apache.org by GitBox <gi...@apache.org> on 2021/08/19 15:51:02 UTC

[GitHub] [daffodil] stevedlawrence commented on a change in pull request #623: Ensure we reset groupIndexStack in sequence when an exception is thrown

stevedlawrence commented on a change in pull request #623:
URL: https://github.com/apache/daffodil/pull/623#discussion_r692258851



##########
File path: daffodil-runtime1/src/main/scala/org/apache/daffodil/processors/parsers/SequenceParserBases.scala
##########
@@ -72,322 +72,326 @@ abstract class SequenceParserBase(
   override protected def parse(pstate: PState): Unit = {
     pstate.mpstate.groupIndexStack.push(1L)
 
-    val children = childParsers
+    try {
 
-    var scpIndex = 0
+      val children = childParsers
 
-    val limit = children.length
+      var scpIndex = 0
 
-    var resultOfTry: ParseAttemptStatus = ParseAttemptStatus.Uninitialized
+      val limit = children.length
 
-    val infosetIndexStart = pstate.infoset.asInstanceOf[DIComplex].childNodes.size
+      var resultOfTry: ParseAttemptStatus = ParseAttemptStatus.Uninitialized
 
-    if (!isOrdered) {
-      // If this is an unordered sequence, upon completion of parsing all the
-      // elements we will reorder the elements into schema definition order.
-      // This means that we cannot let the infoset walker walk any of the
-      // elements while we are parsing because their event order might change.
-      // To ensure we don't walk, add a block on the parent of the infoset
-      // elements. The infoset walker will inspect this to see if it should
-      // walk any children. We'll remove this block once the unordered sequence
-      // is complete.
-      pstate.infoset.infosetWalkerBlockCount += 1
-    }
+      val infosetIndexStart = pstate.infoset.asInstanceOf[DIComplex].childNodes.size
 
-    /**
-     * On exit from the sequence loop, if the last thing was Missing, we
-     * want to look back one prior to see if that followed a EmptyRep or AbsentRep,
-     * so that we can implement the check for trailingEmptyStrict
-     */
-    var priorResultOfTry: ParseAttemptStatus = ParseAttemptStatus.Uninitialized
+      if (!isOrdered) {
+        // If this is an unordered sequence, upon completion of parsing all the
+        // elements we will reorder the elements into schema definition order.
+        // This means that we cannot let the infoset walker walk any of the
+        // elements while we are parsing because their event order might change.
+        // To ensure we don't walk, add a block on the parent of the infoset
+        // elements. The infoset walker will inspect this to see if it should
+        // walk any children. We'll remove this block once the unordered sequence
+        // is complete.
+        pstate.infoset.infosetWalkerBlockCount += 1
+      }
 
-    var child: SequenceChildParser = null
+      /**
+       * On exit from the sequence loop, if the last thing was Missing, we
+       * want to look back one prior to see if that followed a EmptyRep or AbsentRep,
+       * so that we can implement the check for trailingEmptyStrict
+       */
+      var priorResultOfTry: ParseAttemptStatus = ParseAttemptStatus.Uninitialized
 
-    var isDone = false
+      var child: SequenceChildParser = null
 
-    //
-    // This loop iterates over the children terms of the sequence
-    //
-    while (!isDone && (scpIndex < limit) && (pstate.processorStatus eq Success)) {
+      var isDone = false
 
-      // keep track of the current last child node. If the last child changes
-      // while parsing, we know a new child was added in this loop
-
-      child = children(scpIndex).asInstanceOf[SequenceChildParser]
-
-      child match {
-        case parser: RepeatingChildParser if isOrdered => {
-          //
-          // The sequence child is an array/repeating element (or optional
-          // element as the runtime doesn't distinguish them) of an ordered
-          // sequence. Unordred sequences are treated as scalars below.
-          //
-          val min = parser.minRepeats(pstate)
-          val max = parser.maxRepeats(pstate)
-          val isBounded = parser.isBoundedMax
-          val erd = parser.trd.asInstanceOf[ElementRuntimeData]
-
-          parser.startArray(pstate)
+      //
+      // This loop iterates over the children terms of the sequence
+      //
+      while (!isDone && (scpIndex < limit) && (pstate.processorStatus eq Success)) {
 
-          //
-          // This case for array/optionals where the number of occurences is
-          // determined by speculative parsing. OCK=implicit with min/maxOccurs
-          // different, or OCK=parsed.
-          //
+        // keep track of the current last child node. If the last child changes
+        // while parsing, we know a new child was added in this loop
 
-          priorResultOfTry = resultOfTry
-          resultOfTry = ParseAttemptStatus.Uninitialized
+        child = children(scpIndex).asInstanceOf[SequenceChildParser]
 
-          var ais: ArrayIndexStatus = ArrayIndexStatus.Uninitialized
-          while ((ais ne Done) && { // check ais for Done in case it was assigned
-            ais = parser.arrayIndexStatus(min, max, pstate)
-            (pstate.isSuccess) && (ais ne Done) // check ais for done from min/max computation
-          }) {
-            val roStatus = ais.asInstanceOf[RequiredOptionalStatus]
+        child match {
+          case parser: RepeatingChildParser if isOrdered => {
+            //
+            // The sequence child is an array/repeating element (or optional
+            // element as the runtime doesn't distinguish them) of an ordered
+            // sequence. Unordred sequences are treated as scalars below.
+            //
+            val min = parser.minRepeats(pstate)
+            val max = parser.maxRepeats(pstate)
+            val isBounded = parser.isBoundedMax
+            val erd = parser.trd.asInstanceOf[ElementRuntimeData]
 
-            val priorPos = pstate.bitPos0b
+            parser.startArray(pstate)
 
-            {
-              //
-              // Note: Performance - counting on Scala compiler to optimize away
-              // this 2-tuple to avoid allocation in the inner loop here.
-              //
-              val (nextAIS, nextResultOfTry) = parseOneInstance(parser, pstate, roStatus)
-              ais = nextAIS
-              priorResultOfTry = resultOfTry
-              resultOfTry = nextResultOfTry
-            }
-            val currentPos = pstate.bitPos0b
-            if (pstate.isSuccess && !isBounded && (
-              resultOfTry match {
-                case ParseAttemptStatus.AbsentRep => true
-                case _: ParseAttemptStatus.SuccessParseAttemptStatus => true
-                case _ => false
-              })) {
-              //
-              // result of try could be missing if we just ended an array
-              // by speculation.
-              //
-              // result of try could also be absent if we just ended a group
-              // by not finding a separator
-              //
-              ais = checkForwardProgress(pstate, currentPos, priorPos, ais)
-            }
             //
-            // advance array position.
-            // Done unconditionally, as some failures get converted into successes
+            // This case for array/optionals where the number of occurences is
+            // determined by speculative parsing. OCK=implicit with min/maxOccurs
+            // different, or OCK=parsed.
             //
-            // If ultimately this is a real failure, then mothing cares about this, it is
-            // about to get poppped/cleared anyway.
-            //
-            if (ais ne Done) {
-              pstate.mpstate.moveOverOneArrayIndexOnly()
-            }
 
-            if (currentPos > priorPos ||
-              ((resultOfTry eq AbsentRep) && pstate.isSuccess) ||
-                resultOfTry.isInstanceOf[SuccessParseAttemptStatus]) {
-              // If we consumed some bits, then we moved past something, and so
-              // we're definitely not first in the group any more.
-              //
-              // Or if AbsentRep, that means we sucessfully parsed a
-              // zero-length separated element. Even though this element may
-              // not end up in the infoset due to separator suppression, we
-              // must still increment the group index since that is used to
-              // determine when to consume infix separators
+            priorResultOfTry = resultOfTry
+            resultOfTry = ParseAttemptStatus.Uninitialized
+
+            var ais: ArrayIndexStatus = ArrayIndexStatus.Uninitialized
+            while ((ais ne Done) && { // check ais for Done in case it was assigned
+              ais = parser.arrayIndexStatus(min, max, pstate)
+              (pstate.isSuccess) && (ais ne Done) // check ais for done from min/max computation
+            }) {
+              val roStatus = ais.asInstanceOf[RequiredOptionalStatus]
+
+              val priorPos = pstate.bitPos0b
+
+              {
+                //
+                // Note: Performance - counting on Scala compiler to optimize away
+                // this 2-tuple to avoid allocation in the inner loop here.
+                //
+                val (nextAIS, nextResultOfTry) = parseOneInstance(parser, pstate, roStatus)
+                ais = nextAIS
+                priorResultOfTry = resultOfTry
+                resultOfTry = nextResultOfTry
+              }
+              val currentPos = pstate.bitPos0b
+              if (pstate.isSuccess && !isBounded && (
+                resultOfTry match {
+                  case ParseAttemptStatus.AbsentRep => true
+                  case _: ParseAttemptStatus.SuccessParseAttemptStatus => true
+                  case _ => false
+                })) {
+                //
+                // result of try could be missing if we just ended an array
+                // by speculation.
+                //
+                // result of try could also be absent if we just ended a group
+                // by not finding a separator
+                //
+                ais = checkForwardProgress(pstate, currentPos, priorPos, ais)
+              }
               //
-              // Otherwise, the parse failed or nothing was consumed and we do
-              // should not increment the group index.
-              pstate.mpstate.moveOverOneGroupIndexOnly()
-            }
-
-            val newLastChildNode = pstate.infoset.maybeLastChild
-            if (newLastChildNode.isDefined) {
-              // We have potentially added a child to to this complex during
-              // this array loop.
+              // advance array position.
+              // Done unconditionally, as some failures get converted into successes
               //
-              // If the new child is a DIArray, we know this DIArray has at
-              // least one element, but we don't know if we actually added a
-              // new one in this loop or not. So just get the last array
-              // element and set it as final anyways.
+              // If ultimately this is a real failure, then mothing cares about this, it is
+              // about to get poppped/cleared anyway.
               //
-              // If it's not a DIArray, that means it's just an optional
-              // simple/complex and that will get set final below where all
-              // other non-array elements get set as final.
-              val lastChild = newLastChildNode.get
-              if (lastChild.isArray) {
-                // not simple or complex, must be an array
-                val lastArrayElem = lastChild.maybeLastChild
-                if (lastArrayElem.isDefined) {
-                  lastArrayElem.get.isFinal = true
-                  pstate.walker.walk()
+              if (ais ne Done) {
+                pstate.mpstate.moveOverOneArrayIndexOnly()
+              }
+
+              if (currentPos > priorPos ||
+                ((resultOfTry eq AbsentRep) && pstate.isSuccess) ||
+                  resultOfTry.isInstanceOf[SuccessParseAttemptStatus]) {
+                // If we consumed some bits, then we moved past something, and so
+                // we're definitely not first in the group any more.
+                //
+                // Or if AbsentRep, that means we sucessfully parsed a
+                // zero-length separated element. Even though this element may
+                // not end up in the infoset due to separator suppression, we
+                // must still increment the group index since that is used to
+                // determine when to consume infix separators
+                //
+                // Otherwise, the parse failed or nothing was consumed and we do
+                // should not increment the group index.
+                pstate.mpstate.moveOverOneGroupIndexOnly()
+              }
+
+              val newLastChildNode = pstate.infoset.maybeLastChild
+              if (newLastChildNode.isDefined) {
+                // We have potentially added a child to to this complex during
+                // this array loop.
+                //
+                // If the new child is a DIArray, we know this DIArray has at
+                // least one element, but we don't know if we actually added a
+                // new one in this loop or not. So just get the last array
+                // element and set it as final anyways.
+                //
+                // If it's not a DIArray, that means it's just an optional
+                // simple/complex and that will get set final below where all
+                // other non-array elements get set as final.
+                val lastChild = newLastChildNode.get
+                if (lastChild.isArray) {
+                  // not simple or complex, must be an array
+                  val lastArrayElem = lastChild.maybeLastChild
+                  if (lastArrayElem.isDefined) {
+                    lastArrayElem.get.isFinal = true
+                    pstate.walker.walk()
+                  }
                 }
               }
-            }
 
-          } // end while for each repeat
-          parser.endArray(pstate)
-        } // end match case RepeatingChildParser
+            } // end while for each repeat
+            parser.endArray(pstate)
+          } // end match case RepeatingChildParser
 
-        case nonRepresentedParser: NonRepresentedSequenceChildParser => {
-          // should never have non-represented children in unordered sequences
-          Assert.invariant(isOrdered)
+          case nonRepresentedParser: NonRepresentedSequenceChildParser => {
+            // should never have non-represented children in unordered sequences
+            Assert.invariant(isOrdered)
 
-          nonRepresentedParser.parseOne(pstate, null)
-          // don't need to digest result from this. All
-          // information about success/failure is in the pstate.
-          //
-          // We do NOT move over the group index state for non-represented things.
-        }
+            nonRepresentedParser.parseOne(pstate, null)
+            // don't need to digest result from this. All
+            // information about success/failure is in the pstate.
+            //
+            // We do NOT move over the group index state for non-represented things.
+          }
 
-        // This case for scalar parsers. This includes both scalar elements,
-        // and model group terms (choices, or sequences that are children of a
-        // sequence). A model group term is considered scalar in that they
-        // cannot be repeating at all in DFDL v1.0.
-        //
-        // This case is also used for all children of unordered sequences. In
-        // that case, we repeatedly attempt to parse all the children (starting
-        // over on success), until all children fail or if discriminated
-        // content causes us to bail early.
-        case scalarParser => {
-          val diagnosticsBeforeAttempt = pstate.diagnostics
-          val roStatus =
-            if (isOrdered)
-              scalarParser.maybeStaticRequiredOptionalStatus.get
-            else {
-              // Treat unordered sequence children as if they are required.
-              // This way if they fail, we will simply backtrack and try the
-              // next child
-              RequiredOptionalStatus.Required
-            }
-          val (_, nextResultOfTry) = parseOneInstance(scalarParser, pstate, roStatus)
-          priorResultOfTry = resultOfTry
-          resultOfTry = nextResultOfTry
-          resultOfTry match {
-            case AbsentRep => {
-              // a scalar element, or a model group is absent. That means no separator
-              // was found for it.
-              //
-              // That means were at the end of the representation of this sequence,
-              // This is only returned as resultOfTry if it is
-              // OK for us to act on it. I.e., we know that the situation is
-              // Positional trailing, with a group that can have zero-length representation.
-              // and no separator was found for it.
-              //
-              // So we mask the failure, and exit the sequence successfully
-              pstate.setSuccess()
-              isDone = true
-              // If we're masking the failure, we don't want the error dianostics
-              // to flow up. Restore the diagnostics from before the parse
-              // attempt
-              pstate.diagnostics = diagnosticsBeforeAttempt
-            }
+          // This case for scalar parsers. This includes both scalar elements,
+          // and model group terms (choices, or sequences that are children of a
+          // sequence). A model group term is considered scalar in that they
+          // cannot be repeating at all in DFDL v1.0.
+          //
+          // This case is also used for all children of unordered sequences. In
+          // that case, we repeatedly attempt to parse all the children (starting
+          // over on success), until all children fail or if discriminated
+          // content causes us to bail early.
+          case scalarParser => {
+            val diagnosticsBeforeAttempt = pstate.diagnostics
+            val roStatus =
+              if (isOrdered)
+                scalarParser.maybeStaticRequiredOptionalStatus.get
+              else {
+                // Treat unordered sequence children as if they are required.
+                // This way if they fail, we will simply backtrack and try the
+                // next child
+                RequiredOptionalStatus.Required
+              }
+            val (_, nextResultOfTry) = parseOneInstance(scalarParser, pstate, roStatus)
+            priorResultOfTry = resultOfTry
+            resultOfTry = nextResultOfTry
+            resultOfTry match {
+              case AbsentRep => {
+                // a scalar element, or a model group is absent. That means no separator
+                // was found for it.
+                //
+                // That means were at the end of the representation of this sequence,
+                // This is only returned as resultOfTry if it is
+                // OK for us to act on it. I.e., we know that the situation is
+                // Positional trailing, with a group that can have zero-length representation.
+                // and no separator was found for it.
+                //
+                // So we mask the failure, and exit the sequence successfully
+                pstate.setSuccess()
+                isDone = true
+                // If we're masking the failure, we don't want the error dianostics
+                // to flow up. Restore the diagnostics from before the parse
+                // attempt
+                pstate.diagnostics = diagnosticsBeforeAttempt
+              }
 
-            // This child alternative of an unordered sequence failed, and that
-            // failure occurred after a discriminator within that child
-            // evaluated to true. This means that this unordered sequence has
-            // failed. We set isDone to true so we do not attempt anymore
-            // children of this unordered sequence. Additionally, that failure
-            // is still in the PState, which will cause us to backtrack to the
-            // nearest unresolved point of uncertainty.
-            case UnorderedSeqDiscriminatedFailure => isDone = true
-
-            // We failed to parse a single instance of an unordered sequence
-            // element, and we did not hit a discriminator. parseOneInstance
-            // will have backtracked to before this instance was attempted, so
-            // we can just try to parse the next child. We do not need to do
-            // anything special, the end of this loop will increment to the
-            // next child.
-            case _: FailedParseAttemptStatus if (!isOrdered) => // no-op
-
-            case _ => {
-              if (isOrdered) {
-                // Successfully parsed a scalar ordered sequence element,
-                // nothing to do. We'll increment scpIndex before looping
-                // back around and try parsing the next sequence child
-              } else {
-                // Successfully parsed an unordered sequence child. We want to
-                // try parsing the unordered sequence children again from the
-                // beginning, so we set the index to -1 so it is incremented
-                // back to zero at the end of the while loop
-                scpIndex = -1
+              // This child alternative of an unordered sequence failed, and that
+              // failure occurred after a discriminator within that child
+              // evaluated to true. This means that this unordered sequence has
+              // failed. We set isDone to true so we do not attempt anymore
+              // children of this unordered sequence. Additionally, that failure
+              // is still in the PState, which will cause us to backtrack to the
+              // nearest unresolved point of uncertainty.
+              case UnorderedSeqDiscriminatedFailure => isDone = true
+
+              // We failed to parse a single instance of an unordered sequence
+              // element, and we did not hit a discriminator. parseOneInstance
+              // will have backtracked to before this instance was attempted, so
+              // we can just try to parse the next child. We do not need to do
+              // anything special, the end of this loop will increment to the
+              // next child.
+              case _: FailedParseAttemptStatus if (!isOrdered) => // no-op
+
+              case _ => {
+                if (isOrdered) {
+                  // Successfully parsed a scalar ordered sequence element,
+                  // nothing to do. We'll increment scpIndex before looping
+                  // back around and try parsing the next sequence child
+                } else {
+                  // Successfully parsed an unordered sequence child. We want to
+                  // try parsing the unordered sequence children again from the
+                  // beginning, so we set the index to -1 so it is incremented
+                  // back to zero at the end of the while loop
+                  scpIndex = -1
+                }
+                // We successfully parsed something, so we must increment the group
+                // index
+                pstate.mpstate.moveOverOneGroupIndexOnly()
               }
-              // We successfully parsed something, so we must increment the group
-              // index
-              pstate.mpstate.moveOverOneGroupIndexOnly()
             }
-          }
-        } // end case scalarParser
-      } // end match case parser
+          } // end case scalarParser
+        } // end match case parser
 
-      // now that we have finished parsing a single instance of this sequence,
-      // we need to potentially set things as final, get the last child to
-      // determine if it changed from the saved last child, which lets us know
-      // if a new child was actually added.
-      val newLastChildNode = pstate.infoset.maybeLastChild
+        // now that we have finished parsing a single instance of this sequence,
+        // we need to potentially set things as final, get the last child to
+        // determine if it changed from the saved last child, which lets us know
+        // if a new child was actually added.
+        val newLastChildNode = pstate.infoset.maybeLastChild
 
-      if (!isOrdered) {
-        // In the special case of unordered sequences with arrays, we do not
-        // use the RepatingChildParser. Instead we parse on instance at a time
-        // in this loop. So array elements aren't set final above like normal
-        // arrays are.
-        //
-        // So if the last child node is a DIArray, we must set new array
-        // elements as final here. We can't know if we actually added a new
-        // DIArray element or not, so just set the last one as final
-        // regardless.
-        //
-        // Note that we do not need to do a null check because in an unordered
-        // sequence we are blocking, so we can't possibly walk/free any of
-        // these newly added elements.
-        if (newLastChildNode.isDefined && newLastChildNode.get.isArray) {
-          // we have a new last child, and it's not simple or complex, so must
-          // be an array. Set its last child final
-          newLastChildNode.get.maybeLastChild.get.isFinal = true
+        if (!isOrdered) {
+          // In the special case of unordered sequences with arrays, we do not
+          // use the RepatingChildParser. Instead we parse on instance at a time
+          // in this loop. So array elements aren't set final above like normal
+          // arrays are.
+          //
+          // So if the last child node is a DIArray, we must set new array
+          // elements as final here. We can't know if we actually added a new
+          // DIArray element or not, so just set the last one as final
+          // regardless.
+          //
+          // Note that we do not need to do a null check because in an unordered
+          // sequence we are blocking, so we can't possibly walk/free any of
+          // these newly added elements.
+          if (newLastChildNode.isDefined && newLastChildNode.get.isArray) {
+            // we have a new last child, and it's not simple or complex, so must
+            // be an array. Set its last child final
+            newLastChildNode.get.maybeLastChild.get.isFinal = true
+          }
         }
-      }
 
-      // We finished parsing one part of a sequence, which could either be an
-      // array, simple, or complex. We aren't sure if we actually added a new
-      // element or not, but in case we did, mark the last node as final.
-      //
-      // Additionally, if this is an ordered sequence, try to walk the infoset
-      // to output events for this potentially new element. If this is an
-      // unordered sequence, walking is unnecessary. This is because we may
-      // need to reorder the infoset once this unordered sequence is complete
-      // (via flattenAndValidateChildNodes below) and cannot walk until that
-      // happens. To ensure we don't walk even if a child parser tries to call
-      // walk() we incremented infosetWalkerBlockCount at the beginning of this
-      // function, so the walker is effectively blocked from making any
-      // progress. So we don't even bother calling walk() in this case.
-      if (newLastChildNode.isDefined) {
-        newLastChildNode.get.isFinal = true
-        if (isOrdered) pstate.walker.walk()
-      }
-
-      scpIndex += 1
+        // We finished parsing one part of a sequence, which could either be an
+        // array, simple, or complex. We aren't sure if we actually added a new
+        // element or not, but in case we did, mark the last node as final.
+        //
+        // Additionally, if this is an ordered sequence, try to walk the infoset
+        // to output events for this potentially new element. If this is an
+        // unordered sequence, walking is unnecessary. This is because we may
+        // need to reorder the infoset once this unordered sequence is complete
+        // (via flattenAndValidateChildNodes below) and cannot walk until that
+        // happens. To ensure we don't walk even if a child parser tries to call
+        // walk() we incremented infosetWalkerBlockCount at the beginning of this
+        // function, so the walker is effectively blocked from making any
+        // progress. So we don't even bother calling walk() in this case.
+        if (newLastChildNode.isDefined) {
+          newLastChildNode.get.isFinal = true
+          if (isOrdered) pstate.walker.walk()
+        }
 
-    } // end while for each sequence child parser
+        scpIndex += 1
 
-    if (!isOrdered) {
-      // we are unordered, so we need to reorder the new children into schema
-      // definition order, flatten arrays, and validate
-      val infoset = pstate.infoset.asInstanceOf[DIComplex]
-      infoset.flattenAndValidateChildNodes(pstate, infosetIndexStart)
+      } // end while for each sequence child parser
 
-      // now that we have flattened children, we can decrement the block count
-      // that we incremented above. This will allow the infoset walker to walk
-      // into the new children that are now in the correct order.
-      pstate.infoset.infosetWalkerBlockCount -= 1
+      if (!isOrdered) {
+        // we are unordered, so we need to reorder the new children into schema
+        // definition order, flatten arrays, and validate
+        val infoset = pstate.infoset.asInstanceOf[DIComplex]
+        infoset.flattenAndValidateChildNodes(pstate, infosetIndexStart)
+
+        // now that we have flattened children, we can decrement the block count
+        // that we incremented above. This will allow the infoset walker to walk
+        // into the new children that are now in the correct order.
+        pstate.infoset.infosetWalkerBlockCount -= 1
+
+        // we've unblocked the unordered sequence, try walking to output
+        // everything we've created
+        pstate.walker.walk()
+      }
 
-      // we've unblocked the unordered sequence, try walking to output
-      // everything we've created
-      pstate.walker.walk()
+      if (child ne null) child.finalChecks(pstate, resultOfTry, priorResultOfTry)
+      ()
+    } finally {
+      pstate.mpstate.groupIndexStack.pop()

Review comment:
       This is mostly just indentation changes. If you click the gear at the top and click "Hide whitespace changes" you can see that the only thing that really changes is this new finally block.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@daffodil.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org