Refactor IfFeaturePredicateVisitor 01/101001/10
authorSamuel Schneider <samuel.schneider@pantheon.tech>
Fri, 6 May 2022 09:58:29 +0000 (11:58 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 17 May 2022 21:34:33 +0000 (23:34 +0200)
Refactor IfFeaturePredicateVisitor to work purely on
IfFeatureExpressionParser without use of ANTLR's visitors.

JIRA: YANGTOOLS-1396
Change-Id: I4ff988caa34a50da843fd35b8918e7b502bdf770
Signed-off-by: Samuel Schneider <samuel.schneider@pantheon.tech>
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
parser/yang-parser-rfc7950/pom.xml
parser/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/if_feature/IfFeaturePredicateParser.java [new file with mode: 0644]
parser/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/if_feature/IfFeaturePredicateVisitor.java [deleted file]
parser/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/if_feature/IfFeatureStatementRFC7950Support.java

index 7daa3fde362daf24a94a7650297ed7579c6b46ec..7653f4bd489e87a04ed040d6538e4e9af403a3ca 100644 (file)
                     </execution>
                 </executions>
                 <configuration>
-                    <!-- FIXME: YANGTOOLS-1396: disable visitors -->
-                    <visitor>true</visitor>
+                    <visitor>false</visitor>
                     <listener>false</listener>
                 </configuration>
             </plugin>
diff --git a/parser/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/if_feature/IfFeaturePredicateParser.java b/parser/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/if_feature/IfFeaturePredicateParser.java
new file mode 100644 (file)
index 0000000..f9d0392
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2017, 2022 PANTHEON.tech, 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.stmt.if_feature;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.ImmutableSet;
+import org.antlr.v4.runtime.CharStreams;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.tree.TerminalNode;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.opendaylight.yangtools.yang.model.api.stmt.IfFeatureExpr;
+import org.opendaylight.yangtools.yang.parser.antlr.IfFeatureExpressionLexer;
+import org.opendaylight.yangtools.yang.parser.antlr.IfFeatureExpressionParser;
+import org.opendaylight.yangtools.yang.parser.antlr.IfFeatureExpressionParser.Identifier_ref_argContext;
+import org.opendaylight.yangtools.yang.parser.antlr.IfFeatureExpressionParser.If_feature_exprContext;
+import org.opendaylight.yangtools.yang.parser.antlr.IfFeatureExpressionParser.If_feature_factorContext;
+import org.opendaylight.yangtools.yang.parser.antlr.IfFeatureExpressionParser.If_feature_termContext;
+import org.opendaylight.yangtools.yang.parser.rfc7950.antlr.SourceExceptionParser;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
+import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
+import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
+
+@NonNullByDefault
+final class IfFeaturePredicateParser {
+    private final StmtContext<?, ?, ?> stmt;
+
+    private IfFeaturePredicateParser(final StmtContext<?, ?, ?> stmt) {
+        this.stmt = requireNonNull(stmt);
+    }
+
+    static IfFeatureExpr parseIfFeatureExpression(final StmtContext<?, ?, ?> stmt, final String value) {
+        final var lexer = new IfFeatureExpressionLexer(CharStreams.fromString(value));
+        final var parser = new IfFeatureExpressionParser(new CommonTokenStream(lexer));
+        final var ifFeatureExprContext =
+                SourceExceptionParser.parse(lexer, parser, parser::if_feature_expr, stmt.sourceReference());
+        return new IfFeaturePredicateParser(stmt).parseIfFeatureExpr(ifFeatureExprContext);
+    }
+
+    private IfFeatureExpr parseIfFeatureExpr(final If_feature_exprContext expr) {
+        final int count = verifyExprOrTermChildren(expr);
+        final var expressions = ImmutableSet.<IfFeatureExpr>builderWithExpectedSize(count / 4 + 1);
+        for (int i = 0; i < count; i += 4) {
+            expressions.add(parseIfFeatureTerm(getChild(expr, i, If_feature_termContext.class)));
+        }
+        return IfFeatureExpr.or(expressions.build());
+    }
+
+    private IfFeatureExpr parseIfFeatureTerm(final If_feature_termContext term) {
+        final int count = verifyExprOrTermChildren(term);
+        final var expressions = ImmutableSet.<IfFeatureExpr>builderWithExpectedSize(count / 4 + 1);
+        expressions.add(parseIfFeatureFactor(getChild(term, 0, If_feature_factorContext.class)));
+
+        for (int i = 4; i < count; i += 4) {
+            expressions.add(parseIfFeatureTerm(getChild(term, i, If_feature_termContext.class)));
+        }
+        return IfFeatureExpr.and(expressions.build());
+    }
+
+    private IfFeatureExpr parseIfFeatureFactor(final If_feature_factorContext factor) {
+        final var first = factor.getChild(0);
+        if (first instanceof Identifier_ref_argContext refArg) {
+            return IfFeatureExpr.isPresent(StmtContextUtils.parseNodeIdentifier(stmt, refArg.getText()));
+        } else if (first instanceof TerminalNode terminal) {
+            return switch (terminal.getSymbol().getType()) {
+                case IfFeatureExpressionParser.LP ->
+                    parseIfFeatureExpr(factor.getChild(If_feature_exprContext.class, 0));
+                case IfFeatureExpressionParser.NOT ->
+                    parseIfFeatureFactor(getChild(factor, 2, If_feature_factorContext.class)).negate();
+                default -> throw new SourceException(stmt, "Unexpected terminal %s in sub-expression at %s",
+                    terminal.getText(), factor.getSourceInterval());
+            };
+        } else {
+            throw new SourceException(stmt, "Unexpected error: sub-expression at %s has context %s. Please file a bug "
+                + "report with the corresponding model attached.", factor.getSourceInterval(), first);
+        }
+    }
+
+    private int verifyExprOrTermChildren(ParserRuleContext context) {
+        final int count = context.getChildCount();
+        if (count % 4 != 1) {
+            throw new SourceException(stmt, "Unexpected error: sub-expression at %s has %s children. Please file a bug "
+                + "report with the corresponding model attached.", context.getSourceInterval(), count);
+        }
+        return count;
+    }
+
+    private <T> T getChild(final ParserRuleContext parent, final int offset, final Class<T> clazz) {
+        final var child = parent.getChild(offset);
+        if (!clazz.isInstance(child)) {
+            throw new SourceException(stmt, "Unexpected error: sub-expression at %s has child %s at offset %s when "
+                + "expecting %s. Please file a bug report with the corresponding model attached.",
+                parent.getSourceInterval(), child, offset, clazz);
+        }
+        return clazz.cast(child);
+    }
+}
diff --git a/parser/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/if_feature/IfFeaturePredicateVisitor.java b/parser/yang-parser-rfc7950/src/main/java/org/opendaylight/yangtools/yang/parser/rfc7950/stmt/if_feature/IfFeaturePredicateVisitor.java
deleted file mode 100644 (file)
index 53c6631..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.rfc7950.stmt.if_feature;
-
-import static java.util.Objects.requireNonNull;
-
-import com.google.common.collect.ImmutableSet;
-import java.util.ArrayList;
-import java.util.List;
-import org.antlr.v4.runtime.CharStreams;
-import org.antlr.v4.runtime.CommonTokenStream;
-import org.eclipse.jdt.annotation.NonNullByDefault;
-import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.yangtools.yang.model.api.stmt.IfFeatureExpr;
-import org.opendaylight.yangtools.yang.parser.antlr.IfFeatureExpressionLexer;
-import org.opendaylight.yangtools.yang.parser.antlr.IfFeatureExpressionParser;
-import org.opendaylight.yangtools.yang.parser.antlr.IfFeatureExpressionParser.Identifier_ref_argContext;
-import org.opendaylight.yangtools.yang.parser.antlr.IfFeatureExpressionParser.If_feature_exprContext;
-import org.opendaylight.yangtools.yang.parser.antlr.IfFeatureExpressionParser.If_feature_factorContext;
-import org.opendaylight.yangtools.yang.parser.antlr.IfFeatureExpressionParser.If_feature_termContext;
-import org.opendaylight.yangtools.yang.parser.antlr.IfFeatureExpressionParserBaseVisitor;
-import org.opendaylight.yangtools.yang.parser.rfc7950.antlr.SourceExceptionParser;
-import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContext;
-import org.opendaylight.yangtools.yang.parser.spi.meta.StmtContextUtils;
-import org.opendaylight.yangtools.yang.parser.spi.source.SourceException;
-
-// FIXME: YANGTOOLS-1396: refactor on top of vanilla IfFeatureExpressionParser
-@NonNullByDefault
-final class IfFeaturePredicateVisitor extends IfFeatureExpressionParserBaseVisitor<IfFeatureExpr> {
-    private final StmtContext<?, ?, ?> stmtCtx;
-
-    private IfFeaturePredicateVisitor(final StmtContext<?, ?, ?> ctx) {
-        this.stmtCtx = requireNonNull(ctx);
-    }
-
-    static IfFeatureExpr parseIfFeatureExpression(final StmtContext<?, ?, ?> ctx, final String value) {
-        final IfFeatureExpressionLexer lexer = new IfFeatureExpressionLexer(CharStreams.fromString(value));
-        final IfFeatureExpressionParser parser = new IfFeatureExpressionParser(new CommonTokenStream(lexer));
-        final IfFeatureExpr ret = new IfFeaturePredicateVisitor(ctx).visit(SourceExceptionParser.parse(lexer, parser,
-            parser::if_feature_expr, ctx.sourceReference()));
-
-        return ret;
-    }
-
-    @Override
-    public IfFeatureExpr visitIf_feature_expr(final @Nullable If_feature_exprContext ctx) {
-        return IfFeatureExpr.or(ctx.if_feature_term().stream()
-            .map(this::visitIf_feature_term)
-            .collect(ImmutableSet.toImmutableSet()));
-    }
-
-    @Override
-    public IfFeatureExpr visitIf_feature_term(final @Nullable If_feature_termContext ctx) {
-        final IfFeatureExpr factor = visitIf_feature_factor(ctx.if_feature_factor());
-        final List<If_feature_termContext> terms = ctx.if_feature_term();
-        if (terms == null || terms.isEmpty()) {
-            return factor;
-        }
-        final List<IfFeatureExpr> factors = new ArrayList<>(terms.size() + 1);
-        factors.add(factor);
-        for (If_feature_termContext term : terms) {
-            factors.add(visitIf_feature_term(term));
-        }
-        return IfFeatureExpr.and(ImmutableSet.copyOf(factors));
-    }
-
-    @Override
-    public IfFeatureExpr visitIf_feature_factor(final @Nullable If_feature_factorContext ctx) {
-        if (ctx.if_feature_expr() != null) {
-            return visitIf_feature_expr(ctx.if_feature_expr());
-        } else if (ctx.if_feature_factor() != null) {
-            return visitIf_feature_factor(ctx.if_feature_factor()).negate();
-        } else if (ctx.identifier_ref_arg() != null) {
-            return visitIdentifier_ref_arg(ctx.identifier_ref_arg());
-        }
-
-        throw new SourceException("Unexpected grammar context during parsing of IfFeature expression. "
-                + "Most probably IfFeature grammar has been changed.", stmtCtx);
-    }
-
-    @Override
-    public IfFeatureExpr visitIdentifier_ref_arg(final @Nullable Identifier_ref_argContext ctx) {
-        return IfFeatureExpr.isPresent(StmtContextUtils.parseNodeIdentifier(stmtCtx, ctx.getText()));
-    }
-}
index ee94c7300fb6136fd92aeeb4edbaa79562d72bce..1f1460a2f7a3035de46a7469995bd5fda3d1f82c 100644 (file)
@@ -18,6 +18,6 @@ public final class IfFeatureStatementRFC7950Support extends AbstractIfFeatureSta
 
     @Override
     public IfFeatureExpr parseArgumentValue(final StmtContext<?, ?, ?> ctx, final String value) {
-        return IfFeaturePredicateVisitor.parseIfFeatureExpression(ctx, value);
+        return IfFeaturePredicateParser.parseIfFeatureExpression(ctx, value);
     }
 }