summaryrefslogtreecommitdiff
path: root/uscript/val.c
diff options
context:
space:
mode:
Diffstat (limited to 'uscript/val.c')
-rw-r--r--uscript/val.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/uscript/val.c b/uscript/val.c
new file mode 100644
index 0000000..d713645
--- /dev/null
+++ b/uscript/val.c
@@ -0,0 +1,204 @@
+#include "val.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "dyn_arr.h"
+#include "vm.h"
+
+#define STR_NUM_FMT "%g"
+#define STR_FUNC_FMT "<func %s: %p>"
+
+static
+void init_obj(struct us_val val, struct us_obj *obj)
+{
+ (void)obj; // nothing to init yet
+ da_append(struct us_val, &vm.objs, val);
+}
+
+struct us_str *take_str(char *chars, int len)
+{
+ if (len < 0)
+ len = strlen(chars);
+ struct us_str *str = mem_alloc(sizeof(struct us_str));
+ str->chars = chars;
+ str->len = len;
+ init_obj(wrap_str(str), &str->header);
+ return str;
+}
+
+struct us_str *copy_str(const char *chars, int len)
+{
+ if (len < 0)
+ len = strlen(chars);
+ char *copy = mem_alloc(len + 1);
+ memcpy(copy, chars, len);
+ copy[len] = '\0';
+ return take_str(copy, len);
+}
+
+struct us_proto *create_proto(struct us_str *name)
+{
+ struct us_proto *proto = mem_alloc(sizeof(struct us_proto));
+ proto->name = name;
+ proto->bytecode = da_create(u8, 0);
+ proto->upvalc = 0;
+ proto->argc = 0;
+ proto->is_variadic = false;
+ proto->nconstants = 0;
+ init_obj(wrap_proto(proto), &proto->header);
+ return proto;
+}
+
+struct us_func *create_func(struct us_proto *proto)
+{
+ struct us_func *func = mem_alloc(sizeof(struct us_func));
+ func->proto = proto;
+ func->upvals = mem_alloc(sizeof(struct us_upval*) * proto->upvalc);
+ init_obj(wrap_func(func), &func->header);
+ return func;
+}
+
+struct us_upval *create_upval(struct us_val *val)
+{
+ struct us_upval *upval = mem_alloc(sizeof(struct us_upval));
+ upval->loc = val;
+ upval->closed = create_zilch();
+ upval->next = NULL;
+ init_obj(wrap_upval(upval), &upval->header);
+ return upval;
+}
+
+void free_val(struct us_val v)
+{
+ switch (v.type) {
+ case VAL_STR: {
+ struct us_str *str = get_str(v);
+ mem_free(str->chars);
+ mem_free(str);
+ break;
+ }
+ case VAL_PROTO: {
+ struct us_proto *proto = get_proto(v);
+ da_free(proto->bytecode);
+ mem_free(proto->upval_locs);
+ mem_free(proto);
+ break;
+ }
+ case VAL_FUNC: {
+ struct us_func *func = get_func(v);
+ mem_free(func->upvals);
+ mem_free(func);
+ break;
+ }
+ case VAL_UPVAL:
+ mem_free(get_obj(v));
+ break;
+ case VAL_NUM:
+ case VAL_BOOL:
+ case VAL_ZILCH:
+ break;
+ }
+}
+
+void proto_add_const(struct us_proto *proto, struct us_val v)
+{
+ proto->constants[proto->nconstants] = v;
+ proto_add_byte(proto, BC_LOAD);
+ proto_add_byte(proto, proto->nconstants++);
+}
+
+bool vals_eql(struct us_val a, struct us_val b)
+{
+ if (a.type != b.type)
+ return false;
+
+ switch (a.type) {
+ case VAL_NUM: return get_num(a) == get_num(b);
+ case VAL_BOOL: return get_bool(a) == get_bool(b);
+ case VAL_ZILCH: return true;
+ case VAL_STR: {
+ struct us_str *a_str = get_str(a);
+ struct us_str *b_str = get_str(b);
+ return a_str->len == b_str->len &&
+ memcmp(a_str->chars, b_str->chars, a_str->len) == 0;
+ }
+ case VAL_FUNC:
+ case VAL_UPVAL:
+ case VAL_PROTO: return get_obj(a) == get_obj(b);
+ }
+
+ // unreachable
+ return false;
+}
+
+char *val_to_str(struct us_val v, int *len_out)
+{
+ // TODO: have this function return a us_str so that we own the memory,
+ // and so concatenation of strings is faster.
+
+ switch (v.type) {
+ case VAL_NUM: {
+ int len = snprintf(NULL, 0, STR_NUM_FMT, get_num(v));
+ char *str = mem_alloc(sizeof(char) * (len + 1));
+ snprintf(str, len + 1, STR_NUM_FMT, get_num(v));
+ if (len_out)
+ *len_out = len;
+ return str;
+ }
+ case VAL_BOOL: {
+ const char *bool_str = get_bool(v) ? "true" : "false";
+ char *str = mem_alloc(strlen(bool_str) + 1);
+ strcpy(str, bool_str);
+ if (len_out)
+ *len_out = strlen(bool_str);
+ return str;
+ }
+ case VAL_ZILCH: {
+ const char *zilch_str = "zilch";
+ char *str = mem_alloc(strlen(zilch_str) + 1);
+ strcpy(str, zilch_str);
+ if (len_out)
+ *len_out = strlen(zilch_str);
+ return str;
+ }
+ case VAL_STR: {
+ const struct us_str *us_str = get_str(v);
+ char *str = mem_alloc(sizeof(char) * us_str->len + 1);
+ strncpy(str, us_str->chars, us_str->len);
+ str[us_str->len] = 0;
+ if (len_out)
+ *len_out = us_str->len;
+ return str;
+ }
+ case VAL_PROTO: {
+ const struct us_proto *proto = get_proto(v);
+ int len = snprintf(
+ NULL,
+ 0,
+ STR_FUNC_FMT,
+ proto->name->chars,
+ (void*)proto
+ );
+ char *str = mem_alloc(sizeof(char) * (len + 1));
+ snprintf(
+ str,
+ len + 1,
+ STR_FUNC_FMT,
+ proto->name->chars,
+ (void*)proto
+ );
+ if (len_out)
+ *len_out = len;
+ return str;
+ }
+ case VAL_FUNC:
+ return val_to_str(wrap_proto(get_func(v)->proto), len_out);
+ case VAL_UPVAL:
+ return val_to_str(*get_upval(v)->loc, len_out);
+ }
+
+ // unreachable
+ return NULL;
+}
+