Bug 6901 - [Yang 1.1] Default value MUST NOT be marked with an if-feature
[yangtools.git] / yang / yang-parser-impl / src / main / java / org / opendaylight / yangtools / yang / parser / stmt / rfc6020 / YangStatementSourceImpl.java
index fb322026479f3f71d07b2ebcd2381ffbd8ae5211..291e27b313bdb40282205dbe112b3b1e5aaa6fbe 100644 (file)
@@ -5,22 +5,29 @@
  * 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.stmt.rfc6020;
 
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URISyntaxException;
 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.yang.model.parser.api.YangSyntaxErrorException;
 import org.opendaylight.yangtools.yang.model.repo.api.SourceIdentifier;
-import org.opendaylight.yangtools.yang.parser.impl.YangErrorListener;
 import org.opendaylight.yangtools.yang.parser.impl.YangStatementParserListenerImpl;
+import org.opendaylight.yangtools.yang.parser.rfc6020.repo.YangErrorListener;
 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;
@@ -30,87 +37,96 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- *
  * This class represents implementation of StatementStreamSource
- * in order to emit YANG statements using supplied StatementWriter
- *
+ * in order to emit YANG statements using supplied StatementWriter.
  */
 public final class YangStatementSourceImpl implements StatementStreamSource {
 
+    private static final Logger LOG = LoggerFactory.getLogger(YangStatementSourceImpl.class);
+
+    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 YangStatementParserListenerImpl yangStatementModelParser;
     private YangStatementParser.StatementContext statementContext;
-    private ParseTreeWalker walker;
     private String sourceName;
-//    private String source;
-//    private InputStream sourceStream;
-    private static final Logger LOG = LoggerFactory.getLogger(YangStatementSourceImpl.class);
 
-    public YangStatementSourceImpl(final String fileName, boolean isAbsolute) {
+    public YangStatementSourceImpl(final String fileName, final boolean isAbsolute) {
         try {
             statementContext = parseYangSource(loadFile(fileName, isAbsolute));
-            walker = new ParseTreeWalker();
             yangStatementModelParser = new YangStatementParserListenerImpl(sourceName);
-        } catch (Exception e) {
-            logError(e);
+        } catch (IOException | URISyntaxException | YangSyntaxErrorException e) {
+            throw Throwables.propagate(e);
         }
     }
 
     public YangStatementSourceImpl(final InputStream inputStream) {
         try {
             statementContext = parseYangSource(inputStream);
-            walker = new ParseTreeWalker();
             yangStatementModelParser = new YangStatementParserListenerImpl(sourceName);
-        } catch (Exception e) {
-            logError(e);
+        } catch (IOException | YangSyntaxErrorException e) {
+            throw Throwables.propagate(e);
         }
     }
 
-    public YangStatementSourceImpl(SourceIdentifier identifier, YangStatementParser.StatementContext statementContext) {
-        try {
-            this.statementContext = statementContext;
-            this.sourceName = identifier.getName();
-            walker = new ParseTreeWalker();
-            yangStatementModelParser = new YangStatementParserListenerImpl(sourceName);
-        } catch (Exception e) {
-            logError(e);
-        }
+    public YangStatementSourceImpl(final SourceIdentifier identifier,
+            final YangStatementParser.StatementContext statementContext) {
+        this.statementContext = statementContext;
+        this.sourceName = identifier.getName();
+        yangStatementModelParser = new YangStatementParserListenerImpl(sourceName);
     }
 
     @Override
     public void writePreLinkage(final StatementWriter writer, final QNameToStatementDefinition stmtDef) {
         yangStatementModelParser.setAttributes(writer, stmtDef);
-        walker.walk(yangStatementModelParser, statementContext);
+        ParseTreeWalker.DEFAULT.walk(yangStatementModelParser, statementContext);
     }
 
     @Override
-    public void writeLinkage(final StatementWriter writer, final QNameToStatementDefinition stmtDef, final PrefixToModule preLinkagePrefixes) {
+    public void writeLinkage(final StatementWriter writer, final QNameToStatementDefinition stmtDef,
+            final PrefixToModule preLinkagePrefixes) {
         yangStatementModelParser.setAttributes(writer, stmtDef, preLinkagePrefixes);
-        walker.walk(yangStatementModelParser, statementContext);
+        ParseTreeWalker.DEFAULT.walk(yangStatementModelParser, statementContext);
     }
 
     @Override
-    public void writeLinkageAndStatementDefinitions(final StatementWriter writer, final QNameToStatementDefinition stmtDef, final PrefixToModule prefixes) {
+    public void writeLinkageAndStatementDefinitions(final StatementWriter writer,
+            final QNameToStatementDefinition stmtDef, final PrefixToModule prefixes) {
         yangStatementModelParser.setAttributes(writer, stmtDef, prefixes);
-        walker.walk(yangStatementModelParser, statementContext);
+        ParseTreeWalker.DEFAULT.walk(yangStatementModelParser, statementContext);
     }
 
     @Override
-    public void writeFull(final StatementWriter writer, final QNameToStatementDefinition stmtDef, final PrefixToModule prefixes) {
+    public void writeFull(final StatementWriter writer, final QNameToStatementDefinition stmtDef,
+            final PrefixToModule prefixes) {
         yangStatementModelParser.setAttributes(writer, stmtDef, prefixes);
-        walker.walk(yangStatementModelParser, statementContext);
+        ParseTreeWalker.DEFAULT.walk(yangStatementModelParser, statementContext);
     }
 
-    private NamedFileInputStream loadFile(final String fileName, boolean isAbsolute) throws URISyntaxException,
-            IOException {
+    private NamedFileInputStream loadFile(final String fileName, final boolean isAbsolute)
+            throws URISyntaxException, IOException {
         //TODO: we need absolute path first!
-        return isAbsolute ? new NamedFileInputStream(new File(fileName), fileName) : new NamedFileInputStream(new File
-                (getClass().getResource(fileName).toURI()), fileName);
-
-//        final File file = new File(fileName);
-//        final ByteSource byteSource = BuilderUtils.fileToByteSource(file);
-//        source = byteSource.asCharSource(Charsets.UTF_8).read();
-//        return isAbsolute ? new NamedFileInputStream(file, fileName) : new NamedFileInputStream(new File
-//                (getClass().getResource(fileName).toURI()), fileName);
+        return isAbsolute ? new NamedFileInputStream(new File(fileName), fileName)
+                : new NamedFileInputStream(new File(getClass().getResource(fileName).toURI()), fileName);
     }
 
     private YangStatementParser.StatementContext parseYangSource(final InputStream stream) throws IOException,
@@ -130,15 +146,14 @@ public final class YangStatementSourceImpl implements StatementStreamSource {
             sourceName = null;
         }
 
-//        sourceStream = stream;
-//        sourceName = parser.getSourceName();
-//
-//        if (sourceName == null) {
-//            sourceName = stream.toString();
-//        }
         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;
     }
 
@@ -150,16 +165,4 @@ public final class YangStatementSourceImpl implements StatementStreamSource {
     public String toString() {
         return sourceName;
     }
-
-//    public InputStream getSourceStream() {
-//        return sourceStream;
-//    }
-
-    private static void logError(Exception e) {
-        if (e instanceof YangSyntaxErrorException) {
-            LOG.error(((YangSyntaxErrorException) e).getFormattedMessage(), e);
-        } else {
-            LOG.error(e.getMessage(), e);
-        }
-    }
 }