X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=binding%2Fmdsal-binding-generator%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fbinding%2Fgenerator%2Fimpl%2Freactor%2FGeneratorReactor.java;h=f8214ad1445247f3e4d6878234037ee7e1f92bd4;hb=feaecf128a14832eec9661057af4de6b3704a07f;hp=ce2681193362f09a9ad1f632c288378896bc23d4;hpb=c7c6dc9fd42184c4e7cf85219d58cc7480f5bd90;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 ce26811933..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; @@ -67,7 +68,6 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable private final @NonNull List children; private final @NonNull SchemaInferenceStack inferenceStack; - private Map> leafGenerators; private State state = State.INITIALIZED; public GeneratorReactor(final EffectiveModelContext context) { @@ -123,23 +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: 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); - // 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. - linkOriginalGenerator(children); + if (augments.isEmpty() && unlinkedModules.isEmpty()) { + break; + } + + 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 @@ -285,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) { @@ -294,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) { @@ -305,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()), @@ -315,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); } @@ -334,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) { @@ -346,19 +404,6 @@ public final class GeneratorReactor extends GeneratorContext implements Mutable } } - private void linkOriginalGenerator(final Iterable parent) { - for (Generator child : parent) { - if (child instanceof AbstractExplicitGenerator) { - ((AbstractExplicitGenerator) child).linkOriginalGenerator(this); - } - if (child instanceof AbstractCompositeGenerator) { - stack.push(child); - linkOriginalGenerator(child); - stack.pop(); - } - } - } - private void bindTypeDefinition(final Iterable parent) { for (Generator child : parent) { stack.push(child);