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);
|
||||
|
||||
Node empty_node = {};
|
||||
Function fn = { empty_node, memory.make_closure() };
|
||||
UserFunction fn = { empty_node, memory.make_closure() };
|
||||
|
||||
memory.update(function_name, fn);
|
||||
|
||||
memory.add_scope(ScopeType::Function, &memory.get(function_name));
|
||||
for (tuple<Type, string> variable : prototype) {
|
||||
for (ArgDefinition variable : prototype) {
|
||||
Type vtype = get<0>(variable);
|
||||
string vname = get<1>(variable);
|
||||
|
||||
|
@ -25,12 +25,16 @@ class Memory {
|
||||
|
||||
StackTrace get_trace(CodePosition pos);
|
||||
|
||||
void _debug_clear(void);
|
||||
Scope& _debug_top(void);
|
||||
void _debug_print(void);
|
||||
|
||||
Memory(void);
|
||||
|
||||
private:
|
||||
void make_global_scope(void);
|
||||
void make_standard_fn(string identifier, InternalCall call, FunctionPrototype prototype);
|
||||
|
||||
list<Scope> scopes;
|
||||
};
|
||||
|
||||
|
@ -20,7 +20,8 @@ enum class TypeType {
|
||||
Int, Double, Void, Function
|
||||
};
|
||||
|
||||
using FunctionPrototype = vector<tuple<Type, string>>;
|
||||
using ArgDefinition = tuple<Type, string>;
|
||||
using FunctionPrototype = vector<ArgDefinition>;
|
||||
using TypeData = variant<monostate, FunctionPrototype>;
|
||||
|
||||
struct Type {
|
||||
@ -171,12 +172,12 @@ enum class NodeType {
|
||||
Return, // -> Return ; | Return Expr ;
|
||||
};
|
||||
|
||||
struct InnerNode;
|
||||
|
||||
/**
|
||||
* InnerNode: noeud interne
|
||||
* Token: feuille
|
||||
*/
|
||||
struct InnerNode;
|
||||
|
||||
using Node = variant<InnerNode, Token>;
|
||||
|
||||
/**
|
||||
@ -205,7 +206,13 @@ struct ParseReturn {
|
||||
struct 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>;
|
||||
|
||||
|
@ -173,7 +173,7 @@ EvalResult eval(Node &ast, Memory &memory) {
|
||||
.data = prototype
|
||||
});
|
||||
|
||||
Function fn = { node.children[3], memory.make_closure() };
|
||||
UserFunction fn = { node.children[3], memory.make_closure() };
|
||||
|
||||
memory.update(identifier, fn);
|
||||
|
||||
@ -189,45 +189,51 @@ EvalResult eval(Node &ast, Memory &memory) {
|
||||
if (!var.initialized)
|
||||
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 = {};
|
||||
for (Node arg : args) {
|
||||
argValues.push_back(eval(arg, memory));
|
||||
}
|
||||
|
||||
FunctionPrototype prototype = get<FunctionPrototype>(var.type.data);
|
||||
|
||||
EvalResult res = {};
|
||||
|
||||
memory.add_scope(ScopeType::Function, &var, identifierTok.pos);
|
||||
|
||||
try {
|
||||
for (size_t i = 1; i < prototype.size(); i++) {
|
||||
tuple<Type, string> argDef = prototype[i];
|
||||
Type argType = get<0>(argDef);
|
||||
string argName = get<1>(argDef);
|
||||
memory.declare(argName, argType);
|
||||
memory.update(argName, cast_from_type(argType, argValues[i - 1]));
|
||||
}
|
||||
if (holds_alternative<UserFunction>(fn)) {
|
||||
memory.add_scope(ScopeType::Function, &var, identifierTok.pos);
|
||||
|
||||
try {
|
||||
eval(get<0>(get<Function>(var.value)), memory);
|
||||
|
||||
// Tmp: no flow control
|
||||
if (get<0>(prototype[0]).type != TypeType::Void) {
|
||||
throw ControlError(ErrorType::ControlReachesEndOfNonVoidFn, identifierTok.pos);
|
||||
for (size_t i = 1; i < prototype.size(); i++) {
|
||||
ArgDefinition argDef = prototype[i];
|
||||
Type argType = get<0>(argDef);
|
||||
string argName = get<1>(argDef);
|
||||
memory.declare(argName, argType);
|
||||
memory.update(argName, cast_from_type(argType, argValues[i - 1]));
|
||||
}
|
||||
}
|
||||
catch (const ReturnException& e) {
|
||||
res = e.val;
|
||||
}
|
||||
|
||||
memory.remove_scope();
|
||||
try {
|
||||
eval(get<0>(get<UserFunction>(fn)), memory);
|
||||
|
||||
// Tmp: no flow control
|
||||
if (get<0>(prototype[0]).type != TypeType::Void) {
|
||||
throw ControlError(ErrorType::ControlReachesEndOfNonVoidFn, identifierTok.pos);
|
||||
}
|
||||
}
|
||||
catch (const ReturnException& e) {
|
||||
res = e.val;
|
||||
}
|
||||
|
||||
memory.remove_scope();
|
||||
}
|
||||
catch (...) {
|
||||
memory.remove_scope();
|
||||
|
||||
exception_ptr e = current_exception();
|
||||
if (e) rethrow_exception(e);
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
memory.remove_scope();
|
||||
|
||||
exception_ptr e = current_exception();
|
||||
if (e) rethrow_exception(e);
|
||||
else {
|
||||
memory._debug_clear();
|
||||
}
|
||||
|
||||
return cast_from_type(get<0>(prototype[0]), res);
|
||||
|
@ -5,16 +5,47 @@
|
||||
using namespace std;
|
||||
|
||||
Memory::Memory(void) {
|
||||
scopes.emplace_back();
|
||||
scopes.back().depth = 0;
|
||||
make_global_scope();
|
||||
}
|
||||
|
||||
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) {
|
||||
for (auto rit = scopes.rbegin(); rit != scopes.rend(); ++rit) {
|
||||
Scope& scope = *rit;
|
||||
if (scope.vars.contains(identifier)) return true;
|
||||
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;
|
||||
break;
|
||||
}
|
||||
@ -46,7 +77,7 @@ MemoryVar& Memory::get(string identifier) {
|
||||
Scope& scope = *rit;
|
||||
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));
|
||||
Closure closure = std::get<1>(std::get<UserFunction>(std::get<Function>(scope.fn->value)));
|
||||
if (closure.contains(identifier)) return closure.at(identifier);
|
||||
break;
|
||||
}
|
||||
@ -80,7 +111,7 @@ void Memory::update(string identifier, EvalResult value) {
|
||||
return;
|
||||
}
|
||||
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)) {
|
||||
MemoryVar& var = closure.at(identifier);
|
||||
var.value = value;
|
||||
@ -123,6 +154,11 @@ StackTrace Memory::get_trace(CodePosition pos) {
|
||||
return trace;
|
||||
}
|
||||
|
||||
void Memory::_debug_clear(void) {
|
||||
scopes.clear();
|
||||
make_global_scope();
|
||||
}
|
||||
|
||||
Scope& Memory::_debug_top(void) {
|
||||
Scope& top = scopes.back();
|
||||
return top;
|
||||
|
Loading…
Reference in New Issue
Block a user