Repository navigation
Define isKnownNonZeroLength for delimiters - #1729
aaronmbauman wants to merge 1 commit into
Conversation
|
@stevedlawrence or @olabusayoT would appreciate a review of this |
|
@aaronmbauman, yes, I plan to get to it next week. Thanks for the PR! |
olabusayoT
left a comment
There was a problem hiding this comment.
Great work...some changes for readability and a comment correctness check
| </xs:complexType> | ||
| </xs:element> | ||
|
|
||
| <xs:element name="entityAloneInList"> |
There was a problem hiding this comment.
maybe these elements should be prefixed with possibleZeroLenEntity instead of just entity
There was a problem hiding this comment.
also this test elem should mention initatedContent so maybe possibleZeroLenEntityWithInitiatedContentYes (long but clear)
There was a problem hiding this comment.
also also they should probably be in a different schema instead of emptyInitiator as they are not empty
There was a problem hiding this comment.
Agreed, the old names didn't say much. They now start with possibleZeroLenEntity and say which initiatedContent value they use. I also pulled them out into their own possibleZeroLenEntityInitiator schema, since you're right that they aren't empty initiators.
| </xs:complexType> | ||
| </xs:element> | ||
|
|
||
| <xs:element name="entitiesNotAlone"> |
There was a problem hiding this comment.
maybe renamed to multiplePossibleNonZeroEntities
There was a problem hiding this comment.
Went with multiplePossibleZeroLenEntitiesWithInitiatedContentYes. I think you meant ZeroLen here, since %WSP*;%WSP*; can match nothing, but let me know if not.
| </xs:complexType> | ||
| </xs:element> | ||
|
|
||
| <xs:element name="migrateToInitiatedContentNo"> |
There was a problem hiding this comment.
I don't understand the migrate prefix, should be possibleZeroLenEntityWithInitiatedContentNo or something like that
There was a problem hiding this comment.
Fair, "migrate" only made sense if you'd read the commit message. It's possibleZeroLenEntityWithInitiatedContentNo now.
| </xs:complexType> | ||
| </xs:element> | ||
|
|
||
| <xs:element name="migrateDropZeroLengthAlternative"> |
There was a problem hiding this comment.
change naming of this as well
There was a problem hiding this comment.
Renamed to nonZeroLenInitiatorWithInitiatedContentYes.
| </tdml:errors> | ||
| </tdml:parserTestCase> | ||
|
|
||
| <tdml:parserTestCase name="emptyInitiator5" |
There was a problem hiding this comment.
same with the test names
There was a problem hiding this comment.
The test names match the element names now.
| // Bug DAFFODIL-2132 is why isModelGroupRepNonZeroLength is incorrect in the above case. | ||
| // | ||
| // Assert.invariant(isModelGroupRepPossiblyZeroLength && !isModelGroupRepNonZeroLength) | ||
| Assert.invariant(isModelGroupRepPossiblyZeroLength && !isModelGroupRepNonZeroLength) |
There was a problem hiding this comment.
I didn't see any changes to isModelGroupRepPossiblyZeroLength, so the comment there probably reads incorrectly
There was a problem hiding this comment.
You're right, that doc still described the old behavior. I rewrote it to match what SequenceChild actually computes.
There was a problem hiding this comment.
Also sequenceChild.scala has a comment referencing the 2132 bug, I'd do a search just to make sure all comments are taken care of/updated
There was a problem hiding this comment.
The DAFFODIL-2132 block in SequenceChild.scala was removed in this PR; it shows as deleted lines inside isModelGroupRepPossiblyZeroLength. Two other DAFFODIL-2132 comments were also removed: the FIXME on hasFraming in ModelGroup.scala, and the note on the commented-out assert in checkModelGroupZL, which is now enabled again. I searched the repo for other references: the only remaining DAFFODIL-2132 mentions are in the new SequenceGroupZLFraming tests, and I didn't find any other comments that still describe the old behavior.
ModelGroup.hasFraming answers whether a delimiter is written in the schema, not whether it occupies bits in the data stream. DFDL spec section 9.2 defines framing as the parts of the data stream "which are present and may be necessary to determine the length or position of the content", so a %ES; or %WSP*; delimiter, which matches zero-length data, is not framing. hasFraming short-circuits hasKnownRequiredSyntax, so a group framed only by one of those counts as definitely non-zero-length and is denied separator suppression: parsing raises a spurious "Failed to find infix separator" error, and unparsing writes a separator that does not belong. The zero-length test now runs per literal in the delimiter list, and splits in two. The framing analysis asks whether a literal can match zero-length data, which covers "X %ES;" and "%WSP*;%WSP*;" alike. The dfdl:initiatedContent check asks the narrower question section 12.2 asks, whether an entity appears "alone as one of the string literals in the list", so it diagnoses only what the spec restricts and leaves the rest to the runtime check in DelimiterParsers. Those same predicates now serve LocalElementMixin.couldBeMissing, which no longer analyzes delimiters by hand. A delimiter from an expression is not analyzed; the unknown case counts as zero-length matching, which is what mil-std-2045 needs. This covers dfdl:initiator and dfdl:terminator. The issue notes that the predicate can also be false for separators where lengthKind is not 'delimited', but a constant %ES; or %WSP*; separator is already a Schema Definition Error from the delimiter cooker, and giving the separator the same predicate changed no observable behavior. Not addressed here. checkModelGroupZL asserts that a model group which parsed zero length was analyzed as possibly zero length. That could not hold while a %ES; delimiter counted as framing, so the assert has been commented out since 2018. It is enabled again. Deprecation/Compatibility: - A schema with dfdl:initiatedContent='yes' whose dfdl:initiator lists %ES; or %WSP*; as one of its alternatives, such as "P %ES;", is now rejected with a Schema Definition Error, as the DFDL spec requires. Such schemas used to compile and parse. To migrate, set dfdl:initiatedContent='no', or drop the zero-length alternative from the initiator. - A sequence or choice group whose only initiator or terminator matches zero-length data, such as %ES; or %WSP*;, no longer counts as occupying space in the data. When such a group is last in a sequence, its separator may now be omitted on parse, and is no longer written on unparse. Data that failed with "Failed to find infix separator" now parses, and unparsed output no longer carries that trailing separator, so files compared against previously generated output will differ. DAFFODIL-2132
03bb776 to
6830c4f
Compare
olabusayoT
left a comment
There was a problem hiding this comment.
+1 with fixes; some more comment updates
| // Bug DAFFODIL-2132 is why isModelGroupRepNonZeroLength is incorrect in the above case. | ||
| // | ||
| // Assert.invariant(isModelGroupRepPossiblyZeroLength && !isModelGroupRepNonZeroLength) | ||
| Assert.invariant(isModelGroupRepPossiblyZeroLength && !isModelGroupRepNonZeroLength) |
There was a problem hiding this comment.
Also sequenceChild.scala has a comment referencing the 2132 bug, I'd do a search just to make sure all comments are taken care of/updated
What
ModelGroup.hasFraminganswers whether a delimiter is written in the schema,not whether it occupies bits in the data stream. A
%ES;or%WSP*;delimitermatches zero-length data, so per DFDL spec section 9.2 it is not framing.
Because
hasFramingshort-circuitshasKnownRequiredSyntax, a group framed onlyby such a delimiter counts as definitely non-zero-length and is denied separator
suppression: parsing raises a spurious
Failed to find infix separator, andunparsing writes a trailing separator that does not belong.
The zero-length test now runs per literal in the delimiter list, and splits in two:
isKnownCanMatchEmptyStringfor the framing analysis, andhasZeroLengthEntityAlonefor the narrower restriction section 12.2 actually states.
Evidence
The same TDML suite run against
mainand this branch (TestSequenceGroupZLFraming):esInit_absent,esTerm_absent,wspInit_absent,esChoice_absent,esInitList,wspWspInit,esTermList,exprTermRealFailed to find infix separatoresInit_absent_unparse,wspWspInit_unparseoutput data length 2 for 'X,'Xctl_*,esInit_present,constTermReal, ...Every case has a control that differs only in the delimiter on the inner model
group, so a control failure means the harness is broken rather than Daffodil.
Full
daffodil-testagainst this commit: 4725 tests, 0 failures (4724 passed,1 skipped, 115 ignored), on Ubuntu 22.04 / JDK 17 / Scala 3.3.7.
Notable for reviewers
checkModelGroupZL: it asserts that a model group which parsed zero lengthwas analyzed as possibly zero length. That could not hold while a
%ES;delimiter counted as framing, so the assert was commented out in 53d6b4f
(2018). It is enabled again.
dfdl:initiatedContent='yes': an initiator list such as"P %ES;"is now aSchema Definition Error, as section 12.2 requires. Such schemas used to compile
and parse, so the commit message carries a Deprecation/Compatibility note with
a migration path, covered by
possibleZeroLenEntityWithInitiatedContentNoandnonZeroLenInitiatorWithInitiatedContentYes.known to occupy bits", which accepts input previously rejected. That is what
mil-std-2045 needs. It cannot be narrowed statically, since an expression
returning
%ES;and one returning a real delimiter are indistinguishable atcompile time.
AlignedMixinkeeps usinghasSeparator. A delimiterthat can match zero length can also match non-zero length, so asserting zero
length there would risk silent misalignment.
On separators
The issue's requirement is to define
isKnownNonZeroLengthfor delimiters so theterm-level calculations are correct, which this PR does for initiators and
terminators. It also notes the predicate can be false for separators where
lengthKind is not
'delimited'. I tried that:SeparatorCookerisDelimiterCookerNoES, so a constant%ES;/%WSP*;separator is already an SDE andnever reaches the framing analysis, and wiring the same predicate into the separator
paths changed no observable behavior across four schema shapes, so I backed it out
rather than ship an untestable change.
Also found while testing, unrelated:
dfdl:separator="%WSP*;%WSP*;"passes thecooker and then aborts in the delimiter DFA (
Assert.impossibleCase,dfa/Rules.scala:117) onmaintoo. I can file that if you want it tracked.