int compar(struct context *context, const void *a, const void *b, struct variable *comparator) { struct variable *av = *(struct variable**)a; struct variable *bv = *(struct variable**)b; if (comparator) { byte_array_reset(comparator->str); vm_call(context, comparator, av, bv, NULL); struct variable *result = (struct variable*)stack_pop(context->operand_stack); if (result->type == VAR_SRC) result = array_get(result->list.ordered, 0); assert_message(result->type == VAR_INT, "non-integer comparison result"); return result->integer; } else { enum VarType at = av->type; enum VarType bt = bv->type; if (at == VAR_INT && bt == VAR_INT) { // DEBUGPRINT("compare %p:%d to %p:%d : %d\n", av, av->integer, bv, bv->integer, av->integer - bv->integer); return av->integer - bv->integer; } else DEBUGPRINT("can't compare %s to %s\n", var_type_str(at), var_type_str(bt)); vm_exit_message(context, "incompatible types for comparison"); return 0; } }
static void dst(struct context *context, bool really) // drop unused assignment right-hand-side values { DEBUGPRINT("DST "); if (!context->runtime) VM_DEBUGPRINT(" (not runtime)\n"); if (stack_empty(context->operand_stack)) { DEBUGPRINT(" %x mt\n", context->operand_stack); return; } struct variable *v = (struct variable*)stack_peek(context->operand_stack, 0); if (v->type == VAR_SRC) // unused result stack_pop(context->operand_stack); else DEBUGPRINT(" (%s/%d)", var_type_str(v->type), really); DEBUGPRINT("\n"); }
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; }