static Klass* _klass_new(uint32_t klass_id, Val name, uint32_t parent_id) { Klass* k = val_alloc(KLASS_KLASS, sizeof(Klass)); k->id = klass_id; k->name = name; k->parent_id = parent_id; IdMethods.init(&k->id_methods); Includes.init(&k->includes, 0); IdFieldIndexes.init(&k->id_field_indexes); Fields.init(&k->fields, 0); k->hash_func = NULL; k->eq_func = NULL; k->destruct_func = NULL; k->delete_func = NULL; k->debug_func = NULL; val_perm(k); ConstSearchKey key = {.parent = k->parent_id, .name_str = VAL_TO_STR(k->name)}; KlassSearchMap.insert(&runtime.klass_search_map, key, k->id); ConstSearchMap.insert(&runtime.const_search_map, key, (Val)k); return k; } static void _klass_delete(Klass* k) { ConstSearchKey key = {.parent = k->parent_id, .name_str = VAL_TO_STR(k->name)}; KlassSearchMap.remove(&runtime.klass_search_map, key); ConstSearchMap.remove(&runtime.const_search_map, key); IdMethods.cleanup(&k->id_methods); Includes.cleanup(&k->includes); IdFieldIndexes.cleanup(&k->id_field_indexes); Fields.cleanup(&k->fields); val_free(k); } static Method* _method_new(uint32_t method_id, int32_t min_argc, int32_t max_argc, bool is_final) { Method* meth = val_alloc(KLASS_METHOD, sizeof(Method)); METHOD_ID(meth) = method_id; METHOD_IS_FINAL(meth) = is_final; METHOD_MIN_ARGC(meth) = min_argc; METHOD_MAX_ARGC(meth) = max_argc; val_perm(meth); return meth; }
/* range([start],end,[step]) */ static inline MUST_CHECK value_t function_range(value_t vals, linepos_t epoint) { struct values_s *v = vals->u.funcargs.val; size_t args = vals->u.funcargs.len; value_t err, new_value; ival_t start = 0, end, step = 1; size_t i = 0, len2; value_t *val; if (args < 1 || args > 3) { err_msg_argnum(args, 1, 3, epoint); return val_reference(none_value); } switch (args) { case 1: err = v[0].val->obj->ival(v[0].val, &end, 8*sizeof(ival_t), &v[0].epoint); break; case 3: err = v[2].val->obj->ival(v[2].val, &step, 8*sizeof(ival_t), &v[2].epoint); if (err) return err; case 2: err = v[0].val->obj->ival(v[0].val, &start, 8*sizeof(ival_t), &v[0].epoint); if (err) return err; err = v[1].val->obj->ival(v[1].val, &end, 8*sizeof(ival_t), &v[1].epoint); break; } if (err) return err; if (step == 0) { return new_error_obj(ERROR_NO_ZERO_VALUE, &v[2].epoint); } if (step > 0) { if (end < start) end = start; len2 = (end - start + step - 1) / step; } else { if (end > start) end = start; len2 = (start - end - step - 1) / -step; } new_value = val_alloc(LIST_OBJ); val = list_create_elements(new_value, len2); if (len2) { i = 0; while ((end > start && step > 0) || (end < start && step < 0)) { val[i] = int_from_ival(start); i++; start += step; } } new_value->u.list.len = len2; new_value->u.list.data = val; return new_value; }
static MUST_CHECK value_t repr(const value_t v1, linepos_t epoint) { uint8_t *s; const char *prefix; size_t len; value_t v; if (!epoint) return NULL; prefix = "<native_function '"; len = strlen(prefix); v = val_alloc(STR_OBJ); v->u.str.len = v1->u.function.name.len + 2 + len; if (v->u.str.len < (2 + len)) err_msg_out_of_memory(); /* overflow */ v->u.str.chars = v->u.str.len; s = str_create_elements(v, v->u.str.len); memcpy(s, prefix, len); memcpy(s + len, v1->u.function.name.data, v1->u.function.name.len); s[v->u.str.len - 2] = '\''; s[v->u.str.len - 1] = '>'; v->u.str.data = s; return v; }
static MUST_CHECK value_t apply_func2(oper_t op, enum func_e func) { value_t err, v, v1 = op->v1, v2 = op->v2, val, *vals; double real, real2; if (v1->obj == TUPLE_OBJ || v1->obj == LIST_OBJ) { size_t i; if (v1->obj == v2->obj) { if (v1->u.list.len == v2->u.list.len) { if (v1->u.list.len) { int error = 1; v = val_alloc(v1->obj); vals = list_create_elements(v, v1->u.list.len); for (i = 0; i < v1->u.list.len; i++) { op->v1 = v1->u.list.data[i]; op->v2 = v2->u.list.data[i]; val = apply_func2(op, func); if (val->obj == ERROR_OBJ) { if (error) {err_msg_output(val); error = 0;} val_destroy(val); val = val_reference(none_value); } vals[i] = val; } op->v1 = v1; op->v2 = v2; v->u.list.len = i; v->u.list.data = vals; return v; } return val_reference(v1); } if (v1->u.list.len == 1) { op->v1 = v1->u.list.data[0]; v = apply_func2(op, func); op->v1 = v1; return v; } if (v2->u.list.len == 1) { op->v2 = v2->u.list.data[0]; v = apply_func2(op, func); op->v2 = v2; return v; } v = new_error_obj(ERROR_CANT_BROADCAS, op->epoint3); v->u.error.u.broadcast.v1 = v1->u.list.len; v->u.error.u.broadcast.v2 = v2->u.list.len; return v; } if (v1->u.list.len) { int error = 1; v = val_alloc(v1->obj); vals = list_create_elements(v, v1->u.list.len); for (i = 0; i < v1->u.list.len; i++) { op->v1 = v1->u.list.data[i]; val = apply_func2(op, func); if (val->obj == ERROR_OBJ) { if (error) {err_msg_output(val); error = 0;} val_destroy(val); val = val_reference(none_value); } vals[i] = val; } op->v1 = v1; v->u.list.len = i; v->u.list.data = vals; return v; } return val_reference(v1); } if (v2->obj == TUPLE_OBJ || v2->obj == LIST_OBJ) { if (v2->u.list.len) { int error = 1; size_t i; v = val_alloc(v2->obj); vals = list_create_elements(v, v2->u.list.len); for (i = 0; i < v2->u.list.len; i++) { op->v2 = v2->u.list.data[i]; val = apply_func2(op, func); if (val->obj == ERROR_OBJ) { if (error) {err_msg_output(val); error = 0;} val_destroy(val); val = val_reference(none_value); } vals[i] = val; } op->v2 = v2; v->u.list.len = i; v->u.list.data = vals; return v; } return val_reference(v2); } err = FLOAT_OBJ->create(v1, op->epoint); if (err->obj != FLOAT_OBJ) return err; real = err->u.real; val_destroy(err); err = FLOAT_OBJ->create(v2, op->epoint2); if (err->obj != FLOAT_OBJ) return err; real2 = err->u.real; val_destroy(err); switch (func) { case F_HYPOT: real = hypot(real, real2); break; case F_ATAN2: real = atan2(real, real2);break; case F_POW: if (real2 < 0.0 && !real) { return new_error_obj(ERROR_DIVISION_BY_Z, op->epoint3); } if (real < 0.0 && (double)((int)real2) != real2) { return new_error_obj(ERROR_NEGFRAC_POWER, op->epoint3); } real = pow(real, real2); break; default: real = HUGE_VAL; break; } return float_from_double2(real, op->epoint3); }
static MUST_CHECK value_t apply_func(value_t v1, enum func_e func, linepos_t epoint) { value_t err, v; double real; switch (func) { case F_ANY: return v1->obj->truth(v1, TRUTH_ANY, epoint); case F_ALL: return v1->obj->truth(v1, TRUTH_ALL, epoint); case F_LEN: return v1->obj->len(v1, epoint); default: break; } if (v1->obj == TUPLE_OBJ || v1->obj == LIST_OBJ) { if (v1->u.list.len) { int error = 1; size_t i; value_t *vals; v = val_alloc(v1->obj); vals = list_create_elements(v, v1->u.list.len); for (i = 0; i < v1->u.list.len; i++) { value_t val = apply_func(v1->u.list.data[i], func, epoint); if (val->obj == ERROR_OBJ) { if (error) {err_msg_output(val); error = 0;} val_destroy(val); val = val_reference(none_value); } vals[i] = val; } v->u.list.len = i; v->u.list.data = vals; return v; } return val_reference(v1); } switch (func) { case F_SIZE: return v1->obj->size(v1, epoint); case F_SIGN: return v1->obj->sign(v1, epoint); case F_ABS: return v1->obj->abs(v1, epoint); case F_REPR: return v1->obj->repr(v1, epoint); default: break; } err = FLOAT_OBJ->create(v1, epoint); if (err->obj != FLOAT_OBJ) return err; real = err->u.real; val_destroy(err); switch (func) { case F_FLOOR: real = floor(real);break; case F_CEIL: real = ceil(real);break; case F_SQRT: if (real < 0.0) { return new_error_obj(ERROR_SQUARE_ROOT_N, epoint); } real = sqrt(real); break; case F_LOG10: if (real <= 0.0) { return new_error_obj(ERROR_LOG_NON_POSIT, epoint); } real = log10(real); break; case F_LOG: if (real <= 0.0) { return new_error_obj(ERROR_LOG_NON_POSIT, epoint); } real = log(real); break; case F_EXP: real = exp(real);break; case F_SIN: real = sin(real);break; case F_COS: real = cos(real);break; case F_TAN: real = tan(real);break; case F_ACOS: if (real < -1.0 || real > 1.0) { return new_error_obj(ERROR___MATH_DOMAIN, epoint); } real = acos(real); break; case F_ASIN: if (real < -1.0 || real > 1.0) { return new_error_obj(ERROR___MATH_DOMAIN, epoint); } real = asin(real); break; case F_ATAN: real = atan(real);break; case F_CBRT: real = cbrt(real);break; case F_ROUND: real = round(real);break; case F_TRUNC: real = trunc(real);break; case F_FRAC: real -= trunc(real);break; case F_RAD: real = real * M_PI / 180.0;break; case F_DEG: real = real * 180.0 / M_PI;break; case F_COSH: real = cosh(real);break; case F_SINH: real = sinh(real);break; case F_TANH: real = tanh(real);break; default: real = HUGE_VAL; break; /* can't happen */ } return float_from_double2(real, epoint); }