Move substatement ordering to yang-parser-reactor 26/105326/3
authorRobert Varga <robert.varga@pantheon.tech>
Sat, 8 Apr 2023 17:49:57 +0000 (19:49 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Sat, 8 Apr 2023 19:45:05 +0000 (21:45 +0200)
Substatement ordering should be something reactor handles, hence move it
out to make sure StatementFactory does not have to deal with this,
making the API towards StatementFactory more consistent.

Change-Id: I9106e04c22227f054be23cf4ace492ffe416ff98
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
parser/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/AbstractResumedStatement.java
parser/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/augment/AbstractAugmentStatementSupport.java
parser/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/meta/AbstractImplicitStatementSupport.java
parser/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/module/ModuleStatementSupport.java
parser/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/type/AbstractTypeStatementSupport.java
parser/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/AbstractStatementSupport.java
parser/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/ForwardingStatementSupport.java
parser/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StatementFactory.java

index 501eb2bcc0b456c9cb973974103c5a9d05ac383a..5d219160f697794080ac734fbe9952323ff07e33 100644 (file)
@@ -8,10 +8,14 @@
 package org.opendaylight.yangtools.yang.parser.stmt.reactor;
 
 import static com.google.common.base.Preconditions.checkState;
-import static com.google.common.base.Verify.verify;
 import static com.google.common.base.Verify.verifyNotNull;
 
+import com.google.common.base.VerifyException;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
@@ -45,10 +49,10 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
     // Copy constructor
     AbstractResumedStatement(final AbstractResumedStatement<A, D, E> original) {
         super(original);
-        this.rawArgument = original.rawArgument;
-        this.substatements = original.substatements;
-        this.declaredInstance = original.declaredInstance;
-        this.fullyDefined = original.fullyDefined;
+        rawArgument = original.rawArgument;
+        substatements = original.substatements;
+        declaredInstance = original.declaredInstance;
+        fullyDefined = original.fullyDefined;
     }
 
     AbstractResumedStatement(final StatementDefinitionContext<A, D, E> def, final StatementSourceReference ref,
@@ -74,10 +78,12 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
     }
 
     private @NonNull D loadDeclared() {
-        final ModelProcessingPhase phase = getCompletedPhase();
-        checkState(phase == ModelProcessingPhase.FULL_DECLARATION || phase == ModelProcessingPhase.EFFECTIVE_MODEL,
-                "Cannot build declared instance after phase %s", phase);
-        return declaredInstance = definition().getFactory().createDeclared(this, substatementsAsDeclared());
+        final var phase = getCompletedPhase();
+        return switch (phase) {
+            case FULL_DECLARATION, EFFECTIVE_MODEL ->
+                declaredInstance = definition().getFactory().createDeclared(this, substatementsAsDeclared());
+            default -> throw new IllegalStateException("Cannot build declared instance after phase " + phase);
+        };
     }
 
     @SuppressWarnings({ "rawtypes", "unchecked" })
@@ -128,7 +134,72 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
         // the substatements may be gone by the time the factory attempts to acquire the declared statement.
         ctx.declared();
 
-        return factory.createEffective(ctx, declared, effective);
+        return factory.createEffective(ctx, orderSubstatements(declared, effective));
+    }
+
+    private static @NonNull Stream<StmtContext<?, ?, ?>> orderSubstatements(
+            final Stream<? extends StmtContext<?, ?, ?>> declaredSubstatements,
+            final Stream<? extends StmtContext<?, ?, ?>> effectiveSubstatements) {
+        /*
+         * This dance is required to ensure that effects of 'uses' nodes are applied in the same order as
+         * the statements were defined -- i.e. if we have something like this:
+         *
+         * container foo {
+         *   uses bar;
+         *   uses baz;
+         * }
+         *
+         * grouping baz {
+         *   leaf baz {
+         *     type string;
+         *   }
+         * }
+         *
+         * grouping bar {
+         *   leaf bar {
+         *     type string;
+         *   }
+         * }
+         *
+         * The reactor would first inline 'uses baz' as that definition is the first one completely resolved and then
+         * inline 'uses bar'. Here we are iterating in declaration order re-inline the statements.
+         *
+         * FIXME: 7.0.0: this really should be handled by UsesStatementSupport such that 'uses baz' would have a
+         *               prerequisite of a resolved 'uses bar'.
+         */
+        final var declaredInit = declaredSubstatements
+            .filter(StmtContext::isSupportedByFeatures)
+            .collect(Collectors.toList());
+
+        final var substatementsInit = new ArrayList<StmtContext<?, ?, ?>>();
+        Set<StmtContext<?, ?, ?>> filteredStatements = null;
+        for (var declaredSubstatement : declaredInit) {
+            substatementsInit.add(declaredSubstatement);
+
+            // FIXME: YANGTOOLS-1161: we need to integrate this functionality into the reactor, so that this
+            //                        transformation is something reactor's declared statements already take into
+            //                        account.
+            final Collection<? extends StmtContext<?, ?, ?>> effect = declaredSubstatement.getEffectOfStatement();
+            if (!effect.isEmpty()) {
+                if (filteredStatements == null) {
+                    filteredStatements = new HashSet<>();
+                }
+                filteredStatements.addAll(effect);
+                // Note: we need to filter here to exclude unsupported statements
+                effect.stream().filter(StmtContext::isSupportedToBuildEffective).forEach(substatementsInit::add);
+            }
+        }
+
+        final Stream<? extends StmtContext<?, ?, ?>> effective;
+        if (filteredStatements != null) {
+            final var filtered = filteredStatements;
+            effective = effectiveSubstatements.filter(stmt -> !filtered.contains(stmt));
+        } else {
+            effective = effectiveSubstatements;
+        }
+
+        substatementsInit.addAll(effective.collect(Collectors.toList()));
+        return substatementsInit.stream();
     }
 
     @Override
