Implement closures

This commit is contained in:
ala89 2024-01-04 21:53:47 +01:00
parent a0c1724b2e
commit a2dd06b1bf
5 changed files with 42 additions and 7 deletions

View File

@ -337,7 +337,9 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
memory.declare(function_name, type); memory.declare(function_name, type);
memory.update(function_name, node.children[3]); Function fn = { {}, memory.make_closure() };
memory.update(function_name, fn);
memory.add_scope(ScopeType::Function, &memory.get(function_name)); memory.add_scope(ScopeType::Function, &memory.get(function_name));
for (tuple<Type, string> variable : prototype) { for (tuple<Type, string> variable : prototype) {

View File

@ -13,7 +13,7 @@ class Memory {
public: public:
bool contains(string identifier); bool contains(string identifier);
bool contains_top(string identifier); bool contains_top(string identifier);
void add_scope(ScopeType type, MemoryVar* fn = NULL, CodePosition entry_pos = { }); void add_scope(ScopeType type, MemoryVar* fn = nullptr, CodePosition entry_pos = { });
void remove_scope(void); void remove_scope(void);
MemoryVar& get(string identifier); MemoryVar& get(string identifier);
@ -21,6 +21,8 @@ class Memory {
void declare(string identifier, Type type); void declare(string identifier, Type type);
void update(string identifier, EvalResult value); void update(string identifier, EvalResult value);
Closure make_closure(void);
StackTrace get_trace(CodePosition pos); StackTrace get_trace(CodePosition pos);
Scope& _debug_top(void); Scope& _debug_top(void);

View File

@ -8,6 +8,7 @@
#include <vector> #include <vector>
#include <stdexcept> #include <stdexcept>
#include <tuple> #include <tuple>
#include <functional>
using namespace std; using namespace std;
/** /**
@ -201,7 +202,12 @@ struct ParseReturn {
/** /**
* Interpreter * Interpreter
*/ */
using EvalResult = variant<monostate, int, double, Node>; struct MemoryVar;
using Closure = unordered_map<string, reference_wrapper<MemoryVar>>;
using Function = tuple<Node, Closure>;
using EvalResult = variant<monostate, int, double, Function>;
enum class ScopeType { Block, Function, For }; enum class ScopeType { Block, Function, For };

View File

@ -173,7 +173,9 @@ EvalResult eval(Node &ast, Memory &memory) {
.data = prototype .data = prototype
}); });
memory.update(identifier, node.children[3]); Function fn = { node.children[3], memory.make_closure() };
memory.update(identifier, fn);
return {}; return {};
} break; } break;
@ -208,7 +210,7 @@ EvalResult eval(Node &ast, Memory &memory) {
} }
try { try {
eval(get<Node>(var.value), memory); eval(get<0>(get<Function>(var.value)), memory);
// Tmp: no flow control // Tmp: no flow control
if (get<0>(prototype[0]).type != TypeType::Void) { if (get<0>(prototype[0]).type != TypeType::Void) {

View File

@ -1,6 +1,7 @@
#include "include/memory.h" #include "include/memory.h"
#include "include/errors.h" #include "include/errors.h"
#include "include/utils.h" #include "include/utils.h"
#include "include/types.h"
using namespace std; using namespace std;
Memory::Memory(void) { Memory::Memory(void) {
@ -12,6 +13,11 @@ bool Memory::contains(string identifier) {
for (auto rit = scopes.rbegin(); rit != scopes.rend(); ++rit) { for (auto rit = scopes.rbegin(); rit != scopes.rend(); ++rit) {
Scope& scope = *rit; Scope& scope = *rit;
if (scope.vars.contains(identifier)) return true; if (scope.vars.contains(identifier)) return true;
if (scope.type == ScopeType::Function) {
Closure closure = std::get<1>(std::get<Function>(scope.fn->value));
if (closure.contains(identifier)) return true;
break;
}
} }
return false; return false;
@ -39,6 +45,11 @@ MemoryVar& Memory::get(string identifier) {
for (auto rit = scopes.rbegin(); rit != scopes.rend(); ++rit) { for (auto rit = scopes.rbegin(); rit != scopes.rend(); ++rit) {
Scope& scope = *rit; Scope& scope = *rit;
if (scope.vars.contains(identifier)) return scope.vars[identifier]; if (scope.vars.contains(identifier)) return scope.vars[identifier];
if (scope.type == ScopeType::Function) {
Closure closure = std::get<1>(std::get<Function>(scope.fn->value));
if (closure.contains(identifier)) return closure.at(identifier);
break;
}
} }
throw exception(); throw exception();
@ -73,14 +84,26 @@ void Memory::update(string identifier, EvalResult value) {
throw exception(); throw exception();
} }
Closure Memory::make_closure(void) {
Closure closure;
for (auto rit = scopes.rbegin(); rit != scopes.rend(); ++rit) {
Scope& scope = *rit;
for (auto& [identifier, var] : scope.vars) {
if (!closure.contains(identifier)) closure.insert_or_assign(identifier, var);
}
}
return closure;
}
StackTrace Memory::get_trace(CodePosition pos) { StackTrace Memory::get_trace(CodePosition pos) {
StackTrace trace = {}; StackTrace trace = {};
for (auto rit = scopes.rbegin(); rit != scopes.rend(); ++rit) { for (auto rit = scopes.rbegin(); rit != scopes.rend(); ++rit) {
Scope& scope = *rit; Scope& scope = *rit;
if (scope.type == ScopeType::Function) { if (scope.type == ScopeType::Function) {
MemoryVar fn = *(scope.fn); StackTraceEntry entry = { scope.fn->identifier, pos };
StackTraceEntry entry = { fn.identifier, pos };
trace.push_back(entry); trace.push_back(entry);
pos = scope.entry_pos; pos = scope.entry_pos;
} }