17.4. Simple Predicates

Simple Predicates
[66]SimplePredicate::=Identifer ':' '.' | Identifier ':' SimplePredicateNoLabel | SimplePredicateNoLabel  
[67]SimplePredicateNoLabel::=NamePredicate | ParametrizedPredicate | TypePredicate | WrappedTypePredicate | ExpressionPredicate | MethodPredicate | RootPredicate | PathPredicate | StandardEdgePredicate | FirstElementPredicate | TransitiveClosure | MinimalElementsPredicate  

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)

17.4.1. Predicate Arguments

Predicate Arguments
[68]PredicateArgument::=Identifier | AssignmentExpression  

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
]

17.4.2. Label Arguments

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.

17.4.3. Name Predicates

Name Predicates
[69]NamePredicate::=Name  

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:

17.4.4. Parametrized Predicates

Parametrized Predicates
[70]ParametrizedPredicate::=Name '(' [ OptPredicateArgument { ',' OptPredicateArgument } ] ')'  
[71]OptPredicateArgument::=PredicateArgument | '.' |  

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.

17.4.5. Type Predicates

Type Predicates
[72]TypePredicate::=Type  

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.

17.4.6. Wrapped Type Predicates

Type Predicates
[73]WrappedTypePredicate::=Type '(' PredicateArgument ')'  

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 unwrapA(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.

17.4.7. Expression Predicates

Expression Predicates
[74]ExpressionPredicate::=PrimaryNoParen | '\(' Expression ')'  

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.

17.4.8. Method Predicates

Method Predicates
[75]MethodPredicate::=PrimaryNoParen { '.' Identifier Arguments } '.' Identifier Arguments  

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()

17.4.9. Class Predicates

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.

17.4.10. Root Predicate

Root Predicate
[76]RootPredicate::='^'  

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().