@@ -155,7 +226,7 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
             AbstractResumedStatement<X, Y, Z> createSubstatement(final int offset,
                     final StatementDefinitionContext<X, Y, Z> def, final StatementSourceReference ref,
                     final String argument) {
-        final ModelProcessingPhase inProgressPhase = getRoot().getSourceContext().getInProgressPhase();
+        final var inProgressPhase = getRoot().getSourceContext().getInProgressPhase();
         checkState(inProgressPhase != ModelProcessingPhase.EFFECTIVE_MODEL,
                 "Declared statement cannot be added in effective phase at: %s", sourceReference());
 
@@ -217,8 +288,11 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
     private static @NonNull AbstractResumedStatement<?, ?, ?> unmaskUndeclared(final ReactorStmtCtx<?, ?, ?> stmt) {
         var ret = stmt;
         while (!(ret instanceof AbstractResumedStatement<?, ?, ?> resumed)) {
-            verify(ret instanceof UndeclaredStmtCtx, "Unexpectred statement %s", ret);
-            ret = ((UndeclaredStmtCtx<?, ?, ?>) ret).getResumedSubstatement();
+            if (ret instanceof UndeclaredStmtCtx<?, ?, ?> undeclared) {
+                ret = undeclared.getResumedSubstatement();
+            } else {
+                throw new VerifyException("Unexpected statement " + ret);
+            }
         }
         return resumed;
     }
@@ -238,19 +312,21 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
 
         var ret = verifyParent(parent);
         // Unwind all undeclared statements
-        while (!(ret instanceof AbstractResumedStatement)) {
+        while (!(ret instanceof AbstractResumedStatement<?, ?, ?> resumed)) {
             ret.finishDeclaration(phase);
             ret = verifyParent(ret.getParentContext());
         }
-        return (AbstractResumedStatement<?, ?, ?>) ret;
+        return resumed;
     }
 
     // FIXME: AbstractResumedStatement should only ever have OriginalStmtCtx parents, which would remove the need for
     //        this method. In ordered to do that we need to untangle SubstatementContext's users and do not allow it
     //        being reparent()ed.
     private static OriginalStmtCtx<?, ?, ?> verifyParent(final StatementContextBase<?, ?, ?> parent) {
-        verify(parent instanceof OriginalStmtCtx, "Unexpected parent context %s", parent);
-        return (OriginalStmtCtx<?, ?, ?>) parent;
+        if (parent instanceof OriginalStmtCtx<?, ?, ?> original) {
+            return original;
+        }
+        throw new VerifyException("Unexpected parent context " + parent);
     }
 
     final void resizeSubstatements(final int expectedSize) {
index 2de5f0f6380205423afa96a36a7d02871b2de8dd..7e53180ae247db1cb68198a540df9c6d349e078e 100644 (file)
@@ -8,9 +8,8 @@
 package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.augment;
 
 import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import java.util.List;
 import java.util.regex.Pattern;
+import java.util.stream.Stream;
 import org.opendaylight.yangtools.yang.common.Empty;
 import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
@@ -118,14 +117,14 @@ abstract class AbstractAugmentStatementSupport
     }
 
     @Override
-    protected final List<? extends StmtContext<?, ?, ?>> statementsToBuild(
+    protected final Stream<? extends StmtContext<?, ?, ?>> statementsToBuild(
             final Current<SchemaNodeIdentifier, AugmentStatement> stmt,
-            final List<? extends StmtContext<?, ?, ?>> substatements) {
+            final Stream<? extends StmtContext<?, ?, ?>> substatements) {
         // Pick up the marker left by onFullDefinitionDeclared() inference action. If it is present we need to pass our
         // children through target's implicit wrapping.
         final var implicitDef = stmt.namespaceItem(AugmentImplicitHandlingNamespace.INSTANCE, Empty.value());
         return implicitDef == null ? substatements
-            : Lists.transform(substatements, subCtx -> implicitDef.wrapWithImplicit(subCtx));
+            : substatements.map(subCtx -> implicitDef.wrapWithImplicit(subCtx));
     }
 
     @Override
index 45bc4aad896e8cb8ff209d0f0bb60f2d5ebc441e..0597cea5aa87614d8974ab474c064d1d77eabfce 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.meta;
 import static java.util.Objects.requireNonNull;
 
 import com.google.common.collect.ImmutableList;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -44,9 +43,7 @@ abstract class AbstractImplicitStatementSupport<D extends DeclaredStatement<QNam
     public final E createUndeclaredEffective(final UndeclaredCurrent<QName, D> stmt,
             final @NonNull Stream<? extends StmtContext<?, ?, ?>> effectiveSubstatements) {
         return createUndeclaredEffective(stmt, buildEffectiveSubstatements(stmt,
-            statementsToBuild(stmt, effectiveSubstatements
-                .filter(StmtContext::isSupportedToBuildEffective)
-                .collect(Collectors.toUnmodifiableList()))));
+            statementsToBuild(stmt, effectiveSubstatements.filter(StmtContext::isSupportedToBuildEffective))));
     }
 
     abstract @NonNull E createUndeclaredEffective(@NonNull UndeclaredCurrent<QName, D> stmt,
index 44e770572337b0dce4adb6c56ec0bf0c1f24460a..b93e46189842c8c4f128deae85aea65f731a4215 100644 (file)
@@ -17,6 +17,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Stream;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.common.Empty;
 import org.opendaylight.yangtools.yang.common.QNameModule;
@@ -184,7 +185,7 @@ public final class ModuleStatementSupport
     @Override
     protected ImmutableList<? extends EffectiveStatement<?, ?>> buildEffectiveSubstatements(
             final Current<Unqualified, ModuleStatement> stmt,
-            final List<? extends StmtContext<?, ?, ?>> substatements) {
+            final Stream<? extends StmtContext<?, ?, ?>> substatements) {
         final ImmutableList<? extends EffectiveStatement<?, ?>> local =
                 super.buildEffectiveSubstatements(stmt, substatements);
         final Collection<StmtContext<?, ?, ?>> submodules = submoduleContexts(stmt);
index 0ce63172232d42e5848922fc33d68b672195628a..5458b668fed3a1ce29aa0041bf156899021f0e05 100644 (file)
@@ -12,7 +12,6 @@ import static com.google.common.base.Verify.verifyNotNull;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import java.util.Collection;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.common.Decimal64;
@@ -188,9 +187,7 @@ abstract class AbstractTypeStatementSupport extends AbstractTypeSupport<TypeStat
             final UndeclaredCurrent<QName, TypeStatement> stmt,
             final Stream<? extends StmtContext<?, ?, ?>> effectiveSubstatements) {
         final ImmutableList<? extends EffectiveStatement<?, ?>> substatements = buildEffectiveSubstatements(stmt,
-            statementsToBuild(stmt, effectiveSubstatements
-                .filter(StmtContext::isSupportedToBuildEffective)
-                .collect(Collectors.toUnmodifiableList())));
+            statementsToBuild(stmt, effectiveSubstatements.filter(StmtContext::isSupportedToBuildEffective)));
 
         // First look up the proper base type
         final TypeEffectiveStatement<TypeStatement> typeStmt = resolveType(stmt);
index b0ba945f295481ecc36bfd23dd880cff6bbd4534..c774f38b1fdc0722b24fef5618f0cd19a8cee191 100644 (file)
@@ -9,12 +9,7 @@ package org.opendaylight.yangtools.yang.parser.spi.meta;
 
 import com.google.common.annotations.Beta;
 import com.google.common.collect.ImmutableList;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.eclipse.jdt.annotation.NonNull;
 import org.eclipse.jdt.annotation.Nullable;
@@ -42,8 +37,8 @@ public abstract class AbstractStatementSupport<A, D extends DeclaredStatement<A>
     protected AbstractStatementSupport(final StatementDefinition publicDefinition, final StatementPolicy<A, D> policy,
             final YangParserConfiguration config, final @Nullable SubstatementValidator validator) {
         super(publicDefinition, policy);
-        this.retainDeclarationReference = config.retainDeclarationReferences();
-        this.substatementValidator = validator;
+        retainDeclarationReference = config.retainDeclarationReferences();
+        substatementValidator = validator;
     }
 
     @Override
@@ -61,7 +56,7 @@ public abstract class AbstractStatementSupport<A, D extends DeclaredStatement<A>
             @NonNull ImmutableList<DeclaredStatement<?>> substatements);
 
     private @NonNull D attachDeclarationReference(final @NonNull D stmt, final @NonNull BoundStmtCtx<A> ctx) {
-        final DeclarationReference ref = ctx.sourceReference().declarationReference();
+        final var ref = ctx.sourceReference().declarationReference();
         return ref == null ? stmt : attachDeclarationReference(stmt, ref);
     }
 
