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