ArkScript
A small, fast, functional and scripting language for video games
ScopeResolver.cpp
Go to the documentation of this file.
2
3#include <ranges>
4
5namespace Ark::internal
6{
8 {
9 createNewNamespace("", /* with_prefix= */ false, /* is_glob= */ true, /* symbols= */ {});
10 }
11
13 {
14 m_scopes.emplace_back(std::make_unique<StaticScope>());
15 }
16
18 {
19 m_scopes.pop_back();
20 }
21
22 void ScopeResolver::createNewNamespace(const std::string& name, bool with_prefix, bool is_glob, const std::vector<std::string>& symbols)
23 {
24 m_scopes.emplace_back(std::make_unique<NamespaceScope>(name, with_prefix, is_glob, symbols));
25 }
26
27 std::string ScopeResolver::registerInCurrent(const std::string& name, const bool is_mutable)
28 {
29 return m_scopes.back()->add(name, is_mutable);
30 }
31
33 {
34 for (auto& m_scope : std::ranges::reverse_view(m_scopes) | std::ranges::views::drop(1))
35 {
36 if (m_scope->saveNamespace(m_scopes.back()))
37 break;
38 }
39
40 m_scopes.pop_back();
41 }
42
43 std::optional<bool> ScopeResolver::isImmutable(const std::string& name) const
44 {
45 for (const auto& m_scope : std::ranges::reverse_view(m_scopes))
46 {
47 if (auto maybe = m_scope->get(name, true); maybe.has_value())
48 return !maybe.value().is_mutable;
49 }
50 return std::nullopt;
51 }
52
53 bool ScopeResolver::isRegistered(const std::string& name) const
54 {
55 for (const auto& m_scope : std::ranges::reverse_view(m_scopes))
56 {
57 if (m_scope->get(name, true).has_value())
58 return true;
59 }
60 return false;
61 }
62
63 bool ScopeResolver::isInScope(const std::string& name) const
64 {
65 return m_scopes.back()->get(name, false).has_value();
66 }
67
68 std::string ScopeResolver::getFullyQualifiedNameInNearestScope(const std::string& name) const
69 {
70 for (const auto& scope : std::ranges::reverse_view(m_scopes))
71 {
72 if (auto maybe_fqn = scope->get(name, true); maybe_fqn.has_value())
73 return maybe_fqn.value().name;
74 }
75 return name;
76 }
77
78 std::pair<bool, std::string> ScopeResolver::canFullyQualifyName(const std::string& name)
79 {
80 // a given name can be fully qualified if
81 // old == new
82 // old != new and new has prefix
83 // if the prefix namespace is glob
84 // if the prefix namespace has name in its symbols
85 // if the prefix namespace is with_prefix && it is the top most scope
86 const std::string maybe_fqn = getFullyQualifiedNameInNearestScope(name);
87
88 if (maybe_fqn == name)
89 return std::make_pair(true, maybe_fqn);
90
91 const std::string prefix = maybe_fqn.substr(0, maybe_fqn.find_first_of(':'));
92 const std::string unprefixed_name = maybe_fqn.substr(maybe_fqn.find_first_of(':') + 1);
93 auto namespaces =
94 std::ranges::reverse_view(m_scopes) | std::ranges::views::filter([](const auto& e) {
95 return e->isNamespace();
96 });
97 bool top = true;
98 for (auto& scope : namespaces)
99 {
100 if (top && prefix == scope->prefix())
101 return std::make_pair(true, maybe_fqn);
102 if (!top && prefix == scope->prefix() && (scope->isGlob() || scope->hasSymbol(name)))
103 return std::make_pair(true, maybe_fqn);
104
105 if (scope->recursiveHasSymbol(unprefixed_name))
106 return std::make_pair(true, maybe_fqn);
107
108 top = false;
109 }
110
111 return std::make_pair(false, maybe_fqn);
112 }
113
115 {
116 if (!m_scopes.empty()) [[likely]]
117 return m_scopes.back().get();
118 return nullptr;
119 }
120}
Handle scope resolution at compile time.
std::string registerInCurrent(const std::string &name, bool is_mutable)
Register a Declaration in the current (last) scope.
ScopeResolver()
Create a ScopeResolver.
void createNewNamespace(const std::string &name, bool with_prefix, bool is_glob, const std::vector< std::string > &symbols)
Create a new namespace scope.
void saveNamespaceAndRemove()
Save the last scope as a namespace, by attaching it to the nearest namespace scope.
std::string getFullyQualifiedNameInNearestScope(const std::string &name) const
Get a FQN from a variable name in the nearest scope it is declared in.
bool isRegistered(const std::string &name) const
Checks if any scope has 'name', in reverse order.
void createNew()
Create a new scope.
std::vector< std::unique_ptr< StaticScope > > m_scopes
StaticScope * currentScope() const
Return a non-owning raw pointer to the current scope.
bool isInScope(const std::string &name) const
Checks if 'name' is in the current scope.
void removeLastScope()
Remove the last scope.
std::optional< bool > isImmutable(const std::string &name) const
Checks the scopes in reverse order for 'name' and returns its mutability status.
std::pair< bool, std::string > canFullyQualifyName(const std::string &name)
Checks if a name can be fully qualified (allows only unprefixed names to be resolved by glob namespac...
virtual std::optional< Declaration > get(const std::string &name, bool extensive_lookup)
Try to return a Declaration from this scope with a given name.