Move StatementContextWriter.exitStatement()
[yangtools.git] / parser / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / AbstractResumedStatement.java
1 /*
2  * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.parser.stmt.reactor;
9
10 import static com.google.common.base.Preconditions.checkState;
11 import static com.google.common.base.Verify.verify;
12 import static com.google.common.base.Verify.verifyNotNull;
13 import static java.util.Objects.requireNonNull;
14
15 import com.google.common.collect.ImmutableList;
16 import java.util.Collection;
17 import java.util.List;
18 import java.util.Optional;
19 import java.util.stream.Stream;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
23 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
24 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
25 import org.opendaylight.yangtools.yang.model.api.meta.StatementOrigin;
26 import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
27 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
28 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
29 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
30 import org.opendaylight.yangtools.yang.parser.spi.source.ImplicitSubstatement;
31 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
32 import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter.ResumedStatement;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 /**
37  * Intermediate subclass of StatementContextBase facing the parser stream via implementation of ResumedStatement. This
38  * shields inference-type substatements from these details.
39  *
40  * @param <A> Argument type
41  * @param <D> Declared Statement representation
42  * @param <E> Effective Statement representation
43  */
44 abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
45         extends StatementContextBase<A, D, E> implements ResumedStatement {
46     private static final Logger LOG = LoggerFactory.getLogger(AbstractResumedStatement.class);
47
48     private final @NonNull StatementSourceReference statementDeclSource;
49     private final String rawArgument;
50
51     private List<ReactorStmtCtx<?, ?, ?>> effective = ImmutableList.of();
52     private StatementMap substatements = StatementMap.empty();
53     private @Nullable D declaredInstance;
54
55     // Copy constructor
56     AbstractResumedStatement(final AbstractResumedStatement<A, D, E> original) {
57         super(original);
58         this.statementDeclSource = original.statementDeclSource;
59         this.rawArgument = original.rawArgument;
60         this.substatements = original.substatements;
61         this.declaredInstance = original.declaredInstance;
62     }
63
64     AbstractResumedStatement(final StatementDefinitionContext<A, D, E> def, final StatementSourceReference ref,
65             final String rawArgument) {
66         super(def);
67         this.statementDeclSource = requireNonNull(ref);
68         this.rawArgument = def.support().internArgument(rawArgument);
69     }
70
71     AbstractResumedStatement(final StatementDefinitionContext<A, D, E> def, final StatementSourceReference ref,
72             final String rawArgument, final CopyType copyType) {
73         super(def, copyType);
74         this.statementDeclSource = requireNonNull(ref);
75         this.rawArgument = rawArgument;
76     }
77
78     @Override
79     public final Optional<StmtContext<A, D, E>> getOriginalCtx() {
80         return Optional.empty();
81     }
82
83     @Override
84     public final Optional<StmtContext<A, D, E>> getPreviousCopyCtx() {
85         return Optional.empty();
86     }
87
88     @Override
89     public final StatementSourceReference sourceReference() {
90         return statementDeclSource;
91     }
92
93     @Override
94     public final String rawArgument() {
95         return rawArgument;
96     }
97
98     @Override
99     public Collection<? extends StatementContextBase<?, ?, ?>> mutableDeclaredSubstatements() {
100         return substatements;
101     }
102
103     @Override
104     public final Collection<? extends Mutable<?, ?, ?>> mutableEffectiveSubstatements() {
105         return mutableEffectiveSubstatements(effective);
106     }
107
108     @Override
109     public final void removeStatementFromEffectiveSubstatements(final StatementDefinition statementDef) {
110         effective = removeStatementFromEffectiveSubstatements(effective, statementDef);
111     }
112
113     @Override
114     public final void removeStatementFromEffectiveSubstatements(final StatementDefinition statementDef,
115             final String statementArg) {
116         effective = removeStatementFromEffectiveSubstatements(effective, statementDef, statementArg);
117     }
118
119     @Override
120     public final void addEffectiveSubstatement(final Mutable<?, ?, ?> substatement) {
121         effective = addEffectiveSubstatement(effective, substatement);
122     }
123
124     @Override
125     final void addEffectiveSubstatementsImpl(final Collection<? extends Mutable<?, ?, ?>> statements) {
126         effective = addEffectiveSubstatementsImpl(effective, statements);
127     }
128
129     @Override
130     public final D declared() {
131         final D existing;
132         return (existing = declaredInstance) != null ? existing : loadDeclared();
133     }
134
135     private @NonNull D loadDeclared() {
136         final ModelProcessingPhase phase = getCompletedPhase();
137         checkState(phase == ModelProcessingPhase.FULL_DECLARATION || phase == ModelProcessingPhase.EFFECTIVE_MODEL,
138                 "Cannot build declared instance after phase %s", phase);
139         return declaredInstance = definition().getFactory().createDeclared(this);
140     }
141
142     @Override
143     public final StatementDefinition getDefinition() {
144         return publicDefinition();
145     }
146
147     @Override
148     public final StatementSourceReference getSourceReference() {
149         return statementDeclSource;
150     }
151
152     @Override
153     public final boolean isFullyDefined() {
154         return fullyDefined();
155     }
156
157     /**
158      * Create a new substatement at the specified offset.
159      *
160      * @param offset Substatement offset
161      * @param def definition context
162      * @param ref source reference
163      * @param argument statement argument
164      * @param <X> new substatement argument type
165      * @param <Y> new substatement declared type
166      * @param <Z> new substatement effective type
167      * @return A new substatement
168      */
169     @SuppressWarnings("checkstyle:methodTypeParameterName")
170     final <X, Y extends DeclaredStatement<X>, Z extends EffectiveStatement<X, Y>>
171             AbstractResumedStatement<X, Y, Z> createSubstatement(final int offset,
172                     final StatementDefinitionContext<X, Y, Z> def, final StatementSourceReference ref,
173                     final String argument) {
174         final ModelProcessingPhase inProgressPhase = getRoot().getSourceContext().getInProgressPhase();
175         checkState(inProgressPhase != ModelProcessingPhase.EFFECTIVE_MODEL,
176                 "Declared statement cannot be added in effective phase at: %s", sourceReference());
177
178         final var implicitParent = definition().getImplicitParentFor(this, def.getPublicView());
179         if (implicitParent.isPresent()) {
180             return createImplicitParent(offset, implicitParent.orElseThrow(), ref, argument)
181                 .createSubstatement(0, def, ref, argument);
182         }
183
184         final AbstractResumedStatement<X, Y, Z> ret = new SubstatementContext<>(this, def, ref, argument);
185         substatements = substatements.put(offset, ret);
186         def.onStatementAdded(ret);
187         return ret;
188     }
189
190     @Override
191     final AbstractResumedStatement<A, D, E> unmodifiedEffectiveSource() {
192         // This statement is comes from the source
193         return this;
194     }
195
196     @Override
197     final boolean hasEmptySubstatements() {
198         return substatements.size() == 0 && effective.isEmpty();
199     }
200
201     @Override
202     final boolean noSensitiveSubstatements() {
203         return hasEmptySubstatements()
204             || noSensitiveSubstatements(substatements) && noSensitiveSubstatements(effective);
205     }
206
207     @Override
208     final Iterable<ReactorStmtCtx<?, ?, ?>> effectiveChildrenToComplete() {
209         return effective;
210     }
211
212     @Override
213     final Stream<? extends @NonNull StmtContext<?, ?, ?>> streamDeclared() {
214         return declaredSubstatements().stream().filter(StmtContext::isSupportedToBuildEffective);
215     }
216
217     @Override
218     final Stream<? extends @NonNull StmtContext<?, ?, ?>> streamEffective() {
219         return effective.stream().filter(StmtContext::isSupportedToBuildEffective);
220     }
221
222     @Override
223     final void markNoParentRef() {
224         markNoParentRef(substatements);
225         markNoParentRef(effective);
226     }
227
228     @Override
229     final int sweepSubstatements() {
230         // First we need to sweep all statements, which may trigger sweeps all across the place, for example:
231         // - 'effective' member sweeping a 'substatements' member
232         // - 'substatements' member sweeping a 'substatements' member which came before it during iteration
233         // We then iterate once again, counting what remains unswept
234         sweep(substatements);
235         sweep(effective);
236         final int count = countUnswept(substatements) + countUnswept(effective);
237         if (count != 0) {
238             LOG.debug("{} children left to sweep from {}", count, this);
239         }
240         substatements = null;
241         effective = null;
242         return count;
243     }
244
245     /**
246      * Attempt to lookup a declared substatement by its offset in this statement, passing through any implicit
247      * statements which have been created to encapsulate it.
248      *
249      * @param offset Substatement offset
250      * @return Substatement, or null if substatement does not exist.
251      */
252     final @Nullable AbstractResumedStatement<?, ?, ?> enterSubstatement(final int offset) {
253         var ret = substatements.get(offset);
254         if (ret != null) {
255             while (ret.origin() == StatementOrigin.CONTEXT) {
256                 ret = verifyNotNull(ret.substatements.get(0));
257             }
258         }
259         return ret;
260     }
261
262     /**
263      * End the specified phase for this statement and return this statement's declared parent statement.
264      *
265      * @param phase processing phase that ended
266      * @return Declared parent statement
267      */
268     final @Nullable AbstractResumedStatement<?, ?, ?> exitStatement(final ModelProcessingPhase phase) {
269         endDeclared(phase);
270         final var parent = getParentContext();
271         if (parent == null) {
272             return null;
273         }
274
275         var ret = verifyParent(parent);
276         // Unwind all undeclared statements
277         while (ret.origin() == StatementOrigin.CONTEXT) {
278             ret.endDeclared(phase);
279             ret = verifyParent(ret.getParentContext());
280         }
281         return ret;
282     }
283
284     // FIXME: AbstractResumedStatement should only ever have AbstractResumedStatement parents, which would remove the
285     //        need for this method. In ordered to do that we need to untangle SubstatementContext's users and do not
286     //        allow it being reparent()ed.
287     private static AbstractResumedStatement<?, ?, ?> verifyParent(final StatementContextBase<?, ?, ?> parent) {
288         verify(parent instanceof AbstractResumedStatement, "Unexpected parent context %s", parent);
289         return (AbstractResumedStatement<?, ?, ?>) parent;
290     }
291
292     final void resizeSubstatements(final int expectedSize) {
293         substatements = substatements.ensureCapacity(expectedSize);
294     }
295
296     final void walkChildren(final ModelProcessingPhase phase) {
297         checkState(isFullyDefined());
298         substatements.forEach(stmt -> {
299             stmt.walkChildren(phase);
300             stmt.endDeclared(phase);
301         });
302     }
303
304     /**
305      * Ends declared section of current node for the specified phase.
306      *
307      * @param phase processing phase that ended
308      */
309     final void endDeclared(final ModelProcessingPhase phase) {
310         definition().onDeclarationFinished(this, phase);
311     }
312
313     private AbstractResumedStatement<?, ?, ?> createImplicitParent(final int offset,
314             final StatementSupport<?, ?, ?> implicitParent, final StatementSourceReference ref, final String argument) {
315         return createSubstatement(offset, new StatementDefinitionContext<>(implicitParent),
316             ImplicitSubstatement.of(ref), argument);
317     }
318 }