diff --git a/cli/modules/std_math.c b/cli/modules/std_math.c index 1247f52..7ea4359 100644 --- a/cli/modules/std_math.c +++ b/cli/modules/std_math.c @@ -8,12 +8,8 @@ #include -// M_PI is non standard. The macro _USE_MATH_DEFINES defining before importing -// will define the constants for MSVC. But for a portable solution, -// we're defining it ourselves if it isn't already. -#ifndef M_PI - #define M_PI 3.14159265358979323846 -#endif +// M_PI is non standard. For a portable solution, we're defining it ourselves. +#define PK_PI 3.14159265358979323846 DEF(stdMathFloor, "floor(value:num) -> num\n") { @@ -187,6 +183,12 @@ void registerModuleMath(PKVM* vm) { PkHandle* math = pkNewModule(vm, "math"); + // Set global value PI. + pkReserveSlots(vm, 2); + pkSetSlotHandle(vm, 0, math); // slot[0] = math + pkSetSlotNumber(vm, 1, PK_PI); // slot[1] = 3.14 + pkSetGlobal(vm, 0, 1, "PI"); // slot[0].PI = slot[1] + pkModuleAddFunction(vm, math, "floor", stdMathFloor, 1); pkModuleAddFunction(vm, math, "ceil", stdMathCeil, 1); pkModuleAddFunction(vm, math, "pow", stdMathPow, 2); @@ -205,14 +207,6 @@ void registerModuleMath(PKVM* vm) { pkModuleAddFunction(vm, math, "log10", stdMathLog10, 1); pkModuleAddFunction(vm, math, "round", stdMathRound, 1); - // FIXME: - // Refactor native type interface and add PI as a global to the module. - // - // Note that currently it's mutable (since it's a global variable, not - // constant and pocketlang doesn't support constant) so the user shouldn't - // modify the PI, like in python. - //pkModuleAddGlobal(vm, math, "PI", Handle-Of-PI); - pkRegisterModule(vm, math); pkReleaseHandle(vm, math); } diff --git a/src/include/pocketlang.h b/src/include/pocketlang.h index 541a447..611e3df 100644 --- a/src/include/pocketlang.h +++ b/src/include/pocketlang.h @@ -348,7 +348,11 @@ PK_PUBLIC void pkSetSlotStringLength(PKVM* vm, int index, // Set the [index] slot's value as the given [handle]. The function won't // reclaim the ownership of the handle and you can still use it till // it's released by yourself. -PK_PUBLIC void PkSetSlotHandle(PKVM* vm, int index, PkHandle* handle); +PK_PUBLIC void pkSetSlotHandle(PKVM* vm, int index, PkHandle* handle); + +// Assign a global variable to a module at [module] slot, with the value at the +// [global] slot with the given [name]. +PK_PUBLIC void pkSetGlobal(PKVM* vm, int module, int global, const char* name); #ifdef __cplusplus } // extern "C" diff --git a/src/pk_public.c b/src/pk_public.c index 21c0799..2ccd7d5 100644 --- a/src/pk_public.c +++ b/src/pk_public.c @@ -36,10 +36,10 @@ #define VALIDATE_ARGC(arg) \ ASSERT(arg > 0 && arg <= ARGC, "Invalid argument index.") -#define CHECK_RUNTIME() \ - do { \ - ASSERT(vm->fiber != NULL, \ - "This function can only be called at runtime."); \ +#define CHECK_FIBER_EXISTS(vm) \ + do { \ + ASSERT(vm->fiber != NULL, \ + "No fiber exists. Did you forget to call pkReserveSlots()?"); \ } while (false) // A convenient macro to get the nth (1 based) argument of the current @@ -484,25 +484,25 @@ PkResult pkRunREPL(PKVM* vm) { /*****************************************************************************/ void pkSetRuntimeError(PKVM* vm, const char* message) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); VM_SET_ERROR(vm, newString(vm, message)); } void* pkGetSelf(const PKVM* vm) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); ASSERT(IS_OBJ_TYPE(vm->fiber->self, OBJ_INST), OOPS); - Instance* inst = (Instance*)AS_OBJ(vm->fiber->self); + Instance* inst = (Instance*) AS_OBJ(vm->fiber->self); ASSERT(inst->native != NULL, OOPS); return inst->native; } int pkGetArgc(const PKVM* vm) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); return ARGC; } bool pkCheckArgcRange(PKVM* vm, int argc, int min, int max) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); ASSERT(min <= max, "invalid argc range (min > max)."); if (argc < min) { @@ -533,7 +533,7 @@ bool pkCheckArgcRange(PKVM* vm, int argc, int min, int max) { // FIXME: If the user needs just the boolean value of the object, they should // use pkGetSlotBool(). PK_PUBLIC bool pkValidateSlotBool(PKVM* vm, int arg, bool* value) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); VALIDATE_ARGC(arg); Var val = ARG(arg); @@ -547,7 +547,7 @@ PK_PUBLIC bool pkValidateSlotBool(PKVM* vm, int arg, bool* value) { } PK_PUBLIC bool pkValidateSlotNumber(PKVM* vm, int arg, double* value) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); VALIDATE_ARGC(arg); Var val = ARG(arg); @@ -562,7 +562,7 @@ PK_PUBLIC bool pkValidateSlotNumber(PKVM* vm, int arg, double* value) { PK_PUBLIC bool pkValidateSlotString(PKVM* vm, int arg, const char** value, uint32_t* length) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); VALIDATE_ARGC(arg); Var val = ARG(arg); @@ -577,46 +577,40 @@ PK_PUBLIC bool pkValidateSlotString(PKVM* vm, int arg, const char** value, } void pkReserveSlots(PKVM* vm, int count) { - CHECK_RUNTIME(); - + if (vm->fiber == NULL) vm->fiber = newFiber(vm, NULL); int needed = (int)(vm->fiber->ret - vm->fiber->stack) + count; vmEnsureStackSize(vm, needed); } int pkGetSlotsCount(PKVM* vm) { - CHECK_RUNTIME(); - - return (int)(vm->fiber->sp - vm->fiber->ret); + CHECK_FIBER_EXISTS(vm); + return (int) ((vm->fiber->stack + vm->fiber->stack_size) - vm->fiber->ret); } PkVarType pkGetSlotType(PKVM* vm, int index) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); VALIDATE_SLOT_INDEX(index); - return getVarType(SLOT(index)); } bool pkGetSlotBool(PKVM* vm, int index) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); VALIDATE_SLOT_INDEX(index); - Var value = SLOT(index); return toBool(value); } double pkGetSlotNumber(PKVM* vm, int index) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); VALIDATE_SLOT_INDEX(index); - Var value = SLOT(index); ASSERT(IS_NUM(value), "Slot value wasn't a Number."); return AS_NUM(value); } const char* pkGetSlotString(PKVM* vm, int index, uint32_t* length) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); VALIDATE_SLOT_INDEX(index); - Var value = SLOT(index); ASSERT(IS_OBJ_TYPE(value, OBJ_STRING), "Slot value wasn't a String."); if (length != NULL) *length = ((String*)AS_OBJ(value))->length; @@ -624,55 +618,61 @@ const char* pkGetSlotString(PKVM* vm, int index, uint32_t* length) { } PkHandle* pkGetSlotHandle(PKVM* vm, int index) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); VALIDATE_SLOT_INDEX(index); - return vmNewHandle(vm, SLOT(index)); } void pkSetSlotNull(PKVM* vm, int index) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); VALIDATE_SLOT_INDEX(index); - SET_SLOT(index, VAR_NULL); } void pkSetSlotBool(PKVM* vm, int index, bool value) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); VALIDATE_SLOT_INDEX(index); - SET_SLOT(index, VAR_BOOL(value)); } void pkSetSlotNumber(PKVM* vm, int index, double value) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); VALIDATE_SLOT_INDEX(index); - SET_SLOT(index, VAR_NUM(value)); } void pkSetSlotString(PKVM* vm, int index, const char* value) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); VALIDATE_SLOT_INDEX(index); - SET_SLOT(index, VAR_OBJ(newString(vm, value))); } PK_PUBLIC void pkSetSlotStringLength(PKVM* vm, int index, const char* value, uint32_t length) { - CHECK_RUNTIME(); + CHECK_FIBER_EXISTS(vm); VALIDATE_SLOT_INDEX(index); - SET_SLOT(index, VAR_OBJ(newStringLength(vm, value, length))); } -void PkSetSlotHandle(PKVM* vm, int index, PkHandle* handle) { - CHECK_RUNTIME(); +void pkSetSlotHandle(PKVM* vm, int index, PkHandle* handle) { + CHECK_FIBER_EXISTS(vm); VALIDATE_SLOT_INDEX(index); SET_SLOT(index, handle->value); } -#undef CHECK_RUNTIME +void pkSetGlobal(PKVM* vm, int module, int global, const char* name) { + CHECK_FIBER_EXISTS(vm); + CHECK_ARG_NULL(name); + VALIDATE_SLOT_INDEX(module); + VALIDATE_SLOT_INDEX(global); + + Var value = SLOT(module); + ASSERT(IS_OBJ_TYPE(value, OBJ_MODULE), "Slot value wasn't a module."); + Module* m = (Module*) AS_OBJ(value); + (void) moduleAddGlobal(vm, m, name, (uint32_t) strlen(name), SLOT(global)); +} + +#undef CHECK_FIBER_EXISTS #undef VALIDATE_ARGC #undef ERR_INVALID_ARG_TYPE #undef ARG diff --git a/src/pk_value.c b/src/pk_value.c index cd7a9bf..5b2ade3 100644 --- a/src/pk_value.c +++ b/src/pk_value.c @@ -389,7 +389,7 @@ Upvalue* newUpvalue(PKVM* vm, Var* value) { } Fiber* newFiber(PKVM* vm, Closure* closure) { - ASSERT(closure->fn->arity >= -1, OOPS); + ASSERT(closure == NULL || closure->fn->arity >= -1, OOPS); Fiber* fiber = ALLOCATE(vm, Fiber); @@ -401,11 +401,13 @@ Fiber* newFiber(PKVM* vm, Closure* closure) { fiber->state = FIBER_NEW; fiber->closure = closure; - if (closure->fn->is_native) { + if (closure == NULL || closure->fn->is_native) { // For native functions, we're only using stack for parameters, // there won't be any locals or temps (which are belongs to the // native "C" stack). - int stack_size = utilPowerOf2Ceil(closure->fn->arity + 1); + + int stack_size = (closure == NULL) ? 1 : closure->fn->arity + 1; + stack_size = utilPowerOf2Ceil(stack_size); // We need at least 1 stack slot for the return value. if (stack_size == 0) stack_size++; diff --git a/tests/examples/pi.pk b/tests/examples/pi.pk index b6e4ff2..3440632 100644 --- a/tests/examples/pi.pk +++ b/tests/examples/pi.pk @@ -3,11 +3,7 @@ ## ## PI/4 = 1 - 1/3 + 1/5 - 1/7 + 1/9 - ... -from math import abs - -## Temproarly we cannot register variables on native modules -## will be implemented soon. So defining the PI here. -PI = 3.14159265358979323846 +from math import abs, PI pi_by_4 = 0; sign = -1 for i in 1..100000 diff --git a/tests/modules/math.pk b/tests/modules/math.pk index ef9055f..28d9042 100644 --- a/tests/modules/math.pk +++ b/tests/modules/math.pk @@ -7,18 +7,13 @@ from math import abs, round, log10, assert(ceil(1.1) == floor(2.9)) -## FIXME: -## temproarly modules cannot define globals via native interface -## and it'll be fixed soon. -PI = 3.14159265358979323846 - assert(m.sin(0) == 0) -assert(m.sin(PI/2) == 1) +assert(m.sin(m.PI/2) == 1) threshold = 0.0000000000001 -assert(abs(m.cos(PI/3) - 0.5) < threshold ) -assert(abs(m.tan(PI/4) - 1.0) < threshold ) +assert(abs(m.cos(m.PI/3) - 0.5) < threshold ) +assert(abs(m.tan(m.PI/4) - 1.0) < threshold ) for i in 0..1000 assert(abs(m.sin(i) / m.cos(i) - m.tan(i)) < threshold) end @@ -29,8 +24,8 @@ for i in 0..100 assert(abs(m.sinh(i) / m.cosh(i) - m.tanh(i)) < threshold) end -assert(abs(m.acos(PI/4) - 0.5) < 0.35) -assert(abs(m.atan(PI/4) - 0.5) < 0.2) +assert(abs(m.acos(m.PI/4) - 0.5) < 0.35) +assert(abs(m.atan(m.PI/4) - 0.5) < 0.2) assert((m.acos(0.5) - 1.1276259652063807) < threshold) assert((m.atan(0.3) - 1.1276259652063807) < threshold)