2 * Copyright (c) 2017 Pantheon Technologies, s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.parser.rfc7950.repo;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static java.util.Objects.requireNonNull;
13 import com.google.common.annotations.Beta;
14 import com.google.common.collect.ImmutableList;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import org.antlr.v4.runtime.CharStreams;
18 import org.antlr.v4.runtime.CommonTokenStream;
19 import org.antlr.v4.runtime.ParserRuleContext;
20 import org.antlr.v4.runtime.tree.ErrorNode;
21 import org.antlr.v4.runtime.tree.ParseTreeListener;
22 import org.antlr.v4.runtime.tree.ParseTreeWalker;
23 import org.antlr.v4.runtime.tree.TerminalNode;
24 import org.opendaylight.yangtools.concepts.AbstractIdentifiable;
25 import org.opendaylight.yangtools.yang.common.QName;
26 import org.opendaylight.yangtools.yang.common.QNameModule;
27 import org.opendaylight.yangtools.yang.common.YangVersion;
28 import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
29 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
30 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
31 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
32 import org.opendaylight.yangtools.yang.parser.antlr.YangStatementLexer;
33 import org.opendaylight.yangtools.yang.parser.antlr.YangStatementParser;
34 import org.opendaylight.yangtools.yang.parser.antlr.YangStatementParser.StatementContext;
35 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
36 import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
37 import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
38 import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
39 import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
40 import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter;
43 * This class represents implementation of StatementStreamSource in order to emit YANG statements using supplied
46 * @author Robert Varga
49 public final class YangStatementStreamSource extends AbstractIdentifiable<SourceIdentifier>
50 implements StatementStreamSource {
51 private static final ParseTreeListener MAKE_IMMUTABLE_LISTENER = new ParseTreeListener() {
53 public void enterEveryRule(final ParserRuleContext ctx) {
58 public void exitEveryRule(final ParserRuleContext ctx) {
59 ctx.children = ctx.children == null ? ImmutableList.of() : ImmutableList.copyOf(ctx.children);
63 public void visitTerminal(final TerminalNode node) {
68 public void visitErrorNode(final ErrorNode node) {
73 private final StatementContext context;
74 private final String sourceName;
76 private YangStatementStreamSource(final SourceIdentifier identifier, final StatementContext context,
77 final String sourceName) {
79 this.context = requireNonNull(context);
80 this.sourceName = sourceName;
84 * Create a {@link YangStatementStreamSource} for a {@link YangTextSchemaSource}.
86 * @param source YangTextSchemaSource, must not be null
87 * @return A new {@link YangStatementStreamSource}
88 * @throws IOException When we fail to read the source
89 * @throws YangSyntaxErrorException If the source fails basic parsing
91 public static YangStatementStreamSource create(final YangTextSchemaSource source) throws IOException,
92 YangSyntaxErrorException {
93 final StatementContext context;
94 try (InputStream stream = source.openStream()) {
95 context = parseYangSource(source.getIdentifier(), stream);
98 return new YangStatementStreamSource(source.getIdentifier(), context, source.getSymbolicName().orElse(null));
102 * Create a {@link YangStatementStreamSource} for a {@link ASTSchemaSource}.
104 * @param source YangTextSchemaSource, must not be null
105 * @return A new {@link YangStatementStreamSource}
107 public static YangStatementStreamSource create(final ASTSchemaSource source) {
108 final ParserRuleContext ast = source.getAST();
109 checkArgument(ast instanceof StatementContext,
110 "Unsupported context class %s for source %s", ast.getClass(), source.getIdentifier());
111 return create(source.getIdentifier(), (StatementContext) ast, source.getSymbolicName().orElse(null));
114 public static YangStatementStreamSource create(final SourceIdentifier identifier, final StatementContext context,
115 final String symbolicName) {
116 return new YangStatementStreamSource(identifier, context, symbolicName);
120 public void writePreLinkage(final StatementWriter writer, final QNameToStatementDefinition stmtDef) {
121 new StatementContextVisitor(sourceName, writer, stmtDef, null, YangVersion.VERSION_1).visit(context);
125 public void writeLinkage(final StatementWriter writer, final QNameToStatementDefinition stmtDef,
126 final PrefixToModule preLinkagePrefixes, final YangVersion yangVersion) {
127 new StatementContextVisitor(sourceName, writer, stmtDef, preLinkagePrefixes, yangVersion) {
129 StatementDefinition resolveStatement(final QNameModule module, final String localName) {
130 return stmtDef.getByNamespaceAndLocalName(module.getNamespace(), localName);
136 public void writeLinkageAndStatementDefinitions(final StatementWriter writer,
137 final QNameToStatementDefinition stmtDef, final PrefixToModule prefixes, final YangVersion yangVersion) {
138 new StatementContextVisitor(sourceName, writer, stmtDef, prefixes, yangVersion).visit(context);
142 public void writeFull(final StatementWriter writer, final QNameToStatementDefinition stmtDef,
143 final PrefixToModule prefixes, final YangVersion yangVersion) {
144 new StatementContextVisitor(sourceName, writer, stmtDef, prefixes, yangVersion) {
146 QName getValidStatementDefinition(final String keywordText, final StatementSourceReference ref) {
147 return SourceException.throwIfNull(super.getValidStatementDefinition(keywordText, ref), ref,
148 "%s is not a YANG statement or use of extension.", keywordText);
153 @Deprecated(forRemoval = true)
154 public ParserRuleContext getYangAST() {
155 return statementContext();
158 StatementContext statementContext() {
162 private static StatementContext parseYangSource(final SourceIdentifier source, final InputStream stream)
163 throws IOException, YangSyntaxErrorException {
164 final YangStatementLexer lexer = new YangStatementLexer(CharStreams.fromStream(stream));
165 final YangStatementParser parser = new YangStatementParser(new CommonTokenStream(lexer));
166 // disconnect from console error output
167 lexer.removeErrorListeners();
168 parser.removeErrorListeners();
170 final YangErrorListener errorListener = new YangErrorListener(source);
171 lexer.addErrorListener(errorListener);
172 parser.addErrorListener(errorListener);
174 final StatementContext result = parser.statement();
175 errorListener.validate();
177 // Walk the resulting tree and replace each children with an immutable list, lowering memory requirements
178 // and making sure the resulting tree will not get accidentally modified. An alternative would be to use
179 // org.antlr.v4.runtime.Parser.TrimToSizeListener, but that does not make the tree immutable.
180 ParseTreeWalker.DEFAULT.walk(MAKE_IMMUTABLE_LISTENER, result);