ArkScript
A small, fast, functional and scripting language for video games
NameResolutionPass.hpp
Go to the documentation of this file.
1/**
2 * @file NameResolutionPass.hpp
3 * @author Alexandre Plateau ([email protected])
4 * @brief
5 * @version 1.0
6 * @date 2024-07-22
7 *
8 * @copyright Copyright (c) 2024
9 *
10 */
11
12#ifndef ARK_COMPILER_NAMERESOLUTIONPASS_HPP
13#define ARK_COMPILER_NAMERESOLUTIONPASS_HPP
14
15#include <vector>
16#include <string>
17#include <optional>
18#include <unordered_set>
19
20#include <Ark/Compiler/Pass.hpp>
21
22namespace Ark::internal
23{
24 struct Variable
25 {
26 std::string name;
28
29 bool operator==(const Variable& other) const = default;
30 };
31}
32
33template <>
34struct std::hash<Ark::internal::Variable>
35{
36 inline size_t operator()(const Ark::internal::Variable& x) const noexcept
37 {
38 return std::hash<std::string> {}(x.name);
39 }
40};
41
42namespace Ark::internal
43{
45 {
46 public:
47 /**
48 * @brief Create a ScopeResolver
49 * @details Kickstart by create a default global scope
50 */
52
53 /**
54 * @brief Create a new scope
55 */
56 void createNew();
57
58 /**
59 * @brief Remove the last scope
60 */
61 void removeLocalScope();
62
63 /**
64 * @brief Register a variable in the current (last) scope
65 * @param name
66 * @param is_mutable
67 */
68 void registerInCurrent(const std::string& name, bool is_mutable);
69
70 /**
71 * @brief Checks the scopes in reverse order for 'name' and returns its mutability status
72 * @param name
73 * @return std::nullopt if the variable could not be found
74 * @return true if immutable
75 * @return false if mutable
76 */
77 [[nodiscard]] std::optional<bool> isImmutable(const std::string& name) const;
78
79 /**
80 * @brief Checks if any scope has 'name', in reverse order
81 * @param name
82 * @return
83 */
84 [[nodiscard]] bool isRegistered(const std::string& name) const;
85
86 /**
87 * @brief Checks if 'name' is in the current scope
88 *
89 * @param name
90 * @return
91 */
92 [[nodiscard]] bool isInScope(const std::string& name) const;
93
94 class Scope
95 {
96 public:
97 /**
98 * @brief Add a variable to the scope, given a mutability status
99 * @param name
100 * @param is_mutable
101 */
102 void add(const std::string& name, bool is_mutable);
103
104 /**
105 * @brief Try to return a variable from this scope with a given name.
106 * @param name
107 * @return std::optional<Variable> std::nullopt if the variable isn't in scope
108 */
109 [[nodiscard]] std::optional<Variable> get(const std::string& name) const;
110
111 [[nodiscard]] bool has(const std::string& name) const;
112
113 private:
114 std::unordered_set<Variable> m_vars {};
115 };
116
117 private:
118 std::vector<Scope> m_scopes;
119 };
120
121 class NameResolutionPass final : public Pass
122 {
123 public:
124 /**
125 * @brief Create a NameResolutionPass
126 * @param debug debug level
127 */
128 explicit NameResolutionPass(unsigned debug);
129
130 /**
131 * @brief Start visiting the given AST, checking for mutability violation and unbound variables
132 * @param ast AST to analyze
133 */
134 void process(const Node& ast) override;
135
136 /**
137 * @brief Unused overload that return the input AST (untouched as this pass only generates errors)
138 * @return const Node& ast
139 */
140 [[nodiscard]] const Node& ast() const noexcept override;
141
142 /**
143 * @brief Register a symbol as defined, so that later we can throw errors on undefined symbols
144 *
145 * @param sym
146 * @param is_mutable true if the symbol is inside mut/set, false otherwise (let)
147 */
148 void addDefinedSymbol(const std::string& sym, bool is_mutable);
149
150 private:
152 std::unordered_set<std::string> m_language_symbols; ///< Precomputed set of language symbols that can't be used to define variables
153 std::vector<Node> m_symbol_nodes;
154 std::unordered_set<std::string> m_defined_symbols;
155 std::vector<std::string> m_plugin_names;
157
158 /**
159 * @brief Recursively visit nodes
160 * @param node node to visit
161 */
162 void visit(const Node& node);
163
164 /**
165 *
166 * @param node a list node whose first child is a keyword
167 * @param keyword
168 */
169 void visitKeyword(const Node& node, Keyword keyword);
170
171 /**
172 * @brief Register a given node in the symbol table
173 *
174 * @param symbol
175 */
176 void addSymbolNode(const Node& symbol);
177
178 /**
179 * @brief Checking if a symbol may be coming from a plugin
180 *
181 * @param name symbol name
182 * @return true the symbol may be from a plugin, loaded at runtime
183 * @return false
184 */
185 [[nodiscard]] bool mayBeFromPlugin(const std::string& name) const noexcept;
186
187 /**
188 * @brief Checks for undefined symbols, not present in the defined symbols table
189 *
190 */
191 void checkForUndefinedSymbol() const;
192
193 /**
194 * @brief Suggest a symbol of what the user may have meant to input
195 *
196 * @param str the string
197 * @return std::string
198 */
199 [[nodiscard]] std::string offerSuggestion(const std::string& str) const;
200 };
201}
202
203#endif // ARK_COMPILER_NAMERESOLUTIONPASS_HPP
Interface for a compiler pass (take in an AST, output an AST)
std::vector< std::string > m_plugin_names
const Node & ast() const noexcept override
Unused overload that return the input AST (untouched as this pass only generates errors)
void checkForUndefinedSymbol() const
Checks for undefined symbols, not present in the defined symbols table.
void addSymbolNode(const Node &symbol)
Register a given node in the symbol table.
std::string offerSuggestion(const std::string &str) const
Suggest a symbol of what the user may have meant to input.
void visit(const Node &node)
Recursively visit nodes.
std::unordered_set< std::string > m_language_symbols
Precomputed set of language symbols that can't be used to define variables.
std::unordered_set< std::string > m_defined_symbols
bool mayBeFromPlugin(const std::string &name) const noexcept
Checking if a symbol may be coming from a plugin.
void process(const Node &ast) override
Start visiting the given AST, checking for mutability violation and unbound variables.
void addDefinedSymbol(const std::string &sym, bool is_mutable)
Register a symbol as defined, so that later we can throw errors on undefined symbols.
void visitKeyword(const Node &node, Keyword keyword)
NameResolutionPass(unsigned debug)
Create a NameResolutionPass.
A node of an Abstract Syntax Tree for ArkScript.
Definition Node.hpp:30
An interface to describe compiler passes.
Definition Pass.hpp:23
bool has(const std::string &name) const
std::unordered_set< Variable > m_vars
void add(const std::string &name, bool is_mutable)
Add a variable to the scope, given a mutability status.
std::optional< Variable > get(const std::string &name) const
Try to return a variable from this scope with a given name.
void removeLocalScope()
Remove the last scope.
ScopeResolver()
Create a ScopeResolver.
bool isRegistered(const std::string &name) const
Checks if any scope has 'name', in reverse order.
void createNew()
Create a new scope.
void registerInCurrent(const std::string &name, bool is_mutable)
Register a variable in the current (last) scope.
bool isInScope(const std::string &name) const
Checks if 'name' is in the current scope.
std::optional< bool > isImmutable(const std::string &name) const
Checks the scopes in reverse order for 'name' and returns its mutability status.
Keyword
The different keywords available.
Definition Common.hpp:58
bool operator==(const Variable &other) const =default
size_t operator()(const Ark::internal::Variable &x) const noexcept