#include #include "apfl.h" #include "internal.h" /** * Decrease a refererence count. Returns true, if the object should be freed. */ static bool dec_refcount(unsigned *rc) { if (rc == 0) { return false; } return --(*rc) == 0; } static void print(unsigned indent, FILE *out, struct apfl_value value) { switch (value.type) { case APFL_VALUE_NIL: apfl_print_indented(indent, out, "nil\n"); return; case APFL_VALUE_BOOLEAN: apfl_print_indented(indent, out, value.boolean ? "true\n" : "false\n"); return; case APFL_VALUE_NUMBER: apfl_print_indented(indent, out, "%f\n", value.number); return; case APFL_VALUE_STRING: apfl_print_indented(indent, out, "\"" APFL_STR_FMT "\"\n", APFL_STR_FMT_ARGS(value.string)); return; case APFL_VALUE_LIST: apfl_print_indented(indent, out, "[\n"); for (size_t i = 0; i < value.list->len; i++) { print(indent+1, out, value.list->items[i]); } apfl_print_indented(indent, out, "]\n"); return; } fprintf(out, "Unknown value? (%d)\n", (int)value.type); } bool apfl_value_copy(struct apfl_value *dst, struct apfl_value src) { struct apfl_string string; *dst = src; switch (src.type) { case APFL_VALUE_NIL: case APFL_VALUE_BOOLEAN: case APFL_VALUE_NUMBER: // Nothing to do goto ok; case APFL_VALUE_STRING: string = apfl_string_blank(); if (!apfl_string_copy(&string, apfl_string_view_from(src.string))) { return false; } dst->string = string; goto ok; case APFL_VALUE_LIST: assert(src.list != NULL); assert(dst->list == src.list); src.list->refcount++; goto ok; } assert(false); ok: return true; } void apfl_value_print(struct apfl_value value, FILE *out) { print(0, out, value); } struct apfl_list * apfl_list_new(void) { struct apfl_list *list = ALLOC(struct apfl_list); if (list == NULL) { return NULL; } *list = (struct apfl_list) { .refcount = 1, .items = NULL, .len = 0, .cap = 0, }; return list; } void apfl_list_deinit(struct apfl_list *list) { DEINIT_LIST(list->items, list->len, apfl_value_deinit); list->refcount = 0; list->cap = 0; } void apfl_value_deinit(struct apfl_value *value) { switch (value->type) { case APFL_VALUE_NIL: case APFL_VALUE_BOOLEAN: case APFL_VALUE_NUMBER: goto ok; case APFL_VALUE_STRING: apfl_string_deinit(&value->string); goto ok; case APFL_VALUE_LIST: if (dec_refcount(&value->list->refcount)) { DESTROY(value->list, apfl_list_deinit); } goto ok; } assert(false); ok: value->type = APFL_VALUE_NIL; }