diff options
Diffstat (limited to 'src/object.c')
-rw-r--r-- | src/object.c | 195 |
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); +} |