Add standard functions
This commit is contained in:
parent
0a1a288df6
commit
bba2e812c4
@ -362,12 +362,12 @@ AnalysisResult analyze(Node &ast, Memory &memory) {
|
|||||||
memory.declare(function_name, type);
|
memory.declare(function_name, type);
|
||||||
|
|
||||||
Node empty_node = {};
|
Node empty_node = {};
|
||||||
Function fn = { empty_node, memory.make_closure() };
|
UserFunction fn = { empty_node, memory.make_closure() };
|
||||||
|
|
||||||
memory.update(function_name, fn);
|
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 (ArgDefinition variable : prototype) {
|
||||||
Type vtype = get<0>(variable);
|
Type vtype = get<0>(variable);
|
||||||
string vname = get<1>(variable);
|
string vname = get<1>(variable);
|
||||||
|
|
||||||
|
@ -25,12 +25,16 @@ class Memory {
|
|||||||
|
|
||||||
StackTrace get_trace(CodePosition pos);
|
StackTrace get_trace(CodePosition pos);
|
||||||
|
|
||||||
|
void _debug_clear(void);
|
||||||
Scope& _debug_top(void);
|
Scope& _debug_top(void);
|
||||||
void _debug_print(void);
|
void _debug_print(void);
|
||||||
|
|
||||||
Memory(void);
|
Memory(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void make_global_scope(void);
|
||||||
|
void make_standard_fn(string identifier, InternalCall call, FunctionPrototype prototype);
|
||||||
|
|
||||||
list<Scope> scopes;
|
list<Scope> scopes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -20,7 +20,8 @@ enum class TypeType {
|
|||||||
Int, Double, Void, Function
|
Int, Double, Void, Function
|
||||||
};
|
};
|
||||||
|
|
||||||
using FunctionPrototype = vector<tuple<Type, string>>;
|
using ArgDefinition = tuple<Type, string>;
|
||||||
|
using FunctionPrototype = vector<ArgDefinition>;
|
||||||
using TypeData = variant<monostate, FunctionPrototype>;
|
using TypeData = variant<monostate, FunctionPrototype>;
|
||||||
|
|
||||||
struct Type {
|
struct Type {
|
||||||
@ -171,12 +172,12 @@ enum class NodeType {
|
|||||||
Return, // -> Return ; | Return Expr ;
|
Return, // -> Return ; | Return Expr ;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct InnerNode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* InnerNode: noeud interne
|
* InnerNode: noeud interne
|
||||||
* Token: feuille
|
* Token: feuille
|
||||||
*/
|
*/
|
||||||
|
struct InnerNode;
|
||||||
|
|
||||||
using Node = variant<InnerNode, Token>;
|
using Node = variant<InnerNode, Token>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -205,7 +206,13 @@ struct ParseReturn {
|
|||||||
struct MemoryVar;
|
struct MemoryVar;
|
||||||
|
|
||||||
using Closure = unordered_map<string, reference_wrapper<MemoryVar>>;
|
using Closure = unordered_map<string, reference_wrapper<MemoryVar>>;
|
||||||
using Function = tuple<Node, Closure>;
|
using UserFunction = tuple<Node, Closure>;
|
||||||
|
|
||||||
|
enum class InternalCall {
|
||||||
|
ClearMemory, DumpMemory, DumpHistory
|
||||||
|
};
|
||||||
|
|
||||||
|
using Function = variant<UserFunction, InternalCall>;
|
||||||
|
|
||||||
using EvalResult = variant<monostate, int, double, Function>;
|
using EvalResult = variant<monostate, int, double, Function>;
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ EvalResult eval(Node &ast, Memory &memory) {
|
|||||||
.data = prototype
|
.data = prototype
|
||||||
});
|
});
|
||||||
|
|
||||||
Function fn = { node.children[3], memory.make_closure() };
|
UserFunction fn = { node.children[3], memory.make_closure() };
|
||||||
|
|
||||||
memory.update(identifier, fn);
|
memory.update(identifier, fn);
|
||||||
|
|
||||||
@ -189,20 +189,22 @@ EvalResult eval(Node &ast, Memory &memory) {
|
|||||||
if (!var.initialized)
|
if (!var.initialized)
|
||||||
throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, memory.get_trace(identifierTok.pos), identifier);
|
throw RuntimeError(ErrorType::UninitializedIdentifier, identifierTok.pos, memory.get_trace(identifierTok.pos), identifier);
|
||||||
|
|
||||||
|
Function& fn = get<Function>(var.value);
|
||||||
|
FunctionPrototype& prototype = get<FunctionPrototype>(var.type.data);
|
||||||
|
|
||||||
vector<EvalResult> argValues = {};
|
vector<EvalResult> argValues = {};
|
||||||
for (Node arg : args) {
|
for (Node arg : args) {
|
||||||
argValues.push_back(eval(arg, memory));
|
argValues.push_back(eval(arg, memory));
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionPrototype prototype = get<FunctionPrototype>(var.type.data);
|
|
||||||
|
|
||||||
EvalResult res = {};
|
EvalResult res = {};
|
||||||
|
|
||||||
|
if (holds_alternative<UserFunction>(fn)) {
|
||||||
memory.add_scope(ScopeType::Function, &var, identifierTok.pos);
|
memory.add_scope(ScopeType::Function, &var, identifierTok.pos);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (size_t i = 1; i < prototype.size(); i++) {
|
for (size_t i = 1; i < prototype.size(); i++) {
|
||||||
tuple<Type, string> argDef = prototype[i];
|
ArgDefinition argDef = prototype[i];
|
||||||
Type argType = get<0>(argDef);
|
Type argType = get<0>(argDef);
|
||||||
string argName = get<1>(argDef);
|
string argName = get<1>(argDef);
|
||||||
memory.declare(argName, argType);
|
memory.declare(argName, argType);
|
||||||
@ -210,7 +212,7 @@ EvalResult eval(Node &ast, Memory &memory) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
eval(get<0>(get<Function>(var.value)), memory);
|
eval(get<0>(get<UserFunction>(fn)), 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) {
|
||||||
@ -229,6 +231,10 @@ EvalResult eval(Node &ast, Memory &memory) {
|
|||||||
exception_ptr e = current_exception();
|
exception_ptr e = current_exception();
|
||||||
if (e) rethrow_exception(e);
|
if (e) rethrow_exception(e);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memory._debug_clear();
|
||||||
|
}
|
||||||
|
|
||||||
return cast_from_type(get<0>(prototype[0]), res);
|
return cast_from_type(get<0>(prototype[0]), res);
|
||||||
} break;
|
} break;
|
||||||
|
@ -5,16 +5,47 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
Memory::Memory(void) {
|
Memory::Memory(void) {
|
||||||
scopes.emplace_back();
|
make_global_scope();
|
||||||
scopes.back().depth = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Memory::make_global_scope(void) {
|
||||||
|
scopes.emplace_back();
|
||||||
|
|
||||||
|
Scope& global = scopes.back();
|
||||||
|
global.depth = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
FunctionPrototype proto = { { type_type_to_type(TypeType::Void), "" } };
|
||||||
|
make_standard_fn("clear_memory", InternalCall::ClearMemory, proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
FunctionPrototype proto = { { type_type_to_type(TypeType::Void), "" } };
|
||||||
|
make_standard_fn("dump_memory", InternalCall::DumpMemory, proto);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
FunctionPrototype proto = { { type_type_to_type(TypeType::Void), "" } };
|
||||||
|
make_standard_fn("dump_history", InternalCall::DumpHistory, proto);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Memory::make_standard_fn(string identifier, InternalCall call, FunctionPrototype prototype) {
|
||||||
|
Type type = {
|
||||||
|
.type = TypeType::Function,
|
||||||
|
.data = prototype
|
||||||
|
};
|
||||||
|
|
||||||
|
declare(identifier, type);
|
||||||
|
update(identifier, (Function) call);
|
||||||
|
};
|
||||||
|
|
||||||
bool Memory::contains(string identifier) {
|
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) {
|
if (scope.type == ScopeType::Function) {
|
||||||
Closure closure = std::get<1>(std::get<Function>(scope.fn->value));
|
Closure closure = std::get<1>(std::get<UserFunction>(std::get<Function>(scope.fn->value)));
|
||||||
if (closure.contains(identifier)) return true;
|
if (closure.contains(identifier)) return true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -46,7 +77,7 @@ MemoryVar& Memory::get(string identifier) {
|
|||||||
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) {
|
if (scope.type == ScopeType::Function) {
|
||||||
Closure closure = std::get<1>(std::get<Function>(scope.fn->value));
|
Closure closure = std::get<1>(std::get<UserFunction>(std::get<Function>(scope.fn->value)));
|
||||||
if (closure.contains(identifier)) return closure.at(identifier);
|
if (closure.contains(identifier)) return closure.at(identifier);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -80,7 +111,7 @@ void Memory::update(string identifier, EvalResult value) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (scope.type == ScopeType::Function) {
|
if (scope.type == ScopeType::Function) {
|
||||||
Closure closure = std::get<1>(std::get<Function>(scope.fn->value));
|
Closure closure = std::get<1>(std::get<UserFunction>(std::get<Function>(scope.fn->value)));
|
||||||
if (closure.contains(identifier)) {
|
if (closure.contains(identifier)) {
|
||||||
MemoryVar& var = closure.at(identifier);
|
MemoryVar& var = closure.at(identifier);
|
||||||
var.value = value;
|
var.value = value;
|
||||||
@ -123,6 +154,11 @@ StackTrace Memory::get_trace(CodePosition pos) {
|
|||||||
return trace;
|
return trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Memory::_debug_clear(void) {
|
||||||
|
scopes.clear();
|
||||||
|
make_global_scope();
|
||||||
|
}
|
||||||
|
|
||||||
Scope& Memory::_debug_top(void) {
|
Scope& Memory::_debug_top(void) {
|
||||||
Scope& top = scopes.back();
|
Scope& top = scopes.back();
|
||||||
return top;
|
return top;
|
||||||
|
Loading…
Reference in New Issue
Block a user