Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/tests/AstQueryDsl.h
2723 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
#pragma once
3
4
#include "Luau/Ast.h"
5
#include "Luau/Common.h"
6
7
#include <vector>
8
#include <type_traits>
9
10
namespace Luau
11
{
12
13
struct Nth
14
{
15
int classIndex;
16
int nth;
17
};
18
19
template<typename T>
20
Nth nth(int nth = 1)
21
{
22
static_assert(std::is_base_of_v<AstNode, T>, "T must be a derived class of AstNode");
23
LUAU_ASSERT(nth > 0); // Did you mean to use `nth<T>(1)`?
24
25
return Nth{T::ClassIndex(), nth};
26
}
27
28
struct FindNthOccurenceOf : public AstVisitor
29
{
30
Nth requestedNth;
31
int currentOccurrence = 0;
32
AstNode* theNode = nullptr;
33
34
FindNthOccurenceOf(Nth nth);
35
36
bool checkIt(AstNode* n);
37
38
bool visit(AstNode* n) override;
39
bool visit(AstType* n) override;
40
bool visit(AstTypePack* n) override;
41
};
42
43
/** DSL querying of the AST.
44
*
45
* Given an AST, one can query for a particular node directly without having to manually unwrap the tree, for example:
46
*
47
* ```
48
* if a and b then
49
* print(a + b)
50
* end
51
*
52
* function f(x, y)
53
* return x + y
54
* end
55
* ```
56
*
57
* There are numerous ways to access the second AstExprBinary.
58
* 1. Luau::query<AstExprBinary>(block, {nth<AstStatFunction>(), nth<AstExprBinary>()})
59
* 2. Luau::query<AstExprBinary>(Luau::query<AstStatFunction>(block))
60
* 3. Luau::query<AstExprBinary>(block, {nth<AstExprBinary>(2)})
61
*/
62
template<typename T, int N = 1>
63
T* query(AstNode* node, const std::vector<Nth>& nths = {nth<T>(N)})
64
{
65
static_assert(std::is_base_of_v<AstNode, T>, "T must be a derived class of AstNode");
66
67
// If a nested query call fails to find the node in question, subsequent calls can propagate rather than trying to do more.
68
// This supports `query(query(...))`
69
70
for (Nth nth : nths)
71
{
72
if (!node)
73
return nullptr;
74
75
FindNthOccurenceOf finder{nth};
76
node->visit(&finder);
77
node = finder.theNode;
78
}
79
80
return node ? node->as<T>() : nullptr;
81
}
82
83
} // namespace Luau
84
85