diff --git a/build.sh b/build.sh index 68d2457..0d66a63 100755 --- a/build.sh +++ b/build.sh @@ -36,6 +36,7 @@ mkdir temp/runtime gcc -c src/runtime/runtime_error.c -o temp/runtime/runtime_error.o $FLAGS gcc -c src/runtime/runtime.c -o temp/runtime/runtime.o $FLAGS gcc -c src/runtime/o_builtins.c -o temp/runtime/o_builtins.o $FLAGS +gcc -c src/runtime/o_closure.c -o temp/runtime/o_closure.o $FLAGS gcc -c src/runtime/o_nfunc.c -o temp/runtime/o_nfunc.o $FLAGS gcc -c src/runtime/o_func.c -o temp/runtime/o_func.o $FLAGS @@ -81,6 +82,7 @@ gcc src/main.c src/debug.c \ temp/runtime/runtime.o \ temp/runtime/runtime_error.o \ temp/runtime/o_builtins.o \ + temp/runtime/o_closure.o \ temp/runtime/o_nfunc.o \ temp/runtime/o_func.o \ temp/common/executable.o \ diff --git a/samples/deepfailure.noja b/samples/deepfailure.noja index 7178f7d..05e5701 100644 --- a/samples/deepfailure.noja +++ b/samples/deepfailure.noja @@ -11,14 +11,27 @@ fun fail(p) #fail(0); -fun a() +defined_globally = 111; + +fun A() { - fun b() + print('Hello from A!\n'); + + defined_in_A = 10; + + fun B() { - print(depth, '\n'); + defined_in_B = 33; + + print('Hello from B!\n'); + print('defined_globally = ', defined_globally, '\n'); + print('defined_in_A = ', defined_in_A, '\n'); + print('defined_in_B = ', defined_in_B, '\n'); } - b(); + B(); + + print('defined_in_B = ', defined_in_B, '\n'); } -a(); \ No newline at end of file +A(); \ No newline at end of file diff --git a/src/main.c b/src/main.c index 29903c2..6891691 100644 --- a/src/main.c +++ b/src/main.c @@ -233,7 +233,7 @@ int main(int argc, char **argv) Runtime_SetBuiltins(runtime, builtins); - Object *result = run(runtime, (Error*) &error, exe, 0, NULL, 1, NULL, 0); + Object *result = run(runtime, (Error*) &error, exe, 0, NULL, NULL, 0); if(result == NULL) { diff --git a/src/runtime/o_closure.c b/src/runtime/o_closure.c new file mode 100644 index 0000000..71c1394 --- /dev/null +++ b/src/runtime/o_closure.c @@ -0,0 +1,57 @@ +#include "../utils/defs.h" +#include "../objects/objects.h" + +typedef struct ClosureObject ClosureObject; + +struct ClosureObject { + Object base; + ClosureObject *prev; + Object *vars; +}; + +static Object *select(Object *self, Object *key, Heap *heap, Error *err); + +static const Type t_closure = { + .base = (Object) { .type = &t_type, .flags = Object_STATIC }, + .name = "closure", + .size = sizeof(ClosureObject), + .select = select, +}; + +Object *Object_NewClosure(Object *parent, Object *new_map, Heap *heap, Error *error) +{ + ClosureObject *obj = (ClosureObject*) Heap_Malloc(heap, &t_closure, error); + + if(obj == NULL) + return NULL; + + if(parent != NULL && parent->type != &t_closure) + { + Error_Report(error, 0, "Object is not a closure"); + return NULL; + } + + obj->prev = (ClosureObject*) parent; + obj->vars = new_map; + + return (Object*) obj; +} + +static Object *select(Object *self, Object *key, Heap *heap, Error *err) +{ + ClosureObject *closure = (ClosureObject*) self; + + Object *selected = NULL; + + while(closure != NULL && selected == NULL) + { + selected = Object_Select(closure->vars, key, heap, err); + + if(err->occurred) + return NULL; + + closure = closure->prev; + } + + return selected; +} \ No newline at end of file diff --git a/src/runtime/o_func.c b/src/runtime/o_func.c index 5c58cc9..b1983d1 100644 --- a/src/runtime/o_func.c +++ b/src/runtime/o_func.c @@ -9,7 +9,7 @@ typedef struct { Runtime *runtime; Executable *exe; int index, argc; - Object *globals; + Object *closure; } FunctionObject; static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, Error *error); @@ -74,7 +74,7 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, // The right amount of arguments was provided. argv2 = argv; - Object *result = run(func->runtime, error, func->exe, func->index, func->globals, 0, argv2, expected_argc); + Object *result = run(func->runtime, error, func->exe, func->index, func->closure, argv2, expected_argc); if(argv2 != argv) free(argv2); @@ -82,7 +82,7 @@ static Object *call(Object *self, Object **argv, unsigned int argc, Heap *heap, return result; } -Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, int argc, Object *globals, Heap *heap, Error *error) +Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, int argc, Object *closure, Heap *heap, Error *error) { assert(runtime != NULL); assert(exe != NULL); @@ -108,7 +108,7 @@ Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, in func->exe = exe_copy; func->index = index; func->argc = argc; - func->globals = globals; + func->closure = closure; return (Object*) func; } \ No newline at end of file diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c index 19881b8..6297517 100644 --- a/src/runtime/runtime.c +++ b/src/runtime/runtime.c @@ -7,11 +7,10 @@ #define MAX_FRAMES 16 typedef struct Frame Frame; - struct Frame { Frame *prev; Object *locals; - Object *globals; + Object *closure; Executable *exe; int index, used; }; @@ -838,7 +837,7 @@ static _Bool step(Runtime *runtime, Error *error) Object *locations[] = { runtime->frame->locals, - runtime->frame->globals, + runtime->frame->closure, Runtime_GetBuiltins(runtime), }; @@ -914,7 +913,12 @@ static _Bool step(Runtime *runtime, Error *error) assert(ops[0].type == OPTP_INT); assert(ops[1].type == OPTP_INT); - Object *obj = Object_FromNojaFunction(runtime, runtime->frame->exe, ops[0].as_int, ops[1].as_int, runtime->frame->globals, runtime->heap, error); + Object *closure = Object_NewClosure(runtime->frame->closure, runtime->frame->locals, Runtime_GetHeap(runtime), error); + + if(closure == NULL) + return 0; + + Object *obj = Object_FromNojaFunction(runtime, runtime->frame->exe, ops[0].as_int, ops[1].as_int, closure, runtime->heap, error); if(obj == NULL) return 0; @@ -1035,7 +1039,7 @@ static _Bool step(Runtime *runtime, Error *error) return 1; } -Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *globals, _Bool is_global_scope, Object **argv, int argc) +Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *closure, Object **argv, int argc) { assert(runtime != NULL); assert(error != NULL); @@ -1055,28 +1059,15 @@ Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object * Frame frame; { frame.prev = NULL; - - if(is_global_scope) - { - if(globals == NULL) - globals = Object_NewMap(-1, runtime->heap, error); - - frame.globals = globals; - frame.locals = frame.globals; - } - else - { - frame.globals = globals; - frame.locals = Object_NewMap(-1, runtime->heap, error); - } - - if(frame.locals == NULL) - return NULL; - + frame.closure = closure; + frame.locals = Object_NewMap(-1, runtime->heap, error); frame.exe = Executable_Copy(exe); frame.index = index; frame.used = 0; + if(frame.locals == NULL) + return NULL; + if(frame.exe == NULL) { Error_Report(error, 1, "Failed to copy executable"); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index 3970934..ca5cda5 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -23,9 +23,10 @@ Snapshot *Snapshot_New(Runtime *runtime); void Snapshot_Free(Snapshot *snapshot); void Snapshot_Print(Snapshot *snapshot, FILE *fp); -Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *globals, _Bool is_global_scope, Object **argv, int argc); +Object *run(Runtime *runtime, Error *error, Executable *exe, int index, Object *closure, Object **argv, int argc); +Object *Object_NewClosure(Object *parent, Object *new_map, Heap *heap, Error *error); Object *Object_NewBuiltinsMap(Runtime *runtime, Heap *heap, Error *err); Object* Object_FromNativeFunction(Runtime *runtime, Object *(*callback)(Runtime*, Object**, unsigned int, Error*), int argc, Heap *heap, Error *error); -Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, int argc, Object *globals, Heap *heap, Error *error); +Object *Object_FromNojaFunction(Runtime *runtime, Executable *exe, int index, int argc, Object *closure, Heap *heap, Error *error); #endif \ No newline at end of file