Update yang-parser-api
[yangtools.git] / yang / yang-parser-rfc7950 / src / main / java / org / opendaylight / yangtools / yang / parser / rfc7950 / repo / YangStatementStreamSource.java
index e14ef46abf3671660aecb59b99d749e713a310b2..956ab49ab5cfbb4125793df63de1d2641c4c6067 100644 (file)
@@ -7,28 +7,35 @@
  */
 package org.opendaylight.yangtools.yang.parser.rfc7950.repo;
 
+import static com.google.common.base.Verify.verifyNotNull;
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.annotations.Beta;
-import com.google.common.base.MoreObjects;
-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.CharStreams;
 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.AbstractSimpleIdentifiable;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
 import org.opendaylight.yangtools.yang.common.YangVersion;
-import org.opendaylight.yangtools.yang.model.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
 import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource;
+import org.opendaylight.yangtools.yang.parser.antlr.YangStatementLexer;
+import org.opendaylight.yangtools.yang.parser.antlr.YangStatementParser;
+import org.opendaylight.yangtools.yang.parser.antlr.YangStatementParser.FileContext;
+import org.opendaylight.yangtools.yang.parser.antlr.YangStatementParser.StatementContext;
+import org.opendaylight.yangtools.yang.parser.api.YangSyntaxErrorException;
+import org.opendaylight.yangtools.yang.parser.rfc7950.antlr.CompactYangStatementLexer;
+import org.opendaylight.yangtools.yang.parser.rfc7950.ir.AntlrSupport;
+import org.opendaylight.yangtools.yang.parser.rfc7950.ir.IRKeyword;
+import org.opendaylight.yangtools.yang.parser.rfc7950.ir.IRSchemaSource;
+import org.opendaylight.yangtools.yang.parser.rfc7950.ir.IRStatement;
 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.SourceException;
+import org.opendaylight.yangtools.yang.parser.spi.source.StatementSourceReference;
 import org.opendaylight.yangtools.yang.parser.spi.source.StatementStreamSource;
 import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter;
 
@@ -39,135 +46,111 @@ import org.opendaylight.yangtools.yang.parser.spi.source.StatementWriter;
  * @author Robert Varga
  */
 @Beta
