in daffodil-runtime1/src/main/scala/org/apache/daffodil/runtime1/processors/parsers/SeparatedParseHelper.scala [190:316]
override def parseOneWithSeparator(
pstate: PState,
requiredOptional: RequiredOptionalStatus
): ParseAttemptStatus = {
val prevBitPosBeforeChild = pstate.bitPos0b
pstate.withPointOfUncertainty("PostfixSeparatorHelper", childParser.context) { pou =>
childParser.parse1(pstate)
val childSuccessful = pstate.processorStatus eq Success
val childFailure = !childSuccessful // just makes later logic easier to read
val bitPosAfterChildAttempt = pstate.bitPos0b
val prh = scParser.parseResultHelper
// This seems odd, but there are cases where after a failure
// the bitPos has not yet been repositioned back to where it started.
// This does happen for complex types.
val hasZLChildAttempt = prevBitPosBeforeChild == bitPosAfterChildAttempt
if (childSuccessful) {
val dataOnlyRep =
prh.computeParseAttemptStatus(
scParser,
prevBitPosBeforeChild,
pstate,
requiredOptional
)
sep.parse1(pstate)
if (pstate.processorStatus eq Success) {
// we got the postfix sep after successful parse of the data item
// so whatever the status of the item was, that's the status overall.
dataOnlyRep
} else {
// child successful, but
// no postfix sep found.
// capture failure reason, but reset position to before the child,
// and remove any elements. That way this behaves like a prefix
// or infix separator, where if you don't get the sep, then you
// usually (except first one in infix case) don't run the child parser
val failure = pstate.processorStatus.asInstanceOf[Failure]
Assert.invariant(!pstate.isPointOfUncertaintyResolved(pou))
pstate.resetToPointOfUncertainty(pou)
pstate.setFailed(failure.cause)
failedSeparator(pstate, "postfix")
prh.computeFailedSeparatorParseAttemptStatus(
scParser,
prevBitPosBeforeChild,
pstate,
hasZLChildAttempt,
requiredOptional
)
}
} else {
Assert.invariant(childFailure)
// We might be tempted to just try the postfix sep now,
// to see if the postfix sep is there immediately.
// This is, however, problematic.
//
// We're depending on this item being an element with lengthKind="delimited"
// which can't have a zero-length representation, so that if there is zero-data before
// the postfix separator, we can declare the item to be absentRep.
//
// But what if the element is not lengthKind 'delimited'.
// Or what if it has complex type? But has a non-zero-length structure where this
// same delimiter is used at a more deeply nested depth?
//
// If the type is simple, and lengthKind 'delimited' we can proceed.
// Otherwise we punt and call it missing.
//
if (isSimpleDelimited) {
val failure = pstate.processorStatus.asInstanceOf[Failure]
Assert.invariant(!pstate.isPointOfUncertaintyResolved(pou))
pstate.resetToPointOfUncertainty(pou)
sep.parse1(pstate)
if (pstate.isSuccess) {
val posAfterSep = pstate.bitPos0b
// failed child, but success on postfix sep.
// behave here just like a prefix separator that was then followed by a child failure
pstate.setFailed(failure.cause)
val pas =
prh.computeParseAttemptStatus(
scParser,
prevBitPosBeforeChild,
pstate,
requiredOptional
)
val res = pas match {
case AbsentRep => {
pstate.dataInputStream.setBitPos0b(posAfterSep)
MissingSeparator
}
case _ => pas
}
res
} else {
// the separator failed on ZL data
// so no chance on a ZL representation here.
val isZL = false
prh.computeFailedSeparatorParseAttemptStatus(
scParser,
prevBitPosBeforeChild,
pstate,
isZL,
requiredOptional
)
}
} else {
// not simple delimited. We really have no way of knowing
// if trying to parse just the sep now makes any sense at all.
// (ex: the child could be failing because it is fixed length, with asserts that check the value
// that fail.)
val isZL = false
prh.computeFailedParseAttemptStatus(
scParser,
prevBitPosBeforeChild,
pstate,
isZL,
requiredOptional
)
}
}
}
}