ArkScript
A small, fast, functional and scripting language for video games
StaticScope.cpp
Go to the documentation of this file.
2
3#include <utility>
4#include <fmt/format.h>
5
6namespace Ark::internal
7{
8 std::string StaticScope::add(const std::string& name, bool is_mutable)
9 {
10 m_vars.emplace(name, name, is_mutable);
11 return name;
12 }
13
14 std::optional<Declaration> StaticScope::get(const std::string& name, [[maybe_unused]] const bool extensive_lookup)
15 {
16 if (const auto it = std::ranges::find(m_vars, name, &Declaration::name); it != m_vars.end())
17 return *it;
18 return std::nullopt;
19 }
20
21 std::string StaticScope::fullyQualifiedName(const std::string& name) const
22 {
23 return name;
24 }
25
26 bool StaticScope::saveNamespace([[maybe_unused]] std::unique_ptr<StaticScope>&)
27 {
28 // the scope can not be saved on a static scope
29 return false;
30 }
31
33 {
34 return false;
35 }
36
37 NamespaceScope::NamespaceScope(std::string name, const bool with_prefix, const bool is_glob, const std::vector<std::string>& symbols) :
39 m_namespace(std::move(name)),
40 m_with_prefix(with_prefix),
41 m_is_glob(is_glob),
42 m_symbols(symbols)
43 {}
44
45 std::string NamespaceScope::add(const std::string& name, bool is_mutable)
46 {
47 // Since we do multiple passes on namespaces, we need to check if the given name is already hidden,
48 // so that we can save the name as it was on the first pass
49 if (name.ends_with("#hidden"))
50 {
51 std::string std_name = name.substr(0, name.find_first_of('#'));
52 return m_vars.emplace(name, std_name, is_mutable).first->name;
53 }
54
55 // Otherwise, we also have to check for the presence of a namespace prefix,
56 // and remove it when checking against the symbols list, to determine if we
57 // need to hide the name or not
58 const bool starts_with_prefix = !m_namespace.empty() && name.starts_with(m_namespace + ":");
59 std::string fqn = fullyQualifiedName(name);
60 std::string unprefixed_name = starts_with_prefix ? name.substr(name.find_first_of(':') + 1) : name;
61
62 if (!m_symbols.empty() && !hasSymbol(unprefixed_name) && !m_with_prefix && !m_is_glob)
63 return m_vars.emplace(fqn + "#hidden", fqn, is_mutable).first->name;
64 return m_vars.emplace(fqn, fqn, is_mutable).first->name;
65 }
66
67 std::optional<Declaration> NamespaceScope::get(const std::string& name, const bool extensive_lookup)
68 {
69 const bool starts_with_prefix = !m_namespace.empty() && name.starts_with(m_namespace + ":");
70 // If the name starts with the namespace and we imported the namespace with prefix
71 // search for name in the namespace
72 if (starts_with_prefix && m_with_prefix)
73 {
74 if (const auto it = std::ranges::find(m_vars, name, &Declaration::name); it != m_vars.end())
75 return *it;
76 }
77 // If the name does not start with the prefix, and we import through either glob or symbol list
78 // search for the name in the namespace
79 // If the name does not start with the prefix, in a namespace with a symbol list but can be resolved,
80 // modify it to hide it to the end user
81 // If the name wasn't qualified, in a prefixed namespace, look up for it but by qualifying the name
82 else if (!starts_with_prefix)
83 {
84 auto it = std::ranges::find(m_vars, fullyQualifiedName(name), &Declaration::name);
85 auto it_original = std::ranges::find(m_vars, fullyQualifiedName(name), &Declaration::original_name);
86 if ((m_is_glob || hasSymbol(name) || m_with_prefix) && it != m_vars.end())
87 return *it;
88 if (!m_symbols.empty() && it_original != m_vars.end())
89 return *it_original;
90 }
91 // lookup in the additional saved namespaces
92 if (extensive_lookup)
93 {
94 for (const auto& scope : m_additional_namespaces)
95 {
96 if (auto maybe_decl = scope->get(name, extensive_lookup); maybe_decl.has_value())
97 return maybe_decl;
98 }
99 }
100 // otherwise we didn't find the name in the namespace
101 return std::nullopt;
102 }
103
104 std::string NamespaceScope::fullyQualifiedName(const std::string& name) const
105 {
106 const bool starts_with_prefix = !m_namespace.empty() && name.starts_with(m_namespace + ":");
107 if (!m_namespace.empty() && !starts_with_prefix)
108 return fmt::format("{}:{}", m_namespace, name);
109 return name;
110 }
111
112 bool NamespaceScope::saveNamespace(std::unique_ptr<StaticScope>& scope)
113 {
114 m_additional_namespaces.push_back(std::move(scope));
115 return true;
116 }
117
119 {
120 return true;
121 }
122}
bool saveNamespace(std::unique_ptr< StaticScope > &) override
Save a namespace scope to help with lookup.
std::string fullyQualifiedName(const std::string &name) const override
Given a Declaration name, compute its fully qualified name.
std::unordered_set< Declaration > m_vars
bool hasSymbol(const std::string &symbol) const override
std::optional< Declaration > get(const std::string &name, bool extensive_lookup) override
Try to return a Declaration from this scope with a given name.
bool isNamespace() const override
NamespaceScope(std::string name, bool with_prefix, bool is_glob, const std::vector< std::string > &symbols)
std::vector< std::string > m_symbols
std::string add(const std::string &name, bool is_mutable) override
Add a Declaration to the scope, given a mutability status.
std::vector< std::unique_ptr< StaticScope > > m_additional_namespaces
std::unordered_set< Declaration > m_vars
virtual std::optional< Declaration > get(const std::string &name, bool extensive_lookup)
Try to return a Declaration from this scope with a given name.
virtual bool saveNamespace(std::unique_ptr< StaticScope > &)
Save a namespace scope to help with lookup.
virtual bool isNamespace() const
virtual std::string add(const std::string &name, bool is_mutable)
Add a Declaration to the scope, given a mutability status.
virtual std::string fullyQualifiedName(const std::string &name) const
Given a Declaration name, compute its fully qualified name.
std::string name
End name, can be modified to be hidden.
std::string original_name
Original name, with the prefix, without hidden namespaces.