Add standard functions

This commit is contained in:
ala89 2024-01-05 19:05:44 +01:00
parent 0a1a288df6
commit bba2e812c4
5 changed files with 92 additions and 39 deletions

View File

@ -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);

View File

@ -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;
};

View File

@ -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>;

View File

@ -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);

View File

@ -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;