// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details #pragma once // Do not include LValue. It should never be used here. #include "Luau/Ast.h" #include "Luau/DenseHash.h" #include "Luau/Def.h" #include "Luau/Symbol.h" #include namespace Luau { struct DataFlowGraph { DataFlowGraph(DataFlowGraph&&) = default; DataFlowGraph& operator=(DataFlowGraph&&) = default; // TODO: AstExprLocal, AstExprGlobal, and AstLocal* are guaranteed never to return nullopt. // We leave them to return an optional as we build it out, but the end state is for them to return a non-optional DefId. std::optional getDef(const AstExpr* expr) const; std::optional getDef(const AstLocal* local) const; /// Retrieve the Def that corresponds to the given Symbol. /// /// We do not perform dataflow analysis on globals, so this function always /// yields nullopt when passed a global Symbol. std::optional getDef(const Symbol& symbol) const; private: DataFlowGraph() = default; DataFlowGraph(const DataFlowGraph&) = delete; DataFlowGraph& operator=(const DataFlowGraph&) = delete; DefArena arena; DenseHashMap astDefs{nullptr}; DenseHashMap localDefs{nullptr}; friend struct DataFlowGraphBuilder; }; struct DfgScope { DfgScope* parent; DenseHashMap bindings{Symbol{}}; }; struct ExpressionFlowGraph { std::optional def; }; // Currently unsound. We do not presently track the control flow of the program. // Additionally, we do not presently track assignments. struct DataFlowGraphBuilder { static DataFlowGraph build(AstStatBlock* root, NotNull handle); private: DataFlowGraphBuilder() = default; DataFlowGraphBuilder(const DataFlowGraphBuilder&) = delete; DataFlowGraphBuilder& operator=(const DataFlowGraphBuilder&) = delete; DataFlowGraph graph; NotNull arena{&graph.arena}; struct InternalErrorReporter* handle; std::vector> scopes; DfgScope* childScope(DfgScope* scope); std::optional use(DfgScope* scope, Symbol symbol, AstExpr* e); void visit(DfgScope* scope, AstStatBlock* b); void visitBlockWithoutChildScope(DfgScope* scope, AstStatBlock* b); // TODO: visit type aliases void visit(DfgScope* scope, AstStat* s); void visit(DfgScope* scope, AstStatIf* i); void visit(DfgScope* scope, AstStatWhile* w); void visit(DfgScope* scope, AstStatRepeat* r); void visit(DfgScope* scope, AstStatBreak* b); void visit(DfgScope* scope, AstStatContinue* c); void visit(DfgScope* scope, AstStatReturn* r); void visit(DfgScope* scope, AstStatExpr* e); void visit(DfgScope* scope, AstStatLocal* l); void visit(DfgScope* scope, AstStatFor* f); void visit(DfgScope* scope, AstStatForIn* f); void visit(DfgScope* scope, AstStatAssign* a); void visit(DfgScope* scope, AstStatCompoundAssign* c); void visit(DfgScope* scope, AstStatFunction* f); void visit(DfgScope* scope, AstStatLocalFunction* l); ExpressionFlowGraph visitExpr(DfgScope* scope, AstExpr* e); ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprLocal* l); ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprGlobal* g); ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprCall* c); ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprIndexName* i); ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprIndexExpr* i); ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprFunction* f); ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprTable* t); ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprUnary* u); ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprBinary* b); ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprTypeAssertion* t); ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprIfElse* i); ExpressionFlowGraph visitExpr(DfgScope* scope, AstExprInterpString* i); // TODO: visitLValue // TODO: visitTypes (because of typeof which has access to values namespace, needs unreachable scope) // TODO: visitTypePacks (because of typeof which has access to values namespace, needs unreachable scope) }; } // namespace Luau