Rule Language Reference¶
A quick reference to all the builtin functions, operators and actions.
- Functions are used in predicates (i.e. in the
where
clause) of matchers. - Operators can be used to combine multiple expressions within predicates.
- Actions can be taken in the body of match.
- AST Providers can also export Functions and Actions.
- Variables & Conditions can be used for expressing pre-conditions
- Scoped Matchers can be used to restrict a matcher’s breadth and depth.
Example:
Function where not(Public) && Override {
fail("")
}
In the sample matcher above, not
is a function, &&
is an operator and fail
is an action.
Functions¶
match(Property, RegExp)
¶
Tries to convert the value of Property
to a string, and matches it against the regular expression in RegExp
.
not(Expression)
¶
Converts the value of Expression
to a boolean value and performs a logical negation.
count(List)
¶
Converts the value of List to a list and returns the number of elements in the list. Returns 0
if List
is not an actual list.
Operators¶
Expression1 == Expression2
¶
Structural equality operator.
Expression1 != Expression2
¶
Negation of Expression1 == Expression2
Expression1 && Expression2
¶
Converts both Expression1
and Expression2
to boolean values and performs a boolean “and”.
Expression1 || Expression2
¶
Converts both Expression1
and Expression2
to boolean values and performs a boolean “or”.
node.property
¶
Access property
of the AST node
. If the node
is actually a list of nodes, the property access works like flatMap: the property access is computed for every node in the list and then compacted into a new list.
Actions¶
fail(Explanation)
¶
Reports that an error was found in the current node being matched. Explanation
should be a string explaining why is this is a violation and, ideally, how to correct it.
warn(Explanation)
¶
Similar to fail(Explanation)
, but reports a warning instead of an error.
AST Providers¶
Swift¶
The Swift provider only exports one convenience function:
inheritsFrom(ClassName)
This function assumes that a class is being matched and will return true
if the string ClassName
appears in the inheritance clause of the class declaration. It returns false
if either the current node does not have a TypeInheritanceClause
(i.e. it’s not a ClassDeclaration
) or if the string ClassName
does not appear in the inheritance clause.
Python¶
The Python provider currently does not export any function or action.
Variables & Conditions¶
NEAL allows you to declare boolean variables inside a matcher. Those variables can be mutated from nested matchers and used in where
clauses and conditions.
Declaring a new variable¶
Variable declarations must be prefix with var
and have a initial value assigned to it.
Provider::Matcher {
var is_valid := true
var did_match := false
}
Mutating a variable¶
Variables are block-scoped and can be mutated from nested matchers at any depth.
Provider::Matcher {
var is_valid := true
var did_match := false
NestedMatcher {
did_match := true
}
OtherMatcher {
is_valid := false
}
}
Conditions¶
Conditions are evaluated when exiting the node and can be used in conjunction with variables to check that a series of pre-conditions within that node.
Provider::Matcher {
var is_valid := true
var did_match := false
condition (is_valid && did_match) {
fail("....")
}
NestedMatcher where is_valid {
did_match := true
}
OtherMatcher {
is_valid := false
}
}
Scoped Matchers¶
Any matcher can be scoped to a given property of it’s parent matcher, thus restricting in breadth: instead of searching through all the properties of the current AST node, restrict it to a single property. The choice of the operator used for scoping (>
vs >>
) can be used to restrict in depth: >
will match only immediate children nodes, >>
will nodes at any depth.
For example, the following matcher will match class C { var x: String = "" }
but not class C { func f() { var x: String = "" } }
Swift::Class {
ClassBody > VariableDeclaration {
fail("...")
}
}
Replacing the >
operator with >>
would lead to matching both cases.