10 #define ONE_ARGUMENT(name) if (argc != 1) { \
11 krk_runtimeError(vm.exceptions->argumentError, "%s() expects one argument", #name); \
15 #define TWO_ARGUMENTS(name) if (argc != 2) { \
16 krk_runtimeError(vm.exceptions->argumentError, "%s() expects two arguments", #name); \
20 #define FORCE_FLOAT(src,arg) \
22 if (!IS_FLOATING(arg)) { switch (KRK_VAL_TYPE(arg)) { \
23 case KRK_VAL_INTEGER: arg = FLOATING_VAL(AS_INTEGER(arg)); break; \
24 case KRK_VAL_BOOLEAN: arg = FLOATING_VAL(AS_BOOLEAN(arg)); break; \
26 KrkClass * type = krk_getType(arg); \
28 if (!krk_bindMethod(type, S("__float__"))) { \
31 arg = krk_callStack(0); \
36 #define REAL_NUMBER_NOT(name, garbage) { \
37 krk_runtimeError(vm.exceptions->typeError, "%s() argument must be real number, not '%T'", #name, garbage); \
41 extern KrkValue krk_int_from_float(
double val);
43 #define MATH_DELEGATE(func) \
44 static KrkValue _math_ ## func(int argc, const KrkValue argv[], int hasKw) { \
46 if (IS_FLOATING(argv[0])) { \
47 return krk_int_from_float(func(AS_FLOATING(argv[0]))); \
48 } else if (IS_INTEGER(argv[0])) { \
51 KrkClass * type = krk_getType(argv[0]); \
53 if (!krk_bindMethod(type, S("__" #func "__"))) REAL_NUMBER_NOT(func,argv[0]) \
54 return krk_callStack(0); \
62 #define MATH_ONE_NAME(func,name) \
63 static KrkValue _math_ ## name(int argc, const KrkValue argv[], int hasKw) { \
65 FORCE_FLOAT(argv[0],arg_0) \
66 if (IS_FLOATING(arg_0)) { \
67 return FLOATING_VAL(func(AS_FLOATING(arg_0))); \
68 } else REAL_NUMBER_NOT(name,arg_0) \
70 #define MATH_ONE(func) MATH_ONE_NAME(func,func)
95 #define MATH_TWO(func) \
96 static KrkValue _math_ ## func(int argc, const KrkValue argv[], int hasKw) { \
98 FORCE_FLOAT(argv[0],arg_0) \
99 FORCE_FLOAT(argv[1],arg_1) \
100 if (!IS_FLOATING(arg_0)) REAL_NUMBER_NOT(func,arg_0) \
101 if (!IS_FLOATING(arg_1)) REAL_NUMBER_NOT(func,arg_1) \
102 return FLOATING_VAL(func(AS_FLOATING(arg_0),AS_FLOATING(arg_1))); \
112 TWO_ARGUMENTS(__pow__);
113 if (unlikely(!IS_FLOATING(argv[0])))
return krk_runtimeError(
vm.exceptions->typeError,
"expected float");
114 if (likely(IS_FLOATING(argv[1]))) {
115 return FLOATING_VAL(pow(AS_FLOATING(argv[0]),AS_FLOATING(argv[1])));
116 }
else if (likely(IS_INTEGER(argv[1]))) {
117 return FLOATING_VAL(pow(AS_FLOATING(argv[0]),(
double)AS_INTEGER(argv[1])));
119 return NOTIMPL_VAL();
125 FORCE_FLOAT(argv[0],arg_0)
126 if (!IS_FLOATING(arg_0)) {
127 REAL_NUMBER_NOT(frexp,arg_0)
130 double result = frexp(AS_FLOATING(arg_0), &exp);
135 return OBJECT_VAL(outValue);
138 #define MATH_IS(func) \
139 static KrkValue _math_ ## func(int argc, const KrkValue argv[], int hasKw) { \
141 if (!IS_FLOATING(argv[0])) REAL_NUMBER_NOT(func,argv[0]) \
142 return BOOLEAN_VAL(func(AS_FLOATING(argv[0]))); \
149 #define bind(name) krk_defineNative(&module->fields, #name, _math_ ## name)
152 KRK_DOC(module,
"@brief Provides access to floating-point mathematical functions from the system `libm`.");
154 "@brief Returns the smallest integer value not less than the input.\n"
157 "@brief Returns the largest integer value not greater than the input.\n"
160 "@brief Rounds the input towards zero to an integer.\n"
163 "@brief Returns the base-e exponentiation of the input.\n"
166 "@brief Equivalent to `exp(x) - 1`.\n"
169 "@brief Calculates the base-2 logarithm of the input.\n"
172 "@brief Calculates the base-10 logarithm of the input.\n"
175 "@brief Calculates the square root of the input.\n"
178 "@brief Calculates the arc-cosine of the radian input.\n"
181 "@brief Calculates the arc-sine of the radian input.\n"
184 "@brief Calculates the arc-tangent of the radian input.\n"
187 "@brief Calculates the cosine of the radian input.\n"
190 "@brief Calculates the sine of the radian input.\n"
193 "@brief Calculates the tangent of the radian input.\n"
196 "@brief Calculates the inverse hyperbolic cosine of the input.\n"
199 "@brief Calculates the inverse hyperbolic sine of the input.\n"
202 "@brief Calculates the inverse hyperbolic tangent of the input.\n"
205 "@brief Calculates the hyperbolic cosine of the input.\n"
208 "@brief Calculates the hyperbolic sine of the input.\n"
211 "@brief Calculates the hyperbolic tangent of the input.\n"
214 "@brief Calculates the error function of the input.\n"
217 "@brief Calculates the complementary error function of the input.\n"
220 "@brief Calculates the gamma of the input.\n"
223 "@brief Calculates the log gamma of the input.\n"
226 "@brief Copies the sign from @p x to @p y\n"
229 "@brief Returns the floating point remainder of @p x over @p y\n"
232 "@brief Somehow different from `fmod`.");
234 "@brief Equivalent to `log(x + 1)`\n"
237 "@brief Equivalent to `exp(x) - 1`\n"
240 "@brief Calculates `x^p`\n"
243 "@brief Calculates the arctangent of `x` and `y`\n"
246 "@brief Converts a floating point input to a fractional and integer component pair, returned as a tuple.\n"
248 "@returns @ref tuple of two @ref int");
250 "@brief Determines if the input is finite.\n"
253 "@brief Determines if the input is infinite.\n"
256 "@brief Determines if the input is the floating point `NaN`.\n"
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Struct definitions for core object types.
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
KrkNative * krk_defineNative(KrkTable *table, const char *name, NativeFn function)
Attach a native C function to an attribute table.
void krk_attachNamedValue(KrkTable *table, const char name[], KrkValue obj)
Attach a value to an attribute table.
Immutable sequence of arbitrary values.
KrkValueArray values
Stores the length, capacity, and actual values of the tuple.
KrkTuple * krk_newTuple(size_t length)
Create a new tuple.
Stack reference or primative value.
Utilities for creating native bindings.
#define KRK_DOC(thing, text)
Attach documentation to a thing of various types.
Definitions for primitive stack references.
Core API for the bytecode virtual machine.
#define vm
Convenience macro for namespacing.