2 * Copyright (c) 2015 Cisco Systems, Inc. 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
9 package org.opendaylight.yangtools.yang.parser.stmt.rfc6020;
11 import com.google.common.base.Preconditions;
12 import com.google.common.base.Throwables;
13 import com.google.common.collect.ImmutableList;
15 import java.io.IOException;
16 import java.io.InputStream;
17 import java.net.URISyntaxException;
18 import org.antlr.v4.runtime.ANTLRInputStream;
19 import org.antlr.v4.runtime.CommonTokenStream;
20 import org.antlr.v4.runtime.ParserRuleContext;
21 import org.antlr.v4.runtime.tree.ErrorNode;
22 import org.antlr.v4.runtime.tree.ParseTreeListener;
23 import org.antlr.v4.runtime.tree.ParseTreeWalker;
24 import org.antlr.v4.runtime.tree.TerminalNode;
25 import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementLexer;
26 import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser;
27 import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.StatementContext;
28 import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
29 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
30 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
31 import org.opendaylight.yangtools.yang.parser.impl.YangStatementParserListenerImpl;
32 import org.opendaylight.yangtools.yang.parser.rfc6020.repo.YangErrorListener;
33 import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
34 import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
35 import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
36 import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter;
37 import org.opendaylight.yangtools.yang.parser.util.NamedFileInputStream;
38 import org.opendaylight.yangtools.yang.parser.util.NamedInputStream;
41 * This class represents implementation of StatementStreamSource
42 * in order to emit YANG statements using supplied StatementWriter.
44 public final class YangStatementSourceImpl implements StatementStreamSource {
45 private static final ParseTreeListener MAKE_IMMUTABLE_LISTENER = new ParseTreeListener() {
47 public void enterEveryRule(final ParserRuleContext ctx) {
52 public void exitEveryRule(final ParserRuleContext ctx) {
53 ctx.children = ctx.children == null ? ImmutableList.of() : ImmutableList.copyOf(ctx.children);
57 public void visitTerminal(final TerminalNode node) {
62 public void visitErrorNode(final ErrorNode node) {
67 private final YangStatementParserListenerImpl yangStatementModelParser;
68 private final StatementContext statementContext;
69 private final String sourceName;
71 private YangStatementSourceImpl(final YangStatementParserListenerImpl parser, final StatementContext context,
72 final String sourceName) {
73 this.yangStatementModelParser = Preconditions.checkNotNull(parser);
74 this.statementContext = Preconditions.checkNotNull(context);
75 this.sourceName = sourceName;
78 public YangStatementSourceImpl(final String fileName, final boolean isAbsolute) {
80 final NamedFileInputStream is = loadFile(fileName, isAbsolute);
81 sourceName = is.toString();
82 statementContext = parseYangSource(is);
83 yangStatementModelParser = new YangStatementParserListenerImpl(sourceName);
84 } catch (IOException | URISyntaxException | YangSyntaxErrorException e) {
85 throw Throwables.propagate(e);
89 public YangStatementSourceImpl(final InputStream inputStream) {
91 sourceName = inputStream instanceof NamedInputStream ? inputStream.toString() : null;
92 statementContext = parseYangSource(inputStream);
93 yangStatementModelParser = new YangStatementParserListenerImpl(sourceName);
94 } catch (IOException | YangSyntaxErrorException e) {
95 throw Throwables.propagate(e);
99 public YangStatementSourceImpl(final SourceIdentifier identifier, final StatementContext statementContext) {
100 this.statementContext = statementContext;
101 this.sourceName = identifier.getName();
102 yangStatementModelParser = new YangStatementParserListenerImpl(sourceName);
105 public static YangStatementSourceImpl create(final YangTextSchemaSource source) throws IOException,
106 YangSyntaxErrorException {
107 final StatementContext context;
108 try (final InputStream stream = source.openStream()) {
109 context = parseYangSource(source.openStream());
112 final String sourceName = source.getSymbolicName().orElse(null);
113 final YangStatementParserListenerImpl parser = new YangStatementParserListenerImpl(sourceName);
115 return new YangStatementSourceImpl(parser, context, sourceName);
119 public void writePreLinkage(final StatementWriter writer, final QNameToStatementDefinition stmtDef) {
120 yangStatementModelParser.setAttributes(writer, stmtDef);
121 ParseTreeWalker.DEFAULT.walk(yangStatementModelParser, statementContext);
125 public void writeLinkage(final StatementWriter writer, final QNameToStatementDefinition stmtDef,
126 final PrefixToModule preLinkagePrefixes) {
127 yangStatementModelParser.setAttributes(writer, stmtDef, preLinkagePrefixes);
128 ParseTreeWalker.DEFAULT.walk(yangStatementModelParser, statementContext);
132 public void writeLinkageAndStatementDefinitions(final StatementWriter writer,
133 final QNameToStatementDefinition stmtDef, final PrefixToModule prefixes) {
134 yangStatementModelParser.setAttributes(writer, stmtDef, prefixes);
135 ParseTreeWalker.DEFAULT.walk(yangStatementModelParser, statementContext);
139 public void writeFull(final StatementWriter writer, final QNameToStatementDefinition stmtDef,
140 final PrefixToModule prefixes) {
141 yangStatementModelParser.setAttributes(writer, stmtDef, prefixes);
142 ParseTreeWalker.DEFAULT.walk(yangStatementModelParser, statementContext);
145 private NamedFileInputStream loadFile(final String fileName, final boolean isAbsolute)
146 throws URISyntaxException, IOException {
147 //TODO: we need absolute path first!
148 return isAbsolute ? new NamedFileInputStream(new File(fileName), fileName)
149 : new NamedFileInputStream(new File(getClass().getResource(fileName).toURI()), fileName);
152 private static StatementContext parseYangSource(final InputStream stream) throws IOException,
153 YangSyntaxErrorException {
154 final YangStatementLexer lexer = new YangStatementLexer(new ANTLRInputStream(stream));
155 final CommonTokenStream tokens = new CommonTokenStream(lexer);
156 final YangStatementParser parser = new YangStatementParser(tokens);
157 //disconnect from console error output
158 parser.removeErrorListeners();
160 final YangErrorListener errorListener = new YangErrorListener();
161 parser.addErrorListener(errorListener);
163 final StatementContext result = parser.statement();
164 errorListener.validate();
166 // Walk the resulting tree and replace each children with an immutable list, lowering memory requirements
167 // and making sure the resulting tree will not get accidentally modified. An alternative would be to use
168 // org.antlr.v4.runtime.Parser.TrimToSizeListener, but that does not make the tree immutable.
169 ParseTreeWalker.DEFAULT.walk(MAKE_IMMUTABLE_LISTENER, result);
174 public StatementContext getYangAST() {
175 return statementContext;
179 public String toString() {