Syntax Classes
We saw that a pattern variable is printed as x:::expr. This means that x is constrained by the syntax class expr.
A syntax class is a syntax matching construct useful for defining syntactic "categories". You can see it as an abstraction for patterns. (You can read more about them in the syntax/parse documentation.)
expr is the "category" of all Julia expressions. It is a syntax class provided by Argus. We can define our own syntax classes and use them in patterns. Let's write a syntax class for vectors:
julia> vec = @syntax_class "vector" begin
@pattern [{_}...]
end
SyntaxClass: vector
Pattern alternative #1:
[vect]
[~rep]
_:::expr :: ~varSyntax class bodies consist of a sequence of patterns. The match behaviour is that of a short-circuiting or — the result is either the first successful pattern match, or a failure if no patterns match.
Let's test vec:
julia> syntax_match(vec, parsestmt(SyntaxNode, "[]"))
BindingSet @ 0:0 with 0 entries
julia> syntax_match(vec, parsestmt(SyntaxNode, "[1, [2]]"))
BindingSet @ 0:0 with 0 entriesThe match results are empty binding sets. This is because we used an anonymous pattern variable in the syntax class's pattern.
If we want to use our syntax class in a pattern with the ::: syntax we need to register it first.
julia> register_syntax_class!(:my_vec, vec)
SyntaxClass: vector
Pattern alternative #1:
[vect]
[~rep]
_:::expr :: ~varNow we can find it in the syntax class registry under the name :my_vec.
julia> Argus.SYNTAX_CLASS_REGISTRY[:my_vec]
SyntaxClass: vector
Pattern alternative #1:
[vect]
[~rep]
_:::expr :: ~varLet's use it to rewrite the vec_of_vecs pattern:
julia> vec_of_vecs2 = @pattern [{v:::vec}...]
Pattern:
[vect]
[~rep]
v:::vec :: ~var
julia> syntax_match(vec_of_vecs2, parsestmt(SyntaxNode, "[[1, 2], [[3]]]"))
BindingSet @ 0:0 with 1 entry:
:v => Binding:
Name: :v
Bound sources: [(vect 1 2) @ 1:2, (vect (vect 3)) @ 1:10]
Ellipsis depth: 1
Sub-bindings:
[
BindingSet @ 0:0 with 0 entries,
BindingSet @ 0:0 with 0 entries
]
julia> syntax_match(vec_of_vecs2, parsestmt(SyntaxNode, "[1]"))
MatchFail: no match @ :1:2Argus's built-in implementation of the vec syntax class uses @define_syntax_class to define and register vec and the same time:
julia> @define_syntax_class :vec "vector" begin
@pattern [{_}...]
end
SyntaxClass: vector
Pattern alternative #1:
[vect]
[~rep]
_:::expr :: ~var