diff --git a/javascript/extractor/src/com/semmle/js/ast/SourceLocation.java b/javascript/extractor/src/com/semmle/js/ast/SourceLocation.java
index 2ef727051f5..3a8475c3a5e 100644
--- a/javascript/extractor/src/com/semmle/js/ast/SourceLocation.java
+++ b/javascript/extractor/src/com/semmle/js/ast/SourceLocation.java
@@ -21,6 +21,10 @@ public class SourceLocation {
this(source, start, null);
}
+ public SourceLocation(SourceLocation that) {
+ this(that.source, that.start, that.end);
+ }
+
/**
* The source code contained in this location.
*/
diff --git a/javascript/extractor/src/com/semmle/js/ast/regexp/Error.java b/javascript/extractor/src/com/semmle/js/ast/regexp/Error.java
index b5f56e3d4f6..66977309781 100644
--- a/javascript/extractor/src/com/semmle/js/ast/regexp/Error.java
+++ b/javascript/extractor/src/com/semmle/js/ast/regexp/Error.java
@@ -7,6 +7,20 @@ import com.semmle.js.ast.SourceLocation;
* An error encountered while parsing a regular expression.
*/
public class Error extends SourceElement {
+ public static final int UNEXPECTED_EOS = 0;
+ public static final int UNEXPECTED_CHARACTER = 1;
+ public static final int EXPECTED_DIGIT = 2;
+ public static final int EXPECTED_HEX_DIGIT = 3;
+ public static final int EXPECTED_CONTROL_LETTER = 4;
+ public static final int EXPECTED_CLOSING_PAREN = 5;
+ public static final int EXPECTED_CLOSING_BRACE = 6;
+ public static final int EXPECTED_EOS = 7;
+ public static final int OCTAL_ESCAPE = 8;
+ public static final int INVALID_BACKREF = 9;
+ public static final int EXPECTED_RBRACKET = 10;
+ public static final int EXPECTED_IDENTIFIER = 11;
+ public static final int EXPECTED_CLOSING_ANGLE = 12;
+
private final int code;
public Error(SourceLocation loc, Number code) {
diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java
index 9116a71dc0a..bca6014f66c 100644
--- a/javascript/extractor/src/com/semmle/js/extractor/Main.java
+++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java
@@ -39,7 +39,7 @@ public class Main {
* such a way that it may produce different tuples for the same file under the same
* {@link ExtractorConfig}.
*/
- public static final String EXTRACTOR_VERSION = "2018-10-16";
+ public static final String EXTRACTOR_VERSION = "2018-11-12";
public static final Pattern NEWLINE = Pattern.compile("\n");
diff --git a/javascript/extractor/src/com/semmle/js/parser/JSDocParser.java b/javascript/extractor/src/com/semmle/js/parser/JSDocParser.java
index a4fcd786758..da5c351d23c 100644
--- a/javascript/extractor/src/com/semmle/js/parser/JSDocParser.java
+++ b/javascript/extractor/src/com/semmle/js/parser/JSDocParser.java
@@ -3,12 +3,10 @@ package com.semmle.js.parser;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
-
-import org.mozilla.javascript.NativeArray;
-import org.mozilla.javascript.NativeObject;
-import org.mozilla.javascript.Undefined;
+import java.util.Set;
import com.semmle.js.ast.Comment;
import com.semmle.js.ast.Position;
@@ -33,71 +31,38 @@ import com.semmle.js.ast.jsdoc.TypeApplication;
import com.semmle.js.ast.jsdoc.UndefinedLiteral;
import com.semmle.js.ast.jsdoc.UnionType;
import com.semmle.js.ast.jsdoc.VoidLiteral;
+import com.semmle.util.data.Pair;
import com.semmle.util.exception.Exceptions;
/**
- * A wrapper for invoking doctrine through Rhino.
+ * A Java port of doctrine.
*/
-public class JSDocParser extends ScriptLoader {
- public JSDocParser() {
- super("/doctrine.js");
- }
+public class JSDocParser {
+ private String source;
/**
* Parse the given string as a JSDoc comment.
*/
public JSDocComment parse(Comment comment) {
- NativeObject doctrine = (NativeObject)readGlobal("doctrine");
- NativeObject opts = mkObject("unwrap", true, "recoverable", true,
- "sloppy", true, "lineNumbers", true);
- NativeObject res = (NativeObject)callMethod(doctrine, "parse", comment.getText().substring(1), opts);
- return decodeJSDocComment(res, comment);
- }
+ source = comment.getText().substring(1);
+ JSDocTagParser p = new JSDocTagParser();
+ Pair> r = p.new TagParser(null).parse(source);
+ List tags = new ArrayList<>();
+ for (JSDocTagParser.Tag tag : r.snd()) {
+ String title = tag.title;
+ String description = tag.description;
+ String name = tag.name;
+ int startLine = tag.startLine;
+ int startColumn = tag.startColumn;
- private JSDocComment decodeJSDocComment(NativeObject obj, Comment comment) {
- String description = (String)readProperty(obj, "description");
- NativeArray tags = (NativeArray)readProperty(obj, "tags");
- return new JSDocComment(comment, description, decodeJSDocTags(tags, comment));
- }
-
- private List decodeJSDocTags(NativeArray tags, Comment comment) {
- String src = comment.getText().substring(1);
- List result = new ArrayList(tags.size());
- for (Object tag : tags) {
- String title = readStringProperty(tag, "title");
- String description = readStringProperty(tag, "description");
- String name = readStringProperty(tag, "name");
- int startLine = readIntProperty(tag, "startLine");
- int startColumn = readIntProperty(tag, "startColumn");
-
- Object type = readProperty(tag, "type");
- JSDocTypeExpression jsdocType;
- if (type == null || type == Undefined.instance) {
- jsdocType = null;
- } else {
- JSObjectDecoder typeDecoder = new JSObjectDecoder(src, this, "com.semmle.js.ast.jsdoc", spec);
- try {
- jsdocType = typeDecoder.decodeObject((NativeObject)type);
- } catch (ParseError e) {
- Exceptions.ignore(e, "Exceptions in JSDoc should always be ignored.");
- jsdocType = null;
- }
- }
-
- NativeArray err = (NativeArray)readProperty(tag, "errors");
- List errors = new ArrayList();
- if (err != null) {
- for (Object msg : err) {
- errors.add(String.valueOf(msg));
- }
- }
+ JSDocTypeExpression jsdocType = tag.type;
int realStartLine = comment.getLoc().getStart().getLine() + startLine;
int realStartColumn = (startLine == 0 ? comment.getLoc().getStart().getColumn() + 3 : 0) + startColumn;
- SourceLocation loc = new SourceLocation(src, new Position(realStartLine, realStartColumn, -1), new Position(realStartLine, realStartColumn + 1 + title.length(), -1));
- result.add(new JSDocTag(loc, title, description, name, jsdocType, errors));
+ SourceLocation loc = new SourceLocation(source, new Position(realStartLine, realStartColumn, -1), new Position(realStartLine, realStartColumn + 1 + title.length(), -1));
+ tags.add(new JSDocTag(loc, title, description, name, jsdocType, tag.errors));
}
- return result;
+ return new JSDocComment(comment, r.fst(), tags);
}
/**
@@ -123,4 +88,1705 @@ public class JSDocParser extends ScriptLoader {
spec.put(UnionType.class, Arrays.asList("elements"));
spec.put(VoidLiteral.class, Arrays.asList());
}
+
+ private static String sliceSource(String source, int index, int last) {
+ if (index >= source.length())
+ return "";
+ if (last > source.length())
+ last = source.length();
+ return source.substring(index, last);
+ }
+
+ private static boolean isLineTerminator(int ch) {
+ return ch == '\n' || ch == '\r' || ch == '\u2028' || ch == '\u2029';
+ }
+
+ private static boolean isWhiteSpace(char ch) {
+ return Character.isWhitespace(ch) && !isLineTerminator(ch) ||
+ ch == '\u00a0';
+ }
+
+ private static boolean isDecimalDigit(char ch) {
+ return "0123456789".indexOf(ch) >= 0;
+ }
+
+ private static boolean isHexDigit(char ch) {
+ return "0123456789abcdefABCDEF".indexOf(ch) >= 0;
+ }
+
+ private static boolean isOctalDigit(char ch) {
+ return "01234567".indexOf(ch) >= 0;
+ }
+
+ private static boolean isASCIIAlphanumeric(char ch) {
+ return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9');
+ }
+
+ private static boolean isIdentifierStart(char ch) {
+ return (ch == '\\') || Character.isJavaIdentifierStart(ch);
+ }
+
+ private static boolean isIdentifierPart(char ch) {
+ return (ch == '\\') || Character.isJavaIdentifierPart(ch);
+ }
+
+ private static boolean isTypeName(char ch) {
+ return "><(){}[],:*|?!=".indexOf(ch) == -1 && !isWhiteSpace(ch) && !isLineTerminator(ch);
+ }
+
+ private static boolean isParamTitle(String title) {
+ return title.equals("param") || title.equals("argument") || title.equals("arg");
+ }
+
+ private static boolean isProperty(String title) {
+ return title.equals("property") || title.equals("prop");
+ }
+
+ private static boolean isNameParameterRequired(String title) {
+ return isParamTitle(title) || isProperty(title) ||
+ title.equals("alias") || title.equals("this") || title.equals("mixes") || title.equals("requires");
+ }
+
+ private static boolean isAllowedName(String title) {
+ return isNameParameterRequired(title) || title.equals("const") || title.equals("constant");
+ }
+
+ private static boolean isAllowedNested(String title) {
+ return isProperty(title) || isParamTitle(title);
+ }
+
+ private static boolean isTypeParameterRequired(String title) {
+ return isParamTitle(title) || title.equals("define") || title.equals("enum") ||
+ title.equals("implements") || title.equals("return") ||
+ title.equals("this") || title.equals("type") || title.equals("typedef") ||
+ title.equals("returns") || isProperty(title);
+ }
+
+ // Consider deprecation instead using 'isTypeParameterRequired' and 'Rules' declaration to pick when a type is optional/required
+ // This would require changes to 'parseType'
+ private static boolean isAllowedType(String title) {
+ return isTypeParameterRequired(title) || title.equals("throws") || title.equals("const") || title.equals("constant") ||
+ title.equals("namespace") || title.equals("member") || title.equals("var") || title.equals("module") ||
+ title.equals("constructor") || title.equals("class") || title.equals("extends") || title.equals("augments") ||
+ title.equals("public") || title.equals("private") || title.equals("protected");
+ }
+
+ private static T throwError(String message) throws ParseError {
+ throw new ParseError(message, null);
+ }
+
+ private static class TypeExpressionParser {
+ private enum Token {
+ ILLEGAL, // ILLEGAL
+ DOT, // .
+ DOT_LT, // .<
+ REST, // ...
+ LT, // <
+ GT, // >
+ LPAREN, // (
+ RPAREN, // )
+ LBRACE, // {
+ RBRACE, // }
+ LBRACK, // [
+ RBRACK, // ]
+ COMMA, // ,
+ COLON, // :
+ STAR, // *
+ PIPE, // |
+ QUESTION, // ?
+ BANG, // !
+ EQUAL, // =
+ NAME, // name token
+ STRING, // string
+ NUMBER, // number
+ EOF
+ };
+
+ String source;
+ int length;
+ int previous, index;
+ Token token;
+ Object value;
+
+ private class Context {
+ int _previous, _index;
+ Token _token;
+ Object _value;
+
+ Context(int previous, int index, Token token, Object value) {
+ this._previous = previous;
+ this._index = index;
+ this._token = token;
+ this._value = value;
+ }
+
+ void restore() {
+ previous = this._previous;
+ index = this._index;
+ token = this._token;
+ value = this._value;
+ }
+ }
+
+ Context save() {
+ return new Context(previous, index, token, value);
+ }
+
+ private SourceLocation loc() {
+ return new SourceLocation(pos());
+ }
+
+ private Position pos() {
+ return new Position(1, index+1, index);
+ }
+
+ private T finishNode(T node) {
+ SourceLocation loc = node.getLoc();
+ Position end = pos();
+ loc.setSource(inputSubstring(loc.getStart().getOffset(), end.getOffset()));
+ loc.setEnd(end);
+ return node;
+ }
+
+ private String inputSubstring(int start, int end) {
+ if (start >= source.length())
+ return "";
+ if (end > source.length())
+ end = source.length();
+ return source.substring(start, end);
+ }
+
+ private int advance() {
+ if (index >= source.length())
+ return -1;
+ return source.charAt(index++);
+ }
+
+ private String scanHexEscape(char prefix) {
+ int i, len, ch, code = 0;
+
+ len = (prefix == 'u') ? 4 : 2;
+ for (i = 0; i < len; ++i) {
+ if (index < length && isHexDigit(source.charAt(index))) {
+ ch = advance();
+ code = code * 16 + "0123456789abcdef".indexOf(Character.toLowerCase(ch));
+ } else {
+ return "";
+ }
+ }
+ return new String(Character.toChars(code));
+ }
+
+ private Token scanString() throws ParseError {
+ StringBuilder str = new StringBuilder();
+ int quote, ch, code, restore; //TODO review removal octal = false
+ String unescaped;
+ quote = source.charAt(index);
+ ++index;
+
+ while (index < length) {
+ ch = advance();
+
+ if (ch == quote) {
+ quote = -1;
+ break;
+ } else if (ch == '\\') {
+ ch = advance();
+ if (!isLineTerminator(ch)) {
+ switch (ch) {
+ case 'n':
+ str.append('\n');
+ break;
+ case 'r':
+ str.append('\r');
+ break;
+ case 't':
+ str.append('\t');
+ break;
+ case 'u':
+ case 'x':
+ restore = index;
+ unescaped = scanHexEscape((char) ch);
+ if (!unescaped.isEmpty()) {
+ str.append(unescaped);
+ } else {
+ index = restore;
+ str.append((char) ch);
+ }
+ break;
+ case 'b':
+ str.append('\b');
+ break;
+ case 'f':
+ str.append('\f');
+ break;
+ case 'v':
+ str.append('\u000b');
+ break;
+
+ default:
+ if (isOctalDigit((char) ch)) {
+ code = "01234567".indexOf(ch);
+
+ // \0 is not octal escape sequence
+ // Deprecating unused code. TODO review removal
+ //if (code != 0) {
+ // octal = true;
+ //}
+
+ if (index < length && isOctalDigit(source.charAt(index))) {
+ //TODO Review Removal octal = true;
+ code = code * 8 + "01234567".indexOf(advance());
+
+ // 3 digits are only allowed when string starts
+ // with 0, 1, 2, 3
+ if ("0123".indexOf(ch) >= 0 &&
+ index < length &&
+ isOctalDigit(source.charAt(index))) {
+ code = code * 8 + "01234567".indexOf(advance());
+ }
+ }
+ str.append(Character.toChars(code));
+ } else {
+ str.append((char) ch);
+ }
+ break;
+ }
+ } else {
+ if (ch == '\r' && index < length && source.charAt(index) == '\n') {
+ ++index;
+ }
+ }
+ } else if (isLineTerminator(ch)) {
+ break;
+ } else {
+ str.append((char) ch);
+ }
+ }
+
+ if (quote != -1) {
+ throwError("unexpected quote");
+ }
+
+ value = str.toString();
+ return Token.STRING;
+ }
+
+ private Token scanNumber() throws ParseError {
+ StringBuilder number = new StringBuilder();
+ boolean isFloat = false;
+ char ch = '\0';
+
+ if (ch != '.') {
+ int next = advance();
+ number.append((char)next);
+ ch = index < length ? source.charAt(index) : '\0';
+
+ if (next == '0') {
+ if (ch == 'x' || ch == 'X') {
+ number.append((char)advance());
+ while (index < length) {
+ ch = source.charAt(index);
+ if (!isHexDigit(ch)) {
+ break;
+ }
+ number.append((char)advance());
+ }
+
+ if (number.length() <= 2) {
+ // only 0x
+ throwError("unexpected token");
+ }
+
+ if (index < length) {
+ ch = source.charAt(index);
+ if (isIdentifierStart(ch)) {
+ throwError("unexpected token");
+ }
+ }
+ try {
+ value = Integer.parseInt(number.toString(), 16);
+ } catch (NumberFormatException nfe) {
+ Exceptions.ignore(nfe, "Precise exception content is unimportant");
+ throwError("Invalid hexadecimal constant " + number);
+ }
+ return Token.NUMBER;
+ }
+
+ if (isOctalDigit(ch)) {
+ number.append((char)advance());
+ while (index < length) {
+ ch = source.charAt(index);
+ if (!isOctalDigit(ch)) {
+ break;
+ }
+ number.append((char)advance());
+ }
+
+ if (index < length) {
+ ch = source.charAt(index);
+ if (isIdentifierStart(ch) || isDecimalDigit(ch)) {
+ throwError("unexpected token");
+ }
+ }
+ try {
+ value = Integer.parseInt(number.toString(), 8);
+ } catch (NumberFormatException nfe) {
+ Exceptions.ignore(nfe, "Precise exception content is unimportant");
+ throwError("Invalid octal constant " + number);
+ }
+ return Token.NUMBER;
+ }
+
+ if (isDecimalDigit(ch)) {
+ throwError("unexpected token");
+ }
+ }
+
+ while (index < length) {
+ ch = source.charAt(index);
+ if (!isDecimalDigit(ch)) {
+ break;
+ }
+ number.append((char)advance());
+ }
+ }
+
+ if (ch == '.') {
+ isFloat = true;
+ number.append((char)advance());
+ while (index < length) {
+ ch = source.charAt(index);
+ if (!isDecimalDigit(ch)) {
+ break;
+ }
+ number.append((char)advance());
+ }
+ }
+
+ if (ch == 'e' || ch == 'E') {
+ isFloat = true;
+ number.append((char)advance());
+
+ ch = index < length ? source.charAt(index) : '\0';
+ if (ch == '+' || ch == '-') {
+ number.append((char)advance());
+ }
+
+ ch = index < length ? source.charAt(index) : '\0';
+ if (isDecimalDigit(ch)) {
+ number.append((char)advance());
+ while (index < length) {
+ ch = source.charAt(index);
+ if (!isDecimalDigit(ch)) {
+ break;
+ }
+ number.append((char)advance());
+ }
+ } else {
+ throwError("unexpected token");
+ }
+ }
+
+ if (index < length) {
+ ch = source.charAt(index);
+ if (isIdentifierStart(ch)) {
+ throwError("unexpected token");
+ }
+ }
+
+ String num = number.toString();
+ try {
+ if (isFloat)
+ value = Double.parseDouble(num);
+ else
+ value = Integer.parseInt(num);
+ } catch (NumberFormatException nfe) {
+ Exceptions.ignore(nfe, "Precise exception content is unimportant");
+ throwError("Invalid numeric literal " + num);
+ }
+ return Token.NUMBER;
+ }
+
+ private Token scanTypeName() {
+ char ch, ch2;
+
+ value = new String(Character.toChars(advance()));
+ while (index < length && isTypeName(source.charAt(index))) {
+ ch = source.charAt(index);
+ if (ch == '.') {
+ if ((index + 1) < length) {
+ ch2 = source.charAt(index + 1);
+ if (ch2 == '<') {
+ break;
+ }
+ }
+ }
+ value += new String(Character.toChars(advance()));
+ }
+ return Token.NAME;
+ }
+
+ private Token next() throws ParseError {
+ char ch;
+
+ previous = index;
+
+ while (index < length && isWhiteSpace(source.charAt(index))) {
+ advance();
+ }
+ if (index >= length) {
+ token = Token.EOF;
+ return token;
+ }
+
+ ch = source.charAt(index);
+ switch (ch) {
+ case '"':
+ token = scanString();
+ return token;
+
+ case ':':
+ advance();
+ token = Token.COLON;
+ return token;
+
+ case ',':
+ advance();
+ token = Token.COMMA;
+ return token;
+
+ case '(':
+ advance();
+ token = Token.LPAREN;
+ return token;
+
+ case ')':
+ advance();
+ token = Token.RPAREN;
+ return token;
+
+ case '[':
+ advance();
+ token = Token.LBRACK;
+ return token;
+
+ case ']':
+ advance();
+ token = Token.RBRACK;
+ return token;
+
+ case '{':
+ advance();
+ token = Token.LBRACE;
+ return token;
+
+ case '}':
+ advance();
+ token = Token.RBRACE;
+ return token;
+
+ case '.':
+ advance();
+ if (index < length) {
+ ch = source.charAt(index);
+ if (ch == '<') {
+ advance();
+ token = Token.DOT_LT;
+ return token;
+ }
+
+ if (ch == '.' && index + 1 < length && source.charAt(index + 1) == '.') {
+ advance();
+ advance();
+ token = Token.REST;
+ return token;
+ }
+
+ if (isDecimalDigit(ch)) {
+ token = scanNumber();
+ return token;
+ }
+ }
+ token = Token.DOT;
+ return token;
+
+ case '<':
+ advance();
+ token = Token.LT;
+ return token;
+
+ case '>':
+ advance();
+ token = Token.GT;
+ return token;
+
+ case '*':
+ advance();
+ token = Token.STAR;
+ return token;
+
+ case '|':
+ advance();
+ token = Token.PIPE;
+ return token;
+
+ case '?':
+ advance();
+ token = Token.QUESTION;
+ return token;
+
+ case '!':
+ advance();
+ token = Token.BANG;
+ return token;
+
+ case '=':
+ advance();
+ token = Token.EQUAL;
+ return token;
+
+ default:
+ if (isDecimalDigit(ch)) {
+ token = scanNumber();
+ return token;
+ }
+
+ // type string permits following case,
+ //
+ // namespace.module.MyClass
+ //
+ // this reduced 1 token TK_NAME
+ if (isTypeName(ch)) {
+ token = scanTypeName();
+ return token;
+ }
+
+ token = Token.ILLEGAL;
+ return token;
+ }
+ }
+
+ private void consume(Token target, String text) throws ParseError {
+ if (token != target)
+ throwError(text == null ? "consumed token not matched" : text);
+ next();
+ }
+
+ private void consume(Token target) throws ParseError {
+ consume(target, null);
+ }
+
+ private void expect(Token target) throws ParseError {
+ if (token != target) {
+ throwError("unexpected token");
+ }
+ next();
+ }
+
+ // UnionType := '(' TypeUnionList ')'
+ //
+ // TypeUnionList :=
+ // <>
+ // | NonemptyTypeUnionList
+ //
+ // NonemptyTypeUnionList :=
+ // TypeExpression
+ // | TypeExpression '|' NonemptyTypeUnionList
+ private JSDocTypeExpression parseUnionType() throws ParseError {
+ SourceLocation loc = loc();
+ List elements = new ArrayList<>();
+ consume(Token.LPAREN, "UnionType should start with (");
+ if (token != Token.RPAREN) {
+ while (true) {
+ elements.add(parseTypeExpression());
+ if (token == Token.RPAREN) {
+ break;
+ }
+ expect(Token.PIPE);
+ }
+ }
+ consume(Token.RPAREN, "UnionType should end with )");
+ return finishNode(new UnionType(loc, elements));
+ }
+
+ // ArrayType := '[' ElementTypeList ']'
+ //
+ // ElementTypeList :=
+ // <>
+ // | TypeExpression
+ // | '...' TypeExpression
+ // | TypeExpression ',' ElementTypeList
+ private JSDocTypeExpression parseArrayType() throws ParseError {
+ SourceLocation loc = loc();
+ List elements = new ArrayList<>();
+ consume(Token.LBRACK, "ArrayType should start with [");
+ while (token != Token.RBRACK) {
+ loc = loc();
+ if (token == Token.REST) {
+ consume(Token.REST);
+ elements.add(finishNode(new RestType(loc, parseTypeExpression())));
+ break;
+ } else {
+ elements.add(parseTypeExpression());
+ }
+ if (token != Token.RBRACK) {
+ expect(Token.COMMA);
+ }
+ }
+ expect(Token.RBRACK);
+ return finishNode(new ArrayType(loc, elements));
+ }
+
+ private String parseFieldName() throws ParseError {
+ Object v = value;
+ if (token == Token.NAME || token == Token.STRING) {
+ next();
+ return v.toString();
+ }
+
+ if (token == Token.NUMBER) {
+ consume(Token.NUMBER);
+ return v.toString();
+ }
+
+ return throwError("unexpected token");
+ }
+
+ // FieldType :=
+ // FieldName
+ // | FieldName ':' TypeExpression
+ //
+ // FieldName :=
+ // NameExpression
+ // | StringLiteral
+ // | NumberLiteral
+ // | ReservedIdentifier
+ private FieldType parseFieldType() throws ParseError {
+ String key;
+ SourceLocation loc = loc();
+ key = parseFieldName();
+ if (token == Token.COLON) {
+ consume(Token.COLON);
+ return finishNode(new FieldType(loc, key, parseTypeExpression()));
+ }
+ return finishNode(new FieldType(loc, key, null));
+ }
+
+ // RecordType := '{' FieldTypeList '}'
+ //
+ // FieldTypeList :=
+ // <>
+ // | FieldType
+ // | FieldType ',' FieldTypeList
+ private JSDocTypeExpression parseRecordType() throws ParseError {
+ List fields = new ArrayList<>();
+ SourceLocation loc = loc();
+ consume(Token.LBRACE, "RecordType should start with {");
+ if (token == Token.COMMA) {
+ consume(Token.COMMA);
+ } else {
+ while (token != Token.RBRACE) {
+ fields.add(parseFieldType());
+ if (token != Token.RBRACE) {
+ expect(Token.COMMA);
+ }
+ }
+ }
+ expect(Token.RBRACE);
+ return finishNode(new RecordType(loc, fields));
+ }
+
+ private JSDocTypeExpression parseNameExpression() throws ParseError {
+ Object name = value;
+ SourceLocation loc = loc();
+ expect(Token.NAME);
+ return finishNode(new NameExpression(loc, name.toString()));
+ }
+
+ // TypeExpressionList :=
+ // TopLevelTypeExpression
+ // | TopLevelTypeExpression ',' TypeExpressionList
+ private List parseTypeExpressionList() throws ParseError {
+ List elements = new ArrayList<>();
+
+ elements.add(parseTop());
+ while (token == Token.COMMA) {
+ consume(Token.COMMA);
+ elements.add(parseTop());
+ }
+ return elements;
+ }
+
+ // TypeName :=
+ // NameExpression
+ // | NameExpression TypeApplication
+ //
+ // TypeApplication :=
+ // '.<' TypeExpressionList '>'
+ // | '<' TypeExpressionList '>' // this is extension of doctrine
+ private JSDocTypeExpression parseTypeName() throws ParseError {
+ JSDocTypeExpression expr;
+ List applications;
+ SourceLocation loc = loc();
+ expr = parseNameExpression();
+ if (token == Token.DOT_LT || token == Token.LT) {
+ next();
+ applications = parseTypeExpressionList();
+ expect(Token.GT);
+ return finishNode(new TypeApplication(loc, expr, applications));
+ }
+ return expr;
+ }
+
+ // ResultType :=
+ // <>
+ // | ':' void
+ // | ':' TypeExpression
+ //
+ // BNF is above
+ // but, we remove <> pattern, so token is always TypeToken::COLON
+ private JSDocTypeExpression parseResultType() throws ParseError {
+ consume(Token.COLON, "ResultType should start with :");
+ SourceLocation loc = loc();
+ if (token == Token.NAME && value.equals("void")) {
+ consume(Token.NAME);
+ return finishNode(new VoidLiteral(loc));
+ }
+ return parseTypeExpression();
+ }
+
+ // ParametersType :=
+ // RestParameterType
+ // | NonRestParametersType
+ // | NonRestParametersType ',' RestParameterType
+ //
+ // RestParameterType :=
+ // '...'
+ // '...' Identifier
+ //
+ // NonRestParametersType :=
+ // ParameterType ',' NonRestParametersType
+ // | ParameterType
+ // | OptionalParametersType
+ //
+ // OptionalParametersType :=
+ // OptionalParameterType
+ // | OptionalParameterType, OptionalParametersType
+ //
+ // OptionalParameterType := ParameterType=
+ //
+ // ParameterType := TypeExpression | Identifier ':' TypeExpression
+ //
+ // Identifier is "new" or "this"
+ private List parseParametersType() throws ParseError {
+ List params = new ArrayList<>();
+ boolean normal = true;
+ JSDocTypeExpression expr;
+ boolean rest = false;
+
+ while (token != Token.RPAREN) {
+ if (token == Token.REST) {
+ // RestParameterType
+ consume(Token.REST);
+ rest = true;
+ }
+
+ SourceLocation loc = loc();
+ expr = parseTypeExpression();
+ if (expr instanceof NameExpression && token == Token.COLON) {
+ // Identifier ':' TypeExpression
+ consume(Token.COLON);
+ expr = finishNode(new ParameterType(loc, ((NameExpression) expr).getName(), parseTypeExpression()));
+ }
+ if (token == Token.EQUAL) {
+ consume(Token.EQUAL);
+ expr = finishNode(new OptionalType(loc, expr));
+ normal = false;
+ } else {
+ if (!normal) {
+ throwError("unexpected token");
+ }
+ }
+ if (rest) {
+ expr = finishNode(new RestType(new SourceLocation(loc), expr));
+ }
+ params.add(expr);
+ if (token != Token.RPAREN) {
+ expect(Token.COMMA);
+ }
+ }
+ return params;
+ }
+
+ // FunctionType := 'function' FunctionSignatureType
+ //
+ // FunctionSignatureType :=
+ // | TypeParameters '(' ')' ResultType
+ // | TypeParameters '(' ParametersType ')' ResultType
+ // | TypeParameters '(' 'this' ':' TypeName ')' ResultType
+ // | TypeParameters '(' 'this' ':' TypeName ',' ParametersType ')' ResultType
+ private JSDocTypeExpression parseFunctionType() throws ParseError {
+ SourceLocation loc = loc();
+ boolean isNew;
+ JSDocTypeExpression thisBinding;
+ List params;
+ JSDocTypeExpression result;
+ consume(Token.NAME);
+
+ // Google Closure Compiler is not implementing TypeParameters.
+ // So we do not. if we don't get '(', we see it as error.
+ expect(Token.LPAREN);
+
+ isNew = false;
+ params = new ArrayList();
+ thisBinding = null;
+ if (token != Token.RPAREN) {
+ // ParametersType or 'this'
+ if (token == Token.NAME &&
+ (value.equals("this") || value.equals("new"))) {
+ // 'this' or 'new'
+ // 'new' is Closure Compiler extension
+ isNew = value.equals("new");
+ consume(Token.NAME);
+ expect(Token.COLON);
+ thisBinding = parseTypeName();
+ if (token == Token.COMMA) {
+ consume(Token.COMMA);
+ params = parseParametersType();
+ }
+ } else {
+ params = parseParametersType();
+ }
+ }
+
+ expect(Token.RPAREN);
+
+ result = null;
+ if (token == Token.COLON) {
+ result = parseResultType();
+ }
+
+ return finishNode(new FunctionType(loc, thisBinding, isNew, params, result));
+ }
+
+ // BasicTypeExpression :=
+ // '*'
+ // | 'null'
+ // | 'undefined'
+ // | TypeName
+ // | FunctionType
+ // | UnionType
+ // | RecordType
+ // | ArrayType
+ private JSDocTypeExpression parseBasicTypeExpression() throws ParseError {
+ Context context;
+ SourceLocation loc;
+ switch (token) {
+ case STAR:
+ loc = loc();
+ consume(Token.STAR);
+ return new AllLiteral(loc);
+
+ case LPAREN:
+ return parseUnionType();
+
+ case LBRACK:
+ return parseArrayType();
+
+ case LBRACE:
+ return parseRecordType();
+
+ case NAME:
+ if (value.equals("null")) {
+ loc = loc();
+ consume(Token.NAME);
+ return new NullLiteral(loc);
+ }
+
+ if (value.equals("undefined")) {
+ loc = loc();
+ consume(Token.NAME);
+ return new UndefinedLiteral(loc);
+ }
+
+ context = save();
+ if (value.equals("function")) {
+ try {
+ return parseFunctionType();
+ } catch (ParseError e) {
+ context.restore();
+ }
+ }
+
+ return parseTypeName();
+
+ default:
+ return throwError("unexpected token");
+ }
+ }
+
+ // TypeExpression :=
+ // BasicTypeExpression
+ // | '?' BasicTypeExpression
+ // | '!' BasicTypeExpression
+ // | BasicTypeExpression '?'
+ // | BasicTypeExpression '!'
+ // | '?'
+ // | BasicTypeExpression '[]'
+ private JSDocTypeExpression parseTypeExpression() throws ParseError {
+ JSDocTypeExpression expr;
+ SourceLocation loc = loc();
+
+ if (token == Token.QUESTION) {
+ consume(Token.QUESTION);
+ if (token == Token.COMMA || token == Token.EQUAL || token == Token.RBRACE ||
+ token == Token.RPAREN || token == Token.PIPE || token == Token.EOF ||
+ token == Token.RBRACK) {
+ return finishNode(new NullableLiteral(loc));
+ }
+ return finishNode(new NullableType(loc, parseBasicTypeExpression(), true));
+ }
+
+ if (token == Token.BANG) {
+ consume(Token.BANG);
+ return finishNode(new NonNullableType(loc, parseBasicTypeExpression(), true));
+ }
+
+ expr = parseBasicTypeExpression();
+ if (token == Token.BANG) {
+ consume(Token.BANG);
+ return finishNode(new NonNullableType(loc, expr, false));
+ }
+
+ if (token == Token.QUESTION) {
+ consume(Token.QUESTION);
+ return finishNode(new NullableType(loc, expr, false));
+ }
+
+ if (token == Token.LBRACK) {
+ consume(Token.LBRACK);
+ consume(Token.RBRACK, "expected an array-style type declaration (' + value + '[])");
+ List expressions = new ArrayList<>();
+ expressions.add(expr);
+ return finishNode(new TypeApplication(loc, new NameExpression(loc, "Array"), expressions));
+ }
+
+ return expr;
+ }
+
+ // TopLevelTypeExpression :=
+ // TypeExpression
+ // | TypeUnionList
+ //
+ // This rule is Google Closure Compiler extension, not ES4
+ // like,
+ // { number | string }
+ // If strict to ES4, we should write it as
+ // { (number|string) }
+ private JSDocTypeExpression parseTop() throws ParseError {
+ JSDocTypeExpression expr;
+ List elements = new ArrayList();
+ SourceLocation loc = loc();
+
+ expr = parseTypeExpression();
+ if (token != Token.PIPE) {
+ return expr;
+ }
+
+ elements.add(expr);
+ consume(Token.PIPE);
+ while (true) {
+ elements.add(parseTypeExpression());
+ if (token != Token.PIPE) {
+ break;
+ }
+ consume(Token.PIPE);
+ }
+
+ return finishNode(new UnionType(loc, elements));
+ }
+
+ private JSDocTypeExpression parseTopParamType() throws ParseError {
+ JSDocTypeExpression expr;
+ SourceLocation loc = loc();
+
+ if (token == Token.REST) {
+ consume(Token.REST);
+ return finishNode(new RestType(loc, parseTop()));
+ }
+
+ expr = parseTop();
+ if (token == Token.EQUAL) {
+ consume(Token.EQUAL);
+ return finishNode(new OptionalType(loc, expr));
+ }
+
+ return expr;
+ }
+
+ private JSDocTypeExpression parseType(String src) throws ParseError {
+ JSDocTypeExpression expr;
+
+ source = src;
+ length = source.length();
+ index = 0;
+ previous = 0;
+
+ next();
+ expr = parseTop();
+
+ if (token != Token.EOF) {
+ throwError("not reach to EOF");
+ }
+
+ return expr;
+ }
+
+ private JSDocTypeExpression parseParamType(String src) throws ParseError {
+ JSDocTypeExpression expr;
+
+ source = src;
+ length = source.length();
+ index = 0;
+ previous = 0;
+
+ next();
+ expr = parseTopParamType();
+
+ if (token != Token.EOF) {
+ throwError("not reach to EOF");
+ }
+
+ return expr;
+ }
+ }
+ private static TypeExpressionParser typed = new TypeExpressionParser();
+
+ private static class JSDocTagParser {
+ int index, lineNumber, lineStart, length;
+ String source;
+ boolean recoverable = true, sloppy = false;
+
+ private int skipStars(int index) {
+ while (index < length && isWhiteSpace(source.charAt(index)) && !isLineTerminator(source.charAt(index))) {
+ index += 1;
+ }
+ while (index < length && source.charAt(index) == '*') {
+ index += 1;
+ }
+ while (index < length && isWhiteSpace(source.charAt(index)) && !isLineTerminator(source.charAt(index))) {
+ index += 1;
+ }
+ return index;
+ }
+
+ private char advance() {
+ char ch = source.charAt(index);
+ index += 1;
+ if (isLineTerminator(ch) &&
+ !(ch == '\r' && index < length && source.charAt(index) == '\n')) {
+ lineNumber += 1;
+ lineStart = index;
+ index = skipStars(index);
+ }
+ return ch;
+ }
+
+ private String scanTitle() {
+ StringBuilder title = new StringBuilder();
+ // waste '@'
+ advance();
+
+ while (index < length && isASCIIAlphanumeric(source.charAt(index))) {
+ title.append(advance());
+ }
+
+ return title.toString();
+ }
+
+ private int seekContent() {
+ char ch;
+ boolean waiting = false;
+ int last = index;
+
+ while (last < length) {
+ ch = source.charAt(last);
+ if (isLineTerminator(ch) &&
+ !(ch == '\r' && last + 1 < length && source.charAt(last + 1) == '\n')) {
+ lineNumber += 1;
+ lineStart = last + 1;
+ last = skipStars(last + 1) - 1;
+ waiting = true;
+ } else if (waiting) {
+ if (ch == '@') {
+ break;
+ }
+ if (!isWhiteSpace(ch)) {
+ waiting = false;
+ }
+ }
+ last += 1;
+ }
+ return last;
+ }
+
+ // type expression may have nest brace, such as,
+ // { { ok: string } }
+ //
+ // therefore, scanning type expression with balancing braces.
+ private JSDocTypeExpression parseType(String title, int last) throws ParseError {
+ char ch;
+ int brace;
+ StringBuilder type;
+ boolean direct = false;
+
+ // search '{'
+ while (index < last) {
+ ch = source.charAt(index);
+ if (isWhiteSpace(ch)) {
+ advance();
+ } else if (ch == '{') {
+ advance();
+ break;
+ } else {
+ // this is direct pattern
+ direct = true;
+ break;
+ }
+ }
+
+ if (!direct) {
+ // type expression { is found
+ brace = 1;
+ type = new StringBuilder();
+ while (index < last) {
+ ch = source.charAt(index);
+ if (isLineTerminator(ch)) {
+ advance();
+ } else {
+ if (ch == '}') {
+ brace -= 1;
+ if (brace == 0) {
+ advance();
+ break;
+ }
+ } else if (ch == '{') {
+ brace += 1;
+ }
+ type.append(advance());
+ }
+ }
+
+ if (brace != 0) {
+ // braces is not balanced
+ return throwError("Braces are not balanced");
+ }
+
+ try {
+ if (isParamTitle(title)) {
+ return typed.parseParamType(type.toString());
+ }
+ return typed.parseType(type.toString());
+ } catch (ParseError e) {
+ // parse failed
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ private String scanIdentifier(int last) {
+ StringBuilder identifier = new StringBuilder();
+ if (!(index < length && isIdentifierStart(source.charAt(index)))) {
+ return null;
+ }
+ identifier.append(advance());
+ while (index < last && isIdentifierPart(source.charAt(index))) {
+ identifier.append(advance());
+ }
+ return identifier.toString();
+ }
+
+ private void skipWhiteSpace(int last) {
+ while (index < last && (isWhiteSpace(source.charAt(index)) || isLineTerminator(source.charAt(index)))) {
+ advance();
+ }
+ }
+
+ private String parseName(int last, boolean allowBrackets, boolean allowNestedParams) {
+ StringBuilder name = new StringBuilder();
+ boolean useBrackets = false;
+
+ skipWhiteSpace(last);
+
+ if (index >= last) {
+ return null;
+ }
+
+ if (allowBrackets && source.charAt(index) == '[') {
+ useBrackets = true;
+ name.append(advance());
+ }
+
+ if (!isIdentifierStart(source.charAt(index))) {
+ return null;
+ }
+
+ name.append(scanIdentifier(last));
+
+ if (allowNestedParams) {
+ while (index < last &&
+ (source.charAt(index) == '.' || source.charAt(index) == '#' || source.charAt(index) == '~')) {
+ name.append(source.charAt(index));
+ index += 1;
+ name.append(scanIdentifier(last));
+ }
+ }
+
+ if (useBrackets) {
+ // do we have a default value for this?
+ if (index < last && source.charAt(index) == '=') {
+
+ // consume the '='' symbol
+ name.append(advance());
+ // scan in the default value
+ while (index < last && source.charAt(index) != ']') {
+ name .append(advance());
+ }
+ }
+
+ if (index >= last || source.charAt(index) != ']') {
+ // we never found a closing ']'
+ return null;
+ }
+
+ // collect the last ']'
+ name .append(advance());
+ }
+
+ return name.toString();
+ }
+
+ boolean skipToTag() {
+ while (index < length && source.charAt(index) != '@') {
+ advance();
+ }
+ if (index >= length) {
+ return false;
+ }
+ return true;
+ }
+
+ private class Tag {
+ public String description;
+ public String title;
+ List errors = new ArrayList<>();
+ JSDocTypeExpression type;
+ String name;
+ public int startLine;
+ public int startColumn;
+ }
+
+ private class TagParser {
+ String _title;
+ Tag _tag;
+ int _last;
+ String _extra_name;
+
+ TagParser(String title) {
+ this._title = title;
+ this._tag = new Tag();
+ this._tag.description = null;
+ this._tag.title = title;
+ this._last = 0;
+ // space to save special information for title parsers.
+ this._extra_name = null;
+ }
+
+ // addError(err, ...)
+ public boolean addError(String errorText, Object... args) {
+ this._tag.errors.add(String.format(errorText, args));
+ return recoverable;
+ }
+
+ public boolean parseType() {
+ // type required titles
+ if (isTypeParameterRequired(this._title)) {
+ try {
+ this._tag.type = JSDocTagParser.this.parseType(this._title, this._last);
+ if (this._tag.type == null) {
+ if (!isParamTitle(this._title)) {
+ if (!this.addError("Missing or invalid tag type")) {
+ return false;
+ }
+ }
+ }
+ } catch (ParseError error) {
+ this._tag.type = null;
+ if (!this.addError(error.getMessage())) {
+ return false;
+ }
+ }
+ } else if (isAllowedType(this._title)) {
+ // optional types
+ try {
+ this._tag.type = JSDocTagParser.this.parseType(this._title, this._last);
+ } catch (ParseError e) {
+ //For optional types, lets drop the thrown error when we hit the end of the file
+ }
+ }
+ return true;
+ }
+
+ private boolean _parseNamePath(boolean optional) {
+ String name = JSDocTagParser.this.parseName(this._last, sloppy && isParamTitle(this._title), true);
+ if (name == null) {
+ if (!optional) {
+ if (!this.addError("Missing or invalid tag name")) {
+ return false;
+ }
+ }
+ }
+ this._tag.name = name;
+ return true;
+ }
+
+ public boolean parseNamePath() {
+ return _parseNamePath(false);
+ }
+
+ public boolean parseNamePathOptional() {
+ return this._parseNamePath(true);
+ }
+
+ public boolean parseName() {
+ String[] assign;
+ String name;
+
+ // param, property requires name
+ if (isAllowedName(this._title)) {
+ this._tag.name = JSDocTagParser.this.parseName(this._last, sloppy && isParamTitle(this._title), isAllowedNested(this._title));
+ if (this._tag.name == null) {
+ if (!isNameParameterRequired(this._title)) {
+ return true;
+ }
+
+ // it's possible the name has already been parsed but interpreted as a type
+ // it's also possible this is a sloppy declaration, in which case it will be
+ // fixed at the end
+ if (isParamTitle(this._title) && this._tag.type != null && this._tag.type instanceof NameExpression) {
+ this._extra_name = ((NameExpression) this._tag.type).getName();
+ this._tag.name = ((NameExpression) this._tag.type).getName();
+ this._tag.type = null;
+ } else {
+ if (!this.addError("Missing or invalid tag name")) {
+ return false;
+ }
+ }
+ } else {
+ name = this._tag.name;
+ if (name.charAt(0) == '[' && name.charAt(name.length() - 1) == ']') {
+ // extract the default value if there is one
+ // example: @param {string} [somebody=John Doe] description
+ assign = name.substring(1, name.length() - 1).split("=");
+ this._tag.name = assign[0];
+
+ // convert to an optional type
+ if (this._tag.type != null && !(this._tag.type instanceof OptionalType)) {
+ Position start = new Position(_tag.startLine, _tag.startColumn, _tag.startColumn);
+ Position end = new Position(_tag.startLine, _tag.startColumn, _tag.startColumn);
+ SourceLocation loc = new SourceLocation(_extra_name, start, end);
+ this._tag.type = new OptionalType(loc, this._tag.type);
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private boolean parseDescription() {
+ String description = sliceSource(source, index, this._last).trim();
+ if (!description.isEmpty()) {
+ if (description.matches("(?s)^-\\s+.*")) {
+ description = description.substring(2);
+ }
+ description = description.replaceAll("(?m)^\\s*\\*+\\s*", "");
+ this._tag.description = description;
+ }
+ return true;
+ }
+
+ private final Set kinds = new LinkedHashSet<>();
+ {
+ kinds.add("class");
+ kinds.add("constant");
+ kinds.add("event");
+ kinds.add("external");
+ kinds.add("file");
+ kinds.add("function");
+ kinds.add("member");
+ kinds.add("mixin");
+ kinds.add("module");
+ kinds.add("namespace");
+ kinds.add("typedef");
+ }
+
+ private boolean parseKind() {
+ String kind = sliceSource(source, index, this._last).trim();
+ if (!kinds.contains(kind)) {
+ if (!this.addError("Invalid kind name \'%s\'", kind)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean parseAccess() {
+ String access = sliceSource(source, index, this._last).trim();
+ if (!access.equals("private") && !access.equals("protected") && !access.equals("public")) {
+ if (!this.addError("Invalid access name \'%s\'", access)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean parseVariation() {
+ double variation;
+ String text = sliceSource(source, index, this._last).trim();
+ try {
+ variation = Double.parseDouble(text);
+ } catch (NumberFormatException nfe) {
+ variation = Double.NaN;
+ }
+ if (Double.isNaN(variation)) {
+ if (!this.addError("Invalid variation \'%s\'", text)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean ensureEnd() {
+ String shouldBeEmpty = sliceSource(source, index, this._last).trim();
+ if (!shouldBeEmpty.matches("^[\\s*]*$")) {
+ if (!this.addError("Unknown content \'%s\'", shouldBeEmpty)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private boolean epilogue() {
+ String description;
+
+ description = this._tag.description;
+ // un-fix potentially sloppy declaration
+ if (isParamTitle(this._title) && this._tag.type == null && description != null
+ && description.startsWith("[")) {
+ if (_extra_name != null) {
+ Position start = new Position(_tag.startLine, _tag.startColumn, _tag.startColumn);
+ Position end = new Position(_tag.startLine, _tag.startColumn, _tag.startColumn);
+ SourceLocation loc = new SourceLocation(_extra_name, start, end);
+ this._tag.type = new NameExpression(loc, _extra_name);
+ }
+ this._tag.name = null;
+
+ if (!sloppy) {
+ if (!this.addError("Missing or invalid tag name")) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ private Tag parse() {
+ int oldLineNumber, oldLineStart, newLineNumber, newLineStart;
+
+ // empty title
+ if (this._title == null || this._title.isEmpty()) {
+ if (!this.addError("Missing or invalid title")) {
+ return null;
+ }
+ }
+
+ // Seek to content last index.
+ oldLineNumber = lineNumber;
+ oldLineStart = lineStart;
+ this._last = seekContent();
+ newLineNumber = lineNumber;
+ newLineStart = lineStart;
+ lineNumber = oldLineNumber;
+ lineStart = oldLineStart;
+
+ switch (this._title) {
+ // http://usejsdoc.org/tags-access.html
+ case "access": if (!parseAccess()) return null; break;
+ // http://usejsdoc.org/tags-alias.html
+ case "alias": if (!parseNamePath() || !ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-augments.html
+ case "augments": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-constructor.html
+ case "constructor": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break;
+ // Synonym: http://usejsdoc.org/tags-constructor.html
+ case "class": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break;
+ // Synonym: http://usejsdoc.org/tags-extends.html
+ case "extends": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-deprecated.html
+ case "deprecated": if (!parseDescription()) return null; break;
+ // http://usejsdoc.org/tags-global.html
+ case "global": if (!ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-inner.html
+ case "inner": if (!ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-instance.html
+ case "instance": if (!ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-kind.html
+ case "kind": if (!parseKind()) return null; break;
+ // http://usejsdoc.org/tags-mixes.html
+ case "mixes": if (!parseNamePath() || !ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-mixin.html
+ case "mixin": if (!parseNamePathOptional() || !ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-member.html
+ case "member": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-method.html
+ case "method": if (!parseNamePathOptional() || !ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-module.html
+ case "module": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break;
+ // Synonym: http://usejsdoc.org/tags-method.html
+ case "func": if (!parseNamePathOptional() || !ensureEnd()) return null; break;
+ // Synonym: http://usejsdoc.org/tags-method.html
+ case "function": if (!parseNamePathOptional() || !ensureEnd()) return null; break;
+ // Synonym: http://usejsdoc.org/tags-member.html
+ case "var": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-name.html
+ case "name": if (!parseNamePath() || !ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-namespace.html
+ case "namespace": if (!parseType() || !parseNamePathOptional() || !ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-private.html
+ case "private": if (!parseType() || !parseDescription()) return null; break;
+ // http://usejsdoc.org/tags-protected.html
+ case "protected": if (!parseType() || !parseDescription()) return null; break;
+ // http://usejsdoc.org/tags-public.html
+ case "public": if (!parseType() || !parseDescription()) return null; break;
+ // http://usejsdoc.org/tags-readonly.html
+ case "readonly": if (!ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-requires.html
+ case "requires": if (!parseNamePath() || !ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-since.html
+ case "since": if (!parseDescription()) return null; break;
+ // http://usejsdoc.org/tags-static.html
+ case "static": if (!ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-summary.html
+ case "summary": if (!parseDescription()) return null; break;
+ // http://usejsdoc.org/tags-this.html
+ case "this": if (!parseNamePath() || !ensureEnd()) return null; break;
+ // http://usejsdoc.org/tags-todo.html
+ case "todo": if (!parseDescription()) return null; break;
+ // http://usejsdoc.org/tags-variation.html
+ case "variation": if (!parseVariation()) return null; break;
+ // http://usejsdoc.org/tags-version.html
+ case "version": if (!parseDescription()) return null; break;
+ // default sequences
+ default: if (!parseType() || !parseName() || !parseDescription() || !epilogue()) return null; break;
+ }
+
+ // Seek global index to end of this tag.
+ index = this._last;
+ lineNumber = newLineNumber;
+ lineStart = newLineStart;
+ return this._tag;
+ }
+
+ private Tag parseTag() {
+ String title;
+ Tag res;
+ TagParser parser;
+ int startColumn;
+ int startLine;
+
+ // skip to tag
+ if (!skipToTag()) {
+ return null;
+ }
+
+ startLine = lineNumber;
+ startColumn = index - lineStart;
+
+ // scan title
+ title = scanTitle();
+
+ // construct tag parser
+ parser = new TagParser(title);
+ res = parser.parse();
+
+ if (res != null) {
+ res.startLine = startLine;
+ res.startColumn = startColumn;
+ }
+
+ return res;
+ }
+
+ //
+ // Parse JSDoc
+ //
+
+ String scanJSDocDescription() {
+ StringBuilder description = new StringBuilder();
+ char ch;
+ boolean atAllowed;
+
+ atAllowed = true;
+ while (index < length) {
+ ch = source.charAt(index);
+
+ if (atAllowed && ch == '@') {
+ break;
+ }
+
+ if (isLineTerminator(ch)) {
+ atAllowed = true;
+ } else if (atAllowed && !isWhiteSpace(ch)) {
+ atAllowed = false;
+ }
+
+ description.append(advance());
+ }
+ return description.toString().trim();
+ }
+
+
+ public Pair> parse(String comment) {
+ List tags = new ArrayList<>();
+ Tag tag;
+ String description;
+
+ source = comment.replaceAll("^/?\\*+", "").replaceAll("\\*+/?\\z", "");
+
+ length = source.length();
+ index = 0;
+ lineNumber = 0;
+ lineStart = 0;
+ recoverable = true;
+ sloppy = true;
+
+ description = scanJSDocDescription();
+
+ while (true) {
+ tag = parseTag();
+ if (tag == null) {
+ break;
+ }
+ tags.add(tag);
+ }
+
+ return Pair.make(description, tags);
+ }
+ }
+ }
}
diff --git a/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java b/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java
index 2099edcbd91..bfa4919cde6 100644
--- a/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java
+++ b/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java
@@ -1,17 +1,9 @@
package com.semmle.js.parser;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map;
-
-import org.mozilla.javascript.Function;
-import org.mozilla.javascript.NativeArray;
-import org.mozilla.javascript.NativeObject;
-import org.mozilla.javascript.ScriptableObject;
+import com.semmle.js.ast.Position;
import com.semmle.js.ast.SourceLocation;
import com.semmle.js.ast.regexp.BackReference;
import com.semmle.js.ast.regexp.Caret;
@@ -47,54 +39,9 @@ import com.semmle.js.ast.regexp.ZeroWidthPositiveLookahead;
import com.semmle.js.ast.regexp.ZeroWidthPositiveLookbehind;
/**
- * Wrapper for invoking esregex through Rhino.
+ * A parser for ECMAScript 2018 regular expressions.
*/
-public class RegExpParser extends ScriptLoader {
- /**
- * Specification for esregex AST types.
- */
- private static final Map, List> spec = new LinkedHashMap, List>();
- static {
- spec.put(BackReference.class, Arrays.asList("value", "raw"));
- spec.put(Caret.class, Collections.emptyList());
- spec.put(CharacterClass.class, Arrays.asList("elements", "inverted"));
- spec.put(CharacterClassEscape.class, Arrays.asList("class", "raw"));
- spec.put(CharacterClassRange.class, Arrays.asList("left", "right"));
- spec.put(Constant.class, Arrays.asList("value"));
- spec.put(ControlEscape.class, Arrays.asList("value", "codepoint", "raw"));
- spec.put(ControlLetter.class, Arrays.asList("value", "codepoint", "raw"));
- spec.put(DecimalEscape.class, Arrays.asList("value", "codepoint", "raw"));
- spec.put(Disjunction.class, Arrays.asList("disjuncts"));
- spec.put(Dollar.class, Collections.emptyList());
- spec.put(Dot.class, Collections.emptyList());
- spec.put(Group.class, Arrays.asList("capture", "number", "name", "operand"));
- spec.put(HexEscapeSequence.class, Arrays.asList("value", "codepoint", "raw"));
- spec.put(IdentityEscape.class, Arrays.asList("value", "codepoint", "raw"));
- spec.put(NamedBackReference.class, Arrays.asList("name", "raw"));
- spec.put(NonWordBoundary.class, Collections.emptyList());
- spec.put(OctalEscape.class, Arrays.asList("value", "codepoint", "raw"));
- spec.put(Opt.class, Arrays.asList("operand", "greedy"));
- spec.put(Plus.class, Arrays.asList("operand", "greedy"));
- spec.put(Range.class, Arrays.asList("operand", "greedy", "lo", "hi"));
- spec.put(Sequence.class, Arrays.asList("elements"));
- spec.put(Star.class, Arrays.asList("operand", "greedy"));
- spec.put(UnicodeEscapeSequence.class, Arrays.asList("value", "codepoint", "raw"));
- spec.put(WordBoundary.class, Collections.emptyList());
- spec.put(ZeroWidthNegativeLookahead.class, Arrays.asList("operand"));
- spec.put(ZeroWidthPositiveLookahead.class, Arrays.asList("operand"));
- spec.put(ZeroWidthNegativeLookbehind.class, Arrays.asList("operand"));
- spec.put(ZeroWidthPositiveLookbehind.class, Arrays.asList("operand"));
- spec.put(UnicodePropertyEscape.class, Arrays.asList("name", "value", "raw"));
- }
-
- /**
- * Specification for esregex parse errors.
- */
- private static final Map, List> errspec = new LinkedHashMap, List>();
- static {
- errspec.put(Error.class, Arrays.asList("code"));
- }
-
+public class RegExpParser {
/**
* The result of a parse.
*/
@@ -102,12 +49,12 @@ public class RegExpParser extends ScriptLoader {
/**
* The root of the parsed AST.
*/
- private final RegExpTerm ast;
+ public final RegExpTerm ast;
/**
* A list of errors encountered during parsing.
*/
- private final List errors;
+ public final List errors;
public Result(RegExpTerm ast, List errors) {
this.ast = ast;
@@ -123,28 +70,450 @@ public class RegExpParser extends ScriptLoader {
}
}
- public RegExpParser() {
- super("/regexparser.js");
- }
+ private String src;
+ private int pos;
+ private List errors;
+ private List backrefs;
+ private int maxbackref;
/**
* Parse the given string as a regular expression.
*/
public Result parse(String src) {
- Function ctor = (Function)readGlobal("RegExpParser");
- ScriptableObject parser = construct(ctor, src);
- NativeObject ast = (NativeObject)callMethod(parser, "Pattern");
- NativeArray errors = (NativeArray)readProperty(parser, "errors");
- JSObjectDecoder decoder = new JSObjectDecoder(src, this, "com.semmle.js.ast.regexp", spec);
- List errs = null;
- RegExpTerm term = null;
- try {
- term = decoder.decodeObject(ast);
- errs = new JSObjectDecoder(src, this, "com.semmle.js.ast.regexp", errspec).decodeObjects(errors);
- } catch (ParseError e) {
- errs = new ArrayList();
- errs.add(new Error(new SourceLocation("", e.getPosition(), e.getPosition()), 1));
+ this.src = src;
+ this.pos = 0;
+ this.errors = new ArrayList<>();
+ this.backrefs = new ArrayList<>();
+ this.maxbackref = 0;
+ RegExpTerm root = parsePattern();
+ for (BackReference backref : backrefs)
+ if (backref.getValue() > maxbackref)
+ errors.add(new Error(backref.getLoc(), Error.INVALID_BACKREF));
+ return new Result(root, errors);
+ }
+
+ private static String fromCodePoint(int codepoint) {
+ if (Character.isValidCodePoint(codepoint))
+ return new String(Character.toChars(codepoint));
+ // replacement character
+ return "\ufffd";
+ }
+
+ private Position pos() {
+ return new Position(1, pos, pos);
+ }
+
+ private void error(int code, int start, int end) {
+ Position startPos, endPos;
+ startPos = new Position(1, start, start);
+ endPos = new Position(1, end, end);
+ this.errors.add(new Error(new SourceLocation(inputSubstring(start, end), startPos, endPos), code));
+ }
+
+ private void error(int code, int start) {
+ error(code, start, start+1);
+ }
+
+ private void error(int code) {
+ error(code, this.pos);
+ }
+
+ private boolean atEOS() {
+ return pos >= src.length();
+ }
+
+ private char peekChar(boolean opt) {
+ if (this.atEOS()) {
+ if (!opt)
+ this.error(Error.UNEXPECTED_EOS);
+ return '\0';
+ } else {
+ return this.src.charAt(this.pos);
}
- return new Result(term, errs);
+ }
+
+ private char nextChar() {
+ char c = peekChar(false);
+ if (this.pos < src.length())
+ ++this.pos;
+ return c;
+ }
+
+ private String readHexDigit() {
+ char c = this.peekChar(false);
+ if (c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F') {
+ ++this.pos;
+ return String.valueOf(c);
+ }
+ if (c != '\0')
+ this.error(Error.EXPECTED_HEX_DIGIT, this.pos);
+ return "";
+ }
+
+ private String readHexDigits(int n) {
+ StringBuilder res = new StringBuilder();
+ while (n-->0) {
+ res.append(readHexDigit());
+ }
+ if (res.length() == 0)
+ return "0";
+ return res.toString();
+ }
+
+ private String readDigits(boolean opt) {
+ StringBuilder res = new StringBuilder();
+ for (char c=peekChar(true); c >= '0' && c <= '9'; nextChar(), c=peekChar(true))
+ res.append(c);
+ if (res.length() == 0 && !opt)
+ this.error(Error.EXPECTED_DIGIT);
+ return res.toString();
+ }
+
+ private Double toNumber(String s) {
+ if (s.isEmpty())
+ return 0.0;
+ return Double.valueOf(s);
+ }
+
+ private String readIdentifier() {
+ StringBuilder res = new StringBuilder();
+ for (char c=peekChar(true);
+ c != '\0' && Character.isJavaIdentifierPart(c);
+ nextChar(), c=peekChar(true))
+ res.append(c);
+ if (res.length() == 0)
+ this.error(Error.EXPECTED_IDENTIFIER);
+ return res.toString();
+ }
+
+ private void expectRParen() {
+ if (!this.match(")"))
+ this.error(Error.EXPECTED_CLOSING_PAREN, this.pos-1);
+ }
+
+ private void expectRBrace() {
+ if (!this.match("}"))
+ this.error(Error.EXPECTED_CLOSING_BRACE, this.pos-1);
+ }
+
+ private void expectRAngle() {
+ if (!this.match(">"))
+ this.error(Error.EXPECTED_CLOSING_ANGLE, this.pos-1);
+ }
+
+ private boolean lookahead(String... arguments) {
+ for (String prefix : arguments) {
+ if (prefix == null) {
+ if (atEOS())
+ return true;
+ } else if (inputSubstring(pos, pos+prefix.length()).equals(prefix)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean match(String... arguments) {
+ for (String prefix : arguments) {
+ if (this.lookahead(prefix)) {
+ if (prefix == null)
+ prefix = "";
+ this.pos += prefix.length();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private RegExpTerm parsePattern() {
+ RegExpTerm res = parseDisjunction();
+ if (!this.atEOS())
+ this.error(Error.EXPECTED_EOS);
+ return res;
+ }
+
+ protected String inputSubstring(int start, int end) {
+ if (start >= src.length())
+ return "";
+ if (end > src.length())
+ end = src.length();
+ return src.substring(start, end);
+ }
+
+ private T finishTerm(T term) {
+ SourceLocation loc = term.getLoc();
+ Position end = pos();
+ loc.setSource(inputSubstring(loc.getStart().getOffset(), end.getOffset()));
+ loc.setEnd(end);
+ return term;
+ }
+
+ private RegExpTerm parseDisjunction() {
+ SourceLocation loc = new SourceLocation(pos());
+ List disjuncts = new ArrayList<>();
+ disjuncts.add(this.parseAlternative());
+ while (this.match("|"))
+ disjuncts.add(this.parseAlternative());
+ if (disjuncts.size() == 1)
+ return disjuncts.get(0);
+ return this.finishTerm(new Disjunction(loc, disjuncts));
+ }
+
+ private RegExpTerm parseAlternative() {
+ SourceLocation loc = new SourceLocation(pos());
+ List elements = new ArrayList<>();
+ while (!this.lookahead(null, "|", ")"))
+ elements.add(this.parseTerm());
+ if (elements.size() == 1)
+ return elements.get(0);
+ return this.finishTerm(new Sequence(loc, elements));
+ }
+
+ private RegExpTerm parseTerm() {
+ SourceLocation loc = new SourceLocation(pos());
+
+ if (this.match("^"))
+ return this.finishTerm(new Caret(loc));
+
+ if (this.match("$"))
+ return this.finishTerm(new Dollar(loc));
+
+ if (this.match("\\b"))
+ return this.finishTerm(new WordBoundary(loc));
+
+ if (this.match("\\B"))
+ return this.finishTerm(new NonWordBoundary(loc));
+
+ if (this.match("(?=")) {
+ RegExpTerm dis = this.parseDisjunction();
+ this.expectRParen();
+ return this.finishTerm(new ZeroWidthPositiveLookahead(loc, dis));
+ }
+
+ if (this.match("(?!")) {
+ RegExpTerm dis = this.parseDisjunction();
+ this.expectRParen();
+ return this.finishTerm(new ZeroWidthNegativeLookahead(loc, dis));
+ }
+
+ if (this.match("(?<=")) {
+ RegExpTerm dis = this.parseDisjunction();
+ this.expectRParen();
+ return this.finishTerm(new ZeroWidthPositiveLookbehind(loc, dis));
+ }
+
+ if (this.match("(?"));
+ }
+
+ if (this.match("p{", "P{")) {
+ String name = this.readIdentifier();
+ if (this.match("=")) {
+ value = this.readIdentifier();
+ raw = "\\p{" + name + "=" + value + "}";
+ } else {
+ value = null;
+ raw = "\\p{" + name + "}";
+ }
+ this.expectRBrace();
+ return this.finishTerm(new UnicodePropertyEscape(loc, name, value, raw));
+ }
+
+ int startpos = this.pos-1;
+ char c = this.nextChar();
+
+ if (c >= '0' && c <= '9') {
+ raw = c + this.readDigits(true);
+ if (c == '0' || inCharClass) {
+ int base = c == '0' && raw.length() > 1 ? 8 : 10;
+ try {
+ codepoint = Long.parseLong(raw, base);
+ value = fromCodePoint((int) codepoint);
+ } catch (NumberFormatException nfe) {
+ codepoint = 0;
+ value = "\0";
+ }
+ if (base == 8) {
+ this.error(Error.OCTAL_ESCAPE, startpos, this.pos);
+ return this.finishTerm(new OctalEscape(loc, value, (double)codepoint, "\\" + raw));
+ } else {
+ return this.finishTerm(new DecimalEscape(loc, value, (double)codepoint, "\\" + raw));
+ }
+ } else {
+ try {
+ codepoint = Long.parseLong(raw, 10);
+ } catch (NumberFormatException nfe) {
+ codepoint = 0;
+ }
+ BackReference br = this.finishTerm(new BackReference(loc, (double)codepoint, "\\" + raw));
+ this.backrefs.add(br);
+ return br;
+ }
+ }
+
+ String ctrltab = "f\fn\nr\rt\tv\u000b";
+ int idx;
+ if ((idx=ctrltab.indexOf(c)) % 2 == 0) {
+ codepoint = ctrltab.charAt(idx+1);
+ value = String.valueOf((char)codepoint);
+ return this.finishTerm(new ControlEscape(loc, value, codepoint, "\\" + c));
+ }
+
+ if (c == 'c') {
+ c = this.nextChar();
+ if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z'))
+ this.error(Error.EXPECTED_CONTROL_LETTER, this.pos-1);
+ codepoint = c % 32;
+ value = String.valueOf((char)codepoint);
+ return this.finishTerm(new ControlLetter(loc, value, codepoint, "\\c" + c));
+ }
+
+ if ("dDsSwW".indexOf(c) >= 0) {
+ return this.finishTerm(new CharacterClassEscape(loc, String.valueOf(c), "\\" + c));
+ }
+
+ codepoint = c;
+ value = String.valueOf((char)codepoint);
+ return this.finishTerm(new IdentityEscape(loc, value, codepoint, "\\" + c));
+ }
+
+ private RegExpTerm parseCharacterClass() {
+ SourceLocation loc = new SourceLocation(pos());
+ List elements = new ArrayList<>();
+
+ this.match("[");
+ boolean inverted = this.match("^");
+ while (!this.match("]")) {
+ if (this.atEOS()) {
+ this.error(Error.EXPECTED_RBRACKET);
+ break;
+ }
+ elements.add(this.parseCharacterClassElement());
+ }
+ return this.finishTerm(new CharacterClass(loc, elements, inverted));
+ }
+
+ private RegExpTerm parseCharacterClassElement() {
+ SourceLocation loc = new SourceLocation(pos());
+ RegExpTerm atom = this.parseCharacterClassAtom();
+ if (!this.lookahead("-]") && this.match("-"))
+ return this.finishTerm(new CharacterClassRange(loc, atom, this.parseCharacterClassAtom()));
+ return atom;
+ }
+
+ private RegExpTerm parseCharacterClassAtom() {
+ SourceLocation loc = new SourceLocation(pos());
+ char c = this.nextChar();
+ if (c == '\\') {
+ if (this.match("b"))
+ return this.finishTerm(new ControlEscape(loc, "\b", 8, "\\b"));
+ return this.finishTerm(this.parseAtomEscape(loc, true));
+ }
+ return this.finishTerm(new Constant(loc, String.valueOf(c)));
}
}
diff --git a/javascript/extractor/tests/comments/input/jsdoc.js b/javascript/extractor/tests/comments/input/jsdoc.js
index e8b4b59c3bf..5f22f8bd78d 100644
--- a/javascript/extractor/tests/comments/input/jsdoc.js
+++ b/javascript/extractor/tests/comments/input/jsdoc.js
@@ -15,3 +15,28 @@
* @param {Function(DOMNode)}
* @param {Function(DOMNode)} x
*/
+
+/**
+ * @{link a}
+ */
+
+/**
+ * @typedef
+ * {a}
+ */
+
+/**
+ * [resize description]
+ * @param {[type]} w [description]
+ * @param { } h [description]
+ * @return {[type]} [description]
+ */
+
+/**
+* @exports R
+*
+*/
+
+/**
+ * @typedef {{0: number}}
+ */
diff --git a/javascript/extractor/tests/comments/output/trap/jsdoc.js.trap b/javascript/extractor/tests/comments/output/trap/jsdoc.js.trap
index 5c0c6c543b0..7d0e6318fee 100644
--- a/javascript/extractor/tests/comments/output/trap/jsdoc.js.trap
+++ b/javascript/extractor/tests/comments/output/trap/jsdoc.js.trap
@@ -10,8 +10,8 @@ hasLocation(#10000,#10002)
scopes(#20000,0)
#20001=@"script;{#10000},1,1"
toplevels(#20001,0)
-#20002=@"loc,{#10000},1,1,18,0"
-locations_default(#20002,#10000,1,1,18,0)
+#20002=@"loc,{#10000},1,1,43,0"
+locations_default(#20002,#10000,1,1,43,0)
hasLocation(#20001,#20002)
#20003=*
comments(#20003,2,#20001,"
@@ -51,253 +51,537 @@ comments(#20011,2,#20001,"
locations_default(#20012,#10000,14,1,17,3)
hasLocation(#20011,#20012)
#20013=*
-lines(#20013,#20001,"/**","
-")
-#20014=@"loc,{#10000},1,1,1,3"
-locations_default(#20014,#10000,1,1,1,3)
+comments(#20013,2,#20001,"
+ * @{link a}
+ ","/**\n * @{link a}\n */")
+#20014=@"loc,{#10000},19,1,21,3"
+locations_default(#20014,#10000,19,1,21,3)
hasLocation(#20013,#20014)
#20015=*
-lines(#20015,#20001," * This is a constant.","
-")
-#20016=@"loc,{#10000},2,1,2,22"
-locations_default(#20016,#10000,2,1,2,22)
+comments(#20015,2,#20001,"
+ * @typedef
+ * {a}
+ ","/**\n * ... {a}\n */")
+#20016=@"loc,{#10000},23,1,26,3"
+locations_default(#20016,#10000,23,1,26,3)
hasLocation(#20015,#20016)
-indentation(#10000,2," ",1)
#20017=*
-lines(#20017,#20001," * ","
-")
-#20018=@"loc,{#10000},3,1,3,3"
-locations_default(#20018,#10000,3,1,3,3)
+comments(#20017,2,#20001,"
+ * [resize description]
+ * @param {[type]} w [description]
+ * @param { } h [description]
+ * @return {[type]} [description]
+ ","/**\n * ... on]\n */")
+#20018=@"loc,{#10000},28,1,33,3"
+locations_default(#20018,#10000,28,1,33,3)
hasLocation(#20017,#20018)
-indentation(#10000,3," ",1)
#20019=*
-lines(#20019,#20001," * @const x","
-")
-#20020=@"loc,{#10000},4,1,4,11"
-locations_default(#20020,#10000,4,1,4,11)
+comments(#20019,2,#20001,"
+* @exports R
+*
+","/**\n* @ ... R\n*\n*/")
+#20020=@"loc,{#10000},35,1,38,2"
+locations_default(#20020,#10000,35,1,38,2)
hasLocation(#20019,#20020)
-indentation(#10000,4," ",1)
#20021=*
-lines(#20021,#20001," */","
-")
-#20022=@"loc,{#10000},5,1,5,3"
-locations_default(#20022,#10000,5,1,5,3)
+comments(#20021,2,#20001,"
+ * @typedef {{0: number}}
+ ","/**\n * ... r}}\n */")
+#20022=@"loc,{#10000},40,1,42,3"
+locations_default(#20022,#10000,40,1,42,3)
hasLocation(#20021,#20022)
-indentation(#10000,5," ",1)
#20023=*
-lines(#20023,#20001,"/** @class {Object} klass */","
+lines(#20023,#20001,"/**","
")
-hasLocation(#20023,#20006)
-#20024=*
-lines(#20024,#20001,"/** @deprecated */","
-")
-hasLocation(#20024,#20008)
+#20024=@"loc,{#10000},1,1,1,3"
+locations_default(#20024,#10000,1,1,1,3)
+hasLocation(#20023,#20024)
#20025=*
-lines(#20025,#20001,"/** @param {(int|bool)} x","
+lines(#20025,#20001," * This is a constant.","
")
-#20026=@"loc,{#10000},8,1,8,25"
-locations_default(#20026,#10000,8,1,8,25)
+#20026=@"loc,{#10000},2,1,2,22"
+locations_default(#20026,#10000,2,1,2,22)
hasLocation(#20025,#20026)
+indentation(#10000,2," ",1)
#20027=*
-lines(#20027,#20001," * @param {Array.} ys","
+lines(#20027,#20001," * ","
")
-#20028=@"loc,{#10000},9,1,9,38"
-locations_default(#20028,#10000,9,1,9,38)
+#20028=@"loc,{#10000},3,1,3,3"
+locations_default(#20028,#10000,3,1,3,3)
hasLocation(#20027,#20028)
-indentation(#10000,9," ",1)
+indentation(#10000,3," ",1)
#20029=*
-lines(#20029,#20001," * @param {String[]} zs","
+lines(#20029,#20001," * @const x","
")
-#20030=@"loc,{#10000},10,1,10,24"
-locations_default(#20030,#10000,10,1,10,24)
+#20030=@"loc,{#10000},4,1,4,11"
+locations_default(#20030,#10000,4,1,4,11)
hasLocation(#20029,#20030)
-indentation(#10000,10," ",1)
+indentation(#10000,4," ",1)
#20031=*
-lines(#20031,#20001," * @param {function(new:goog.ui.Menu, ?string=, number=): void} f","
+lines(#20031,#20001," */","
")
-#20032=@"loc,{#10000},11,1,11,66"
-locations_default(#20032,#10000,11,1,11,66)
+#20032=@"loc,{#10000},5,1,5,3"
+locations_default(#20032,#10000,5,1,5,3)
hasLocation(#20031,#20032)
-indentation(#10000,11," ",1)
+indentation(#10000,5," ",1)
#20033=*
-lines(#20033,#20001," * @param {...number} var_args","
+lines(#20033,#20001,"/** @class {Object} klass */","
")
-#20034=@"loc,{#10000},12,1,12,31"
-locations_default(#20034,#10000,12,1,12,31)
-hasLocation(#20033,#20034)
-indentation(#10000,12," ",1)
+hasLocation(#20033,#20006)
+#20034=*
+lines(#20034,#20001,"/** @deprecated */","
+")
+hasLocation(#20034,#20008)
#20035=*
-lines(#20035,#20001," */","
+lines(#20035,#20001,"/** @param {(int|bool)} x","
")
-#20036=@"loc,{#10000},13,1,13,3"
-locations_default(#20036,#10000,13,1,13,3)
+#20036=@"loc,{#10000},8,1,8,25"
+locations_default(#20036,#10000,8,1,8,25)
hasLocation(#20035,#20036)
-indentation(#10000,13," ",1)
#20037=*
-lines(#20037,#20001,"/**","
+lines(#20037,#20001," * @param {Array.} ys","
")
-#20038=@"loc,{#10000},14,1,14,3"
-locations_default(#20038,#10000,14,1,14,3)
+#20038=@"loc,{#10000},9,1,9,38"
+locations_default(#20038,#10000,9,1,9,38)
hasLocation(#20037,#20038)
+indentation(#10000,9," ",1)
#20039=*
-lines(#20039,#20001," * @param {Function(DOMNode)}","
+lines(#20039,#20001," * @param {String[]} zs","
")
-#20040=@"loc,{#10000},15,1,15,29"
-locations_default(#20040,#10000,15,1,15,29)
+#20040=@"loc,{#10000},10,1,10,24"
+locations_default(#20040,#10000,10,1,10,24)
hasLocation(#20039,#20040)
-indentation(#10000,15," ",1)
+indentation(#10000,10," ",1)
#20041=*
-lines(#20041,#20001," * @param {Function(DOMNode)} x","
+lines(#20041,#20001," * @param {function(new:goog.ui.Menu, ?string=, number=): void} f","
")
-#20042=@"loc,{#10000},16,1,16,31"
-locations_default(#20042,#10000,16,1,16,31)
+#20042=@"loc,{#10000},11,1,11,66"
+locations_default(#20042,#10000,11,1,11,66)
hasLocation(#20041,#20042)
-indentation(#10000,16," ",1)
+indentation(#10000,11," ",1)
#20043=*
-lines(#20043,#20001," */","
+lines(#20043,#20001," * @param {...number} var_args","
")
-#20044=@"loc,{#10000},17,1,17,3"
-locations_default(#20044,#10000,17,1,17,3)
+#20044=@"loc,{#10000},12,1,12,31"
+locations_default(#20044,#10000,12,1,12,31)
hasLocation(#20043,#20044)
-indentation(#10000,17," ",1)
-numlines(#20001,17,0,17)
+indentation(#10000,12," ",1)
#20045=*
-tokeninfo(#20045,0,#20001,0,"")
-#20046=@"loc,{#10000},18,1,18,0"
-locations_default(#20046,#10000,18,1,18,0)
+lines(#20045,#20001," */","
+")
+#20046=@"loc,{#10000},13,1,13,3"
+locations_default(#20046,#10000,13,1,13,3)
hasLocation(#20045,#20046)
-next_token(#20003,#20045)
-next_token(#20005,#20045)
-next_token(#20007,#20045)
-next_token(#20009,#20045)
-next_token(#20011,#20045)
+indentation(#10000,13," ",1)
#20047=*
-entry_cfg_node(#20047,#20001)
-#20048=@"loc,{#10000},1,1,1,0"
-locations_default(#20048,#10000,1,1,1,0)
+lines(#20047,#20001,"/**","
+")
+#20048=@"loc,{#10000},14,1,14,3"
+locations_default(#20048,#10000,14,1,14,3)
hasLocation(#20047,#20048)
#20049=*
-exit_cfg_node(#20049,#20001)
-hasLocation(#20049,#20046)
-successor(#20047,#20049)
-#20050=*
-jsdoc(#20050,"This is a constant.",#20003)
-hasLocation(#20050,#20004)
+lines(#20049,#20001," * @param {Function(DOMNode)}","
+")
+#20050=@"loc,{#10000},15,1,15,29"
+locations_default(#20050,#10000,15,1,15,29)
+hasLocation(#20049,#20050)
+indentation(#10000,15," ",1)
#20051=*
-jsdoc_tags(#20051,"const",#20050,0,"@const")
-#20052=@"loc,{#10000},4,4,4,9"
-locations_default(#20052,#10000,4,4,4,9)
+lines(#20051,#20001," * @param {Function(DOMNode)} x","
+")
+#20052=@"loc,{#10000},16,1,16,31"
+locations_default(#20052,#10000,16,1,16,31)
hasLocation(#20051,#20052)
-jsdoc_tag_names(#20051,"x")
+indentation(#10000,16," ",1)
#20053=*
-jsdoc(#20053,"",#20005)
-hasLocation(#20053,#20006)
-#20054=*
-jsdoc_tags(#20054,"class",#20053,0,"@class")
-#20055=@"loc,{#10000},6,5,6,10"
-locations_default(#20055,#10000,6,5,6,10)
-hasLocation(#20054,#20055)
-jsdoc_tag_names(#20054,"klass")
-#20056=*
-jsdoc_type_exprs(#20056,5,#20054,0,"Object")
+lines(#20053,#20001," */","
+")
+#20054=@"loc,{#10000},17,1,17,3"
+locations_default(#20054,#10000,17,1,17,3)
+hasLocation(#20053,#20054)
+indentation(#10000,17," ",1)
+#20055=*
+lines(#20055,#20001,"","
+")
+#20056=@"loc,{#10000},18,1,18,0"
+locations_default(#20056,#10000,18,1,18,0)
+hasLocation(#20055,#20056)
#20057=*
-jsdoc(#20057,"",#20007)
-hasLocation(#20057,#20008)
-#20058=*
-jsdoc_tags(#20058,"deprecated",#20057,0,"@deprecated")
-#20059=@"loc,{#10000},7,5,7,15"
-locations_default(#20059,#10000,7,5,7,15)
-hasLocation(#20058,#20059)
-#20060=*
-jsdoc(#20060,"",#20009)
-hasLocation(#20060,#20010)
+lines(#20057,#20001,"/**","
+")
+#20058=@"loc,{#10000},19,1,19,3"
+locations_default(#20058,#10000,19,1,19,3)
+hasLocation(#20057,#20058)
+#20059=*
+lines(#20059,#20001," * @{link a}","
+")
+#20060=@"loc,{#10000},20,1,20,12"
+locations_default(#20060,#10000,20,1,20,12)
+hasLocation(#20059,#20060)
+indentation(#10000,20," ",1)
#20061=*
-jsdoc_tags(#20061,"param",#20060,0,"@param")
-#20062=@"loc,{#10000},8,5,8,10"
-locations_default(#20062,#10000,8,5,8,10)
+lines(#20061,#20001," */","
+")
+#20062=@"loc,{#10000},21,1,21,3"
+locations_default(#20062,#10000,21,1,21,3)
hasLocation(#20061,#20062)
-jsdoc_tag_names(#20061,"x")
+indentation(#10000,21," ",1)
#20063=*
-jsdoc_type_exprs(#20063,11,#20061,0,"(int|bool)")
-#20064=*
-jsdoc_type_exprs(#20064,5,#20063,0,"int")
+lines(#20063,#20001,"","
+")
+#20064=@"loc,{#10000},22,1,22,0"
+locations_default(#20064,#10000,22,1,22,0)
+hasLocation(#20063,#20064)
#20065=*
-jsdoc_type_exprs(#20065,5,#20063,1,"bool")
-#20066=*
-jsdoc_tags(#20066,"param",#20060,1,"@param")
-#20067=@"loc,{#10000},9,5,9,10"
-locations_default(#20067,#10000,9,5,9,10)
-hasLocation(#20066,#20067)
-jsdoc_tag_names(#20066,"ys")
-#20068=*
-jsdoc_type_exprs(#20068,6,#20066,0,"Array.")
+lines(#20065,#20001,"/**","
+")
+#20066=@"loc,{#10000},23,1,23,3"
+locations_default(#20066,#10000,23,1,23,3)
+hasLocation(#20065,#20066)
+#20067=*
+lines(#20067,#20001," * @typedef","
+")
+#20068=@"loc,{#10000},24,1,24,11"
+locations_default(#20068,#10000,24,1,24,11)
+hasLocation(#20067,#20068)
+indentation(#10000,24," ",1)
#20069=*
-jsdoc_type_exprs(#20069,5,#20068,-1,"Array")
-#20070=*
-jsdoc_type_exprs(#20070,5,#20068,0,"String")
+lines(#20069,#20001," * {a}","
+")
+#20070=@"loc,{#10000},25,1,25,6"
+locations_default(#20070,#10000,25,1,25,6)
+hasLocation(#20069,#20070)
+indentation(#10000,25," ",1)
#20071=*
-jsdoc_type_exprs(#20071,5,#20068,1,"Number")
-#20072=*
-jsdoc_tags(#20072,"param",#20060,2,"@param")
-#20073=@"loc,{#10000},10,5,10,10"
-locations_default(#20073,#10000,10,5,10,10)
-hasLocation(#20072,#20073)
-jsdoc_tag_names(#20072,"zs")
-#20074=*
-jsdoc_type_exprs(#20074,6,#20072,0,"Array.")
+lines(#20071,#20001," */","
+")
+#20072=@"loc,{#10000},26,1,26,3"
+locations_default(#20072,#10000,26,1,26,3)
+hasLocation(#20071,#20072)
+indentation(#10000,26," ",1)
+#20073=*
+lines(#20073,#20001,"","
+")
+#20074=@"loc,{#10000},27,1,27,0"
+locations_default(#20074,#10000,27,1,27,0)
+hasLocation(#20073,#20074)
#20075=*
-jsdoc_type_exprs(#20075,5,#20074,-1,"Array")
-#20076=*
-jsdoc_type_exprs(#20076,5,#20074,0,"String")
+lines(#20075,#20001,"/**","
+")
+#20076=@"loc,{#10000},28,1,28,3"
+locations_default(#20076,#10000,28,1,28,3)
+hasLocation(#20075,#20076)
#20077=*
-jsdoc_tags(#20077,"param",#20060,3,"@param")
-#20078=@"loc,{#10000},11,5,11,10"
-locations_default(#20078,#10000,11,5,11,10)
+lines(#20077,#20001," * [resize description]","
+")
+#20078=@"loc,{#10000},29,1,29,23"
+locations_default(#20078,#10000,29,1,29,23)
hasLocation(#20077,#20078)
-jsdoc_tag_names(#20077,"f")
+indentation(#10000,29," ",1)
#20079=*
-jsdoc_type_exprs(#20079,12,#20077,0,"function (new: goog.ui.Menu, ?string=, number=): void")
-#20080=*
-jsdoc_type_exprs(#20080,13,#20079,0,"?string=")
+lines(#20079,#20001," * @param {[type]} w [description]","
+")
+#20080=@"loc,{#10000},30,1,30,35"
+locations_default(#20080,#10000,30,1,30,35)
+hasLocation(#20079,#20080)
+indentation(#10000,30," ",1)
#20081=*
-jsdoc_type_exprs(#20081,7,#20080,0,"?string")
-#20082=*
-jsdoc_type_exprs(#20082,5,#20081,0,"string")
-jsdoc_prefix_qualifier(#20081)
+lines(#20081,#20001," * @param { } h [description]","
+")
+#20082=@"loc,{#10000},31,1,31,31"
+locations_default(#20082,#10000,31,1,31,31)
+hasLocation(#20081,#20082)
+indentation(#10000,31," ",1)
#20083=*
-jsdoc_type_exprs(#20083,13,#20079,1,"number=")
-#20084=*
-jsdoc_type_exprs(#20084,5,#20083,0,"number")
+lines(#20083,#20001," * @return {[type]} [description]","
+")
+#20084=@"loc,{#10000},32,1,32,35"
+locations_default(#20084,#10000,32,1,32,35)
+hasLocation(#20083,#20084)
+indentation(#10000,32," ",1)
#20085=*
-jsdoc_type_exprs(#20085,4,#20079,-1,"void")
-#20086=*
-jsdoc_type_exprs(#20086,5,#20079,-2,"goog.ui.Menu")
-jsdoc_has_new_parameter(#20079)
+lines(#20085,#20001," */","
+")
+#20086=@"loc,{#10000},33,1,33,3"
+locations_default(#20086,#10000,33,1,33,3)
+hasLocation(#20085,#20086)
+indentation(#10000,33," ",1)
#20087=*
-jsdoc_tags(#20087,"param",#20060,4,"@param")
-#20088=@"loc,{#10000},12,5,12,10"
-locations_default(#20088,#10000,12,5,12,10)
+lines(#20087,#20001,"","
+")
+#20088=@"loc,{#10000},34,1,34,0"
+locations_default(#20088,#10000,34,1,34,0)
hasLocation(#20087,#20088)
-jsdoc_tag_names(#20087,"var_args")
#20089=*
-jsdoc_type_exprs(#20089,14,#20087,0,"...number")
-#20090=*
-jsdoc_type_exprs(#20090,5,#20089,0,"number")
+lines(#20089,#20001,"/**","
+")
+#20090=@"loc,{#10000},35,1,35,3"
+locations_default(#20090,#10000,35,1,35,3)
+hasLocation(#20089,#20090)
#20091=*
-jsdoc(#20091,"",#20011)
-hasLocation(#20091,#20012)
-#20092=*
-jsdoc_tags(#20092,"param",#20091,0,"@param")
-#20093=@"loc,{#10000},15,4,15,9"
-locations_default(#20093,#10000,15,4,15,9)
-hasLocation(#20092,#20093)
-#20094=*
-jsdoc_errors(#20094,#20092,"Missing or invalid tag name","Missing ... ag name")
+lines(#20091,#20001,"* @exports R","
+")
+#20092=@"loc,{#10000},36,1,36,12"
+locations_default(#20092,#10000,36,1,36,12)
+hasLocation(#20091,#20092)
+#20093=*
+lines(#20093,#20001,"*","
+")
+#20094=@"loc,{#10000},37,1,37,1"
+locations_default(#20094,#10000,37,1,37,1)
+hasLocation(#20093,#20094)
#20095=*
-jsdoc_tags(#20095,"param",#20091,1,"@param")
-#20096=@"loc,{#10000},16,4,16,9"
-locations_default(#20096,#10000,16,4,16,9)
+lines(#20095,#20001,"*/","
+")
+#20096=@"loc,{#10000},38,1,38,2"
+locations_default(#20096,#10000,38,1,38,2)
hasLocation(#20095,#20096)
-jsdoc_tag_names(#20095,"x")
-numlines(#10000,17,0,17)
+#20097=*
+lines(#20097,#20001,"","
+")
+#20098=@"loc,{#10000},39,1,39,0"
+locations_default(#20098,#10000,39,1,39,0)
+hasLocation(#20097,#20098)
+#20099=*
+lines(#20099,#20001,"/**","
+")
+#20100=@"loc,{#10000},40,1,40,3"
+locations_default(#20100,#10000,40,1,40,3)
+hasLocation(#20099,#20100)
+#20101=*
+lines(#20101,#20001," * @typedef {{0: number}}","
+")
+#20102=@"loc,{#10000},41,1,41,25"
+locations_default(#20102,#10000,41,1,41,25)
+hasLocation(#20101,#20102)
+indentation(#10000,41," ",1)
+#20103=*
+lines(#20103,#20001," */","
+")
+#20104=@"loc,{#10000},42,1,42,3"
+locations_default(#20104,#10000,42,1,42,3)
+hasLocation(#20103,#20104)
+indentation(#10000,42," ",1)
+numlines(#20001,42,0,37)
+#20105=*
+tokeninfo(#20105,0,#20001,0,"")
+#20106=@"loc,{#10000},43,1,43,0"
+locations_default(#20106,#10000,43,1,43,0)
+hasLocation(#20105,#20106)
+next_token(#20003,#20105)
+next_token(#20005,#20105)
+next_token(#20007,#20105)
+next_token(#20009,#20105)
+next_token(#20011,#20105)
+next_token(#20013,#20105)
+next_token(#20015,#20105)
+next_token(#20017,#20105)
+next_token(#20019,#20105)
+next_token(#20021,#20105)
+#20107=*
+entry_cfg_node(#20107,#20001)
+#20108=@"loc,{#10000},1,1,1,0"
+locations_default(#20108,#10000,1,1,1,0)
+hasLocation(#20107,#20108)
+#20109=*
+exit_cfg_node(#20109,#20001)
+hasLocation(#20109,#20106)
+successor(#20107,#20109)
+#20110=*
+jsdoc(#20110,"This is a constant.",#20003)
+hasLocation(#20110,#20004)
+#20111=*
+jsdoc_tags(#20111,"const",#20110,0,"@const")
+#20112=@"loc,{#10000},4,4,4,9"
+locations_default(#20112,#10000,4,4,4,9)
+hasLocation(#20111,#20112)
+jsdoc_tag_names(#20111,"x")
+#20113=*
+jsdoc(#20113,"",#20005)
+hasLocation(#20113,#20006)
+#20114=*
+jsdoc_tags(#20114,"class",#20113,0,"@class")
+#20115=@"loc,{#10000},6,5,6,10"
+locations_default(#20115,#10000,6,5,6,10)
+hasLocation(#20114,#20115)
+jsdoc_tag_names(#20114,"klass")
+#20116=*
+jsdoc_type_exprs(#20116,5,#20114,0,"Object")
+#20117=*
+jsdoc(#20117,"",#20007)
+hasLocation(#20117,#20008)
+#20118=*
+jsdoc_tags(#20118,"deprecated",#20117,0,"@deprecated")
+#20119=@"loc,{#10000},7,5,7,15"
+locations_default(#20119,#10000,7,5,7,15)
+hasLocation(#20118,#20119)
+#20120=*
+jsdoc(#20120,"",#20009)
+hasLocation(#20120,#20010)
+#20121=*
+jsdoc_tags(#20121,"param",#20120,0,"@param")
+#20122=@"loc,{#10000},8,5,8,10"
+locations_default(#20122,#10000,8,5,8,10)
+hasLocation(#20121,#20122)
+jsdoc_tag_names(#20121,"x")
+#20123=*
+jsdoc_type_exprs(#20123,11,#20121,0,"(int|bool)")
+#20124=*
+jsdoc_type_exprs(#20124,5,#20123,0,"int")
+#20125=*
+jsdoc_type_exprs(#20125,5,#20123,1,"bool")
+#20126=*
+jsdoc_tags(#20126,"param",#20120,1,"@param")
+#20127=@"loc,{#10000},9,5,9,10"
+locations_default(#20127,#10000,9,5,9,10)
+hasLocation(#20126,#20127)
+jsdoc_tag_names(#20126,"ys")
+#20128=*
+jsdoc_type_exprs(#20128,6,#20126,0,"Array.")
+#20129=*
+jsdoc_type_exprs(#20129,5,#20128,-1,"Array")
+#20130=*
+jsdoc_type_exprs(#20130,5,#20128,0,"String")
+#20131=*
+jsdoc_type_exprs(#20131,5,#20128,1,"Number")
+#20132=*
+jsdoc_tags(#20132,"param",#20120,2,"@param")
+#20133=@"loc,{#10000},10,5,10,10"
+locations_default(#20133,#10000,10,5,10,10)
+hasLocation(#20132,#20133)
+jsdoc_tag_names(#20132,"zs")
+#20134=*
+jsdoc_type_exprs(#20134,6,#20132,0,"Array.")
+#20135=*
+jsdoc_type_exprs(#20135,5,#20134,-1,"Array")
+#20136=*
+jsdoc_type_exprs(#20136,5,#20134,0,"String")
+#20137=*
+jsdoc_tags(#20137,"param",#20120,3,"@param")
+#20138=@"loc,{#10000},11,5,11,10"
+locations_default(#20138,#10000,11,5,11,10)
+hasLocation(#20137,#20138)
+jsdoc_tag_names(#20137,"f")
+#20139=*
+jsdoc_type_exprs(#20139,12,#20137,0,"function (new: goog.ui.Menu, ?string=, number=): void")
+#20140=*
+jsdoc_type_exprs(#20140,13,#20139,0,"?string=")
+#20141=*
+jsdoc_type_exprs(#20141,7,#20140,0,"?string")
+#20142=*
+jsdoc_type_exprs(#20142,5,#20141,0,"string")
+jsdoc_prefix_qualifier(#20141)
+#20143=*
+jsdoc_type_exprs(#20143,13,#20139,1,"number=")
+#20144=*
+jsdoc_type_exprs(#20144,5,#20143,0,"number")
+#20145=*
+jsdoc_type_exprs(#20145,4,#20139,-1,"void")
+#20146=*
+jsdoc_type_exprs(#20146,5,#20139,-2,"goog.ui.Menu")
+jsdoc_has_new_parameter(#20139)
+#20147=*
+jsdoc_tags(#20147,"param",#20120,4,"@param")
+#20148=@"loc,{#10000},12,5,12,10"
+locations_default(#20148,#10000,12,5,12,10)
+hasLocation(#20147,#20148)
+jsdoc_tag_names(#20147,"var_args")
+#20149=*
+jsdoc_type_exprs(#20149,14,#20147,0,"...number")
+#20150=*
+jsdoc_type_exprs(#20150,5,#20149,0,"number")
+#20151=*
+jsdoc(#20151,"",#20011)
+hasLocation(#20151,#20012)
+#20152=*
+jsdoc_tags(#20152,"param",#20151,0,"@param")
+#20153=@"loc,{#10000},15,4,15,9"
+locations_default(#20153,#10000,15,4,15,9)
+hasLocation(#20152,#20153)
+#20154=*
+jsdoc_errors(#20154,#20152,"Missing or invalid tag name","Missing ... ag name")
+#20155=*
+jsdoc_tags(#20155,"param",#20151,1,"@param")
+#20156=@"loc,{#10000},16,4,16,9"
+locations_default(#20156,#10000,16,4,16,9)
+hasLocation(#20155,#20156)
+jsdoc_tag_names(#20155,"x")
+#20157=*
+jsdoc(#20157,"",#20013)
+hasLocation(#20157,#20014)
+#20158=*
+jsdoc_tags(#20158,"",#20157,0,"@")
+#20159=@"loc,{#10000},20,4,20,4"
+locations_default(#20159,#10000,20,4,20,4)
+hasLocation(#20158,#20159)
+jsdoc_tag_descriptions(#20158,"{link a}")
+#20160=*
+jsdoc_errors(#20160,#20158,"Missing or invalid title","Missing ... d title")
+#20161=*
+jsdoc(#20161,"",#20015)
+hasLocation(#20161,#20016)
+#20162=*
+jsdoc_tags(#20162,"typedef",#20161,0,"@typedef")
+#20163=@"loc,{#10000},24,4,24,11"
+locations_default(#20163,#10000,24,4,24,11)
+hasLocation(#20162,#20163)
+jsdoc_tag_descriptions(#20162,"{a}")
+#20164=*
+jsdoc_errors(#20164,#20162,"Missing or invalid tag type","Missing ... ag type")
+#20165=*
+jsdoc(#20165,"[resize description]",#20017)
+hasLocation(#20165,#20018)
+#20166=*
+jsdoc_tags(#20166,"param",#20165,0,"@param")
+#20167=@"loc,{#10000},30,4,30,9"
+locations_default(#20167,#10000,30,4,30,9)
+hasLocation(#20166,#20167)
+jsdoc_tag_descriptions(#20166,"[description]
+")
+jsdoc_tag_names(#20166,"w")
+#20168=*
+jsdoc_type_exprs(#20168,10,#20166,0,"[type]")
+#20169=*
+jsdoc_type_exprs(#20169,5,#20168,0,"type")
+#20170=*
+jsdoc_tags(#20170,"param",#20165,1,"@param")
+#20171=@"loc,{#10000},31,4,31,9"
+locations_default(#20171,#10000,31,4,31,9)
+hasLocation(#20170,#20171)
+jsdoc_tag_descriptions(#20170,"[description]
+")
+#20172=*
+jsdoc_tags(#20172,"return",#20165,2,"@return")
+#20173=@"loc,{#10000},32,4,32,10"
+locations_default(#20173,#10000,32,4,32,10)
+hasLocation(#20172,#20173)
+jsdoc_tag_descriptions(#20172,"[description]")
+#20174=*
+jsdoc_type_exprs(#20174,10,#20172,0,"[type]")
+#20175=*
+jsdoc_type_exprs(#20175,5,#20174,0,"type")
+#20176=*
+jsdoc(#20176,"",#20019)
+hasLocation(#20176,#20020)
+#20177=*
+jsdoc_tags(#20177,"exports",#20176,0,"@exports")
+#20178=@"loc,{#10000},36,3,36,10"
+locations_default(#20178,#10000,36,3,36,10)
+hasLocation(#20177,#20178)
+jsdoc_tag_descriptions(#20177,"R
+")
+#20179=*
+jsdoc(#20179,"",#20021)
+hasLocation(#20179,#20022)
+#20180=*
+jsdoc_tags(#20180,"typedef",#20179,0,"@typedef")
+#20181=@"loc,{#10000},41,4,41,11"
+locations_default(#20181,#10000,41,4,41,11)
+hasLocation(#20180,#20181)
+#20182=*
+jsdoc_type_exprs(#20182,9,#20180,0,"{0: number}")
+jsdoc_record_field_name(#20182,0,"0")
+#20183=*
+jsdoc_type_exprs(#20183,5,#20182,0,"number")
+numlines(#10000,42,0,37)
filetype(#10000,"javascript")
diff --git a/javascript/extractor/tests/exprs/output/trap/regexp.js.trap b/javascript/extractor/tests/exprs/output/trap/regexp.js.trap
index 9a3eb7e3595..b255ddbb8a3 100644
--- a/javascript/extractor/tests/exprs/output/trap/regexp.js.trap
+++ b/javascript/extractor/tests/exprs/output/trap/regexp.js.trap
@@ -792,1409 +792,1412 @@ locations_default(#20250,#10000,26,2,26,4)
hasLocation(#20249,#20250)
backref(#20249,10)
#20251=*
-stmts(#20251,2,#20001,26,"/\t\n\r\f\v/;")
-#20252=@"loc,{#10000},27,1,27,13"
-locations_default(#20252,#10000,27,1,27,13)
-hasLocation(#20251,#20252)
-stmtContainers(#20251,#20001)
-#20253=*
-exprs(#20253,5,#20251,0,"/\t\n\r\f\v/")
-#20254=@"loc,{#10000},27,1,27,12"
-locations_default(#20254,#10000,27,1,27,12)
-hasLocation(#20253,#20254)
-enclosingStmt(#20253,#20251)
-exprContainers(#20253,#20001)
-literals("/\t\n\r\f\v/","/\t\n\r\f\v/",#20253)
-#20255=*
-regexpterm(#20255,1,#20253,0,"\t\n\r\f\v")
-#20256=@"loc,{#10000},27,2,27,11"
-locations_default(#20256,#10000,27,2,27,11)
-hasLocation(#20255,#20256)
-#20257=*
-regexpterm(#20257,19,#20255,0,"\t")
-#20258=@"loc,{#10000},27,2,27,3"
-locations_default(#20258,#10000,27,2,27,3)
-hasLocation(#20257,#20258)
-regexpConstValue(#20257," ")
-#20259=*
-regexpterm(#20259,19,#20255,1,"\n")
-#20260=@"loc,{#10000},27,4,27,5"
-locations_default(#20260,#10000,27,4,27,5)
-hasLocation(#20259,#20260)
-regexpConstValue(#20259,"
+regexpParseErrors(#20251,#20249,"invalid back reference")
+hasLocation(#20251,#20250)
+#20252=*
+stmts(#20252,2,#20001,26,"/\t\n\r\f\v/;")
+#20253=@"loc,{#10000},27,1,27,13"
+locations_default(#20253,#10000,27,1,27,13)
+hasLocation(#20252,#20253)
+stmtContainers(#20252,#20001)
+#20254=*
+exprs(#20254,5,#20252,0,"/\t\n\r\f\v/")
+#20255=@"loc,{#10000},27,1,27,12"
+locations_default(#20255,#10000,27,1,27,12)
+hasLocation(#20254,#20255)
+enclosingStmt(#20254,#20252)
+exprContainers(#20254,#20001)
+literals("/\t\n\r\f\v/","/\t\n\r\f\v/",#20254)
+#20256=*
+regexpterm(#20256,1,#20254,0,"\t\n\r\f\v")
+#20257=@"loc,{#10000},27,2,27,11"
+locations_default(#20257,#10000,27,2,27,11)
+hasLocation(#20256,#20257)
+#20258=*
+regexpterm(#20258,19,#20256,0,"\t")
+#20259=@"loc,{#10000},27,2,27,3"
+locations_default(#20259,#10000,27,2,27,3)
+hasLocation(#20258,#20259)
+regexpConstValue(#20258," ")
+#20260=*
+regexpterm(#20260,19,#20256,1,"\n")
+#20261=@"loc,{#10000},27,4,27,5"
+locations_default(#20261,#10000,27,4,27,5)
+hasLocation(#20260,#20261)
+regexpConstValue(#20260,"
")
-#20261=*
-regexpterm(#20261,19,#20255,2,"\r")
-#20262=@"loc,{#10000},27,6,27,7"
-locations_default(#20262,#10000,27,6,27,7)
-hasLocation(#20261,#20262)
-regexpConstValue(#20261,"
")
-#20263=*
-regexpterm(#20263,19,#20255,3,"\f")
-#20264=@"loc,{#10000},27,8,27,9"
-locations_default(#20264,#10000,27,8,27,9)
-hasLocation(#20263,#20264)
-regexpConstValue(#20263,"")
-#20265=*
-regexpterm(#20265,19,#20255,4,"\v")
-#20266=@"loc,{#10000},27,10,27,11"
-locations_default(#20266,#10000,27,10,27,11)
-hasLocation(#20265,#20266)
-regexpConstValue(#20265,"")
-#20267=*
-stmts(#20267,2,#20001,27,"/\ca\cN/;")
-#20268=@"loc,{#10000},28,1,28,9"
-locations_default(#20268,#10000,28,1,28,9)
-hasLocation(#20267,#20268)
-stmtContainers(#20267,#20001)
-#20269=*
-exprs(#20269,5,#20267,0,"/\ca\cN/")
-#20270=@"loc,{#10000},28,1,28,8"
-locations_default(#20270,#10000,28,1,28,8)
-hasLocation(#20269,#20270)
-enclosingStmt(#20269,#20267)
-exprContainers(#20269,#20001)
-literals("/\ca\cN/","/\ca\cN/",#20269)
-#20271=*
-regexpterm(#20271,1,#20269,0,"\ca\cN")
-#20272=@"loc,{#10000},28,2,28,7"
-locations_default(#20272,#10000,28,2,28,7)
-hasLocation(#20271,#20272)
-#20273=*
-regexpterm(#20273,19,#20271,0,"\ca")
-#20274=@"loc,{#10000},28,2,28,4"
-locations_default(#20274,#10000,28,2,28,4)
-hasLocation(#20273,#20274)
-regexpConstValue(#20273,"")
-#20275=*
-regexpterm(#20275,19,#20271,1,"\cN")
-#20276=@"loc,{#10000},28,5,28,7"
-locations_default(#20276,#10000,28,5,28,7)
-hasLocation(#20275,#20276)
-regexpConstValue(#20275,"")
-#20277=*
-stmts(#20277,2,#20001,28,"/\w\S/;")
-#20278=@"loc,{#10000},29,1,29,7"
-locations_default(#20278,#10000,29,1,29,7)
-hasLocation(#20277,#20278)
-stmtContainers(#20277,#20001)
-#20279=*
-exprs(#20279,5,#20277,0,"/\w\S/")
-#20280=@"loc,{#10000},29,1,29,6"
-locations_default(#20280,#10000,29,1,29,6)
-hasLocation(#20279,#20280)
-enclosingStmt(#20279,#20277)
-exprContainers(#20279,#20001)
-literals("/\w\S/","/\w\S/",#20279)
-#20281=*
-regexpterm(#20281,1,#20279,0,"\w\S")
-#20282=@"loc,{#10000},29,2,29,5"
-locations_default(#20282,#10000,29,2,29,5)
-hasLocation(#20281,#20282)
-#20283=*
-regexpterm(#20283,20,#20281,0,"\w")
-#20284=@"loc,{#10000},29,2,29,3"
-locations_default(#20284,#10000,29,2,29,3)
-hasLocation(#20283,#20284)
-charClassEscape(#20283,"w")
-#20285=*
-regexpterm(#20285,20,#20281,1,"\S")
-#20286=@"loc,{#10000},29,4,29,5"
-locations_default(#20286,#10000,29,4,29,5)
-hasLocation(#20285,#20286)
-charClassEscape(#20285,"S")
-#20287=*
-stmts(#20287,2,#20001,29,"/\\/;")
-#20288=@"loc,{#10000},30,1,30,5"
-locations_default(#20288,#10000,30,1,30,5)
-hasLocation(#20287,#20288)
-stmtContainers(#20287,#20001)
-#20289=*
-exprs(#20289,5,#20287,0,"/\\/")
-#20290=@"loc,{#10000},30,1,30,4"
-locations_default(#20290,#10000,30,1,30,4)
-hasLocation(#20289,#20290)
-enclosingStmt(#20289,#20287)
-exprContainers(#20289,#20001)
-literals("/\\/","/\\/",#20289)
-#20291=*
-regexpterm(#20291,21,#20289,0,"\\")
-#20292=@"loc,{#10000},30,2,30,3"
-locations_default(#20292,#10000,30,2,30,3)
-hasLocation(#20291,#20292)
-regexpConstValue(#20291,"\")
-#20293=*
-stmts(#20293,2,#20001,30,"/[abc]/;")
-#20294=@"loc,{#10000},31,1,31,8"
-locations_default(#20294,#10000,31,1,31,8)
-hasLocation(#20293,#20294)
-stmtContainers(#20293,#20001)
-#20295=*
-exprs(#20295,5,#20293,0,"/[abc]/")
-#20296=@"loc,{#10000},31,1,31,7"
-locations_default(#20296,#10000,31,1,31,7)
-hasLocation(#20295,#20296)
-enclosingStmt(#20295,#20293)
-exprContainers(#20295,#20001)
-literals("/[abc]/","/[abc]/",#20295)
-#20297=*
-regexpterm(#20297,23,#20295,0,"[abc]")
-#20298=@"loc,{#10000},31,2,31,6"
-locations_default(#20298,#10000,31,2,31,6)
-hasLocation(#20297,#20298)
-#20299=*
-regexpterm(#20299,14,#20297,0,"a")
-#20300=@"loc,{#10000},31,3,31,3"
-locations_default(#20300,#10000,31,3,31,3)
-hasLocation(#20299,#20300)
-regexpConstValue(#20299,"a")
-#20301=*
-regexpterm(#20301,14,#20297,1,"b")
-#20302=@"loc,{#10000},31,4,31,4"
-locations_default(#20302,#10000,31,4,31,4)
-hasLocation(#20301,#20302)
-regexpConstValue(#20301,"b")
-#20303=*
-regexpterm(#20303,14,#20297,2,"c")
-#20304=@"loc,{#10000},31,5,31,5"
-locations_default(#20304,#10000,31,5,31,5)
-hasLocation(#20303,#20304)
-regexpConstValue(#20303,"c")
-#20305=*
-stmts(#20305,2,#20001,31,"/[a-z]/;")
-#20306=@"loc,{#10000},32,1,32,8"
-locations_default(#20306,#10000,32,1,32,8)
-hasLocation(#20305,#20306)
-stmtContainers(#20305,#20001)
-#20307=*
-exprs(#20307,5,#20305,0,"/[a-z]/")
-#20308=@"loc,{#10000},32,1,32,7"
-locations_default(#20308,#10000,32,1,32,7)
-hasLocation(#20307,#20308)
-enclosingStmt(#20307,#20305)
-exprContainers(#20307,#20001)
-literals("/[a-z]/","/[a-z]/",#20307)
-#20309=*
-regexpterm(#20309,23,#20307,0,"[a-z]")
-#20310=@"loc,{#10000},32,2,32,6"
-locations_default(#20310,#10000,32,2,32,6)
-hasLocation(#20309,#20310)
-#20311=*
-regexpterm(#20311,24,#20309,0,"a-z")
-#20312=@"loc,{#10000},32,3,32,5"
-locations_default(#20312,#10000,32,3,32,5)
-hasLocation(#20311,#20312)
-#20313=*
-regexpterm(#20313,14,#20311,0,"a")
-#20314=@"loc,{#10000},32,3,32,3"
-locations_default(#20314,#10000,32,3,32,3)
-hasLocation(#20313,#20314)
-regexpConstValue(#20313,"a")
-#20315=*
-regexpterm(#20315,14,#20311,1,"z")
-#20316=@"loc,{#10000},32,5,32,5"
-locations_default(#20316,#10000,32,5,32,5)
-hasLocation(#20315,#20316)
-regexpConstValue(#20315,"z")
-#20317=*
-stmts(#20317,2,#20001,32,"/[a-zA-Z]/;")
-#20318=@"loc,{#10000},33,1,33,11"
-locations_default(#20318,#10000,33,1,33,11)
-hasLocation(#20317,#20318)
-stmtContainers(#20317,#20001)
-#20319=*
-exprs(#20319,5,#20317,0,"/[a-zA-Z]/")
-#20320=@"loc,{#10000},33,1,33,10"
-locations_default(#20320,#10000,33,1,33,10)
-hasLocation(#20319,#20320)
-enclosingStmt(#20319,#20317)
-exprContainers(#20319,#20001)
-literals("/[a-zA-Z]/","/[a-zA-Z]/",#20319)
-#20321=*
-regexpterm(#20321,23,#20319,0,"[a-zA-Z]")
-#20322=@"loc,{#10000},33,2,33,9"
-locations_default(#20322,#10000,33,2,33,9)
-hasLocation(#20321,#20322)
-#20323=*
-regexpterm(#20323,24,#20321,0,"a-z")
-#20324=@"loc,{#10000},33,3,33,5"
-locations_default(#20324,#10000,33,3,33,5)
-hasLocation(#20323,#20324)
-#20325=*
-regexpterm(#20325,14,#20323,0,"a")
-#20326=@"loc,{#10000},33,3,33,3"
-locations_default(#20326,#10000,33,3,33,3)
-hasLocation(#20325,#20326)
-regexpConstValue(#20325,"a")
-#20327=*
-regexpterm(#20327,14,#20323,1,"z")
-#20328=@"loc,{#10000},33,5,33,5"
-locations_default(#20328,#10000,33,5,33,5)
-hasLocation(#20327,#20328)
-regexpConstValue(#20327,"z")
-#20329=*
-regexpterm(#20329,24,#20321,1,"A-Z")
-#20330=@"loc,{#10000},33,6,33,8"
-locations_default(#20330,#10000,33,6,33,8)
-hasLocation(#20329,#20330)
-#20331=*
-regexpterm(#20331,14,#20329,0,"A")
-#20332=@"loc,{#10000},33,6,33,6"
-locations_default(#20332,#10000,33,6,33,6)
-hasLocation(#20331,#20332)
-regexpConstValue(#20331,"A")
-#20333=*
-regexpterm(#20333,14,#20329,1,"Z")
-#20334=@"loc,{#10000},33,8,33,8"
-locations_default(#20334,#10000,33,8,33,8)
-hasLocation(#20333,#20334)
-regexpConstValue(#20333,"Z")
-#20335=*
-stmts(#20335,2,#20001,33,"/[-a-z]/;")
-#20336=@"loc,{#10000},34,1,34,9"
-locations_default(#20336,#10000,34,1,34,9)
-hasLocation(#20335,#20336)
-stmtContainers(#20335,#20001)
-#20337=*
-exprs(#20337,5,#20335,0,"/[-a-z]/")
-#20338=@"loc,{#10000},34,1,34,8"
-locations_default(#20338,#10000,34,1,34,8)
-hasLocation(#20337,#20338)
-enclosingStmt(#20337,#20335)
-exprContainers(#20337,#20001)
-literals("/[-a-z]/","/[-a-z]/",#20337)
-#20339=*
-regexpterm(#20339,23,#20337,0,"[-a-z]")
-#20340=@"loc,{#10000},34,2,34,7"
-locations_default(#20340,#10000,34,2,34,7)
-hasLocation(#20339,#20340)
-#20341=*
-regexpterm(#20341,14,#20339,0,"-")
-#20342=@"loc,{#10000},34,3,34,3"
-locations_default(#20342,#10000,34,3,34,3)
-hasLocation(#20341,#20342)
-regexpConstValue(#20341,"-")
-#20343=*
-regexpterm(#20343,24,#20339,1,"a-z")
-#20344=@"loc,{#10000},34,4,34,6"
-locations_default(#20344,#10000,34,4,34,6)
-hasLocation(#20343,#20344)
-#20345=*
-regexpterm(#20345,14,#20343,0,"a")
-#20346=@"loc,{#10000},34,4,34,4"
-locations_default(#20346,#10000,34,4,34,4)
-hasLocation(#20345,#20346)
-regexpConstValue(#20345,"a")
-#20347=*
-regexpterm(#20347,14,#20343,1,"z")
-#20348=@"loc,{#10000},34,6,34,6"
-locations_default(#20348,#10000,34,6,34,6)
-hasLocation(#20347,#20348)
-regexpConstValue(#20347,"z")
-#20349=*
-stmts(#20349,2,#20001,34,"/[^a-z]/;")
-#20350=@"loc,{#10000},35,1,35,9"
-locations_default(#20350,#10000,35,1,35,9)
-hasLocation(#20349,#20350)
-stmtContainers(#20349,#20001)
-#20351=*
-exprs(#20351,5,#20349,0,"/[^a-z]/")
-#20352=@"loc,{#10000},35,1,35,8"
-locations_default(#20352,#10000,35,1,35,8)
-hasLocation(#20351,#20352)
-enclosingStmt(#20351,#20349)
-exprContainers(#20351,#20001)
-literals("/[^a-z]/","/[^a-z]/",#20351)
-#20353=*
-regexpterm(#20353,23,#20351,0,"[^a-z]")
-#20354=@"loc,{#10000},35,2,35,7"
-locations_default(#20354,#10000,35,2,35,7)
-hasLocation(#20353,#20354)
-isInverted(#20353)
-#20355=*
-regexpterm(#20355,24,#20353,0,"a-z")
-#20356=@"loc,{#10000},35,4,35,6"
-locations_default(#20356,#10000,35,4,35,6)
-hasLocation(#20355,#20356)
-#20357=*
-regexpterm(#20357,14,#20355,0,"a")
-#20358=@"loc,{#10000},35,4,35,4"
-locations_default(#20358,#10000,35,4,35,4)
-hasLocation(#20357,#20358)
-regexpConstValue(#20357,"a")
-#20359=*
-regexpterm(#20359,14,#20355,1,"z")
-#20360=@"loc,{#10000},35,6,35,6"
-locations_default(#20360,#10000,35,6,35,6)
-hasLocation(#20359,#20360)
-regexpConstValue(#20359,"z")
-#20361=*
-stmts(#20361,2,#20001,35,"/[a\b\x0c]/;")
-#20362=@"loc,{#10000},36,1,36,12"
-locations_default(#20362,#10000,36,1,36,12)
-hasLocation(#20361,#20362)
-stmtContainers(#20361,#20001)
-#20363=*
-exprs(#20363,5,#20361,0,"/[a\b\x0c]/")
-#20364=@"loc,{#10000},36,1,36,11"
-locations_default(#20364,#10000,36,1,36,11)
-hasLocation(#20363,#20364)
-enclosingStmt(#20363,#20361)
-exprContainers(#20363,#20001)
-literals("/[a\b\x0c]/","/[a\b\x0c]/",#20363)
-#20365=*
-regexpterm(#20365,23,#20363,0,"[a\b\x0c]")
-#20366=@"loc,{#10000},36,2,36,10"
-locations_default(#20366,#10000,36,2,36,10)
-hasLocation(#20365,#20366)
-#20367=*
-regexpterm(#20367,14,#20365,0,"a")
-#20368=@"loc,{#10000},36,3,36,3"
-locations_default(#20368,#10000,36,3,36,3)
-hasLocation(#20367,#20368)
-regexpConstValue(#20367,"a")
-#20369=*
-regexpterm(#20369,19,#20365,1,"\b")
-#20370=@"loc,{#10000},36,4,36,5"
-locations_default(#20370,#10000,36,4,36,5)
-hasLocation(#20369,#20370)
-regexpConstValue(#20369,"")
-#20371=*
-regexpterm(#20371,15,#20365,2,"\x0c")
-#20372=@"loc,{#10000},36,6,36,9"
-locations_default(#20372,#10000,36,6,36,9)
-hasLocation(#20371,#20372)
-regexpConstValue(#20371,"")
-#20373=*
-stmts(#20373,2,#20001,36,"/a{/;")
-#20374=@"loc,{#10000},37,1,37,5"
-locations_default(#20374,#10000,37,1,37,5)
-hasLocation(#20373,#20374)
-stmtContainers(#20373,#20001)
-#20375=*
-exprs(#20375,5,#20373,0,"/a{/")
-#20376=@"loc,{#10000},37,1,37,4"
-locations_default(#20376,#10000,37,1,37,4)
-hasLocation(#20375,#20376)
-enclosingStmt(#20375,#20373)
-exprContainers(#20375,#20001)
-literals("/a{/","/a{/",#20375)
-#20377=*
-regexpterm(#20377,11,#20375,0,"a{")
-#20378=@"loc,{#10000},37,2,37,3"
-locations_default(#20378,#10000,37,2,37,3)
-hasLocation(#20377,#20378)
-isGreedy(#20377)
-rangeQuantifierLowerBound(#20377,0)
-#20379=*
-regexpterm(#20379,14,#20377,0,"a")
-#20380=@"loc,{#10000},37,2,37,2"
-locations_default(#20380,#10000,37,2,37,2)
-hasLocation(#20379,#20380)
-regexpConstValue(#20379,"a")
-#20381=*
-regexpParseErrors(#20381,#20377,"expected digit")
-#20382=@"loc,{#10000},37,4,37,4"
-locations_default(#20382,#10000,37,4,37,4)
-hasLocation(#20381,#20382)
-#20383=*
-regexpParseErrors(#20383,#20377,"expected '}'")
-#20384=@"loc,{#10000},37,3,37,3"
-locations_default(#20384,#10000,37,3,37,3)
-hasLocation(#20383,#20384)
-#20385=*
-stmts(#20385,2,#20001,37,"/a{b}/;")
-#20386=@"loc,{#10000},38,1,38,7"
-locations_default(#20386,#10000,38,1,38,7)
-hasLocation(#20385,#20386)
-stmtContainers(#20385,#20001)
-#20387=*
-exprs(#20387,5,#20385,0,"/a{b}/")
-#20388=@"loc,{#10000},38,1,38,6"
-locations_default(#20388,#10000,38,1,38,6)
-hasLocation(#20387,#20388)
-enclosingStmt(#20387,#20385)
-exprContainers(#20387,#20001)
-literals("/a{b}/","/a{b}/",#20387)
-#20389=*
-regexpterm(#20389,1,#20387,0,"a{b}")
-#20390=@"loc,{#10000},38,2,38,5"
-locations_default(#20390,#10000,38,2,38,5)
-hasLocation(#20389,#20390)
-#20391=*
-regexpterm(#20391,11,#20389,0,"a{")
-#20392=@"loc,{#10000},38,2,38,3"
-locations_default(#20392,#10000,38,2,38,3)
-hasLocation(#20391,#20392)
-isGreedy(#20391)
-rangeQuantifierLowerBound(#20391,0)
-#20393=*
-regexpterm(#20393,14,#20391,0,"a")
-#20394=@"loc,{#10000},38,2,38,2"
-locations_default(#20394,#10000,38,2,38,2)
-hasLocation(#20393,#20394)
-regexpConstValue(#20393,"a")
-#20395=*
-regexpterm(#20395,14,#20389,1,"b")
-#20396=@"loc,{#10000},38,4,38,4"
-locations_default(#20396,#10000,38,4,38,4)
-hasLocation(#20395,#20396)
-regexpConstValue(#20395,"b")
-#20397=*
-regexpterm(#20397,14,#20389,2,"}")
-#20398=@"loc,{#10000},38,5,38,5"
-locations_default(#20398,#10000,38,5,38,5)
-hasLocation(#20397,#20398)
-regexpConstValue(#20397,"}")
-#20399=*
-regexpParseErrors(#20399,#20389,"expected digit")
-hasLocation(#20399,#20396)
+#20262=*
+regexpterm(#20262,19,#20256,2,"\r")
+#20263=@"loc,{#10000},27,6,27,7"
+locations_default(#20263,#10000,27,6,27,7)
+hasLocation(#20262,#20263)
+regexpConstValue(#20262,"
")
+#20264=*
+regexpterm(#20264,19,#20256,3,"\f")
+#20265=@"loc,{#10000},27,8,27,9"
+locations_default(#20265,#10000,27,8,27,9)
+hasLocation(#20264,#20265)
+regexpConstValue(#20264,"")
+#20266=*
+regexpterm(#20266,19,#20256,4,"\v")
+#20267=@"loc,{#10000},27,10,27,11"
+locations_default(#20267,#10000,27,10,27,11)
+hasLocation(#20266,#20267)
+regexpConstValue(#20266,"")
+#20268=*
+stmts(#20268,2,#20001,27,"/\ca\cN/;")
+#20269=@"loc,{#10000},28,1,28,9"
+locations_default(#20269,#10000,28,1,28,9)
+hasLocation(#20268,#20269)
+stmtContainers(#20268,#20001)
+#20270=*
+exprs(#20270,5,#20268,0,"/\ca\cN/")
+#20271=@"loc,{#10000},28,1,28,8"
+locations_default(#20271,#10000,28,1,28,8)
+hasLocation(#20270,#20271)
+enclosingStmt(#20270,#20268)
+exprContainers(#20270,#20001)
+literals("/\ca\cN/","/\ca\cN/",#20270)
+#20272=*
+regexpterm(#20272,1,#20270,0,"\ca\cN")
+#20273=@"loc,{#10000},28,2,28,7"
+locations_default(#20273,#10000,28,2,28,7)
+hasLocation(#20272,#20273)
+#20274=*
+regexpterm(#20274,19,#20272,0,"\ca")
+#20275=@"loc,{#10000},28,2,28,4"
+locations_default(#20275,#10000,28,2,28,4)
+hasLocation(#20274,#20275)
+regexpConstValue(#20274,"")
+#20276=*
+regexpterm(#20276,19,#20272,1,"\cN")
+#20277=@"loc,{#10000},28,5,28,7"
+locations_default(#20277,#10000,28,5,28,7)
+hasLocation(#20276,#20277)
+regexpConstValue(#20276,"")
+#20278=*
+stmts(#20278,2,#20001,28,"/\w\S/;")
+#20279=@"loc,{#10000},29,1,29,7"
+locations_default(#20279,#10000,29,1,29,7)
+hasLocation(#20278,#20279)
+stmtContainers(#20278,#20001)
+#20280=*
+exprs(#20280,5,#20278,0,"/\w\S/")
+#20281=@"loc,{#10000},29,1,29,6"
+locations_default(#20281,#10000,29,1,29,6)
+hasLocation(#20280,#20281)
+enclosingStmt(#20280,#20278)
+exprContainers(#20280,#20001)
+literals("/\w\S/","/\w\S/",#20280)
+#20282=*
+regexpterm(#20282,1,#20280,0,"\w\S")
+#20283=@"loc,{#10000},29,2,29,5"
+locations_default(#20283,#10000,29,2,29,5)
+hasLocation(#20282,#20283)
+#20284=*
+regexpterm(#20284,20,#20282,0,"\w")
+#20285=@"loc,{#10000},29,2,29,3"
+locations_default(#20285,#10000,29,2,29,3)
+hasLocation(#20284,#20285)
+charClassEscape(#20284,"w")
+#20286=*
+regexpterm(#20286,20,#20282,1,"\S")
+#20287=@"loc,{#10000},29,4,29,5"
+locations_default(#20287,#10000,29,4,29,5)
+hasLocation(#20286,#20287)
+charClassEscape(#20286,"S")
+#20288=*
+stmts(#20288,2,#20001,29,"/\\/;")
+#20289=@"loc,{#10000},30,1,30,5"
+locations_default(#20289,#10000,30,1,30,5)
+hasLocation(#20288,#20289)
+stmtContainers(#20288,#20001)
+#20290=*
+exprs(#20290,5,#20288,0,"/\\/")
+#20291=@"loc,{#10000},30,1,30,4"
+locations_default(#20291,#10000,30,1,30,4)
+hasLocation(#20290,#20291)
+enclosingStmt(#20290,#20288)
+exprContainers(#20290,#20001)
+literals("/\\/","/\\/",#20290)
+#20292=*
+regexpterm(#20292,21,#20290,0,"\\")
+#20293=@"loc,{#10000},30,2,30,3"
+locations_default(#20293,#10000,30,2,30,3)
+hasLocation(#20292,#20293)
+regexpConstValue(#20292,"\")
+#20294=*
+stmts(#20294,2,#20001,30,"/[abc]/;")
+#20295=@"loc,{#10000},31,1,31,8"
+locations_default(#20295,#10000,31,1,31,8)
+hasLocation(#20294,#20295)
+stmtContainers(#20294,#20001)
+#20296=*
+exprs(#20296,5,#20294,0,"/[abc]/")
+#20297=@"loc,{#10000},31,1,31,7"
+locations_default(#20297,#10000,31,1,31,7)
+hasLocation(#20296,#20297)
+enclosingStmt(#20296,#20294)
+exprContainers(#20296,#20001)
+literals("/[abc]/","/[abc]/",#20296)
+#20298=*
+regexpterm(#20298,23,#20296,0,"[abc]")
+#20299=@"loc,{#10000},31,2,31,6"
+locations_default(#20299,#10000,31,2,31,6)
+hasLocation(#20298,#20299)
+#20300=*
+regexpterm(#20300,14,#20298,0,"a")
+#20301=@"loc,{#10000},31,3,31,3"
+locations_default(#20301,#10000,31,3,31,3)
+hasLocation(#20300,#20301)
+regexpConstValue(#20300,"a")
+#20302=*
+regexpterm(#20302,14,#20298,1,"b")
+#20303=@"loc,{#10000},31,4,31,4"
+locations_default(#20303,#10000,31,4,31,4)
+hasLocation(#20302,#20303)
+regexpConstValue(#20302,"b")
+#20304=*
+regexpterm(#20304,14,#20298,2,"c")
+#20305=@"loc,{#10000},31,5,31,5"
+locations_default(#20305,#10000,31,5,31,5)
+hasLocation(#20304,#20305)
+regexpConstValue(#20304,"c")
+#20306=*
+stmts(#20306,2,#20001,31,"/[a-z]/;")
+#20307=@"loc,{#10000},32,1,32,8"
+locations_default(#20307,#10000,32,1,32,8)
+hasLocation(#20306,#20307)
+stmtContainers(#20306,#20001)
+#20308=*
+exprs(#20308,5,#20306,0,"/[a-z]/")
+#20309=@"loc,{#10000},32,1,32,7"
+locations_default(#20309,#10000,32,1,32,7)
+hasLocation(#20308,#20309)
+enclosingStmt(#20308,#20306)
+exprContainers(#20308,#20001)
+literals("/[a-z]/","/[a-z]/",#20308)
+#20310=*
+regexpterm(#20310,23,#20308,0,"[a-z]")
+#20311=@"loc,{#10000},32,2,32,6"
+locations_default(#20311,#10000,32,2,32,6)
+hasLocation(#20310,#20311)
+#20312=*
+regexpterm(#20312,24,#20310,0,"a-z")
+#20313=@"loc,{#10000},32,3,32,5"
+locations_default(#20313,#10000,32,3,32,5)
+hasLocation(#20312,#20313)
+#20314=*
+regexpterm(#20314,14,#20312,0,"a")
+#20315=@"loc,{#10000},32,3,32,3"
+locations_default(#20315,#10000,32,3,32,3)
+hasLocation(#20314,#20315)
+regexpConstValue(#20314,"a")
+#20316=*
+regexpterm(#20316,14,#20312,1,"z")
+#20317=@"loc,{#10000},32,5,32,5"
+locations_default(#20317,#10000,32,5,32,5)
+hasLocation(#20316,#20317)
+regexpConstValue(#20316,"z")
+#20318=*
+stmts(#20318,2,#20001,32,"/[a-zA-Z]/;")
+#20319=@"loc,{#10000},33,1,33,11"
+locations_default(#20319,#10000,33,1,33,11)
+hasLocation(#20318,#20319)
+stmtContainers(#20318,#20001)
+#20320=*
+exprs(#20320,5,#20318,0,"/[a-zA-Z]/")
+#20321=@"loc,{#10000},33,1,33,10"
+locations_default(#20321,#10000,33,1,33,10)
+hasLocation(#20320,#20321)
+enclosingStmt(#20320,#20318)
+exprContainers(#20320,#20001)
+literals("/[a-zA-Z]/","/[a-zA-Z]/",#20320)
+#20322=*
+regexpterm(#20322,23,#20320,0,"[a-zA-Z]")
+#20323=@"loc,{#10000},33,2,33,9"
+locations_default(#20323,#10000,33,2,33,9)
+hasLocation(#20322,#20323)
+#20324=*
+regexpterm(#20324,24,#20322,0,"a-z")
+#20325=@"loc,{#10000},33,3,33,5"
+locations_default(#20325,#10000,33,3,33,5)
+hasLocation(#20324,#20325)
+#20326=*
+regexpterm(#20326,14,#20324,0,"a")
+#20327=@"loc,{#10000},33,3,33,3"
+locations_default(#20327,#10000,33,3,33,3)
+hasLocation(#20326,#20327)
+regexpConstValue(#20326,"a")
+#20328=*
+regexpterm(#20328,14,#20324,1,"z")
+#20329=@"loc,{#10000},33,5,33,5"
+locations_default(#20329,#10000,33,5,33,5)
+hasLocation(#20328,#20329)
+regexpConstValue(#20328,"z")
+#20330=*
+regexpterm(#20330,24,#20322,1,"A-Z")
+#20331=@"loc,{#10000},33,6,33,8"
+locations_default(#20331,#10000,33,6,33,8)
+hasLocation(#20330,#20331)
+#20332=*
+regexpterm(#20332,14,#20330,0,"A")
+#20333=@"loc,{#10000},33,6,33,6"
+locations_default(#20333,#10000,33,6,33,6)
+hasLocation(#20332,#20333)
+regexpConstValue(#20332,"A")
+#20334=*
+regexpterm(#20334,14,#20330,1,"Z")
+#20335=@"loc,{#10000},33,8,33,8"
+locations_default(#20335,#10000,33,8,33,8)
+hasLocation(#20334,#20335)
+regexpConstValue(#20334,"Z")
+#20336=*
+stmts(#20336,2,#20001,33,"/[-a-z]/;")
+#20337=@"loc,{#10000},34,1,34,9"
+locations_default(#20337,#10000,34,1,34,9)
+hasLocation(#20336,#20337)
+stmtContainers(#20336,#20001)
+#20338=*
+exprs(#20338,5,#20336,0,"/[-a-z]/")
+#20339=@"loc,{#10000},34,1,34,8"
+locations_default(#20339,#10000,34,1,34,8)
+hasLocation(#20338,#20339)
+enclosingStmt(#20338,#20336)
+exprContainers(#20338,#20001)
+literals("/[-a-z]/","/[-a-z]/",#20338)
+#20340=*
+regexpterm(#20340,23,#20338,0,"[-a-z]")
+#20341=@"loc,{#10000},34,2,34,7"
+locations_default(#20341,#10000,34,2,34,7)
+hasLocation(#20340,#20341)
+#20342=*
+regexpterm(#20342,14,#20340,0,"-")
+#20343=@"loc,{#10000},34,3,34,3"
+locations_default(#20343,#10000,34,3,34,3)
+hasLocation(#20342,#20343)
+regexpConstValue(#20342,"-")
+#20344=*
+regexpterm(#20344,24,#20340,1,"a-z")
+#20345=@"loc,{#10000},34,4,34,6"
+locations_default(#20345,#10000,34,4,34,6)
+hasLocation(#20344,#20345)
+#20346=*
+regexpterm(#20346,14,#20344,0,"a")
+#20347=@"loc,{#10000},34,4,34,4"
+locations_default(#20347,#10000,34,4,34,4)
+hasLocation(#20346,#20347)
+regexpConstValue(#20346,"a")
+#20348=*
+regexpterm(#20348,14,#20344,1,"z")
+#20349=@"loc,{#10000},34,6,34,6"
+locations_default(#20349,#10000,34,6,34,6)
+hasLocation(#20348,#20349)
+regexpConstValue(#20348,"z")
+#20350=*
+stmts(#20350,2,#20001,34,"/[^a-z]/;")
+#20351=@"loc,{#10000},35,1,35,9"
+locations_default(#20351,#10000,35,1,35,9)
+hasLocation(#20350,#20351)
+stmtContainers(#20350,#20001)
+#20352=*
+exprs(#20352,5,#20350,0,"/[^a-z]/")
+#20353=@"loc,{#10000},35,1,35,8"
+locations_default(#20353,#10000,35,1,35,8)
+hasLocation(#20352,#20353)
+enclosingStmt(#20352,#20350)
+exprContainers(#20352,#20001)
+literals("/[^a-z]/","/[^a-z]/",#20352)
+#20354=*
+regexpterm(#20354,23,#20352,0,"[^a-z]")
+#20355=@"loc,{#10000},35,2,35,7"
+locations_default(#20355,#10000,35,2,35,7)
+hasLocation(#20354,#20355)
+isInverted(#20354)
+#20356=*
+regexpterm(#20356,24,#20354,0,"a-z")
+#20357=@"loc,{#10000},35,4,35,6"
+locations_default(#20357,#10000,35,4,35,6)
+hasLocation(#20356,#20357)
+#20358=*
+regexpterm(#20358,14,#20356,0,"a")
+#20359=@"loc,{#10000},35,4,35,4"
+locations_default(#20359,#10000,35,4,35,4)
+hasLocation(#20358,#20359)
+regexpConstValue(#20358,"a")
+#20360=*
+regexpterm(#20360,14,#20356,1,"z")
+#20361=@"loc,{#10000},35,6,35,6"
+locations_default(#20361,#10000,35,6,35,6)
+hasLocation(#20360,#20361)
+regexpConstValue(#20360,"z")
+#20362=*
+stmts(#20362,2,#20001,35,"/[a\b\x0c]/;")
+#20363=@"loc,{#10000},36,1,36,12"
+locations_default(#20363,#10000,36,1,36,12)
+hasLocation(#20362,#20363)
+stmtContainers(#20362,#20001)
+#20364=*
+exprs(#20364,5,#20362,0,"/[a\b\x0c]/")
+#20365=@"loc,{#10000},36,1,36,11"
+locations_default(#20365,#10000,36,1,36,11)
+hasLocation(#20364,#20365)
+enclosingStmt(#20364,#20362)
+exprContainers(#20364,#20001)
+literals("/[a\b\x0c]/","/[a\b\x0c]/",#20364)
+#20366=*
+regexpterm(#20366,23,#20364,0,"[a\b\x0c]")
+#20367=@"loc,{#10000},36,2,36,10"
+locations_default(#20367,#10000,36,2,36,10)
+hasLocation(#20366,#20367)
+#20368=*
+regexpterm(#20368,14,#20366,0,"a")
+#20369=@"loc,{#10000},36,3,36,3"
+locations_default(#20369,#10000,36,3,36,3)
+hasLocation(#20368,#20369)
+regexpConstValue(#20368,"a")
+#20370=*
+regexpterm(#20370,19,#20366,1,"\b")
+#20371=@"loc,{#10000},36,4,36,5"
+locations_default(#20371,#10000,36,4,36,5)
+hasLocation(#20370,#20371)
+regexpConstValue(#20370,"")
+#20372=*
+regexpterm(#20372,15,#20366,2,"\x0c")
+#20373=@"loc,{#10000},36,6,36,9"
+locations_default(#20373,#10000,36,6,36,9)
+hasLocation(#20372,#20373)
+regexpConstValue(#20372,"")
+#20374=*
+stmts(#20374,2,#20001,36,"/a{/;")
+#20375=@"loc,{#10000},37,1,37,5"
+locations_default(#20375,#10000,37,1,37,5)
+hasLocation(#20374,#20375)
+stmtContainers(#20374,#20001)
+#20376=*
+exprs(#20376,5,#20374,0,"/a{/")
+#20377=@"loc,{#10000},37,1,37,4"
+locations_default(#20377,#10000,37,1,37,4)
+hasLocation(#20376,#20377)
+enclosingStmt(#20376,#20374)
+exprContainers(#20376,#20001)
+literals("/a{/","/a{/",#20376)
+#20378=*
+regexpterm(#20378,11,#20376,0,"a{")
+#20379=@"loc,{#10000},37,2,37,3"
+locations_default(#20379,#10000,37,2,37,3)
+hasLocation(#20378,#20379)
+isGreedy(#20378)
+rangeQuantifierLowerBound(#20378,0)
+#20380=*
+regexpterm(#20380,14,#20378,0,"a")
+#20381=@"loc,{#10000},37,2,37,2"
+locations_default(#20381,#10000,37,2,37,2)
+hasLocation(#20380,#20381)
+regexpConstValue(#20380,"a")
+#20382=*
+regexpParseErrors(#20382,#20378,"expected digit")
+#20383=@"loc,{#10000},37,4,37,4"
+locations_default(#20383,#10000,37,4,37,4)
+hasLocation(#20382,#20383)
+#20384=*
+regexpParseErrors(#20384,#20378,"expected '}'")
+#20385=@"loc,{#10000},37,3,37,3"
+locations_default(#20385,#10000,37,3,37,3)
+hasLocation(#20384,#20385)
+#20386=*
+stmts(#20386,2,#20001,37,"/a{b}/;")
+#20387=@"loc,{#10000},38,1,38,7"
+locations_default(#20387,#10000,38,1,38,7)
+hasLocation(#20386,#20387)
+stmtContainers(#20386,#20001)
+#20388=*
+exprs(#20388,5,#20386,0,"/a{b}/")
+#20389=@"loc,{#10000},38,1,38,6"
+locations_default(#20389,#10000,38,1,38,6)
+hasLocation(#20388,#20389)
+enclosingStmt(#20388,#20386)
+exprContainers(#20388,#20001)
+literals("/a{b}/","/a{b}/",#20388)
+#20390=*
+regexpterm(#20390,1,#20388,0,"a{b}")
+#20391=@"loc,{#10000},38,2,38,5"
+locations_default(#20391,#10000,38,2,38,5)
+hasLocation(#20390,#20391)
+#20392=*
+regexpterm(#20392,11,#20390,0,"a{")
+#20393=@"loc,{#10000},38,2,38,3"
+locations_default(#20393,#10000,38,2,38,3)
+hasLocation(#20392,#20393)
+isGreedy(#20392)
+rangeQuantifierLowerBound(#20392,0)
+#20394=*
+regexpterm(#20394,14,#20392,0,"a")
+#20395=@"loc,{#10000},38,2,38,2"
+locations_default(#20395,#10000,38,2,38,2)
+hasLocation(#20394,#20395)
+regexpConstValue(#20394,"a")
+#20396=*
+regexpterm(#20396,14,#20390,1,"b")
+#20397=@"loc,{#10000},38,4,38,4"
+locations_default(#20397,#10000,38,4,38,4)
+hasLocation(#20396,#20397)
+regexpConstValue(#20396,"b")
+#20398=*
+regexpterm(#20398,14,#20390,2,"}")
+#20399=@"loc,{#10000},38,5,38,5"
+locations_default(#20399,#10000,38,5,38,5)
+hasLocation(#20398,#20399)
+regexpConstValue(#20398,"}")
#20400=*
-regexpParseErrors(#20400,#20389,"expected '}'")
-#20401=@"loc,{#10000},38,3,38,3"
-locations_default(#20401,#10000,38,3,38,3)
-hasLocation(#20400,#20401)
-#20402=*
-regexpParseErrors(#20402,#20389,"unexpected character")
-hasLocation(#20402,#20398)
+regexpParseErrors(#20400,#20390,"expected digit")
+hasLocation(#20400,#20397)
+#20401=*
+regexpParseErrors(#20401,#20390,"expected '}'")
+#20402=@"loc,{#10000},38,3,38,3"
+locations_default(#20402,#10000,38,3,38,3)
+hasLocation(#20401,#20402)
#20403=*
-stmts(#20403,2,#20001,38,"/a{2/;")
-#20404=@"loc,{#10000},39,1,39,6"
-locations_default(#20404,#10000,39,1,39,6)
-hasLocation(#20403,#20404)
-stmtContainers(#20403,#20001)
-#20405=*
-exprs(#20405,5,#20403,0,"/a{2/")
-#20406=@"loc,{#10000},39,1,39,5"
-locations_default(#20406,#10000,39,1,39,5)
-hasLocation(#20405,#20406)
-enclosingStmt(#20405,#20403)
-exprContainers(#20405,#20001)
-literals("/a{2/","/a{2/",#20405)
-#20407=*
-regexpterm(#20407,11,#20405,0,"a{2")
-#20408=@"loc,{#10000},39,2,39,4"
-locations_default(#20408,#10000,39,2,39,4)
-hasLocation(#20407,#20408)
-isGreedy(#20407)
-rangeQuantifierLowerBound(#20407,2)
-#20409=*
-regexpterm(#20409,14,#20407,0,"a")
-#20410=@"loc,{#10000},39,2,39,2"
-locations_default(#20410,#10000,39,2,39,2)
-hasLocation(#20409,#20410)
-regexpConstValue(#20409,"a")
-#20411=*
-regexpParseErrors(#20411,#20407,"expected '}'")
-#20412=@"loc,{#10000},39,4,39,4"
-locations_default(#20412,#10000,39,4,39,4)
-hasLocation(#20411,#20412)
-#20413=*
-stmts(#20413,2,#20001,39,"/\xa/;")
-#20414=@"loc,{#10000},40,1,40,6"
-locations_default(#20414,#10000,40,1,40,6)
-hasLocation(#20413,#20414)
-stmtContainers(#20413,#20001)
-#20415=*
-exprs(#20415,5,#20413,0,"/\xa/")
-#20416=@"loc,{#10000},40,1,40,5"
-locations_default(#20416,#10000,40,1,40,5)
-hasLocation(#20415,#20416)
-enclosingStmt(#20415,#20413)
-exprContainers(#20415,#20001)
-literals("/\xa/","/\xa/",#20415)
-#20417=*
-regexpterm(#20417,15,#20415,0,"\xa")
-#20418=@"loc,{#10000},40,2,40,4"
-locations_default(#20418,#10000,40,2,40,4)
-hasLocation(#20417,#20418)
-regexpConstValue(#20417,"
+regexpParseErrors(#20403,#20390,"unexpected character")
+hasLocation(#20403,#20399)
+#20404=*
+stmts(#20404,2,#20001,38,"/a{2/;")
+#20405=@"loc,{#10000},39,1,39,6"
+locations_default(#20405,#10000,39,1,39,6)
+hasLocation(#20404,#20405)
+stmtContainers(#20404,#20001)
+#20406=*
+exprs(#20406,5,#20404,0,"/a{2/")
+#20407=@"loc,{#10000},39,1,39,5"
+locations_default(#20407,#10000,39,1,39,5)
+hasLocation(#20406,#20407)
+enclosingStmt(#20406,#20404)
+exprContainers(#20406,#20001)
+literals("/a{2/","/a{2/",#20406)
+#20408=*
+regexpterm(#20408,11,#20406,0,"a{2")
+#20409=@"loc,{#10000},39,2,39,4"
+locations_default(#20409,#10000,39,2,39,4)
+hasLocation(#20408,#20409)
+isGreedy(#20408)
+rangeQuantifierLowerBound(#20408,2)
+#20410=*
+regexpterm(#20410,14,#20408,0,"a")
+#20411=@"loc,{#10000},39,2,39,2"
+locations_default(#20411,#10000,39,2,39,2)
+hasLocation(#20410,#20411)
+regexpConstValue(#20410,"a")
+#20412=*
+regexpParseErrors(#20412,#20408,"expected '}'")
+#20413=@"loc,{#10000},39,4,39,4"
+locations_default(#20413,#10000,39,4,39,4)
+hasLocation(#20412,#20413)
+#20414=*
+stmts(#20414,2,#20001,39,"/\xa/;")
+#20415=@"loc,{#10000},40,1,40,6"
+locations_default(#20415,#10000,40,1,40,6)
+hasLocation(#20414,#20415)
+stmtContainers(#20414,#20001)
+#20416=*
+exprs(#20416,5,#20414,0,"/\xa/")
+#20417=@"loc,{#10000},40,1,40,5"
+locations_default(#20417,#10000,40,1,40,5)
+hasLocation(#20416,#20417)
+enclosingStmt(#20416,#20414)
+exprContainers(#20416,#20001)
+literals("/\xa/","/\xa/",#20416)
+#20418=*
+regexpterm(#20418,15,#20416,0,"\xa")
+#20419=@"loc,{#10000},40,2,40,4"
+locations_default(#20419,#10000,40,2,40,4)
+hasLocation(#20418,#20419)
+regexpConstValue(#20418,"
")
-#20419=*
-regexpParseErrors(#20419,#20417,"unexpected end of regular expression")
-#20420=@"loc,{#10000},40,5,40,5"
-locations_default(#20420,#10000,40,5,40,5)
-hasLocation(#20419,#20420)
-#20421=*
-stmts(#20421,2,#20001,40,"/\c0/;")
-#20422=@"loc,{#10000},41,1,41,6"
-locations_default(#20422,#10000,41,1,41,6)
-hasLocation(#20421,#20422)
-stmtContainers(#20421,#20001)
-#20423=*
-exprs(#20423,5,#20421,0,"/\c0/")
-#20424=@"loc,{#10000},41,1,41,5"
-locations_default(#20424,#10000,41,1,41,5)
-hasLocation(#20423,#20424)
-enclosingStmt(#20423,#20421)
-exprContainers(#20423,#20001)
-literals("/\c0/","/\c0/",#20423)
-#20425=*
-regexpterm(#20425,19,#20423,0,"\c0")
-#20426=@"loc,{#10000},41,2,41,4"
-locations_default(#20426,#10000,41,2,41,4)
-hasLocation(#20425,#20426)
-regexpConstValue(#20425,"")
-#20427=*
-regexpParseErrors(#20427,#20425,"expected control letter")
-#20428=@"loc,{#10000},41,4,41,4"
-locations_default(#20428,#10000,41,4,41,4)
-hasLocation(#20427,#20428)
-#20429=*
-stmts(#20429,2,#20001,41,"/[]/;")
-#20430=@"loc,{#10000},42,1,42,5"
-locations_default(#20430,#10000,42,1,42,5)
-hasLocation(#20429,#20430)
-stmtContainers(#20429,#20001)
-#20431=*
-exprs(#20431,5,#20429,0,"/[]/")
-#20432=@"loc,{#10000},42,1,42,4"
-locations_default(#20432,#10000,42,1,42,4)
-hasLocation(#20431,#20432)
-enclosingStmt(#20431,#20429)
-exprContainers(#20431,#20001)
-literals("/[]/","/[]/",#20431)
-#20433=*
-regexpterm(#20433,23,#20431,0,"[]")
-#20434=@"loc,{#10000},42,2,42,3"
-locations_default(#20434,#10000,42,2,42,3)
-hasLocation(#20433,#20434)
-#20435=*
-stmts(#20435,2,#20001,42,"/[^]/;")
-#20436=@"loc,{#10000},43,1,43,6"
-locations_default(#20436,#10000,43,1,43,6)
-hasLocation(#20435,#20436)
-stmtContainers(#20435,#20001)
-#20437=*
-exprs(#20437,5,#20435,0,"/[^]/")
-#20438=@"loc,{#10000},43,1,43,5"
-locations_default(#20438,#10000,43,1,43,5)
-hasLocation(#20437,#20438)
-enclosingStmt(#20437,#20435)
-exprContainers(#20437,#20001)
-literals("/[^]/","/[^]/",#20437)
-#20439=*
-regexpterm(#20439,23,#20437,0,"[^]")
-#20440=@"loc,{#10000},43,2,43,4"
-locations_default(#20440,#10000,43,2,43,4)
-hasLocation(#20439,#20440)
-isInverted(#20439)
-#20441=*
-stmts(#20441,2,#20001,43,"//;")
-#20442=@"loc,{#10000},44,1,44,60"
-locations_default(#20442,#10000,44,1,44,60)
-hasLocation(#20441,#20442)
-stmtContainers(#20441,#20001)
-#20443=*
-exprs(#20443,5,#20441,0,"//")
-#20444=@"loc,{#10000},44,1,44,59"
-locations_default(#20444,#10000,44,1,44,59)
-hasLocation(#20443,#20444)
-enclosingStmt(#20443,#20441)
-exprContainers(#20443,#20001)
-literals("/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/","/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/",#20443)
-#20445=*
-regexpterm(#20445,1,#20443,0,"]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>")
-#20446=@"loc,{#10000},44,2,44,58"
-locations_default(#20446,#10000,44,2,44,58)
-hasLocation(#20445,#20446)
-#20447=*
-regexpterm(#20447,14,#20445,0,"<")
-#20448=@"loc,{#10000},44,2,44,2"
-locations_default(#20448,#10000,44,2,44,2)
-hasLocation(#20447,#20448)
-regexpConstValue(#20447,"<")
-#20449=*
-regexpterm(#20449,14,#20445,1,"t")
-#20450=@"loc,{#10000},44,3,44,3"
-locations_default(#20450,#10000,44,3,44,3)
-hasLocation(#20449,#20450)
-regexpConstValue(#20449,"t")
-#20451=*
-regexpterm(#20451,14,#20445,2,"p")
-#20452=@"loc,{#10000},44,4,44,4"
-locations_default(#20452,#10000,44,4,44,4)
-hasLocation(#20451,#20452)
-regexpConstValue(#20451,"p")
-#20453=*
-regexpterm(#20453,14,#20445,3,"l")
-#20454=@"loc,{#10000},44,5,44,5"
-locations_default(#20454,#10000,44,5,44,5)
-hasLocation(#20453,#20454)
-regexpConstValue(#20453,"l")
-#20455=*
-regexpterm(#20455,4,#20445,4,"\b")
-#20456=@"loc,{#10000},44,6,44,7"
-locations_default(#20456,#10000,44,6,44,7)
-hasLocation(#20455,#20456)
-#20457=*
-regexpterm(#20457,8,#20445,5,"[^>]*")
-#20458=@"loc,{#10000},44,8,44,12"
-locations_default(#20458,#10000,44,8,44,12)
-hasLocation(#20457,#20458)
-isGreedy(#20457)
-#20459=*
-regexpterm(#20459,23,#20457,0,"[^>]")
-#20460=@"loc,{#10000},44,8,44,11"
-locations_default(#20460,#10000,44,8,44,11)
-hasLocation(#20459,#20460)
-isInverted(#20459)
-#20461=*
-regexpterm(#20461,14,#20459,0,">")
-#20462=@"loc,{#10000},44,10,44,10"
-locations_default(#20462,#10000,44,10,44,10)
-hasLocation(#20461,#20462)
-regexpConstValue(#20461,">")
-#20463=*
-regexpterm(#20463,14,#20445,6,">")
-#20464=@"loc,{#10000},44,13,44,13"
-locations_default(#20464,#10000,44,13,44,13)
-hasLocation(#20463,#20464)
-regexpConstValue(#20463,">")
-#20465=*
-regexpterm(#20465,13,#20445,7,"((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)")
-#20466=@"loc,{#10000},44,14,44,51"
-locations_default(#20466,#10000,44,14,44,51)
-hasLocation(#20465,#20466)
-isCapture(#20465,1)
-#20467=*
-regexpterm(#20467,8,#20465,0,"(?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?")
-#20468=@"loc,{#10000},44,15,44,50"
-locations_default(#20468,#10000,44,15,44,50)
-hasLocation(#20467,#20468)
-#20469=*
-regexpterm(#20469,13,#20467,0,"(?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))")
-#20470=@"loc,{#10000},44,15,44,48"
-locations_default(#20470,#10000,44,15,44,48)
-hasLocation(#20469,#20470)
-#20471=*
-regexpterm(#20471,0,#20469,0,"(?=([^<]+))\2|<(?!tpl\b[^>]*>)")
-#20472=@"loc,{#10000},44,18,44,47"
-locations_default(#20472,#10000,44,18,44,47)
-hasLocation(#20471,#20472)
-#20473=*
-regexpterm(#20473,1,#20471,0,"(?=([^<]+))\2")
-#20474=@"loc,{#10000},44,18,44,30"
-locations_default(#20474,#10000,44,18,44,30)
-hasLocation(#20473,#20474)
-#20475=*
-regexpterm(#20475,6,#20473,0,"(?=([^<]+))")
-#20476=@"loc,{#10000},44,18,44,28"
-locations_default(#20476,#10000,44,18,44,28)
-hasLocation(#20475,#20476)
-#20477=*
-regexpterm(#20477,13,#20475,0,"([^<]+)")
-#20478=@"loc,{#10000},44,21,44,27"
-locations_default(#20478,#10000,44,21,44,27)
-hasLocation(#20477,#20478)
-isCapture(#20477,2)
-#20479=*
-regexpterm(#20479,9,#20477,0,"[^<]+")
-#20480=@"loc,{#10000},44,22,44,26"
-locations_default(#20480,#10000,44,22,44,26)
-hasLocation(#20479,#20480)
-isGreedy(#20479)
-#20481=*
-regexpterm(#20481,23,#20479,0,"[^<]")
-#20482=@"loc,{#10000},44,22,44,25"
-locations_default(#20482,#10000,44,22,44,25)
-hasLocation(#20481,#20482)
-isInverted(#20481)
-#20483=*
-regexpterm(#20483,14,#20481,0,"<")
-#20484=@"loc,{#10000},44,24,44,24"
-locations_default(#20484,#10000,44,24,44,24)
-hasLocation(#20483,#20484)
-regexpConstValue(#20483,"<")
-#20485=*
-regexpterm(#20485,22,#20473,1,"\2")
-#20486=@"loc,{#10000},44,29,44,30"
-locations_default(#20486,#10000,44,29,44,30)
-hasLocation(#20485,#20486)
-backref(#20485,2)
-#20487=*
-regexpterm(#20487,1,#20471,1,"<(?!tpl\b[^>]*>)")
-#20488=@"loc,{#10000},44,32,44,47"
-locations_default(#20488,#10000,44,32,44,47)
-hasLocation(#20487,#20488)
-#20489=*
-regexpterm(#20489,14,#20487,0,"<")
-#20490=@"loc,{#10000},44,32,44,32"
-locations_default(#20490,#10000,44,32,44,32)
-hasLocation(#20489,#20490)
-regexpConstValue(#20489,"<")
-#20491=*
-regexpterm(#20491,7,#20487,1,"(?!tpl\b[^>]*>)")
-#20492=@"loc,{#10000},44,33,44,47"
-locations_default(#20492,#10000,44,33,44,47)
-hasLocation(#20491,#20492)
-#20493=*
-regexpterm(#20493,1,#20491,0,"tpl\b[^>]*>")
-#20494=@"loc,{#10000},44,36,44,46"
-locations_default(#20494,#10000,44,36,44,46)
-hasLocation(#20493,#20494)
-#20495=*
-regexpterm(#20495,14,#20493,0,"t")
-#20496=@"loc,{#10000},44,36,44,36"
-locations_default(#20496,#10000,44,36,44,36)
-hasLocation(#20495,#20496)
-regexpConstValue(#20495,"t")
-#20497=*
-regexpterm(#20497,14,#20493,1,"p")
-#20498=@"loc,{#10000},44,37,44,37"
-locations_default(#20498,#10000,44,37,44,37)
-hasLocation(#20497,#20498)
-regexpConstValue(#20497,"p")
-#20499=*
-regexpterm(#20499,14,#20493,2,"l")
-#20500=@"loc,{#10000},44,38,44,38"
-locations_default(#20500,#10000,44,38,44,38)
-hasLocation(#20499,#20500)
-regexpConstValue(#20499,"l")
-#20501=*
-regexpterm(#20501,4,#20493,3,"\b")
-#20502=@"loc,{#10000},44,39,44,40"
-locations_default(#20502,#10000,44,39,44,40)
-hasLocation(#20501,#20502)
-#20503=*
-regexpterm(#20503,8,#20493,4,"[^>]*")
-#20504=@"loc,{#10000},44,41,44,45"
-locations_default(#20504,#10000,44,41,44,45)
-hasLocation(#20503,#20504)
-isGreedy(#20503)
-#20505=*
-regexpterm(#20505,23,#20503,0,"[^>]")
-#20506=@"loc,{#10000},44,41,44,44"
-locations_default(#20506,#10000,44,41,44,44)
-hasLocation(#20505,#20506)
-isInverted(#20505)
-#20507=*
-regexpterm(#20507,14,#20505,0,">")
-#20508=@"loc,{#10000},44,43,44,43"
-locations_default(#20508,#10000,44,43,44,43)
-hasLocation(#20507,#20508)
-regexpConstValue(#20507,">")
-#20509=*
-regexpterm(#20509,14,#20493,5,">")
-#20510=@"loc,{#10000},44,46,44,46"
-locations_default(#20510,#10000,44,46,44,46)
-hasLocation(#20509,#20510)
-regexpConstValue(#20509,">")
-#20511=*
-regexpterm(#20511,14,#20445,8,"<")
-#20512=@"loc,{#10000},44,52,44,52"
-locations_default(#20512,#10000,44,52,44,52)
-hasLocation(#20511,#20512)
-regexpConstValue(#20511,"<")
-#20513=*
-regexpterm(#20513,21,#20445,9,"\/")
-#20514=@"loc,{#10000},44,53,44,54"
-locations_default(#20514,#10000,44,53,44,54)
-hasLocation(#20513,#20514)
-regexpConstValue(#20513,"/")
-#20515=*
-regexpterm(#20515,14,#20445,10,"t")
-#20516=@"loc,{#10000},44,55,44,55"
-locations_default(#20516,#10000,44,55,44,55)
-hasLocation(#20515,#20516)
-regexpConstValue(#20515,"t")
-#20517=*
-regexpterm(#20517,14,#20445,11,"p")
-#20518=@"loc,{#10000},44,56,44,56"
-locations_default(#20518,#10000,44,56,44,56)
-hasLocation(#20517,#20518)
-regexpConstValue(#20517,"p")
-#20519=*
-regexpterm(#20519,14,#20445,12,"l")
-#20520=@"loc,{#10000},44,57,44,57"
-locations_default(#20520,#10000,44,57,44,57)
-hasLocation(#20519,#20520)
-regexpConstValue(#20519,"l")
-#20521=*
-regexpterm(#20521,14,#20445,13,">")
-#20522=@"loc,{#10000},44,58,44,58"
-locations_default(#20522,#10000,44,58,44,58)
-hasLocation(#20521,#20522)
-regexpConstValue(#20521,">")
-#20523=*
-lines(#20523,#20001,"/t/;","
-")
-hasLocation(#20523,#20004)
+#20420=*
+regexpParseErrors(#20420,#20418,"unexpected end of regular expression")
+#20421=@"loc,{#10000},40,5,40,5"
+locations_default(#20421,#10000,40,5,40,5)
+hasLocation(#20420,#20421)
+#20422=*
+stmts(#20422,2,#20001,40,"/\c0/;")
+#20423=@"loc,{#10000},41,1,41,6"
+locations_default(#20423,#10000,41,1,41,6)
+hasLocation(#20422,#20423)
+stmtContainers(#20422,#20001)
+#20424=*
+exprs(#20424,5,#20422,0,"/\c0/")
+#20425=@"loc,{#10000},41,1,41,5"
+locations_default(#20425,#10000,41,1,41,5)
+hasLocation(#20424,#20425)
+enclosingStmt(#20424,#20422)
+exprContainers(#20424,#20001)
+literals("/\c0/","/\c0/",#20424)
+#20426=*
+regexpterm(#20426,19,#20424,0,"\c0")
+#20427=@"loc,{#10000},41,2,41,4"
+locations_default(#20427,#10000,41,2,41,4)
+hasLocation(#20426,#20427)
+regexpConstValue(#20426,"")
+#20428=*
+regexpParseErrors(#20428,#20426,"expected control letter")
+#20429=@"loc,{#10000},41,4,41,4"
+locations_default(#20429,#10000,41,4,41,4)
+hasLocation(#20428,#20429)
+#20430=*
+stmts(#20430,2,#20001,41,"/[]/;")
+#20431=@"loc,{#10000},42,1,42,5"
+locations_default(#20431,#10000,42,1,42,5)
+hasLocation(#20430,#20431)
+stmtContainers(#20430,#20001)
+#20432=*
+exprs(#20432,5,#20430,0,"/[]/")
+#20433=@"loc,{#10000},42,1,42,4"
+locations_default(#20433,#10000,42,1,42,4)
+hasLocation(#20432,#20433)
+enclosingStmt(#20432,#20430)
+exprContainers(#20432,#20001)
+literals("/[]/","/[]/",#20432)
+#20434=*
+regexpterm(#20434,23,#20432,0,"[]")
+#20435=@"loc,{#10000},42,2,42,3"
+locations_default(#20435,#10000,42,2,42,3)
+hasLocation(#20434,#20435)
+#20436=*
+stmts(#20436,2,#20001,42,"/[^]/;")
+#20437=@"loc,{#10000},43,1,43,6"
+locations_default(#20437,#10000,43,1,43,6)
+hasLocation(#20436,#20437)
+stmtContainers(#20436,#20001)
+#20438=*
+exprs(#20438,5,#20436,0,"/[^]/")
+#20439=@"loc,{#10000},43,1,43,5"
+locations_default(#20439,#10000,43,1,43,5)
+hasLocation(#20438,#20439)
+enclosingStmt(#20438,#20436)
+exprContainers(#20438,#20001)
+literals("/[^]/","/[^]/",#20438)
+#20440=*
+regexpterm(#20440,23,#20438,0,"[^]")
+#20441=@"loc,{#10000},43,2,43,4"
+locations_default(#20441,#10000,43,2,43,4)
+hasLocation(#20440,#20441)
+isInverted(#20440)
+#20442=*
+stmts(#20442,2,#20001,43,"//;")
+#20443=@"loc,{#10000},44,1,44,60"
+locations_default(#20443,#10000,44,1,44,60)
+hasLocation(#20442,#20443)
+stmtContainers(#20442,#20001)
+#20444=*
+exprs(#20444,5,#20442,0,"//")
+#20445=@"loc,{#10000},44,1,44,59"
+locations_default(#20445,#10000,44,1,44,59)
+hasLocation(#20444,#20445)
+enclosingStmt(#20444,#20442)
+exprContainers(#20444,#20001)
+literals("/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/","/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/",#20444)
+#20446=*
+regexpterm(#20446,1,#20444,0,"]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>")
+#20447=@"loc,{#10000},44,2,44,58"
+locations_default(#20447,#10000,44,2,44,58)
+hasLocation(#20446,#20447)
+#20448=*
+regexpterm(#20448,14,#20446,0,"<")
+#20449=@"loc,{#10000},44,2,44,2"
+locations_default(#20449,#10000,44,2,44,2)
+hasLocation(#20448,#20449)
+regexpConstValue(#20448,"<")
+#20450=*
+regexpterm(#20450,14,#20446,1,"t")
+#20451=@"loc,{#10000},44,3,44,3"
+locations_default(#20451,#10000,44,3,44,3)
+hasLocation(#20450,#20451)
+regexpConstValue(#20450,"t")
+#20452=*
+regexpterm(#20452,14,#20446,2,"p")
+#20453=@"loc,{#10000},44,4,44,4"
+locations_default(#20453,#10000,44,4,44,4)
+hasLocation(#20452,#20453)
+regexpConstValue(#20452,"p")
+#20454=*
+regexpterm(#20454,14,#20446,3,"l")
+#20455=@"loc,{#10000},44,5,44,5"
+locations_default(#20455,#10000,44,5,44,5)
+hasLocation(#20454,#20455)
+regexpConstValue(#20454,"l")
+#20456=*
+regexpterm(#20456,4,#20446,4,"\b")
+#20457=@"loc,{#10000},44,6,44,7"
+locations_default(#20457,#10000,44,6,44,7)
+hasLocation(#20456,#20457)
+#20458=*
+regexpterm(#20458,8,#20446,5,"[^>]*")
+#20459=@"loc,{#10000},44,8,44,12"
+locations_default(#20459,#10000,44,8,44,12)
+hasLocation(#20458,#20459)
+isGreedy(#20458)
+#20460=*
+regexpterm(#20460,23,#20458,0,"[^>]")
+#20461=@"loc,{#10000},44,8,44,11"
+locations_default(#20461,#10000,44,8,44,11)
+hasLocation(#20460,#20461)
+isInverted(#20460)
+#20462=*
+regexpterm(#20462,14,#20460,0,">")
+#20463=@"loc,{#10000},44,10,44,10"
+locations_default(#20463,#10000,44,10,44,10)
+hasLocation(#20462,#20463)
+regexpConstValue(#20462,">")
+#20464=*
+regexpterm(#20464,14,#20446,6,">")
+#20465=@"loc,{#10000},44,13,44,13"
+locations_default(#20465,#10000,44,13,44,13)
+hasLocation(#20464,#20465)
+regexpConstValue(#20464,">")
+#20466=*
+regexpterm(#20466,13,#20446,7,"((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)")
+#20467=@"loc,{#10000},44,14,44,51"
+locations_default(#20467,#10000,44,14,44,51)
+hasLocation(#20466,#20467)
+isCapture(#20466,1)
+#20468=*
+regexpterm(#20468,8,#20466,0,"(?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?")
+#20469=@"loc,{#10000},44,15,44,50"
+locations_default(#20469,#10000,44,15,44,50)
+hasLocation(#20468,#20469)
+#20470=*
+regexpterm(#20470,13,#20468,0,"(?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))")
+#20471=@"loc,{#10000},44,15,44,48"
+locations_default(#20471,#10000,44,15,44,48)
+hasLocation(#20470,#20471)
+#20472=*
+regexpterm(#20472,0,#20470,0,"(?=([^<]+))\2|<(?!tpl\b[^>]*>)")
+#20473=@"loc,{#10000},44,18,44,47"
+locations_default(#20473,#10000,44,18,44,47)
+hasLocation(#20472,#20473)
+#20474=*
+regexpterm(#20474,1,#20472,0,"(?=([^<]+))\2")
+#20475=@"loc,{#10000},44,18,44,30"
+locations_default(#20475,#10000,44,18,44,30)
+hasLocation(#20474,#20475)
+#20476=*
+regexpterm(#20476,6,#20474,0,"(?=([^<]+))")
+#20477=@"loc,{#10000},44,18,44,28"
+locations_default(#20477,#10000,44,18,44,28)
+hasLocation(#20476,#20477)
+#20478=*
+regexpterm(#20478,13,#20476,0,"([^<]+)")
+#20479=@"loc,{#10000},44,21,44,27"
+locations_default(#20479,#10000,44,21,44,27)
+hasLocation(#20478,#20479)
+isCapture(#20478,2)
+#20480=*
+regexpterm(#20480,9,#20478,0,"[^<]+")
+#20481=@"loc,{#10000},44,22,44,26"
+locations_default(#20481,#10000,44,22,44,26)
+hasLocation(#20480,#20481)
+isGreedy(#20480)
+#20482=*
+regexpterm(#20482,23,#20480,0,"[^<]")
+#20483=@"loc,{#10000},44,22,44,25"
+locations_default(#20483,#10000,44,22,44,25)
+hasLocation(#20482,#20483)
+isInverted(#20482)
+#20484=*
+regexpterm(#20484,14,#20482,0,"<")
+#20485=@"loc,{#10000},44,24,44,24"
+locations_default(#20485,#10000,44,24,44,24)
+hasLocation(#20484,#20485)
+regexpConstValue(#20484,"<")
+#20486=*
+regexpterm(#20486,22,#20474,1,"\2")
+#20487=@"loc,{#10000},44,29,44,30"
+locations_default(#20487,#10000,44,29,44,30)
+hasLocation(#20486,#20487)
+backref(#20486,2)
+#20488=*
+regexpterm(#20488,1,#20472,1,"<(?!tpl\b[^>]*>)")
+#20489=@"loc,{#10000},44,32,44,47"
+locations_default(#20489,#10000,44,32,44,47)
+hasLocation(#20488,#20489)
+#20490=*
+regexpterm(#20490,14,#20488,0,"<")
+#20491=@"loc,{#10000},44,32,44,32"
+locations_default(#20491,#10000,44,32,44,32)
+hasLocation(#20490,#20491)
+regexpConstValue(#20490,"<")
+#20492=*
+regexpterm(#20492,7,#20488,1,"(?!tpl\b[^>]*>)")
+#20493=@"loc,{#10000},44,33,44,47"
+locations_default(#20493,#10000,44,33,44,47)
+hasLocation(#20492,#20493)
+#20494=*
+regexpterm(#20494,1,#20492,0,"tpl\b[^>]*>")
+#20495=@"loc,{#10000},44,36,44,46"
+locations_default(#20495,#10000,44,36,44,46)
+hasLocation(#20494,#20495)
+#20496=*
+regexpterm(#20496,14,#20494,0,"t")
+#20497=@"loc,{#10000},44,36,44,36"
+locations_default(#20497,#10000,44,36,44,36)
+hasLocation(#20496,#20497)
+regexpConstValue(#20496,"t")
+#20498=*
+regexpterm(#20498,14,#20494,1,"p")
+#20499=@"loc,{#10000},44,37,44,37"
+locations_default(#20499,#10000,44,37,44,37)
+hasLocation(#20498,#20499)
+regexpConstValue(#20498,"p")
+#20500=*
+regexpterm(#20500,14,#20494,2,"l")
+#20501=@"loc,{#10000},44,38,44,38"
+locations_default(#20501,#10000,44,38,44,38)
+hasLocation(#20500,#20501)
+regexpConstValue(#20500,"l")
+#20502=*
+regexpterm(#20502,4,#20494,3,"\b")
+#20503=@"loc,{#10000},44,39,44,40"
+locations_default(#20503,#10000,44,39,44,40)
+hasLocation(#20502,#20503)
+#20504=*
+regexpterm(#20504,8,#20494,4,"[^>]*")
+#20505=@"loc,{#10000},44,41,44,45"
+locations_default(#20505,#10000,44,41,44,45)
+hasLocation(#20504,#20505)
+isGreedy(#20504)
+#20506=*
+regexpterm(#20506,23,#20504,0,"[^>]")
+#20507=@"loc,{#10000},44,41,44,44"
+locations_default(#20507,#10000,44,41,44,44)
+hasLocation(#20506,#20507)
+isInverted(#20506)
+#20508=*
+regexpterm(#20508,14,#20506,0,">")
+#20509=@"loc,{#10000},44,43,44,43"
+locations_default(#20509,#10000,44,43,44,43)
+hasLocation(#20508,#20509)
+regexpConstValue(#20508,">")
+#20510=*
+regexpterm(#20510,14,#20494,5,">")
+#20511=@"loc,{#10000},44,46,44,46"
+locations_default(#20511,#10000,44,46,44,46)
+hasLocation(#20510,#20511)
+regexpConstValue(#20510,">")
+#20512=*
+regexpterm(#20512,14,#20446,8,"<")
+#20513=@"loc,{#10000},44,52,44,52"
+locations_default(#20513,#10000,44,52,44,52)
+hasLocation(#20512,#20513)
+regexpConstValue(#20512,"<")
+#20514=*
+regexpterm(#20514,21,#20446,9,"\/")
+#20515=@"loc,{#10000},44,53,44,54"
+locations_default(#20515,#10000,44,53,44,54)
+hasLocation(#20514,#20515)
+regexpConstValue(#20514,"/")
+#20516=*
+regexpterm(#20516,14,#20446,10,"t")
+#20517=@"loc,{#10000},44,55,44,55"
+locations_default(#20517,#10000,44,55,44,55)
+hasLocation(#20516,#20517)
+regexpConstValue(#20516,"t")
+#20518=*
+regexpterm(#20518,14,#20446,11,"p")
+#20519=@"loc,{#10000},44,56,44,56"
+locations_default(#20519,#10000,44,56,44,56)
+hasLocation(#20518,#20519)
+regexpConstValue(#20518,"p")
+#20520=*
+regexpterm(#20520,14,#20446,12,"l")
+#20521=@"loc,{#10000},44,57,44,57"
+locations_default(#20521,#10000,44,57,44,57)
+hasLocation(#20520,#20521)
+regexpConstValue(#20520,"l")
+#20522=*
+regexpterm(#20522,14,#20446,13,">")
+#20523=@"loc,{#10000},44,58,44,58"
+locations_default(#20523,#10000,44,58,44,58)
+hasLocation(#20522,#20523)
+regexpConstValue(#20522,">")
#20524=*
-lines(#20524,#20001,"/foo|bar/;","
+lines(#20524,#20001,"/t/;","
")
-hasLocation(#20524,#20010)
+hasLocation(#20524,#20004)
#20525=*
-lines(#20525,#20001,"/(?:)/;","
+lines(#20525,#20001,"/foo|bar/;","
")
-hasLocation(#20525,#20032)
+hasLocation(#20525,#20010)
#20526=*
-lines(#20526,#20001,"/^abc$/;","
+lines(#20526,#20001,"/(?:)/;","
")
-hasLocation(#20526,#20040)
+hasLocation(#20526,#20032)
#20527=*
-lines(#20527,#20001,"/\bx\b/;","
+lines(#20527,#20001,"/^abc$/;","
")
-hasLocation(#20527,#20056)
+hasLocation(#20527,#20040)
#20528=*
-lines(#20528,#20001,"/\bx\B/;","
+lines(#20528,#20001,"/\bx\b/;","
")
-hasLocation(#20528,#20068)
+hasLocation(#20528,#20056)
#20529=*
-lines(#20529,#20001,"/x(?=y)/;","
+lines(#20529,#20001,"/\bx\B/;","
")
-hasLocation(#20529,#20080)
+hasLocation(#20529,#20068)
#20530=*
-lines(#20530,#20001,"/x(?!z)/;","
+lines(#20530,#20001,"/x(?=y)/;","
")
-hasLocation(#20530,#20092)
+hasLocation(#20530,#20080)
#20531=*
-lines(#20531,#20001,"/a*/;","
+lines(#20531,#20001,"/x(?!z)/;","
")
-hasLocation(#20531,#20104)
+hasLocation(#20531,#20092)
#20532=*
-lines(#20532,#20001,"/a*?/;","
+lines(#20532,#20001,"/a*/;","
")
-hasLocation(#20532,#20112)
+hasLocation(#20532,#20104)
#20533=*
-lines(#20533,#20001,"/a+/;","
+lines(#20533,#20001,"/a*?/;","
")
-hasLocation(#20533,#20120)
+hasLocation(#20533,#20112)
#20534=*
-lines(#20534,#20001,"/a+?/;","
+lines(#20534,#20001,"/a+/;","
")
-hasLocation(#20534,#20128)
+hasLocation(#20534,#20120)
#20535=*
-lines(#20535,#20001,"/a?/;","
+lines(#20535,#20001,"/a+?/;","
")
-hasLocation(#20535,#20136)
+hasLocation(#20535,#20128)
#20536=*
-lines(#20536,#20001,"/a??/;","
+lines(#20536,#20001,"/a?/;","
")
-hasLocation(#20536,#20144)
+hasLocation(#20536,#20136)
#20537=*
-lines(#20537,#20001,"/a{1}/;","
+lines(#20537,#20001,"/a??/;","
")
-hasLocation(#20537,#20152)
+hasLocation(#20537,#20144)
#20538=*
-lines(#20538,#20001,"/a{1,}/;","
+lines(#20538,#20001,"/a{1}/;","
")
-hasLocation(#20538,#20160)
+hasLocation(#20538,#20152)
#20539=*
-lines(#20539,#20001,"/a{1,2}/;","
+lines(#20539,#20001,"/a{1,}/;","
")
-hasLocation(#20539,#20168)
+hasLocation(#20539,#20160)
#20540=*
-lines(#20540,#20001,"/a{1}?/;","
+lines(#20540,#20001,"/a{1,2}/;","
")
-hasLocation(#20540,#20176)
+hasLocation(#20540,#20168)
#20541=*
-lines(#20541,#20001,"/a{1,}?/;","
+lines(#20541,#20001,"/a{1}?/;","
")
-hasLocation(#20541,#20184)
+hasLocation(#20541,#20176)
#20542=*
-lines(#20542,#20001,"/a{1,2}?/;","
+lines(#20542,#20001,"/a{1,}?/;","
")
-hasLocation(#20542,#20192)
+hasLocation(#20542,#20184)
#20543=*
-lines(#20543,#20001,"/./;","
+lines(#20543,#20001,"/a{1,2}?/;","
")
-hasLocation(#20543,#20200)
+hasLocation(#20543,#20192)
#20544=*
-lines(#20544,#20001,"/(abc)/;","
+lines(#20544,#20001,"/./;","
")
-hasLocation(#20544,#20206)
+hasLocation(#20544,#20200)
#20545=*
-lines(#20545,#20001,"/(?:abc)/;","
+lines(#20545,#20001,"/(abc)/;","
")
-hasLocation(#20545,#20220)
+hasLocation(#20545,#20206)
#20546=*
-lines(#20546,#20001,"/\x0a/;","
+lines(#20546,#20001,"/(?:abc)/;","
")
-hasLocation(#20546,#20234)
+hasLocation(#20546,#20220)
#20547=*
-lines(#20547,#20001,"/\u000a/;","
+lines(#20547,#20001,"/\x0a/;","
")
-hasLocation(#20547,#20240)
+hasLocation(#20547,#20234)
#20548=*
-lines(#20548,#20001,"/\10/;","
+lines(#20548,#20001,"/\u000a/;","
")
-hasLocation(#20548,#20246)
+hasLocation(#20548,#20240)
#20549=*
-lines(#20549,#20001,"/\t\n\r\f\v/;","
+lines(#20549,#20001,"/\10/;","
")
-hasLocation(#20549,#20252)
+hasLocation(#20549,#20246)
#20550=*
-lines(#20550,#20001,"/\ca\cN/;","
+lines(#20550,#20001,"/\t\n\r\f\v/;","
")
-hasLocation(#20550,#20268)
+hasLocation(#20550,#20253)
#20551=*
-lines(#20551,#20001,"/\w\S/;","
+lines(#20551,#20001,"/\ca\cN/;","
")
-hasLocation(#20551,#20278)
+hasLocation(#20551,#20269)
#20552=*
-lines(#20552,#20001,"/\\/;","
+lines(#20552,#20001,"/\w\S/;","
")
-hasLocation(#20552,#20288)
+hasLocation(#20552,#20279)
#20553=*
-lines(#20553,#20001,"/[abc]/;","
+lines(#20553,#20001,"/\\/;","
")
-hasLocation(#20553,#20294)
+hasLocation(#20553,#20289)
#20554=*
-lines(#20554,#20001,"/[a-z]/;","
+lines(#20554,#20001,"/[abc]/;","
")
-hasLocation(#20554,#20306)
+hasLocation(#20554,#20295)
#20555=*
-lines(#20555,#20001,"/[a-zA-Z]/;","
+lines(#20555,#20001,"/[a-z]/;","
")
-hasLocation(#20555,#20318)
+hasLocation(#20555,#20307)
#20556=*
-lines(#20556,#20001,"/[-a-z]/;","
+lines(#20556,#20001,"/[a-zA-Z]/;","
")
-hasLocation(#20556,#20336)
+hasLocation(#20556,#20319)
#20557=*
-lines(#20557,#20001,"/[^a-z]/;","
+lines(#20557,#20001,"/[-a-z]/;","
")
-hasLocation(#20557,#20350)
+hasLocation(#20557,#20337)
#20558=*
-lines(#20558,#20001,"/[a\b\x0c]/;","
+lines(#20558,#20001,"/[^a-z]/;","
")
-hasLocation(#20558,#20362)
+hasLocation(#20558,#20351)
#20559=*
-lines(#20559,#20001,"/a{/;","
+lines(#20559,#20001,"/[a\b\x0c]/;","
")
-hasLocation(#20559,#20374)
+hasLocation(#20559,#20363)
#20560=*
-lines(#20560,#20001,"/a{b}/;","
+lines(#20560,#20001,"/a{/;","
")
-hasLocation(#20560,#20386)
+hasLocation(#20560,#20375)
#20561=*
-lines(#20561,#20001,"/a{2/;","
+lines(#20561,#20001,"/a{b}/;","
")
-hasLocation(#20561,#20404)
+hasLocation(#20561,#20387)
#20562=*
-lines(#20562,#20001,"/\xa/;","
+lines(#20562,#20001,"/a{2/;","
")
-hasLocation(#20562,#20414)
+hasLocation(#20562,#20405)
#20563=*
-lines(#20563,#20001,"/\c0/;","
+lines(#20563,#20001,"/\xa/;","
")
-hasLocation(#20563,#20422)
+hasLocation(#20563,#20415)
#20564=*
-lines(#20564,#20001,"/[]/;","
+lines(#20564,#20001,"/\c0/;","
")
-hasLocation(#20564,#20430)
+hasLocation(#20564,#20423)
#20565=*
-lines(#20565,#20001,"/[^]/;","
+lines(#20565,#20001,"/[]/;","
")
-hasLocation(#20565,#20436)
+hasLocation(#20565,#20431)
#20566=*
-lines(#20566,#20001,"/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;","")
-hasLocation(#20566,#20442)
-numlines(#20001,44,44,0)
+lines(#20566,#20001,"/[^]/;","
+")
+hasLocation(#20566,#20437)
#20567=*
-tokeninfo(#20567,5,#20001,0,"/t/")
-hasLocation(#20567,#20006)
+lines(#20567,#20001,"/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;","")
+hasLocation(#20567,#20443)
+numlines(#20001,44,44,0)
#20568=*
-tokeninfo(#20568,8,#20001,1,";")
-#20569=@"loc,{#10000},1,4,1,4"
-locations_default(#20569,#10000,1,4,1,4)
-hasLocation(#20568,#20569)
-#20570=*
-tokeninfo(#20570,5,#20001,2,"/foo|bar/")
-hasLocation(#20570,#20012)
+tokeninfo(#20568,5,#20001,0,"/t/")
+hasLocation(#20568,#20006)
+#20569=*
+tokeninfo(#20569,8,#20001,1,";")
+#20570=@"loc,{#10000},1,4,1,4"
+locations_default(#20570,#10000,1,4,1,4)
+hasLocation(#20569,#20570)
#20571=*
-tokeninfo(#20571,8,#20001,3,";")
-#20572=@"loc,{#10000},2,10,2,10"
-locations_default(#20572,#10000,2,10,2,10)
-hasLocation(#20571,#20572)
-#20573=*
-tokeninfo(#20573,5,#20001,4,"/(?:)/")
-hasLocation(#20573,#20034)
+tokeninfo(#20571,5,#20001,2,"/foo|bar/")
+hasLocation(#20571,#20012)
+#20572=*
+tokeninfo(#20572,8,#20001,3,";")
+#20573=@"loc,{#10000},2,10,2,10"
+locations_default(#20573,#10000,2,10,2,10)
+hasLocation(#20572,#20573)
#20574=*
-tokeninfo(#20574,8,#20001,5,";")
-#20575=@"loc,{#10000},3,7,3,7"
-locations_default(#20575,#10000,3,7,3,7)
-hasLocation(#20574,#20575)
-#20576=*
-tokeninfo(#20576,5,#20001,6,"/^abc$/")
-hasLocation(#20576,#20042)
+tokeninfo(#20574,5,#20001,4,"/(?:)/")
+hasLocation(#20574,#20034)
+#20575=*
+tokeninfo(#20575,8,#20001,5,";")
+#20576=@"loc,{#10000},3,7,3,7"
+locations_default(#20576,#10000,3,7,3,7)
+hasLocation(#20575,#20576)
#20577=*
-tokeninfo(#20577,8,#20001,7,";")
-#20578=@"loc,{#10000},4,8,4,8"
-locations_default(#20578,#10000,4,8,4,8)
-hasLocation(#20577,#20578)
-#20579=*
-tokeninfo(#20579,5,#20001,8,"/\bx\b/")
-hasLocation(#20579,#20058)
+tokeninfo(#20577,5,#20001,6,"/^abc$/")
+hasLocation(#20577,#20042)
+#20578=*
+tokeninfo(#20578,8,#20001,7,";")
+#20579=@"loc,{#10000},4,8,4,8"
+locations_default(#20579,#10000,4,8,4,8)
+hasLocation(#20578,#20579)
#20580=*
-tokeninfo(#20580,8,#20001,9,";")
-#20581=@"loc,{#10000},5,8,5,8"
-locations_default(#20581,#10000,5,8,5,8)
-hasLocation(#20580,#20581)
-#20582=*
-tokeninfo(#20582,5,#20001,10,"/\bx\B/")
-hasLocation(#20582,#20070)
+tokeninfo(#20580,5,#20001,8,"/\bx\b/")
+hasLocation(#20580,#20058)
+#20581=*
+tokeninfo(#20581,8,#20001,9,";")
+#20582=@"loc,{#10000},5,8,5,8"
+locations_default(#20582,#10000,5,8,5,8)
+hasLocation(#20581,#20582)
#20583=*
-tokeninfo(#20583,8,#20001,11,";")
-#20584=@"loc,{#10000},6,8,6,8"
-locations_default(#20584,#10000,6,8,6,8)
-hasLocation(#20583,#20584)
-#20585=*
-tokeninfo(#20585,5,#20001,12,"/x(?=y)/")
-hasLocation(#20585,#20082)
+tokeninfo(#20583,5,#20001,10,"/\bx\B/")
+hasLocation(#20583,#20070)
+#20584=*
+tokeninfo(#20584,8,#20001,11,";")
+#20585=@"loc,{#10000},6,8,6,8"
+locations_default(#20585,#10000,6,8,6,8)
+hasLocation(#20584,#20585)
#20586=*
-tokeninfo(#20586,8,#20001,13,";")
-#20587=@"loc,{#10000},7,9,7,9"
-locations_default(#20587,#10000,7,9,7,9)
-hasLocation(#20586,#20587)
-#20588=*
-tokeninfo(#20588,5,#20001,14,"/x(?!z)/")
-hasLocation(#20588,#20094)
+tokeninfo(#20586,5,#20001,12,"/x(?=y)/")
+hasLocation(#20586,#20082)
+#20587=*
+tokeninfo(#20587,8,#20001,13,";")
+#20588=@"loc,{#10000},7,9,7,9"
+locations_default(#20588,#10000,7,9,7,9)
+hasLocation(#20587,#20588)
#20589=*
-tokeninfo(#20589,8,#20001,15,";")
-#20590=@"loc,{#10000},8,9,8,9"
-locations_default(#20590,#10000,8,9,8,9)
-hasLocation(#20589,#20590)
-#20591=*
-tokeninfo(#20591,5,#20001,16,"/a*/")
-hasLocation(#20591,#20106)
+tokeninfo(#20589,5,#20001,14,"/x(?!z)/")
+hasLocation(#20589,#20094)
+#20590=*
+tokeninfo(#20590,8,#20001,15,";")
+#20591=@"loc,{#10000},8,9,8,9"
+locations_default(#20591,#10000,8,9,8,9)
+hasLocation(#20590,#20591)
#20592=*
-tokeninfo(#20592,8,#20001,17,";")
-#20593=@"loc,{#10000},9,5,9,5"
-locations_default(#20593,#10000,9,5,9,5)
-hasLocation(#20592,#20593)
-#20594=*
-tokeninfo(#20594,5,#20001,18,"/a*?/")
-hasLocation(#20594,#20114)
+tokeninfo(#20592,5,#20001,16,"/a*/")
+hasLocation(#20592,#20106)
+#20593=*
+tokeninfo(#20593,8,#20001,17,";")
+#20594=@"loc,{#10000},9,5,9,5"
+locations_default(#20594,#10000,9,5,9,5)
+hasLocation(#20593,#20594)
#20595=*
-tokeninfo(#20595,8,#20001,19,";")
-#20596=@"loc,{#10000},10,6,10,6"
-locations_default(#20596,#10000,10,6,10,6)
-hasLocation(#20595,#20596)
-#20597=*
-tokeninfo(#20597,5,#20001,20,"/a+/")
-hasLocation(#20597,#20122)
+tokeninfo(#20595,5,#20001,18,"/a*?/")
+hasLocation(#20595,#20114)
+#20596=*
+tokeninfo(#20596,8,#20001,19,";")
+#20597=@"loc,{#10000},10,6,10,6"
+locations_default(#20597,#10000,10,6,10,6)
+hasLocation(#20596,#20597)
#20598=*
-tokeninfo(#20598,8,#20001,21,";")
-#20599=@"loc,{#10000},11,5,11,5"
-locations_default(#20599,#10000,11,5,11,5)
-hasLocation(#20598,#20599)
-#20600=*
-tokeninfo(#20600,5,#20001,22,"/a+?/")
-hasLocation(#20600,#20130)
+tokeninfo(#20598,5,#20001,20,"/a+/")
+hasLocation(#20598,#20122)
+#20599=*
+tokeninfo(#20599,8,#20001,21,";")
+#20600=@"loc,{#10000},11,5,11,5"
+locations_default(#20600,#10000,11,5,11,5)
+hasLocation(#20599,#20600)
#20601=*
-tokeninfo(#20601,8,#20001,23,";")
-#20602=@"loc,{#10000},12,6,12,6"
-locations_default(#20602,#10000,12,6,12,6)
-hasLocation(#20601,#20602)
-#20603=*
-tokeninfo(#20603,5,#20001,24,"/a?/")
-hasLocation(#20603,#20138)
+tokeninfo(#20601,5,#20001,22,"/a+?/")
+hasLocation(#20601,#20130)
+#20602=*
+tokeninfo(#20602,8,#20001,23,";")
+#20603=@"loc,{#10000},12,6,12,6"
+locations_default(#20603,#10000,12,6,12,6)
+hasLocation(#20602,#20603)
#20604=*
-tokeninfo(#20604,8,#20001,25,";")
-#20605=@"loc,{#10000},13,5,13,5"
-locations_default(#20605,#10000,13,5,13,5)
-hasLocation(#20604,#20605)
-#20606=*
-tokeninfo(#20606,5,#20001,26,"/a??/")
-hasLocation(#20606,#20146)
+tokeninfo(#20604,5,#20001,24,"/a?/")
+hasLocation(#20604,#20138)
+#20605=*
+tokeninfo(#20605,8,#20001,25,";")
+#20606=@"loc,{#10000},13,5,13,5"
+locations_default(#20606,#10000,13,5,13,5)
+hasLocation(#20605,#20606)
#20607=*
-tokeninfo(#20607,8,#20001,27,";")
-#20608=@"loc,{#10000},14,6,14,6"
-locations_default(#20608,#10000,14,6,14,6)
-hasLocation(#20607,#20608)
-#20609=*
-tokeninfo(#20609,5,#20001,28,"/a{1}/")
-hasLocation(#20609,#20154)
+tokeninfo(#20607,5,#20001,26,"/a??/")
+hasLocation(#20607,#20146)
+#20608=*
+tokeninfo(#20608,8,#20001,27,";")
+#20609=@"loc,{#10000},14,6,14,6"
+locations_default(#20609,#10000,14,6,14,6)
+hasLocation(#20608,#20609)
#20610=*
-tokeninfo(#20610,8,#20001,29,";")
-#20611=@"loc,{#10000},15,7,15,7"
-locations_default(#20611,#10000,15,7,15,7)
-hasLocation(#20610,#20611)
-#20612=*
-tokeninfo(#20612,5,#20001,30,"/a{1,}/")
-hasLocation(#20612,#20162)
+tokeninfo(#20610,5,#20001,28,"/a{1}/")
+hasLocation(#20610,#20154)
+#20611=*
+tokeninfo(#20611,8,#20001,29,";")
+#20612=@"loc,{#10000},15,7,15,7"
+locations_default(#20612,#10000,15,7,15,7)
+hasLocation(#20611,#20612)
#20613=*
-tokeninfo(#20613,8,#20001,31,";")
-#20614=@"loc,{#10000},16,8,16,8"
-locations_default(#20614,#10000,16,8,16,8)
-hasLocation(#20613,#20614)
-#20615=*
-tokeninfo(#20615,5,#20001,32,"/a{1,2}/")
-hasLocation(#20615,#20170)
+tokeninfo(#20613,5,#20001,30,"/a{1,}/")
+hasLocation(#20613,#20162)
+#20614=*
+tokeninfo(#20614,8,#20001,31,";")
+#20615=@"loc,{#10000},16,8,16,8"
+locations_default(#20615,#10000,16,8,16,8)
+hasLocation(#20614,#20615)
#20616=*
-tokeninfo(#20616,8,#20001,33,";")
-#20617=@"loc,{#10000},17,9,17,9"
-locations_default(#20617,#10000,17,9,17,9)
-hasLocation(#20616,#20617)
-#20618=*
-tokeninfo(#20618,5,#20001,34,"/a{1}?/")
-hasLocation(#20618,#20178)
+tokeninfo(#20616,5,#20001,32,"/a{1,2}/")
+hasLocation(#20616,#20170)
+#20617=*
+tokeninfo(#20617,8,#20001,33,";")
+#20618=@"loc,{#10000},17,9,17,9"
+locations_default(#20618,#10000,17,9,17,9)
+hasLocation(#20617,#20618)
#20619=*
-tokeninfo(#20619,8,#20001,35,";")
-#20620=@"loc,{#10000},18,8,18,8"
-locations_default(#20620,#10000,18,8,18,8)
-hasLocation(#20619,#20620)
-#20621=*
-tokeninfo(#20621,5,#20001,36,"/a{1,}?/")
-hasLocation(#20621,#20186)
+tokeninfo(#20619,5,#20001,34,"/a{1}?/")
+hasLocation(#20619,#20178)
+#20620=*
+tokeninfo(#20620,8,#20001,35,";")
+#20621=@"loc,{#10000},18,8,18,8"
+locations_default(#20621,#10000,18,8,18,8)
+hasLocation(#20620,#20621)
#20622=*
-tokeninfo(#20622,8,#20001,37,";")
-#20623=@"loc,{#10000},19,9,19,9"
-locations_default(#20623,#10000,19,9,19,9)
-hasLocation(#20622,#20623)
-#20624=*
-tokeninfo(#20624,5,#20001,38,"/a{1,2}?/")
-hasLocation(#20624,#20194)
+tokeninfo(#20622,5,#20001,36,"/a{1,}?/")
+hasLocation(#20622,#20186)
+#20623=*
+tokeninfo(#20623,8,#20001,37,";")
+#20624=@"loc,{#10000},19,9,19,9"
+locations_default(#20624,#10000,19,9,19,9)
+hasLocation(#20623,#20624)
#20625=*
-tokeninfo(#20625,8,#20001,39,";")
-#20626=@"loc,{#10000},20,10,20,10"
-locations_default(#20626,#10000,20,10,20,10)
-hasLocation(#20625,#20626)
-#20627=*
-tokeninfo(#20627,5,#20001,40,"/./")
-hasLocation(#20627,#20202)
+tokeninfo(#20625,5,#20001,38,"/a{1,2}?/")
+hasLocation(#20625,#20194)
+#20626=*
+tokeninfo(#20626,8,#20001,39,";")
+#20627=@"loc,{#10000},20,10,20,10"
+locations_default(#20627,#10000,20,10,20,10)
+hasLocation(#20626,#20627)
#20628=*
-tokeninfo(#20628,8,#20001,41,";")
-#20629=@"loc,{#10000},21,4,21,4"
-locations_default(#20629,#10000,21,4,21,4)
-hasLocation(#20628,#20629)
-#20630=*
-tokeninfo(#20630,5,#20001,42,"/(abc)/")
-hasLocation(#20630,#20208)
+tokeninfo(#20628,5,#20001,40,"/./")
+hasLocation(#20628,#20202)
+#20629=*
+tokeninfo(#20629,8,#20001,41,";")
+#20630=@"loc,{#10000},21,4,21,4"
+locations_default(#20630,#10000,21,4,21,4)
+hasLocation(#20629,#20630)
#20631=*
-tokeninfo(#20631,8,#20001,43,";")
-#20632=@"loc,{#10000},22,8,22,8"
-locations_default(#20632,#10000,22,8,22,8)
-hasLocation(#20631,#20632)
-#20633=*
-tokeninfo(#20633,5,#20001,44,"/(?:abc)/")
-hasLocation(#20633,#20222)
+tokeninfo(#20631,5,#20001,42,"/(abc)/")
+hasLocation(#20631,#20208)
+#20632=*
+tokeninfo(#20632,8,#20001,43,";")
+#20633=@"loc,{#10000},22,8,22,8"
+locations_default(#20633,#10000,22,8,22,8)
+hasLocation(#20632,#20633)
#20634=*
-tokeninfo(#20634,8,#20001,45,";")
-#20635=@"loc,{#10000},23,10,23,10"
-locations_default(#20635,#10000,23,10,23,10)
-hasLocation(#20634,#20635)
-#20636=*
-tokeninfo(#20636,5,#20001,46,"/\x0a/")
-hasLocation(#20636,#20236)
+tokeninfo(#20634,5,#20001,44,"/(?:abc)/")
+hasLocation(#20634,#20222)
+#20635=*
+tokeninfo(#20635,8,#20001,45,";")
+#20636=@"loc,{#10000},23,10,23,10"
+locations_default(#20636,#10000,23,10,23,10)
+hasLocation(#20635,#20636)
#20637=*
-tokeninfo(#20637,8,#20001,47,";")
-#20638=@"loc,{#10000},24,7,24,7"
-locations_default(#20638,#10000,24,7,24,7)
-hasLocation(#20637,#20638)
-#20639=*
-tokeninfo(#20639,5,#20001,48,"/\u000a/")
-hasLocation(#20639,#20242)
+tokeninfo(#20637,5,#20001,46,"/\x0a/")
+hasLocation(#20637,#20236)
+#20638=*
+tokeninfo(#20638,8,#20001,47,";")
+#20639=@"loc,{#10000},24,7,24,7"
+locations_default(#20639,#10000,24,7,24,7)
+hasLocation(#20638,#20639)
#20640=*
-tokeninfo(#20640,8,#20001,49,";")
-#20641=@"loc,{#10000},25,9,25,9"
-locations_default(#20641,#10000,25,9,25,9)
-hasLocation(#20640,#20641)
-#20642=*
-tokeninfo(#20642,5,#20001,50,"/\10/")
-hasLocation(#20642,#20248)
+tokeninfo(#20640,5,#20001,48,"/\u000a/")
+hasLocation(#20640,#20242)
+#20641=*
+tokeninfo(#20641,8,#20001,49,";")
+#20642=@"loc,{#10000},25,9,25,9"
+locations_default(#20642,#10000,25,9,25,9)
+hasLocation(#20641,#20642)
#20643=*
-tokeninfo(#20643,8,#20001,51,";")
-#20644=@"loc,{#10000},26,6,26,6"
-locations_default(#20644,#10000,26,6,26,6)
-hasLocation(#20643,#20644)
-#20645=*
-tokeninfo(#20645,5,#20001,52,"/\t\n\r\f\v/")
-hasLocation(#20645,#20254)
+tokeninfo(#20643,5,#20001,50,"/\10/")
+hasLocation(#20643,#20248)
+#20644=*
+tokeninfo(#20644,8,#20001,51,";")
+#20645=@"loc,{#10000},26,6,26,6"
+locations_default(#20645,#10000,26,6,26,6)
+hasLocation(#20644,#20645)
#20646=*
-tokeninfo(#20646,8,#20001,53,";")
-#20647=@"loc,{#10000},27,13,27,13"
-locations_default(#20647,#10000,27,13,27,13)
-hasLocation(#20646,#20647)
-#20648=*
-tokeninfo(#20648,5,#20001,54,"/\ca\cN/")
-hasLocation(#20648,#20270)
+tokeninfo(#20646,5,#20001,52,"/\t\n\r\f\v/")
+hasLocation(#20646,#20255)
+#20647=*
+tokeninfo(#20647,8,#20001,53,";")
+#20648=@"loc,{#10000},27,13,27,13"
+locations_default(#20648,#10000,27,13,27,13)
+hasLocation(#20647,#20648)
#20649=*
-tokeninfo(#20649,8,#20001,55,";")
-#20650=@"loc,{#10000},28,9,28,9"
-locations_default(#20650,#10000,28,9,28,9)
-hasLocation(#20649,#20650)
-#20651=*
-tokeninfo(#20651,5,#20001,56,"/\w\S/")
-hasLocation(#20651,#20280)
+tokeninfo(#20649,5,#20001,54,"/\ca\cN/")
+hasLocation(#20649,#20271)
+#20650=*
+tokeninfo(#20650,8,#20001,55,";")
+#20651=@"loc,{#10000},28,9,28,9"
+locations_default(#20651,#10000,28,9,28,9)
+hasLocation(#20650,#20651)
#20652=*
-tokeninfo(#20652,8,#20001,57,";")
-#20653=@"loc,{#10000},29,7,29,7"
-locations_default(#20653,#10000,29,7,29,7)
-hasLocation(#20652,#20653)
-#20654=*
-tokeninfo(#20654,5,#20001,58,"/\\/")
-hasLocation(#20654,#20290)
+tokeninfo(#20652,5,#20001,56,"/\w\S/")
+hasLocation(#20652,#20281)
+#20653=*
+tokeninfo(#20653,8,#20001,57,";")
+#20654=@"loc,{#10000},29,7,29,7"
+locations_default(#20654,#10000,29,7,29,7)
+hasLocation(#20653,#20654)
#20655=*
-tokeninfo(#20655,8,#20001,59,";")
-#20656=@"loc,{#10000},30,5,30,5"
-locations_default(#20656,#10000,30,5,30,5)
-hasLocation(#20655,#20656)
-#20657=*
-tokeninfo(#20657,5,#20001,60,"/[abc]/")
-hasLocation(#20657,#20296)
+tokeninfo(#20655,5,#20001,58,"/\\/")
+hasLocation(#20655,#20291)
+#20656=*
+tokeninfo(#20656,8,#20001,59,";")
+#20657=@"loc,{#10000},30,5,30,5"
+locations_default(#20657,#10000,30,5,30,5)
+hasLocation(#20656,#20657)
#20658=*
-tokeninfo(#20658,8,#20001,61,";")
-#20659=@"loc,{#10000},31,8,31,8"
-locations_default(#20659,#10000,31,8,31,8)
-hasLocation(#20658,#20659)
-#20660=*
-tokeninfo(#20660,5,#20001,62,"/[a-z]/")
-hasLocation(#20660,#20308)
+tokeninfo(#20658,5,#20001,60,"/[abc]/")
+hasLocation(#20658,#20297)
+#20659=*
+tokeninfo(#20659,8,#20001,61,";")
+#20660=@"loc,{#10000},31,8,31,8"
+locations_default(#20660,#10000,31,8,31,8)
+hasLocation(#20659,#20660)
#20661=*
-tokeninfo(#20661,8,#20001,63,";")
-#20662=@"loc,{#10000},32,8,32,8"
-locations_default(#20662,#10000,32,8,32,8)
-hasLocation(#20661,#20662)
-#20663=*
-tokeninfo(#20663,5,#20001,64,"/[a-zA-Z]/")
-hasLocation(#20663,#20320)
+tokeninfo(#20661,5,#20001,62,"/[a-z]/")
+hasLocation(#20661,#20309)
+#20662=*
+tokeninfo(#20662,8,#20001,63,";")
+#20663=@"loc,{#10000},32,8,32,8"
+locations_default(#20663,#10000,32,8,32,8)
+hasLocation(#20662,#20663)
#20664=*
-tokeninfo(#20664,8,#20001,65,";")
-#20665=@"loc,{#10000},33,11,33,11"
-locations_default(#20665,#10000,33,11,33,11)
-hasLocation(#20664,#20665)
-#20666=*
-tokeninfo(#20666,5,#20001,66,"/[-a-z]/")
-hasLocation(#20666,#20338)
+tokeninfo(#20664,5,#20001,64,"/[a-zA-Z]/")
+hasLocation(#20664,#20321)
+#20665=*
+tokeninfo(#20665,8,#20001,65,";")
+#20666=@"loc,{#10000},33,11,33,11"
+locations_default(#20666,#10000,33,11,33,11)
+hasLocation(#20665,#20666)
#20667=*
-tokeninfo(#20667,8,#20001,67,";")
-#20668=@"loc,{#10000},34,9,34,9"
-locations_default(#20668,#10000,34,9,34,9)
-hasLocation(#20667,#20668)
-#20669=*
-tokeninfo(#20669,5,#20001,68,"/[^a-z]/")
-hasLocation(#20669,#20352)
+tokeninfo(#20667,5,#20001,66,"/[-a-z]/")
+hasLocation(#20667,#20339)
+#20668=*
+tokeninfo(#20668,8,#20001,67,";")
+#20669=@"loc,{#10000},34,9,34,9"
+locations_default(#20669,#10000,34,9,34,9)
+hasLocation(#20668,#20669)
#20670=*
-tokeninfo(#20670,8,#20001,69,";")
-#20671=@"loc,{#10000},35,9,35,9"
-locations_default(#20671,#10000,35,9,35,9)
-hasLocation(#20670,#20671)
-#20672=*
-tokeninfo(#20672,5,#20001,70,"/[a\b\x0c]/")
-hasLocation(#20672,#20364)
+tokeninfo(#20670,5,#20001,68,"/[^a-z]/")
+hasLocation(#20670,#20353)
+#20671=*
+tokeninfo(#20671,8,#20001,69,";")
+#20672=@"loc,{#10000},35,9,35,9"
+locations_default(#20672,#10000,35,9,35,9)
+hasLocation(#20671,#20672)
#20673=*
-tokeninfo(#20673,8,#20001,71,";")
-#20674=@"loc,{#10000},36,12,36,12"
-locations_default(#20674,#10000,36,12,36,12)
-hasLocation(#20673,#20674)
-#20675=*
-tokeninfo(#20675,5,#20001,72,"/a{/")
-hasLocation(#20675,#20376)
+tokeninfo(#20673,5,#20001,70,"/[a\b\x0c]/")
+hasLocation(#20673,#20365)
+#20674=*
+tokeninfo(#20674,8,#20001,71,";")
+#20675=@"loc,{#10000},36,12,36,12"
+locations_default(#20675,#10000,36,12,36,12)
+hasLocation(#20674,#20675)
#20676=*
-tokeninfo(#20676,8,#20001,73,";")
-#20677=@"loc,{#10000},37,5,37,5"
-locations_default(#20677,#10000,37,5,37,5)
-hasLocation(#20676,#20677)
-#20678=*
-tokeninfo(#20678,5,#20001,74,"/a{b}/")
-hasLocation(#20678,#20388)
+tokeninfo(#20676,5,#20001,72,"/a{/")
+hasLocation(#20676,#20377)
+#20677=*
+tokeninfo(#20677,8,#20001,73,";")
+#20678=@"loc,{#10000},37,5,37,5"
+locations_default(#20678,#10000,37,5,37,5)
+hasLocation(#20677,#20678)
#20679=*
-tokeninfo(#20679,8,#20001,75,";")
-#20680=@"loc,{#10000},38,7,38,7"
-locations_default(#20680,#10000,38,7,38,7)
-hasLocation(#20679,#20680)
-#20681=*
-tokeninfo(#20681,5,#20001,76,"/a{2/")
-hasLocation(#20681,#20406)
+tokeninfo(#20679,5,#20001,74,"/a{b}/")
+hasLocation(#20679,#20389)
+#20680=*
+tokeninfo(#20680,8,#20001,75,";")
+#20681=@"loc,{#10000},38,7,38,7"
+locations_default(#20681,#10000,38,7,38,7)
+hasLocation(#20680,#20681)
#20682=*
-tokeninfo(#20682,8,#20001,77,";")
-#20683=@"loc,{#10000},39,6,39,6"
-locations_default(#20683,#10000,39,6,39,6)
-hasLocation(#20682,#20683)
-#20684=*
-tokeninfo(#20684,5,#20001,78,"/\xa/")
-hasLocation(#20684,#20416)
+tokeninfo(#20682,5,#20001,76,"/a{2/")
+hasLocation(#20682,#20407)
+#20683=*
+tokeninfo(#20683,8,#20001,77,";")
+#20684=@"loc,{#10000},39,6,39,6"
+locations_default(#20684,#10000,39,6,39,6)
+hasLocation(#20683,#20684)
#20685=*
-tokeninfo(#20685,8,#20001,79,";")
-#20686=@"loc,{#10000},40,6,40,6"
-locations_default(#20686,#10000,40,6,40,6)
-hasLocation(#20685,#20686)
-#20687=*
-tokeninfo(#20687,5,#20001,80,"/\c0/")
-hasLocation(#20687,#20424)
+tokeninfo(#20685,5,#20001,78,"/\xa/")
+hasLocation(#20685,#20417)
+#20686=*
+tokeninfo(#20686,8,#20001,79,";")
+#20687=@"loc,{#10000},40,6,40,6"
+locations_default(#20687,#10000,40,6,40,6)
+hasLocation(#20686,#20687)
#20688=*
-tokeninfo(#20688,8,#20001,81,";")
-#20689=@"loc,{#10000},41,6,41,6"
-locations_default(#20689,#10000,41,6,41,6)
-hasLocation(#20688,#20689)
-#20690=*
-tokeninfo(#20690,5,#20001,82,"/[]/")
-hasLocation(#20690,#20432)
+tokeninfo(#20688,5,#20001,80,"/\c0/")
+hasLocation(#20688,#20425)
+#20689=*
+tokeninfo(#20689,8,#20001,81,";")
+#20690=@"loc,{#10000},41,6,41,6"
+locations_default(#20690,#10000,41,6,41,6)
+hasLocation(#20689,#20690)
#20691=*
-tokeninfo(#20691,8,#20001,83,";")
-#20692=@"loc,{#10000},42,5,42,5"
-locations_default(#20692,#10000,42,5,42,5)
-hasLocation(#20691,#20692)
-#20693=*
-tokeninfo(#20693,5,#20001,84,"/[^]/")
-hasLocation(#20693,#20438)
+tokeninfo(#20691,5,#20001,82,"/[]/")
+hasLocation(#20691,#20433)
+#20692=*
+tokeninfo(#20692,8,#20001,83,";")
+#20693=@"loc,{#10000},42,5,42,5"
+locations_default(#20693,#10000,42,5,42,5)
+hasLocation(#20692,#20693)
#20694=*
-tokeninfo(#20694,8,#20001,85,";")
-#20695=@"loc,{#10000},43,6,43,6"
-locations_default(#20695,#10000,43,6,43,6)
-hasLocation(#20694,#20695)
-#20696=*
-tokeninfo(#20696,5,#20001,86,"/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/")
-hasLocation(#20696,#20444)
+tokeninfo(#20694,5,#20001,84,"/[^]/")
+hasLocation(#20694,#20439)
+#20695=*
+tokeninfo(#20695,8,#20001,85,";")
+#20696=@"loc,{#10000},43,6,43,6"
+locations_default(#20696,#10000,43,6,43,6)
+hasLocation(#20695,#20696)
#20697=*
-tokeninfo(#20697,8,#20001,87,";")
-#20698=@"loc,{#10000},44,60,44,60"
-locations_default(#20698,#10000,44,60,44,60)
-hasLocation(#20697,#20698)
-#20699=*
-tokeninfo(#20699,0,#20001,88,"")
-#20700=@"loc,{#10000},44,61,44,60"
-locations_default(#20700,#10000,44,61,44,60)
-hasLocation(#20699,#20700)
-#20701=*
-entry_cfg_node(#20701,#20001)
-#20702=@"loc,{#10000},1,1,1,0"
-locations_default(#20702,#10000,1,1,1,0)
-hasLocation(#20701,#20702)
-#20703=*
-exit_cfg_node(#20703,#20001)
-hasLocation(#20703,#20700)
-successor(#20441,#20443)
-successor(#20443,#20703)
-successor(#20435,#20437)
-successor(#20437,#20441)
-successor(#20429,#20431)
-successor(#20431,#20435)
-successor(#20421,#20423)
-successor(#20423,#20429)
-successor(#20413,#20415)
-successor(#20415,#20421)
-successor(#20403,#20405)
-successor(#20405,#20413)
-successor(#20385,#20387)
-successor(#20387,#20403)
-successor(#20373,#20375)
-successor(#20375,#20385)
-successor(#20361,#20363)
-successor(#20363,#20373)
-successor(#20349,#20351)
-successor(#20351,#20361)
-successor(#20335,#20337)
-successor(#20337,#20349)
-successor(#20317,#20319)
-successor(#20319,#20335)
-successor(#20305,#20307)
-successor(#20307,#20317)
-successor(#20293,#20295)
-successor(#20295,#20305)
-successor(#20287,#20289)
-successor(#20289,#20293)
-successor(#20277,#20279)
-successor(#20279,#20287)
-successor(#20267,#20269)
-successor(#20269,#20277)
-successor(#20251,#20253)
-successor(#20253,#20267)
+tokeninfo(#20697,5,#20001,86,"/]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/")
+hasLocation(#20697,#20445)
+#20698=*
+tokeninfo(#20698,8,#20001,87,";")
+#20699=@"loc,{#10000},44,60,44,60"
+locations_default(#20699,#10000,44,60,44,60)
+hasLocation(#20698,#20699)
+#20700=*
+tokeninfo(#20700,0,#20001,88,"")
+#20701=@"loc,{#10000},44,61,44,60"
+locations_default(#20701,#10000,44,61,44,60)
+hasLocation(#20700,#20701)
+#20702=*
+entry_cfg_node(#20702,#20001)
+#20703=@"loc,{#10000},1,1,1,0"
+locations_default(#20703,#10000,1,1,1,0)
+hasLocation(#20702,#20703)
+#20704=*
+exit_cfg_node(#20704,#20001)
+hasLocation(#20704,#20701)
+successor(#20442,#20444)
+successor(#20444,#20704)
+successor(#20436,#20438)
+successor(#20438,#20442)
+successor(#20430,#20432)
+successor(#20432,#20436)
+successor(#20422,#20424)
+successor(#20424,#20430)
+successor(#20414,#20416)
+successor(#20416,#20422)
+successor(#20404,#20406)
+successor(#20406,#20414)
+successor(#20386,#20388)
+successor(#20388,#20404)
+successor(#20374,#20376)
+successor(#20376,#20386)
+successor(#20362,#20364)
+successor(#20364,#20374)
+successor(#20350,#20352)
+successor(#20352,#20362)
+successor(#20336,#20338)
+successor(#20338,#20350)
+successor(#20318,#20320)
+successor(#20320,#20336)
+successor(#20306,#20308)
+successor(#20308,#20318)
+successor(#20294,#20296)
+successor(#20296,#20306)
+successor(#20288,#20290)
+successor(#20290,#20294)
+successor(#20278,#20280)
+successor(#20280,#20288)
+successor(#20268,#20270)
+successor(#20270,#20278)
+successor(#20252,#20254)
+successor(#20254,#20268)
successor(#20245,#20247)
-successor(#20247,#20251)
+successor(#20247,#20252)
successor(#20239,#20241)
successor(#20241,#20245)
successor(#20233,#20235)
@@ -2245,6 +2248,6 @@ successor(#20009,#20011)
successor(#20011,#20031)
successor(#20003,#20005)
successor(#20005,#20009)
-successor(#20701,#20003)
+successor(#20702,#20003)
numlines(#10000,44,44,0)
filetype(#10000,"javascript")
diff --git a/javascript/extractor/tests/regexp/input/es2018.js b/javascript/extractor/tests/regexp/input/es2018.js
index f7d0d826b2c..fef868bf99b 100644
--- a/javascript/extractor/tests/regexp/input/es2018.js
+++ b/javascript/extractor/tests/regexp/input/es2018.js
@@ -3,3 +3,4 @@
/(?$/;")
@@ -169,81 +169,125 @@ hasLocation(#20051,#20052)
unicodePropertyEscapeName(#20051,"Script")
unicodePropertyEscapeValue(#20051,"Greek")
#20053=*
-lines(#20053,#20001,"/^(?\s+)\w+\k$/;","
-")
-hasLocation(#20053,#20004)
-#20054=*
-lines(#20054,#20001,"/(?<=.)/;","
-")
-hasLocation(#20054,#20026)
+stmts(#20053,2,#20001,5,"/\k;")
+#20054=@"loc,{#10000},6,1,6,6"
+locations_default(#20054,#10000,6,1,6,6)
+hasLocation(#20053,#20054)
+stmtContainers(#20053,#20001)
#20055=*
-lines(#20055,#20001,"/(?\s+)\w+\k$/")
-hasLocation(#20058,#20006)
+regexpterm(#20057,22,#20055,0,"\k<")
+#20058=@"loc,{#10000},6,2,6,4"
+locations_default(#20058,#10000,6,2,6,4)
+hasLocation(#20057,#20058)
+namedBackref(#20057,"")
#20059=*
-tokeninfo(#20059,8,#20001,1,";")
-#20060=@"loc,{#10000},1,24,1,24"
-locations_default(#20060,#10000,1,24,1,24)
+regexpParseErrors(#20059,#20057,"expected identifier")
+#20060=@"loc,{#10000},6,5,6,5"
+locations_default(#20060,#10000,6,5,6,5)
hasLocation(#20059,#20060)
#20061=*
-tokeninfo(#20061,5,#20001,2,"/(?<=.)/")
-hasLocation(#20061,#20028)
-#20062=*
-tokeninfo(#20062,8,#20001,3,";")
-#20063=@"loc,{#10000},2,9,2,9"
-locations_default(#20063,#10000,2,9,2,9)
-hasLocation(#20062,#20063)
+regexpParseErrors(#20061,#20057,"expected '>'")
+#20062=@"loc,{#10000},6,4,6,4"
+locations_default(#20062,#10000,6,4,6,4)
+hasLocation(#20061,#20062)
+#20063=*
+lines(#20063,#20001,"/^(?\s+)\w+\k$/;","
+")
+hasLocation(#20063,#20004)
#20064=*
-tokeninfo(#20064,5,#20001,4,"/(?\s+)\w+\k$/")
+hasLocation(#20069,#20006)
#20070=*
-tokeninfo(#20070,5,#20001,8,"/\P{Script=Greek}/u")
-hasLocation(#20070,#20050)
-#20071=*
-tokeninfo(#20071,8,#20001,9,";")
-#20072=@"loc,{#10000},5,20,5,20"
-locations_default(#20072,#10000,5,20,5,20)
-hasLocation(#20071,#20072)
+tokeninfo(#20070,8,#20001,1,";")
+#20071=@"loc,{#10000},1,24,1,24"
+locations_default(#20071,#10000,1,24,1,24)
+hasLocation(#20070,#20071)
+#20072=*
+tokeninfo(#20072,5,#20001,2,"/(?<=.)/")
+hasLocation(#20072,#20028)
#20073=*
-tokeninfo(#20073,0,#20001,10,"")
-#20074=@"loc,{#10000},6,1,6,0"
-locations_default(#20074,#10000,6,1,6,0)
+tokeninfo(#20073,8,#20001,3,";")
+#20074=@"loc,{#10000},2,9,2,9"
+locations_default(#20074,#10000,2,9,2,9)
hasLocation(#20073,#20074)
#20075=*
-entry_cfg_node(#20075,#20001)
-#20076=@"loc,{#10000},1,1,1,0"
-locations_default(#20076,#10000,1,1,1,0)
-hasLocation(#20075,#20076)
-#20077=*
-exit_cfg_node(#20077,#20001)
-hasLocation(#20077,#20074)
+tokeninfo(#20075,5,#20001,4,"/(?