Speed up StatementContextVisitor.getValidStatementDefinition()
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / repo / ASTSchemaSource.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.parser.rfc7950.repo;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.annotations.Beta;
13 import com.google.common.base.MoreObjects;
14 import java.util.Optional;
15 import org.antlr.v4.runtime.ParserRuleContext;
16 import org.eclipse.jdt.annotation.NonNull;
17 import org.eclipse.jdt.annotation.Nullable;
18 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
19 import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
20 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
21 import org.opendaylight.yangtools.yang.model.repo.api.SemVerSourceIdentifier;
22 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
23
24 /**
25  * Abstract Syntax Tree representation of a schema source. This representation is internal to the YANG parser
26  * implementation, as it relies on ANTLR types.
27  *
28  * <p>
29  * Instances of this representation are used for caching purposes, as they are a natural intermediate step in YANG text
30  * processing pipeline: the text has been successfully parsed, so we know it is syntactically correct. It also passes
31  * basic semantic validation and we were able to extract dependency information.
32  */
33 @Beta
34 public final class ASTSchemaSource implements SchemaSourceRepresentation {
35     private final @NonNull YangModelDependencyInfo depInfo;
36     private final @NonNull SemVerSourceIdentifier semVerId;
37     private final @NonNull SourceIdentifier identifier;
38     private final @NonNull ParserRuleContext tree;
39     private final @Nullable String symbolicName;
40
41     private ASTSchemaSource(final @NonNull SourceIdentifier identifier, final @NonNull SemVerSourceIdentifier semVerId,
42             final @NonNull ParserRuleContext tree, final @NonNull YangModelDependencyInfo depInfo,
43             @Nullable final String symbolicName) {
44         this.depInfo = requireNonNull(depInfo);
45         this.tree = requireNonNull(tree);
46         this.identifier = requireNonNull(identifier);
47         this.semVerId = requireNonNull(semVerId);
48         this.symbolicName = symbolicName;
49     }
50
51     /**
52      * Create a new instance of AST representation for a abstract syntax tree, performing minimal semantic analysis
53      * to acquire dependency information.
54      *
55      * @param symbolicName
56      *            Symbolic name
57      * @param identifier
58      *            SourceIdentifier of YANG schema source.
59      * @param tree
60      *            ANTLR abstract syntax tree
61      * @return A new representation instance.
62      * @throws YangSyntaxErrorException
63      *             if we fail to extract dependency information.
64      */
65     static @NonNull ASTSchemaSource create(final @NonNull SourceIdentifier identifier,
66             final @Nullable String symbolicName, final @NonNull ParserRuleContext tree)
67                     throws YangSyntaxErrorException {
68         final YangModelDependencyInfo depInfo = YangModelDependencyInfo.fromAST(identifier, tree);
69         final SourceIdentifier id = getSourceId(depInfo);
70
71         final SemVerSourceIdentifier semVerId;
72         if (identifier instanceof SemVerSourceIdentifier && !depInfo.getSemanticVersion().isPresent()) {
73             semVerId = (SemVerSourceIdentifier) identifier;
74         } else {
75             semVerId = getSemVerSourceId(depInfo);
76         }
77
78         return new ASTSchemaSource(id, semVerId, tree, depInfo, symbolicName);
79     }
80
81     @Override
82     public SourceIdentifier getIdentifier() {
83         return identifier;
84     }
85
86     @Override
87     public Optional<String> getSymbolicName() {
88         return Optional.ofNullable(symbolicName);
89     }
90
91     public @NonNull SemVerSourceIdentifier getSemVerIdentifier() {
92         return semVerId;
93     }
94
95     @Override
96     public Class<? extends SchemaSourceRepresentation> getType() {
97         return ASTSchemaSource.class;
98     }
99
100     /**
101      * Return the underlying abstract syntax tree.
102      *
103      * @return Underlying AST.
104      */
105     public @NonNull ParserRuleContext getAST() {
106         return tree;
107     }
108
109     /**
110      * Return the dependency information as extracted from the AST.
111      *
112      * @return Dependency information.
113      */
114     // FIXME: this method should be extracted into a public interface in the model.api.repo class, relying solely
115     //        on model.api types.
116     public @NonNull YangModelDependencyInfo getDependencyInformation() {
117         return depInfo;
118     }
119
120     @Override
121     public String toString() {
122         return MoreObjects.toStringHelper(this).add("identifier", identifier).toString();
123     }
124
125     private static @NonNull SourceIdentifier getSourceId(final @NonNull YangModelDependencyInfo depInfo) {
126         final String name = depInfo.getName();
127         return depInfo.getFormattedRevision() == null ? RevisionSourceIdentifier.create(name)
128                 : RevisionSourceIdentifier.create(name, depInfo.getRevision());
129     }
130
131     private static @NonNull SemVerSourceIdentifier getSemVerSourceId(final @NonNull YangModelDependencyInfo depInfo) {
132         return depInfo.getFormattedRevision() == null
133                 ? SemVerSourceIdentifier.create(depInfo.getName(), depInfo.getSemanticVersion().orElse(null))
134                         : SemVerSourceIdentifier.create(depInfo.getName(), depInfo.getRevision(),
135                             depInfo.getSemanticVersion().orElse(null));
136     }
137 }