@@ -76,13 +71,8 @@ public abstract class AbstractStatementSupport<A, D extends DeclaredStatement<A>
     protected abstract @NonNull D attachDeclarationReference(@NonNull D stmt, @NonNull DeclarationReference reference);
 
     @Override
-    public final E createEffective(final Current<A, D> stmt,
-            final Stream<? extends StmtContext<?, ?, ?>> declaredSubstatements,
-            final Stream<? extends StmtContext<?, ?, ?>> inferredSubstatements) {
-        final ImmutableList<? extends EffectiveStatement<?, ?>> substatements =
-                buildEffectiveSubstatements(stmt, statementsToBuild(stmt,
-                    declaredSubstatements(declaredSubstatements, inferredSubstatements)));
-        return createEffective(stmt, substatements);
+    public final E createEffective(final Current<A, D> stmt, final Stream<StmtContext<?, ?, ?>> substatements) {
+        return createEffective(stmt, buildEffectiveSubstatements(stmt, statementsToBuild(stmt, substatements)));
     }
 
     protected abstract @NonNull E createEffective(@NonNull Current<A, D> stmt,
@@ -102,15 +92,15 @@ public abstract class AbstractStatementSupport<A, D extends DeclaredStatement<A>
      * @param substatements Substatement contexts which have been determined to be built
      * @return Substatement context which are to be actually built
      */
-    protected List<? extends StmtContext<?, ?, ?>> statementsToBuild(final Current<A, D> ctx,
-            final List<? extends StmtContext<?, ?, ?>> substatements) {
+    protected Stream<? extends StmtContext<?, ?, ?>> statementsToBuild(final Current<A, D> ctx,
+            final Stream<? extends StmtContext<?, ?, ?>> substatements) {
         return substatements;
     }
 
     // FIXME: add documentation
     public static final <E extends EffectiveStatement<?, ?>> @Nullable E findFirstStatement(
             final Collection<? extends EffectiveStatement<?, ?>> statements, final Class<E> type) {
-        for (EffectiveStatement<?, ?> stmt : statements) {
+        for (var stmt : statements) {
             if (type.isInstance(stmt)) {
                 return type.cast(stmt);
             }
@@ -135,72 +125,7 @@ public abstract class AbstractStatementSupport<A, D extends DeclaredStatement<A>
      * @return Built effective substatements
      */
     protected @NonNull ImmutableList<? extends EffectiveStatement<?, ?>> buildEffectiveSubstatements(
-            final Current<A, D> stmt, final List<? extends StmtContext<?, ?, ?>> substatements) {
-        return substatements.stream().map(StmtContext::buildEffective).collect(ImmutableList.toImmutableList());
-    }
-
-    private static @NonNull List<StmtContext<?, ?, ?>> declaredSubstatements(
-            final Stream<? extends StmtContext<?, ?, ?>> declaredSubstatements,
-            final Stream<? extends StmtContext<?, ?, ?>> effectiveSubstatements) {
-        /*
-         * This dance is required to ensure that effects of 'uses' nodes are applied in the same order as
-         * the statements were defined -- i.e. if we have something like this:
-         *
-         * container foo {
-         *   uses bar;
-         *   uses baz;
-         * }
-         *
-         * grouping baz {
-         *   leaf baz {
-         *     type string;
-         *   }
-         * }
-         *
-         * grouping bar {
-         *   leaf bar {
-         *     type string;
-         *   }
-         * }
-         *
-         * The reactor would first inline 'uses baz' as that definition is the first one completely resolved and then
-         * inline 'uses bar'. Here we are iterating in declaration order re-inline the statements.
-         *
-         * FIXME: 7.0.0: this really should be handled by UsesStatementSupport such that 'uses baz' would have a
-         *               prerequisite of a resolved 'uses bar'.
-         */
-        final List<StmtContext<?, ?, ?>> declaredInit = declaredSubstatements
-            .filter(StmtContext::isSupportedByFeatures)
-            .collect(Collectors.toList());
-
-        final List<StmtContext<?, ?, ?>> substatementsInit = new ArrayList<>();
-        Set<StmtContext<?, ?, ?>> filteredStatements = null;
-        for (final StmtContext<?, ?, ?> declaredSubstatement : declaredInit) {
-            substatementsInit.add(declaredSubstatement);
-
-            // FIXME: YANGTOOLS-1161: we need to integrate this functionality into the reactor, so that this
-            //                        transformation is something reactor's declared statements already take into
-            //                        account.
-            final Collection<? extends StmtContext<?, ?, ?>> effect = declaredSubstatement.getEffectOfStatement();
-            if (!effect.isEmpty()) {
-                if (filteredStatements == null) {
-                    filteredStatements = new HashSet<>();
-                }
-                filteredStatements.addAll(effect);
-                // Note: we need to filter here to exclude unsupported statements
-                effect.stream().filter(StmtContext::isSupportedToBuildEffective).forEach(substatementsInit::add);
-            }
-        }
-
-        final Stream<? extends StmtContext<?, ?, ?>> effective;
-        if (filteredStatements != null) {
-            final Set<StmtContext<?, ?, ?>> filtered = filteredStatements;
-            effective = effectiveSubstatements.filter(stmt -> !filtered.contains(stmt));
-        } else {
-            effective = effectiveSubstatements;
-        }
-
-        substatementsInit.addAll(effective.collect(Collectors.toList()));
-        return substatementsInit;
+            final Current<A, D> stmt, final Stream<? extends StmtContext<?, ?, ?>> substatements) {
+        return substatements.map(StmtContext::buildEffective).collect(ImmutableList.toImmutableList());
     }
 }
index 40ffb4effd1fba12cbe961c8dceddf0fff545f94..931df13f3679e62f36481f8d6ca925bce20d1e96 100644 (file)
@@ -40,10 +40,8 @@ public abstract class ForwardingStatementSupport<A, D extends DeclaredStatement<
     }
 
     @Override
-    public E createEffective(final Current<A, D> stmt,
-            final Stream<? extends StmtContext<?, ?, ?>> declaredSubstatements,
-            final Stream<? extends StmtContext<?, ?, ?>> inferredSubstatements) {
-        return delegate.createEffective(stmt, declaredSubstatements, inferredSubstatements);
+    public E createEffective(final Current<A, D> stmt, final Stream<StmtContext<?, ?, ?>> substatements) {
+        return delegate.createEffective(stmt, substatements);
     }
 
     @Override
index f35d34c302a008c8704dbe1a804d8a37d792e9d9..93976f548189560c521be2a1be41d14cf3d75939 100644 (file)
@@ -37,14 +37,10 @@ public interface StatementFactory<A, D extends DeclaredStatement<A>, E extends E
      * Create a {@link EffectiveStatement} for specified context.
      *
      * @param stmt Effective capture of this statement's significant state
-     * @param declaredSubstatements effectively-visible declared substatements
-     * @param inferredSubstatements effectively-visible inferred substatements
+     * @param substatements effectively-visible substatements
      * @return An effective statement instance
      */
-    // FIXME: we really want a single coherent 'effectiveSubstatements' stream
-    @NonNull E createEffective(@NonNull Current<A, D> stmt,
-        Stream<? extends StmtContext<?, ?, ?>> declaredSubstatements,
-        Stream<? extends StmtContext<?, ?, ?>> inferredSubstatements);
+    @NonNull E createEffective(@NonNull Current<A, D> stmt, @NonNull Stream<StmtContext<?, ?, ?>> substatements);
 
     /**
      * Create a {@link EffectiveStatement} copy of provided original for specified context.