// this is the fn parameter passed into file_list() int file_list_callback(const char *path, bool dir, long mod, void *fl_context) { // -> / path = remove_substring(path, "//"); //printf("file_list_callback %s\n", path); size_t size = file_size(path); path = remove_substring(path, hal_doc_path(NULL)); struct file_list_context *flc = (struct file_list_context*)fl_context; struct variable *path3 = variable_new_str_chars(flc->context, path); struct variable *key2 = variable_new_str_chars(flc->context, RESERVED_DIR); struct variable *value = variable_new_bool(flc->context, dir); struct variable *metadata = variable_new_list(flc->context, NULL); variable_map_insert(flc->context, metadata, key2, value); key2 = variable_new_str_chars(flc->context, RESERVED_MODIFIED); value = variable_new_int(flc->context, (int32_t)mod); variable_map_insert(flc->context, metadata, key2, value); variable_map_insert(flc->context, flc->result, path3, metadata); key2 = variable_new_str_chars(flc->context, RESERVED_SIZE); value = variable_new_int(flc->context, (int32_t)size); variable_map_insert(flc->context, metadata, key2, value); variable_map_insert(flc->context, flc->result, path3, metadata); return 0; }
// FOR who IN what WHERE where DO how static bool iterate(struct context *context, enum Opcode op, struct program_state *state, struct byte_array *program) { struct byte_array *who = serial_decode_string(program); struct byte_array *where = serial_decode_string(program); struct byte_array *how = serial_decode_string(program); #ifdef DEBUG DEBUGPRINT("%s %s\n", NUM_TO_STRING(opcodes, op), byte_array_to_string(who)); if (!context->runtime) { if (where && where->length) { DEBUGPRINT("%s\tWHERE\n", indentation(context)); display_code(context, where); } DEBUGPRINT("%s\tDO\n", indentation(context)); display_code(context, how); return false; } #endif bool comprehending = (op == VM_COM); struct variable *result = comprehending ? variable_new_list(context, NULL) : NULL; struct variable *what = variable_pop(context); uint32_t len = variable_length(context, what); for (int i=0; i<len; i++) { struct variable *that = list_get_int(context, what, i); set_named_variable(context, state, who, that); byte_array_reset(where); byte_array_reset(how); if (where && where->length) run(context, where, NULL, true); if (!where || !where->length || test_operand(context)) { if (run(context, how, NULL, true)) // true if run hit VM_RET return true; if (comprehending) { struct variable *item = (struct variable*)stack_pop(context->operand_stack); array_add(result->list, item); } } } if (comprehending) stack_push(context->operand_stack, result); return false; }
struct variable *sys_file_list(struct context *context) { struct variable *arguments = (struct variable*)stack_pop(context->operand_stack); struct variable *path = array_get(arguments->list.ordered, 1); const char *path2 = hal_doc_path(path->str); struct variable *result = variable_new_list(context, NULL); struct file_list_context flc = {context, result}; file_list(path2, &file_list_callback, &flc); return flc.result; }
struct variable *sys_new(struct context *context) { struct variable *sys = variable_new_list(context, NULL); for (int i=0; i<ARRAY_LEN(builtin_funcs); i++) { struct variable *key = variable_new_str_chars(context, builtin_funcs[i].name); struct variable *value = variable_new_cfnc(context, builtin_funcs[i].func); variable_map_insert(context, sys, key, value); } return sys; }
struct variable *variable_map_list(struct context *context, struct variable *indexable, struct array* (*map_list)(const struct map*)) { assert_message(indexable->type == VAR_LST, "values are only for list"); struct variable *result = variable_new_list(context, NULL); if (NULL != indexable->list.map) { struct array *a = map_list(indexable->list.map); for (int i=0; i<a->length; i++) { struct variable *u = variable_copy(context, (struct variable*)array_get(a, i)); array_add(result->list.ordered, u); } array_del(a); } return result; }
static inline struct variable *cfnc_insert(struct context *context) // todo: test { struct variable *args = (struct variable*)stack_pop(context->operand_stack); struct variable *self = (struct variable*)array_get(args->list.ordered, 0); struct variable *insertion = (struct variable*)array_get(args->list.ordered, 1); struct variable *start = args->list.ordered->length > 2 ? (struct variable*)array_get(args->list.ordered, 2) : NULL; null_check(self); null_check(insertion); assert_message(!start || start->type == VAR_INT, "non-integer index"); int32_t position = 0; switch (self->type) { case VAR_LST: { struct array *list = array_new_size(1); array_set(list, 0, insertion); insertion = variable_new_list(context, list); position = self->list.ordered->length; array_del(list); } break; case VAR_STR: assert_message(insertion->type == VAR_STR, "insertion doesn't match destination"); position = self->str->length; break; default: exit_message("bad insertion destination"); break; } struct variable *first = variable_part(context, variable_copy(context, self), 0, position); struct variable *second = variable_part(context, variable_copy(context, self), position, -1); struct variable *joined = variable_concatenate(context, 3, first, insertion, second); if (self->type == VAR_LST) { array_del(self->list.ordered); self->list.ordered = array_copy(joined->list.ordered); } else { byte_array_del(self->str); self->str = byte_array_copy(joined->str); } return joined; }
static void push_list(struct context *context, struct byte_array *program) { int32_t num_items = serial_decode_int(program); DEBUGPRINT("LST %d", num_items); if (!context->runtime) VM_DEBUGPRINT("\n"); struct array *items = array_new(); struct map *map = NULL; while (num_items--) { struct variable* v = variable_pop(context); if (v->type == VAR_MAP) { if (!map) map = map_new(context, NULL); map_update(map, v->map); // mapped values are stored in the map, not list } else array_insert(items, 0, v); } struct variable *list = variable_new_list(context, items); list->map = map; DEBUGPRINT(": %s\n", variable_value_str(context, list)); variable_push(context, list); }
struct variable *builtin_method(struct context *context, struct variable *indexable, const struct variable *index) { enum VarType it = indexable->type; char *idxstr = byte_array_to_string(index->str); struct variable *result = NULL; if (!strcmp(idxstr, FNC_LENGTH)) { int n; switch (indexable->type) { case VAR_LST: n = indexable->list.ordered->length; break; case VAR_STR: n = indexable->str->length; break; case VAR_NIL: n = 0; break; default: free(idxstr); exit_message("no length for non-indexable"); return NULL; } result = variable_new_int(context, n); } else if (!strcmp(idxstr, FNC_TYPE)) { const char *typestr = var_type_str(it); result = variable_new_str_chars(context, typestr); } else if (!strcmp(idxstr, FNC_STRING)) { switch (indexable->type) { case VAR_STR: case VAR_BYT: case VAR_FNC: result = variable_copy(context, indexable); break; default: { struct byte_array *vv = variable_value(context, indexable); result = variable_new_str(context, vv); byte_array_del(vv); break; } } } else if (!strcmp(idxstr, FNC_LIST)) result = variable_new_list(context, indexable->list.ordered); else if (!strcmp(idxstr, FNC_KEY)) { if (indexable->type == VAR_KVP) result = indexable->kvp.key; else result = variable_new_nil(context); } else if (!strcmp(idxstr, FNC_VAL)) { if (indexable->type == VAR_KVP) result = indexable->kvp.val; else result = variable_new_nil(context); } else if (!strcmp(idxstr, FNC_KEYS)) result = variable_map_list(context, indexable, &map_keys); else if (!strcmp(idxstr, FNC_VALS)) result = variable_map_list(context, indexable, &map_vals); else if (!strcmp(idxstr, FNC_PACK)) result = variable_new_cfnc(context, &cfnc_pack); else if (!strcmp(idxstr, FNC_SERIALIZE)) result = variable_new_cfnc(context, &cfnc_serialize); else if (!strcmp(idxstr, FNC_DESERIALIZE)) result = variable_new_cfnc(context, &cfnc_deserialize); else if (!strcmp(idxstr, FNC_SORT)) { assert_message(indexable->type == VAR_LST, "sorting non-list"); result = variable_new_cfnc(context, &cfnc_sort); } else if (!strcmp(idxstr, FNC_CHAR)) result = variable_new_cfnc(context, &cfnc_char); else if (!strcmp(idxstr, FNC_HAS)) result = variable_new_cfnc(context, &cfnc_has); else if (!strcmp(idxstr, FNC_FIND)) result = variable_new_cfnc(context, &cfnc_find); else if (!strcmp(idxstr, FNC_PART)) result = variable_new_cfnc(context, &cfnc_part); else if (!strcmp(idxstr, FNC_REMOVE)) result = variable_new_cfnc(context, &cfnc_remove); else if (!strcmp(idxstr, FNC_INSERT)) result = variable_new_cfnc(context, &cfnc_insert); else if (!strcmp(idxstr, FNC_REPLACE)) result = variable_new_cfnc(context, &cfnc_replace); free(idxstr); return result; }