From c14ebac4552e912bf2fef0162266c955fd13d9e6 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 9 Nov 2018 08:36:30 +0000 Subject: [PATCH 1/3] JavaScript: Port regular expression parser to Java. --- .../src/com/semmle/js/ast/regexp/Error.java | 14 + .../com/semmle/js/parser/RegExpParser.java | 519 +++- .../tests/exprs/output/trap/regexp.js.trap | 2541 +++++++++-------- .../extractor/tests/regexp/input/es2018.js | 1 + .../extractor/tests/regexp/input/tst.js | 2 + .../tests/regexp/output/trap/es2018.js.trap | 174 +- .../tests/regexp/output/trap/tst.js.trap | Bin 0 -> 3092 bytes 7 files changed, 1842 insertions(+), 1409 deletions(-) create mode 100644 javascript/extractor/tests/regexp/input/tst.js create mode 100644 javascript/extractor/tests/regexp/output/trap/tst.js.trap 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/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/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\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,"/(?`k(SLZS4o7Y7dXst{bSHr>>*7u#D}O5r?0AGMFr zZ!{zA+Ln_*Hi<@~-~9PTdZ{yfy?L8n4gK)?vA^rvQ&-vjp|)v4Kl^`PIuqqBQkB9K zKOg&4W$VN(Yw~cnZ|j}yu+M$UPK}+gPS;7*HbZ%6Y+YIbjEA}sr3>?*MrGD~% zf2oYW(**x5heO-+_dB~UPqpkfvfmr7lP_ieL2Ny{b7pXak!T<4_H$X^_f>mDobCg- zZq>y^zfnwm)g6w*U7*oQr^(PBYx~XCvO|X*GkBP*TxC&sIwHV};RN1MD2L_Y^Ea=O zes~(>>|DVGn`OxJr_)cJ6JIsK3&k{{bQHeLB2?is>MbKwIiFgr9n3pl*g(Zh zg0KOz{eJ9Zb)z=C8<`m~d*tf{WTZaQ1Qh-C1X)Lr<w`_e59( z=rkT#h1dEp*set7FLRCVzQ}ya!EGe?8wB6k2e`$~CqC^)X%G|mhEfo!<`Zx`Pk^DC zEjQBbIRR`LNx%&sdAk-KMA;7?%lc$JRr=@m@Bcl-cHC*(bElD_KUJZ{G>wmuW(mQl z%~H8^=4r(+0=spv8uNv^eOeG+%}@}^qSm7Z)7m%KmK&_Pl9=>NpbStfk_Lf_;hYqw zIR*%H-dD1iZKHkVS0{Z1Tuv}|lJ-%O^e3I9bEPFym_q2J%11hry+K8c$`>OIsu#mZ zq%3+3(KE)RfdG@f@aL1}+3Mf2>+SolYeoN>)kM~(2C}f#V0SCq>{ji5g)OJL>{g^g z+xHmv-r;O07*!yk<q^T4H9(N*U zB+lmabVk8GY94wMkZ)4u(0;Yeq1m@?#F(H=*R7XBbB+pQ2P4%nX70`?WRHP??5{kN zPv;R`chBB=2CdDnoM0LO;;Yu=5??U~D*WW3Ot>K#seysi0IlUpHzbuwo;K&e&~hQL zhz2$|XmQY*3k^8KNKmW+x02twXxP7-#vLpG literal 0 HcmV?d00001 From f06cef5d40ce1bb6c383c328fe528409e993ff1d Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 9 Nov 2018 08:38:52 +0000 Subject: [PATCH 2/3] JavaScript: Port JSDoc parser to Java. --- .../src/com/semmle/js/ast/SourceLocation.java | 4 + .../src/com/semmle/js/parser/JSDocParser.java | 1776 ++++++++++++++++- .../extractor/tests/comments/input/jsdoc.js | 25 + .../tests/comments/output/trap/jsdoc.js.trap | 650 ++++-- 4 files changed, 2217 insertions(+), 238 deletions(-) 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/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/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") From f26d47aacb48263e1e1e98679920dd2129a79ef9 Mon Sep 17 00:00:00 2001 From: Max Schaefer Date: Fri, 9 Nov 2018 08:50:55 +0000 Subject: [PATCH 3/3] JavaScript: Bump extractor version. This is not so much because extractor output has changed (it hasn't, except for corner cases) but to disable trap caching so as to help us to flush out bugs. --- javascript/extractor/src/com/semmle/js/extractor/Main.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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");