Merge "Bug 1119 - Optimize generated range checks"
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / impl / YangParserImpl.java
index 83d605f1290ca058700c488662bb86c4a62ca880..1d0d48a7ddf2d7b5c034440d15f477c76b29e8fd 100644 (file)
@@ -14,11 +14,6 @@ import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.f
 import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findSchemaNode;
 import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.findSchemaNodeInModule;
 import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.processAugmentation;
-import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.setNodeAddedByUses;
-import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.wrapChildNodes;
-import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.wrapGroupings;
-import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.wrapTypedefs;
-import static org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils.wrapUnknownNodes;
 import static org.opendaylight.yangtools.yang.parser.builder.impl.TypeUtils.resolveType;
 import static org.opendaylight.yangtools.yang.parser.builder.impl.TypeUtils.resolveTypeUnion;
 
@@ -27,6 +22,7 @@ import com.google.common.base.Preconditions;
 import com.google.common.base.Splitter;
 import com.google.common.collect.HashBiMap;
 import com.google.common.io.ByteSource;
+
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -36,14 +32,15 @@ import java.util.Collections;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
+
 import javax.annotation.concurrent.Immutable;
+
 import org.antlr.v4.runtime.ANTLRInputStream;
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.antlr.v4.runtime.tree.ParseTree;
@@ -54,7 +51,6 @@ import org.opendaylight.yangtools.antlrv4.code.gen.YangParser.YangContext;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
-import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
 import org.opendaylight.yangtools.yang.model.api.ModuleImport;
@@ -71,7 +67,6 @@ import org.opendaylight.yangtools.yang.parser.builder.api.ExtensionBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.GroupingBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.SchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.TypeAwareBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.api.TypeDefinitionBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.UnknownSchemaNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.api.UsesNodeBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.impl.BuilderUtils;
@@ -84,7 +79,6 @@ import org.opendaylight.yangtools.yang.parser.builder.impl.IdentityrefTypeBuilde
 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleBuilder;
 import org.opendaylight.yangtools.yang.parser.builder.impl.ModuleImpl;
 import org.opendaylight.yangtools.yang.parser.builder.impl.UnionTypeBuilder;
-import org.opendaylight.yangtools.yang.parser.builder.impl.UnknownSchemaNodeBuilderImpl;
 import org.opendaylight.yangtools.yang.parser.builder.util.Comparators;
 import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
 import org.opendaylight.yangtools.yang.parser.util.NamedByteArrayInputStream;
@@ -116,8 +110,7 @@ public final class YangParserImpl implements YangContextParser {
     }
 
     @Override
