Add math module
This commit is contained in:
parent
648ed8c85f
commit
9d9d5d5be7
3
Makefile
3
Makefile
@ -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
183
src/math.c
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user