aboutsummaryrefslogtreecommitdiff
path: root/src/object.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/object.c')
-rw-r--r--src/object.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/src/object.c b/src/object.c
new file mode 100644
index 0000000..d3f589d
--- /dev/null
+++ b/src/object.c
@@ -0,0 +1,195 @@
+#include "object.h"
+#include "ast.h"
+#include "hmap.h"
+#include "vector.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static const char *object_types[] = {
+ "error",
+ "null",
+ "int",
+ "bool",
+ "return",
+};
+
+static void
+environment_destroy_cb(const void *key, void *val)
+{
+ struct object *obj = val;
+ object_unref(obj);
+}
+
+static inline char *
+bool_sprint(bool val, char *str)
+{
+ sprintf(str, val ? "true" : "false");
+ return str;
+}
+
+extern inline const char *
+object_type_print(enum object_type type)
+{
+ return object_types[type];
+}
+
+static inline char *
+object_func_sprint(struct object *obj, char *str)
+{
+ char *cur = str;
+ sprintf(cur, "fn(");
+ cur += strlen(cur);
+ size_t i;
+ struct expression *ident;
+ vector_foreach(obj->func.params, i, ident) {
+ node_sprint(ident, cur);
+ cur += strlen(cur);
+ if (i < (obj->func.params->len - 1)) {
+ cur[0] = ',', cur[1] = ' ', cur += 2;
+ }
+ }
+ sprintf(cur, ") {\n");
+ cur += strlen(cur);
+ node_sprint(obj->func.body, cur);
+ cur += strlen(cur);
+ sprintf(cur, "\n}");
+
+ return str;
+}
+
+char *
+object_sprint(struct object *obj, char *str)
+{
+ switch (obj->type) {
+ case OBJECT_NULL:
+ sprintf(str, "null");
+ break;
+ case OBJECT_BOOL:
+ return bool_sprint(obj->boolean, str);
+ case OBJECT_INT:
+ sprintf(str, "%ld", obj->integer);
+ break;
+ case OBJECT_RETURN:
+ object_sprint(obj->retrn.value, str);
+ case OBJECT_ERROR:
+ strcpy(str, obj->error.msg);
+ case OBJECT_FUNC:
+ return object_func_sprint(obj, str);
+ }
+ return str;
+}
+
+struct object *
+object_new_int(int64_t val)
+{
+ struct object *obj = malloc(sizeof(*obj));
+ obj->type = OBJECT_INT;
+ obj->refcount = 1;
+ obj->integer = val;
+ return obj;
+}
+
+struct object *
+object_new_error(char *msg)
+{
+ struct object *obj = malloc(sizeof(*obj));
+ obj->type = OBJECT_ERROR;
+ obj->refcount = 1;
+ obj->error.msg = msg;
+ return obj;
+}
+
+struct object *
+object_new_return(struct object *val)
+{
+ struct object *obj = malloc(sizeof(*obj));
+ obj->type = OBJECT_RETURN;
+ obj->refcount = 1;
+ obj->retrn.value = val;
+ return obj;
+}
+
+struct object *
+object_new_func(struct expression *expr)
+{
+ struct object *obj = malloc(sizeof(*obj));
+ obj->type = OBJECT_FUNC;
+ obj->refcount = 1;
+ obj->func.body = node_dup(expr->func.body);
+ obj->func.params = expression_vector_dup(expr->func.parameters);
+ return obj;
+}
+
+void
+object_ref(struct object *obj)
+{
+ obj->refcount++;
+}
+
+void
+object_unref(struct object *obj)
+{
+ if (obj->type == OBJECT_NULL || obj->type == OBJECT_BOOL) return;
+ if (--obj->refcount < 1) {
+ switch (obj->type) {
+ case OBJECT_RETURN:
+ object_unref(obj->retrn.value);
+ break;
+ case OBJECT_ERROR:
+ free(obj->error.msg);
+ break;
+ case OBJECT_FUNC:
+ node_destroy(obj->func.body);
+ size_t i;
+ struct expression *param;
+ vector_foreach(obj->func.params, i, param) {
+ node_destroy(param);
+ }
+ vector_free(obj->func.params);
+ break;
+ default:
+ break;
+ }
+ free(obj);
+ }
+}
+
+struct environment *
+environment_new_enclosed(struct environment *outer)
+{
+ struct environment *env = malloc(sizeof(*env));
+ env->store = hmap_new();
+ if (!env->store) {
+ free(env);
+ return NULL;
+ }
+ env->outer = outer;
+
+ return env;
+}
+
+struct object *
+environment_set(struct environment *env, struct slice key, struct object *val)
+{
+ object_ref(val);
+ return hmap_sets(env->store, key, val);
+}
+
+struct object *
+environment_get(struct environment *env, const struct slice *key)
+{
+ struct object *obj = hmap_gets(env->store, key);
+ if (!obj && env->outer) {
+ obj = environment_get(env->outer, key);
+ }
+ return obj;
+}
+
+void
+environment_destroy(struct environment *env)
+{
+ hmap_destroy(env->store, environment_destroy_cb);
+ free(env);
+}