-    public SchemaContext parseFile(final File yangFile, final File directory) throws IOException,
-            YangSyntaxErrorException {
+    public SchemaContext parseFile(final File yangFile, final File directory) throws IOException, YangSyntaxErrorException {
         Preconditions.checkState(yangFile.exists(), yangFile + " does not exists");
         Preconditions.checkState(directory.exists(), directory + " does not exists");
         Preconditions.checkState(directory.isDirectory(), directory + " is not a directory");
@@ -182,7 +175,7 @@ public final class YangParserImpl implements YangContextParser {
 
     @Override
     public SchemaContext parseFiles(final Collection<File> yangFiles, final SchemaContext context) throws IOException,
-            YangSyntaxErrorException {
+    YangSyntaxErrorException {
         if (yangFiles == null) {
             return resolveSchemaContext(Collections.<Module> emptySet());
         }
@@ -203,12 +196,8 @@ public final class YangParserImpl implements YangContextParser {
     }
 
     @Override
-    public SchemaContext parseSources(final Collection<ByteSource> sources) throws IOException,
-            YangSyntaxErrorException {
-        Collection<Module> unsorted = parseYangModelSources(sources).values();
-        Set<Module> sorted = new LinkedHashSet<>(
-                ModuleDependencySort.sort(unsorted.toArray(new Module[unsorted.size()])));
-        return resolveSchemaContext(sorted);
+    public SchemaContext parseSources(final Collection<ByteSource> sources) throws IOException,YangSyntaxErrorException {
+        return assembleContext(parseYangModelSources(sources).values());
     }
 
     @Override
@@ -245,8 +234,8 @@ public final class YangParserImpl implements YangContextParser {
         return resolveSchemaContext(result);
     }
 
-    private LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> resolveModulesWithImports(List<ModuleBuilder> sorted,
-            SchemaContext context) {
+    private static LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> resolveModulesWithImports(final List<ModuleBuilder> sorted,
+            final SchemaContext context) {
         final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> modules = orderModules(sorted);
         for (ModuleBuilder module : sorted) {
             if (module != null) {
@@ -344,8 +333,21 @@ public final class YangParserImpl implements YangContextParser {
         return new SchemaContextImpl(modules, identifiersToSources);
     }
 
-    private Map<ByteSource, Module> parseYangModelSources(final Collection<ByteSource> sources) throws IOException,
-            YangSyntaxErrorException {
+    public Collection<Module> buildModules(final Collection<ModuleBuilder> builders) {
+        List<ModuleBuilder> sorted = ModuleDependencySort.sort(builders);
+        Map<String, TreeMap<Date, ModuleBuilder>> modules = resolveModulesWithImports(sorted, null);
+        Map<ModuleBuilder, Module> builderToModule = build(modules);
+
+        return builderToModule.values();
+    }
+
+    public SchemaContext assembleContext(final Collection<Module> modules) {
+        final Set<Module> sorted = new LinkedHashSet<>(
+                ModuleDependencySort.sort(modules.toArray(new Module[modules.size()])));
+        return resolveSchemaContext(sorted);
+    }
+
+    private Map<ByteSource, Module> parseYangModelSources(final Collection<ByteSource> sources) throws IOException, YangSyntaxErrorException {
         if (sources == null || sources.isEmpty()) {
             return Collections.emptyMap();
         }
@@ -377,8 +379,7 @@ public final class YangParserImpl implements YangContextParser {
      * @throws YangSyntaxErrorException
      */
     // TODO: remove ByteSource result after removing YangModelParser
-    private Map<ByteSource, ModuleBuilder> resolveSources(final Collection<ByteSource> streams) throws IOException,
-            YangSyntaxErrorException {
+    private Map<ByteSource, ModuleBuilder> resolveSources(final Collection<ByteSource> streams) throws IOException, YangSyntaxErrorException {
         Map<ByteSource, ModuleBuilder> builders = parseSourcesToBuilders(streams);
         return resolveSubmodules(builders);
     }
@@ -520,7 +521,7 @@ public final class YangParserImpl implements YangContextParser {
      *            topologically sorted modules
      * @return modules ordered by name and revision
      */
-    private LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> orderModules(final List<ModuleBuilder> modules) {
+    private static LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> orderModules(final List<ModuleBuilder> modules) {
         final LinkedHashMap<String, TreeMap<Date, ModuleBuilder>> result = new LinkedHashMap<>();
         for (final ModuleBuilder builder : modules) {
             if (builder == null) {
@@ -592,31 +593,29 @@ public final class YangParserImpl implements YangContextParser {
         }
     }
 
-    private Map<ByteSource, ParseTree> parseYangSources(final Collection<ByteSource> sources) throws IOException,
-            YangSyntaxErrorException {
+    private Map<ByteSource, ParseTree> parseYangSources(final Collection<ByteSource> sources) throws IOException, YangSyntaxErrorException {
         final Map<ByteSource, ParseTree> trees = new HashMap<>();
         for (ByteSource source : sources) {
-            trees.put(source, parseYangSource(source));
+            try (InputStream stream = source.openStream()) {
+                trees.put(source, parseYangSource(stream));
+            }
         }
         return trees;
     }
 
-    private YangContext parseYangSource(final ByteSource source) throws IOException, YangSyntaxErrorException {
-        try (InputStream stream = source.openStream()) {
-            final ANTLRInputStream input = new ANTLRInputStream(stream);
-            final YangLexer lexer = new YangLexer(input);
-            final CommonTokenStream tokens = new CommonTokenStream(lexer);
-            final YangParser parser = new YangParser(tokens);
-            parser.removeErrorListeners();
+    public static YangContext parseYangSource(final InputStream stream) throws IOException, YangSyntaxErrorException {
+        final YangLexer lexer = new YangLexer(new ANTLRInputStream(stream));
+        final CommonTokenStream tokens = new CommonTokenStream(lexer);
+        final YangParser parser = new YangParser(tokens);
+        parser.removeErrorListeners();
 
-            final YangErrorListener errorListener = new YangErrorListener();
-            parser.addErrorListener(errorListener);
+        final YangErrorListener errorListener = new YangErrorListener();
+        parser.addErrorListener(errorListener);
 
-            final YangContext result = parser.yang();
-            errorListener.validate();
+        final YangContext result = parser.yang();
+        errorListener.validate();
 
-            return result;
-        }
+        return result;
     }
 
     /**
@@ -764,13 +763,11 @@ public final class YangParserImpl implements YangContextParser {
     private void setCorrectAugmentTargetPath(final Map<String, TreeMap<Date, ModuleBuilder>> modules,
             final AugmentationSchemaBuilder augment) {
         ModuleBuilder module = BuilderUtils.getParentModule(augment);
-        Iterable<QName> oldPath = augment.getTargetPath().getPathFromRoot();
-        List<QName> newPath = new ArrayList<>();
+        final SchemaPath newSchemaPath;
 
         Builder parent = augment.getParent();
         if (parent instanceof UsesNodeBuilder) {
             DataNodeContainerBuilder usesParent = ((UsesNodeBuilder) parent).getParent();
-            newPath.addAll(usesParent.getPath().getPath());
 
             QName baseQName = usesParent.getQName();
             final QNameModule qnm;
@@ -784,11 +781,16 @@ public final class YangParserImpl implements YangContextParser {
                 prefix = baseQName.getPrefix();
             }
 
-            for (QName qn : oldPath) {
-                newPath.add(QName.create(qnm, prefix, qn.getLocalName()));
+            SchemaPath s = usesParent.getPath();
+            for (QName qn : augment.getTargetPath().getPathFromRoot()) {
+                s = s.createChild(QName.create(qnm, prefix, qn.getLocalName()));
             }
+
+            newSchemaPath = s;
         } else {
-            for (QName qn : oldPath) {
+            final List<QName> newPath = new ArrayList<>();
+
+            for (QName qn : augment.getTargetPath().getPathFromRoot()) {
                 QNameModule qnm = module.getQNameModule();
                 String localPrefix = qn.getPrefix();
                 if (localPrefix != null && !localPrefix.isEmpty()) {
@@ -799,10 +801,18 @@ public final class YangParserImpl implements YangContextParser {
                     }
                     qnm = currentModule.getQNameModule();
                 }
-                newPath.add(new QName(qnm.getNamespace(), qnm.getRevision(), localPrefix, qn.getLocalName()));
+                newPath.add(QName.create(qnm, localPrefix, qn.getLocalName()));
             }
+
+            /*
+             * FIXME: this method of SchemaPath construction is highly ineffective.
+             *        It would be great if we could actually dive into the context,
+             *        find the actual target node and reuse its SchemaPath. Can we
+             *        do that?
+             */
+            newSchemaPath = SchemaPath.create(newPath, true);
         }
-        augment.setTargetNodeSchemaPath(SchemaPath.create(newPath, true));
+        augment.setTargetNodeSchemaPath(newSchemaPath);
 
         for (DataSchemaNodeBuilder childNode : augment.getChildNodeBuilders()) {
             correctPathForAugmentNodes(childNode, augment.getTargetNodeSchemaPath());
@@ -880,7 +890,7 @@ public final class YangParserImpl implements YangContextParser {
             if (mb != null) {
                 List<AugmentationSchemaBuilder> augments = mb.getAllAugments();
                 checkAugmentMandatoryNodes(augments);
-                Collections.sort(augments, Comparators.AUGMENT_COMP);
+                Collections.sort(augments, Comparators.AUGMENT_BUILDER_COMP);
                 for (AugmentationSchemaBuilder augment : augments) {
                     if (!(augment.isResolved())) {
                         boolean resolved = resolveAugment(augment, mb, modules);
@@ -996,7 +1006,7 @@ public final class YangParserImpl implements YangContextParser {
         }
     }
 
-    private void resolveIdentity(final Map<String, TreeMap<Date, ModuleBuilder>> modules, ModuleBuilder module,
+    private void resolveIdentity(final Map<String, TreeMap<Date, ModuleBuilder>> modules, final ModuleBuilder module,
             final IdentitySchemaNodeBuilder identity) {
         final String baseIdentityName = identity.getBaseIdentityName();
         if (baseIdentityName != null) {
@@ -1101,79 +1111,49 @@ public final class YangParserImpl implements YangContextParser {
             DataNodeContainerBuilder parent = usesNode.getParent();
             ModuleBuilder module = BuilderUtils.getParentModule(parent);
             GroupingBuilder target = GroupingUtils.getTargetGroupingFromModules(usesNode, modules, module);
-            if (target == null) {
-                resolveUsesWithContext(usesNode);
-                usesNode.setResolved(true);
-                for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) {
-                    resolveUsesAugment(augment, module, modules);
-                }
-            } else {
-                parent.getChildNodeBuilders().addAll(target.instantiateChildNodes(parent));
-                parent.getTypeDefinitionBuilders().addAll(target.instantiateTypedefs(parent));
-                parent.getGroupingBuilders().addAll(target.instantiateGroupings(parent));
-                parent.getUnknownNodes().addAll(target.instantiateUnknownNodes(parent));
-                usesNode.setResolved(true);
-                for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) {
-                    resolveUsesAugment(augment, module, modules);
-                }
+
+            int index = nodeAfterUsesIndex(usesNode);
+            List<DataSchemaNodeBuilder> targetNodes = target.instantiateChildNodes(parent);
+            for (DataSchemaNodeBuilder targetNode : targetNodes) {
+                parent.addChildNode(index++, targetNode);
+            }
+            parent.getTypeDefinitionBuilders().addAll(target.instantiateTypedefs(parent));
+            parent.getGroupingBuilders().addAll(target.instantiateGroupings(parent));
+            parent.getUnknownNodes().addAll(target.instantiateUnknownNodes(parent));
+            usesNode.setResolved(true);
+            for (AugmentationSchemaBuilder augment : usesNode.getAugmentations()) {
+                resolveUsesAugment(augment, module, modules);
             }
+
             GroupingUtils.performRefine(usesNode);
         }
     }
 
-    /**
-     * Copy target grouping child nodes to current location with new namespace.
-     *
-     * @param usesNode
-     *            uses node to resolve
-     */
-    private void resolveUsesWithContext(final UsesNodeBuilder usesNode) {
-        final int line = usesNode.getLine();
+    private int nodeAfterUsesIndex(final UsesNodeBuilder usesNode) {
         DataNodeContainerBuilder parent = usesNode.getParent();
-        ModuleBuilder module = BuilderUtils.getParentModule(parent);
-        SchemaPath parentPath;
-
-        final QName parentQName;
-        if (parent instanceof AugmentationSchemaBuilder || parent instanceof ModuleBuilder) {
-            parentQName = QName.create(module.getQNameModule(), module.getPrefix(), "dummy");
-            if (parent instanceof AugmentationSchemaBuilder) {
-                parentPath = ((AugmentationSchemaBuilder) parent).getTargetNodeSchemaPath();
-            } else {
-                parentPath = parent.getPath();
-            }
-        } else {
-            parentQName = parent.getQName();
-            parentPath = parent.getPath();
-        }
+        int usesLine = usesNode.getLine();
 
-        GroupingDefinition gd = usesNode.getGroupingDefinition();
-
-        Set<DataSchemaNodeBuilder> childNodes = wrapChildNodes(module.getModuleName(), line, gd.getChildNodes(),
-                parentPath, parentQName);
-        parent.getChildNodeBuilders().addAll(childNodes);
-        for (DataSchemaNodeBuilder childNode : childNodes) {
-            setNodeAddedByUses(childNode);
+        List<DataSchemaNodeBuilder> childNodes = parent.getChildNodeBuilders();
+        if (childNodes.isEmpty()) {
+            return 0;
         }
 
-        Set<TypeDefinitionBuilder> typedefs = wrapTypedefs(module.getModuleName(), line, gd, parentPath, parentQName);
-        parent.getTypeDefinitionBuilders().addAll(typedefs);
-        for (TypeDefinitionBuilder typedef : typedefs) {
-            setNodeAddedByUses(typedef);
+        DataSchemaNodeBuilder nextNodeAfterUses = null;
+        for (DataSchemaNodeBuilder childNode : childNodes) {
+            if (!(childNode.isAddedByUses()) && !(childNode.isAugmenting())) {
+                if (childNode.getLine() > usesLine) {
+                    nextNodeAfterUses = childNode;
+                    break;
+                }
+            }
         }
 
-        Set<GroupingBuilder> groupings = wrapGroupings(module.getModuleName(), line, usesNode.getGroupingDefinition()
-                .getGroupings(), parentPath, parentQName);
-        parent.getGroupingBuilders().addAll(groupings);
-        for (GroupingBuilder gb : groupings) {
-            setNodeAddedByUses(gb);
+        // uses is declared after child nodes
+        if (nextNodeAfterUses == null) {
+            return childNodes.size();
         }
 
-        List<UnknownSchemaNodeBuilderImpl> unknownNodes = wrapUnknownNodes(module.getModuleName(), line,
-                gd.getUnknownSchemaNodes(), parentPath, parentQName);
-        parent.getUnknownNodes().addAll(unknownNodes);
-        for (UnknownSchemaNodeBuilder un : unknownNodes) {
-            un.setAddedByUses(true);
-        }
+        return parent.getChildNodeBuilders().indexOf(nextNodeAfterUses);
     }
 
     /**
@@ -1189,6 +1169,12 @@ public final class YangParserImpl implements YangContextParser {
         for (UnknownSchemaNodeBuilder usnb : module.getAllUnknownNodes()) {
             QName nodeType = usnb.getNodeType();
             ModuleBuilder dependentModuleBuilder = BuilderUtils.getModuleByPrefix(module, nodeType.getPrefix());
+            if (dependentModuleBuilder == null) {
+                LOG.warn(
+                        "Error in module {} at line {}: Failed to resolve node {}: no such extension definition found.",
+                        module.getName(), usnb.getLine(), usnb);
+                continue;
+            }
             ExtensionBuilder extBuilder = findExtBuilder(nodeType.getLocalName(),
                     dependentModuleBuilder.getAddedExtensions());
             if (extBuilder == null) {
@@ -1203,7 +1189,7 @@ public final class YangParserImpl implements YangContextParser {
                     usnb.setExtensionDefinition(extDef);
                 }
             } else {
-                usnb.setNodeType(new QName(extBuilder.getQName().getNamespace(), extBuilder.getQName().getRevision(),
+                usnb.setNodeType(QName.create(extBuilder.getQName().getModule(),
                         nodeType.getPrefix(), extBuilder.getQName().getLocalName()));
                 usnb.setExtensionBuilder(extBuilder);
             }
@@ -1298,5 +1284,4 @@ public final class YangParserImpl implements YangContextParser {
         }
         dev.setTargetPath(((SchemaNodeBuilder) currentParent).getPath());
     }
-
 }