@@ -15,35 +15,69 @@ private predicate regexpCaptureTwo(string input, string regexp, string capture1,
1515 capture2 = input .regexpCapture ( regexp , 2 )
1616}
1717
18- /** Companion module to the `AccessPath` class. */
19- module AccessPath {
20- /** A string that should be parsed as an access path. */
21- abstract class Range extends string {
22- bindingset [ this ]
23- Range ( ) { any ( ) }
24- }
18+ /**
19+ * Parses an integer constant `n` or interval `n1..n2` (inclusive) and gets the value
20+ * of the constant or any value contained in the interval.
21+ */
22+ bindingset [ arg]
23+ int parseInt ( string arg ) {
24+ result = arg .toInt ( )
25+ or
26+ // Match "n1..n2"
27+ exists ( string lo , string hi |
28+ regexpCaptureTwo ( arg , "(-?\\d+)\\.\\.(-?\\d+)" , lo , hi ) and
29+ result = [ lo .toInt ( ) .. hi .toInt ( ) ]
30+ )
31+ }
2532
26- /**
27- * Parses an integer constant `n` or interval `n1..n2` (inclusive) and gets the value
28- * of the constant or any value contained in the interval.
29- */
30- bindingset [ arg]
31- int parseInt ( string arg ) {
32- result = arg .toInt ( )
33- or
34- // Match "n1..n2"
35- exists ( string lo , string hi |
36- regexpCaptureTwo ( arg , "(-?\\d+)\\.\\.(-?\\d+)" , lo , hi ) and
37- result = [ lo .toInt ( ) .. hi .toInt ( ) ]
38- )
33+ /**
34+ * Parses a lower-bounded interval `n..` and gets the lower bound.
35+ */
36+ bindingset [ arg]
37+ int parseLowerBound ( string arg ) { result = arg .regexpCapture ( "(-?\\d+)\\.\\." , 1 ) .toInt ( ) }
38+
39+ /**
40+ * An access part token such as `Argument[1]` or `ReturnValue`.
41+ */
42+ class AccessPathTokenBase extends string {
43+ bindingset [ this ]
44+ AccessPathTokenBase ( ) { exists ( this ) }
45+
46+ bindingset [ this ]
47+ private string getPart ( int part ) {
48+ result = this .regexpCapture ( "([^\\[]+)(?:\\[([^\\]]*)\\])?" , part )
3949 }
4050
51+ /** Gets the name of the token, such as `Member` from `Member[x]` */
52+ bindingset [ this ]
53+ string getName ( ) { result = this .getPart ( 1 ) }
54+
4155 /**
42- * Parses a lower-bounded interval `n..` and gets the lower bound.
56+ * Gets the argument list, such as `1,2` from `Member[1,2]`,
57+ * or has no result if there are no arguments.
4358 */
44- bindingset [ arg]
45- int parseLowerBound ( string arg ) { result = arg .regexpCapture ( "(-?\\d+)\\.\\." , 1 ) .toInt ( ) }
59+ bindingset [ this ]
60+ string getArgumentList ( ) { result = this .getPart ( 2 ) }
61+
62+ /** Gets the `n`th argument to this token, such as `x` or `y` from `Member[x,y]`. */
63+ bindingset [ this ]
64+ string getArgument ( int n ) { result = this .getArgumentList ( ) .splitAt ( "," , n ) .trim ( ) }
65+
66+ /** Gets an argument to this token, such as `x` or `y` from `Member[x,y]`. */
67+ bindingset [ this ]
68+ string getAnArgument ( ) { result = this .getArgument ( _) }
69+
70+ /** Gets the number of arguments to this token, such as 2 for `Member[x,y]` or zero for `ReturnValue`. */
71+ bindingset [ this ]
72+ int getNumArgument ( ) { result = count ( int n | exists ( this .getArgument ( n ) ) ) }
73+ }
74+
75+ final private class AccessPathTokenBaseFinal = AccessPathTokenBase ;
76+
77+ signature predicate accessPathRangeSig ( string s ) ;
4678
79+ /** Companion module to the `AccessPath` class. */
80+ module AccessPath< accessPathRangeSig / 1 accessPathRange> {
4781 /**
4882 * Parses an integer constant or interval (bounded or unbounded) that explicitly
4983 * references the arity, such as `N-1` or `N-3..N-1`.
@@ -109,74 +143,78 @@ module AccessPath {
109143 or
110144 result = parseIntWithExplicitArity ( arg , arity )
111145 }
112- }
113-
114- /** Gets the `n`th token on the access path as a string. */
115- private string getRawToken ( AccessPath path , int n ) {
116- // Avoid splitting by '.' since tokens may contain dots, e.g. `Field[foo.Bar.x]`.
117- // Instead use regexpFind to match valid tokens, and supplement with a final length
118- // check (in `AccessPath.hasSyntaxError`) to ensure all characters were included in a token.
119- result = path .regexpFind ( "\\w+(?:\\[[^\\]]*\\])?(?=\\.|$)" , n , _)
120- }
121-
122- /**
123- * A string that occurs as an access path (either identifying or input/output spec)
124- * which might be relevant for this database.
125- */
126- class AccessPath extends string instanceof AccessPath:: Range {
127- /** Holds if this string is not a syntactically valid access path. */
128- predicate hasSyntaxError ( ) {
129- // If the lengths match, all characters must haven been included in a token
130- // or seen by the `.` lookahead pattern.
131- this != "" and
132- not this .length ( ) = sum ( int n | | getRawToken ( this , n ) .length ( ) + 1 ) - 1
133- }
134-
135- /** Gets the `n`th token on the access path (if there are no syntax errors). */
136- AccessPathToken getToken ( int n ) {
137- result = getRawToken ( this , n ) and
138- not this .hasSyntaxError ( )
139- }
140146
141- /** Gets the number of tokens on the path (if there are no syntax errors). */
142- int getNumToken ( ) {
143- result = count ( int n | exists ( getRawToken ( this , n ) ) ) and
144- not this .hasSyntaxError ( )
147+ /** Gets the `n`th token on the access path as a string. */
148+ private string getRawToken ( AccessPath path , int n ) {
149+ // Avoid splitting by '.' since tokens may contain dots, e.g. `Field[foo.Bar.x]`.
150+ // Instead use regexpFind to match valid tokens, and supplement with a final length
151+ // check (in `AccessPath.hasSyntaxError`) to ensure all characters were included in a token.
152+ result = path .regexpFind ( "\\w+(?:\\[[^\\]]*\\])?(?=\\.|$)" , n , _)
145153 }
146- }
147-
148- /**
149- * An access part token such as `Argument[1]` or `ReturnValue`, appearing in one or more access paths.
150- */
151- class AccessPathToken extends string {
152- AccessPathToken ( ) { this = getRawToken ( _, _) }
153154
154- private string getPart ( int part ) {
155- result = this .regexpCapture ( "([^\\[]+)(?:\\[([^\\]]*)\\])?" , part )
155+ /**
156+ * A string that occurs as an access path (either identifying or input/output spec)
157+ * which might be relevant for this database.
158+ */
159+ final class AccessPath extends string {
160+ AccessPath ( ) { accessPathRange ( this ) }
161+
162+ /** Holds if this string is not a syntactically valid access path. */
163+ predicate hasSyntaxError ( ) {
164+ // If the lengths match, all characters must haven been included in a token
165+ // or seen by the `.` lookahead pattern.
166+ this != "" and
167+ not this .length ( ) = sum ( int n | | getRawToken ( this , n ) .length ( ) + 1 ) - 1
168+ }
169+
170+ /** Gets the `n`th token on the access path (if there are no syntax errors). */
171+ AccessPathToken getToken ( int n ) {
172+ result = getRawToken ( this , n ) and
173+ not this .hasSyntaxError ( )
174+ }
175+
176+ /** Gets the number of tokens on the path (if there are no syntax errors). */
177+ int getNumToken ( ) {
178+ result = count ( int n | exists ( getRawToken ( this , n ) ) ) and
179+ not this .hasSyntaxError ( )
180+ }
156181 }
157182
158- /** Gets the name of the token, such as `Member` from `Member[x]` */
159- string getName ( ) { result = this .getPart ( 1 ) }
160-
161183 /**
162- * Gets the argument list, such as `1,2` from `Member[1,2]`,
163- * or has no result if there are no arguments.
184+ * An access part token such as `Argument[1]` or `ReturnValue`, appearing in one or more access paths.
164185 */
165- string getArgumentList ( ) { result = this .getPart ( 2 ) }
166-
167- /** Gets the `n`th argument to this token, such as `x` or `y` from `Member[x,y]`. */
168- string getArgument ( int n ) { result = this .getArgumentList ( ) .splitAt ( "," , n ) .trim ( ) }
169-
170- /** Gets the `n`th argument to this `name` token, such as `x` or `y` from `Member[x,y]`. */
171- pragma [ nomagic]
172- string getArgument ( string name , int n ) { name = this .getName ( ) and result = this .getArgument ( n ) }
173-
174- /** Gets an argument to this token, such as `x` or `y` from `Member[x,y]`. */
175- string getAnArgument ( ) { result = this .getArgument ( _) }
176-
177- /** Gets an argument to this `name` token, such as `x` or `y` from `Member[x,y]`. */
178- string getAnArgument ( string name ) { result = this .getArgument ( name , _) }
179-
180- /** Gets the number of arguments to this token, such as 2 for `Member[x,y]` or zero for `ReturnValue`. */
181- int getNumArgument ( ) { result = count ( int n | exists ( this .getArgument ( n ) ) ) }
186+ class AccessPathToken extends AccessPathTokenBaseFinal {
187+ AccessPathToken ( ) { this = getRawToken ( _, _) }
188+
189+ /** Gets the name of the token, such as `Member` from `Member[x]` */
190+ pragma [ nomagic]
191+ string getName ( ) { result = super .getName ( ) }
192+
193+ /**
194+ * Gets the argument list, such as `1,2` from `Member[1,2]`,
195+ * or has no result if there are no arguments.
196+ */
197+ pragma [ nomagic]
198+ string getArgumentList ( ) { result = super .getArgumentList ( ) }
199+
200+ /** Gets the `n`th argument to this token, such as `x` or `y` from `Member[x,y]`. */
201+ pragma [ nomagic]
202+ string getArgument ( int n ) { result = super .getArgument ( n ) }
203+
204+ /** Gets the `n`th argument to this `name` token, such as `x` or `y` from `Member[x,y]`. */
205+ pragma [ nomagic]
206+ string getArgument ( string name , int n ) {
207+ name = this .getName ( ) and result = this .getArgument ( n )
208+ }
209+
210+ /** Gets an argument to this token, such as `x` or `y` from `Member[x,y]`. */
211+ string getAnArgument ( ) { result = this .getArgument ( _) }
212+
213+ /** Gets an argument to this `name` token, such as `x` or `y` from `Member[x,y]`. */
214+ string getAnArgument ( string name ) { result = this .getArgument ( name , _) }
215+
216+ /** Gets the number of arguments to this token, such as 2 for `Member[x,y]` or zero for `ReturnValue`. */
217+ pragma [ nomagic]
218+ int getNumArgument ( ) { result = count ( int n | exists ( this .getArgument ( n ) ) ) }
219+ }
182220}
0 commit comments