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=f8214ad1445247f3e4d6878234037ee7e1f92bd4;hb=feaecf128a14832eec9661057af4de6b3704a07f;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..f8214ad144 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; @@ -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) { + augments.add(((ModuleAugmentGenerator) gen).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 @@ -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()), @@ -324,7 +349,7 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable final List> 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); } @@ -343,6 +368,30 @@ 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) {