X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=binding%2Fmdsal-binding-generator%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fbinding%2Fgenerator%2Fimpl%2Freactor%2FGeneratorReactor.java;h=2907f0e2324be93feb2c6a1c1cbb6f1639abf6dd;hb=59b1a7d1771becd7ed5c38abb2055849e8b30769;hp=8eec089c175edcb0565bffd9954f8e03b851de5e;hpb=3131e455f634c58b81443b6ddfa495e448c2a7bf;p=mdsal.git diff --git a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/GeneratorReactor.java b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/GeneratorReactor.java index 8eec089c17..2907f0e232 100644 --- a/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/GeneratorReactor.java +++ b/binding/mdsal-binding-generator/src/main/java/org/opendaylight/mdsal/binding/generator/impl/reactor/GeneratorReactor.java @@ -21,6 +21,7 @@ import java.util.Deque; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.function.Function; import java.util.stream.Collectors; import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; @@ -33,6 +34,7 @@ import org.opendaylight.yangtools.yang.binding.ChoiceIn; import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.common.QNameModule; import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; +import org.opendaylight.yangtools.yang.model.api.Module; import org.opendaylight.yangtools.yang.model.api.PathExpression; import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement; import org.opendaylight.yangtools.yang.model.api.stmt.ModuleEffectiveStatement; @@ -70,6 +72,7 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable private State state = State.INITIALIZED; public GeneratorReactor(final EffectiveModelContext context) { + super(context); inferenceStack = SchemaInferenceStack.of(context); // Construct modules and their subtrees. Dependency sort is very much needed here, as it establishes order of @@ -77,10 +80,8 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable // AugmentGenerators without having forward references. // FIXME: migrate to new ModuleDependencySort when it is available, which streamline things here children = ModuleDependencySort.sort(context.getModules()).stream() - .map(module -> { - verify(module instanceof ModuleEffectiveStatement, "Unexpected module %s", module); - return new ModuleGenerator((ModuleEffectiveStatement) module); - }) + .map(Module::asEffectiveStatement) + .map(ModuleGenerator::new) .collect(Collectors.toUnmodifiableList()); generators = Maps.uniqueIndex(children, gen -> gen.statement().localQNameModule()); } @@ -122,33 +123,57 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable // Start measuring time... final Stopwatch sw = Stopwatch.createStarted(); - // Step 1a: walk all composite generators and resolve 'uses' statements to the corresponding grouping node, - // establishing implied inheritance ... + // Step 1a: Walk all composite generators and resolve 'uses' statements to the corresponding grouping generator, + // establishing implied inheritance. During this walk we maintain 'stack' to aid this process. + // This indirectly triggers resolution of UsesAugmentGenerators' targets by hooking a requirement + // on the resolved grouping's child nodes as needed. linkUsesDependencies(children); - // Step 1b: ... and also link augments and their targets in a separate pass, as we need groupings fully resolved - // before we attempt augmentation lookups ... + // Step 1b: Walk all module generators and start ModuleAugmentGenerators' target resolution by linking the first + // step of each 'augment' statement to its corresponding instantiated site. + // Then start all UsesAugmentGenerators' target resolution. + final var augments = new ArrayList(); for (ModuleGenerator module : children) { - for (Generator child : module) { - if (child instanceof ModuleAugmentGenerator) { - ((ModuleAugmentGenerator) child).linkAugmentationTarget(this); + for (Generator gen : module) { + if (gen instanceof ModuleAugmentGenerator moduleGen) { + augments.add(moduleGen.startLinkage(this)); } } } + for (ModuleGenerator module : children) { + module.startUsesAugmentLinkage(augments); + } + 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. - long unlinkedOriginals = Long.MAX_VALUE; - do { - long remaining = 0; - for (ModuleGenerator module : children) { - remaining += module.linkOriginalGenerator(); + // 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); + } + + final var unlinkedModules = new ArrayList<>(children); + while (true) { + final boolean progress = + progressAndClean(unlinkedModules, ModuleGenerator::linkOriginalGeneratorRecursive) + // not '||' because we need the side-effects, which would get short-circuited + | progressAndClean(augments, AugmentRequirement::resolve); + + if (augments.isEmpty() && unlinkedModules.isEmpty()) { + break; } - verify(remaining < unlinkedOriginals, "Failed to make progress on linking of remaining %s originals", - remaining); - unlinkedOriginals = remaining; - } while (unlinkedOriginals != 0); + + if (!progress) { + final var ex = new VerifyException("Failed to make progress on linking of original generators"); + for (var augment : augments) { + ex.addSuppressed(new IllegalStateException(augment + " is incomplete")); + } + for (var module : unlinkedModules) { + ex.addSuppressed(new IllegalStateException(module + " remains unlinked")); + } + throw ex; + } + } /* * Step 2: link typedef statements, so that typedef's 'type' axis is fully established @@ -219,14 +244,14 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable for (Generator gen : parent) { gen.ensureMember(); collectCollisionDomains(result, gen); - if (gen instanceof AbstractCompositeGenerator) { - result.add(((AbstractCompositeGenerator) gen).domain()); + if (gen instanceof AbstractCompositeGenerator compositeGen) { + result.add(compositeGen.domain()); } } } @Override - , G extends AbstractExplicitGenerator> G resolveTreeScoped( + , G extends AbstractExplicitGenerator> G resolveTreeScoped( final Class type, final QName argument) { LOG.trace("Searching for tree-scoped argument {} at {}", argument, stack); @@ -272,7 +297,7 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable } @Override - AbstractTypeObjectGenerator resolveLeafref(final PathExpression path) { + AbstractTypeObjectGenerator resolveLeafref(final PathExpression path) { LOG.trace("Resolving path {}", path); verify(inferenceStack.isEmpty(), "Unexpected data tree state %s", inferenceStack); try { @@ -294,7 +319,7 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable } } - private @NonNull AbstractTypeAwareGenerator strictResolvePath(final @NonNull PathExpression path) { + private @NonNull AbstractTypeAwareGenerator strictResolvePath(final @NonNull PathExpression path) { try { inferenceStack.resolvePathExpression(path); } catch (IllegalArgumentException e) { @@ -303,7 +328,7 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable 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) { @@ -314,7 +339,7 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable } // 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()), @@ -322,9 +347,9 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable // Now kick of the search final List> stmtPath = inferenceStack.toInference().statementPath(); - final AbstractExplicitGenerator found = gen.findGenerator(stmtPath); - if (found instanceof AbstractTypeAwareGenerator) { - return (AbstractTypeAwareGenerator) found; + final AbstractExplicitGenerator found = gen.findGenerator(stmtPath); + if (found instanceof AbstractTypeAwareGenerator typeAware) { + return typeAware; } throw new VerifyException("Statements " + stmtPath + " resulted in unexpected " + found); } @@ -332,9 +357,8 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable // Note: unlike other methods, this method pushes matching child to the stack private void linkUsesDependencies(final Iterable parent) { for (Generator child : parent) { - if (child instanceof AbstractCompositeGenerator) { - LOG.trace("Visiting composite {}", child); - final AbstractCompositeGenerator composite = (AbstractCompositeGenerator) child; + if (child instanceof AbstractCompositeGenerator composite) { + LOG.trace("Visiting composite {}", composite); stack.push(composite); composite.linkUsesDependencies(this); linkUsesDependencies(composite); @@ -343,10 +367,34 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable } } + private static boolean progressAndClean(final List items, final Function function) { + boolean progress = false; + + final var it = items.iterator(); + while (it.hasNext()) { + final var item = it.next(); + final var tmp = function.apply(item); + if (tmp == LinkageProgress.NONE) { + LOG.debug("No progress made linking {}", item); + continue; + } + + progress = true; + if (tmp == LinkageProgress.DONE) { + LOG.debug("Finished linking {}", item); + it.remove(); + } else { + LOG.debug("Progress made linking {}", item); + } + } + + return progress; + } + private void linkDependencies(final Iterable parent) { for (Generator child : parent) { - if (child instanceof AbstractDependentGenerator) { - ((AbstractDependentGenerator) child).linkDependencies(this); + if (child instanceof AbstractDependentGenerator dependent) { + dependent.linkDependencies(this); } else if (child instanceof AbstractCompositeGenerator) { stack.push(child); linkDependencies(child); @@ -358,8 +406,8 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable private void bindTypeDefinition(final Iterable parent) { for (Generator child : parent) { stack.push(child); - if (child instanceof AbstractTypeObjectGenerator) { - ((AbstractTypeObjectGenerator) child).bindTypeDefinition(this); + if (child instanceof AbstractTypeObjectGenerator typeObject) { + typeObject.bindTypeDefinition(this); } else if (child instanceof AbstractCompositeGenerator) { bindTypeDefinition(child); }