static void *default_copyor(const void *key, void *context) { struct variable *v = (struct variable *)key; struct variable *u = variable_copy((struct context *)context, v); variable_old(u); return u; }
static void push_fnc(struct context *context, struct byte_array *program) { uint32_t num_closures = serial_decode_int(program); struct map *closures = NULL; for (int i=0; i<num_closures; i++) { struct byte_array *name = serial_decode_string(program); if (context->runtime) { if (!closures) closures = map_new(); struct variable *c = find_var(context, name); c = variable_copy(context, c); map_insert(closures, name, c); } } struct byte_array *body = serial_decode_string(program); DEBUGPRINT("FNC %u,%u\n", num_closures, body->length); //display_code(context, body); if (context->runtime) { struct variable *f = variable_new_fnc(context, body, closures); variable_push(context, f); } }
// arguments most recently passed into a function struct variable *sys_args(struct context *context) { stack_pop(context->operand_stack); // self struct program_state *above = (struct program_state*)stack_peek(context->program_stack, 1); struct variable *result = variable_copy(context, above->args); result->type = VAR_LST; return result; }
struct variable *sys_listen(struct context *context) { struct variable *arguments = (struct variable*)stack_pop(context->operand_stack); struct listen_arguments *la = (struct listen_arguments*)malloc(sizeof(struct listen_arguments)); la->serverport = param_int(arguments, 1); la->listener = variable_copy(context, (struct variable*)array_get(arguments->list, 2)); pthread_t child; pthread_create(&child, NULL, sys_listen2, la); return NULL; }
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; }
void set_named_variable(struct context *context, struct program_state *state, const struct byte_array *name, const struct variable *value) { // DEBUGPRINT(" set_named_variable: %p\n", state); if (!state) state = (struct program_state*)stack_peek(context->program_stack, 0); struct map *var_map = state->named_variables; struct variable *to_var = variable_copy(context, value); map_insert(var_map, name, to_var); //DEBUGPRINT("SET %s to %s\n", byte_array_to_string(name), variable_value_str(context, value)); // DEBUGPRINT(" SET %s at %p in {p:%p, s:%p, m:%p}\n", byte_array_to_string(name), to_var, context->program_stack, state, var_map); }
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 struct variable *binary_op_lst(struct context *context, enum Opcode op, const struct variable *u, const struct variable *v) { vm_assert(context, u->type==VAR_LST && v->type==VAR_LST, "list op with non-lists"); struct variable *w = NULL; switch (op) { case VM_ADD: w = variable_copy(context, v); for (int i=0; i<u->list->length; i++) array_add(w->list, array_get(u->list, i)); map_update(w->map, u->map); break; default: return (struct variable*)vm_exit_message(context, "unknown string operation"); } return w; }
static struct variable *binary_op_nil(struct context *context, enum Opcode op, const struct variable *u, const struct variable *v) { vm_assert(context, u->type==VAR_NIL || v->type==VAR_NIL, "nil op with non-nils"); if (v->type == VAR_NIL && u->type != VAR_NIL) return binary_op_nil(context, op, v, u); // 1st var should be nil switch (op) { case VM_EQU: return variable_new_bool(context, v->type == u->type); case VM_NEQ: return variable_new_bool(context, v->type != u->type); case VM_ADD: case VM_SUB: return variable_copy(context, v); case VM_LTN: case VM_GTN: case VM_LEQ: case VM_GRQ: return variable_new_bool(context, false); default: return vm_exit_message(context, "unknown binary nil op"); } }
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; }