diff --git a/include/ast/BlockNode.h b/include/ast/BlockNode.h index dbb6944bf78fcfea42ba840b18220c4ca3e0a60d..d1ec053029b16dd18ca585d020f14667c606ecb9 100644 --- a/include/ast/BlockNode.h +++ b/include/ast/BlockNode.h @@ -1,6 +1,7 @@ #pragma once #include "ast/Node.h" +#include "parser/Scope.h" namespace funk { @@ -9,6 +10,7 @@ class BlockNode : public Node { public: BlockNode(const SourceLocation& loc); + BlockNode(const SourceLocation& loc, const Vector<Node*>& statements); ~BlockNode(); void add(Node* statement); diff --git a/include/parser/Parser.h b/include/parser/Parser.h index add438b6e88bbb8564f2a737a37d4f672ab084b7..48d6d316c24e6c344cd39ea554ac944b783a191e 100644 --- a/include/parser/Parser.h +++ b/include/parser/Parser.h @@ -7,6 +7,7 @@ #pragma once #include "lexer/Lexer.h" +#include "parser/Scope.h" #include "token/Token.h" #include "utils/Common.h" diff --git a/include/parser/Scope.h b/include/parser/Scope.h index 186f2b03ce60a5c4f8fd9d4699be50f72925e6cb..91ab262ab536a5b5db9b299c361428c2945511dc 100644 --- a/include/parser/Scope.h +++ b/include/parser/Scope.h @@ -1,4 +1,28 @@ -/* -Create a Scope class with a singleton accesor. See Logger for example of singleton. -Create a global scope with HasMap, some util functions? key string value NodeValue / LiteralNode. -*/ +#pragma once + +#include "ast/Node.h" +#include "logging/LogMacros.h" +#include "utils/Common.h" + +namespace funk +{ + +class Scope +{ +public: + static Scope& instance(); + + void push(); + void pop(); + + void add(const String& name, Node* node); + Node* get(const String& name) const; + +private: + Scope(); + ~Scope(); + Vector<HashMap<String, Node*>> scopes; + int depth{0}; +}; + +} // namespace funk diff --git a/include/utils/Common.h b/include/utils/Common.h index 1abd922312b1d83887269e322bb64ad643effc91..38da432c9cc113c1b5b0d21be93d00597708ab30 100644 --- a/include/utils/Common.h +++ b/include/utils/Common.h @@ -46,6 +46,11 @@ template <typename T> using Vector = std::vector<T>; */ template <typename K, typename V> using HashMap = std::unordered_map<K, V>; +/** + * @brief Macro for std::to_string. + */ +#define to_str(x) std::to_string(x) + /** * @brief Stores location information for source code elements. * Used for error reporting and debugging to identify where in the source code an element appears. diff --git a/source/ast/BlockNode.cc b/source/ast/BlockNode.cc index c8cd698331cf1b5eb434281f7fcd9d601d708774..826cdfbace5962e014b8c7b7a57c12442b82e03f 100644 --- a/source/ast/BlockNode.cc +++ b/source/ast/BlockNode.cc @@ -4,6 +4,8 @@ namespace funk { BlockNode::BlockNode(const SourceLocation& loc) : Node(loc), statements{} {} +BlockNode::BlockNode(const SourceLocation& loc, const Vector<Node*>& statements) : Node(loc), statements{statements} {} + BlockNode::~BlockNode() { for (Node* statement : statements) { delete statement; } @@ -21,8 +23,10 @@ Vector<Node*> BlockNode::get_statements() const Node* BlockNode::evaluate() const { + Scope::instance().push(); Node* result{}; for (Node* statement : statements) { result = statement->evaluate(); } + Scope::instance().pop(); return result; } diff --git a/source/parser/Scope.cc b/source/parser/Scope.cc new file mode 100644 index 0000000000000000000000000000000000000000..bd38505059cbfe6efdd1afcf54cbde9b89e67efa --- /dev/null +++ b/source/parser/Scope.cc @@ -0,0 +1,50 @@ +#include "parser/Scope.h" + +namespace funk +{ + +Scope::Scope() {} +Scope::~Scope() {} + +Scope& Scope::instance() +{ + static Scope instance; + return instance; +} + +void Scope::push() +{ + LOG_DEBUG("Pushing scope at depth " + to_str(depth) + " -> " + to_str(depth + 1)); + scopes.push_back({}); + depth++; +} + +void Scope::pop() +{ + LOG_DEBUG("Popping scope at depth " + to_str(depth) + " -> " + to_str(depth - 1)); + scopes.pop_back(); + depth--; +} + +void Scope::add(const String& name, Node* node) +{ + LOG_DEBUG("Registering symbol '" + name + "' with node " + node->to_s()); + scopes.back()[name] = node; +} + +Node* Scope::get(const String& name) const +{ + for (int i = scopes.size() - 1; i >= 0; i--) + { + LOG_DEBUG("Searching for symbol '" + name + "' at depth " + to_str(i)); + auto it = scopes[i].find(name); + if (it != scopes[i].end()) + { + LOG_DEBUG("Found symbol '" + name + "' at depth " + to_str(i)); + return it->second; + } + } + return nullptr; +} + +} // namespace funk