You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@daffodil.apache.org by "Olabusayo Kilo (Jira)" <ji...@apache.org> on 2026/08/13 15:51:00 UTC

[jira] [Updated] (DAFFODIL-3094) Failure when prefix separator is not backtracked after repeating complex element stops

     [ https://issues.apache.org/jira/browse/DAFFODIL-3094?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Olabusayo Kilo updated DAFFODIL-3094:
-------------------------------------
    Summary: Failure when prefix separator is not backtracked after repeating complex element stops  (was: Failure when prefix separator is not backtracked after repeating complex element ends)

> Failure when prefix separator is not backtracked after repeating complex element stops
> --------------------------------------------------------------------------------------
>
>                 Key: DAFFODIL-3094
>                 URL: https://issues.apache.org/jira/browse/DAFFODIL-3094
>             Project: Daffodil
>          Issue Type: Bug
>    Affects Versions: 4.2.0
>            Reporter: Olabusayo Kilo
>            Priority: Major
>             Fix For: 4.3.0
>
>         Attachments: data.dat, test.xsd
>
>
> Schema:
> {code:xml}
>   <xs:element name="r">
>     <xs:complexType>
>       <xs:sequence dfdl:separatorPosition="prefix" dfdl:separator="/ %NL;/" dfdl:terminator="%NL;">
>         <xs:element name="foo" type="xs:string"/>
>         <xs:element name="GroupOfFields" maxOccurs="5" dfdl:occursCountKind="implicit">
>           <xs:complexType>
>             <xs:sequence dfdl:separator="/ %NL;/" dfdl:separatorSuppressionPolicy="never">
>               <xs:element name="c">
>                 <xs:complexType>
>                   <xs:choice>
>                     <xs:element name="bar" type="xs:string" dfdl:initiator="R:"/>
>                     <xs:element name="ban" type="xs:string" dfdl:initiator="N:"/>
>                   </xs:choice>
>                 </xs:complexType>
>               </xs:element>
>             </xs:sequence>
>           </xs:complexType>
>         </xs:element>
>         <xs:element name="baz" type="xs:string" minOccurs="0" />
>       </xs:sequence>
>     </xs:complexType>
>   </xs:element>
> {code}
> Data:
> {code:none}
> /1/N:ABC/R:DEF/N:HIJ/R:LMN/2
> {code}
> In the above, an outer sequence is separatorPosition="prefix" and a complex element, GroupOfFields, has occursCountKind="implicit", minOccurs=1 and maxOccurs=5, and the data has exactly 4 real GroupOfFields occurrences (ABC/DEF/HIJ/LMN) followed by /2; that trailing / belongs to baz's own prefix separator, and 2 is baz's value. 
>  
> Bug: since maxOccurs=5 and only 4 occurred, the parser must speculatively attempt occurrence #5 (position 5 = maxRepeats, so RequiredOptionalStatus.Optional). It: 
>   1. Parses the prefix separator / before slot 5 and succeeds (bits 208→216). 
>   2. Tries the child (GroupOfFields's inner choice bar/ban) and both initiators fail, 0 bits consumed (isZL=true). 
>  
> That failure goes through anyTypeElementFailedParseAttemptStatus (SequenceChildParseResultHelper.scala:190-218):
> {code:scala}
> case _: RequiredOptionalStatus.Optional if isZL => ParseAttemptStatus.AbsentRep 
> {code}
> AbsentRep is documented as "backtrack any elements created but retain bit position" which is exactly what parseOneInstanceWithMaybePoU does (SequenceParserBases.scala:413-421): it resets to the PoU (undoing the infoset side effects) but then explicitly forces the bit position back forward past the separator (pstate.dataInputStream.setBitPos0b(currentPos)), i.e. it keeps the separator consumed. 
>  
> That convention is correct for a simple type whose legitimate empty representation is genuinely zero-length (classic "two adjacent separators = an empty positional slot" idiom). But here the child is a complex type wrapping a mandatory xs:choice with two required initiators; there is no such thing as a valid zero-length match for it. The ZL failure isn't "the slot is legitimately empty," it's "there is no occurrence 5 at all." Keeping the separator steals the / that rightfully belongs to baz's own prefix separator, so baz's separator search then fails, and ultimately the sequence terminator search fails too. 
> anyTypeElementFailedParseAttemptStatus conflates two different situations under one AbsentRep result: "legitimately empty content" vs. "total structural failure with nothing consumed"; only the former should retain the separator. The complex-type/model-group path currently has no static "can this ever legitimately be zero-length" flag analogous to isEmptyRepZeroLength (which simple types have) or isModelGroupRepPossiblyZeroLength (which exists for model groups used directly as sequence children, but isn't threaded into element-with-complex-type result helpers). 
>  
> This is a real design gap the code needs a way to know, for a complex-typed array element, whether its content can ever be validly zero-length, and use that to decide AbsentRep (retain separator) vs. a status that forces full backtrack (give the separator back). 



--
This message was sent by Atlassian Jira
(v8.20.10#820010)