1
0
Fork 0
forked from fun/fun

Built-ins: Maps and more... ;)

This commit is contained in:
Johannes Findeisen 2025-09-15 04:41:11 +02:00
commit d1bbd2e501
9 changed files with 663 additions and 36 deletions

View file

@ -9,6 +9,14 @@ typedef struct Array {
Value *items; /* owns items; each item owned by array */
} Array;
typedef struct Map {
int refcount;
int count;
int cap;
char **keys; /* each key owned here */
Value *vals; /* each value owned here */
} Map;
Value make_int(int64_t v) {
Value val;
val.type = VAL_INT;
@ -37,6 +45,100 @@ Value make_nil(void) {
return v;
}
Value make_map_empty(void) {
Map *m = (Map*)malloc(sizeof(Map));
if (!m) return make_nil();
m->refcount = 1;
m->count = 0;
m->cap = 0;
m->keys = NULL;
m->vals = NULL;
Value v;
v.type = VAL_MAP;
v.map = (struct Map*)m;
return v;
}
static int map_ensure_cap(Map *m, int need) {
if (m->cap >= need) return 1;
int ncap = m->cap == 0 ? 4 : m->cap * 2;
while (ncap < need) ncap *= 2;
char **nkeys = (char**)realloc(m->keys, sizeof(char*) * ncap);
Value *nvals = (Value*)realloc(m->vals, sizeof(Value) * ncap);
if (!nkeys || !nvals) return 0;
m->keys = nkeys;
m->vals = nvals;
m->cap = ncap;
return 1;
}
int map_set(Value *vm, const char *key, Value v) {
if (!vm || vm->type != VAL_MAP || !vm->map || !key) { free_value(v); return 0; }
Map *m = (Map*)vm->map;
/* replace if exists */
for (int i = 0; i < m->count; ++i) {
if (strcmp(m->keys[i], key) == 0) {
free_value(m->vals[i]);
m->vals[i] = v;
return 1;
}
}
if (!map_ensure_cap(m, m->count + 1)) { free_value(v); return 0; }
m->keys[m->count] = strdup(key);
m->vals[m->count] = v;
m->count++;
return 1;
}
int map_get_copy(const Value *vm, const char *key, Value *out) {
if (!vm || vm->type != VAL_MAP || !vm->map || !key) return 0;
Map *m = (Map*)vm->map;
for (int i = 0; i < m->count; ++i) {
if (strcmp(m->keys[i], key) == 0) {
if (out) *out = copy_value(&m->vals[i]);
return 1;
}
}
return 0;
}
int map_has(const Value *vm, const char *key) {
if (!vm || vm->type != VAL_MAP || !vm->map || !key) return 0;
Map *m = (Map*)vm->map;
for (int i = 0; i < m->count; ++i) {
if (strcmp(m->keys[i], key) == 0) return 1;
}
return 0;
}
Value map_keys_array(const Value *vm) {
if (!vm || vm->type != VAL_MAP || !vm->map) return make_array_from_values(NULL, 0);
Map *m = (Map*)vm->map;
if (m->count <= 0) return make_array_from_values(NULL, 0);
Value *tmp = (Value*)malloc(sizeof(Value) * m->count);
for (int i = 0; i < m->count; ++i) {
tmp[i] = make_string(m->keys[i]);
}
Value arr = make_array_from_values(tmp, m->count);
for (int i = 0; i < m->count; ++i) free_value(tmp[i]);
free(tmp);
return arr;
}
Value map_values_array(const Value *vm) {
if (!vm || vm->type != VAL_MAP || !vm->map) return make_array_from_values(NULL, 0);
Map *m = (Map*)vm->map;
if (m->count <= 0) return make_array_from_values(NULL, 0);
Value *tmp = (Value*)malloc(sizeof(Value) * m->count);
for (int i = 0; i < m->count; ++i) {
tmp[i] = copy_value(&m->vals[i]);
}
Value arr = make_array_from_values(tmp, m->count);
for (int i = 0; i < m->count; ++i) free_value(tmp[i]);
free(tmp);
return arr;
}
Value make_array_from_values(const Value *vals, int count) {
if (count < 0) count = 0;
Array *arr = (Array*)malloc(sizeof(Array));
@ -212,6 +314,12 @@ Value copy_value(const Value *v) {
if (a) a->refcount++;
break;
}
case VAL_MAP: {
Map *m = (Map*)v->map;
out.map = (struct Map*)m;
if (m) m->refcount++;
break;
}
case VAL_NIL:
default:
break;
@ -240,13 +348,22 @@ Value deep_copy_value(const Value *v) {
tmp[i] = deep_copy_value(&a->items[i]);
}
Value out = make_array_from_values(tmp, a->count);
/* free temporaries (we created new deep copies already moved into out) */
for (int i = 0; i < a->count; ++i) {
free_value(tmp[i]);
}
free(tmp);
return out;
}
case VAL_MAP: {
const Map *m = (const Map*)v->map;
if (!m || m->count <= 0) return make_map_empty();
Value out = make_map_empty();
for (int i = 0; i < m->count; ++i) {
Value dv = deep_copy_value(&m->vals[i]);
map_set(&out, m->keys[i], dv);
}
return out;
}
case VAL_NIL:
default:
return make_nil();
@ -265,6 +382,17 @@ void free_value(Value v) {
free(a->items);
free(a);
}
} else if (v.type == VAL_MAP && v.map) {
Map *m = (Map*)v.map;
if (--m->refcount == 0) {
for (int i = 0; i < m->count; ++i) {
if (m->keys[i]) free(m->keys[i]);
free_value(m->vals[i]);
}
free(m->keys);
free(m->vals);
free(m);
}
}
/* VAL_FUNCTION: we *do not* free the Bytecode here (caller frees it) */
}
@ -292,6 +420,19 @@ void print_value(const Value *v) {
printf("]");
break;
}
case VAL_MAP: {
const Map *m = (const Map*)v->map;
printf("{");
if (m) {
for (int i = 0; i < m->count; ++i) {
if (i > 0) printf(", ");
printf("\"%s\": ", m->keys[i] ? m->keys[i] : "");
print_value(&m->vals[i]);
}
}
printf("}");
break;
}
case VAL_NIL:
default:
printf("nil");