#include "val.h" #include #include #include "dyn_arr.h" #include "vm.h" #define STR_NUM_FMT "%g" #define STR_FUNC_FMT "" #define STR_ARR_FMT "" 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_arr *create_arr(void) { struct us_arr *arr = mem_alloc(sizeof(struct us_arr)); arr->e = da_create(struct us_val, 0); init_obj(wrap_arr(arr), &arr->header); return arr; } 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_ARR: { struct us_arr *arr = get_arr(v); da_free(arr->e); mem_free(arr); 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_ARR: 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_ARR: { const struct us_arr *arr = get_arr(v); int len = snprintf(NULL, 0, STR_ARR_FMT, (void*)arr); char *str = mem_alloc(sizeof(char) * (len + 1)); snprintf(str, len + 1, STR_ARR_FMT, (void*)arr); if (len_out) *len_out = 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; }