in daffodil-runtime1-unparser/src/main/scala/org/apache/daffodil/unparsers/runtime1/SeparatedSequenceUnparsers.scala [591:720]
private def unparseWithNoSuppression(state: UState): Unit = {
state.groupIndexStack.push(1L) // one-based indexing
var index = 0
var doUnparser = false
val limit = childUnparsers.length
while (index < limit) {
val childUnparser = childUnparsers(index)
val trd = childUnparser.trd
state.pushTRD(trd) // because we inspect before we invoke child unparser
//
// Unparsing an ordered sequence depends on the incoming
// stream of infoset events matching up with the order that
// they are expected as the unparser recurses through the
// child term unparsers.
//
childUnparser match {
case unparser: RepOrderedSeparatedSequenceChildUnparser => {
state.arrayIterationIndexStack.push(1L)
state.occursIndexStack.push(1L)
val erd = unparser.erd
Assert.invariant(erd.isArray || erd.isOptional)
Assert.invariant(erd.isRepresented) // arrays/optionals cannot have inputValueCalc
var numOccurrences = 0
val maxReps = unparser.maxRepeats(state)
Assert.invariant(state.inspect)
val ev = state.inspectAccessor
val isArr = erd.isArray
// If the event is for this Rep unparser, we need to consume the StartArray event
if (ev.erd eq erd) {
unparser.startArrayOrOptional(state)
}
// Unparse each occurrence of this array in the infoset. Note that there could be zero
// occurrences
while ({
doUnparser = unparser.shouldDoUnparser(unparser, state)
doUnparser
}) {
//
// These are so we can check invariants on these stacks being
// pushed and popped reliably, and incremented only once
//
val arrayIterationIndexBefore = state.arrayIterationPos
val arrayIterationIndexStackDepthBefore =
state.arrayIterationIndexStack.length
val occursIndexBefore = state.occursPos
val occursIndexStackDepthBefore = state.occursIndexStack.length
val groupIndexBefore = state.groupPos
val groupIndexStackDepthBefore = state.groupIndexStack.length
if (isArr && state.dataProc.isDefined)
state.dataProc.get.beforeRepetition(state, this)
unparseOne(unparser, erd, state)
numOccurrences += 1
Assert.invariant(
state.arrayIterationIndexStack.length == arrayIterationIndexStackDepthBefore
)
state.moveOverOneArrayIterationIndexOnly()
Assert.invariant(state.arrayIterationPos == arrayIterationIndexBefore + 1)
Assert.invariant(state.occursIndexStack.length == occursIndexStackDepthBefore)
state.moveOverOneOccursIndexOnly()
Assert.invariant(state.occursPos == occursIndexBefore + 1)
Assert.invariant(state.groupIndexStack.length == groupIndexStackDepthBefore)
state.moveOverOneGroupIndexOnly() // array elements are always represented.
Assert.invariant(state.groupPos == groupIndexBefore + 1)
if (isArr && state.dataProc.isDefined)
state.dataProc.get.afterRepetition(state, this)
}
// If not enough occurrences are in the infoset, we output extra separators because
// we are unparsing with no suppression
if (maxReps > numOccurrences) {
var numExtraSeps = {
val sepsNeeded = erd.maxOccurs - numOccurrences
if ((spos eq Infix) && state.groupPos == 1) {
// If separatorPosition is infix and we haven't output anything for this sequence
// yet, then we need one less extra separator, since the separator is skipped
// for the first instance of infix separators.
sepsNeeded - 1
} else {
sepsNeeded
}
}
while (numExtraSeps > 0) {
unparseJustSeparator(state)
numExtraSeps -= 1
}
}
unparser.checkFinalOccursCountBetweenMinAndMaxOccurs(
state,
unparser,
numOccurrences,
maxReps,
state.arrayIterationPos - 1
)
// If the event is for this Rep unparser, we need to consume the EndArray event
if (ev.erd eq erd) {
unparser.endArrayOrOptional(erd, state)
}
state.arrayIterationIndexStack.pop()
state.occursIndexStack.pop()
}
case scalarUnparser => {
unparseOne(scalarUnparser, trd, state)
// only move over in group if the scalar "thing" is an element
// that is represented.
trd match {
case erd: ElementRuntimeData if (!erd.isRepresented) => // ok, skip group advance
case _ => state.moveOverOneGroupIndexOnly()
}
}
}
state.popTRD(trd)
index += 1
}
state.groupIndexStack.pop()
}