Add support for '\q{}' escape sequence in regular expressions.

This commit is contained in:
Napalys
2025-02-28 18:51:24 +01:00
parent d162acf02c
commit ed418be97a
5 changed files with 203 additions and 267 deletions

View File

@@ -0,0 +1,25 @@
package com.semmle.js.ast.regexp;
import com.semmle.js.ast.SourceLocation;
/**
* A '\q{}' escape sequence in a regular expression, which is a special extension
* to standard regular expressions.
*/
public class CharacterClassQuotedString extends RegExpTerm {
private final RegExpTerm term;
public CharacterClassQuotedString(SourceLocation loc, RegExpTerm term) {
super(loc, "CharacterClassQuotedString");
this.term = term;
}
public RegExpTerm getTerm() {
return term;
}
@Override
public void accept(Visitor v) {
v.visit(this);
}
}

View File

@@ -61,4 +61,6 @@ public interface Visitor {
public void visit(ZeroWidthNegativeLookbehind nd); public void visit(ZeroWidthNegativeLookbehind nd);
public void visit(UnicodePropertyEscape nd); public void visit(UnicodePropertyEscape nd);
public void visit(CharacterClassQuotedString nd);
} }

View File

@@ -10,6 +10,7 @@ import com.semmle.js.ast.regexp.BackReference;
import com.semmle.js.ast.regexp.Caret; import com.semmle.js.ast.regexp.Caret;
import com.semmle.js.ast.regexp.CharacterClass; import com.semmle.js.ast.regexp.CharacterClass;
import com.semmle.js.ast.regexp.CharacterClassEscape; import com.semmle.js.ast.regexp.CharacterClassEscape;
import com.semmle.js.ast.regexp.CharacterClassQuotedString;
import com.semmle.js.ast.regexp.CharacterClassRange; import com.semmle.js.ast.regexp.CharacterClassRange;
import com.semmle.js.ast.regexp.Constant; import com.semmle.js.ast.regexp.Constant;
import com.semmle.js.ast.regexp.ControlEscape; import com.semmle.js.ast.regexp.ControlEscape;
@@ -92,6 +93,7 @@ public class RegExpExtractor {
termkinds.put("ZeroWidthPositiveLookbehind", 25); termkinds.put("ZeroWidthPositiveLookbehind", 25);
termkinds.put("ZeroWidthNegativeLookbehind", 26); termkinds.put("ZeroWidthNegativeLookbehind", 26);
termkinds.put("UnicodePropertyEscape", 27); termkinds.put("UnicodePropertyEscape", 27);
termkinds.put("CharacterClassQuotedString", 28);
} }
private static final String[] errmsgs = private static final String[] errmsgs =
@@ -344,6 +346,12 @@ public class RegExpExtractor {
visit(nd.getLeft(), lbl, 0); visit(nd.getLeft(), lbl, 0);
visit(nd.getRight(), lbl, 1); visit(nd.getRight(), lbl, 1);
} }
@Override
public void visit(CharacterClassQuotedString nd) {
Label lbl = extractTerm(nd, parent, idx);
visit(nd.getTerm(), lbl, 0);
}
} }
public void extract(String src, SourceMap sourceMap, Node parent, boolean isSpeculativeParsing, String flags) { public void extract(String src, SourceMap sourceMap, Node parent, boolean isSpeculativeParsing, String flags) {

View File

@@ -6,6 +6,7 @@ import com.semmle.js.ast.regexp.BackReference;
import com.semmle.js.ast.regexp.Caret; import com.semmle.js.ast.regexp.Caret;
import com.semmle.js.ast.regexp.CharacterClass; import com.semmle.js.ast.regexp.CharacterClass;
import com.semmle.js.ast.regexp.CharacterClassEscape; import com.semmle.js.ast.regexp.CharacterClassEscape;
import com.semmle.js.ast.regexp.CharacterClassQuotedString;
import com.semmle.js.ast.regexp.CharacterClassRange; import com.semmle.js.ast.regexp.CharacterClassRange;
import com.semmle.js.ast.regexp.Constant; import com.semmle.js.ast.regexp.Constant;
import com.semmle.js.ast.regexp.ControlEscape; import com.semmle.js.ast.regexp.ControlEscape;
@@ -283,6 +284,45 @@ public class RegExpParser {
return this.finishTerm(this.parseQuantifierOpt(loc, this.parseAtom())); return this.finishTerm(this.parseQuantifierOpt(loc, this.parseAtom()));
} }
private RegExpTerm parseDisjunctionInsideQuotedString() {
SourceLocation loc = new SourceLocation(pos());
List<RegExpTerm> disjuncts = new ArrayList<>();
disjuncts.add(this.parseAlternativeInsideQuotedString());
while (this.match("|")) {
disjuncts.add(this.parseAlternativeInsideQuotedString());
}
if (disjuncts.size() == 1) return disjuncts.get(0);
return this.finishTerm(new Disjunction(loc, disjuncts));
}
private RegExpTerm parseAlternativeInsideQuotedString() {
SourceLocation loc = new SourceLocation(pos());
StringBuilder sb = new StringBuilder();
boolean escaped = false;
while (true) {
// If we're at the end of the string, something went wrong.
if (this.atEOS()) {
this.error(Error.UNEXPECTED_EOS);
break;
}
// We can end parsing if we're not escaped and we see a `|` which would mean Alternation
// or `}` which would mean the end of the Quoted String.
if(!escaped && this.lookahead(null, "|", "}")){
break;
}
char c = this.nextChar();
// Track whether the character is an escape character.
escaped = !escaped && (c == '\\');
sb.append(c);
}
String literal = sb.toString();
loc.setEnd(pos());
loc.setSource(literal);
return new Constant(loc, literal);
}
private RegExpTerm parseQuantifierOpt(SourceLocation loc, RegExpTerm atom) { private RegExpTerm parseQuantifierOpt(SourceLocation loc, RegExpTerm atom) {
if (this.match("*")) return this.finishTerm(new Star(loc, atom, !this.match("?"))); if (this.match("*")) return this.finishTerm(new Star(loc, atom, !this.match("?")));
if (this.match("+")) return this.finishTerm(new Plus(loc, atom, !this.match("?"))); if (this.match("+")) return this.finishTerm(new Plus(loc, atom, !this.match("?")));
@@ -427,6 +467,12 @@ public class RegExpParser {
return this.finishTerm(new NamedBackReference(loc, name, "\\k<" + name + ">")); return this.finishTerm(new NamedBackReference(loc, name, "\\k<" + name + ">"));
} }
if (this.match("q{")) {
RegExpTerm term = parseDisjunctionInsideQuotedString();
this.expectRBrace();
return this.finishTerm(new CharacterClassQuotedString(loc, term));
}
if (this.match("p{", "P{")) { if (this.match("p{", "P{")) {
String name = this.readIdentifier(); String name = this.readIdentifier();
if (this.match("=")) { if (this.match("=")) {

View File

@@ -115,317 +115,172 @@ regexpterm(#20037,23,#20036,0,"[\q{abc}]")
locations_default(#20038,#10000,1,2,1,10) locations_default(#20038,#10000,1,2,1,10)
hasLocation(#20037,#20038) hasLocation(#20037,#20038)
#20039=* #20039=*
regexpterm(#20039,21,#20037,0,"\q") regexpterm(#20039,28,#20037,0,"\q{abc}")
#20040=@"loc,{#10000},1,3,1,4" #20040=@"loc,{#10000},1,3,1,9"
locations_default(#20040,#10000,1,3,1,4) locations_default(#20040,#10000,1,3,1,9)
hasLocation(#20039,#20040) hasLocation(#20039,#20040)
regexp_const_value(#20039,"q")
#20041=* #20041=*
regexpterm(#20041,14,#20037,1,"{") regexpterm(#20041,14,#20039,0,"abc")
#20042=@"loc,{#10000},1,5,1,5" #20042=@"loc,{#10000},1,6,1,8"
locations_default(#20042,#10000,1,5,1,5) locations_default(#20042,#10000,1,6,1,8)
hasLocation(#20041,#20042) hasLocation(#20041,#20042)
regexp_const_value(#20041,"{") regexp_const_value(#20041,"abc")
#20043=* #20043=*
regexpterm(#20043,14,#20037,2,"a") stmts(#20043,2,#20001,1,"/[\q{ab ... cb}]/v;")
#20044=@"loc,{#10000},1,6,1,6" hasLocation(#20043,#20005)
locations_default(#20044,#10000,1,6,1,6) stmt_containers(#20043,#20001)
hasLocation(#20043,#20044) #20044=*
regexp_const_value(#20043,"a") exprs(#20044,5,#20043,0,"/[\q{abc|cbd|dcb}]/v")
hasLocation(#20044,#20017)
enclosing_stmt(#20044,#20043)
expr_containers(#20044,#20001)
literals("/[\q{abc|cbd|dcb}]/v","/[\q{abc|cbd|dcb}]/v",#20044)
#20045=* #20045=*
regexpterm(#20045,14,#20037,3,"b") regexpterm(#20045,23,#20044,0,"[\q{abc|cbd|dcb}]")
#20046=@"loc,{#10000},1,7,1,7" #20046=@"loc,{#10000},2,2,2,18"
locations_default(#20046,#10000,1,7,1,7) locations_default(#20046,#10000,2,2,2,18)
hasLocation(#20045,#20046) hasLocation(#20045,#20046)
regexp_const_value(#20045,"b")
#20047=* #20047=*
regexpterm(#20047,14,#20037,4,"c") regexpterm(#20047,28,#20045,0,"\q{abc|cbd|dcb}")
#20048=@"loc,{#10000},1,8,1,8" #20048=@"loc,{#10000},2,3,2,17"
locations_default(#20048,#10000,1,8,1,8) locations_default(#20048,#10000,2,3,2,17)
hasLocation(#20047,#20048) hasLocation(#20047,#20048)
regexp_const_value(#20047,"c")
#20049=* #20049=*
regexpterm(#20049,14,#20037,5,"}") regexpterm(#20049,0,#20047,0,"abc|cbd|dcb")
#20050=@"loc,{#10000},1,9,1,9" #20050=@"loc,{#10000},2,6,2,16"
locations_default(#20050,#10000,1,9,1,9) locations_default(#20050,#10000,2,6,2,16)
hasLocation(#20049,#20050) hasLocation(#20049,#20050)
regexp_const_value(#20049,"}")
#20051=* #20051=*
stmts(#20051,2,#20001,1,"/[\q{ab ... cb}]/v;") regexpterm(#20051,14,#20049,0,"abc")
hasLocation(#20051,#20005) #20052=@"loc,{#10000},2,6,2,8"
stmt_containers(#20051,#20001) locations_default(#20052,#10000,2,6,2,8)
#20052=* hasLocation(#20051,#20052)
exprs(#20052,5,#20051,0,"/[\q{abc|cbd|dcb}]/v") regexp_const_value(#20051,"abc")
hasLocation(#20052,#20017)
enclosing_stmt(#20052,#20051)
expr_containers(#20052,#20001)
literals("/[\q{abc|cbd|dcb}]/v","/[\q{abc|cbd|dcb}]/v",#20052)
#20053=* #20053=*
regexpterm(#20053,23,#20052,0,"[\q{abc|cbd|dcb}]") regexpterm(#20053,14,#20049,1,"cbd")
#20054=@"loc,{#10000},2,2,2,18" #20054=@"loc,{#10000},2,10,2,12"
locations_default(#20054,#10000,2,2,2,18) locations_default(#20054,#10000,2,10,2,12)
hasLocation(#20053,#20054) hasLocation(#20053,#20054)
regexp_const_value(#20053,"cbd")
#20055=* #20055=*
regexpterm(#20055,21,#20053,0,"\q") regexpterm(#20055,14,#20049,2,"dcb")
#20056=@"loc,{#10000},2,3,2,4" #20056=@"loc,{#10000},2,14,2,16"
locations_default(#20056,#10000,2,3,2,4) locations_default(#20056,#10000,2,14,2,16)
hasLocation(#20055,#20056) hasLocation(#20055,#20056)
regexp_const_value(#20055,"q") regexp_const_value(#20055,"dcb")
#20057=* #20057=*
regexpterm(#20057,14,#20053,1,"{") stmts(#20057,2,#20001,2,"/[\q{\}}]/v;")
#20058=@"loc,{#10000},2,5,2,5" hasLocation(#20057,#20007)
locations_default(#20058,#10000,2,5,2,5) stmt_containers(#20057,#20001)
hasLocation(#20057,#20058) #20058=*
regexp_const_value(#20057,"{") exprs(#20058,5,#20057,0,"/[\q{\}}]/v")
hasLocation(#20058,#20021)
enclosing_stmt(#20058,#20057)
expr_containers(#20058,#20001)
literals("/[\q{\}}]/v","/[\q{\}}]/v",#20058)
#20059=* #20059=*
regexpterm(#20059,14,#20053,2,"a") regexpterm(#20059,23,#20058,0,"[\q{\}}]")
#20060=@"loc,{#10000},2,6,2,6" #20060=@"loc,{#10000},3,2,3,9"
locations_default(#20060,#10000,2,6,2,6) locations_default(#20060,#10000,3,2,3,9)
hasLocation(#20059,#20060) hasLocation(#20059,#20060)
regexp_const_value(#20059,"a")
#20061=* #20061=*
regexpterm(#20061,14,#20053,3,"b") regexpterm(#20061,28,#20059,0,"\q{\}}")
#20062=@"loc,{#10000},2,7,2,7" #20062=@"loc,{#10000},3,3,3,8"
locations_default(#20062,#10000,2,7,2,7) locations_default(#20062,#10000,3,3,3,8)
hasLocation(#20061,#20062) hasLocation(#20061,#20062)
regexp_const_value(#20061,"b")
#20063=* #20063=*
regexpterm(#20063,14,#20053,4,"c") regexpterm(#20063,14,#20061,0,"\}")
#20064=@"loc,{#10000},2,8,2,8" #20064=@"loc,{#10000},3,6,3,7"
locations_default(#20064,#10000,2,8,2,8) locations_default(#20064,#10000,3,6,3,7)
hasLocation(#20063,#20064) hasLocation(#20063,#20064)
regexp_const_value(#20063,"c") regexp_const_value(#20063,"\}")
#20065=* #20065=*
regexpterm(#20065,14,#20053,5,"|") stmts(#20065,2,#20001,3,"/[\q{\{}]/v;")
#20066=@"loc,{#10000},2,9,2,9" hasLocation(#20065,#20009)
locations_default(#20066,#10000,2,9,2,9) stmt_containers(#20065,#20001)
hasLocation(#20065,#20066) #20066=*
regexp_const_value(#20065,"|") exprs(#20066,5,#20065,0,"/[\q{\{}]/v")
hasLocation(#20066,#20025)
enclosing_stmt(#20066,#20065)
expr_containers(#20066,#20001)
literals("/[\q{\{}]/v","/[\q{\{}]/v",#20066)
#20067=* #20067=*
regexpterm(#20067,14,#20053,6,"c") regexpterm(#20067,23,#20066,0,"[\q{\{}]")
#20068=@"loc,{#10000},2,10,2,10" #20068=@"loc,{#10000},4,2,4,9"
locations_default(#20068,#10000,2,10,2,10) locations_default(#20068,#10000,4,2,4,9)
hasLocation(#20067,#20068) hasLocation(#20067,#20068)
regexp_const_value(#20067,"c")
#20069=* #20069=*
regexpterm(#20069,14,#20053,7,"b") regexpterm(#20069,28,#20067,0,"\q{\{}")
#20070=@"loc,{#10000},2,11,2,11" #20070=@"loc,{#10000},4,3,4,8"
locations_default(#20070,#10000,2,11,2,11) locations_default(#20070,#10000,4,3,4,8)
hasLocation(#20069,#20070) hasLocation(#20069,#20070)
regexp_const_value(#20069,"b")
#20071=* #20071=*
regexpterm(#20071,14,#20053,8,"d") regexpterm(#20071,14,#20069,0,"\{")
#20072=@"loc,{#10000},2,12,2,12" #20072=@"loc,{#10000},4,6,4,7"
locations_default(#20072,#10000,2,12,2,12) locations_default(#20072,#10000,4,6,4,7)
hasLocation(#20071,#20072) hasLocation(#20071,#20072)
regexp_const_value(#20071,"d") regexp_const_value(#20071,"\{")
#20073=* #20073=*
regexpterm(#20073,14,#20053,9,"|") stmts(#20073,2,#20001,4,"/[\q{cc|\}a|cc}]/v;")
#20074=@"loc,{#10000},2,13,2,13" hasLocation(#20073,#20011)
locations_default(#20074,#10000,2,13,2,13) stmt_containers(#20073,#20001)
hasLocation(#20073,#20074) #20074=*
regexp_const_value(#20073,"|") exprs(#20074,5,#20073,0,"/[\q{cc|\}a|cc}]/v")
hasLocation(#20074,#20029)
enclosing_stmt(#20074,#20073)
expr_containers(#20074,#20001)
literals("/[\q{cc|\}a|cc}]/v","/[\q{cc|\}a|cc}]/v",#20074)
#20075=* #20075=*
regexpterm(#20075,14,#20053,10,"d") regexpterm(#20075,23,#20074,0,"[\q{cc|\}a|cc}]")
#20076=@"loc,{#10000},2,14,2,14" #20076=@"loc,{#10000},5,2,5,16"
locations_default(#20076,#10000,2,14,2,14) locations_default(#20076,#10000,5,2,5,16)
hasLocation(#20075,#20076) hasLocation(#20075,#20076)
regexp_const_value(#20075,"d")
#20077=* #20077=*
regexpterm(#20077,14,#20053,11,"c") regexpterm(#20077,28,#20075,0,"\q{cc|\}a|cc}")
#20078=@"loc,{#10000},2,15,2,15" #20078=@"loc,{#10000},5,3,5,15"
locations_default(#20078,#10000,2,15,2,15) locations_default(#20078,#10000,5,3,5,15)
hasLocation(#20077,#20078) hasLocation(#20077,#20078)
regexp_const_value(#20077,"c")
#20079=* #20079=*
regexpterm(#20079,14,#20053,12,"b") regexpterm(#20079,0,#20077,0,"cc|\}a|cc")
#20080=@"loc,{#10000},2,16,2,16" #20080=@"loc,{#10000},5,6,5,14"
locations_default(#20080,#10000,2,16,2,16) locations_default(#20080,#10000,5,6,5,14)
hasLocation(#20079,#20080) hasLocation(#20079,#20080)
regexp_const_value(#20079,"b")
#20081=* #20081=*
regexpterm(#20081,14,#20053,13,"}") regexpterm(#20081,14,#20079,0,"cc")
#20082=@"loc,{#10000},2,17,2,17" #20082=@"loc,{#10000},5,6,5,7"
locations_default(#20082,#10000,2,17,2,17) locations_default(#20082,#10000,5,6,5,7)
hasLocation(#20081,#20082) hasLocation(#20081,#20082)
regexp_const_value(#20081,"}") regexp_const_value(#20081,"cc")
#20083=* #20083=*
stmts(#20083,2,#20001,2,"/[\q{\}}]/v;") regexpterm(#20083,14,#20079,1,"\}a")
hasLocation(#20083,#20007) #20084=@"loc,{#10000},5,9,5,11"
stmt_containers(#20083,#20001) locations_default(#20084,#10000,5,9,5,11)
#20084=* hasLocation(#20083,#20084)
exprs(#20084,5,#20083,0,"/[\q{\}}]/v") regexp_const_value(#20083,"\}a")
hasLocation(#20084,#20021)
enclosing_stmt(#20084,#20083)
expr_containers(#20084,#20001)
literals("/[\q{\}}]/v","/[\q{\}}]/v",#20084)
#20085=* #20085=*
regexpterm(#20085,23,#20084,0,"[\q{\}}]") regexpterm(#20085,14,#20079,2,"cc")
#20086=@"loc,{#10000},3,2,3,9" #20086=@"loc,{#10000},5,13,5,14"
locations_default(#20086,#10000,3,2,3,9) locations_default(#20086,#10000,5,13,5,14)
hasLocation(#20085,#20086) hasLocation(#20085,#20086)
regexp_const_value(#20085,"cc")
#20087=* #20087=*
regexpterm(#20087,21,#20085,0,"\q") entry_cfg_node(#20087,#20001)
#20088=@"loc,{#10000},3,3,3,4" #20088=@"loc,{#10000},1,1,1,0"
locations_default(#20088,#10000,3,3,3,4) locations_default(#20088,#10000,1,1,1,0)
hasLocation(#20087,#20088) hasLocation(#20087,#20088)
regexp_const_value(#20087,"q")
#20089=* #20089=*
regexpterm(#20089,14,#20085,1,"{") exit_cfg_node(#20089,#20001)
#20090=@"loc,{#10000},3,5,3,5" hasLocation(#20089,#20033)
locations_default(#20090,#10000,3,5,3,5) successor(#20073,#20074)
hasLocation(#20089,#20090) successor(#20074,#20089)
regexp_const_value(#20089,"{") successor(#20065,#20066)
#20091=* successor(#20066,#20073)
regexpterm(#20091,21,#20085,2,"\}") successor(#20057,#20058)
#20092=@"loc,{#10000},3,6,3,7" successor(#20058,#20065)
locations_default(#20092,#10000,3,6,3,7) successor(#20043,#20044)
hasLocation(#20091,#20092) successor(#20044,#20057)
regexp_const_value(#20091,"}")
#20093=*
regexpterm(#20093,14,#20085,3,"}")
#20094=@"loc,{#10000},3,8,3,8"
locations_default(#20094,#10000,3,8,3,8)
hasLocation(#20093,#20094)
regexp_const_value(#20093,"}")
#20095=*
stmts(#20095,2,#20001,3,"/[\q{\{}]/v;")
hasLocation(#20095,#20009)
stmt_containers(#20095,#20001)
#20096=*
exprs(#20096,5,#20095,0,"/[\q{\{}]/v")
hasLocation(#20096,#20025)
enclosing_stmt(#20096,#20095)
expr_containers(#20096,#20001)
literals("/[\q{\{}]/v","/[\q{\{}]/v",#20096)
#20097=*
regexpterm(#20097,23,#20096,0,"[\q{\{}]")
#20098=@"loc,{#10000},4,2,4,9"
locations_default(#20098,#10000,4,2,4,9)
hasLocation(#20097,#20098)
#20099=*
regexpterm(#20099,21,#20097,0,"\q")
#20100=@"loc,{#10000},4,3,4,4"
locations_default(#20100,#10000,4,3,4,4)
hasLocation(#20099,#20100)
regexp_const_value(#20099,"q")
#20101=*
regexpterm(#20101,14,#20097,1,"{")
#20102=@"loc,{#10000},4,5,4,5"
locations_default(#20102,#10000,4,5,4,5)
hasLocation(#20101,#20102)
regexp_const_value(#20101,"{")
#20103=*
regexpterm(#20103,21,#20097,2,"\{")
#20104=@"loc,{#10000},4,6,4,7"
locations_default(#20104,#10000,4,6,4,7)
hasLocation(#20103,#20104)
regexp_const_value(#20103,"{")
#20105=*
regexpterm(#20105,14,#20097,3,"}")
#20106=@"loc,{#10000},4,8,4,8"
locations_default(#20106,#10000,4,8,4,8)
hasLocation(#20105,#20106)
regexp_const_value(#20105,"}")
#20107=*
stmts(#20107,2,#20001,4,"/[\q{cc|\}a|cc}]/v;")
hasLocation(#20107,#20011)
stmt_containers(#20107,#20001)
#20108=*
exprs(#20108,5,#20107,0,"/[\q{cc|\}a|cc}]/v")
hasLocation(#20108,#20029)
enclosing_stmt(#20108,#20107)
expr_containers(#20108,#20001)
literals("/[\q{cc|\}a|cc}]/v","/[\q{cc|\}a|cc}]/v",#20108)
#20109=*
regexpterm(#20109,23,#20108,0,"[\q{cc|\}a|cc}]")
#20110=@"loc,{#10000},5,2,5,16"
locations_default(#20110,#10000,5,2,5,16)
hasLocation(#20109,#20110)
#20111=*
regexpterm(#20111,21,#20109,0,"\q")
#20112=@"loc,{#10000},5,3,5,4"
locations_default(#20112,#10000,5,3,5,4)
hasLocation(#20111,#20112)
regexp_const_value(#20111,"q")
#20113=*
regexpterm(#20113,14,#20109,1,"{")
#20114=@"loc,{#10000},5,5,5,5"
locations_default(#20114,#10000,5,5,5,5)
hasLocation(#20113,#20114)
regexp_const_value(#20113,"{")
#20115=*
regexpterm(#20115,14,#20109,2,"c")
#20116=@"loc,{#10000},5,6,5,6"
locations_default(#20116,#10000,5,6,5,6)
hasLocation(#20115,#20116)
regexp_const_value(#20115,"c")
#20117=*
regexpterm(#20117,14,#20109,3,"c")
#20118=@"loc,{#10000},5,7,5,7"
locations_default(#20118,#10000,5,7,5,7)
hasLocation(#20117,#20118)
regexp_const_value(#20117,"c")
#20119=*
regexpterm(#20119,14,#20109,4,"|")
#20120=@"loc,{#10000},5,8,5,8"
locations_default(#20120,#10000,5,8,5,8)
hasLocation(#20119,#20120)
regexp_const_value(#20119,"|")
#20121=*
regexpterm(#20121,21,#20109,5,"\}")
#20122=@"loc,{#10000},5,9,5,10"
locations_default(#20122,#10000,5,9,5,10)
hasLocation(#20121,#20122)
regexp_const_value(#20121,"}")
#20123=*
regexpterm(#20123,14,#20109,6,"a")
#20124=@"loc,{#10000},5,11,5,11"
locations_default(#20124,#10000,5,11,5,11)
hasLocation(#20123,#20124)
regexp_const_value(#20123,"a")
#20125=*
regexpterm(#20125,14,#20109,7,"|")
#20126=@"loc,{#10000},5,12,5,12"
locations_default(#20126,#10000,5,12,5,12)
hasLocation(#20125,#20126)
regexp_const_value(#20125,"|")
#20127=*
regexpterm(#20127,14,#20109,8,"c")
#20128=@"loc,{#10000},5,13,5,13"
locations_default(#20128,#10000,5,13,5,13)
hasLocation(#20127,#20128)
regexp_const_value(#20127,"c")
#20129=*
regexpterm(#20129,14,#20109,9,"c")
#20130=@"loc,{#10000},5,14,5,14"
locations_default(#20130,#10000,5,14,5,14)
hasLocation(#20129,#20130)
regexp_const_value(#20129,"c")
#20131=*
regexpterm(#20131,14,#20109,10,"}")
#20132=@"loc,{#10000},5,15,5,15"
locations_default(#20132,#10000,5,15,5,15)
hasLocation(#20131,#20132)
regexp_const_value(#20131,"}")
#20133=*
entry_cfg_node(#20133,#20001)
#20134=@"loc,{#10000},1,1,1,0"
locations_default(#20134,#10000,1,1,1,0)
hasLocation(#20133,#20134)
#20135=*
exit_cfg_node(#20135,#20001)
hasLocation(#20135,#20033)
successor(#20107,#20108)
successor(#20108,#20135)
successor(#20095,#20096)
successor(#20096,#20107)
successor(#20083,#20084)
successor(#20084,#20095)
successor(#20051,#20052)
successor(#20052,#20083)
successor(#20035,#20036) successor(#20035,#20036)
successor(#20036,#20051) successor(#20036,#20043)
successor(#20133,#20035) successor(#20087,#20035)
numlines(#10000,5,5,0) numlines(#10000,5,5,0)
filetype(#10000,"javascript") filetype(#10000,"javascript")