I haven't completed this note yet, but as I am having to shift gears for a few 
days, I am providing my current state of thinking around what's actually 
required here for posterity/amusement, and to share what I anticipate will 
actually be a great improvement to Daffodil, but non-trivial to implement.


Comments are welcome. This needs to turn into a plan/design for the fix.


-----------------------


Design/Redesign Issues for Sequences with Separators

We recently found issues associated with nested separators, and with 
dfdl:separatorSuppressionPolicy 'trailing' and 'trailingStrict'.

It's not possible to get the IBM4690TLog DFDL schema to work on Daffodil until 
these are fixed, and the bug with nested separators also has impact on the DFDL 
schema for USMTF.

Fixing these is going to require some refactoring and reimplementation starting 
from the daffodil-core grammar package.

The Problems

The grammar has some mistakes in it that make it impossible to properly 
implement.

* The first place we look at dfdl:separatorSuppressionPolicy is in the grammar 
production for arrayContentsWithSeparators. This is incorrect because separator 
suppression can apply to terms in a sequence that are not related by being part 
of an array.

That said, it is not terribly important (from a bug standpoint) to support 
separator suppression except for when there are repeating/optional elements 
involved.

The bigger problem is:

* The separatedForArrayPosition(body) method composes together the separators 
with the term following them that is separated. This prevents independent 
orchestration of the parse of the separator with that of the following element. 
It is depending on the parse of the separator failing, and that causing 
backtracking to try subsequent alternatives, as a way of identifying which 
delimiter was actually found. This could be made to work, but it requires 
changes to the way separators and all delimiters really, are parsed.

The current design, where separators are composed together into the child 
terms, makes implementation of trailing separator suppression basically 
impossible.

Fact is, all of this was designed to recursively compose by just composing 
parsers from other parsers, but that turns out to be naive because it doesn't 
provide enough structure to issue really good clear diagnostics, and it is too 
hard to tell what is going on.

-----------------------------------------------

A sequence combinator should be laid down depending on whether the sequence has 
separators or not, and whether it has trailing separator suppression or not.

That is, the decision we see being made in arrayContentsWithSeparators, needs 
to be made in SequenceGrammarMixin in the orderedSequenceContent production. 
(When implemented unorderedSequenceContent may be similar.)

The kind of sequence combinator being laid down should depend on separators or 
not right at that point, and the sequence combinator for the hasSeparators case 
will have a rich set of parameters.

The asTermInSequence, and asTermInArray both need to go away. Instead of 
combining all these characteristics into one composed term that we 
parse/unparse, with separators embedded into it, whether it is even represented 
embedded in it, etc. Instead we need an array of tuples, each tuple is a 
(termContentBody, termRuntimeData) where termRuntimeData lets us know if the 
term isNotRepresented, is scalar, or is array, and what the max/min occurs are, 
etc.

So the SeparatedSequenceCombinator then must orchestrate everything about 
prefix/posfix separators, and the loops needed for repeating/array/optional 
terms.

I expect we will have at least

SeparatedSequenceCombinator
UnseparatedSequenceCombinator

I believe the entire LocalElementGrammarMixin will have to be 
refactored/rewritten. I think every method will likely have to be removed.

All these methods have to go away:
separatedEmpty
separatedRecurring
StopValue - which isn't implemented anyway, so it's just clutter.
recurrance
separatedContentWithMinUnboundedWithoutTrailingEmpties
separatedContentWithMinAndMaxWithoutTrailingEmpties
separatedContentWithMinUnbounded
separatedContentWithMinAndMax
separatedContentZeroToUnbounded
separatedContentAtMostNWithoutTrailingEmpties
stopValueSize
separatedContentExactlyN
separatedContentExactlyNComputed
arrayContents
arrayContentsNoSeparators
arrayContentsWithSeparators
contentUnbounded

Instead, LocalElementGrammarMixin - which is all about recurrance/optionality - 
will be in service of several kinds of sequence combinators. Its methods will 
provide the things needed in order for proper compilation of the parameters 
given to a sequence combinator. It may not be a grammar mixin anymore. It may 
just become methods on LocalElementMixin.

The chosen sequence combinator must interoperate with the repeat combinators 
when dealing with separators. Or alternatively, it must subsume their 
functionality.

---------------------------
The below is probably NOT true:

Interplay of field isolation that scans for a value, ending at a delimiter, 
vs., after that, we parse the delimiter again, is where we get into trouble.

We're depending on backtracking - when it tries to "reparse" the separator, but 
doesn't find the separator, then backtracking causes the parser to then again 
parse the field, but then try the next outward possible terminating markup. 
Until something parses successfully.

------------------

TODO and FIXME comments in the DelimiterText code suggest this is not being 
done properly - elements that could NOT be terminated by the sequence's 
terminator are nevertheless being scanned with the sequence's terminator as one 
of the possible delimiters.  (Though the semantics of nested delimiters are a 
bit unclear here. For example, if a simple type element has a terminator, then 
one would *think* that one would not need to escape the enclosing group 
separator appearing within it, because the only thing that matters is the 
terminator; however, this is not the case. One must still escape the enclosing 
separator. (This is the agreed upon view of the DFDL Workgroup. I am not sure 
it is right... but we may have to introduce a different lengthKind='delimited2' 
variation to provide the alternate behavior where a terminator on a simple 
element eliminates the need to escape anything except that terminator.

-----------------------

If we create new Sequence combinators and eliminate the composition of 
separators into child term parsers, we can better orchtestrate how the 
delimited term parsers identify a simple-type element, scanning until some 
terminating markup is found, with the testing for whether what was found is the 
expected separator or not.

That is, we can eliminate the redundant parse of the delimiter that happens 
currently - first to isolate the element value, second to consume the 
delimiter, verifying that it is an expected separator, etc.

Reply via email to