diff --git a/javascript/extractor/src/com/semmle/js/ast/regexp/CharacterClassUnion.java b/javascript/extractor/src/com/semmle/js/ast/regexp/CharacterClassUnion.java new file mode 100644 index 00000000000..7d3ec4510d5 --- /dev/null +++ b/javascript/extractor/src/com/semmle/js/ast/regexp/CharacterClassUnion.java @@ -0,0 +1,22 @@ +package com.semmle.js.ast.regexp; + +import com.semmle.js.ast.SourceLocation; +import java.util.List; + +public class CharacterClassUnion extends RegExpTerm { + private final List union; + + public CharacterClassUnion(SourceLocation loc, List union) { + super(loc, "CharacterClassUnion"); + this.union = union; + } + + @Override + public void accept(Visitor v) { + v.visit(this); + } + + public List getUnion() { + return union; + } +} diff --git a/javascript/extractor/src/com/semmle/js/ast/regexp/Visitor.java b/javascript/extractor/src/com/semmle/js/ast/regexp/Visitor.java index 373cb727c5a..45f73779488 100644 --- a/javascript/extractor/src/com/semmle/js/ast/regexp/Visitor.java +++ b/javascript/extractor/src/com/semmle/js/ast/regexp/Visitor.java @@ -67,4 +67,6 @@ public interface Visitor { public void visit(CharacterClassIntersection nd); public void visit(CharacterClassSubtraction nd); + + public void visit(CharacterClassUnion nd); } diff --git a/javascript/extractor/src/com/semmle/js/extractor/RegExpExtractor.java b/javascript/extractor/src/com/semmle/js/extractor/RegExpExtractor.java index 8d382466c41..4fbf1b4f6cf 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/RegExpExtractor.java +++ b/javascript/extractor/src/com/semmle/js/extractor/RegExpExtractor.java @@ -13,6 +13,7 @@ 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.CharacterClassSubtraction; +import com.semmle.js.ast.regexp.CharacterClassUnion; import com.semmle.js.ast.regexp.Constant; import com.semmle.js.ast.regexp.ControlEscape; import com.semmle.js.ast.regexp.ControlLetter; @@ -98,6 +99,7 @@ public class RegExpExtractor { termkinds.put("CharacterClassQuotedString", 28); termkinds.put("CharacterClassIntersection", 29); termkinds.put("CharacterClassSubtraction", 30); + termkinds.put("CharacterClassUnion", 31); } private static final String[] errmsgs = @@ -372,6 +374,14 @@ public class RegExpExtractor { for (RegExpTerm element : nd.getSubtraction()) visit(element, lbl, i++); } + + @Override + public void visit(CharacterClassUnion nd) { + Label lbl = extractTerm(nd, parent, idx); + int i = 0; + for (RegExpTerm element : nd.getUnion()) + visit(element, lbl, i++); + } } public void extract(String src, SourceMap sourceMap, Node parent, boolean isSpeculativeParsing, String flags) { diff --git a/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java b/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java index 18cfddf0171..70b3487d88b 100644 --- a/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java +++ b/javascript/extractor/src/com/semmle/js/parser/RegExpParser.java @@ -9,6 +9,7 @@ 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.CharacterClassSubtraction; +import com.semmle.js.ast.regexp.CharacterClassUnion; import com.semmle.js.ast.regexp.Constant; import com.semmle.js.ast.regexp.ControlEscape; import com.semmle.js.ast.regexp.ControlLetter; @@ -568,6 +569,7 @@ public class RegExpParser { STANDARD, INTERSECTION, SUBTRACTION, + UNION } // ECMA 2024 `v` flag allows nested character classes. @@ -599,12 +601,26 @@ public class RegExpParser { } } + boolean containsComplex = elements.stream().anyMatch(term -> term instanceof UnicodePropertyEscape || + term instanceof CharacterClassQuotedString || + term instanceof CharacterClass); + + // Set type to UNION only if: + // 1. We haven't already determined a specific type (intersection/subtraction) + // 2. We have more than one element + // 3. We have at least one complex element (i.e. a nested character class or a UnicodePropertyEscape) + if (containsComplex && classType == CharacterClassType.STANDARD && elements.size() > 1) { + classType = CharacterClassType.UNION; + } + // Create appropriate RegExpTerm based on the detected class type switch (classType) { case INTERSECTION: return this.finishTerm(new CharacterClass(loc, Collections.singletonList(new CharacterClassIntersection(loc, elements)), inverted)); case SUBTRACTION: return this.finishTerm(new CharacterClass(loc, Collections.singletonList(new CharacterClassSubtraction(loc, elements)), inverted)); + case UNION: + return this.finishTerm(new CharacterClass(loc, Collections.singletonList(new CharacterClassUnion(loc, elements)), inverted)); case STANDARD: default: return this.finishTerm(new CharacterClass(loc, elements, inverted)); diff --git a/javascript/extractor/tests/es2024/output/trap/regex_nested_character_class.js.trap b/javascript/extractor/tests/es2024/output/trap/regex_nested_character_class.js.trap index c3bc9112cc5..25ba1d8bb6d 100644 --- a/javascript/extractor/tests/es2024/output/trap/regex_nested_character_class.js.trap +++ b/javascript/extractor/tests/es2024/output/trap/regex_nested_character_class.js.trap @@ -137,75 +137,81 @@ regexpterm(#20042,23,#20041,0,"[ [] [ [] [] ] ]") locations_default(#20043,#10000,3,2,3,17) hasLocation(#20042,#20043) #20044=* -regexpterm(#20044,14,#20042,0," ") -#20045=@"loc,{#10000},3,3,3,3" -locations_default(#20045,#10000,3,3,3,3) -hasLocation(#20044,#20045) -regexp_const_value(#20044," ") -#20046=* -regexpterm(#20046,23,#20042,1,"[]") -#20047=@"loc,{#10000},3,4,3,5" -locations_default(#20047,#10000,3,4,3,5) -hasLocation(#20046,#20047) -#20048=* -regexpterm(#20048,14,#20042,2," ") -#20049=@"loc,{#10000},3,6,3,6" -locations_default(#20049,#10000,3,6,3,6) -hasLocation(#20048,#20049) -regexp_const_value(#20048," ") -#20050=* -regexpterm(#20050,23,#20042,3,"[ [] [] ]") -#20051=@"loc,{#10000},3,7,3,15" -locations_default(#20051,#10000,3,7,3,15) -hasLocation(#20050,#20051) -#20052=* -regexpterm(#20052,14,#20050,0," ") -#20053=@"loc,{#10000},3,8,3,8" -locations_default(#20053,#10000,3,8,3,8) -hasLocation(#20052,#20053) -regexp_const_value(#20052," ") +regexpterm(#20044,31,#20042,0,"[ [] [ [] [] ] ]") +hasLocation(#20044,#20043) +#20045=* +regexpterm(#20045,14,#20044,0," ") +#20046=@"loc,{#10000},3,3,3,3" +locations_default(#20046,#10000,3,3,3,3) +hasLocation(#20045,#20046) +regexp_const_value(#20045," ") +#20047=* +regexpterm(#20047,23,#20044,1,"[]") +#20048=@"loc,{#10000},3,4,3,5" +locations_default(#20048,#10000,3,4,3,5) +hasLocation(#20047,#20048) +#20049=* +regexpterm(#20049,14,#20044,2," ") +#20050=@"loc,{#10000},3,6,3,6" +locations_default(#20050,#10000,3,6,3,6) +hasLocation(#20049,#20050) +regexp_const_value(#20049," ") +#20051=* +regexpterm(#20051,23,#20044,3,"[ [] [] ]") +#20052=@"loc,{#10000},3,7,3,15" +locations_default(#20052,#10000,3,7,3,15) +hasLocation(#20051,#20052) +#20053=* +regexpterm(#20053,31,#20051,0,"[ [] [] ]") +hasLocation(#20053,#20052) #20054=* -regexpterm(#20054,23,#20050,1,"[]") -#20055=@"loc,{#10000},3,9,3,10" -locations_default(#20055,#10000,3,9,3,10) +regexpterm(#20054,14,#20053,0," ") +#20055=@"loc,{#10000},3,8,3,8" +locations_default(#20055,#10000,3,8,3,8) hasLocation(#20054,#20055) +regexp_const_value(#20054," ") #20056=* -regexpterm(#20056,14,#20050,2," ") -#20057=@"loc,{#10000},3,11,3,11" -locations_default(#20057,#10000,3,11,3,11) +regexpterm(#20056,23,#20053,1,"[]") +#20057=@"loc,{#10000},3,9,3,10" +locations_default(#20057,#10000,3,9,3,10) hasLocation(#20056,#20057) -regexp_const_value(#20056," ") #20058=* -regexpterm(#20058,23,#20050,3,"[]") -#20059=@"loc,{#10000},3,12,3,13" -locations_default(#20059,#10000,3,12,3,13) +regexpterm(#20058,14,#20053,2," ") +#20059=@"loc,{#10000},3,11,3,11" +locations_default(#20059,#10000,3,11,3,11) hasLocation(#20058,#20059) +regexp_const_value(#20058," ") #20060=* -regexpterm(#20060,14,#20050,4," ") -#20061=@"loc,{#10000},3,14,3,14" -locations_default(#20061,#10000,3,14,3,14) +regexpterm(#20060,23,#20053,3,"[]") +#20061=@"loc,{#10000},3,12,3,13" +locations_default(#20061,#10000,3,12,3,13) hasLocation(#20060,#20061) -regexp_const_value(#20060," ") #20062=* -regexpterm(#20062,14,#20042,4," ") -#20063=@"loc,{#10000},3,16,3,16" -locations_default(#20063,#10000,3,16,3,16) +regexpterm(#20062,14,#20053,4," ") +#20063=@"loc,{#10000},3,14,3,14" +locations_default(#20063,#10000,3,14,3,14) hasLocation(#20062,#20063) regexp_const_value(#20062," ") #20064=* -entry_cfg_node(#20064,#20001) -#20065=@"loc,{#10000},1,1,1,0" -locations_default(#20065,#10000,1,1,1,0) +regexpterm(#20064,14,#20044,4," ") +#20065=@"loc,{#10000},3,16,3,16" +locations_default(#20065,#10000,3,16,3,16) hasLocation(#20064,#20065) +regexp_const_value(#20064," ") #20066=* -exit_cfg_node(#20066,#20001) -hasLocation(#20066,#20023) +entry_cfg_node(#20066,#20001) +#20067=@"loc,{#10000},1,1,1,0" +locations_default(#20067,#10000,1,1,1,0) +hasLocation(#20066,#20067) +#20068=* +exit_cfg_node(#20068,#20001) +hasLocation(#20068,#20023) successor(#20040,#20041) -successor(#20041,#20066) +successor(#20041,#20068) successor(#20032,#20033) successor(#20033,#20040) successor(#20025,#20027) successor(#20027,#20032) -successor(#20064,#20025) +successor(#20066,#20025) numlines(#10000,3,3,1) filetype(#10000,"javascript") diff --git a/javascript/extractor/tests/es2024/output/trap/union.js.trap b/javascript/extractor/tests/es2024/output/trap/union.js.trap index 31d98f755e8..32674c50e53 100644 --- a/javascript/extractor/tests/es2024/output/trap/union.js.trap +++ b/javascript/extractor/tests/es2024/output/trap/union.js.trap @@ -131,262 +131,274 @@ regexpterm(#20043,23,#20042,0,"[\p{Script_Extensions=Greek}\p{RGI_Emoji}]") locations_default(#20044,#10000,1,2,1,43) hasLocation(#20043,#20044) #20045=* -regexpterm(#20045,27,#20043,0,"\p{Script_Extensions=Greek}") -#20046=@"loc,{#10000},1,3,1,29" -locations_default(#20046,#10000,1,3,1,29) -hasLocation(#20045,#20046) -unicode_property_escapename(#20045,"Script_Extensions") -unicode_property_escapevalue(#20045,"Greek") -#20047=* -regexpterm(#20047,27,#20043,1,"\p{RGI_Emoji}") -#20048=@"loc,{#10000},1,30,1,42" -locations_default(#20048,#10000,1,30,1,42) -hasLocation(#20047,#20048) -unicode_property_escapename(#20047,"RGI_Emoji") -#20049=* -stmts(#20049,2,#20001,1,"/[[abc][cbd]]/v;") -hasLocation(#20049,#20005) -stmt_containers(#20049,#20001) +regexpterm(#20045,31,#20043,0,"[\p{Script_Extensions=Greek}\p{RGI_Emoji}]") +hasLocation(#20045,#20044) +#20046=* +regexpterm(#20046,27,#20045,0,"\p{Script_Extensions=Greek}") +#20047=@"loc,{#10000},1,3,1,29" +locations_default(#20047,#10000,1,3,1,29) +hasLocation(#20046,#20047) +unicode_property_escapename(#20046,"Script_Extensions") +unicode_property_escapevalue(#20046,"Greek") +#20048=* +regexpterm(#20048,27,#20045,1,"\p{RGI_Emoji}") +#20049=@"loc,{#10000},1,30,1,42" +locations_default(#20049,#10000,1,30,1,42) +hasLocation(#20048,#20049) +unicode_property_escapename(#20048,"RGI_Emoji") #20050=* -exprs(#20050,5,#20049,0,"/[[abc][cbd]]/v") -hasLocation(#20050,#20019) -enclosing_stmt(#20050,#20049) -expr_containers(#20050,#20001) -literals("/[[abc][cbd]]/v","/[[abc][cbd]]/v",#20050) +stmts(#20050,2,#20001,1,"/[[abc][cbd]]/v;") +hasLocation(#20050,#20005) +stmt_containers(#20050,#20001) #20051=* -regexpterm(#20051,23,#20050,0,"[[abc][cbd]]") -#20052=@"loc,{#10000},2,2,2,13" -locations_default(#20052,#10000,2,2,2,13) -hasLocation(#20051,#20052) -#20053=* -regexpterm(#20053,23,#20051,0,"[abc]") -#20054=@"loc,{#10000},2,3,2,7" -locations_default(#20054,#10000,2,3,2,7) -hasLocation(#20053,#20054) +exprs(#20051,5,#20050,0,"/[[abc][cbd]]/v") +hasLocation(#20051,#20019) +enclosing_stmt(#20051,#20050) +expr_containers(#20051,#20001) +literals("/[[abc][cbd]]/v","/[[abc][cbd]]/v",#20051) +#20052=* +regexpterm(#20052,23,#20051,0,"[[abc][cbd]]") +#20053=@"loc,{#10000},2,2,2,13" +locations_default(#20053,#10000,2,2,2,13) +hasLocation(#20052,#20053) +#20054=* +regexpterm(#20054,31,#20052,0,"[[abc][cbd]]") +hasLocation(#20054,#20053) #20055=* -regexpterm(#20055,14,#20053,0,"a") -#20056=@"loc,{#10000},2,4,2,4" -locations_default(#20056,#10000,2,4,2,4) +regexpterm(#20055,23,#20054,0,"[abc]") +#20056=@"loc,{#10000},2,3,2,7" +locations_default(#20056,#10000,2,3,2,7) hasLocation(#20055,#20056) -regexp_const_value(#20055,"a") #20057=* -regexpterm(#20057,14,#20053,1,"b") -#20058=@"loc,{#10000},2,5,2,5" -locations_default(#20058,#10000,2,5,2,5) +regexpterm(#20057,14,#20055,0,"a") +#20058=@"loc,{#10000},2,4,2,4" +locations_default(#20058,#10000,2,4,2,4) hasLocation(#20057,#20058) -regexp_const_value(#20057,"b") +regexp_const_value(#20057,"a") #20059=* -regexpterm(#20059,14,#20053,2,"c") -#20060=@"loc,{#10000},2,6,2,6" -locations_default(#20060,#10000,2,6,2,6) +regexpterm(#20059,14,#20055,1,"b") +#20060=@"loc,{#10000},2,5,2,5" +locations_default(#20060,#10000,2,5,2,5) hasLocation(#20059,#20060) -regexp_const_value(#20059,"c") +regexp_const_value(#20059,"b") #20061=* -regexpterm(#20061,23,#20051,1,"[cbd]") -#20062=@"loc,{#10000},2,8,2,12" -locations_default(#20062,#10000,2,8,2,12) +regexpterm(#20061,14,#20055,2,"c") +#20062=@"loc,{#10000},2,6,2,6" +locations_default(#20062,#10000,2,6,2,6) hasLocation(#20061,#20062) +regexp_const_value(#20061,"c") #20063=* -regexpterm(#20063,14,#20061,0,"c") -#20064=@"loc,{#10000},2,9,2,9" -locations_default(#20064,#10000,2,9,2,9) +regexpterm(#20063,23,#20054,1,"[cbd]") +#20064=@"loc,{#10000},2,8,2,12" +locations_default(#20064,#10000,2,8,2,12) hasLocation(#20063,#20064) -regexp_const_value(#20063,"c") #20065=* -regexpterm(#20065,14,#20061,1,"b") -#20066=@"loc,{#10000},2,10,2,10" -locations_default(#20066,#10000,2,10,2,10) +regexpterm(#20065,14,#20063,0,"c") +#20066=@"loc,{#10000},2,9,2,9" +locations_default(#20066,#10000,2,9,2,9) hasLocation(#20065,#20066) -regexp_const_value(#20065,"b") +regexp_const_value(#20065,"c") #20067=* -regexpterm(#20067,14,#20061,2,"d") -#20068=@"loc,{#10000},2,11,2,11" -locations_default(#20068,#10000,2,11,2,11) +regexpterm(#20067,14,#20063,1,"b") +#20068=@"loc,{#10000},2,10,2,10" +locations_default(#20068,#10000,2,10,2,10) hasLocation(#20067,#20068) -regexp_const_value(#20067,"d") +regexp_const_value(#20067,"b") #20069=* -stmts(#20069,2,#20001,2,"/[\p{Em ... byz]/v;") -hasLocation(#20069,#20007) -stmt_containers(#20069,#20001) -#20070=* -exprs(#20070,5,#20069,0,"/[\p{Em ... }byz]/v") -hasLocation(#20070,#20023) -enclosing_stmt(#20070,#20069) -expr_containers(#20070,#20001) -literals("/[\p{Emoji}\q{a&}byz]/v","/[\p{Emoji}\q{a&}byz]/v",#20070) +regexpterm(#20069,14,#20063,2,"d") +#20070=@"loc,{#10000},2,11,2,11" +locations_default(#20070,#10000,2,11,2,11) +hasLocation(#20069,#20070) +regexp_const_value(#20069,"d") #20071=* -regexpterm(#20071,23,#20070,0,"[\p{Emoji}\q{a&}byz]") -#20072=@"loc,{#10000},3,2,3,21" -locations_default(#20072,#10000,3,2,3,21) -hasLocation(#20071,#20072) +stmts(#20071,2,#20001,2,"/[\p{Em ... byz]/v;") +hasLocation(#20071,#20007) +stmt_containers(#20071,#20001) +#20072=* +exprs(#20072,5,#20071,0,"/[\p{Em ... }byz]/v") +hasLocation(#20072,#20023) +enclosing_stmt(#20072,#20071) +expr_containers(#20072,#20001) +literals("/[\p{Emoji}\q{a&}byz]/v","/[\p{Emoji}\q{a&}byz]/v",#20072) #20073=* -regexpterm(#20073,27,#20071,0,"\p{Emoji}") -#20074=@"loc,{#10000},3,3,3,11" -locations_default(#20074,#10000,3,3,3,11) +regexpterm(#20073,23,#20072,0,"[\p{Emoji}\q{a&}byz]") +#20074=@"loc,{#10000},3,2,3,21" +locations_default(#20074,#10000,3,2,3,21) hasLocation(#20073,#20074) -unicode_property_escapename(#20073,"Emoji") #20075=* -regexpterm(#20075,28,#20071,1,"\q{a&}") -#20076=@"loc,{#10000},3,12,3,17" -locations_default(#20076,#10000,3,12,3,17) -hasLocation(#20075,#20076) -#20077=* -regexpterm(#20077,14,#20075,0,"a&") -#20078=@"loc,{#10000},3,15,3,16" -locations_default(#20078,#10000,3,15,3,16) -hasLocation(#20077,#20078) -regexp_const_value(#20077,"a&") -#20079=* -regexpterm(#20079,14,#20071,2,"b") -#20080=@"loc,{#10000},3,18,3,18" -locations_default(#20080,#10000,3,18,3,18) -hasLocation(#20079,#20080) -regexp_const_value(#20079,"b") -#20081=* -regexpterm(#20081,14,#20071,3,"y") -#20082=@"loc,{#10000},3,19,3,19" -locations_default(#20082,#10000,3,19,3,19) -hasLocation(#20081,#20082) -regexp_const_value(#20081,"y") -#20083=* -regexpterm(#20083,14,#20071,4,"z") -#20084=@"loc,{#10000},3,20,3,20" -locations_default(#20084,#10000,3,20,3,20) -hasLocation(#20083,#20084) -regexp_const_value(#20083,"z") -#20085=* -stmts(#20085,2,#20001,3,"/[\q{\\\}a&}byz]/v;") -hasLocation(#20085,#20009) -stmt_containers(#20085,#20001) +regexpterm(#20075,31,#20073,0,"[\p{Emoji}\q{a&}byz]") +hasLocation(#20075,#20074) +#20076=* +regexpterm(#20076,27,#20075,0,"\p{Emoji}") +#20077=@"loc,{#10000},3,3,3,11" +locations_default(#20077,#10000,3,3,3,11) +hasLocation(#20076,#20077) +unicode_property_escapename(#20076,"Emoji") +#20078=* +regexpterm(#20078,28,#20075,1,"\q{a&}") +#20079=@"loc,{#10000},3,12,3,17" +locations_default(#20079,#10000,3,12,3,17) +hasLocation(#20078,#20079) +#20080=* +regexpterm(#20080,14,#20078,0,"a&") +#20081=@"loc,{#10000},3,15,3,16" +locations_default(#20081,#10000,3,15,3,16) +hasLocation(#20080,#20081) +regexp_const_value(#20080,"a&") +#20082=* +regexpterm(#20082,14,#20075,2,"b") +#20083=@"loc,{#10000},3,18,3,18" +locations_default(#20083,#10000,3,18,3,18) +hasLocation(#20082,#20083) +regexp_const_value(#20082,"b") +#20084=* +regexpterm(#20084,14,#20075,3,"y") +#20085=@"loc,{#10000},3,19,3,19" +locations_default(#20085,#10000,3,19,3,19) +hasLocation(#20084,#20085) +regexp_const_value(#20084,"y") #20086=* -exprs(#20086,5,#20085,0,"/[\q{\\\}a&}byz]/v") -hasLocation(#20086,#20027) -enclosing_stmt(#20086,#20085) -expr_containers(#20086,#20001) -literals("/[\q{\\\}a&}byz]/v","/[\q{\\\}a&}byz]/v",#20086) -#20087=* -regexpterm(#20087,23,#20086,0,"[\q{\\\}a&}byz]") -#20088=@"loc,{#10000},4,2,4,16" -locations_default(#20088,#10000,4,2,4,16) -hasLocation(#20087,#20088) +regexpterm(#20086,14,#20075,4,"z") +#20087=@"loc,{#10000},3,20,3,20" +locations_default(#20087,#10000,3,20,3,20) +hasLocation(#20086,#20087) +regexp_const_value(#20086,"z") +#20088=* +stmts(#20088,2,#20001,3,"/[\q{\\\}a&}byz]/v;") +hasLocation(#20088,#20009) +stmt_containers(#20088,#20001) #20089=* -regexpterm(#20089,28,#20087,0,"\q{\\\}a&}") -#20090=@"loc,{#10000},4,3,4,12" -locations_default(#20090,#10000,4,3,4,12) -hasLocation(#20089,#20090) -#20091=* -regexpterm(#20091,14,#20089,0,"\\\}a&") -#20092=@"loc,{#10000},4,6,4,11" -locations_default(#20092,#10000,4,6,4,11) -hasLocation(#20091,#20092) -regexp_const_value(#20091,"\\\}a&") +exprs(#20089,5,#20088,0,"/[\q{\\\}a&}byz]/v") +hasLocation(#20089,#20027) +enclosing_stmt(#20089,#20088) +expr_containers(#20089,#20001) +literals("/[\q{\\\}a&}byz]/v","/[\q{\\\}a&}byz]/v",#20089) +#20090=* +regexpterm(#20090,23,#20089,0,"[\q{\\\}a&}byz]") +#20091=@"loc,{#10000},4,2,4,16" +locations_default(#20091,#10000,4,2,4,16) +hasLocation(#20090,#20091) +#20092=* +regexpterm(#20092,31,#20090,0,"[\q{\\\}a&}byz]") +hasLocation(#20092,#20091) #20093=* -regexpterm(#20093,14,#20087,1,"b") -#20094=@"loc,{#10000},4,13,4,13" -locations_default(#20094,#10000,4,13,4,13) +regexpterm(#20093,28,#20092,0,"\q{\\\}a&}") +#20094=@"loc,{#10000},4,3,4,12" +locations_default(#20094,#10000,4,3,4,12) hasLocation(#20093,#20094) -regexp_const_value(#20093,"b") #20095=* -regexpterm(#20095,14,#20087,2,"y") -#20096=@"loc,{#10000},4,14,4,14" -locations_default(#20096,#10000,4,14,4,14) +regexpterm(#20095,14,#20093,0,"\\\}a&") +#20096=@"loc,{#10000},4,6,4,11" +locations_default(#20096,#10000,4,6,4,11) hasLocation(#20095,#20096) -regexp_const_value(#20095,"y") +regexp_const_value(#20095,"\\\}a&") #20097=* -regexpterm(#20097,14,#20087,3,"z") -#20098=@"loc,{#10000},4,15,4,15" -locations_default(#20098,#10000,4,15,4,15) +regexpterm(#20097,14,#20092,1,"b") +#20098=@"loc,{#10000},4,13,4,13" +locations_default(#20098,#10000,4,13,4,13) hasLocation(#20097,#20098) -regexp_const_value(#20097,"z") +regexp_const_value(#20097,"b") #20099=* -stmts(#20099,2,#20001,4,"/[\q{\\}]/v;") -hasLocation(#20099,#20011) -stmt_containers(#20099,#20001) -#20100=* -exprs(#20100,5,#20099,0,"/[\q{\\}]/v") -hasLocation(#20100,#20031) -enclosing_stmt(#20100,#20099) -expr_containers(#20100,#20001) -literals("/[\q{\\}]/v","/[\q{\\}]/v",#20100) +regexpterm(#20099,14,#20092,2,"y") +#20100=@"loc,{#10000},4,14,4,14" +locations_default(#20100,#10000,4,14,4,14) +hasLocation(#20099,#20100) +regexp_const_value(#20099,"y") #20101=* -regexpterm(#20101,23,#20100,0,"[\q{\\}]") -#20102=@"loc,{#10000},5,2,5,9" -locations_default(#20102,#10000,5,2,5,9) +regexpterm(#20101,14,#20092,3,"z") +#20102=@"loc,{#10000},4,15,4,15" +locations_default(#20102,#10000,4,15,4,15) hasLocation(#20101,#20102) +regexp_const_value(#20101,"z") #20103=* -regexpterm(#20103,28,#20101,0,"\q{\\}") -#20104=@"loc,{#10000},5,3,5,8" -locations_default(#20104,#10000,5,3,5,8) -hasLocation(#20103,#20104) +stmts(#20103,2,#20001,4,"/[\q{\\}]/v;") +hasLocation(#20103,#20011) +stmt_containers(#20103,#20001) +#20104=* +exprs(#20104,5,#20103,0,"/[\q{\\}]/v") +hasLocation(#20104,#20031) +enclosing_stmt(#20104,#20103) +expr_containers(#20104,#20001) +literals("/[\q{\\}]/v","/[\q{\\}]/v",#20104) #20105=* -regexpterm(#20105,14,#20103,0,"\\") -#20106=@"loc,{#10000},5,6,5,7" -locations_default(#20106,#10000,5,6,5,7) +regexpterm(#20105,23,#20104,0,"[\q{\\}]") +#20106=@"loc,{#10000},5,2,5,9" +locations_default(#20106,#10000,5,2,5,9) hasLocation(#20105,#20106) -regexp_const_value(#20105,"\\") #20107=* -stmts(#20107,2,#20001,5,"/[\q{abc|cbd|\}}]/v;") -hasLocation(#20107,#20013) -stmt_containers(#20107,#20001) -#20108=* -exprs(#20108,5,#20107,0,"/[\q{abc|cbd|\}}]/v") -hasLocation(#20108,#20035) -enclosing_stmt(#20108,#20107) -expr_containers(#20108,#20001) -literals("/[\q{abc|cbd|\}}]/v","/[\q{abc|cbd|\}}]/v",#20108) +regexpterm(#20107,28,#20105,0,"\q{\\}") +#20108=@"loc,{#10000},5,3,5,8" +locations_default(#20108,#10000,5,3,5,8) +hasLocation(#20107,#20108) #20109=* -regexpterm(#20109,23,#20108,0,"[\q{abc|cbd|\}}]") -#20110=@"loc,{#10000},6,2,6,17" -locations_default(#20110,#10000,6,2,6,17) +regexpterm(#20109,14,#20107,0,"\\") +#20110=@"loc,{#10000},5,6,5,7" +locations_default(#20110,#10000,5,6,5,7) hasLocation(#20109,#20110) +regexp_const_value(#20109,"\\") #20111=* -regexpterm(#20111,28,#20109,0,"\q{abc|cbd|\}}") -#20112=@"loc,{#10000},6,3,6,16" -locations_default(#20112,#10000,6,3,6,16) -hasLocation(#20111,#20112) +stmts(#20111,2,#20001,5,"/[\q{abc|cbd|\}}]/v;") +hasLocation(#20111,#20013) +stmt_containers(#20111,#20001) +#20112=* +exprs(#20112,5,#20111,0,"/[\q{abc|cbd|\}}]/v") +hasLocation(#20112,#20035) +enclosing_stmt(#20112,#20111) +expr_containers(#20112,#20001) +literals("/[\q{abc|cbd|\}}]/v","/[\q{abc|cbd|\}}]/v",#20112) #20113=* -regexpterm(#20113,0,#20111,0,"abc|cbd|\}") -#20114=@"loc,{#10000},6,6,6,15" -locations_default(#20114,#10000,6,6,6,15) +regexpterm(#20113,23,#20112,0,"[\q{abc|cbd|\}}]") +#20114=@"loc,{#10000},6,2,6,17" +locations_default(#20114,#10000,6,2,6,17) hasLocation(#20113,#20114) #20115=* -regexpterm(#20115,14,#20113,0,"abc") -#20116=@"loc,{#10000},6,6,6,8" -locations_default(#20116,#10000,6,6,6,8) +regexpterm(#20115,28,#20113,0,"\q{abc|cbd|\}}") +#20116=@"loc,{#10000},6,3,6,16" +locations_default(#20116,#10000,6,3,6,16) hasLocation(#20115,#20116) -regexp_const_value(#20115,"abc") #20117=* -regexpterm(#20117,14,#20113,1,"cbd") -#20118=@"loc,{#10000},6,10,6,12" -locations_default(#20118,#10000,6,10,6,12) +regexpterm(#20117,0,#20115,0,"abc|cbd|\}") +#20118=@"loc,{#10000},6,6,6,15" +locations_default(#20118,#10000,6,6,6,15) hasLocation(#20117,#20118) -regexp_const_value(#20117,"cbd") #20119=* -regexpterm(#20119,14,#20113,2,"\}") -#20120=@"loc,{#10000},6,14,6,15" -locations_default(#20120,#10000,6,14,6,15) +regexpterm(#20119,14,#20117,0,"abc") +#20120=@"loc,{#10000},6,6,6,8" +locations_default(#20120,#10000,6,6,6,8) hasLocation(#20119,#20120) -regexp_const_value(#20119,"\}") +regexp_const_value(#20119,"abc") #20121=* -entry_cfg_node(#20121,#20001) -#20122=@"loc,{#10000},1,1,1,0" -locations_default(#20122,#10000,1,1,1,0) +regexpterm(#20121,14,#20117,1,"cbd") +#20122=@"loc,{#10000},6,10,6,12" +locations_default(#20122,#10000,6,10,6,12) hasLocation(#20121,#20122) +regexp_const_value(#20121,"cbd") #20123=* -exit_cfg_node(#20123,#20001) -hasLocation(#20123,#20039) -successor(#20107,#20108) -successor(#20108,#20123) -successor(#20099,#20100) -successor(#20100,#20107) -successor(#20085,#20086) -successor(#20086,#20099) -successor(#20069,#20070) -successor(#20070,#20085) -successor(#20049,#20050) -successor(#20050,#20069) +regexpterm(#20123,14,#20117,2,"\}") +#20124=@"loc,{#10000},6,14,6,15" +locations_default(#20124,#10000,6,14,6,15) +hasLocation(#20123,#20124) +regexp_const_value(#20123,"\}") +#20125=* +entry_cfg_node(#20125,#20001) +#20126=@"loc,{#10000},1,1,1,0" +locations_default(#20126,#10000,1,1,1,0) +hasLocation(#20125,#20126) +#20127=* +exit_cfg_node(#20127,#20001) +hasLocation(#20127,#20039) +successor(#20111,#20112) +successor(#20112,#20127) +successor(#20103,#20104) +successor(#20104,#20111) +successor(#20088,#20089) +successor(#20089,#20103) +successor(#20071,#20072) +successor(#20072,#20088) +successor(#20050,#20051) +successor(#20051,#20071) successor(#20041,#20042) -successor(#20042,#20049) -successor(#20121,#20041) +successor(#20042,#20050) +successor(#20125,#20041) numlines(#10000,6,6,0) filetype(#10000,"javascript")