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