import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.stream.Collectors;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.binding.generator.impl.tree.SchemaTreeChild;
+import org.opendaylight.mdsal.binding.generator.impl.tree.SchemaTreeParent;
import org.opendaylight.mdsal.binding.model.api.Enumeration;
import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
import org.opendaylight.mdsal.binding.model.api.GeneratedType;
* with linking original instances in the tree iteration order. The part dealing with augment attachment lives mostly
* in {@link AugmentRequirement}.
*/
-abstract class AbstractCompositeGenerator<T extends EffectiveStatement<?, ?>> extends AbstractExplicitGenerator<T> {
+public abstract class AbstractCompositeGenerator<T extends EffectiveStatement<?, ?>>
+ extends AbstractExplicitGenerator<T> implements SchemaTreeParent<T> {
private static final Logger LOG = LoggerFactory.getLogger(AbstractCompositeGenerator.class);
// FIXME: we want to allocate this lazily to lower memory footprint
private final @NonNull CollisionDomain domain = new CollisionDomain(this);
- private final List<Generator> children;
+ private final @NonNull List<Generator> childGenerators;
+ /**
+ * {@link SchemaTreeChild} children of this generator. Generator linkage is ensured on first access.
+ */
+ private final @NonNull List<SchemaTreeChild<?, ?>> schemaTreeChildren;
/**
* List of {@code augment} statements targeting this generator. This list is maintained only for the primary
AbstractCompositeGenerator(final T statement) {
super(statement);
- children = createChildren(statement);
+
+ final var children = createChildren(statement);
+ childGenerators = children.getKey();
+ schemaTreeChildren = children.getValue();
}
AbstractCompositeGenerator(final T statement, final AbstractCompositeGenerator<?> parent) {
super(statement, parent);
- children = createChildren(statement);
+
+ final var children = createChildren(statement);
+ childGenerators = children.getKey();
+ schemaTreeChildren = children.getValue();
}
@Override
public final Iterator<Generator> iterator() {
- return children.iterator();
+ return childGenerators.iterator();
+ }
+
+ @Override
+ public List<SchemaTreeChild<?, ?>> schemaTreeChildren() {
+ for (var child : schemaTreeChildren) {
+ if (child instanceof SchemaTreePlaceholder) {
+ ((SchemaTreePlaceholder<?, ?>) child).setGenerator(this);
+ }
+ }
+ return schemaTreeChildren;
}
@Override
final boolean isEmpty() {
- return children.isEmpty();
+ return childGenerators.isEmpty();
}
final @Nullable AbstractExplicitGenerator<?> findGenerator(final List<EffectiveStatement<?, ?>> stmtPath) {
final EffectiveStatement<?, ?> stmt = stmtPath.get(offset);
// Try direct children first, which is simple
- AbstractExplicitGenerator<?> ret = childStrategy.findGenerator(stmt, children);
+ AbstractExplicitGenerator<?> ret = childStrategy.findGenerator(stmt, childGenerators);
if (ret != null) {
final int next = offset + 1;
if (stmtPath.size() == next) {
}
final void startUsesAugmentLinkage(final List<AugmentRequirement> requirements) {
- for (Generator child : children) {
+ for (Generator child : childGenerators) {
if (child instanceof UsesAugmentGenerator) {
requirements.add(((UsesAugmentGenerator) child).startLinkage());
}
}
if (unlinkedChildren == null) {
- unlinkedChildren = children.stream()
+ unlinkedChildren = childGenerators.stream()
.filter(AbstractExplicitGenerator.class::isInstance)
.map(child -> (AbstractExplicitGenerator<?>) child)
.collect(Collectors.toList());
}
}
- private List<Generator> createChildren(final EffectiveStatement<?, ?> statement) {
- final List<Generator> tmp = new ArrayList<>();
- final List<AbstractAugmentGenerator> tmpAug = new ArrayList<>();
+ private Entry<List<Generator>, List<SchemaTreeChild<?, ?>>> createChildren(
+ final EffectiveStatement<?, ?> statement) {
+ final var tmp = new ArrayList<Generator>();
+ final var tmpAug = new ArrayList<AbstractAugmentGenerator>();
+ final var tmpSchema = new ArrayList<SchemaTreeChild<?, ?>>();
- for (EffectiveStatement<?, ?> stmt : statement.effectiveSubstatements()) {
+ for (var stmt : statement.effectiveSubstatements()) {
if (stmt instanceof ActionEffectiveStatement) {
- if (!isAugmenting(stmt)) {
- tmp.add(new ActionGenerator((ActionEffectiveStatement) stmt, this));
+ final var cast = (ActionEffectiveStatement) stmt;
+ if (isAugmenting(cast)) {
+ tmpSchema.add(new SchemaTreePlaceholder<>(cast, ActionGenerator.class));
+ } else {
+ tmp.add(new ActionGenerator(cast, this));
}
} else if (stmt instanceof AnydataEffectiveStatement) {
- if (!isAugmenting(stmt)) {
- tmp.add(new OpaqueObjectGenerator<>((AnydataEffectiveStatement) stmt, this));
+ final var cast = (AnydataEffectiveStatement) stmt;
+ if (isAugmenting(stmt)) {
+ tmpSchema.add(new SchemaTreePlaceholder<>(cast, OpaqueObjectGenerator.class));
+ } else {
+ tmp.add(new OpaqueObjectGenerator<>(cast, this));
}
} else if (stmt instanceof AnyxmlEffectiveStatement) {
- if (!isAugmenting(stmt)) {
- tmp.add(new OpaqueObjectGenerator<>((AnyxmlEffectiveStatement) stmt, this));
+ final var cast = (AnyxmlEffectiveStatement) stmt;
+ if (isAugmenting(stmt)) {
+ tmpSchema.add(new SchemaTreePlaceholder<>(cast, OpaqueObjectGenerator.class));
+ } else {
+ tmp.add(new OpaqueObjectGenerator<>(cast, this));
}
} else if (stmt instanceof CaseEffectiveStatement) {
tmp.add(new CaseGenerator((CaseEffectiveStatement) stmt, this));
} else if (stmt instanceof ChoiceEffectiveStatement) {
+ final var cast = (ChoiceEffectiveStatement) stmt;
// FIXME: use isOriginalDeclaration() ?
- if (!isAddedByUses(stmt)) {
- tmp.add(new ChoiceGenerator((ChoiceEffectiveStatement) stmt, this));
+ if (isAddedByUses(stmt)) {
+ tmpSchema.add(new SchemaTreePlaceholder<>(cast, ChoiceGenerator.class));
+ } else {
+ tmp.add(new ChoiceGenerator(cast, this));
}
} else if (stmt instanceof ContainerEffectiveStatement) {
+ final var cast = (ContainerEffectiveStatement) stmt;
if (isOriginalDeclaration(stmt)) {
tmp.add(new ContainerGenerator((ContainerEffectiveStatement) stmt, this));
+ } else {
+ tmpSchema.add(new SchemaTreePlaceholder<>(cast, ContainerGenerator.class));
}
} else if (stmt instanceof GroupingEffectiveStatement) {
tmp.add(new GroupingGenerator((GroupingEffectiveStatement) stmt, this));
tmp.add(this instanceof RpcGenerator ? new RpcContainerGenerator((InputEffectiveStatement) stmt, this)
: new OperationContainerGenerator((InputEffectiveStatement) stmt, this));
} else if (stmt instanceof LeafEffectiveStatement) {
- if (!isAugmenting(stmt)) {
- tmp.add(new LeafGenerator((LeafEffectiveStatement) stmt, this));
+ final var cast = (LeafEffectiveStatement) stmt;
+ if (isAugmenting(stmt)) {
+ tmpSchema.add(new SchemaTreePlaceholder<>(cast, LeafGenerator.class));
+ } else {
+ tmp.add(new LeafGenerator(cast, this));
}
} else if (stmt instanceof LeafListEffectiveStatement) {
- if (!isAugmenting(stmt)) {
+ final var cast = (LeafListEffectiveStatement) stmt;
+ if (isAugmenting(stmt)) {
+ tmpSchema.add(new SchemaTreePlaceholder<>(cast, LeafListGenerator.class));
+ } else {
tmp.add(new LeafListGenerator((LeafListEffectiveStatement) stmt, this));
}
} else if (stmt instanceof ListEffectiveStatement) {
+ final var cast = (ListEffectiveStatement) stmt;
if (isOriginalDeclaration(stmt)) {
- final ListGenerator listGen = new ListGenerator((ListEffectiveStatement) stmt, this);
+ final ListGenerator listGen = new ListGenerator(cast, this);
tmp.add(listGen);
final KeyGenerator keyGen = listGen.keyGenerator();
if (keyGen != null) {
tmp.add(keyGen);
}
+ } else {
+ tmpSchema.add(new SchemaTreePlaceholder<>(cast, ListGenerator.class));
}
} else if (stmt instanceof NotificationEffectiveStatement) {
- if (!isAugmenting(stmt)) {
- tmp.add(new NotificationGenerator((NotificationEffectiveStatement) stmt, this));
+ final var cast = (NotificationEffectiveStatement) stmt;
+ if (isAugmenting(stmt)) {
+ tmpSchema.add(new SchemaTreePlaceholder<>(cast, NotificationGenerator.class));
+ } else {
+ tmp.add(new NotificationGenerator(cast, this));
}
} else if (stmt instanceof OutputEffectiveStatement) {
// FIXME: do not generate legacy RPC layout
}
}
+ // Add any SchemaTreeChild generators to the list
+ for (var child : tmp) {
+ if (child instanceof SchemaTreeChild) {
+ tmpSchema.add((SchemaTreeChild<?, ?>) child);
+ }
+ }
+
// Sort augments and add them last. This ensures child iteration order always reflects potential
// interdependencies, hence we do not need to worry about them. This is extremely important, as there are a
// number of places where we would have to either move the logic to parent statement and explicitly filter/sort
}
}
- return List.copyOf(tmp);
+ return Map.entry(List.copyOf(tmp), List.copyOf(tmpSchema));
}
// Utility equivalent of (!isAddedByUses(stmt) && !isAugmenting(stmt)). Takes advantage of relationship between
import static com.google.common.base.Verify.verify;
+import org.opendaylight.mdsal.binding.generator.impl.tree.SchemaTreeChild;
import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
import org.opendaylight.mdsal.binding.model.api.Type;
import org.opendaylight.yangtools.yang.model.api.TypedDataSchemaNode;
import org.opendaylight.yangtools.yang.model.api.stmt.DataTreeEffectiveStatement;
import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* Common base class for {@link LeafGenerator} and {@link LeafListGenerator}.
*/
-abstract class AbstractTypeAwareGenerator<T extends DataTreeEffectiveStatement<?>>
- extends AbstractTypeObjectGenerator<T> {
- private static final Logger LOG = LoggerFactory.getLogger(AbstractTypeAwareGenerator.class);
-
+abstract class AbstractTypeAwareGenerator<T extends DataTreeEffectiveStatement<?>,
+ G extends AbstractTypeAwareGenerator<T, G>>
+ extends AbstractTypeObjectGenerator<T> implements SchemaTreeChild<T, G> {
private IdentityGenerator contextType;
AbstractTypeAwareGenerator(final T statement, final AbstractCompositeGenerator<?> parent) {
verify(statement instanceof TypeAware, "Unexpected statement %s", statement);
}
+ @Override
+ @SuppressWarnings("unchecked")
+ public final G generator() {
+ return (G) this;
+ }
+
@Override
final void pushToInference(final SchemaInferenceStack dataTree) {
dataTree.enterDataTree(statement().getIdentifier());
/**
* Generator corresponding to a {@code action} statement.
*/
-final class ActionGenerator extends AbstractCompositeGenerator<ActionEffectiveStatement> {
+final class ActionGenerator extends CompositeSchemaTreeGenerator<ActionEffectiveStatement, ActionGenerator> {
ActionGenerator(final ActionEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
super(statement, parent);
}
/**
* Generator corresponding to a {@code case} statement.
*/
-final class CaseGenerator extends AbstractCompositeGenerator<CaseEffectiveStatement> {
+final class CaseGenerator extends CompositeSchemaTreeGenerator<CaseEffectiveStatement, CaseGenerator> {
CaseGenerator(final CaseEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
super(statement, parent);
}
/**
* Generator corresponding to a {@code choice} statement.
*/
-final class ChoiceGenerator extends AbstractCompositeGenerator<ChoiceEffectiveStatement> {
+final class ChoiceGenerator extends CompositeSchemaTreeGenerator<ChoiceEffectiveStatement, ChoiceGenerator> {
ChoiceGenerator(final ChoiceEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
super(statement, parent);
}
--- /dev/null
+/*
+ * Copyright (c) 2022 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.mdsal.binding.generator.impl.reactor;
+
+import org.opendaylight.mdsal.binding.generator.impl.tree.SchemaTreeChild;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+
+/**
+ * Abstract base class for {@link AbstractCompositeGenerator}s which are also {@link SchemaTreeChild}ren.
+ */
+abstract class CompositeSchemaTreeGenerator<S extends SchemaTreeEffectiveStatement<?>,
+ G extends CompositeSchemaTreeGenerator<S, G>>
+ extends AbstractCompositeGenerator<S> implements SchemaTreeChild<S, G> {
+ CompositeSchemaTreeGenerator(final S statement, final AbstractCompositeGenerator<?> parent) {
+ super(statement, parent);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public final G generator() {
+ return (G) this;
+ }
+}
/**
* Generator corresponding to a {@code container} statement.
*/
-final class ContainerGenerator extends AbstractCompositeGenerator<ContainerEffectiveStatement> {
+final class ContainerGenerator extends CompositeSchemaTreeGenerator<ContainerEffectiveStatement, ContainerGenerator> {
ContainerGenerator(final ContainerEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
super(statement, parent);
}
}
LOG.trace("Processing linkage of {} augment generators", augments.size());
- // Step 1c: ... finally establish linkage along the reverse uses/augment axis. This is needed to route generated
- // type manifestations (isAddedByUses/isAugmenting) to their type generation sites. Since generator
- // tree iteration order does not match dependencies, we may need to perform multiple passes.
+ // Step 1c: Establish linkage along the reverse uses/augment axis. This is needed to route generated type
+ // manifestations (isAddedByUses/isAugmenting) to their type generation sites. Since generator tree
+ // iteration order does not match dependencies, we may need to perform multiple passes.
for (ModuleGenerator module : children) {
verify(module.linkOriginalGenerator(), "Module %s failed to link", module);
}
}
}
- private @NonNull AbstractTypeAwareGenerator<?> strictResolvePath(final @NonNull PathExpression path) {
+ private @NonNull AbstractTypeAwareGenerator<?, ?> strictResolvePath(final @NonNull PathExpression path) {
try {
inferenceStack.resolvePathExpression(path);
} catch (IllegalArgumentException e) {
return mapToGenerator();
}
- private @Nullable AbstractTypeAwareGenerator<?> lenientResolveLeafref(final @NonNull PathExpression path) {
+ private @Nullable AbstractTypeAwareGenerator<?, ?> lenientResolveLeafref(final @NonNull PathExpression path) {
try {
inferenceStack.resolvePathExpression(path);
} catch (IllegalArgumentException e) {
}
// Map a statement to the corresponding generator
- private @NonNull AbstractTypeAwareGenerator<?> mapToGenerator() {
+ private @NonNull AbstractTypeAwareGenerator<?, ?> mapToGenerator() {
// Some preliminaries first: we need to be in the correct module to walk the path
final ModuleEffectiveStatement module = inferenceStack.currentModule();
final ModuleGenerator gen = verifyNotNull(generators.get(module.localQNameModule()),
final List<EffectiveStatement<?, ?>> stmtPath = inferenceStack.toInference().statementPath();
final AbstractExplicitGenerator<?> found = gen.findGenerator(stmtPath);
if (found instanceof AbstractTypeAwareGenerator) {
- return (AbstractTypeAwareGenerator<?>) found;
+ return (AbstractTypeAwareGenerator<?, ?>) found;
}
throw new VerifyException("Statements " + stmtPath + " resulted in unexpected " + found);
}
/**
* Generator corresponding to a {@code leaf} statement.
*/
-final class LeafGenerator extends AbstractTypeAwareGenerator<LeafEffectiveStatement> {
+final class LeafGenerator extends AbstractTypeAwareGenerator<LeafEffectiveStatement, LeafGenerator> {
LeafGenerator(final LeafEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
super(statement, parent);
}
/**
* Generator corresponding to a {@code leaf-list} statement.
*/
-final class LeafListGenerator extends AbstractTypeAwareGenerator<LeafListEffectiveStatement> {
+final class LeafListGenerator extends AbstractTypeAwareGenerator<LeafListEffectiveStatement, LeafListGenerator> {
LeafListGenerator(final LeafListEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
super(statement, parent);
}
/**
* Generator corresponding to a {@code list} statement.
*/
-final class ListGenerator extends AbstractCompositeGenerator<ListEffectiveStatement> {
+final class ListGenerator extends CompositeSchemaTreeGenerator<ListEffectiveStatement, ListGenerator> {
private final @Nullable KeyGenerator keyGen;
ListGenerator(final ListEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
/**
* Generator corresponding to a {@code notification} statement.
*/
-final class NotificationGenerator extends AbstractCompositeGenerator<NotificationEffectiveStatement> {
+final class NotificationGenerator
+ extends CompositeSchemaTreeGenerator<NotificationEffectiveStatement, NotificationGenerator> {
NotificationGenerator(final NotificationEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
super(statement, parent);
}
*/
package org.opendaylight.mdsal.binding.generator.impl.reactor;
+import org.opendaylight.mdsal.binding.generator.impl.tree.SchemaTreeChild;
import org.opendaylight.mdsal.binding.model.api.GeneratedType;
import org.opendaylight.mdsal.binding.model.api.Type;
import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
/**
* Common generator for {@code anydata} and {@code anyxml}.
*/
-final class OpaqueObjectGenerator<T extends DataTreeEffectiveStatement<?>> extends AbstractExplicitGenerator<T> {
+final class OpaqueObjectGenerator<T extends DataTreeEffectiveStatement<?>> extends AbstractExplicitGenerator<T>
+ implements SchemaTreeChild<T, OpaqueObjectGenerator<T>> {
OpaqueObjectGenerator(final T statement, final AbstractCompositeGenerator<?> parent) {
super(statement, parent);
}
+ @Override
+ public OpaqueObjectGenerator<T> generator() {
+ return this;
+ }
+
@Override
void pushToInference(final SchemaInferenceStack dataTree) {
dataTree.enterDataTree(statement().getIdentifier());
/**
* Generator corresponding to an {@code input} or an {@code output} statement.
*/
-class OperationContainerGenerator extends AbstractCompositeGenerator<SchemaTreeEffectiveStatement<?>> {
+class OperationContainerGenerator
+ extends CompositeSchemaTreeGenerator<SchemaTreeEffectiveStatement<?>, OperationContainerGenerator> {
private final ConcreteType baseInterface;
OperationContainerGenerator(final InputEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
/**
* Generator corresponding to a {@code rpc} statement.
*/
-final class RpcGenerator extends AbstractCompositeGenerator<RpcEffectiveStatement> {
+final class RpcGenerator extends CompositeSchemaTreeGenerator<RpcEffectiveStatement, RpcGenerator> {
RpcGenerator(final RpcEffectiveStatement statement, final AbstractCompositeGenerator<?> parent) {
super(statement, parent);
}
--- /dev/null
+/*
+ * Copyright (c) 2022 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.mdsal.binding.generator.impl.reactor;
+
+import static com.google.common.base.Verify.verify;
+import static com.google.common.base.Verify.verifyNotNull;
+import static java.util.Objects.requireNonNull;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.binding.generator.impl.tree.SchemaTreeChild;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+
+/**
+ * A placeholder {@link SchemaTreeChild}.
+ *
+ */
+final class SchemaTreePlaceholder<S extends SchemaTreeEffectiveStatement<?>,
+ G extends AbstractExplicitGenerator<S> & SchemaTreeChild<S, G>> implements SchemaTreeChild<S, G> {
+ private final @NonNull Class<G> generatorType;
+ private final @NonNull S statement;
+
+ private @Nullable G generator;
+
+ SchemaTreePlaceholder(final S statement, final Class<G> generatorType) {
+ this.statement = requireNonNull(statement);
+ this.generatorType = requireNonNull(generatorType);
+ }
+
+ @Override
+ public S statement() {
+ return statement;
+ }
+
+ @Override
+ public G generator() {
+ final var local = generator;
+ if (local == null) {
+ throw new IllegalStateException("Unresolved generator in " + this);
+ }
+ return local;
+ }
+
+ void setGenerator(final AbstractCompositeGenerator<?> parent) {
+ verify(generator == null, "Attempted to set generator for %s", this);
+ final var qname = getIdentifier();
+ generator = generatorType.cast(verifyNotNull(parent.findSchemaTreeGenerator(qname),
+ "Failed to find generator for child %s in %s", qname, parent));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2022 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.mdsal.binding.generator.impl.tree;
+
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.binding.generator.impl.reactor.AbstractExplicitGenerator;
+import org.opendaylight.yangtools.concepts.Identifiable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.stmt.SchemaTreeEffectiveStatement;
+
+/**
+ * An object reflecting a YANG {@code schema node}.
+ *
+ * @param <S> Concrete {@link SchemaTreeEffectiveStatement} type
+ * @param <G> Concrete {@link AbstractExplicitGenerator} type
+ */
+// FIXME: do not reference Generator once we have the codegen and runtime views well-defined
+public interface SchemaTreeChild<S extends SchemaTreeEffectiveStatement<?>,
+ G extends AbstractExplicitGenerator<S> & SchemaTreeChild<S, G>> extends Identifiable<QName> {
+ @Override
+ default QName getIdentifier() {
+ return statement().argument();
+ }
+
+ /**
+ * Return the effective YANG statement being represented by this object.
+ *
+ * @return A YANG statement
+ */
+ @NonNull S statement();
+
+ /**
+ * Return the generator responsible for handling the binding type view of this statement. Note that the statement
+ * returned by {@code generator().statement()} may differ from the statement returned by {@link #statement()}.
+ *
+ * @return Underlying binding generator
+ * @throws IllegalStateException if the generator has not been resolved yet
+ */
+ @NonNull G generator();
+}
--- /dev/null
+/*
+ * Copyright (c) 2022 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.mdsal.binding.generator.impl.tree;
+
+import java.util.List;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
+
+/**
+ * A parent containing a number of {@link SchemaTreeChild} objects.
+ *
+ * @param <S> Concrete {@link EffectiveStatement} type
+ */
+// FIXME: S extends SchemaTreeAwareStatement ... once AugmentEffectiveStatement implements that
+public interface SchemaTreeParent<S extends EffectiveStatement<?, ?>> {
+ /*
+ * Immutable view of children of this object along the {@code schema tree} child axis.
+ *
+ * @return Immutable view of this objects children along the {@code schema tree} child axis.
+ */
+ @NonNull List<SchemaTreeChild<?, ?>> schemaTreeChildren();
+}
--- /dev/null
+/*
+ * Copyright (c) 2022 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
+ */
+/**
+ * Concepts relating to the organization of the tree backing the codegen and runtime type information generator.
+ */
+package org.opendaylight.mdsal.binding.generator.impl.tree;
\ No newline at end of file