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

View File

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

View File

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

View File

@ -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,45 +189,51 @@ 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 = {};
memory.add_scope(ScopeType::Function, &var, identifierTok.pos); if (holds_alternative<UserFunction>(fn)) {
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]));
}
try { try {
eval(get<0>(get<Function>(var.value)), memory); for (size_t i = 1; i < prototype.size(); i++) {
ArgDefinition argDef = prototype[i];
// Tmp: no flow control Type argType = get<0>(argDef);
if (get<0>(prototype[0]).type != TypeType::Void) { string argName = get<1>(argDef);
throw ControlError(ErrorType::ControlReachesEndOfNonVoidFn, identifierTok.pos); 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 (...) { else {
memory.remove_scope(); memory._debug_clear();
exception_ptr e = current_exception();
if (e) rethrow_exception(e);
} }
return cast_from_type(get<0>(prototype[0]), res); return cast_from_type(get<0>(prototype[0]), res);

View File

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