Simple Predicates | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
The simplest form of a simple predicate is an identifier, followed by a colon, followed by a dot:
x:.
This predicate declares
a query variable with the given identifier as name as its
label. The type of the query variable is the node type of the
current compile-time model (Section 3.1, “Compile-Time Model”), i.e., the
result of the invocation of the method getNodeClass
on this model. The predicate has a single closed in-out-parameter of the
same type. The predicate is fulfilled if and only if
the value of the parameter is a node of the current run-time model
(Section 3.2, “Run-Time Model”), i.e., if
the invocation of the method isNode
on
this model with the value of the in-out-parameter as argument returns
true
.
The other simple predicates may be prefixed by a label, i.e., an identifier, followed by a colon. If the labelled predicate has a closed in-out-parameter, a query variable is declared, its type being the type of the in-out-parameter, its name being the identifier. Otherwise, a compile-time error occurs. Here are some examples for labelled predicates:
x:Object a:F(b)
Predicate Arguments | |||||
---|---|---|---|---|---|
|
Some of the following predicates make use of predicate arguments. Predicate arguments are related to predicate parameters in a similar way as arguments of method invocation expressions are related to method parameters. However, there is an important difference:
If the predicate argument is a single identifier, and a local variable of that name has not yet been declared in the current scope, the predicate argument is a label argument (Section 17.4.2, “Label Arguments”) with the given identifier. Note that this declares a query variable with the identifier as its name.
Otherwise, if the predicate argument is a single identifier and a query variable of that name exists in the current query, then it is used as label variable for the place of the corresponding predicate parameter.
Otherwise, the predicate argument is handled as an expression. A
condition is imposed on the query variable corresponding to
the predicate parameter: Its value has to be equal in the sense
of the operator ==
to the result of the evaluation
of the expression.
Note that fields cannot be addressed by a single identifier in predicate arguments: Single identifiers as predicate arguments are always interpreted as local variables. If such a variable does not yet exist, it is declared. In order to use a field for a predicate argument expression, it can be enclosed in parentheses, or it can be qualified as in the following example:
int f; // field declaration void test() [ X(f) ::> {} // attention: implicit declaration of query variable f X((f)) ::> {} // field access expression for f is used X(this.f) ::> {} // field access expression for f is used ]
Some of the following predicates may have label arguments as their predicate arguments (Section 17.4.1, “Predicate Arguments”). A label argument is defined by a single identifier. A query variable is declared whose name is this identifier, this variable is then used as the label of the place of the corresponding predicate parameter.
Name Predicates | |||||
---|---|---|---|---|---|
|
A name predicate consists of a single name and may denote a local variable, a field, a type, a predicate, or a method. The meaning is resolved as follows:
If the name is a single identifier, and if a local
variable v
of that name exists in the
current scope, this is handled specially: If v
is
a query variable of the current query, then the name predicate is
a type predicate (Section 17.4.5, “Type Predicates”) of the type of
v
, and v
is made the label variable of the type predicate. This kind of
a name predicate is used to refer to previously defined places.
Otherwise, the name predicate is an expression predicate
(Section 17.4.7, “Expression Predicates”). Its expression
is the variable w
if v
has a wrapper variable
w
, otherwise it is v
itself.
Otherwise, the meaning of the name is determined as described in Section 9.2, “Determining the Meaning of a Name”, where the possible meanings are expression names, type names, predicate names, or method names. An expression name is reclassified as an expression predicate (Section 17.4.7, “Expression Predicates”), a type name as a type predicate (Section 17.4.5, “Type Predicates”), a predicate name as a class predicate (Section 17.4.9, “Class Predicates”) with no arguments, and a method name as a method predicate (Section 17.4.8, “Method Predicates”) with no arguments.
Parametrized Predicates | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
A parametrized predicate is specified by a name and a number of arguments. Each argument may by a predicate argument (Section 17.4.1, “Predicate Arguments”), or it may be empty, which is represented by a single dot or even by omitting it at all (the latter is possibly only if there are at least two arguments, i.e., at least one comma). An empty argument is handled as a label argument (Section 17.4.2, “Label Arguments”) with an internal, compiler-generated identifier. Examples for parametrized predicates are:
F(x) M(.) X(a,,,d,) Object(x) root(n)
The meaning of the name is determined as described in Section 9.2, “Determining the Meaning of a Name”, where the possible meanings are predicate names, type names if there exists exactly one argument, and method names if there are no empty arguments. If the name is a predicate name, the parametrized predicate is reclassified as a class predicate (Section 17.4.9, “Class Predicates”) with the specified arguments. If the name is a type name, the parametrized predicate is reclassified as a wrapped type predicate (Section 17.4.6, “Wrapped Type Predicates”) with the specified argument. If the name is a method name, the parametrized predicate is reclassified as a method predicate (Section 17.4.8, “Method Predicates”) with the specified arguments.
Type Predicates | |||||
---|---|---|---|---|---|
|
A type predicate is specified by a single type. A type predicate may also result from the reclassification of a name predicate (Section 17.4.3, “Name Predicates”). Examples are:
Object Runnable long String[] javax.swing.tree.TreeNode
A type predicate has a single closed in-out-parameter of the specified type. It is fulfilled for every binding of values to query variables; it just serves to restrict the type of its associated query variable.
Type Predicates | |||||
---|---|---|---|---|---|
|
Wrapped type predicates are used to identify
wrapper nodes which wrap values of
other (non-node-) types. A wrapped type predicate is specified by a single type
T
and
an argument enclosed in parentheses.
A wrapped type predicate may also result from the reclassification of a
parametrized predicate (Section 17.4.4, “Parametrized Predicates”).
Examples are:
String[](a) int(i)
A wrapped type predicate has two parameters: The first is its
closed in-out-parameter, its type is the result of the method invocation
getWrapperClassFor(
T
)
on the
current compile-time model (Section 3.1, “Compile-Time Model”).
The second parameter has type T
.
A wrapped type predicate is fulfilled if and only if the result of
the invocation of the method
isWrapperFor(
o
,
T
)
on the current run-time model (Section 3.2, “Run-Time Model”) returns
true
, where o
is the bound value of the first parameter, and if in addition the
result of the invocation of the method
unwrap
A
(
o
)
on the current run-time model
is equal in the sense of the operator ==
to the bound value of the second parameter.
A
is the type affix (Section 6.1, “Type Affixes and Type Letters”)
of T
.
Expression Predicates | |||||
---|---|---|---|---|---|
|
Expression predicates are used to directly fix the value of a query variable to the result of an expression. If necessary, the expression has to be enclosed in backslash-prefixed parentheses; the backslash is needed in order to disambiguate the syntax. An expression predicate may also result from the reclassification of a name predicate (Section 17.4.3, “Name Predicates”), a method predicate (Section 17.4.8, “Method Predicates”), or a root predicate (Section 17.4.10, “Root Predicate”). Examples are:
this "Hello World" 42 \(a[i]) \(x + y)
An expression predicate has a single closed in-out-parameter of the
type of the expression. It is fulfilled iff the bound value of the
parameter is equal in the sense of the operator ==
to the result of the evaluation of the expression.
Method Predicates | |||||
---|---|---|---|---|---|
|
Method predicates are used to create predicates from methods. At first, the tokens to the left from the last '.' are treated as an ordinary expression. Then the most specific applicable (Chapter 13, Signatures) and accessible method declared in or inherited by the type of the expression is chosen, where the set of possible argument transformations (Section 13.1, “Argument Transformations”) is:
All argument transformations of method invocation expressions (Section 16.2.1, “Argument Transformations”). In this case, the whole method predicate is treated as an expression and is thus reclassified as an expression predicate (Section 17.4.7, “Expression Predicates”).
An additional argument transformation is defined for methods
with return type boolean
. This
transformation provides
a single implicit argument which is prepended before the explicit
argument expressions and is commensurate with the first method parameter.
In this case, the method predicate has a single closed in-out-parameter
of the type of the first method parameter. The method predicate
is fulfilled iff the invocation of the method returns
true
for a binding of the single parameter.
Method predicates may also result from the reclassification of a name predicate (Section 17.4.3, “Name Predicates”) or a parametrized predicate (Section 17.4.4, “Parametrized Predicates”), in these cases they consist of a name and an argument list. The name is resolved as for method invocation expressions, and the predicate is handled as before.
Examples for method predicates are:
getRoot() x.getParent() isVisible()
A class predicate results from the reclassification of a name predicate (Section 17.4.3, “Name Predicates”) or a parametrized predicate (Section 17.4.4, “Parametrized Predicates”). The reclassification provides a predicate name and a list of arguments for the class predicate. Now the most specific class predicate (Chapter 12, Class Predicates) is determined as specified for signatures (Chapter 13, Signatures), and the parameters of the resulting class predicate declaration are the parameters of the predicate. The following alternatives of argument transformations (Section 13.1, “Argument Transformations”) are possible:
The arguments are not transformed at all. The invocation uses the explicitly specified argument expressions. In this case, the predicate has no in- and out-parameters.
For class predicate declarations whose first parameter is the in-out-parameter (Chapter 12, Class Predicates), an additional argument transformation exists. It provides a single implicit argument which is prepended before the explicit argument expressions and is commensurate with the in-out-parameter. In this case, the in-out-parameter of the declaration is the closed in-out-parameter of the predicate.
Label arguments (Section 17.4.2, “Label Arguments”) are always commensurate with their parameter. Note that for class predicates, parameters and arguments of reference type are commensurate if there exists a casting conversion (Section 13.2, “Applicable Signatures”).
As a class predicate is declared by a subclass of
de.grogra.xl.qnp.ClassPredicate
(Chapter 12, Class Predicates), its class has to implement the
abstract method createMatcher
. The returned
instance of de.grogra.xl.qnp.Predicate.Matcher
defines a means to fulfill the class predicate.
Root Predicate | |||||
---|---|---|---|---|---|
|
A root predicate is used to bind a query variable to the root node
of the extent (Section 3.2, “Run-Time Model”) of the current query state
qs
(Section 17.2, “Invocation of Queries”).
It is reclassified as an expression predicate
(Section 17.4.7, “Expression Predicates”), its expression being
qs
.getExtent().getRoot()
.