import static java.util.Objects.requireNonNull;
import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.getChild;
import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.illegalShape;
+import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.verifyTerminal;
import static org.opendaylight.yangtools.yang.xpath.impl.ParseTreeUtils.verifyToken;
+import com.google.common.base.VerifyException;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.List;
import javax.xml.xpath.XPathExpressionException;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
-import org.antlr.v4.runtime.tree.ParseTree;
import org.opendaylight.yangtools.yang.common.UnresolvedQName;
import org.opendaylight.yangtools.yang.common.YangNamespaceContext;
+import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierLexer;
import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser;
import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.EqQuotedStringContext;
-import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.InstanceIdentifierContext;
import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.KeyPredicateContext;
import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.KeyPredicateExprContext;
import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.LeafListPredicateContext;
import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.PosContext;
import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.PredicateContext;
import org.opendaylight.yangtools.yang.xpath.antlr.instanceIdentifierParser.QuotedStringContext;
-import org.opendaylight.yangtools.yang.xpath.antlr.xpathLexer;
import org.opendaylight.yangtools.yang.xpath.api.YangBinaryOperator;
import org.opendaylight.yangtools.yang.xpath.api.YangExpr;
import org.opendaylight.yangtools.yang.xpath.api.YangLiteralExpr;
}
final Absolute interpretAsInstanceIdentifier(final YangLiteralExpr expr) throws XPathExpressionException {
- final xpathLexer lexer = new xpathLexer(CharStreams.fromString(expr.getLiteral()));
- final instanceIdentifierParser parser = new instanceIdentifierParser(new CommonTokenStream(lexer));
- final CapturingErrorListener listener = new CapturingErrorListener();
+ final var lexer = new instanceIdentifierLexer(CharStreams.fromString(expr.getLiteral()));
+ final var parser = new instanceIdentifierParser(new CommonTokenStream(lexer));
+ final var listener = new CapturingErrorListener();
lexer.removeErrorListeners();
lexer.addErrorListener(listener);
parser.removeErrorListeners();
parser.addErrorListener(listener);
- final InstanceIdentifierContext id = parser.instanceIdentifier();
+ final var id = parser.instanceIdentifier();
listener.reportError();
final int length = id.getChildCount();
- final List<Step> steps = new ArrayList<>(length / 2);
+ final var steps = new ArrayList<Step>(length / 2);
for (int i = 1; i < length; i += 2) {
steps.add(parsePathArgument(getChild(id, PathArgumentContext.class, i)));
}
final String prefix = verifyIdentifier(childExpr, 0);
final String localName = verifyIdentifier(childExpr, 2);
- switch (expr.getChildCount()) {
- case 1:
- return createChildStep(prefix, localName, ImmutableSet.of());
- case 2:
- return createChildStep(prefix, localName, parsePredicate(getChild(expr, PredicateContext.class, 1)));
- default:
- throw illegalShape(expr);
- }
+ return switch (expr.getChildCount()) {
+ case 1 -> createChildStep(prefix, localName, ImmutableSet.of());
+ case 2 -> createChildStep(prefix, localName, parsePredicate(getChild(expr, PredicateContext.class, 1)));
+ default -> throw illegalShape(expr);
+ };
}
private Collection<YangExpr> parsePredicate(final PredicateContext expr) {
- final ParseTree first = expr.getChild(0);
- if (first instanceof LeafListPredicateContext) {
+ final var first = expr.getChild(0);
+ if (first instanceof LeafListPredicateContext llp) {
return ImmutableSet.of(YangBinaryOperator.EQUALS.exprWith(YangLocationPath.self(),
- parseEqStringValue(getChild(((LeafListPredicateContext) first)
- .getChild(LeafListPredicateExprContext.class, 0), EqQuotedStringContext.class, 1))));
- } else if (first instanceof PosContext) {
+ parseEqStringValue(getChild(llp.getChild(LeafListPredicateExprContext.class, 0),
+ EqQuotedStringContext.class, 1))));
+ } else if (first instanceof PosContext pc) {
return ImmutableSet.of(YangBinaryOperator.EQUALS.exprWith(FunctionSupport.POSITION,
- mathSupport.createNumber(((PosContext) first).getToken(instanceIdentifierParser.PositiveIntegerValue, 0)
- .getText())));
+ mathSupport.createNumber(pc.getToken(instanceIdentifierParser.PositiveIntegerValue, 0).getText())));
}
final int length = expr.getChildCount();
- final List<YangExpr> ret = new ArrayList<>(length);
+ final var ret = new ArrayList<YangExpr>(length);
for (int i = 0; i < length; ++i) {
- final KeyPredicateExprContext pred = getChild(expr, KeyPredicateContext.class, i)
- .getChild(KeyPredicateExprContext.class, 0);
+ final var pred = getChild(expr, KeyPredicateContext.class, i).getChild(KeyPredicateExprContext.class, 0);
ret.add(YangBinaryOperator.EQUALS.exprWith(
createChildExpr(getChild(pred, NodeIdentifierContext.class, 0)),
parseEqStringValue(getChild(pred, EqQuotedStringContext.class, 1))));
-
}
return ret;
}
private static YangLiteralExpr parseEqStringValue(final EqQuotedStringContext expr) {
- return YangLiteralExpr.of(verifyToken(getChild(expr, QuotedStringContext.class, expr.getChildCount() - 1), 1,
- instanceIdentifierParser.STRING).getText());
+ final var quotedString = getChild(expr, QuotedStringContext.class, expr.getChildCount() - 1);
+ return switch (quotedString.getChildCount()) {
+ case 1 -> YangLiteralExpr.empty();
+ case 2 -> {
+ final var terminal = verifyTerminal(quotedString.getChild(0));
+ final var token = terminal.getSymbol();
+ final var literal = switch (token.getType()) {
+ case instanceIdentifierParser.DQUOT_STRING -> unescape(token.getText());
+ case instanceIdentifierParser.SQUOT_STRING -> token.getText();
+ default -> throw illegalShape(terminal);
+ };
+ yield YangLiteralExpr.of(literal);
+ }
+ default -> throw illegalShape(quotedString);
+ };
+ }
+
+ private static String unescape(final String escaped) {
+ final int firstEscape = escaped.indexOf('\\');
+ return firstEscape == -1 ? escaped : unescape(escaped, firstEscape);
+ }
+
+ private static String unescape(final String escaped, final int firstEscape) {
+ // Sizing: optimize allocation for only a single escape
+ final int length = escaped.length();
+ final var sb = new StringBuilder(length - 1).append(escaped, 0, firstEscape);
+
+ int esc = firstEscape;
+ while (true) {
+ final var ch = escaped.charAt(esc + 1);
+ sb.append(
+ switch (ch) {
+ case 'n' -> '\n';
+ case 't' -> '\t';
+ case '"' -> '"';
+ case '\\' -> '\\';
+ default -> throw new VerifyException("Unexpected escaped char '" + ch + "'");
+ });
+
+ final int start = esc + 2;
+ esc = escaped.indexOf('\\', start);
+ if (esc == -1) {
+ return sb.append(escaped, start, length).toString();
+ }
+
+ sb.append(escaped, start, esc);
+ }
}
}