Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ import org.apache.daffodil.core.dsom.walker.ChoiceView
import org.apache.daffodil.core.grammar.ChoiceGrammarMixin
import org.apache.daffodil.lib.schema.annotation.props.Found
import org.apache.daffodil.lib.schema.annotation.props.gen.ChoiceAGMixin
import org.apache.daffodil.lib.schema.annotation.props.gen.ChoiceLengthKind
import org.apache.daffodil.lib.schema.annotation.props.gen.Choice_AnnotationMixin
import org.apache.daffodil.lib.schema.annotation.props.gen.LengthUnits
import org.apache.daffodil.lib.schema.annotation.props.gen.YesNo

/**
Expand Down Expand Up @@ -103,6 +105,7 @@ abstract class ChoiceTermBase(
requiredEvaluationsIfActivated(noBranchesFound)
requiredEvaluationsIfActivated(branchesAreNonOptional)
requiredEvaluationsIfActivated(branchesAreNotIVCElements)
requiredEvaluationsIfActivated(checkEndOfParentRestrictions())

final protected lazy val optionChoiceDispatchKeyRaw =
findPropertyOption("choiceDispatchKey", expressionAllowed = true)
Expand Down Expand Up @@ -159,7 +162,7 @@ abstract class ChoiceTermBase(
* Open issues:
* 1) Is alignment or leading/trailing skip to be considered syntax. Alignment might not be there.
* 2) What about an empty sequence that only carries statement annotations such as dfdl:assert or
* dfdl:setVariable
* dfdl:setVariable
*
* This latter need to be allowed, because while they do not have known required syntax they do
* have to be executed for side-effect.
Expand Down Expand Up @@ -189,6 +192,33 @@ abstract class ChoiceTermBase(
}
assuming(branchesOk.forall { x => x })
}.value

lazy val optMyEffectiveLengthUnits: Option[LengthUnits] =
this match {
case self: ChoiceTermBase if self.choiceLengthKind == ChoiceLengthKind.Explicit =>
Some(LengthUnits.Bytes)
case _ => None
}

def checkEndOfParentRestrictions() = {
val parent = this
val eopChildren = this.childrenEndOfParent
if (eopChildren.isEmpty) {} else {
parent match {
case c: ChoiceTermBase if c.choiceLengthKind == ChoiceLengthKind.Implicit => {
schemaDefinitionWhen(
c.hasTerminator,
"element is specified as dfdl:lengthKind=\"endOfParent\", but is in a choice with a dfdl:terminator."
)
schemaDefinitionWhen(
c.trailingSkip != 0,
"element is specified as dfdl:lengthKind=\"endOfParent\", but is in a choice with a non-zero dfdl:trailingSkip."
)
}
case _ => // do nothing
}
}
}
}

object Choice {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,8 @@ trait LocalElementMixin extends ParticleMixin with LocalElementGrammarMixin {
else if (representation =:= Representation.Binary) true
else false
}
case LengthKind.EndOfParent if isComplexType =>
notYetImplemented("lengthKind='endOfParent' for complex type")
case LengthKind.EndOfParent =>
notYetImplemented("lengthKind='endOfParent' for simple type")
// we can rarely statically know if an endOfParent element must have non-zero length
case LengthKind.EndOfParent => false
}
res
}.value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import org.apache.daffodil.lib.iapi.Diagnostic
import org.apache.daffodil.lib.iapi.UnitTestSchemaSource
import org.apache.daffodil.lib.oolag.OOLAG
import org.apache.daffodil.lib.schema.annotation.props.LookupLocation
import org.apache.daffodil.lib.schema.annotation.props.gen.LengthUnits
import org.apache.daffodil.lib.util.TransitiveClosure
import org.apache.daffodil.lib.xml.*

Expand Down Expand Up @@ -116,6 +117,7 @@ final class SchemaSet private (

requiredEvaluationsAlways(root)
requiredEvaluationsAlways(checkForDuplicateTopLevels())
requiredEvaluationsAlways(root.checkEndOfParentRestrictions(LengthUnits.Characters))

lazy val resolver = DFDLCatalogResolver.get

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import org.apache.daffodil.lib.schema.annotation.props.gen.OccursCountKind
import org.apache.daffodil.lib.schema.annotation.props.gen.SeparatorPosition
import org.apache.daffodil.lib.schema.annotation.props.gen.SequenceKind
import org.apache.daffodil.lib.schema.annotation.props.gen.TestKind
import org.apache.daffodil.lib.schema.annotation.props.gen.YesNo
import org.apache.daffodil.lib.xml.RefQName
import org.apache.daffodil.lib.xml.XMLUtils
import org.apache.daffodil.runtime1.layers.LayerRuntimeData
Expand Down Expand Up @@ -105,6 +106,7 @@ abstract class SequenceGroupTermBase(xml: Node, lexicalParent: SchemaComponent,
requiredEvaluationsIfActivated(checkValidityOccursCountKind)
requiredEvaluationsIfActivated(checkIfNonEmptyAndDiscrimsOrAsserts)
requiredEvaluationsIfActivated(checkIfMultipleChildrenWithSameName)
requiredEvaluationsIfActivated(checkEndOfParentRestrictions())

protected def apparentXMLChildren: Seq[Node]

Expand Down Expand Up @@ -270,6 +272,38 @@ abstract class SequenceGroupTermBase(xml: Node, lexicalParent: SchemaComponent,
case SequenceKind.Unordered => false
}

def checkEndOfParentRestrictions() = {
val parent = this
val eopChildren = this.childrenEndOfParent
if (eopChildren.isEmpty) {} else {
parent match {
case s: SequenceTermBase => {
schemaDefinitionWhen(
s.separatorPosition == SeparatorPosition.Postfix,
"element is specified as dfdl:lengthKind=\"endOfParent\", but is in a sequence with dfdl:separatorPosition defined as 'postfix'."
)
schemaDefinitionWhen(
s.sequenceKind != SequenceKind.Ordered,
"element is specified as dfdl:lengthKind=\"endOfParent\", but is in a sequence with dfdl:sequenceKind defined as 'unordered'."
)
schemaDefinitionWhen(
s.hasTerminator,
"element is specified as dfdl:lengthKind=\"endOfParent\", but is in a sequence with a dfdl:terminator."
)
schemaDefinitionWhen(
s.realElementChildren.exists(e => e.floating == YesNo.Yes),
"element is specified as dfdl:lengthKind=\"endOfParent\", but is in a sequence with elements defining dfdl:floating='yes'."
)
schemaDefinitionWhen(
s.trailingSkip != 0,
"element is specified as dfdl:lengthKind=\"endOfParent\", but is in a sequence with a non-zero dfdl:trailingSkip."
)
}
case null => // do nothing
}
}
}

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@ import org.apache.daffodil.lib.iapi.WarnID
import org.apache.daffodil.lib.schema.annotation.props.Found
import org.apache.daffodil.lib.schema.annotation.props.NotFound
import org.apache.daffodil.lib.schema.annotation.props.SeparatorSuppressionPolicy
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.YesNo
import org.apache.daffodil.lib.schema.annotation.props.gen.*

/**
* Mixin for objects that are shared, but have consistency checks to be run
Expand Down Expand Up @@ -96,6 +94,17 @@ trait Term
requiredEvaluationsIfActivated(defaultPropertySources)
requiredEvaluationsIfActivated(termChecks)

final lazy val childrenEndOfParent: Seq[ElementBase] = LV(Symbol("childrenEndOfParent")) {
val gms = termChildren
val chls = gms.flatMap {
case eb: ElementBase if eb.lengthKind == LengthKind.EndOfParent => Seq(eb)
case eb: ElementBase => Nil
case c: Choice => Nil
case mg: ModelGroup => mg.childrenEndOfParent
}
chls
}.value

private lazy val termChecks = {
statements.foreach { _.checkTerm(this) }
}
Expand Down Expand Up @@ -269,6 +278,26 @@ trait Term
.getOrElse(false)
}

final lazy val immediatelyEnclosingParentForEOPElem: Option[Term] = {
val p = optLexicalParent.flatMap {
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.

Note that I think lexical parents does not extend past global decls, so if a global decl has endOfParent then I'm not sure we will correctly check EOP restrictions for anything that references that decl. I'm wondering if the checks need to go down instead up?

For example, maybe an element needs to check if it has properties that would disallow children with lengthKind EOP and if so check if any children have are EOP? Or check if any immediate children have EOP, and if so then check if they are compatible?

case e: ElementBase => Some(e)
case ge: GlobalElementDecl => Some(ge.asRoot)
case s: SequenceTermBase => s.immediatelyEnclosingParentForEOPElem
case c: ChoiceTermBase => Some(c)
case ct: ComplexTypeBase => {
ct.optLexicalParent.flatMap {
case e: ElementBase => Some(e)
case ge: GlobalElementDecl => Some(ge.asRoot)
case _ => {
None
}
}
}
case _ => None
}
p
}

final lazy val immediatelyEnclosingGroupDef: Option[GroupDefLike] = {
optLexicalParent.flatMap { lexicalParent =>
val res: Option[GroupDefLike] = lexicalParent match {
Expand Down Expand Up @@ -562,4 +591,21 @@ trait Term
}
}

final protected lazy val realElementChildren: Seq[ElementBase] = {
termChildren.flatMap {
case eb: ElementBase => Seq(eb)
case c: Choice => Nil
case mg: ModelGroup => mg.realElementChildren
}
}

lazy val flattenedChildren: IndexedSeq[Term] = termChildren.flatMap { c =>
c match {
case eb: ElementBase => IndexedSeq(eb)
case mg: ModelGroup if mg.groupMembers.isEmpty => IndexedSeq(mg)
case s: SequenceTermBase => s.flattenedChildren
case c: ChoiceTermBase => c.flattenedChildren
case _ => Nil
}
}.toIndexedSeq
}
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,11 @@ trait AlignedMixin extends GrammarMixin { self: Term =>
}
case LengthKind.Delimited => encodingLengthApprox
case LengthKind.Pattern => encodingLengthApprox
case LengthKind.EndOfParent => LengthMultipleOf(1) // NYI
case LengthKind.EndOfParent =>
// technically the alignment of an EndOfParent element would be the
// alignment of its parent minus our current alignment (i.e alignment of
// prior sibs) but since nothing can follow
LengthMultipleOf(1)
// If an element is lengthKind="prefixed", the element's length is the length
// of the value of the prefix element, which can't be known till runtime
case LengthKind.Prefixed => LengthMultipleOf(1) // NYI (see DAFFODIL-3066)
Expand Down
Loading
Loading