@@ -107,6 +107,51 @@ abstract class RegexString extends StringLiteral {
107107 end = start + 3
108108 }
109109
110+ private predicate namedBackreference ( int start , int end , string name ) {
111+ this .escapingChar ( start ) and
112+ this .getChar ( start + 1 ) = "k" and
113+ this .getChar ( start + 2 ) = "<" and
114+ end = min ( int i | i > start + 2 and this .getChar ( i ) = ">" ) + 1 and
115+ name = this .getText ( ) .substring ( start + 3 , end - 2 )
116+ }
117+
118+ private predicate numberedBackreference ( int start , int end , int value ) {
119+ this .escapingChar ( start ) and
120+ // starting with 0 makes it an octal escape
121+ not this .getChar ( start + 1 ) = "0" and
122+ exists ( string text , string svalue , int len |
123+ end = start + len and
124+ text = this .getText ( ) and
125+ len in [ 2 .. 3 ]
126+ |
127+ svalue = text .substring ( start + 1 , start + len ) and
128+ value = svalue .toInt ( ) and
129+ // value is composed of digits
130+ forall ( int i | i in [ start + 1 .. start + len - 1 ] | this .getChar ( i ) = [ 0 .. 9 ] .toString ( ) ) and
131+ // a longer reference is not possible
132+ not (
133+ len = 2 and
134+ exists ( text .substring ( start + 1 , start + len + 1 ) .toInt ( ) )
135+ ) and
136+ // 3 octal digits makes it an octal escape
137+ not forall ( int i | i in [ start + 1 .. start + 4 ] | this .isOctal ( i ) )
138+ // TODO: Inside a character set, all numeric escapes are treated as characters.
139+ )
140+ }
141+
142+ /** Holds if the text in the range start,end is a back reference */
143+ predicate backreference ( int start , int end ) {
144+ this .numberedBackreference ( start , end , _)
145+ or
146+ this .namedBackreference ( start , end , _)
147+ }
148+
149+ /** Gets the number of the back reference in start,end */
150+ int getBackrefNumber ( int start , int end ) { this .numberedBackreference ( start , end , result ) }
151+
152+ /** Gets the name, if it has one, of the back reference in start,end */
153+ string getBackrefName ( int start , int end ) { this .namedBackreference ( start , end , result ) }
154+
110155 pragma [ inline]
111156 private predicate isOctal ( int index ) { this .getChar ( index ) = [ 0 .. 7 ] .toString ( ) }
112157
@@ -592,51 +637,6 @@ abstract class RegexString extends StringLiteral {
592637 this .positiveLookbehindAssertionGroup ( start , end )
593638 }
594639
595- private predicate namedBackreference ( int start , int end , string name ) {
596- this .escapingChar ( start ) and
597- this .getChar ( start + 1 ) = "k" and
598- this .getChar ( start + 2 ) = "<" and
599- end = min ( int i | i > start + 2 and this .getChar ( i ) = ">" ) + 1 and
600- name = this .getText ( ) .substring ( start + 3 , end - 2 )
601- }
602-
603- private predicate numberedBackreference ( int start , int end , int value ) {
604- this .escapingChar ( start ) and
605- // starting with 0 makes it an octal escape
606- not this .getChar ( start + 1 ) = "0" and
607- exists ( string text , string svalue , int len |
608- end = start + len and
609- text = this .getText ( ) and
610- len in [ 2 .. 3 ]
611- |
612- svalue = text .substring ( start + 1 , start + len ) and
613- value = svalue .toInt ( ) and
614- // value is composed of digits
615- forall ( int i | i in [ start + 1 .. start + len - 1 ] | this .getChar ( i ) = [ 0 .. 9 ] .toString ( ) ) and
616- // a longer reference is not possible
617- not (
618- len = 2 and
619- exists ( text .substring ( start + 1 , start + len + 1 ) .toInt ( ) )
620- ) and
621- // 3 octal digits makes it an octal escape
622- not forall ( int i | i in [ start + 1 .. start + 4 ] | this .isOctal ( i ) )
623- // TODO: Inside a character set, all numeric escapes are treated as characters.
624- )
625- }
626-
627- /** Holds if the text in the range start,end is a back reference */
628- predicate backreference ( int start , int end ) {
629- this .numberedBackreference ( start , end , _)
630- or
631- this .namedBackreference ( start , end , _)
632- }
633-
634- /** Gets the number of the back reference in start,end */
635- int getBackrefNumber ( int start , int end ) { this .numberedBackreference ( start , end , result ) }
636-
637- /** Gets the name, if it has one, of the back reference in start,end */
638- string getBackrefName ( int start , int end ) { this .namedBackreference ( start , end , result ) }
639-
640640 private predicate baseItem ( int start , int end ) {
641641 this .character ( start , end ) and
642642 not exists ( int x , int y | this .charSet ( x , y ) and x <= start and y >= end )
0 commit comments