Github user mbeckerle commented on a diff in the pull request:

    https://github.com/apache/incubator-daffodil/pull/4#discussion_r149394482
  
    --- Diff: 
daffodil-runtime1/src/main/scala/edu/illinois/ncsa/daffodil/processors/parsers/RepParsers.scala
 ---
    @@ -207,87 +253,129 @@ class RepUnboundedParser(occursCountKind: 
OccursCountKind.Value, rParser: Parser
       extends RepParser(-1, rParser, erd, "Unbounded") {
     
       def parseAllRepeats(initialState: PState): Unit = {
    +    var startState: PState.Mark = null
    +    var priorState: PState.Mark = null
    +    var markLeakCausedByException = false
    +
         Assert.invariant(initialState.processorStatus eq Success)
    -    val startState = initialState.mark("RepUnboundedParser1")
    -    val pstate = initialState
    -    var priorState = initialState.mark("RepUnboundedParser2")
    -    var returnFlag = false
    -    while (!returnFlag && (pstate.processorStatus eq Success)) {
    -
    -      //      erd.maxOccurs.foreach { maxOccurs =>
    -      //        if ((occursCountKind == OccursCountKind.Implicit) &&
    -      //          (maxOccurs == -1)) {
    -      //          erd.minOccurs.foreach { minOccurs =>
    -      //            if (pstate.mpstate.arrayPos - 1 <= minOccurs) {
    -      //              // Is required element
    -      //              // Need to trigger default value creation
    -      //              // in right situations (like the element is 
defaultable)
    -      //              // This is relatively easy for simple types
    -      //              // for complex types, defaulting is trickier as one
    -      //              // must recursively traverse the type, and then 
determine one
    -      //              // has not advanced the data at all.
    -      //            }
    -      //          }
    -      //        }
    -      //      }
    -
    -      //
    -      // Every parse is a new point of uncertainty.
    -      pstate.pushDiscriminator
    -      if (pstate.dataProc.isDefined) 
pstate.dataProc.get.beforeRepetition(pstate, this)
    -
    -      try {
    -        rParser.parse1(pstate)
    -      } catch {
    -        case sde: SchemaDefinitionDiagnosticBase => {
    -          pstate.discard(startState)
    -          throw sde
    -        }
    -      }
     
    -      if (pstate.dataProc.isDefined) 
pstate.dataProc.get.afterRepetition(pstate, this)
    -      if (pstate.processorStatus ne Success) {
    -        //
    -        // Did not succeed
    -        //
    -        // Was a discriminator set?
    +    try {
    +      val pstate = initialState
    +      startState = initialState.mark("RepUnboundedParser1")
    +      priorState = initialState.mark("RepUnboundedParser2")
    +      var returnFlag = false
    +      while (!returnFlag && (pstate.processorStatus eq Success)) {
    +
    +        //      erd.maxOccurs.foreach { maxOccurs =>
    +        //        if ((occursCountKind == OccursCountKind.Implicit) &&
    +        //          (maxOccurs == -1)) {
    +        //          erd.minOccurs.foreach { minOccurs =>
    +        //            if (pstate.mpstate.arrayPos - 1 <= minOccurs) {
    +        //              // Is required element
    +        //              // Need to trigger default value creation
    +        //              // in right situations (like the element is 
defaultable)
    +        //              // This is relatively easy for simple types
    +        //              // for complex types, defaulting is trickier as one
    +        //              // must recursively traverse the type, and then 
determine one
    +        //              // has not advanced the data at all.
    +        //            }
    +        //          }
    +        //        }
    +        //      }
    +
             //
    -        if (pstate.discriminator == true) {
    -          // we fail the whole RepUnbounded, because there was a 
discriminator set
    -          // before the failure.
    -          pstate.reset(startState)
    -          // no need discard priorState, that is implicitly discarded by 
resetting the startState
    -        } else {
    +        // Every parse is a new point of uncertainty.
    +        pstate.pushDiscriminator
    +        if (pstate.dataProc.isDefined) 
pstate.dataProc.get.beforeRepetition(pstate, this)
    +
    +        try {
    +          rParser.parse1(pstate)
    +        } catch {
    +          case sde: SchemaDefinitionDiagnosticBase => {
    +            pstate.discard(startState)
    +            startState = null
    +            priorState = null
    +            throw sde
    +          }
    +        }
    +
    +        if (pstate.dataProc.isDefined) 
pstate.dataProc.get.afterRepetition(pstate, this)
    +        if (pstate.processorStatus ne Success) {
               //
    -          // no discriminator, so suppress the failure. Loop terminated 
with prior element.
    +          // Did not succeed
    +          //
    +          // Was a discriminator set?
               //
    +          if (pstate.discriminator == true) {
    +            // we fail the whole RepUnbounded, because there was a 
discriminator set
    +            // before the failure.
    +            pstate.reset(startState)
    +            startState = null
    +            priorState = null
    +            // no need discard priorState, that is implicitly discarded by 
resetting the startState
    +          } else {
    +            //
    +            // no discriminator, so suppress the failure. Loop terminated 
with prior element.
    +            //
     
    -          log(LogLevel.Debug, "Failure suppressed. This is normal 
termination of a occursCountKind='parsed' array.")
    -          pstate.reset(priorState)
    -          pstate.discard(startState)
    -        }
    -        returnFlag = true
    -      } else {
    -        // Success
    -        // Need to check for forward progress
    -        if (pstate.bitPos =#= priorState.bitPos0b) {
    -          pstate.discard(priorState) // didn't move, but might have 
assigned variables, have to undo those.
    -          pstate.discard(startState)
    -          PE(pstate,
    -            "RepUnbounded - No forward progress at byte %s. Attempt to 
parse %s " +
    -              "succeeded but consumed no data.\nPlease re-examine your 
schema to correct this infinite loop.",
    -            pstate.bytePos, erd.diagnosticDebugName)
    +            log(LogLevel.Debug, "Failure suppressed. This is normal 
termination of a occursCountKind='parsed' array.")
    +            pstate.reset(priorState)
    +            pstate.discard(startState)
    +            startState = null
    +            priorState = null
    +          }
               returnFlag = true
             } else {
    -          pstate.discard(priorState)
    -          priorState = pstate.mark("RepUnboundedParser3")
    -          pstate.mpstate.moveOverOneArrayIndexOnly
    -          returnFlag = false
    +          // Success
    +          // Need to check for forward progress
    +          if (pstate.bitPos =#= priorState.bitPos0b) {
    +            pstate.discard(priorState) // didn't move, but might have 
assigned variables, have to undo those.
    +            pstate.discard(startState)
    +            startState = null
    +            priorState = null
    +            PE(pstate,
    +              "RepUnbounded - No forward progress at byte %s. Attempt to 
parse %s " +
    +                "succeeded but consumed no data.\nPlease re-examine your 
schema to correct this infinite loop.",
    +              pstate.bytePos, erd.diagnosticDebugName)
    +            returnFlag = true
    +          } else {
    +            pstate.discard(priorState)
    +            priorState = pstate.mark("RepUnboundedParser3")
    +            pstate.mpstate.moveOverOneArrayIndexOnly
    +            returnFlag = false
    +          }
    +        }
    +        pstate.popDiscriminator
    +      }
    +      Assert.invariant(returnFlag == true)
    +    } catch {
    +      case t: Throwable => {
    +        if (priorState != null || startState != null) {
    +          markLeakCausedByException = true
    +          if (!t.isInstanceOf[SchemaDefinitionDiagnosticBase] && 
!t.isInstanceOf[UnsuppressableException]) {
    --- End diff --
    
    I was going to comment on shared logic between this and the AltCompParser, 
but really I think sharing would be more complex than duplicating in this case. 
I suggest just a comment in the AltCompParser directing developers to the 
corresponding part of Rep Parsers, and vice versa, so that nobody edits one 
without also considering the other. 
    
    I had to think about whether there are other places that need to deal with 
marks before I convinced myself there are only these two. It would be good to 
write that down in a comment in here. 


---

Reply via email to