Skip to content
Merged
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
45 changes: 10 additions & 35 deletions src/main/java/eu/europa/ted/efx/sdk2/EfxExpressionTranslatorV2.java
Original file line number Diff line number Diff line change
Expand Up @@ -3077,7 +3077,7 @@ public void exitFieldReferenceWithVariableContextOverride(
@Override
public void enterLateBoundScalar(LateBoundScalarContext ctx) {
this.typeResolutionStack.push(
this.adjustForGrammarAmbiguities(ctx, CardinalityResolutionContext.RESOLVE_SCALAR));
this.adjustForGrammarAmbiguity(ctx, CardinalityResolutionContext.RESOLVE_SCALAR));
}

@Override
Expand All @@ -3088,7 +3088,7 @@ public void exitLateBoundScalar(LateBoundScalarContext ctx) {
@Override
public void enterLateBoundSequence(LateBoundSequenceContext ctx) {
this.typeResolutionStack.push(
this.adjustForGrammarAmbiguities(ctx, CardinalityResolutionContext.RESOLVE_SEQUENCE));
this.adjustForGrammarAmbiguity(ctx, CardinalityResolutionContext.RESOLVE_SEQUENCE));
}

@Override
Expand All @@ -3101,36 +3101,21 @@ public void exitLateBoundSequence(LateBoundSequenceContext ctx) {
* cardinality is ambiguous, and returns {@code RESOLVE_EITHER} if so.
* Otherwise returns the provided default context.
*
* There are two grammar ambiguities that require this adjustment:
*
* Ambiguity 1: The {@code expression} rule accepts both
* {@code lateBoundScalar} and {@code lateBoundSequence} via
* {@code lateBoundExpression}. The parser picks one alternative, but the
* actual cardinality is unknown until the preprocessor resolves it.
*
* Ambiguity 2: The {@code for...return} construct has two rules:
* {@code lateBoundSequenceFromIteration} (scalar body) and
* {@code lateBoundSequenceFromConcatenatedIterations} (sequence body).
* The parser picks one, but the body cardinality is unknown until resolved.
* The {@code lateBoundExpression} rule accepts both {@code lateBoundScalar}
* and {@code lateBoundSequence}. The parser picks one alternative, but the
* actual cardinality is unknown until the preprocessor resolves it. This
* ambiguity applies wherever {@code lateBoundExpression} appears in the
* grammar: the top-level {@code expression} rule and the body of
* {@code lateBoundSequenceFromIteration}.
*
* @param ctx the late-bound parse tree node (scalar or sequence)
* @param defaultContext the context to use when no ambiguity is detected
* @return {@code RESOLVE_EITHER} if an ambiguity applies, otherwise
* {@code defaultContext}
*/
private CardinalityResolutionContext adjustForGrammarAmbiguities(ParserRuleContext ctx,
private CardinalityResolutionContext adjustForGrammarAmbiguity(ParserRuleContext ctx,
CardinalityResolutionContext defaultContext) {
ParserRuleContext parent = ctx.getParent();

// Ambiguity 1: expression → lateBoundExpression → lateBoundScalar | lateBoundSequence
boolean ambiguity1 = (parent instanceof LateBoundExpressionContext)
&& (parent.getParent() instanceof ExpressionContext);

// Ambiguity 2: lateBoundSequenceFromIteration vs lateBoundSequenceFromConcatenatedIterations
boolean ambiguity2 = (parent instanceof LateBoundSequenceFromIterationContext)
|| (parent instanceof LateBoundSequenceFromConcatenatedIterationsContext);

return (ambiguity1 || ambiguity2)
return (ctx.getParent() instanceof LateBoundExpressionContext)
? CardinalityResolutionContext.RESOLVE_EITHER
: defaultContext;
}
Expand Down Expand Up @@ -3769,16 +3754,6 @@ public void exitDurationSequenceFromConcatenatedIterations(DurationSequenceFromC
this.stack.popStackFrame();
}

@Override
public void enterLateBoundSequenceFromConcatenatedIterations(LateBoundSequenceFromConcatenatedIterationsContext ctx) {
this.stack.pushStackFrame();
}

@Override
public void exitLateBoundSequenceFromConcatenatedIterations(LateBoundSequenceFromConcatenatedIterationsContext ctx) {
this.stack.popStackFrame();
}

// #endregion Scope management --------------------------------------------

// #region Guards ---------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,13 @@ void testResolveFieldReference_Either_NonRepeatableFieldInForReturn() {
"for text:$x in BT-00-Text return BT-00-Text"));
}

@Test
void testResolveFieldReference_Either_NestedForReturn() {
assertDoesNotThrow(
() -> translateExpressionWithContext("ND-Root",
"for text:$x in BT-00-Text return (for text:$y in BT-00-Text return BT-00-Repeatable-Text)"));
}

// #endregion resolveFieldOrAttributeReference --------------------------------

// #region resolveFunctionInvocation ------------------------------------------
Expand Down