mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-06 04:37:47 +08:00
adding globals support in native interface
pkSetGlobal function implemented to support adding globals from the native interface. Also the PKVM slots doesn't need a runtime anymore to use them (see math.PI global to see how it works).
This commit is contained in:
parent
78b7004de6
commit
b5d98ca4c3
@ -8,12 +8,8 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
// M_PI is non standard. The macro _USE_MATH_DEFINES defining before importing
|
||||
// <math.h> 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);
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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++;
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user