Improve verify() calls
[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
14 import java.util.Collection;
15 import java.util.stream.Stream;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.eclipse.jdt.annotation.Nullable;
18 import org.opendaylight.yangtools.yang.model.api.meta.DeclaredStatement;
19 import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
20 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
21 import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
22 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementFactory;
23 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
24 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
25 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
26 import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter.ResumedStatement;
27
28 /**
29  * Intermediate subclass of StatementContextBase facing the parser stream via implementation of ResumedStatement. This
30  * shields inference-type substatements from these details.
31  *
32  * @param <A> Argument type
33  * @param <D> Declared Statement representation
34  * @param <E> Effective Statement representation
35  */
36 abstract class AbstractResumedStatement<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
37         extends OriginalStmtCtx<A, D, E> implements ResumedStatement {
38     private final String rawArgument;
39
40     private StatementMap substatements = StatementMap.empty();
41     private @Nullable D declaredInstance;
42     private boolean implicitDeclared;
43     private boolean fullyDefined;
44
45     // Copy constructor
46     AbstractResumedStatement(final AbstractResumedStatement<A, D, E> original) {
47         super(original);
48         this.rawArgument = original.rawArgument;
49         this.substatements = original.substatements;
50         this.declaredInstance = original.declaredInstance;
51         this.fullyDefined = original.fullyDefined;
52     }
53
54     AbstractResumedStatement(final StatementDefinitionContext<A, D, E> def, final StatementSourceReference ref,
55             final String rawArgument) {
56         super(def, ref);
57         this.rawArgument = def.support().internArgument(rawArgument);
58     }
59
60     @Override
61     public final String rawArgument() {
62         return rawArgument;
63     }
64
65     @Override
66     public Collection<? extends StatementContextBase<?, ?, ?>> mutableDeclaredSubstatements() {
67         return verifyNotNull(substatements, "Substatements no longer available in %s", this);
68     }
69
70     @Override
71     public final D declared() {
72         final D existing;
73         return (existing = declaredInstance) != null ? existing : loadDeclared();
74     }
75
76     private @NonNull D loadDeclared() {
77         final ModelProcessingPhase phase = getCompletedPhase();
78         checkState(phase == ModelProcessingPhase.FULL_DECLARATION || phase == ModelProcessingPhase.EFFECTIVE_MODEL,
79                 "Cannot build declared instance after phase %s", phase);
80         return declaredInstance = definition().getFactory().createDeclared(this, substatementsAsDeclared());
81     }
82
83     @SuppressWarnings({ "rawtypes", "unchecked" })
84     private @NonNull Stream<DeclaredStatement<?>> substatementsAsDeclared() {
85         final Stream<AbstractResumedStatement<?, ?, ?>> stream;
86         if (implicitDeclared) {
87             stream = substatements.stream().map(AbstractResumedStatement::unmaskUndeclared);
88         } else {
89             stream = (Stream) substatements.stream();
90         }
91
92         return stream.map(AbstractResumedStatement::declared);
93     }
94
95     @Override
96     public final StatementDefinition getDefinition() {
97         return publicDefinition();
98     }
99
100     @Override
101     public final StatementSourceReference getSourceReference() {
102         return sourceReference();
103     }
104
105     @Override
106     public final boolean isFullyDefined() {
107         return fullyDefined;
108     }
109
110     final void setFullyDefined() {
111         fullyDefined = true;
112     }
113
114     @Override
115     final E createEffective(final StatementFactory<A, D, E> factory) {
116         return createEffective(factory, this, streamDeclared(), streamEffective());
117     }
118
119     // Creates EffectiveStatement through full materialization and assumes declared statement presence
120     private @NonNull E createEffective(final StatementFactory<A, D, E> factory,
121             final StatementContextBase<A, D, E> ctx, final Stream<? extends StmtContext<?, ?, ?>> declared,
122             final Stream<? extends ReactorStmtCtx<?, ?, ?>> effective) {
123         // Statement reference count infrastructure makes an assumption that effective statement is only built after
124         // the declared statement is already done. Statements tracked by this class always have a declared view, and
125         // we need to ensure that is built before we touch effective substatements.
126         //
127         // Once the effective substatement stream has been exhausted, reference counting will triggers a sweep, hence
128         // the substatements may be gone by the time the factory attempts to acquire the declared statement.
129         ctx.declared();
130
131         return factory.createEffective(ctx, declared, effective);
132     }
133
134     @Override
135     final E createInferredEffective(final StatementFactory<A, D, E> factory,
136             final InferredStatementContext<A, D, E> ctx, final Stream<? extends ReactorStmtCtx<?, ?, ?>> declared,
137             final Stream<? extends ReactorStmtCtx<?, ?, ?>> effective) {
138         return createEffective(factory, ctx, declared, effective);
139     }
140
141     /**
142      * Create a new substatement at the specified offset.
143      *
144      * @param offset Substatement offset
145      * @param def definition context
146      * @param ref source reference
147      * @param argument statement argument
148      * @param <X> new substatement argument type
149      * @param <Y> new substatement declared type
150      * @param <Z> new substatement effective type
151      * @return A new substatement
152      */
153     @SuppressWarnings("checkstyle:methodTypeParameterName")
154     final <X, Y extends DeclaredStatement<X>, Z extends EffectiveStatement<X, Y>>
155             AbstractResumedStatement<X, Y, Z> createSubstatement(final int offset,
156                     final StatementDefinitionContext<X, Y, Z> def, final StatementSourceReference ref,
157                     final String argument) {
158         final ModelProcessingPhase inProgressPhase = getRoot().getSourceContext().getInProgressPhase();
159         checkState(inProgressPhase != ModelProcessingPhase.EFFECTIVE_MODEL,
160                 "Declared statement cannot be added in effective phase at: %s", sourceReference());
161
162         final SubstatementContext<X, Y, Z> ret;
163         final var implicitParent = definition().getImplicitParentFor(this, def.getPublicView());
164         if (implicitParent.isPresent()) {
165             implicitDeclared = true;
166             final var parent = createUndeclared(offset, implicitParent.orElseThrow(), ref, argument);
167             ret = new SubstatementContext<>(parent, def, ref, argument);
168             parent.addEffectiveSubstatement(ret);
169         } else {
170             ret = new SubstatementContext<>(this, def, ref, argument);
171             substatements = substatements.put(offset, ret);
172         }
173
174         def.onStatementAdded(ret);
175         return ret;
176     }
177
178     private <X, Y extends DeclaredStatement<X>, Z extends EffectiveStatement<X, Y>>
179             UndeclaredStmtCtx<X, Y, Z> createUndeclared(final int offset, final StatementSupport<X, Y, Z> support,
180                 final StatementSourceReference ref, final String argument) {
181         final UndeclaredStmtCtx<X, Y, Z> ret;
182         final var implicitParent = definition().getImplicitParentFor(this, support.getPublicView());
183         if (implicitParent.isPresent()) {
184             final var parent = createUndeclared(offset, implicitParent.orElseThrow(), ref, argument);
185             ret = new ImplicitStmtCtx<>(parent, support, argument);
186             parent.addEffectiveSubstatement(ret);
187         } else {
188             ret = new ImplicitStmtCtx<>(this, support, argument);
189             substatements = substatements.put(offset, ret);
190         }
191         support.onStatementAdded(ret);
192         return ret;
193     }
194
195     @Override
196     final Stream<? extends @NonNull ReactorStmtCtx<?, ?, ?>> streamDeclared() {
197         return substatements.stream().filter(StmtContext::isSupportedToBuildEffective);
198     }
199
200     @Override
201     final void dropDeclaredSubstatements() {
202         substatements = null;
203     }
204
205     /**
206      * Attempt to lookup a declared substatement by its offset in this statement, passing through any implicit
207      * statements which have been created to encapsulate it.
208      *
209      * @param offset Substatement offset
210      * @return Substatement, or null if substatement does not exist.
211      */
212     final @Nullable AbstractResumedStatement<?, ?, ?> enterSubstatement(final int offset) {
213         final var stmt = substatements.get(offset);
214         return stmt == null ? null : unmaskUndeclared(stmt);
215     }
216
217     private static @NonNull AbstractResumedStatement<?, ?, ?> unmaskUndeclared(final ReactorStmtCtx<?, ?, ?> stmt) {
218         var ret = stmt;
219         while (!(ret instanceof AbstractResumedStatement)) {
220             verify(ret instanceof UndeclaredStmtCtx, "Unexpectred statement %s", ret);
221             ret = ((UndeclaredStmtCtx<?, ?, ?>) ret).getResumedSubstatement();
222         }
223         return (AbstractResumedStatement<?, ?, ?>) ret;
224     }
225
226     /**
227      * End the specified phase for this statement and return this statement's declared parent statement.
228      *
229      * @param phase processing phase that ended
230      * @return Declared parent statement
231      */
232     final @Nullable AbstractResumedStatement<?, ?, ?> exitStatement(final ModelProcessingPhase phase) {
233         finishDeclaration(phase);
234         final var parent = getParentContext();
235         if (parent == null) {
236             return null;
237         }
238
239         var ret = verifyParent(parent);
240         // Unwind all undeclared statements
241         while (!(ret instanceof AbstractResumedStatement)) {
242             ret.finishDeclaration(phase);
243             ret = verifyParent(ret.getParentContext());
244         }
245         return (AbstractResumedStatement<?, ?, ?>) ret;
246     }
247
248     // FIXME: AbstractResumedStatement should only ever have OriginalStmtCtx parents, which would remove the need for
249     //        this method. In ordered to do that we need to untangle SubstatementContext's users and do not allow it
250     //        being reparent()ed.
251     private static OriginalStmtCtx<?, ?, ?> verifyParent(final StatementContextBase<?, ?, ?> parent) {
252         verify(parent instanceof OriginalStmtCtx, "Unexpected parent context %s", parent);
253         return (OriginalStmtCtx<?, ?, ?>) parent;
254     }
255
256     final void resizeSubstatements(final int expectedSize) {
257         substatements = substatements.ensureCapacity(expectedSize);
258     }
259
260     @Override
261     final void declarationFinished(final ModelProcessingPhase phase) {
262         finishChildrenDeclaration(phase);
263         finishDeclaration(phase);
264     }
265
266     private void finishChildrenDeclaration(final ModelProcessingPhase phase) {
267         checkState(isFullyDefined());
268         substatements.forEach(stmt -> stmt.declarationFinished(phase));
269     }
270 }