Skip to main content

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 kind
  • text: (stripped) text of a given node
  • length: length of a string or List
  • 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.

caution

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 }