Selectors allow traversing nodes of any syntax tree. Selectors return arrays of nodes.

Simple selectors

syntax rule NestedIfs on ApexClass {
	when ifStatement x {	
		var nestedIfs = [x : find descendants having it.type == "ifStatement"]
		if (nestedIfs.size > 5) {
			capture x // too many ifs
		}
	}
}

Selectors allow to navigate from an AST to others, such as their ancestors, descendants, and siblings.

// given x, find all its ancestors
[x : find ancestors] 

// given x, find all its descendants
[x : find descendants] 

// given x, find all its left/right siblings
[x : find left siblings]  // only left
[x : find right siblings] // only right
[x : find siblings]       // left + right

Selectors allow using any expression as filters (the nth node can be reference using the identifier it)

// given x, find all its descendants with type expression
[x : find descendants having it.type == "expression"]

// given x, find all its descendants with type expression and 1+ sub-nodes
[x : find descendants having (it.type == "expression" && it.size > 1)]

Chaining multiple selectors

Selectors can be chained any number of times to allow movement in the syntax tree, using then between selectors.

// given x, find its subexpressions, 
// then move to their left siblings having 2 subnodes 
[x : find descendants having (it.type == "expression")
		 then find left siblings having (it.type == "variableDeclaratorId")]

When chaining selectors it may be helpful to skip, limit the elements traversed

// given x, finds all its subexpressions, but skip the first 2
[x : find descendants having type = "expression"
		 then skip 2]

// given x, finds all its subexpressions, and keep only the first 3
[x : find descendants having type = "expression"
		 then limit 3]