// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details1#pragma once23#include "Luau/Ast.h"4#include "Luau/Common.h"56#include <vector>7#include <type_traits>89namespace Luau10{1112struct Nth13{14int classIndex;15int nth;16};1718template<typename T>19Nth nth(int nth = 1)20{21static_assert(std::is_base_of_v<AstNode, T>, "T must be a derived class of AstNode");22LUAU_ASSERT(nth > 0); // Did you mean to use `nth<T>(1)`?2324return Nth{T::ClassIndex(), nth};25}2627struct FindNthOccurenceOf : public AstVisitor28{29Nth requestedNth;30int currentOccurrence = 0;31AstNode* theNode = nullptr;3233FindNthOccurenceOf(Nth nth);3435bool checkIt(AstNode* n);3637bool visit(AstNode* n) override;38bool visit(AstType* n) override;39bool visit(AstTypePack* n) override;40};4142/** DSL querying of the AST.43*44* Given an AST, one can query for a particular node directly without having to manually unwrap the tree, for example:45*46* ```47* if a and b then48* print(a + b)49* end50*51* function f(x, y)52* return x + y53* end54* ```55*56* There are numerous ways to access the second AstExprBinary.57* 1. Luau::query<AstExprBinary>(block, {nth<AstStatFunction>(), nth<AstExprBinary>()})58* 2. Luau::query<AstExprBinary>(Luau::query<AstStatFunction>(block))59* 3. Luau::query<AstExprBinary>(block, {nth<AstExprBinary>(2)})60*/61template<typename T, int N = 1>62T* query(AstNode* node, const std::vector<Nth>& nths = {nth<T>(N)})63{64static_assert(std::is_base_of_v<AstNode, T>, "T must be a derived class of AstNode");6566// If a nested query call fails to find the node in question, subsequent calls can propagate rather than trying to do more.67// This supports `query(query(...))`6869for (Nth nth : nths)70{71if (!node)72return nullptr;7374FindNthOccurenceOf finder{nth};75node->visit(&finder);76node = finder.theNode;77}7879return node ? node->as<T>() : nullptr;80}8182} // namespace Luau838485