2 * Copyright (c) 2020 PANTHEON.tech, s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.parser.stmt.reactor;
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;
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;
38 * Intermediate subclass of StatementContextBase facing the parser stream via implementation of ResumedStatement. This
39 * shields inference-type substatements from these details.
41 * @param <A> Argument type
42 * @param <D> Declared Statement representation
43 * @param <E> Effective Statement representation
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);
49 private final @NonNull StatementSourceReference statementDeclSource;
50 private final String rawArgument;
52 private List<ReactorStmtCtx<?, ?, ?>> effective = ImmutableList.of();
53 private StatementMap substatements = StatementMap.empty();
54 private @Nullable D declaredInstance;
57 AbstractResumedStatement(final AbstractResumedStatement<A, D, E> original) {
59 this.statementDeclSource = original.statementDeclSource;
60 this.rawArgument = original.rawArgument;
61 this.substatements = original.substatements;
62 this.declaredInstance = original.declaredInstance;
65 AbstractResumedStatement(final StatementDefinitionContext<A, D, E> def, final StatementSourceReference ref,
66 final String rawArgument) {
68 this.statementDeclSource = requireNonNull(ref);
69 this.rawArgument = def.support().internArgument(rawArgument);
72 AbstractResumedStatement(final StatementDefinitionContext<A, D, E> def, final StatementSourceReference ref,
73 final String rawArgument, final CopyType copyType) {
75 this.statementDeclSource = requireNonNull(ref);
76 this.rawArgument = rawArgument;
80 public final Optional<StmtContext<A, D, E>> getOriginalCtx() {
81 return Optional.empty();
85 public final Optional<StmtContext<A, D, E>> getPreviousCopyCtx() {
86 return Optional.empty();
90 public final StatementSourceReference sourceReference() {
91 return statementDeclSource;
95 public final String rawArgument() {
100 public final Collection<? extends StatementContextBase<?, ?, ?>> mutableDeclaredSubstatements() {
101 return substatements;
105 public final Collection<? extends Mutable<?, ?, ?>> mutableEffectiveSubstatements() {
106 return mutableEffectiveSubstatements(effective);
110 public final void removeStatementFromEffectiveSubstatements(final StatementDefinition statementDef) {
111 effective = removeStatementFromEffectiveSubstatements(effective, statementDef);
115 public final void removeStatementFromEffectiveSubstatements(final StatementDefinition statementDef,
116 final String statementArg) {
117 effective = removeStatementFromEffectiveSubstatements(effective, statementDef, statementArg);
121 public final void addEffectiveSubstatement(final Mutable<?, ?, ?> substatement) {
122 effective = addEffectiveSubstatement(effective, substatement);
126 final void addEffectiveSubstatementsImpl(final Collection<? extends Mutable<?, ?, ?>> statements) {
127 effective = addEffectiveSubstatementsImpl(effective, statements);
131 public final D declared() {
133 return (existing = declaredInstance) != null ? existing : loadDeclared();
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());
143 private @NonNull Stream<DeclaredStatement<?>> substatementsAsDeclared() {
144 var stream = substatements.stream();
145 if (getImplicitDeclaredFlag()) {
146 stream = stream.map(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));
157 return stream.map(AbstractResumedStatement::declared);
161 public final StatementDefinition getDefinition() {
162 return publicDefinition();
166 public final StatementSourceReference getSourceReference() {
167 return statementDeclSource;
171 public final boolean isFullyDefined() {
172 return fullyDefined();
176 * Create a new substatement at the specified offset.
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
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());
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);
202 final AbstractResumedStatement<X, Y, Z> ret = new SubstatementContext<>(this, def, ref, argument);
203 substatements = substatements.put(offset, ret);
204 def.onStatementAdded(ret);
209 final AbstractResumedStatement<A, D, E> unmodifiedEffectiveSource() {
210 // This statement is comes from the source
215 final boolean hasEmptySubstatements() {
216 return substatements.size() == 0 && effective.isEmpty();
220 final boolean noSensitiveSubstatements() {
221 return hasEmptySubstatements()
222 || noSensitiveSubstatements(substatements) && noSensitiveSubstatements(effective);
226 final Iterator<ReactorStmtCtx<?, ?, ?>> effectiveChildrenToComplete() {
227 return effective.iterator();
231 final Stream<? extends @NonNull StmtContext<?, ?, ?>> streamDeclared() {
232 return substatements.stream().filter(StmtContext::isSupportedToBuildEffective);
236 final Stream<? extends @NonNull StmtContext<?, ?, ?>> streamEffective() {
237 return effective.stream().filter(StmtContext::isSupportedToBuildEffective);
241 final void markNoParentRef() {
242 markNoParentRef(substatements);
243 markNoParentRef(effective);
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);
254 final int count = countUnswept(substatements) + countUnswept(effective);
256 LOG.debug("{} children left to sweep from {}", count, this);
258 substatements = null;
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.
267 * @param offset Substatement offset
268 * @return Substatement, or null if substatement does not exist.
270 final @Nullable AbstractResumedStatement<?, ?, ?> enterSubstatement(final int offset) {
271 var ret = substatements.get(offset);
273 while (ret.origin() == StatementOrigin.CONTEXT) {
274 ret = verifyNotNull(ret.substatements.get(0));
281 * End the specified phase for this statement and return this statement's declared parent statement.
283 * @param phase processing phase that ended
284 * @return Declared parent statement
286 final @Nullable AbstractResumedStatement<?, ?, ?> exitStatement(final ModelProcessingPhase phase) {
287 finishDeclaration(phase);
288 final var parent = getParentContext();
289 if (parent == null) {
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());
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;
310 final void resizeSubstatements(final int expectedSize) {
311 substatements = substatements.ensureCapacity(expectedSize);
314 final void declarationFinished(final ModelProcessingPhase phase) {
315 finishChildrenDeclaration(phase);
316 finishDeclaration(phase);
319 private void finishChildrenDeclaration(final ModelProcessingPhase phase) {
320 checkState(isFullyDefined());
321 substatements.forEach(stmt -> stmt.declarationFinished(phase));
325 * Ends declared section of current node for the specified phase.
327 * @param phase processing phase that ended
329 private void finishDeclaration(final ModelProcessingPhase phase) {
330 definition().onDeclarationFinished(this, phase);
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);