static bool variable_compare(struct context *context, const struct variable *u, const struct variable *v) { if (!u != !v) return false; enum VarType ut = (enum VarType)u->type; enum VarType vt = (enum VarType)v->type; if (ut != vt) return false; switch (ut) { case VAR_LST: if (u->list->length != v->list->length) return false; for (int i=0; i<u->list->length; i++) { struct variable *ui = (struct variable*)array_get(u->list, i); struct variable *vi = (struct variable*)array_get(v->list, i); if (!variable_compare(context, ui, vi)) return false; } break; case VAR_BOOL: case VAR_INT: if (u->integer != v->integer) return false; break; case VAR_FLT: if (u->floater != v->floater) return false; break; case VAR_STR: if (!byte_array_equals(u->str, v->str)) return false; break; default: return (bool)vm_exit_message(context, "bad comparison"); } return variable_compare_maps(context, u->map, v->map); }
static bool variable_compare_maps(struct context *context, const struct map *umap, const struct map *vmap) { if (!umap && !vmap) return true; if (!umap) return variable_compare_maps(context, vmap, umap); struct array *keys = map_keys(umap); if (!vmap) return !keys->length; for (int i=0; i<keys->length; i++) { struct byte_array *key = (struct byte_array*)array_get(keys, i); struct variable *uvalue = (struct variable*)map_get(umap, key); struct variable *vvalue = (struct variable*)map_get(vmap, key); if (!variable_compare(context, uvalue, vvalue)) return false; } return true; }
static void binary_op(struct context *context, enum Opcode op) { if (!context->runtime) VM_DEBUGPRINT("%s\n", NUM_TO_STRING(opcodes, op)); struct variable *u = variable_pop(context); struct variable *v = variable_pop(context); enum VarType ut = (enum VarType)u->type; enum VarType vt = (enum VarType)v->type; struct variable *w; if (ut == VAR_NIL || vt == VAR_NIL) { w = binary_op_nil(context, op, u, v); } else if ((op == VM_EQU) || (op == VM_NEQ)) { bool same = variable_compare(context, u, v) ^ (op == VM_NEQ); w = variable_new_bool(context, same); } else { bool floater = (ut == VAR_FLT && is_num(vt)) || (vt == VAR_FLT && is_num(ut)); bool inter = (ut==VAR_INT || ut==VAR_BOOL) && (vt==VAR_INT || vt==VAR_BOOL); if (floater) w = binary_op_float(context, op, u, v); else if (inter) w = binary_op_int(context, op, v, u); else if (vt == VAR_STR || ut == VAR_STR) w = binary_op_str(context, op, u, v); else if (vt == VAR_LST) w = binary_op_lst(context, op, u, v); else vm_exit_message(context, "unknown binary op"); } variable_push(context, w); DEBUGPRINT("%s(%s,%s) = %s\n", NUM_TO_STRING(opcodes, op), variable_value_str(context, v), variable_value_str(context, u), variable_value_str(context, w)); }
static bool default_comparator(const void *a, const void *b, void *context) { return variable_compare((struct context *)context, (struct variable *)a, (struct variable *)b); }