Split out refine/if-feature handling 62/106362/3
authorRobert Varga <robert.varga@pantheon.tech>
Sat, 3 Jun 2023 21:56:43 +0000 (23:56 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Sat, 3 Jun 2023 22:24:23 +0000 (00:24 +0200)
UsesStatementSupport takes over a lot of what RefineStatementSupport
should be doing. As a first step in untangling these statements, move
evaluation of if-feature expressions and rely on simple
isSupportedToBuildEffective().

Also make performRefine() more integrated by improving variable naming
and inlining addOrReplaceNodes().

Change-Id: I3c9e704e856646115a53fb456b73e2a10367511b
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
parser/yang-parser-reactor/src/main/java/org/opendaylight/yangtools/yang/parser/stmt/reactor/OriginalStmtCtx.java
parser/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/refine/RefineStatementSupport.java
parser/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/uses/UsesStatementSupport.java
parser/yang-parser-spi/src/main/java/org/opendaylight/yangtools/yang/parser/spi/meta/StmtContextUtils.java

index 48ce7189f3c8f032af069693c4d6a72d405a2376..1eece382a2b9ac081c2a2b63e7aaa2d56db1149f 100644 (file)
@@ -18,11 +18,9 @@ import java.util.List;
 import java.util.Optional;
 import java.util.stream.Stream;
 import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.yang.common.Empty;
 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
-import org.opendaylight.yangtools.yang.parser.spi.ParserNamespaces;
 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
@@ -127,8 +125,7 @@ abstract class OriginalStmtCtx<A, D extends DeclaredStatement<A>, E extends Effe
     @Override
     final boolean computeSupportedByFeatures() {
         // If the set of supported features has not been provided, all features are supported by default.
-        final var supportedFeatures = namespaceItem(ParserNamespaces.SUPPORTED_FEATURES, Empty.value());
-        return supportedFeatures == null || StmtContextUtils.checkFeatureSupport(this, supportedFeatures);
+        return StmtContextUtils.evaluateIfFeatures(this);
     }
 
     @Override
index 49e9b24b3100146e71ca90e405efbfc65dc411bf..d019a1047ca5f3aaf9a2634433ea60729903651c 100644 (file)
@@ -29,66 +29,91 @@ import org.opendaylight.yangtools.yang.parser.spi.meta.AbstractStatementSupport;
 import org.opendaylight.yangtools.yang.parser.spi.meta.BoundStmtCtx;
 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
 import org.opendaylight.yangtools.yang.parser.spi.meta.SubstatementValidator;
 
 @Beta
-public final class RefineStatementSupport
+public abstract sealed class RefineStatementSupport
         extends AbstractStatementSupport<Descendant, RefineStatement, RefineEffectiveStatement> {
-    private static final SubstatementValidator RFC6020_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.REFINE)
-        .addOptional(YangStmtMapping.DEFAULT)
-        .addOptional(YangStmtMapping.DESCRIPTION)
-        .addOptional(YangStmtMapping.REFERENCE)
-        .addOptional(YangStmtMapping.CONFIG)
-        .addOptional(YangStmtMapping.MANDATORY)
-        .addOptional(YangStmtMapping.PRESENCE)
-        .addAny(YangStmtMapping.MUST)
-        .addOptional(YangStmtMapping.MIN_ELEMENTS)
-        .addOptional(YangStmtMapping.MAX_ELEMENTS)
-        .build();
-    private static final SubstatementValidator RFC7950_VALIDATOR = SubstatementValidator.builder(YangStmtMapping.REFINE)
-        .addOptional(YangStmtMapping.DEFAULT)
-        .addOptional(YangStmtMapping.DESCRIPTION)
-        .addOptional(YangStmtMapping.REFERENCE)
-        .addOptional(YangStmtMapping.CONFIG)
-        .addAny(YangStmtMapping.IF_FEATURE)
-        .addOptional(YangStmtMapping.MANDATORY)
-        .addOptional(YangStmtMapping.PRESENCE)
-        .addAny(YangStmtMapping.MUST)
-        .addOptional(YangStmtMapping.MIN_ELEMENTS)
-        .addOptional(YangStmtMapping.MAX_ELEMENTS)
-        .build();
+    private static final class Rfc6020 extends RefineStatementSupport {
+        private static final SubstatementValidator VALIDATOR = SubstatementValidator.builder(YangStmtMapping.REFINE)
+            .addOptional(YangStmtMapping.DEFAULT)
+            .addOptional(YangStmtMapping.DESCRIPTION)
+            .addOptional(YangStmtMapping.REFERENCE)
+            .addOptional(YangStmtMapping.CONFIG)
+            .addOptional(YangStmtMapping.MANDATORY)
+            .addOptional(YangStmtMapping.PRESENCE)
+            .addAny(YangStmtMapping.MUST)
+            .addOptional(YangStmtMapping.MIN_ELEMENTS)
+            .addOptional(YangStmtMapping.MAX_ELEMENTS)
+            .build();
+
+        Rfc6020(final YangParserConfiguration config) {
+            super(config, VALIDATOR);
+        }
+    }
+
+    private static final class Rfc7950 extends RefineStatementSupport {
+        private static final SubstatementValidator VALIDATOR = SubstatementValidator.builder(YangStmtMapping.REFINE)
+            .addOptional(YangStmtMapping.DEFAULT)
+            .addOptional(YangStmtMapping.DESCRIPTION)
+            .addOptional(YangStmtMapping.REFERENCE)
+            .addOptional(YangStmtMapping.CONFIG)
+            .addAny(YangStmtMapping.IF_FEATURE)
+            .addOptional(YangStmtMapping.MANDATORY)
+            .addOptional(YangStmtMapping.PRESENCE)
+            .addAny(YangStmtMapping.MUST)
+            .addOptional(YangStmtMapping.MIN_ELEMENTS)
+            .addOptional(YangStmtMapping.MAX_ELEMENTS)
+            .build();
+
+        Rfc7950(final YangParserConfiguration config) {
+            super(config, VALIDATOR);
+        }
+
+        @Override
+        public void onFullDefinitionDeclared(
+                final Mutable<Descendant, RefineStatement, RefineEffectiveStatement> stmt) {
+            super.onFullDefinitionDeclared(stmt);
+
+            if (!StmtContextUtils.evaluateIfFeatures(stmt)) {
+                stmt.setUnsupported();
+            }
+        }
+    }
 
     private RefineStatementSupport(final YangParserConfiguration config, final SubstatementValidator validator) {
         super(YangStmtMapping.REFINE, StatementPolicy.reject(), config, validator);
     }
 
     public static @NonNull RefineStatementSupport rfc6020Instance(final YangParserConfiguration config) {
-        return new RefineStatementSupport(config, RFC6020_VALIDATOR);
+        return new Rfc6020(config);
     }
 
     public static @NonNull RefineStatementSupport rfc7950Instance(final YangParserConfiguration config) {
-        return new RefineStatementSupport(config, RFC7950_VALIDATOR);
+        return new Rfc7950(config);
     }
 
     @Override
-    public Descendant parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
+    public final Descendant parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
         return ArgumentUtils.parseDescendantSchemaNodeIdentifier(ctx, value);
     }
 
     @Override
-    protected RefineStatement createDeclared(final BoundStmtCtx<Descendant> ctx,
+    protected final RefineStatement createDeclared(final BoundStmtCtx<Descendant> ctx,
             final ImmutableList<DeclaredStatement<?>> substatements) {
         return DeclaredStatements.createRefine(ctx.getRawArgument(), ctx.getArgument(), substatements);
     }
 
     @Override
-    protected RefineStatement attachDeclarationReference(final RefineStatement stmt,
+    protected final RefineStatement attachDeclarationReference(final RefineStatement stmt,
             final DeclarationReference reference) {
         return DeclaredStatementDecorators.decorateRefine(stmt, reference);
     }
 
     @Override
-    protected RefineEffectiveStatement createEffective(final Current<Descendant, RefineStatement> stmt,
+    protected final RefineEffectiveStatement createEffective(final Current<Descendant, RefineStatement> stmt,
             final ImmutableList<? extends EffectiveStatement<?, ?>> substatements) {
         // Empty refine is exceedingly unlikely: let's be lazy and reuse the implementation
         return new RefineEffectiveStatementImpl(stmt.declared(), substatements,
index cd9b9b13248ff651f0430335c224a6e88bf3273e..e2c2628ae56d01f7875bfd2da5f3fb4869522d85 100644 (file)
@@ -10,6 +10,7 @@ package org.opendaylight.yangtools.yang.parser.rfc7950.stmt.uses;
 import static com.google.common.base.Verify.verify;
 import static com.google.common.base.Verify.verifyNotNull;
 
+import com.google.common.base.VerifyException;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import java.util.ArrayList;
@@ -19,7 +20,6 @@ import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.yangtools.yang.common.Empty;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.common.YangVersion;
 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.YangStmtMapping;
@@ -29,7 +29,6 @@ import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
 import org.opendaylight.yangtools.yang.model.api.stmt.RefineEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.RefineStatement;
-import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Descendant;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.UsesEffectiveStatement;
@@ -105,9 +104,9 @@ public final class UsesStatementSupport
                 copyFromSourceToTarget(sourceGrpStmtCtx, targetNodeStmtCtx, usesNode);
 
                 // Apply any refine statements
-                for (var subStmtCtx : usesNode.mutableDeclaredSubstatements()) {
-                    if (subStmtCtx.producesDeclared(RefineStatement.class) && areFeaturesSupported(subStmtCtx)) {
-                        performRefine(subStmtCtx, targetNodeStmtCtx);
+                for (var subStmt : usesNode.mutableDeclaredSubstatements()) {
+                    if (subStmt.producesDeclared(RefineStatement.class) && subStmt.isSupportedToBuildEffective()) {
+                        performRefine(subStmt, targetNodeStmtCtx);
                     }
                 }
 
@@ -265,55 +264,44 @@ public final class UsesStatementSupport
         return null;
     }
 
-    private static boolean areFeaturesSupported(final StmtContext<?, ?, ?> subStmtCtx) {
-        /*
-         * In case of Yang 1.1, checks whether features are supported.
-         */
-        return !YangVersion.VERSION_1_1.equals(subStmtCtx.yangVersion()) || subStmtCtx.isSupportedByFeatures();
-    }
-
-    private static void performRefine(final Mutable<?, ?, ?> subStmtCtx, final StmtContext<?, ?, ?> usesParentCtx) {
-        final Object refineArgument = subStmtCtx.argument();
-        if (!(refineArgument instanceof SchemaNodeIdentifier refineTarget)) {
-            throw new InferenceException(subStmtCtx,
+    private static void performRefine(final Mutable<?, ?, ?> refineStmtCtx, final StmtContext<?, ?, ?> usesParentCtx) {
+        final Object refineArgument = refineStmtCtx.argument();
+        if (!(refineArgument instanceof Descendant refineDescendant)) {
+            throw new InferenceException(refineStmtCtx,
                 "Invalid refine argument %s. It must be instance of SchemaNodeIdentifier.", refineArgument);
         }
 
         // FIXME: this really should be handled via separate inference, i.e. we first instantiate the template and when
         //        it appears, this refine will trigger on it. This reinforces the FIXME below.
-        final var optRefineTargetCtx = ParserNamespaces.findSchemaTreeStatement(usesParentCtx, refineTarget);
-        InferenceException.throwIf(!optRefineTargetCtx.isPresent(), subStmtCtx, "Refine target node %s not found.",
-            refineTarget);
+        final var optRefineTargetCtx = ParserNamespaces.findSchemaTreeStatement(usesParentCtx, refineDescendant);
+        InferenceException.throwIf(!optRefineTargetCtx.isPresent(), refineStmtCtx, "Refine target node %s not found.",
+            refineDescendant);
 
         // FIXME: This communicates the looked-up target node to RefineStatementSupport.buildEffective(). We should do
         //        this trick through a shared namespace or similar reactor-agnostic meeting place. It really feels like
         //        an inference action RefineStatementSupport should be doing.
-        final var refineTargetNodeCtx = optRefineTargetCtx.orElseThrow();
-        if (StmtContextUtils.isUnknownStatement(refineTargetNodeCtx)) {
+        final var refineTargetCtx = optRefineTargetCtx.orElseThrow();
+        if (StmtContextUtils.isUnknownStatement(refineTargetCtx)) {
             LOG.trace("Refine node '{}' in uses '{}' has target node unknown statement '{}'. "
-                + "Refine has been skipped. At line: {}", subStmtCtx.argument(),
-                subStmtCtx.coerceParentContext().argument(), refineTargetNodeCtx.argument(),
-                subStmtCtx.sourceReference());
+                + "Refine has been skipped. At line: {}", refineStmtCtx.argument(),
+                refineStmtCtx.coerceParentContext().argument(), refineTargetCtx.argument(),
+                refineStmtCtx.sourceReference());
+        } else if (refineTargetCtx instanceof Mutable<?, ?, ?> refineTarget) {
+            for (var refineSubstatementCtx : refineStmtCtx.declaredSubstatements()) {
+                if (isSupportedRefineSubstatement(refineSubstatementCtx)) {
+                    addOrReplaceNode(refineSubstatementCtx, refineTarget);
+                }
+            }
         } else {
-            verify(refineTargetNodeCtx instanceof Mutable, "Unexpected target %s", refineTargetNodeCtx);
-            addOrReplaceNodes(subStmtCtx, (Mutable<?, ?, ?>) refineTargetNodeCtx);
+            throw new VerifyException("Unexpected target " + refineTargetCtx);
         }
 
         // Target is a prerequisite for the 'refine', hence if the target is not supported, the refine is not supported
         // as well. Otherwise add a pointer to the target into refine's local namespace.
-        if (refineTargetNodeCtx.isSupportedToBuildEffective() && refineTargetNodeCtx.isSupportedByFeatures()) {
-            subStmtCtx.addToNs(RefineTargetNamespace.INSTANCE, Empty.value(), refineTargetNodeCtx);
+        if (refineTargetCtx.isSupportedToBuildEffective() && refineTargetCtx.isSupportedByFeatures()) {
+            refineStmtCtx.addToNs(RefineTargetNamespace.INSTANCE, Empty.value(), refineTargetCtx);
         } else {
-            subStmtCtx.setUnsupported();
-        }
-    }
-
-    private static void addOrReplaceNodes(final StmtContext<?, ?, ?> subStmtCtx,
-            final Mutable<?, ?, ?> refineTargetNodeCtx) {
-        for (StmtContext<?, ?, ?> refineSubstatementCtx : subStmtCtx.declaredSubstatements()) {
-            if (isSupportedRefineSubstatement(refineSubstatementCtx)) {
-                addOrReplaceNode(refineSubstatementCtx, refineTargetNodeCtx);
-            }
+            refineStmtCtx.setUnsupported();
         }
     }
 
index 250b61f66c586136bb2ef72825e2c36da26bf4d4..117e10047ef4c8270f6b93cc4b6185f5074293f0 100644 (file)
@@ -17,6 +17,7 @@ import java.util.Collection;
 import java.util.Optional;
 import java.util.Set;
 import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.common.Empty;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.Revision;
@@ -212,6 +213,18 @@ public final class StmtContextUtils {
         return UnknownStatement.class.isAssignableFrom(stmtCtx.publicDefinition().getDeclaredRepresentationClass());
     }
 
+    /**
+     * Evaluate {@code if-feature} substatement of a statement and indicate whether they result in the statement being
+     * supported.
+     *
+     * @param stmt Parent statement
+     * @return {@code true} if the statement is indicated to be supported under currently-supported features
+     */
+    public static boolean evaluateIfFeatures(final @NonNull StmtContext<?, ?, ?> stmt) {
+        final var supportedFeatures = stmt.namespaceItem(ParserNamespaces.SUPPORTED_FEATURES, Empty.value());
+        return supportedFeatures == null || checkFeatureSupport(stmt, supportedFeatures);
+    }
+
     public static boolean checkFeatureSupport(final StmtContext<?, ?, ?> stmtContext,
             final FeatureSet supportedFeatures) {
         boolean isSupported = false;