Implement closures
This commit is contained in:
parent
a0c1724b2e
commit
a2dd06b1bf
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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 };
|
||||||
|
|
||||||
|
@ -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) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user