3.35. AST Matching
AST matching is reverse reification — instead of building AST from values, it matches compiled AST against structural patterns and extracts values from it.
The module daslib/ast_match provides three macros: qmatch, qmatch_block, and qmatch_function.
They use the same tag system as qmacro ($e, $v, $i, $t, $c, $f, $b, $a)
but in reverse — tags extract values from the matched expression instead of substituting values in.
require daslib/ast_match
3.35.1. Simple example
Match a compiled expression and extract parts of it:
var expr = qmacro(a + b)
var left_name : string
let r = qmatch(expr, $i(left_name) + b)
assert(r.matched)
assert(left_name == "a")
qmatch compiles the pattern $i(left_name) + b into a series of checks:
verify the expression is ExprOp2 with op="+" and right operand ExprVar(name="b"),
then extract the left operand’s identifier name into left_name.
3.35.2. Macros
3.35.2.1. qmatch
qmatch(expr, pattern) matches a single expression against a structural pattern.
Returns a QMatchResult.
var expr = qmacro(x * 2 + 1)
let r = qmatch(expr, x * 2 + 1)
assert(r.matched)
The pattern is not type-inferred — it stays as raw AST, the same way qmacro patterns work.
This means identifier names in the pattern refer to AST variable names, not local variables.
3.35.2.2. qmatch_block
qmatch_block(expr) $ { stmts } matches a block’s statement list with wildcard support.
Optionally matches block arguments and return type:
var blk = qmacro_block() {
var x = 1
print("{x}\n")
return x
}
let r = qmatch_block(blk) $ {
_wildcard()
return x
}
assert(r.matched)
With argument and return type matching:
let r = qmatch_block(blk) $(x : int) : int {
_wildcard()
return x
}
Arguments are matched strictly — if the pattern specifies zero arguments, the target must also have
zero arguments. Use $a(var) to match any remaining arguments (see below). Omitting the return
type matches any return type.
3.35.2.3. qmatch_function
qmatch_function(func) $(args) : RetType { stmts } matches a compiled function’s
arguments, return type, and body:
[export]
def target_add(a, b : int) : int {
return a + b
}
[test]
def test_add(t : T?) {
var func = find_module_function_via_rtti(compiling_module(), @@target_add)
let r = qmatch_function(func) $(a : int; b : int) : int {
return a + b
}
assert(r.matched)
}
The function has been through compilation and optimization, so the AST may differ from the source.
Compiler-injected fakeContext and fakeLineInfo arguments are filtered automatically.
3.35.4. Wildcards
Wildcards match variable numbers of statements in block and function patterns:
Wildcard |
Matches |
|---|---|
|
0 or more statements |
|
1 or more statements |
|
0 or 1 statement (fails if 2+) |
|
Exactly 1 statement |
All wildcards accept an optional $b(var) argument to capture the matched statements.
// Match: any prefix, then if(...), then any suffix
let r = qmatch_block(blk) $ {
_wildcard()
if (a < 5) { return b }
_wildcard()
}
3.35.5. Type matching
Types in patterns are matched structurally — base type, const/ref/pointer flags, struct/enum names, and child types are all compared recursively.
3.35.5.1. auto (type wildcard)
Use auto in any type position to match any type:
// Matches any array type
let r = qmatch(expr, type<array<auto>>)
// Matches any table with string keys
let r2 = qmatch(expr, type<table<string; auto>>)
3.35.6. Constant constructors and folding
The compiler folds constant constructor calls like range(1, 10) into ExprConstRange values.
ast_match handles this transparently — a pattern range(1, 10) matches the folded constant.
Tags work inside constant constructors:
var x_val : float
let r = qmatch(expr, float4($v(x_val), 2.0, 3.0, 4.0))
// Matches ExprConstFloat4, captures the x component
Supported constructors: range, urange, range64, urange64,
int2, int3, int4, uint2, uint3, uint4,
float2, float3, float4.
3.35.7. Generic function matching
When matching calls to generic function instances, the compiler mangles the call name
(e.g. generic_add`12345). ast_match resolves the original name via fromGeneric,
so patterns like generic_add(a, b) match transparently.
$c(name) on a generic call also returns the original (unmangled) name.
3.35.8. Result type
enum QMatchError : int {
ok
rtti_mismatch
field_mismatch
const_type_mismatch
type_mismatch
list_length
wildcard_not_found
null_expression
}
struct QMatchResult {
matched : bool
error : QMatchError
expr : Expression const?
}
When a match fails, error indicates why and expr points to the mismatched AST node
(useful for diagnostics).
See also
Reification for the forward direction — building AST from values using the same tag system, Macros for the compilation lifecycle where AST matching is used, AST pattern matching module for the full API reference.