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