Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,14 @@ jobs:
- name: Run Unit Tests
run: $SBT test

# Build ahead is the default, so run the suite once more event driven to
# keep that unparse path tested.
- name: Run Unit Tests (event-driven unparse)
if: matrix.os == 'ubuntu-22.04' && matrix.java_version == '17'
env:
DAFFODIL_TDML_TUNABLES: infosetBuilderMode=eventDriven
run: $SBT test

Comment on lines +200 to +207

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only effects the TDML tests. Should we be doing something similar for the Scala unit tests so that we test eventDriven with those as well?

- name: Run Integration Tests
run: $SBT daffodil-test-integration/test

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import org.apache.daffodil.core.compiler.ForParser
import org.apache.daffodil.core.compiler.ForUnparser
import org.apache.daffodil.core.dsom.*
import org.apache.daffodil.lib.exceptions.Assert
import org.apache.daffodil.runtime1.infoset.InfosetBuilder
import org.apache.daffodil.runtime1.infoset.SeqCompInfosetBuilder
import org.apache.daffodil.runtime1.processors.parsers.AssertExpressionEvaluationParser
import org.apache.daffodil.runtime1.processors.parsers.NadaParser
import org.apache.daffodil.runtime1.processors.parsers.SeqCompParser
Expand Down Expand Up @@ -124,6 +126,19 @@ class SeqComp private (context: SchemaComponent, children: Seq[Gram])
else if (unparserChildren.length == 1) unparserChildren.head
else new SeqCompUnparser(context.runtimeData, unparserChildren.toArray)
}

// Only the (usually at most one) child(ren) that actually build infoset
// content contribute here; children that build no infoset events
// (delimiters, padding, etc.) simply have no builder to collect.
lazy val builderChildren: Array[InfosetBuilder] = {
children
.filter(x => !x.isEmpty && (x.forWhat != ForParser))
.map(_.builder)
.filterNot(_.isEmpty)
.toArray
}

final override lazy val builder: InfosetBuilder = SeqCompInfosetBuilder(builderChildren)
}

