Fix if-feature propagation for implicit case statements
[yangtools.git] / parser / yang-parser-reactor / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / reactor / UndeclaredStmtCtx.java
1 /*
2  * Copyright (c) 2021 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.Verify.verify;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.collect.ImmutableList;
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.parser.spi.meta.CopyType;
21 import org.opendaylight.yangtools.yang.parser.spi.meta.EffectiveStmtCtx.UndeclaredCurrent;
22 import org.opendaylight.yangtools.yang.parser.spi.meta.NamespaceBehaviour.StorageNodeType;
23 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementFactory;
24 import org.opendaylight.yangtools.yang.parser.spi.meta.StatementSupport;
25 import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
26 import org.opendaylight.yangtools.yang.parser.spi.meta.UndeclaredStatementFactory;
27 import org.opendaylight.yangtools.yang.parser.spi.source.ImplicitSubstatement;
28
29 /**
30  * A statement which has not been declared, but exists in the statement hierarchy through some inference.
31  *
32  * @param <A> Argument type
33  * @param <D> Declared Statement representation
34  * @param <E> Effective Statement representation
35  */
36 class UndeclaredStmtCtx<A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>>
37         extends OriginalStmtCtx<A, D, E> implements UndeclaredCurrent<A, D> {
38     private final StatementContextBase<?, ?, ?> parent;
39     private final A argument;
40
41     private UndeclaredStmtCtx(final UndeclaredStmtCtx<A, D, E> original, final StatementContextBase<?, ?, ?> parent) {
42         super(original);
43         this.parent = requireNonNull(parent);
44         this.argument = original.argument;
45     }
46
47     UndeclaredStmtCtx(final StatementContextBase<?, ?, ?> parent, final StatementSupport<A, D, E> support,
48             final @Nullable A argument) {
49         super(new StatementDefinitionContext<>(support), ImplicitSubstatement.of(parent.sourceReference()));
50         this.parent = requireNonNull(parent);
51         this.argument = argument != null ? argument : definition().parseArgumentValue(this, null);
52     }
53
54     // Exposed for StatementContextBase.wrapWithImplicit()
55     UndeclaredStmtCtx(final StatementContextBase<?, ?, ?> original, final StatementSupport<A, D, E> support) {
56         super(new StatementDefinitionContext<>(verifySupport(support)), original.sourceReference(),
57             original.getLastOperation());
58         this.parent = original.getParentContext();
59         this.argument = castArgument(original);
60     }
61
62     // Exposed for implicit substatement wrapping in StatementContextBase.childCopyOf()
63     UndeclaredStmtCtx(final StatementContextBase<?, ?, ?> parent, final StatementSupport<A, D, E> support,
64             final StatementContextBase<?, ?, ?> original, final CopyType type) {
65         super(new StatementDefinitionContext<>(verifySupport(support)), original.sourceReference(), type);
66         this.parent = requireNonNull(parent);
67         this.argument = castArgument(original);
68     }
69
70     // Exposed for ImplicitStmtCtx
71     UndeclaredStmtCtx(final StatementContextBase<?, ?, ?> parent, final StatementSupport<A, D, E> support,
72             final String rawArgument) {
73         super(new StatementDefinitionContext<>(support), ImplicitSubstatement.of(parent.sourceReference()));
74         this.parent = requireNonNull(parent);
75         this.argument = definition().parseArgumentValue(this, rawArgument);
76     }
77
78     // FIXME: this assumes original's argument type matches this type... which is true for the only case we
79     //        currently care about (implicit case in choice, which is always triggered by a SchemaTree original),
80     //        but this will need re-visiting
81     @SuppressWarnings("unchecked")
82     private static <A> @NonNull A castArgument(final StatementContextBase<?, ?, ?> original) {
83         return (A) original.getArgument();
84     }
85
86     private static <T> T verifySupport(final T support) {
87         verify(support instanceof UndeclaredStatementFactory, "Unexpected statement support %s", support);
88         return support;
89     }
90
91     @Override
92     public Collection<? extends StatementContextBase<?, ?, ?>> mutableDeclaredSubstatements() {
93         return ImmutableList.of();
94     }
95
96     @Override
97     Stream<? extends @NonNull StmtContext<?, ?, ?>> streamDeclared() {
98         return Stream.empty();
99     }
100
101     @Override
102     void dropDeclaredSubstatements() {
103         // No-op
104     }
105
106     @Override
107     UndeclaredStmtCtx<A, D, E> reparent(final StatementContextBase<?, ?, ?> newParent) {
108         return new UndeclaredStmtCtx<>(this, newParent);
109     }
110
111     @Override
112     E createEffective(final StatementFactory<A, D, E> factory) {
113         return createEffective(factory, this, streamEffective());
114     }
115
116     @SuppressWarnings("unchecked")
117     private static <A, D extends DeclaredStatement<A>, E extends EffectiveStatement<A, D>> @NonNull E createEffective(
118             final @NonNull StatementFactory<A, D, E> factory, final @NonNull UndeclaredCurrent<A, D> ctx,
119             final @NonNull Stream<? extends StmtContext<?, ?, ?>> substatements) {
120         verify(factory instanceof UndeclaredStatementFactory, "Unexpected factory %s", factory);
121         return ((UndeclaredStatementFactory<A, D, E>) factory).createUndeclaredEffective(ctx, substatements);
122     }
123
124     @Override
125     E createInferredEffective(final StatementFactory<A, D, E> factory, final InferredStatementContext<A, D, E> ctx,
126             final Stream<? extends StmtContext<?, ?, ?>> declared,
127             final Stream<? extends StmtContext<?, ?, ?>> effective) {
128         final long declaredCount = declared.count();
129         verify(declaredCount == 0, "Unexpected non-empty declared statements in %s", ctx);
130         return createEffective(factory, new ForwardingUndeclaredCurrent<>(ctx), effective);
131     }
132
133     /*
134      * KEEP THINGS ORGANIZED!
135      *
136      * below methods exist in the same form in InferredStatementContext. If any adjustment is made here, make sure it is
137      * properly updated there.
138      */
139     @Override
140     public A argument() {
141         return argument;
142     }
143
144     @Override
145     public StatementContextBase<?, ?, ?> getParentContext() {
146         return parent;
147     }
148
149     @Override
150     public StorageNodeType getStorageNodeType() {
151         return StorageNodeType.STATEMENT_LOCAL;
152     }
153
154     @Override
155     public StatementContextBase<?, ?, ?> getParentNamespaceStorage() {
156         return parent;
157     }
158
159     @Override
160     public RootStatementContext<?, ?, ?> getRoot() {
161         return parent.getRoot();
162     }
163
164     @Override
165     public EffectiveConfig effectiveConfig() {
166         return effectiveConfig(parent);
167     }
168
169     @Override
170     protected boolean isIgnoringIfFeatures() {
171         return isIgnoringIfFeatures(parent);
172     }
173
174     @Override
175     protected boolean isIgnoringConfig() {
176         return isIgnoringConfig(parent);
177     }
178
179     @Override
180     protected boolean isParentSupportedByFeatures() {
181         return parent.isSupportedByFeatures();
182     }
183 }