-public final class YangStatementStreamSource implements 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 final class YangStatementStreamSource extends AbstractSimpleIdentifiable<SourceIdentifier>
+        implements StatementStreamSource {
+    private final IRStatement rootStatement;
+    private final String sourceName;
+
+    private YangStatementStreamSource(final SourceIdentifier identifier,  final IRStatement rootStatement,
+            final String sourceName) {
+        super(identifier);
+        this.rootStatement = requireNonNull(rootStatement);
+        this.sourceName = sourceName;
     }
 
+    /**
+     * Create a {@link YangStatementStreamSource} for a {@link YangTextSchemaSource}.
+     *
+     * @param source YangTextSchemaSource, must not be null
+     * @return A new {@link YangStatementStreamSource}
+     * @throws IOException When we fail to read the source
+     * @throws YangSyntaxErrorException If the source fails basic parsing
+     */
     public static YangStatementStreamSource create(final YangTextSchemaSource source) throws IOException,
             YangSyntaxErrorException {
-        final StatementContext context;
-        try (InputStream stream = source.openStream()) {
-            context = parseYangSource(source.getIdentifier(), stream);
-        }
-
-        final String sourceName = source.getSymbolicName().orElse(null);
-        final YangStatementParserListenerImpl parser = new YangStatementParserListenerImpl(sourceName);
-        return new YangStatementStreamSource(source.getIdentifier(), parser, context);
+        return new YangStatementStreamSource(source.getIdentifier(),
+            AntlrSupport.createStatement(parseYangSource(source)), source.getSymbolicName().orElse(null));
     }
 
-    public static YangStatementStreamSource create(final SourceIdentifier identifier, final StatementContext context,
-        final String symbolicName) {
-        return new YangStatementStreamSource(identifier, new YangStatementParserListenerImpl(symbolicName), context);
+    /**
+     * Create a {@link YangStatementStreamSource} for a {@link IRSchemaSource}.
+     *
+     * @param source YangTextSchemaSource, must not be null
+     * @return A new {@link YangStatementStreamSource}
+     * @throws NullPointerException if {@code source} is null
+     */
+    public static YangStatementStreamSource create(final IRSchemaSource source) {
+        return create(source.getIdentifier(), source.getRootStatement(), source.getSymbolicName().orElse(null));
     }
 
-    @Override
-    public void writePreLinkage(final StatementWriter writer, final QNameToStatementDefinition stmtDef) {
-        yangStatementModelParser.setAttributes(writer, stmtDef);
-        ParseTreeWalker.DEFAULT.walk(yangStatementModelParser, context);
+    public static YangStatementStreamSource create(final SourceIdentifier identifier, final IRStatement rootStatement,
+            final String symbolicName) {
+        return new YangStatementStreamSource(identifier, rootStatement, symbolicName);
     }
 
     @Override
-    public void writeLinkage(final StatementWriter writer, final QNameToStatementDefinition stmtDef,
-            final PrefixToModule preLinkagePrefixes) {
-        writeLinkage(writer, stmtDef, preLinkagePrefixes, YangVersion.VERSION_1);
+    public void writePreLinkage(final StatementWriter writer, final QNameToStatementDefinition stmtDef) {
+        new StatementContextVisitor(sourceName, writer, stmtDef, null, YangVersion.VERSION_1).visit(rootStatement);
     }
 
     @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);
+        new StatementContextVisitor(sourceName, writer, stmtDef, preLinkagePrefixes, yangVersion) {
+            @Override
+            StatementDefinition resolveStatement(final QNameModule module, final String localName) {
+                return stmtDef.getByNamespaceAndLocalName(module.getNamespace(), localName);
+            }
+        }.visit(rootStatement);
     }
 
     @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);
+        new StatementContextVisitor(sourceName, writer, stmtDef, prefixes, yangVersion).visit(rootStatement);
     }
 
     @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);
+        new StatementContextVisitor(sourceName, writer, stmtDef, prefixes, yangVersion) {
+            @Override
+            QName getValidStatementDefinition(final IRKeyword keyword, final StatementSourceReference ref) {
+                final QName ret = super.getValidStatementDefinition(keyword, ref);
+                if (ret == null) {
+                    throw new SourceException(ref, "%s is not a YANG statement or use of extension.",
+                        keyword.asStringDeclaration());
+                }
+                return ret;
+            }
+        }.visit(rootStatement);
     }
 
-    @Override
-    public SourceIdentifier getIdentifier() {
-        return identifier;
+    IRStatement rootStatement() {
+        return rootStatement;
     }
 
-    public ParserRuleContext getYangAST() {
-        return context;
+    static StatementContext parseYangSource(final YangTextSchemaSource source)
+            throws IOException, YangSyntaxErrorException {
+        try (InputStream stream = source.openStream()) {
+            return parseYangSource(source.getIdentifier(), stream);
+        }
     }
 
     private static StatementContext parseYangSource(final SourceIdentifier source, final InputStream stream)
             throws IOException, YangSyntaxErrorException {
-        final YangStatementLexer lexer = new YangStatementLexer(CharStreams.fromStream(stream));
-        final CommonTokenStream tokens = new CommonTokenStream(lexer);
-        final YangStatementParser parser = new YangStatementParser(tokens);
-        //disconnect from console error output
+        final YangStatementLexer lexer = new CompactYangStatementLexer(CharStreams.fromStream(stream));
+        final YangStatementParser parser = new YangStatementParser(new CommonTokenStream(lexer));
+        // disconnect from console error output
+        lexer.removeErrorListeners();
         parser.removeErrorListeners();
 
         final YangErrorListener errorListener = new YangErrorListener(source);
+        lexer.addErrorListener(errorListener);
         parser.addErrorListener(errorListener);
 
-        final StatementContext result = parser.statement();
+        final FileContext result = parser.file();
         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;
-    }
-
-    @Override
-    public String toString() {
-        return MoreObjects.toStringHelper(this).add("identifier", getIdentifier()).toString();
+        return verifyNotNull(result.statement());
     }
 }