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;
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;
29 * Intermediate subclass of StatementContextBase facing the parser stream via implementation of ResumedStatement. This
30 * shields inference-type substatements from these details.
32 * @param <A> Argument type
33 * @param <D> Declared Statement representation
34 * @param <E> Effective Statement representation
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;
40 private StatementMap substatements = StatementMap.empty();
41 private @Nullable D declaredInstance;
42 private boolean implicitDeclared;
43 private boolean fullyDefined;
46 AbstractResumedStatement(final AbstractResumedStatement<A, D, E> original) {
48 this.rawArgument = original.rawArgument;
49 this.substatements = original.substatements;
50 this.declaredInstance = original.declaredInstance;
51 this.fullyDefined = original.fullyDefined;
54 AbstractResumedStatement(final StatementDefinitionContext<A, D, E> def, final StatementSourceReference ref,
55 final String rawArgument) {
57 this.rawArgument = def.support().internArgument(rawArgument);
61 public final String rawArgument() {
66 public Collection<? extends StatementContextBase<?, ?, ?>> mutableDeclaredSubstatements() {
67 return verifyNotNull(substatements, "Substatements no longer available in %s", this);
71 public final D declared() {
73 return (existing = declaredInstance) != null ? existing : loadDeclared();
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());
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);
89 stream = (Stream) substatements.stream();
92 return stream.map(AbstractResumedStatement::declared);
96 public final StatementDefinition getDefinition() {
97 return publicDefinition();
101 public final StatementSourceReference getSourceReference() {
102 return sourceReference();
106 public final boolean isFullyDefined() {
110 final void setFullyDefined() {
115 final E createEffective(final StatementFactory<A, D, E> factory) {
116 return createEffective(factory, this, streamDeclared(), streamEffective());
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.
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.
131 return factory.createEffective(ctx, declared, effective);
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);
142 * Create a new substatement at the specified offset.
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
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());
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);
170 ret = new SubstatementContext<>(this, def, ref, argument);
171 substatements = substatements.put(offset, ret);
174 def.onStatementAdded(ret);
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);
188 ret = new ImplicitStmtCtx<>(this, support, argument);
189 substatements = substatements.put(offset, ret);
191 support.onStatementAdded(ret);
196 final Stream<? extends @NonNull ReactorStmtCtx<?, ?, ?>> streamDeclared() {
197 return substatements.stream().filter(StmtContext::isSupportedToBuildEffective);
201 final void dropDeclaredSubstatements() {
202 substatements = null;
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.
209 * @param offset Substatement offset
210 * @return Substatement, or null if substatement does not exist.
212 final @Nullable AbstractResumedStatement<?, ?, ?> enterSubstatement(final int offset) {
213 final var stmt = substatements.get(offset);
214 return stmt == null ? null : unmaskUndeclared(stmt);
217 private static @NonNull AbstractResumedStatement<?, ?, ?> unmaskUndeclared(final ReactorStmtCtx<?, ?, ?> stmt) {
219 while (!(ret instanceof AbstractResumedStatement<?, ?, ?> resumed)) {
220 verify(ret instanceof UndeclaredStmtCtx, "Unexpectred statement %s", ret);
221 ret = ((UndeclaredStmtCtx<?, ?, ?>) ret).getResumedSubstatement();
227 * End the specified phase for this statement and return this statement's declared parent statement.
229 * @param phase processing phase that ended
230 * @return Declared parent statement
232 final @Nullable AbstractResumedStatement<?, ?, ?> exitStatement(final ModelProcessingPhase phase) {
233 finishDeclaration(phase);
234 final var parent = getParentContext();
235 if (parent == null) {
239 var ret = verifyParent(parent);
240 // Unwind all undeclared statements
241 while (!(ret instanceof AbstractResumedStatement)) {
242 ret.finishDeclaration(phase);
243 ret = verifyParent(ret.getParentContext());
245 return (AbstractResumedStatement<?, ?, ?>) ret;
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;
256 final void resizeSubstatements(final int expectedSize) {
257 substatements = substatements.ensureCapacity(expectedSize);
261 final void declarationFinished(final ModelProcessingPhase phase) {
262 finishChildrenDeclaration(phase);
263 finishDeclaration(phase);
266 private void finishChildrenDeclaration(final ModelProcessingPhase phase) {
267 checkState(isFullyDefined());
268 substatements.forEach(stmt -> stmt.declarationFinished(phase));