Syntax queries
SYLQ (Sylver Query language) can be used to interactively explore your codebase, as well as defining custom linting rules.
A SYLQ query is of the form:
match pattern when boolean_expression
In the simplest cases, the conditional part (when boolean_expression
) can be omitted.
Patterns
A pattern is composed of a node kind name, followed with an optional binding (which can be used in the filtering expression to refer to the current node).
Here are two examples of simple queries:
Return all the Expr
nodes.
match Expr
Return all the Expr
nodes witch have more than two children:
match Expr e when e.children.length > 2
The node kind can be replaced with a placeholder (_
) in order to match any node, regardless of it's kind:
match _
Expressions
Literal values
- unsigned decimal integers:
42
- single or double quoted strings:
'Alice'
,"Bob"
,'some "quoted" value'
,"escaped quote:\""
- null value:
null
- regex literals: perl-style regex between backticks:
`(hello)|(world)`
Binary operators
- logical: short-circuiting and
&&
, or||
- comparison: equals
==
, not equals!=
, higher than>
, higher or equal>=
, lower than<
, lower or equal<=
Field access
Node fields can be accessed using the .
operator.
In addition to user-defined fields, all nodes have a set of built-in fields:
kind
: opaque value representing the node kindtext
: (stripped) text of a given nodelength
: length of astring
orList
parent
,children
,previous_sibling
,next_sibling
Methods
Methods can be called on nodes using the same syntax as fields accesses, followed by the method arguments unclosed in parentheses. Built-in methods are:
matches
n.text.matches(`[0-9]+]`)
Returns true
if the string
matches the given regex, false
otherwise.
to_int
n.to_int()
Converts a string
to an int
value.
The evaluation will fail if the conversion is impossible.
Indexing
Array values can be indexed using the following notation: array[index]
.
is
operator
In an expression, a node can be matched against a pattern using the is
operator.-, using the
following syntax: node is { pattern }
.
If pattern
is a simple pattern (without a filtering expression), the braces can be omitted.
For example using an imaginary spec for a programming language, a query to retrieve all the parameters with an integer literal as default value.
match FunctionParam p when p.defaultValue is IntLiteral
If instead we wanted to identify the function parameter for which the default value is
a call to the list
function:
match FunctionParam p when p.defaultValue is {
FunctionCall c when c.callee.text == 'list'
}
List quantifying expressions
list quantifying expressions are of the form:
<quantifier> <list value> match <query pattern>
Where the quantifier is any of the following keywords: no
, any
, all
.
List quantifying expressions return true when any, all, or none of
the values in the given list match the query pattern.
For example:
match FunDecl f when no f.args.children match { NamedArg }