f772a495c0f47b4a431e3f85ea610f765dc1bc8b
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / util / 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.util;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.annotations.Beta;
13 import java.util.Optional;
14 import javax.annotation.Nonnull;
15 import javax.annotation.Nullable;
16 import org.antlr.v4.runtime.ParserRuleContext;
17 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
18 import org.opendaylight.yangtools.yang.model.repo.api.RevisionSourceIdentifier;
19 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
20 import org.opendaylight.yangtools.yang.model.repo.api.SemVerSourceIdentifier;
21 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
22 import org.opendaylight.yangtools.yang.parser.impl.util.YangModelDependencyInfo;
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 YangModelDependencyInfo depInfo;
36     private final SemVerSourceIdentifier semVerId;
37     private final ParserRuleContext tree;
38     private final SourceIdentifier id;
39     private final String symbolicName;
40
41     private ASTSchemaSource(@Nonnull final SourceIdentifier id, @Nonnull final SemVerSourceIdentifier semVerId,
42             @Nonnull final ParserRuleContext tree, @Nonnull final YangModelDependencyInfo depInfo,
43             @Nullable final String symbolicName) {
44         this.depInfo = requireNonNull(depInfo);
45         this.tree = requireNonNull(tree);
46         this.id = requireNonNull(id);
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 identifier
56      *            SourceIdentifier of yang schema source.
57      * @param tree
58      *            ANTLR abstract syntax tree
59      * @return A new representation instance.
60      * @throws YangSyntaxErrorException
61      *             if we fail to extract dependency information.
62      */
63     public static ASTSchemaSource create(@Nonnull final SourceIdentifier identifier,
64             @Nonnull final ParserRuleContext tree) throws YangSyntaxErrorException {
65         return create(identifier, null, tree);
66     }
67
68     /**
69      * Create a new instance of AST representation for a abstract syntax tree, performing minimal semantic analysis
70      * to acquire dependency information.
71      *
72      * @param symbolicName
73      *            Symbolic name
74      * @param identifier
75      *            SourceIdentifier of yang schema source.
76      * @param tree
77      *            ANTLR abstract syntax tree
78      * @return A new representation instance.
79      * @throws YangSyntaxErrorException
80      *             if we fail to extract dependency information.
81      */
82     public static ASTSchemaSource create(@Nonnull final String symbolicName, @Nonnull final SourceIdentifier identifier,
83             @Nonnull final ParserRuleContext tree) throws YangSyntaxErrorException {
84         return create(identifier, symbolicName, tree);
85     }
86
87     private static ASTSchemaSource create(@Nonnull final SourceIdentifier identifier,
88             @Nullable final String symbolicName, @Nonnull final ParserRuleContext tree)
89                     throws YangSyntaxErrorException {
90         final YangModelDependencyInfo depInfo = YangModelDependencyInfo.fromAST(identifier, tree);
91         final SourceIdentifier id = getSourceId(depInfo);
92
93         final SemVerSourceIdentifier semVerId;
94         if (identifier instanceof SemVerSourceIdentifier && !depInfo.getSemanticVersion().isPresent()) {
95             semVerId = (SemVerSourceIdentifier) identifier;
96         } else {
97             semVerId = getSemVerSourceId(depInfo);
98         }
99
100         return new ASTSchemaSource(id, semVerId, tree, depInfo, symbolicName);
101     }
102
103
104     @Override
105     public SourceIdentifier getIdentifier() {
106         return id;
107     }
108
109     @Override
110     public Optional<String> getSymbolicName() {
111         return Optional.ofNullable(symbolicName);
112     }
113
114     public SemVerSourceIdentifier getSemVerIdentifier() {
115         return semVerId;
116     }
117
118     @Nonnull
119     @Override
120     public Class<? extends SchemaSourceRepresentation> getType() {
121         return ASTSchemaSource.class;
122     }
123
124     /**
125      * Return the underlying abstract syntax tree.
126      *
127      * @return Underlying AST.
128      */
129     @Nonnull public ParserRuleContext getAST() {
130         return tree;
131     }
132
133     /**
134      * Return the dependency information as extracted from the AST.
135      *
136      * @return Dependency information.
137      */
138     // FIXME: this method should be extracted into a public interface in the model.api.repo class, relying solely
139     //        on model.api types.
140     @Nonnull public YangModelDependencyInfo getDependencyInformation() {
141         return depInfo;
142     }
143
144     private static SourceIdentifier getSourceId(final YangModelDependencyInfo depInfo) {
145         final String name = depInfo.getName();
146         return depInfo.getFormattedRevision() == null ? RevisionSourceIdentifier.create(name)
147                 : RevisionSourceIdentifier.create(name, depInfo.getRevision());
148     }
149
150     private static SemVerSourceIdentifier getSemVerSourceId(final YangModelDependencyInfo depInfo) {
151         return depInfo.getFormattedRevision() == null
152                 ? SemVerSourceIdentifier.create(depInfo.getName(), depInfo.getSemanticVersion().orElse(null))
153                         : SemVerSourceIdentifier.create(depInfo.getName(), depInfo.getRevision(),
154                             depInfo.getSemanticVersion().orElse(null));
155     }
156 }