Built-ins: Maps and more... ;)
This commit is contained in:
parent
a4f4fcba99
commit
d1bbd2e501
9 changed files with 663 additions and 36 deletions
143
src/value.c
143
src/value.c
|
|
@ -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");
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue