Rework AugmentRuntimeType and Choice/Case linkage
[mdsal.git] / binding / mdsal-binding-generator / src / main / java / org / opendaylight / mdsal / binding / generator / impl / reactor / AbstractAugmentGenerator.java
index 5a018acdb50257cf2d33f860b10bdd25190deded..d52d09632b0ace7f9401967a1b4611f5db1b165f 100644 (file)
@@ -11,10 +11,13 @@ import static com.google.common.base.Verify.verify;
 import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 
+import com.google.common.collect.ImmutableList;
 import java.util.Comparator;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Optional;
 import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
 import org.opendaylight.mdsal.binding.generator.impl.reactor.CollisionDomain.Member;
 import org.opendaylight.mdsal.binding.generator.impl.rt.DefaultAugmentRuntimeType;
 import org.opendaylight.mdsal.binding.model.api.GeneratedType;
@@ -22,13 +25,17 @@ import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilde
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
 import org.opendaylight.mdsal.binding.model.ri.BindingTypes;
 import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.RuntimeType;
 import org.opendaylight.yangtools.odlext.model.api.AugmentIdentifierEffectiveStatement;
 import org.opendaylight.yangtools.yang.common.AbstractQName;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.AugmentEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.ChoiceEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement.SchemaTreeNamespace;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
 import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
 
 /**
@@ -85,8 +92,9 @@ abstract class AbstractAugmentGenerator
         return otherIt.hasNext() ? -1 : 0;
     };
 
-    private AugmentEffectiveStatement effectiveStatement;
+    private SchemaTreeAwareEffectiveStatement<?, ?> targetStatement;
     private AbstractCompositeGenerator<?, ?> targetGen;
+    private Optional<AugmentRuntimeType> internalRuntimeType;
 
     AbstractAugmentGenerator(final AugmentEffectiveStatement statement, final AbstractCompositeGenerator<?, ?> parent) {
         super(statement, parent);
@@ -147,17 +155,52 @@ abstract class AbstractAugmentGenerator
         return builder.build();
     }
 
-    @Override
-    final AugmentEffectiveStatement effectiveStatement() {
-        return verifyNotNull(effectiveStatement, "Effective statement not set in %s", this);
+    @NonNull List<CaseRuntimeType> augmentedCasesIn(final ChildLookup lookup, final ChoiceEffectiveStatement stmt) {
+        final var target = verifyNotNull(targetStatement);
+        if (!stmt.equals(target)) {
+            return List.of();
+        }
+
+        final var result = createBuilder(effectiveStatement(statement(), target))
+            .fillTypes(ChildLookup.of(target), this)
+            .getCaseChilden();
+        internalRuntimeType = Optional.empty();
+        return result;
     }
 
-    @Override
-    final AugmentRuntimeType createRuntimeType(final GeneratedType type, final AugmentEffectiveStatement statement,
-            final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
-        verify(statement instanceof TargetAugmentEffectiveStatement, "Unexpected statement %s", statement);
-        return new DefaultAugmentRuntimeType(type, ((TargetAugmentEffectiveStatement) statement).delegate(), children,
-            augments);
+    @Nullable AugmentRuntimeType runtimeTypeIn(final ChildLookup lookup, final EffectiveStatement<?, ?> stmt) {
+        final var target = verifyNotNull(targetStatement);
+        if (!stmt.equals(target)) {
+            return null;
+        }
+        if (internalRuntimeType != null) {
+            return internalRuntimeType.orElseThrow();
+        }
+
+        final var result = verifyNotNull(createInternalRuntimeType(ChildLookup.of(target),
+            effectiveStatement(statement(), target)));
+        internalRuntimeType = Optional.of(result);
+        return result;
+    }
+
+    private static @NonNull AugmentEffectiveStatement effectiveStatement(final AugmentEffectiveStatement augment,
+            final SchemaTreeAwareEffectiveStatement<?, ?> target) {
+        final var stmts = augment.effectiveSubstatements();
+        final var builder = ImmutableList.<EffectiveStatement<?, ?>>builderWithExpectedSize(stmts.size());
+        for (var child : stmts) {
+            if (child instanceof SchemaTreeEffectiveStatement) {
+                final var qname = ((SchemaTreeEffectiveStatement<?>) child).getIdentifier();
+                // FIXME: orElseThrow()?
+                target.get(SchemaTreeNamespace.class, qname).ifPresent(builder::add);
+            } else {
+                builder.add(child);
+            }
+        }
+        return new TargetAugmentEffectiveStatement(augment, target, builder.build());
+    }
+
+    final @Nullable AugmentRuntimeType getInternalRuntimeType() {
+        return verifyNotNull(internalRuntimeType, "Internal runtime not resolved in %s", this).orElse(null);
     }
 
     @Override
@@ -165,6 +208,20 @@ abstract class AbstractAugmentGenerator
         // Augments are never added as getters, as they are handled via Augmentable mechanics
     }
 
+    @Override
+    CompositeRuntimeTypeBuilder<AugmentEffectiveStatement, AugmentRuntimeType> createBuilder(
+            final AugmentEffectiveStatement statement) {
+        return new CompositeRuntimeTypeBuilder<>(statement) {
+            @Override
+            AugmentRuntimeType build(final GeneratedType type, final AugmentEffectiveStatement statement,
+                    final List<RuntimeType> children, final List<AugmentRuntimeType> augments) {
+                // 'augment' cannot be targeted by augment
+                verify(augments.isEmpty(), "Unexpected augments %s", augments);
+                return new DefaultAugmentRuntimeType(type, statement, children);
+            }
+        };
+    }
+
     final void setTargetGenerator(final AbstractCompositeGenerator<?, ?> targetGenerator) {
         verify(targetGen == null, "Attempted to relink %s, already have target %s", this, targetGen);
         targetGen = requireNonNull(targetGenerator);
@@ -177,7 +234,6 @@ abstract class AbstractAugmentGenerator
     final void setTargetStatement(final EffectiveStatement<?, ?> targetStatement) {
         verify(targetStatement instanceof SchemaTreeAwareEffectiveStatement, "Unexpected target statement %s",
             targetStatement);
-        effectiveStatement = new TargetAugmentEffectiveStatement(statement(),
-            (SchemaTreeAwareEffectiveStatement<?, ?>) targetStatement);
+        this.targetStatement = (SchemaTreeAwareEffectiveStatement<?, ?>) targetStatement;
     }
 }