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