Expose Iterator from effectiveChildrenToComplete()
[yangtools.git] / parser / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / AbstractResumedStatement.java
index 9346f701eecad291f2a5f042572d26f0d4b6f586..f5b33582799fafbab1d14b39e795f26ce64e21e1 100644 (file)
@@ -8,11 +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;
@@ -135,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
@@ -204,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
@@ -242,12 +249,13 @@ 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) {
+    final @Nullable AbstractResumedStatement<?, ?, ?> enterSubstatement(final int offset) {
         var ret = substatements.get(offset);
         if (ret != null) {
             while (ret.origin() == StatementOrigin.CONTEXT) {
@@ -257,16 +265,57 @@ abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E ext
         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,