recursive (only tail recursion) causes problems because context of rule
call causes endless recursion in getNextElementsInContext()
example:
S: {S} $$ p0 $$?=> 's'
| $$ p1 $$?=> 's' s=S
;
solution: added set of visited rule calls to parameter list, skip rule
call if it was already handled by another recursion
added test cases
when context analysis is needed and an element in context has multiple
cardinality and contains empty paths (e.g. ?-quantified) the quantified
element will be recursed endlessly without the token analysis path even
being done (since there is always an empty path) - this also applies to
unordered groups.
recognizing empty paths is not trivial because of recursive rules.
solution: save "call stack" (actually just a set of visited elements)
during recursions in context analysis. if an element is seen multiple
times we check if there is any progress in the analysis paths. if not
this is an endless recursion
-> throw exception
non-trivial quantifiers in context path are not handled correctly.
change to getNextElementsInContext():
add non-trivially quantified elements in path (except first element
because of potential endless recursion) to result set
when the following context element is optional, the minimal sequence is
not going to get bigger. in this case further context analysis is
blocked by the exception.
=> removed exception
also made sure getNextElementsInContext() won't return non-token,
non-compound elements like actions or predicates.
is necessary because otherwise the identity analysis might not be able
to detect if paths are identical up to the token limit (which should
cause an error)
testRecursiveRuleCallingAlternative_expectCorrectGuard
guard for nested alternatives might not be optimal if the positions that
discriminate in the first alternatives is different from the positions
needed on the next one
collapsed paths loose the containing token guard
=> fixed problem
+ added positional condition in token sequence guard constructor to not
check positions twice (order matters: give local token guard first in
case it is sufficient)
removed testNestedAlternativesWithSingleTokenDifference, because it is
wrong: 'a' 'b' 'd' with p1 satisfies semantic predicates but not the
generated guard condition
nested prefix alternatives analysis
now flattenPaths() considers following repetitions
new problem: unordered groups and non-trivial cardinalities without
non-optional elements causes explosion of generated alternatives, which
in turn cause the identity analysis to go out of control
example: S: ('a'? | 'b'?)+
with a token limit of 10 the nested prefix alternatives analysis would
generate over 1300 alternatives
current quick fix: limit of alternatives
after minimal path difference analysis failed, flatten paths (limited by
token limit; justification: identity check would error out if paths are
not distinguishable within the limit) and recompute alternative guard.
now nested prefixes will be collapsed with all corresponding guard
conditions
cardinality * is only possible if all element in the unordered group are
optional. This case doesn't matter for hoisting or rather is already
dealt with in the containing group (the guard of the resulting
alternatives won't have a terminal).