Expose Iterator from effectiveChildrenToComplete()
[yangtools.git] / parser / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / AbstractResumedStatement.java
index c73b58559290cdb4c568f60014e7014f5d8ebf7d..f5b33582799fafbab1d14b39e795f26ce64e21e1 100644 (file)
@@ -8,10 +8,13 @@
 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 static java.util.Objects.requireNonNull;
 
 import com.google.common.collect.ImmutableList;
 import java.util.Collection;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
 import java.util.stream.Stream;
@@ -20,6 +23,7 @@ import org.eclipse.jdt.annotation.Nullable;
 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.model.api.meta.StatementOrigin;
 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.StatementSupport;
@@ -133,7 +137,12 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
         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);
+        return declaredInstance = definition().getFactory().createDeclared(this, substatementsAsDeclared());
+    }
+
+    private @NonNull Stream<DeclaredStatement<?>> substatementsAsDeclared() {
+        // FIXME: YANGTOOLS-1383: this stream includes implicit case statements, but it should not
+        return substatements.stream().map(AbstractResumedStatement::declared);
     }
 
     @Override
@@ -172,11 +181,10 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
         checkState(inProgressPhase != ModelProcessingPhase.EFFECTIVE_MODEL,
                 "Declared statement cannot be added in effective phase at: %s", sourceReference());
 
-        final Optional<StatementSupport<?, ?, ?>> implicitParent =
-                definition().getImplicitParentFor(def.getPublicView());
+        final var implicitParent = definition().getImplicitParentFor(this, def.getPublicView());
         if (implicitParent.isPresent()) {
-            return createImplicitParent(offset, implicitParent.get(), ref, argument).createSubstatement(offset, def,
-                    ref, argument);
+            return createImplicitParent(offset, implicitParent.orElseThrow(), ref, argument)
+                .createSubstatement(0, def, ref, argument);
         }
 
         final AbstractResumedStatement<X, Y, Z> ret = new SubstatementContext<>(this, def, ref, argument);
@@ -203,8 +211,8 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
     }
 
     @Override
-    final Iterable<ReactorStmtCtx<?, ?, ?>> effectiveChildrenToComplete() {
-        return effective;
+    final Iterator<ReactorStmtCtx<?, ?, ?>> effectiveChildrenToComplete() {
+        return effective.iterator();
     }
 
     @Override
@@ -241,30 +249,78 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
     }
 
     /**
-     * Lookup substatement by its offset in this statement.
+     * Attempt to lookup a declared substatement by its offset in this statement, passing through any implicit
+     * statements which have been created to encapsulate it.
      *
      * @param offset Substatement offset
      * @return Substatement, or null if substatement does not exist.
      */
-    final AbstractResumedStatement<?, ?, ?> lookupSubstatement(final int offset) {
-        return substatements.get(offset);
+    final @Nullable AbstractResumedStatement<?, ?, ?> enterSubstatement(final int offset) {
+        var ret = substatements.get(offset);
+        if (ret != null) {
+            while (ret.origin() == StatementOrigin.CONTEXT) {
+                ret = verifyNotNull(ret.substatements.get(0));
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * End the specified phase for this statement and return this statement's declared parent statement.
+     *
+     * @param phase processing phase that ended
+     * @return Declared parent statement
+     */
+    final @Nullable AbstractResumedStatement<?, ?, ?> exitStatement(final ModelProcessingPhase phase) {
+        finishDeclaration(phase);
+        final var parent = getParentContext();
+        if (parent == null) {
+            return null;
+        }
+
+        var ret = verifyParent(parent);
+        // Unwind all undeclared statements
+        while (ret.origin() == StatementOrigin.CONTEXT) {
+            ret.finishDeclaration(phase);
+            ret = verifyParent(ret.getParentContext());
+        }
+        return ret;
+    }
+
+    // FIXME: AbstractResumedStatement should only ever have AbstractResumedStatement 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 AbstractResumedStatement<?, ?, ?> verifyParent(final StatementContextBase<?, ?, ?> parent) {
+        verify(parent instanceof AbstractResumedStatement, "Unexpected parent context %s", parent);
+        return (AbstractResumedStatement<?, ?, ?>) parent;
     }
 
     final void resizeSubstatements(final int expectedSize) {
         substatements = substatements.ensureCapacity(expectedSize);
     }
 
-    final void walkChildren(final ModelProcessingPhase phase) {
+    final void declarationFinished(final ModelProcessingPhase phase) {
+        finishChildrenDeclaration(phase);
+        finishDeclaration(phase);
+    }
+
+    private void finishChildrenDeclaration(final ModelProcessingPhase phase) {
         checkState(isFullyDefined());
-        substatements.forEach(stmt -> {
-            stmt.walkChildren(phase);
-            stmt.endDeclared(phase);
-        });
+        substatements.forEach(stmt -> stmt.declarationFinished(phase));
+    }
+
+    /**
+     * Ends declared section of current node for the specified phase.
+     *
+     * @param phase processing phase that ended
+     */
+    private void finishDeclaration(final ModelProcessingPhase phase) {
+        definition().onDeclarationFinished(this, phase);
     }
 
     private AbstractResumedStatement<?, ?, ?> createImplicitParent(final int offset,
             final StatementSupport<?, ?, ?> implicitParent, final StatementSourceReference ref, final String argument) {
-        final StatementDefinitionContext<?, ?, ?> def = new StatementDefinitionContext<>(implicitParent);
-        return createSubstatement(offset, def, ImplicitSubstatement.of(ref), argument);
+        return createSubstatement(offset, new StatementDefinitionContext<>(implicitParent),
+            ImplicitSubstatement.of(ref), argument);
     }
 }