/*
* Copyright (c) 2017 Pantheon Technologies, s.r.o. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*/
package org.opendaylight.yangtools.yang.parser.rfc6020.repo;
import com.google.common.annotations.Beta;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.io.InputStream;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.ParseTreeListener;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementLexer;
import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser;
import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.StatementContext;
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.yang.common.YangVersion;
import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
import org.opendaylight.yangtools.yang.parser.impl.YangStatementParserListenerImpl;
import org.opendaylight.yangtools.yang.parser.spi.source.PrefixToModule;
import org.opendaylight.yangtools.yang.parser.spi.source.QNameToStatementDefinition;
import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter;
/**
* This class represents implementation of StatementStreamSource in order to emit YANG statements using supplied
* StatementWriter.
*
* @author Robert Varga
*/
@Beta
public final class YangStatementStreamSource implements Identifiable<SourceIdentifier>, StatementStreamSource {
private static final ParseTreeListener MAKE_IMMUTABLE_LISTENER = new ParseTreeListener() {
@Override
public void enterEveryRule(final ParserRuleContext ctx) {
// No-op
}
@Override
public void exitEveryRule(final ParserRuleContext ctx) {
ctx.children = ctx.children == null ? ImmutableList.of() : ImmutableList.copyOf(ctx.children);
}
@Override
public void visitTerminal(final TerminalNode node) {
// No-op
}
@Override
public void visitErrorNode(final ErrorNode node) {
// No-op
}
};
private final YangStatementParserListenerImpl yangStatementModelParser;
private final SourceIdentifier identifier;
private final StatementContext context;
private YangStatementStreamSource(final SourceIdentifier identifier, final YangStatementParserListenerImpl parser,
final StatementContext context) {
this.identifier = Preconditions.checkNotNull(identifier);
this.yangStatementModelParser = Preconditions.checkNotNull(parser);
this.context = Preconditions.checkNotNull(context);
}
public static YangStatementStreamSource create(final YangTextSchemaSource source) throws IOException,
YangSyntaxErrorException {
final StatementContext context;
try (final InputStream stream = source.openStream()) {
context = parseYangSource(stream);
}
final String sourceName = source.getSymbolicName().orElse(null);
final YangStatementParserListenerImpl parser = new YangStatementParserListenerImpl(sourceName);
return new YangStatementStreamSource(source.getIdentifier(), parser, context);
}
@Override
public void writePreLinkage(final StatementWriter writer, final QNameToStatementDefinition stmtDef) {
yangStatementModelParser.setAttributes(writer, stmtDef);
ParseTreeWalker.DEFAULT.walk(yangStatementModelParser, context);
}
@Override
public void writeLinkage(final StatementWriter writer, final QNameToStatementDefinition stmtDef,
final PrefixToModule preLinkagePrefixes) {
writeLinkage(writer, stmtDef, preLinkagePrefixes, YangVersion.VERSION_1);
}
@Override
public void writeLinkage(final StatementWriter writer, final QNameToStatementDefinition stmtDef,
final PrefixToModule preLinkagePrefixes, final YangVersion yangVersion) {
yangStatementModelParser.setAttributes(writer, stmtDef, preLinkagePrefixes, yangVersion);
ParseTreeWalker.DEFAULT.walk(yangStatementModelParser, context);
}
@Override
public void writeLinkageAndStatementDefinitions(final StatementWriter writer,
final QNameToStatementDefinition stmtDef, final PrefixToModule prefixes) {
writeLinkageAndStatementDefinitions(writer, stmtDef, prefixes, YangVersion.VERSION_1);
}
@Override
public void writeLinkageAndStatementDefinitions(final StatementWriter writer,
final QNameToStatementDefinition stmtDef, final PrefixToModule prefixes, final YangVersion yangVersion) {
yangStatementModelParser.setAttributes(writer, stmtDef, prefixes, yangVersion);
ParseTreeWalker.DEFAULT.walk(yangStatementModelParser, context);
}
@Override
public void writeFull(final StatementWriter writer, final QNameToStatementDefinition stmtDef,
final PrefixToModule prefixes) {
writeFull(writer, stmtDef, prefixes, YangVersion.VERSION_1);
}
@Override
public void writeFull(final StatementWriter writer, final QNameToStatementDefinition stmtDef,
final PrefixToModule prefixes, final YangVersion yangVersion) {
yangStatementModelParser.setAttributes(writer, stmtDef, prefixes, yangVersion);
ParseTreeWalker.DEFAULT.walk(yangStatementModelParser, context);
}
@Override
public SourceIdentifier getIdentifier() {
return identifier;
}
public ParserRuleContext getYangAST() {
return context;
}
/**
* @deprecated Provided for migration purposes only. Do not use.
*/
@Deprecated
public static StatementContext parseYangSource(final InputStream stream) throws IOException,
YangSyntaxErrorException {
final YangStatementLexer lexer = new YangStatementLexer(new ANTLRInputStream(stream));
final CommonTokenStream tokens = new CommonTokenStream(lexer);
final YangStatementParser parser = new YangStatementParser(tokens);
//disconnect from console error output
parser.removeErrorListeners();
final YangErrorListener errorListener = new YangErrorListener();
parser.addErrorListener(errorListener);
final StatementContext result = parser.statement();
errorListener.validate();
// Walk the resulting tree and replace each children with an immutable list, lowering memory requirements
// and making sure the resulting tree will not get accidentally modified. An alternative would be to use
// org.antlr.v4.runtime.Parser.TrimToSizeListener, but that does not make the tree immutable.
ParseTreeWalker.DEFAULT.walk(MAKE_IMMUTABLE_LISTENER, result);
return result;
}
}