+ final var quotedString = getChild(expr, QuotedStringContext.class, expr.getChildCount() - 1);
+ switch (quotedString.getChildCount()) {
+ case 1:
+ return YangLiteralExpr.empty();
+ case 2:
+ final var terminal = verifyTerminal(quotedString.getChild(0));
+ final var token = terminal.getSymbol();
+ final String literal;
+ switch (token.getType()) {
+ case instanceIdentifierParser.DQUOT_STRING:
+ literal = unescape(token.getText());
+ break;
+ case instanceIdentifierParser.SQUOT_STRING:
+ literal = token.getText();
+ break;
+ default:
+ throw illegalShape(terminal);
+ }
+ return 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) {
+ sb.append(replace(escaped.charAt(esc + 1)));
+
+ final int start = esc + 2;
+ esc = escaped.indexOf('\\', start);
+ if (esc == -1) {
+ return sb.append(escaped, start, length).toString();
+ }
+
+ sb.append(escaped, start, esc);
+ }
+ }
+
+ private static char replace(final char ch) {
+ switch (ch) {
+ case 'n':
+ return '\n';
+ case 't':
+ return '\t';
+ case '"':
+ return '"';
+ case '\\':
+ return '\\';
+ default:
+ throw new VerifyException("Unexpected escaped char '" + ch + "'");
+ }