Turn YangStatementParserListenerImpl into a visitor 78/68678/8
authorRobert Varga <robert.varga@pantheon.tech>
Sun, 25 Feb 2018 21:05:16 +0000 (22:05 +0100)
committerRobert Varga <nite@hq.sk>
Mon, 26 Feb 2018 00:07:51 +0000 (00:07 +0000)
Rather than using a listener with two methods, which needs to keep
and re-lookup state, implement such visitStatement(). This allows us
to skip duplicate lookups and will allow us to completely eliminate
all state tracking.

As it turns out we do not need any visitor logic, because we are
always walking statements and descending into their children. Rework
logic to reflect that, eliminating the need for any statekeeping,
as we can track all of the state inline.

JIRA: YANGTOOLS-713
Change-Id: I22a289fdbb2d8ea1501dd4a8eacd7780afbf1c6c
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/repo/StatementContextVisitor.java [new file with mode: 0644]
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/repo/YangStatementParserListenerImpl.java [deleted file]
yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/repo/YangStatementStreamSource.java

diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/repo/StatementContextVisitor.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/repo/StatementContextVisitor.java
new file mode 100644 (file)
index 0000000..5116b34
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2018 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.rfc7950.repo;
+
+import static com.google.common.base.Verify.verifyNotNull;
+import static java.util.Objects.requireNonNull;
+
+import org.antlr.v4.runtime.tree.ParseTree;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.ArgumentContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.KeywordContext;
+import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.StatementContext;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.common.YangConstants;
+import org.opendaylight.yangtools.yang.common.YangVersion;
+import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
+import org.opendaylight.yangtools.yang.parser.spi.source.DeclarationInTextSource;
+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.StatementWriter;
+
+abstract class StatementContextVisitor {
+    static final class Loose extends StatementContextVisitor {
+        Loose(final String sourceName, final StatementWriter writer,
+            final QNameToStatementDefinition stmtDef, final PrefixToModule prefixes, final YangVersion yangVersion) {
+            super(sourceName, writer, stmtDef, prefixes, yangVersion);
+        }
+
+        Loose(final String sourceName, final StatementWriter writer, final QNameToStatementDefinition stmtDef) {
+            this(sourceName, writer, stmtDef, null, YangVersion.VERSION_1);
+        }
+    }
+
+    static final class Strict extends StatementContextVisitor {
+        Strict(final String sourceName, final StatementWriter writer,
+            final QNameToStatementDefinition stmtDef, final PrefixToModule prefixes, final YangVersion yangVersion) {
+            super(sourceName, writer, stmtDef, prefixes, yangVersion);
+        }
+
+        @Override
+        QName getValidStatementDefinition(final String keywordText, final StatementSourceReference ref) {
+            return SourceException.throwIfNull(super.getValidStatementDefinition(keywordText, ref), ref,
+                "%s is not a YANG statement or use of extension.", keywordText);
+        }
+    }
+
+    private final QNameToStatementDefinition stmtDef;
+    private final StatementWriter writer;
+    private final YangVersion yangVersion;
+    private final PrefixToModule prefixes;
+    private final String sourceName;
+
+    private StatementContextVisitor(final String sourceName, final StatementWriter writer,
+            final QNameToStatementDefinition stmtDef, final PrefixToModule prefixes, final YangVersion yangVersion) {
+        this.writer = requireNonNull(writer);
+        this.stmtDef = requireNonNull(stmtDef);
+        this.yangVersion = requireNonNull(yangVersion);
+        this.sourceName = sourceName;
+        this.prefixes = prefixes;
+    }
+
+    void visit(final StatementContext context) {
+        processStatement(0, context);
+    }
+
+    /**
+     * Based on identifier read from source and collections of relevant prefixes and statement definitions mappings
+     * provided for actual phase, method resolves and returns valid QName for declared statement to be written.
+     * This applies to any declared statement, including unknown statements.
+     *
+     * @param prefixes collection of all relevant prefix mappings supplied for actual parsing phase
+     * @param stmtDef collection of all relevant statement definition mappings provided for actual parsing phase
+     * @param keywordText statement keyword text to parse from source
+     * @param ref Source reference
+     * @return valid QName for declared statement to be written, or null
+     */
+    QName getValidStatementDefinition(final String keywordText, final StatementSourceReference ref) {
+        final int firstColon = keywordText.indexOf(':');
+        if (firstColon == -1) {
+            final StatementDefinition def = stmtDef.get(QName.create(YangConstants.RFC6020_YIN_NAMESPACE, keywordText));
+            return def != null ? def.getStatementName() : null;
+        }
+
+        SourceException.throwIf(firstColon == keywordText.length() - 1
+                || keywordText.indexOf(':', firstColon + 1) != -1, ref, "Malformed statement '%s'", keywordText);
+
+        if (prefixes == null) {
+            // No prefixes to look up from
+            return null;
+        }
+
+        final String prefix = keywordText.substring(0, firstColon);
+        final QNameModule qNameModule = prefixes.get(prefix);
+        if (qNameModule == null) {
+            // Failed to look the namespace
+            return null;
+        }
+
+        final String localName = keywordText.substring(firstColon + 1);
+        final StatementDefinition foundStmtDef;
+        if (prefixes.isPreLinkageMap()) {
+            foundStmtDef = stmtDef.getByNamespaceAndLocalName(qNameModule.getNamespace(), localName);
+        } else {
+            foundStmtDef = stmtDef.get(QName.create(qNameModule, localName));
+        }
+
+        return foundStmtDef != null ? foundStmtDef.getStatementName() : null;
+    }
+
+    private void processStatement(final int myOffset, final StatementContext ctx) {
+        final String keywordTxt = verifyNotNull(ctx.getChild(KeywordContext.class, 0)).getText();
+        final StatementSourceReference ref = DeclarationInTextSource.atPosition(sourceName, ctx.getStart().getLine(),
+            ctx.getStart().getCharPositionInLine());
+        final QName def = getValidStatementDefinition(keywordTxt, ref);
+        if (def == null) {
+            return;
+        }
+
+        final ArgumentContext argumentCtx = ctx.getChild(ArgumentContext.class, 0);
+        final String argument = argumentCtx == null ? null
+                : ArgumentContextUtils.stringFromStringContext(argumentCtx, yangVersion, ref);
+        writer.startStatement(myOffset, def, argument, ref);
+
+        if (ctx.children != null) {
+            int childOffset = 0;
+            for (ParseTree s : ctx.children) {
+                if (s instanceof StatementContext) {
+                    processStatement(childOffset++, (StatementContext) s);
+                }
+            }
+        }
+
+        writer.endStatement(ref);
+    }
+}
diff --git a/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/repo/YangStatementParserListenerImpl.java b/yang/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/repo/YangStatementParserListenerImpl.java
deleted file mode 100644 (file)
index 7d9d51b..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright (c) 2015 Cisco Systems, Inc. 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.rfc7950.repo;
-
-import static com.google.common.base.Verify.verify;
-import static com.google.common.base.Verify.verifyNotNull;
-import static java.util.Objects.requireNonNull;
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Deque;
-import java.util.List;
-import org.antlr.v4.runtime.tree.ParseTreeWalker;
-import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.ArgumentContext;
-import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.KeywordContext;
-import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParser.StatementContext;
-import org.opendaylight.yangtools.antlrv4.code.gen.YangStatementParserBaseListener;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.common.YangConstants;
-import org.opendaylight.yangtools.yang.common.YangVersion;
-import org.opendaylight.yangtools.yang.model.api.meta.StatementDefinition;
-import org.opendaylight.yangtools.yang.parser.spi.meta.ModelProcessingPhase;
-import org.opendaylight.yangtools.yang.parser.spi.source.DeclarationInTextSource;
-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.StatementWriter;
-
-final class YangStatementParserListenerImpl extends YangStatementParserBaseListener {
-    private static final class Counter {
-        private int value = 0;
-
-        int getAndIncrement() {
-            return value++;
-        }
-    }
-
-    private final List<String> toBeSkipped = new ArrayList<>();
-    private final Deque<Counter> counters = new ArrayDeque<>();
-    private final String sourceName;
-
-    private QNameToStatementDefinition stmtDef;
-    private PrefixToModule prefixes;
-    private StatementWriter writer;
-    private YangVersion yangVersion;
-
-    YangStatementParserListenerImpl(final String sourceName) {
-        this.sourceName = sourceName;
-    }
-
-    @SuppressWarnings("checkstyle:hiddenField")
-    void walk(final StatementWriter writer, final QNameToStatementDefinition stmtDef, final StatementContext context) {
-        walk(writer, stmtDef, null, YangVersion.VERSION_1, context);
-    }
-
-    @SuppressWarnings("checkstyle:hiddenField")
-    void walk(final StatementWriter writer, final QNameToStatementDefinition stmtDef,
-            final PrefixToModule prefixes, final YangVersion yangVersion, final StatementContext context) {
-        // Verify & initialize state
-        verify(toBeSkipped.isEmpty());
-        verify(counters.isEmpty());
-        this.writer = requireNonNull(writer);
-        this.stmtDef = requireNonNull(stmtDef);
-        this.prefixes = prefixes;
-        this.yangVersion = requireNonNull(yangVersion);
-        counters.push(new Counter());
-
-        try {
-            ParseTreeWalker.DEFAULT.walk(this, context);
-        } finally {
-            // Reset out state
-            this.writer = null;
-            this.stmtDef = null;
-            this.prefixes = null;
-            this.yangVersion = null;
-            toBeSkipped.clear();
-            counters.clear();
-        }
-    }
-
-    @Override
-    public void enterStatement(final StatementContext ctx) {
-        final StatementSourceReference ref = DeclarationInTextSource.atPosition(sourceName, ctx.getStart().getLine(),
-                ctx.getStart().getCharPositionInLine());
-        final String keywordTxt = verifyNotNull(ctx.getChild(KeywordContext.class, 0)).getText();
-        final QName validStatementDefinition = getValidStatementDefinition(prefixes, stmtDef, keywordTxt, ref);
-
-        final int childId = counters.peek().getAndIncrement();
-        counters.push(new Counter());
-        if (stmtDef == null || validStatementDefinition == null || !toBeSkipped.isEmpty()) {
-            SourceException.throwIf(writer.getPhase() == ModelProcessingPhase.FULL_DECLARATION, ref,
-                    "%s is not a YANG statement or use of extension.", keywordTxt);
-            toBeSkipped.add(keywordTxt);
-            return;
-        }
-
-        final ArgumentContext argumentCtx = ctx.getChild(ArgumentContext.class, 0);
-        final String argument = argumentCtx != null
-                ? ArgumentContextUtils.stringFromStringContext(argumentCtx, yangVersion, ref) : null;
-        writer.startStatement(childId, validStatementDefinition, argument, ref);
-    }
-
-    @Override
-    public void exitStatement(final StatementContext ctx) {
-        final StatementSourceReference ref = DeclarationInTextSource.atPosition(
-            sourceName, ctx.getStart().getLine(), ctx.getStart().getCharPositionInLine());
-
-        final KeywordContext keyword = ctx.getChild(KeywordContext.class, 0);
-        final String statementName = keyword.getText();
-        if (stmtDef != null && getValidStatementDefinition(prefixes, stmtDef, statementName, ref) != null
-                && toBeSkipped.isEmpty()) {
-            writer.endStatement(ref);
-        }
-
-        // No-op if the statement is not on the list
-        toBeSkipped.remove(statementName);
-        counters.pop();
-    }
-
-    /**
-     * Based on identifier read from source and collections of relevant prefixes and statement definitions mappings
-     * provided for actual phase, method resolves and returns valid QName for declared statement to be written.
-     * This applies to any declared statement, including unknown statements.
-     *
-     * @param prefixes collection of all relevant prefix mappings supplied for actual parsing phase
-     * @param stmtDef collection of all relevant statement definition mappings provided for actual parsing phase
-     * @param keywordText statement keyword text to parse from source
-     * @param ref Source reference
-     * @return valid QName for declared statement to be written, or null
-     */
-    private static QName getValidStatementDefinition(final PrefixToModule prefixes,
-            final QNameToStatementDefinition stmtDef, final String keywordText, final StatementSourceReference ref) {
-        final int firstColon = keywordText.indexOf(':');
-        if (firstColon == -1) {
-            final StatementDefinition statementDefinition = stmtDef.get(
-                QName.create(YangConstants.RFC6020_YIN_NAMESPACE, keywordText));
-            return statementDefinition != null ? statementDefinition.getStatementName() : null;
-        }
-
-        SourceException.throwIf(firstColon == keywordText.length() - 1
-                || keywordText.indexOf(':', firstColon + 1) != -1, ref, "Malformed statement '%s'", keywordText);
-
-        if (prefixes == null) {
-            // No prefixes to look up from
-            return null;
-        }
-
-        final String prefix = keywordText.substring(0, firstColon);
-        final QNameModule qNameModule = prefixes.get(prefix);
-        if (qNameModule == null) {
-            // Failed to look the namespace
-            return null;
-        }
-
-        final String localName = keywordText.substring(firstColon + 1);
-        final StatementDefinition foundStmtDef;
-        if (prefixes.isPreLinkageMap()) {
-            foundStmtDef = stmtDef.getByNamespaceAndLocalName(qNameModule.getNamespace(), localName);
-        } else {
-            foundStmtDef = stmtDef.get(QName.create(qNameModule, localName));
-        }
-
-        return foundStmtDef != null ? foundStmtDef.getStatementName() : null;
-    }
-}
index e87268119504d86612cc3f22091ef1a9820f76c8..2fa70ad89c8ad3dc9f253f5d16d277c475ef436f 100644 (file)
@@ -64,15 +64,15 @@ public final class YangStatementStreamSource implements StatementStreamSource {
         }
     };
 