object EmptyGram extends Gram(null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import org.apache.daffodil.core.compiler.ForUnparser
import org.apache.daffodil.core.compiler.ParserOrUnparser
import org.apache.daffodil.core.dsom.SchemaComponent
import org.apache.daffodil.lib.util.Logger
import org.apache.daffodil.runtime1.infoset.InfosetBuilder
import org.apache.daffodil.runtime1.infoset.NadaInfosetBuilder
import org.apache.daffodil.runtime1.processors.parsers.NadaParser
import org.apache.daffodil.unparsers.runtime1.NadaUnparser

Expand Down Expand Up @@ -107,4 +109,16 @@ final class Prod(
else
unp
}

final override lazy val builder: InfosetBuilder = {
if (gram.isEmpty) {
NadaInfosetBuilder
} else {
(forWhat, gram.forWhat) match {
case (ForParser, _) => NadaInfosetBuilder
case (_, ForParser) => NadaInfosetBuilder
case _ => gram.builder
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,17 @@ import org.apache.daffodil.lib.cookers.ChoiceBranchKeyCooker
import org.apache.daffodil.lib.cookers.IntRangeCooker
import org.apache.daffodil.lib.exceptions.Assert
import org.apache.daffodil.lib.schema.annotation.props.gen.ChoiceLengthKind
import org.apache.daffodil.lib.util.Maybe
import org.apache.daffodil.lib.util.Maybe.Nope
import org.apache.daffodil.lib.util.Maybe.One
import org.apache.daffodil.lib.util.MaybeInt
import org.apache.daffodil.lib.util.ProperlySerializableMap.*
import org.apache.daffodil.lib.xml.NamedQName
import org.apache.daffodil.runtime1.infoset.ChoiceInfosetBuilder
import org.apache.daffodil.runtime1.infoset.InfosetBuilder
import org.apache.daffodil.runtime1.infoset.NadaInfosetBuilder
import org.apache.daffodil.runtime1.processors.RangeBound
import org.apache.daffodil.runtime1.processors.TermRuntimeData
import org.apache.daffodil.runtime1.processors.parsers.*
import org.apache.daffodil.runtime1.processors.unparsers.*
import org.apache.daffodil.unparsers.runtime1.*
Expand Down Expand Up @@ -266,8 +273,15 @@ case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: Seq[Gram])
}
}

private lazy val eventUnparserMap = ch.choiceBranchMap._1.map { case (qname, branchTerm) =>
(qname, branchTerm.termContentBody.unparser)
}

private lazy val hasEventBranchUnparser: Boolean =
eventUnparserMap.exists { case (_, branchUnparser) => !branchUnparser.isEmpty }

override lazy val unparser: Unparser = {
val (eventRDMap, optDefaultBranch) = ch.choiceBranchMap
val optDefaultBranch = ch.choiceBranchMap._2
/*
* Since it's impossible to know the hiddenness for terms at this level (unless
* they're a hiddenGroupRef), we always attempt to find a defaultable unparser.
Expand Down Expand Up @@ -313,11 +327,7 @@ case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: Seq[Gram])
optDefaultUnparser
}

val eventUnparserMap = eventRDMap.map { case (qname, branchTerm) =>
(qname, branchTerm.termContentBody.unparser)
}
val mapValues = eventUnparserMap.map { case (k, v) => v }.filterNot(_.isEmpty)
if (mapValues.isEmpty) {
if (!hasEventBranchUnparser) {
if (branchForUnparse.isEmpty) {
new NadaUnparser(null)
} else {
Expand All @@ -332,4 +342,22 @@ case class ChoiceCombinator(ch: ChoiceTermBase, alternatives: Seq[Gram])
new ChoiceCombinatorUnparser(ch.modelGroupRuntimeData, cbm, choiceLengthInBits)
}
}

override lazy val builder: InfosetBuilder = {
val (eventRDMap, optDefaultBranch) = ch.choiceBranchMap

if (!hasEventBranchUnparser && optDefaultBranch.isEmpty) {
NadaInfosetBuilder
} else {
val branchMap: Map[NamedQName, (TermRuntimeData, InfosetBuilder)] =
eventRDMap.map { case (qname, branchTerm) =>
(qname, (branchTerm.termRuntimeData, branchTerm.termContentBody.builder))
}
val defaultBranch: Maybe[(TermRuntimeData, InfosetBuilder)] = optDefaultBranch match {
case Some(term) => One((term.termRuntimeData, term.termContentBody.builder))
case None => Nope
}
new ChoiceInfosetBuilder(ch.modelGroupRuntimeData, branchMap, defaultBranch)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ import org.apache.daffodil.core.dsom.*
import org.apache.daffodil.core.grammar.Gram
import org.apache.daffodil.core.grammar.Terminal
import org.apache.daffodil.lib.exceptions.Assert
import org.apache.daffodil.lib.util.Maybe
import org.apache.daffodil.lib.util.Maybe.*
import org.apache.daffodil.lib.util.Misc
import org.apache.daffodil.lib.xml.XMLUtils
import org.apache.daffodil.runtime1.infoset.InfosetBuilder
import org.apache.daffodil.runtime1.processors.parsers.{ Parser as DaffodilParser, * }
import org.apache.daffodil.runtime1.processors.unparsers.Unparser as DaffodilUnparser
import org.apache.daffodil.unparsers.runtime1.*
Expand Down Expand Up @@ -55,6 +57,10 @@ case class DelimiterStackCombinatorSequence(sq: SequenceTermBase, body: Gram)

override lazy val unparser: DaffodilUnparser =
new DelimiterStackUnparser(uInit, uSep, uTerm, sq.termRuntimeData, body.unparser)

// Delimiters build no infoset events; the builder tree skips straight to
// whatever this sequence's body itself builds, if anything.
override lazy val builder: InfosetBuilder = body.builder
}

case class DelimiterStackCombinatorChoice(ch: ChoiceTermBase, body: Gram)
Expand All @@ -77,6 +83,10 @@ case class DelimiterStackCombinatorChoice(ch: ChoiceTermBase, body: Gram)

override lazy val unparser: DaffodilUnparser =
new DelimiterStackUnparser(uInit, None, uTerm, ch.termRuntimeData, body.unparser)

// Delimiters build no infoset events; the builder tree skips straight to
// whatever this choice's body itself builds, if anything.
override lazy val builder: InfosetBuilder = body.builder
}

case class DelimiterStackCombinatorElement(e: ElementBase, body: Gram)
Expand Down Expand Up @@ -111,6 +121,10 @@ case class DelimiterStackCombinatorElement(e: ElementBase, body: Gram)
if (u.isEmpty) u
else new DelimiterStackUnparser(uInit, None, uTerm, e.termRuntimeData, u)
}

// Delimiters build no infoset events; the builder tree skips straight to
// whatever this element's body itself builds, if anything.
override lazy val builder: InfosetBuilder = body.builder
}

case class DynamicEscapeSchemeCombinatorElement(e: ElementBase, body: Gram)
Expand All @@ -135,4 +149,9 @@ case class DynamicEscapeSchemeCombinatorElement(e: ElementBase, body: Gram)
if (u.isEmpty || schemeUnparseIsConstant) u
else new DynamicEscapeSchemeUnparser(schemeUnparseOpt.get, e.termRuntimeData, u)
}

// The escape scheme only governs delimiter matching in written bytes; the
// builder tree skips straight to whatever this element's body itself
// builds, if anything.
override lazy val builder: InfosetBuilder = body.builder
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ import org.apache.daffodil.lib.schema.annotation.props.gen.LengthKind
import org.apache.daffodil.lib.schema.annotation.props.gen.Representation
import org.apache.daffodil.lib.schema.annotation.props.gen.TestKind
import org.apache.daffodil.lib.util.Maybe
import org.apache.daffodil.runtime1.infoset.ElementInfosetBuilder
import org.apache.daffodil.runtime1.infoset.InfosetBuilder
import org.apache.daffodil.runtime1.infoset.NadaInfosetBuilder
import org.apache.daffodil.runtime1.processors.parsers.CaptureEndOfContentLengthParser
import org.apache.daffodil.runtime1.processors.parsers.CaptureEndOfValueLengthParser
import org.apache.daffodil.runtime1.processors.parsers.CaptureStartOfContentLengthParser
Expand All @@ -44,6 +47,7 @@ import org.apache.daffodil.unparsers.runtime1.CaptureStartOfValueLengthUnparser
import org.apache.daffodil.unparsers.runtime1.ElementOVCSpecifiedLengthUnparser
import org.apache.daffodil.unparsers.runtime1.ElementOVCUnspecifiedLengthUnparser
import org.apache.daffodil.unparsers.runtime1.ElementSpecifiedLengthUnparser
import org.apache.daffodil.unparsers.runtime1.ElementUnparserBase
import org.apache.daffodil.unparsers.runtime1.ElementUnparserInputValueCalc
import org.apache.daffodil.unparsers.runtime1.ElementUnspecifiedLengthUnparser
import org.apache.daffodil.unparsers.runtime1.ElementUnusedUnparser
Expand Down Expand Up @@ -111,6 +115,12 @@ class ElementCombinator(

private lazy val eRepTypeUnparser: Maybe[Unparser] = repTypeElementGram.maybeUnparser

private lazy val isSpecifiedLength: Boolean =
(context.lengthKind._eq_(LengthKind.Explicit)) ||
(context.isSimpleType &&
(context.lengthKind._eq_(LengthKind.Implicit)) &&
(context.impliedRepresentation._eq_(Representation.Text)))

override lazy val unparser: Unparser = {
if (context.isOutputValueCalc) {
new ElementOVCSpecifiedLengthUnparser(
Expand All @@ -122,12 +132,7 @@ class ElementCombinator(
eAfterUnparser,
context.ovcCompiledExpression
)
} else if (
(context.lengthKind._eq_(LengthKind.Explicit)) ||
(context.isSimpleType &&
(context.lengthKind._eq_(LengthKind.Implicit)) &&
(context.impliedRepresentation._eq_(Representation.Text)))
) {
} else if (isSpecifiedLength) {

new ElementSpecifiedLengthUnparser(
context.erd,
Expand All @@ -143,6 +148,26 @@ class ElementCombinator(
}
}

private lazy val eBuilder: InfosetBuilder = {
if (eValue.isEmpty) {
NadaInfosetBuilder
} else {
eValue.builder
}
}
private lazy val eRepTypeBuilder: InfosetBuilder = repTypeElementGram.builder

// Shares the memoized unparser above for unparseBegin/unparseEnd, so
// build and the unparse see identical node-creation behavior.
override lazy val builder: InfosetBuilder = {
if (context.isOutputValueCalc || isSpecifiedLength) {
val eu = unparser.asInstanceOf[ElementUnparserBase]
val contentBuilder = eRepTypeBuilder.orElse(eBuilder)
new ElementInfosetBuilder(context.erd, eu, contentBuilder)
} else {
subComb.builder
}
}
}

case class ElementUnused(ctxt: ElementBase)
Expand Down Expand Up @@ -374,6 +399,14 @@ class ElementParseAndUnspecifiedLength(
new ElementUnparserInputValueCalc(context.erd, uSetVar)
}
}

// Shares the memoized unparser above for unparseBegin/unparseEnd, so
// build and the unparse see identical nilled/OVC/IVC node-creation behavior.
override lazy val builder: InfosetBuilder = {
val eu = unparser.asInstanceOf[ElementUnparserBase]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, I would rather see the same logic rather than type matching. It's much easier to visually verify the conditionalsare the same rather than figuring out which Unparsers are created.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one doesn't pattern match but uses the elementUnparser to call unparseBegin/End

val contentBuilder = eRepTypeBuilder.orElse(eBuilder)
new ElementInfosetBuilder(context.erd, eu, contentBuilder)
}
}

abstract class ElementCombinatorBase(
Expand Down Expand Up @@ -449,4 +482,8 @@ abstract class ElementCombinatorBase(

def unparser: Unparser

lazy val eBuilder: InfosetBuilder = eGram.builder

lazy val eRepTypeBuilder: InfosetBuilder = repTypeElementGram.builder

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ package org.apache.daffodil.core.grammar.primitives
import org.apache.daffodil.core.dsom.ModelGroup
import org.apache.daffodil.core.grammar.Gram
import org.apache.daffodil.core.grammar.Terminal
import org.apache.daffodil.runtime1.infoset.HiddenGroupInfosetBuilder
import org.apache.daffodil.runtime1.infoset.InfosetBuilder
import org.apache.daffodil.runtime1.processors.parsers.HiddenGroupCombinatorParser
import org.apache.daffodil.runtime1.processors.parsers.Parser
import org.apache.daffodil.runtime1.processors.unparsers.Unparser
Expand All @@ -34,4 +36,5 @@ final class HiddenGroupCombinator(ctxt: ModelGroup, body: Gram)
override lazy val unparser: Unparser =
new HiddenGroupCombinatorUnparser(ctxt.modelGroupRuntimeData, body.unparser)

override lazy val builder: InfosetBuilder = HiddenGroupInfosetBuilder(body.builder)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import org.apache.daffodil.core.dsom.*
import org.apache.daffodil.core.grammar.Terminal
import org.apache.daffodil.core.layers.LayerSchemaCompiler
import org.apache.daffodil.lib.util.Misc
import org.apache.daffodil.runtime1.infoset.InfosetBuilder
import org.apache.daffodil.runtime1.infoset.SequenceInfosetBuilder
import org.apache.daffodil.runtime1.processors.parsers.LayeredSequenceParser
import org.apache.daffodil.runtime1.processors.parsers.Parser as DaffodilParser
import org.apache.daffodil.runtime1.processors.unparsers.Unparser as DaffodilUnparser
Expand All @@ -47,4 +49,11 @@ case class LayeredSequence(sq: SequenceGroupTermBase, bodyTerm: SequenceChild)

override lazy val unparser: DaffodilUnparser =
new LayeredSequenceUnparser(srd, bodyUnparser)

// The layer transform builds no infoset events, but this is still a one-child
// sequence position: it must push/pop bodyTerm's TRD and advance the
// group index like any sequence child, or next-element resolution on
// the shared InfosetInputter breaks.
override lazy val builder: InfosetBuilder =
SequenceInfosetBuilder(Array(bodyTerm.sequenceChildBuildInfo))
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import org.apache.daffodil.core.dsom.ElementBase
import org.apache.daffodil.core.grammar.Gram
import org.apache.daffodil.core.grammar.Terminal
import org.apache.daffodil.lib.exceptions.Assert
import org.apache.daffodil.runtime1.infoset.InfosetBuilder
import org.apache.daffodil.runtime1.infoset.NilOrContentInfosetBuilder
import org.apache.daffodil.runtime1.processors.parsers.ComplexNilOrContentParser
import org.apache.daffodil.runtime1.processors.parsers.SimpleNilOrValueParser
import org.apache.daffodil.unparsers.runtime1.ComplexNilOrContentUnparser
Expand Down Expand Up @@ -59,4 +61,8 @@ case class ComplexNilOrContent(ctxt: ElementBase, nilGram: Gram, contentGram: Gr
override lazy val unparser =
ComplexNilOrContentUnparser(ctxt.erd, nilUnparser, contentUnparser)

// A nilled complex element has no children to build; nilled-ness is only
// known once the node exists, so this needs a real runtime check, not a
// static pass-through.
override lazy val builder: InfosetBuilder = NilOrContentInfosetBuilder(contentGram.builder)
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import org.apache.daffodil.lib.schema.annotation.props.gen.LengthKind
import org.apache.daffodil.lib.schema.annotation.props.gen.OccursCountKind
import org.apache.daffodil.lib.schema.annotation.props.gen.Representation
import org.apache.daffodil.runtime1.dpath.NodeInfo
import org.apache.daffodil.runtime1.infoset.InfosetBuilder
import org.apache.daffodil.runtime1.infoset.SequenceChildInfosetBuildInfo
import org.apache.daffodil.runtime1.processors.parsers.*
import org.apache.daffodil.unparsers.runtime1.*

Expand Down Expand Up @@ -69,6 +71,7 @@ abstract class SequenceChild(protected val sq: SequenceTermBase, child: Term, gr

protected lazy val childParser = child.termContentBody.parser
protected lazy val childUnparser = child.termContentBody.unparser
protected lazy val childBuilder: InfosetBuilder = child.termContentBody.builder

final override lazy val parser = sequenceChildParser
final override lazy val unparser = sequenceChildUnparser
Expand All @@ -82,6 +85,9 @@ abstract class SequenceChild(protected val sq: SequenceTermBase, child: Term, gr
final lazy val optSequenceChildUnparser: Option[SequenceChildUnparser] =
if (childUnparser.isEmpty) None else Some(unparser)

final lazy val sequenceChildBuildInfo: SequenceChildInfosetBuildInfo =
SequenceChildInfosetBuildInfo(unparser, childBuilder)

/**
* There's only parse result helpers here, so let's abbreviate
*/
Expand Down
Loading
Loading