Implemented closures
authorDavid Kerkeslager <kerkeslager@gmail.com>
Tue, 1 Oct 2019 19:31:13 +0000 (15:31 -0400)
committerDavid Kerkeslager <kerkeslager@gmail.com>
Tue, 1 Oct 2019 19:31:13 +0000 (15:31 -0400)
templates/environment.c
templates/program2.c

index 2de6b59..483e38a 100644 (file)
@@ -7,6 +7,8 @@ struct _EnvironmentNode {
 };
 
 struct Environment {
+  size_t referenceCount;
+  Environment* shadowed;
   _EnvironmentNode* top;
 };
 
@@ -17,11 +19,15 @@ struct Environment_get_Result {
   Object result;
 };
 
-void Environment_initialize(Environment* self) {
+void Environment_initialize(Environment* self, Environment* shadowed) {
+  self->referenceCount = 1;
+  self->shadowed = shadowed;
   self->top = NULL;
 }
 
 void Environment_deinitialize(Environment* self) {
+  assert(self->referenceCount == 0);
+
   while(self->top != NULL) {
     _EnvironmentNode* en = self->top;
     self->top = en->next;
@@ -30,18 +36,26 @@ void Environment_deinitialize(Environment* self) {
   }
 }
 
-Environment* Environment_construct() {
+Environment* Environment_construct(Environment* shadowed) {
   Environment* result = malloc(sizeof(Environment));
-  Environment_initialize(result);
+  Environment_initialize(result, shadowed);
   return result;
 }
 
+Environment* Environment_reference(Environment* self) {
+  self->referenceCount++; // TODO Do we need to make this thread safe?
+  return self;
+}
+
 void Environment_destruct(Environment* self) {
-  Environment_deinitialize(self);
-  free(self);
+  self->referenceCount--; // TODO Do we need to make this thread safe?
+  if(self->referenceCount == 0) {
+    Environment_deinitialize(self);
+    free(self);
+  }
 }
 
-Environment_get_Result Environment_get(Environment* self, char* symbol) {
+Environment_get_Result Environment_getShallow(Environment* self, char* symbol) {
   for(_EnvironmentNode* current = self->top; current != NULL; current = current->next) {
     if(strcmp(current->symbol, symbol) == 0) {
       return (Environment_get_Result) { true, current->value };
@@ -50,8 +64,16 @@ Environment_get_Result Environment_get(Environment* self, char* symbol) {
   return (Environment_get_Result) { false, BUILTIN_NIL };
 }
 
+Environment_get_Result Environment_get(Environment* self, char* symbol) {
+  for(; self != NULL; self = self->shadowed) {
+    Environment_get_Result result = Environment_getShallow(self, symbol);
+    if(result.found) return result;
+  }
+  return (Environment_get_Result) { false, BUILTIN_NIL };
+}
+
 void Environment_set(Environment* self, char* symbol, Object value) {
-  assert(!(Environment_get(self, symbol).found));
+  assert(!(Environment_getShallow(self, symbol).found));
 
   _EnvironmentNode* en = malloc(sizeof(_EnvironmentNode));
   en->symbol = symbol;
index f307b85..5ca9f61 100644 (file)
@@ -23,8 +23,12 @@ enum Builtin {
   PRINT
 };
 
+struct Object;
+typedef struct Object Object;
 struct Environment;
 typedef struct Environment Environment;
+struct Thread;
+typedef struct Thread Thread;
 
 struct Closure;
 typedef struct Closure Closure;
@@ -43,8 +47,6 @@ union Value {
   int32_t integer;
 };
 
-struct Object;
-typedef struct Object Object;
 struct Object {
   Type type;
   Value value;
@@ -59,39 +61,35 @@ void Object_deinitialize(Object* self) {
 {% include "stack.c" %}
 {% include "frame.c" %}
 
-struct Thread;
-typedef struct Thread Thread;
 struct Thread {
-  Environment* environment;
+  Frame frame;
   Stack stack;
-  size_t programCounter;
 };
 
 void Thread_initialize(Thread* self, size_t programCounter) {
-  self->environment = Environment_construct();
+  Frame_initialize(&(self->frame), Environment_construct(NULL), NULL, programCounter);
   Stack_initialize(&(self->stack));
-  self->programCounter = programCounter;
 }
 
 void Thread_deinitialize(Thread* self) {
-  Environment_destruct(self->environment);
+  Frame_deinitialize(&(self->frame));
   Stack_deinitialize(&(self->stack));
 }
 
 Environment* Thread_getEnvironment(Thread* self) {
-  return self->environment;
+  return self->frame.environment;
 }
 
 void Thread_setProgramCounter(Thread* self, size_t programCounter) {
-  self->programCounter = programCounter;
+  self->frame.programCounter = programCounter;
 }
 
 void Thread_incrementProgramCounter(Thread* self) {
-  self->programCounter++;
+  self->frame.programCounter++;
 }
 
 size_t Thread_getProgramCounter(Thread* self) {
-  return self->programCounter;
+  return self->frame.programCounter;
 }
 
 union Argument;
@@ -179,7 +177,14 @@ void callBuiltin(Thread* thread, Builtin b, size_t argumentCount) {
 void callClosure(Thread* thread, Closure closure, size_t argumentCount) {
   assert(argumentCount == 0);
 
-
+  Frame* returnFrame = malloc(sizeof(Frame));
+  *returnFrame = thread->frame;
+  Frame_initialize(
+    &(thread->frame),
+    Environment_construct(Environment_reference(closure.environment)),
+    returnFrame,
+    closure.entry - 1 // We will increment the frame immediately after this
+  );
 }
 
 void inst_call(Thread* thread, Argument argument) {
@@ -350,7 +355,18 @@ void inst_push_string(Thread* thread, Argument argument) {
 {% endwith %}
 
 void inst_return(Thread* thread, Argument argument) {
-  assert(false);
+  Frame* returnFrame = thread->frame.returnFrame;
+
+  Frame_deinitialize(&(thread->frame));
+
+  Frame_initialize(
+    &(thread->frame),
+    returnFrame->environment,
+    returnFrame->returnFrame,
+    returnFrame->programCounter
+  );
+
+  free(returnFrame);
 }
 
 struct Instruction;