import java.util.Map;
import java.util.Optional;
import java.util.Set;
+import java.util.stream.Stream;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.Empty;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.common.QNameModule;
import org.opendaylight.yangtools.yang.common.YangVersion;
import org.opendaylight.yangtools.yang.model.api.stmt.UsesStatement;
import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
import org.opendaylight.yangtools.yang.parser.spi.meta.CopyType;
+import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStatementState;
import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.Current;
import org.opendaylight.yangtools.yang.parser.spi.meta.InferenceException;
import org.opendaylight.yangtools.yang.parser.spi.meta.ModelActionBuilder;
import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase.ExecutionOrder;
import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.Registry;
import org.opendaylight.yangtools.yang.parser.spi.meta.ParserNamespace;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StatementFactory;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext.Mutable;
import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace;
-import org.opendaylight.yangtools.yang.parser.spi.source.SupportedFeaturesNamespace.SupportedFeatures;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
* {@link #buildEffective()} instance. If this context is reused, it can be inflated to {@link EffectiveInstances}
* and also act as a common instance reuse site.
*/
- private @Nullable E effectiveInstance;
+ private @Nullable Object effectiveInstance;
// Master flag controlling whether this context can yield an effective statement
// FIXME: investigate the mechanics that are being supported by this, as it would be beneficial if we can get rid
public abstract RootStatementContext<?, ?, ?> getRoot();
@Override
- public abstract Collection<? extends StatementContextBase<?, ?, ?>> mutableDeclaredSubstatements();
+ public abstract Collection<? extends @NonNull StatementContextBase<?, ?, ?>> mutableDeclaredSubstatements();
@Override
- public final @NonNull Registry getBehaviourRegistry() {
+ public final Registry getBehaviourRegistry() {
return getRoot().getBehaviourRegistryImpl();
}
return QName.create(StmtContextUtils.getRootModuleQName(root), root.getRawArgument());
}
- @Override
- @Deprecated(since = "7.0.9", forRemoval = true)
- public final EffectiveStatement<?, ?> original() {
- return getOriginalCtx().map(StmtContext::buildEffective).orElse(null);
- }
-
//
// In the next two methods we are looking for an effective statement. If we already have an effective instance,
// defer to it's implementation of the equivalent search. Otherwise we search our substatement contexts.
@Override
public final <X, Z extends EffectiveStatement<X, ?>> @NonNull Optional<X> findSubstatementArgument(
final @NonNull Class<Z> type) {
- final E existing = effectiveInstance;
+ final E existing = effectiveInstance();
return existing != null ? existing.findFirstEffectiveSubstatementArgument(type)
: findSubstatementArgumentImpl(type);
}
@Override
public final boolean hasSubstatement(final @NonNull Class<? extends EffectiveStatement<?, ?>> type) {
- final E existing = effectiveInstance;
+ final E existing = effectiveInstance();
return existing != null ? existing.findFirstEffectiveSubstatement(type).isPresent() : hasSubstatementImpl(type);
}
+ private E effectiveInstance() {
+ final Object existing = effectiveInstance;
+ return existing != null ? EffectiveInstances.local(existing) : null;
+ }
+
// Visible due to InferredStatementContext's override. At this point we do not have an effective instance available.
<X, Z extends EffectiveStatement<X, ?>> @NonNull Optional<X> findSubstatementArgumentImpl(
final @NonNull Class<Z> type) {
}
protected ToStringHelper addToStringAttributes(final ToStringHelper toStringHelper) {
- return toStringHelper.add("definition", definition()).add("rawArgument", rawArgument())
- .add("refCount", refString());
+ return toStringHelper.add("definition", definition()).add("argument", argument()).add("refCount", refString());
}
private String refString() {
QNameModule targetModule);
@Override
- public final ReactorStmtCtx<A, D, E> replicaAsChildOf(final Mutable<?, ?, ?> parent) {
+ public final ReplicaStatementContext<A, D, E> replicaAsChildOf(final Mutable<?, ?, ?> parent) {
checkArgument(parent instanceof StatementContextBase, "Unsupported parent %s", parent);
- return replicaAsChildOf((StatementContextBase<?, ?, ?>) parent);
+ final var ret = replicaAsChildOf((StatementContextBase<?, ?, ?>) parent);
+ definition().onStatementAdded(ret);
+ return ret;
}
abstract @NonNull ReplicaStatementContext<A, D, E> replicaAsChildOf(@NonNull StatementContextBase<?, ?, ?> parent);
@Override
public final E buildEffective() {
- final E existing;
- return (existing = effectiveInstance) != null ? existing : loadEffective();
+ final Object existing;
+ return (existing = effectiveInstance) != null ? EffectiveInstances.local(existing) : loadEffective();
}
private @NonNull E loadEffective() {
- // Creating an effective statement does not strictly require a declared instance -- there are statements like
- // 'input', which are implicitly defined.
- // Our implementation design makes an invariant assumption that buildDeclared() has been called by the time
- // we attempt to create effective statement:
- declared();
-
final E ret = createEffective();
effectiveInstance = ret;
// we have called createEffective(), substatements are no longer guarded by us. Let's see if we can clear up
abstract @NonNull E createEffective();
+ /**
+ * Routing of the request to build an effective statement from {@link InferredStatementContext} towards the original
+ * definition site. This is needed to pick the correct instantiation method: for declared statements we will
+ * eventually land in {@link AbstractResumedStatement}, for underclared statements that will be
+ * {@link UndeclaredStmtCtx}.
+ *
+ * @param factory Statement factory
+ * @param ctx Inferred statement context, i.e. where the effective statement is instantiated
+ * @return Built effective stateue
+ */
+ abstract @NonNull E createInferredEffective(@NonNull StatementFactory<A, D, E> factory,
+ @NonNull InferredStatementContext<A, D, E> ctx, Stream<? extends StmtContext<?, ?, ?>> declared,
+ Stream<? extends StmtContext<?, ?, ?>> effective);
+
+ /**
+ * Attach an effective copy of this statement. This essentially acts as a map, where we make a few assumptions:
+ * <ul>
+ * <li>{@code copy} and {@code this} statement share {@link #getOriginalCtx()} if it exists</li>
+ * <li>{@code copy} did not modify any statements relative to {@code this}</li>
+ * </ul>
+ *
+ * @param state effective statement state, acting as a lookup key
+ * @param stmt New copy to append
+ * @return {@code stmt} or a previously-created instances with the same {@code state}
+ */
+ @SuppressWarnings("unchecked")
+ final @NonNull E attachEffectiveCopy(final @NonNull EffectiveStatementState state, final @NonNull E stmt) {
+ final Object local = effectiveInstance;
+ final EffectiveInstances<E> instances;
+ if (local instanceof EffectiveInstances) {
+ instances = (EffectiveInstances<E>) local;
+ } else {
+ effectiveInstance = instances = new EffectiveInstances<>((E) local);
+ }
+ return instances.attachCopy(state, stmt);
+ }
+
/**
* Walk this statement's copy history and return the statement closest to original which has not had its effective
* statements modified. This statement and returned substatement logically have the same set of substatements, hence
}
@Override
- public final void setIsSupportedToBuildEffective(final boolean isSupportedToBuildEffective) {
- this.isSupportedToBuildEffective = isSupportedToBuildEffective;
+ public final void setUnsupported() {
+ this.isSupportedToBuildEffective = false;
}
@Override
*/
if (isParentSupportedByFeatures()) {
// If the set of supported features has not been provided, all features are supported by default.
- final Set<QName> supportedFeatures = getFromNamespace(SupportedFeaturesNamespace.class,
- SupportedFeatures.SUPPORTED_FEATURES);
+ final Set<QName> supportedFeatures = getFromNamespace(SupportedFeaturesNamespace.class, Empty.value());
if (supportedFeatures == null || StmtContextUtils.checkFeatureSupport(this, supportedFeatures)) {
flags |= SET_SUPPORTED_BY_FEATURES;
return true;