import org.opendaylight.yangtools.yang.model.api.stmt.SchemaNodeIdentifier.Absolute;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeAwareEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypedefEffectiveStatement;
import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.LeafrefTypeDefinition;
import org.opendaylight.yangtools.yang.model.spi.AbstractEffectiveStatementInference;
}
/**
- * Check if the stack is in instantiated context. This indicates the stack is non-empty and there is no grouping
- * (or similar construct) present in the stack.
+ * Check if the stack is in instantiated context. This indicates the stack is non-empty and there are only screma
+ * tree statements in the stack.
*
- * @return False if the stack is empty or contains a grouping, true otherwise.
+ * @return False if the stack is empty or contains a statement which is not a {@link SchemaTreeEffectiveStatement},
+ * true otherwise.
*/
public boolean inInstantiatedContext() {
- return groupingDepth == 0 && !deque.isEmpty();
+ return groupingDepth == 0 && !deque.isEmpty()
+ && deque.stream().allMatch(SchemaTreeEffectiveStatement.class::isInstance);
+ }
+
+ /**
+ * Check if the stack is in a {@code grouping} context.
+ *
+ * @return False if the stack contains a grouping.
+ */
+ public boolean inGrouping() {
+ return groupingDepth != 0;
}
/**
* {@link #enterSchemaTree(QName)}, except it handles the use case where traversal ignores actual {@code case}
* intermediate schema tree children.
*
- * @param nodeIdentifier Node identifier of the grouping to enter
+ * @param nodeIdentifier Node identifier of the choice to enter
* @return Resolved choice
* @throws NullPointerException if {@code nodeIdentifier} is null
* @throws IllegalArgumentException if the corresponding choice cannot be found
return pushData(requireNonNull(nodeIdentifier));
}
+ /**
+ * Lookup a {@code typedef} by its node identifier and push it to the stack.
+ *
+ * @param nodeIdentifier Node identifier of the typedef to enter
+ * @return Resolved choice
+ * @throws NullPointerException if {@code nodeIdentifier} is null
+ * @throws IllegalArgumentException if the corresponding typedef cannot be found
+ */
+ public @NonNull TypedefEffectiveStatement enterTypedef(final QName nodeIdentifier) {
+ return pushTypedef(requireNonNull(nodeIdentifier));
+ }
+
/**
* Pop the current statement from the stack.
*
return ret;
}
+ private @NonNull TypedefEffectiveStatement pushTypedef(final @NonNull QName nodeIdentifier) {
+ final EffectiveStatement<?, ?> parent = deque.peekFirst();
+ return parent != null ? pushTypedef(parent, nodeIdentifier) : pushFirstTypedef(nodeIdentifier);
+ }
+
+ private @NonNull TypedefEffectiveStatement pushTypedef(final @NonNull EffectiveStatement<?, ?> parent,
+ final @NonNull QName nodeIdentifier) {
+ // TODO: 8.0.0: revisit this once we have TypedefNamespace working
+ final TypedefEffectiveStatement ret = parent.streamEffectiveSubstatements(TypedefEffectiveStatement.class)
+ .filter(stmt -> nodeIdentifier.equals(stmt.argument()))
+ .findFirst()
+ .orElseThrow(() -> new IllegalArgumentException("Grouping " + nodeIdentifier + " not present"));
+ deque.push(ret);
+ return ret;
+ }
+
+ private @NonNull TypedefEffectiveStatement pushFirstTypedef(final @NonNull QName nodeIdentifier) {
+ final ModuleEffectiveStatement module = getModule(nodeIdentifier);
+ final TypedefEffectiveStatement ret = pushTypedef(module, nodeIdentifier);
+ currentModule = module;
+ return ret;
+ }
+
private @NonNull ModuleEffectiveStatement getModule(final @NonNull QName nodeIdentifier) {
final ModuleEffectiveStatement module = effectiveModel.getModuleStatements().get(nodeIdentifier.getModule());
checkArgument(module != null, "Module for %s not found", nodeIdentifier);
tmp.enterSchemaTree(((SchemaTreeEffectiveStatement<?> )stmt).argument());
} else if (stmt instanceof GroupingEffectiveStatement) {
tmp.enterGrouping(((GroupingEffectiveStatement) stmt).argument());
+ } else if (stmt instanceof TypedefEffectiveStatement) {
+ tmp.enterTypedef(((TypedefEffectiveStatement) stmt).argument());
} else {
throw new VerifyException("Unexpected statement " + stmt);
}
--- /dev/null
+/*
+ * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.yang.model.util;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.LeafEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.PathEffectiveStatement;
+import org.opendaylight.yangtools.yang.model.api.stmt.TypeEffectiveStatement;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class YT1282Test {
+ private static EffectiveModelContext context;
+
+ private final SchemaInferenceStack stack = SchemaInferenceStack.of(context);
+
+ @BeforeClass
+ public static void beforeClass() {
+ context = YangParserTestUtils.parseYangResource("/yt1282.yang");
+ }
+
+ @Test
+ public void testResolveTypedef() {
+ final TypeEffectiveStatement<?> type = stack.enterTypedef(QName.create("foo", "foo"))
+ .findFirstEffectiveSubstatement(TypeEffectiveStatement.class).orElseThrow();
+ assertFalse(stack.inInstantiatedContext());
+ assertFalse(stack.inGrouping());
+
+ final EffectiveStatement<?, ?> bar = stack.resolvePathExpression(
+ type.findFirstEffectiveSubstatementArgument(PathEffectiveStatement.class).orElseThrow());
+ assertThat(bar, instanceOf(LeafEffectiveStatement.class));
+ assertEquals(QName.create("foo", "bar"), bar.argument());
+ }
+}