Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/Analysis/src/LValue.cpp
2725 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
#include "Luau/LValue.h"
3
4
#include "Luau/Ast.h"
5
6
#include <vector>
7
8
namespace Luau
9
{
10
11
bool Field::operator==(const Field& rhs) const
12
{
13
LUAU_ASSERT(parent && rhs.parent);
14
return key == rhs.key && (parent == rhs.parent || *parent == *rhs.parent);
15
}
16
17
bool Field::operator!=(const Field& rhs) const
18
{
19
return !(*this == rhs);
20
}
21
22
size_t LValueHasher::operator()(const LValue& lvalue) const
23
{
24
// Most likely doesn't produce high quality hashes, but we're probably ok enough with it.
25
// When an evidence is shown that operator==(LValue) is used more often than it should, we can have a look at improving the hash quality.
26
size_t acc = 0;
27
size_t offset = 0;
28
29
const LValue* current = &lvalue;
30
while (current)
31
{
32
if (auto field = get<Field>(*current))
33
acc ^= (std::hash<std::string>{}(field->key) << 1) >> ++offset;
34
else if (auto symbol = get<Symbol>(*current))
35
acc ^= std::hash<Symbol>{}(*symbol) << 1;
36
else
37
LUAU_ASSERT(!"Hash not accumulated for this new LValue alternative.");
38
39
current = baseof(*current);
40
}
41
42
return acc;
43
}
44
45
const LValue* baseof(const LValue& lvalue)
46
{
47
if (auto field = get<Field>(lvalue))
48
return field->parent.get();
49
50
auto symbol = get<Symbol>(lvalue);
51
LUAU_ASSERT(symbol);
52
return nullptr; // Base of root is null.
53
}
54
55
std::optional<LValue> tryGetLValue(const AstExpr& node)
56
{
57
const AstExpr* expr = &node;
58
while (auto e = expr->as<AstExprGroup>())
59
expr = e->expr;
60
61
if (auto local = expr->as<AstExprLocal>())
62
return Symbol{local->local};
63
else if (auto global = expr->as<AstExprGlobal>())
64
return Symbol{global->name};
65
else if (auto indexname = expr->as<AstExprIndexName>())
66
{
67
if (auto lvalue = tryGetLValue(*indexname->expr))
68
return Field{std::make_shared<LValue>(*lvalue), indexname->index.value};
69
}
70
else if (auto indexexpr = expr->as<AstExprIndexExpr>())
71
{
72
if (auto lvalue = tryGetLValue(*indexexpr->expr))
73
if (auto string = indexexpr->index->as<AstExprConstantString>())
74
return Field{std::make_shared<LValue>(*lvalue), std::string(string->value.data, string->value.size)};
75
}
76
77
return std::nullopt;
78
}
79
80
Symbol getBaseSymbol(const LValue& lvalue)
81
{
82
const LValue* current = &lvalue;
83
while (get<Field>(*current))
84
current = baseof(*current);
85
86
const Symbol* symbol = get<Symbol>(*current);
87
LUAU_ASSERT(symbol);
88
return *symbol;
89
}
90
91
void merge(RefinementMap& l, const RefinementMap& r, std::function<TypeId(TypeId, TypeId)> f)
92
{
93
for (const auto& [k, a] : r)
94
{
95
if (auto it = l.find(k); it != l.end())
96
l[k] = f(it->second, a);
97
else
98
l[k] = a;
99
}
100
}
101
102
void addRefinement(RefinementMap& refis, const LValue& lvalue, TypeId ty)
103
{
104
refis[lvalue] = ty;
105
}
106
107
} // namespace Luau
108
109