Add math module

This commit is contained in:
K. Lange 2021-01-16 10:18:19 +09:00
parent 648ed8c85f
commit 9d9d5d5be7
2 changed files with 186 additions and 0 deletions

View File

@ -50,6 +50,9 @@ kuroko: ${KUROKO_LIBS}
modules/%.so: src/%.c
${CC} ${CFLAGS} -shared -o $@ $<
modules/math.so: src/math.c
${CC} ${CFLAGS} -shared -o $@ $< -lm
libkuroko.so: ${OBJS}
${CC} ${CLFAGS} -shared -o $@ ${OBJS}

183
src/math.c Normal file
View File

@ -0,0 +1,183 @@
/**
* math module; thin wrapper around libc math functions.
*/
#include <math.h>
#include "../vm.h"
#include "../value.h"
#include "../object.h"
#define S(c) (krk_copyString(c,sizeof(c)-1))
#define ONE_ARGUMENT(name) if (argc != 1) { \
krk_runtimeError(vm.exceptions.argumentError, "%s() expects one argument", #name); \
return NONE_VAL(); \
}
#define TWO_ARGUMENTS(name) if (argc != 2) { \
krk_runtimeError(vm.exceptions.argumentError, "%s() expects two arguments", #name); \
return NONE_VAL(); \
}
#define FORCE_FLOAT(arg) \
if (!IS_FLOATING(arg)) { switch (arg.type) { \
case VAL_INTEGER: arg = FLOATING_VAL(AS_INTEGER(arg)); break; \
case VAL_BOOLEAN: arg = FLOATING_VAL(AS_BOOLEAN(arg)); break; \
default: { \
KrkClass * type = AS_CLASS(krk_typeOf(1,&arg)); \
krk_push(arg); \
if (!krk_bindMethod(type, S("__float__"))) { \
krk_pop(); \
} else { \
arg = krk_callSimple(krk_peek(0), 0, 1); \
} \
} break; \
} }
#define REAL_NUMBER_NOT(name, garbage) { \
krk_runtimeError(vm.exceptions.typeError, "%s() argument must be real number, not %s", #name, krk_typeName(garbage)); \
return NONE_VAL(); \
}
#define MATH_DELEGATE(func) \
static KrkValue _math_ ## func(int argc, KrkValue argv[]) { \
ONE_ARGUMENT(func) \
if (IS_FLOATING(argv[0])) { \
return INTEGER_VAL(func(AS_FLOATING(argv[0]))); \
} else if (IS_INTEGER(argv[0])) { \
return argv[0]; /* no op */ \
} else { \
KrkClass * type = AS_CLASS(krk_typeOf(1,&argv[0])); \
krk_push(argv[0]); \
if (!krk_bindMethod(type, S("__" #func "__"))) REAL_NUMBER_NOT(func,argv[0]) \
return krk_callSimple(krk_peek(0), 0, 1); \
} \
}
MATH_DELEGATE(ceil)
MATH_DELEGATE(floor)
MATH_DELEGATE(trunc)
#define MATH_ONE_NAME(func,name) \
static KrkValue _math_ ## name(int argc, KrkValue argv[]) { \
ONE_ARGUMENT(name) \
FORCE_FLOAT(argv[0]) \
if (IS_FLOATING(argv[0])) { \
return FLOATING_VAL(func(AS_FLOATING(argv[0]))); \
} else REAL_NUMBER_NOT(name,argv[0]) \
}
#define MATH_ONE(func) MATH_ONE_NAME(func,func)
MATH_ONE(exp)
MATH_ONE(expm1)
MATH_ONE(log2)
MATH_ONE(log10)
MATH_ONE(sqrt)
MATH_ONE(acos)
MATH_ONE(asin)
MATH_ONE(atan)
MATH_ONE(cos)
MATH_ONE(sin)
MATH_ONE(tan)
MATH_ONE(acosh)
MATH_ONE(asinh)
MATH_ONE(atanh)
MATH_ONE(cosh)
MATH_ONE(sinh)
MATH_ONE(tanh)
MATH_ONE(erf)
MATH_ONE(erfc)
MATH_ONE(gamma)
MATH_ONE(lgamma)
MATH_ONE_NAME(log,log1p)
#define MATH_TWO(func) \
static KrkValue _math_ ## func(int argc, KrkValue argv[]) { \
TWO_ARGUMENTS(func) \
FORCE_FLOAT(argv[0]) \
FORCE_FLOAT(argv[1]) \
if (!IS_FLOATING(argv[0])) REAL_NUMBER_NOT(func,argv[0]) \
if (!IS_FLOATING(argv[1])) REAL_NUMBER_NOT(func,argv[1]) \
return FLOATING_VAL(func(AS_FLOATING(argv[0]),AS_FLOATING(argv[1]))); \
}
MATH_TWO(copysign)
MATH_TWO(fmod)
MATH_TWO(remainder)
MATH_TWO(pow)
MATH_TWO(atan2)
static KrkValue _math_frexp(int argc, KrkValue argv[]) {
ONE_ARGUMENT(frexp)
FORCE_FLOAT(argv[0])
if (!IS_FLOATING(argv[0])) {
REAL_NUMBER_NOT(frexp,argv[0])
}
int exp = 0;
double result = frexp(AS_FLOATING(argv[0]), &exp);
KrkTuple * outValue = krk_newTuple(2);
outValue->values.values[0] = FLOATING_VAL(result);
outValue->values.values[1] = INTEGER_VAL(exp);
outValue->values.count = 2;
return OBJECT_VAL(outValue);
}
#define MATH_IS(func) \
static KrkValue _math_ ## func(int argc, KrkValue argv[]) { \
ONE_ARGUMENT(func) \
if (!IS_FLOATING(argv[0])) REAL_NUMBER_NOT(func,argv[0]) \
return BOOLEAN_VAL(func(AS_FLOATING(argv[0]))); \
}
MATH_IS(isfinite)
MATH_IS(isinf)
MATH_IS(isnan)
#define bind(name) krk_defineNative(&module->fields, #name, _math_ ## name)
KrkValue krk_module_onload_math(void) {
KrkInstance * module = krk_newInstance(vm.moduleClass);
krk_push(OBJECT_VAL(module));
bind(ceil);
bind(floor);
bind(trunc);
bind(exp);
bind(expm1);
bind(log2);
bind(log10);
bind(sqrt);
bind(acos);
bind(asin);
bind(atan);
bind(cos);
bind(sin);
bind(tan);
bind(acosh);
bind(asinh);
bind(atanh);
bind(cosh);
bind(sinh);
bind(tanh);
bind(erf);
bind(erfc);
bind(gamma);
bind(lgamma);
bind(copysign);
bind(fmod);
bind(remainder);
bind(log1p);
bind(pow);
bind(atan2);
bind(frexp);
bind(isfinite);
bind(isinf);
bind(isnan);
krk_attachNamedValue(&module->fields, "pi", FLOATING_VAL(M_PI));
krk_attachNamedValue(&module->fields, "e", FLOATING_VAL(M_E));
krk_attachNamedValue(&module->fields, "inf", FLOATING_VAL(INFINITY));
krk_attachNamedValue(&module->fields, "nan", FLOATING_VAL(NAN));
krk_pop();
return OBJECT_VAL(module);
}