-    private final YangStatementParserListenerImpl yangStatementModelParser;
     private final SourceIdentifier identifier;
     private final StatementContext context;
+    private final String sourceName;
 
-    private YangStatementStreamSource(final SourceIdentifier identifier, final YangStatementParserListenerImpl parser,
-            final StatementContext context) {
+    private YangStatementStreamSource(final SourceIdentifier identifier,  final StatementContext context,
+            final String sourceName) {
         this.identifier = Preconditions.checkNotNull(identifier);
-        this.yangStatementModelParser = Preconditions.checkNotNull(parser);
         this.context = Preconditions.checkNotNull(context);
+        this.sourceName = sourceName;
     }
 
     /**
@@ -90,9 +90,7 @@ public final class YangStatementStreamSource implements StatementStreamSource {
             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(), context, source.getSymbolicName().orElse(null));
     }
 
     /**
@@ -110,12 +108,12 @@ public final class YangStatementStreamSource implements StatementStreamSource {
 
     public static YangStatementStreamSource create(final SourceIdentifier identifier, final StatementContext context,
         final String symbolicName) {
-        return new YangStatementStreamSource(identifier, new YangStatementParserListenerImpl(symbolicName), context);
+        return new YangStatementStreamSource(identifier, context, symbolicName);
     }
 
     @Override
     public void writePreLinkage(final StatementWriter writer, final QNameToStatementDefinition stmtDef) {
-        yangStatementModelParser.walk(writer, stmtDef, context);
+        new StatementContextVisitor.Loose(sourceName, writer, stmtDef).visit(context);
     }
 
     @Override
@@ -127,7 +125,7 @@ public final class YangStatementStreamSource implements StatementStreamSource {
     @Override
     public void writeLinkage(final StatementWriter writer, final QNameToStatementDefinition stmtDef,
             final PrefixToModule preLinkagePrefixes, final YangVersion yangVersion) {
-        yangStatementModelParser.walk(writer, stmtDef, preLinkagePrefixes, yangVersion, context);
+        new StatementContextVisitor.Loose(sourceName, writer, stmtDef, preLinkagePrefixes, yangVersion).visit(context);
     }
 
     @Override
@@ -139,7 +137,7 @@ public final class YangStatementStreamSource implements StatementStreamSource {
     @Override
     public void writeLinkageAndStatementDefinitions(final StatementWriter writer,
             final QNameToStatementDefinition stmtDef, final PrefixToModule prefixes, final YangVersion yangVersion) {
-        yangStatementModelParser.walk(writer, stmtDef, prefixes, yangVersion, context);
+        new StatementContextVisitor.Loose(sourceName, writer, stmtDef, prefixes, yangVersion).visit(context);
     }
 
     @Override
@@ -151,7 +149,7 @@ public final class YangStatementStreamSource implements StatementStreamSource {
     @Override
     public void writeFull(final StatementWriter writer, final QNameToStatementDefinition stmtDef,
             final PrefixToModule prefixes, final YangVersion yangVersion) {
-        yangStatementModelParser.walk(writer, stmtDef, prefixes, yangVersion, context);
+        new StatementContextVisitor.Strict(sourceName, writer, stmtDef, prefixes, yangVersion).visit(context);
     }
 
     @Override