mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-05 20:26:53 +08:00
yet another refactor.
This commit doesn't change any behavior, just moving the code around cleaning things.
This commit is contained in:
parent
6083af6dbe
commit
ddc8bd8197
44
cli/common.h
44
cli/common.h
@ -28,8 +28,7 @@
|
||||
|
||||
// The internal assertion macro, this will print error and break regardless of
|
||||
// the build target (debug or release). Use ASSERT() for debug assertion and
|
||||
// use __ASSERT() for TODOs and assertions in public methods (to indicate that
|
||||
// the host application did something wrong).
|
||||
// use __ASSERT() for TODOs.
|
||||
#define __ASSERT(condition, message) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
@ -111,45 +110,4 @@
|
||||
#define TODO __ASSERT(false, "TODO: It hasn't implemented yet.")
|
||||
#define OOPS "Oops a bug!! report please."
|
||||
|
||||
// The formated string to convert double to string. It'll be with the minimum
|
||||
// length string representation of either a regular float or a scientific
|
||||
// notation (at most 15 decimal points).
|
||||
// Reference: https://www.cplusplus.com/reference/cstdio/printf/
|
||||
#define DOUBLE_FMT "%.16g"
|
||||
|
||||
// Double number to string buffer size, used in sprintf with DOUBLE_FMT.
|
||||
// A largest number : "-1.234567890123456e+308"
|
||||
// + 1 fot sign '+' or '-'
|
||||
// + 16 fot significant digits
|
||||
// + 1 for decimal point '.'
|
||||
// + 1 for exponent char 'e'
|
||||
// + 1 for sign of exponent
|
||||
// + 3 for the exponent digits
|
||||
// + 1 for null byte '\0'
|
||||
#define STR_DBL_BUFF_SIZE 24
|
||||
|
||||
// Integer number to string buffer size, used in sprintf with format "%d".
|
||||
// The minimum 32 bit integer = -2147483648
|
||||
// + 1 for sign '-'
|
||||
// + 10 for digits
|
||||
// + 1 for null byte '\0'
|
||||
#define STR_INT_BUFF_SIZE 12
|
||||
|
||||
// Integer number (double) to hex string buffer size.
|
||||
// The maximum value an unsigned 64 bit integer can get is
|
||||
// 0xffffffffffffffff which is 16 characters.
|
||||
// + 16 for hex digits
|
||||
// + 1 for sign '-'
|
||||
// + 2 for '0x' prefix
|
||||
// + 1 for null byte '\0'
|
||||
#define STR_HEX_BUFF_SIZE 20
|
||||
|
||||
// Integer number (double) to bin string buffer size.
|
||||
// The maximum value an unsigned 64 bit integer can get is 0b11111... 64 1s.
|
||||
// + 64 for bin digits
|
||||
// + 1 for sign '-'
|
||||
// + 2 for '0b' prefix
|
||||
// + 1 for null byte '\0'
|
||||
#define STR_BIN_BUFF_SIZE 68
|
||||
|
||||
#endif //PK_COMMON_H
|
||||
|
@ -242,8 +242,15 @@ PK_PUBLIC void pkReleaseHandle(PKVM* vm, PkHandle* handle);
|
||||
PK_PUBLIC void pkModuleAddGlobal(PKVM* vm, PkHandle* module,
|
||||
const char* name, PkHandle* value);
|
||||
|
||||
// Returns the global value with the [name] in the given [module], if the name
|
||||
// not exists in the globals of the module, it'll return NULL.
|
||||
PK_PUBLIC PkHandle* pkModuleGetGlobal(PKVM* vm, PkHandle* module,
|
||||
const char* name);
|
||||
|
||||
// Add a native function to the given module. If [arity] is -1 that means
|
||||
// The function has variadic parameters and use pkGetArgc() to get the argc.
|
||||
// Note that the function will be added as a global variable of the module,
|
||||
// to retrieve the function use pkModuleGetGlobal().
|
||||
PK_PUBLIC void pkModuleAddFunction(PKVM* vm, PkHandle* module,
|
||||
const char* name,
|
||||
pkNativeFn fptr, int arity);
|
||||
|
@ -28,8 +28,7 @@
|
||||
|
||||
// The internal assertion macro, this will print error and break regardless of
|
||||
// the build target (debug or release). Use ASSERT() for debug assertion and
|
||||
// use __ASSERT() for TODOs and assertions in public methods (to indicate that
|
||||
// the host application did something wrong).
|
||||
// use __ASSERT() for TODOs.
|
||||
#define __ASSERT(condition, message) \
|
||||
do { \
|
||||
if (!(condition)) { \
|
||||
@ -111,45 +110,4 @@
|
||||
#define TODO __ASSERT(false, "TODO: It hasn't implemented yet.")
|
||||
#define OOPS "Oops a bug!! report please."
|
||||
|
||||
// The formated string to convert double to string. It'll be with the minimum
|
||||
// length string representation of either a regular float or a scientific
|
||||
// notation (at most 15 decimal points).
|
||||
// Reference: https://www.cplusplus.com/reference/cstdio/printf/
|
||||
#define DOUBLE_FMT "%.16g"
|
||||
|
||||
// Double number to string buffer size, used in sprintf with DOUBLE_FMT.
|
||||
// A largest number : "-1.234567890123456e+308"
|
||||
// + 1 fot sign '+' or '-'
|
||||
// + 16 fot significant digits
|
||||
// + 1 for decimal point '.'
|
||||
// + 1 for exponent char 'e'
|
||||
// + 1 for sign of exponent
|
||||
// + 3 for the exponent digits
|
||||
// + 1 for null byte '\0'
|
||||
#define STR_DBL_BUFF_SIZE 24
|
||||
|
||||
// Integer number to string buffer size, used in sprintf with format "%d".
|
||||
// The minimum 32 bit integer = -2147483648
|
||||
// + 1 for sign '-'
|
||||
// + 10 for digits
|
||||
// + 1 for null byte '\0'
|
||||
#define STR_INT_BUFF_SIZE 12
|
||||
|
||||
// Integer number (double) to hex string buffer size.
|
||||
// The maximum value an unsigned 64 bit integer can get is
|
||||
// 0xffffffffffffffff which is 16 characters.
|
||||
// + 16 for hex digits
|
||||
// + 1 for sign '-'
|
||||
// + 2 for '0x' prefix
|
||||
// + 1 for null byte '\0'
|
||||
#define STR_HEX_BUFF_SIZE 20
|
||||
|
||||
// Integer number (double) to bin string buffer size.
|
||||
// The maximum value an unsigned 64 bit integer can get is 0b11111... 64 1s.
|
||||
// + 64 for bin digits
|
||||
// + 1 for sign '-'
|
||||
// + 2 for '0b' prefix
|
||||
// + 1 for null byte '\0'
|
||||
#define STR_BIN_BUFF_SIZE 68
|
||||
|
||||
#endif //PK_COMMON_H
|
||||
|
@ -607,6 +607,16 @@ static void resolveError(Compiler* compiler, int line, const char* fmt, ...) {
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// Check if the given [index] is greater than or equal to the maximum constants
|
||||
// that a module can contain and report an error.
|
||||
static void checkMaxConstantsReached(Compiler* compiler, int index) {
|
||||
ASSERT(index >= 0, OOPS);
|
||||
if (index >= MAX_CONSTANTS) {
|
||||
parseError(compiler, "A module should contain at most %d "
|
||||
"unique constants.", MAX_CONSTANTS);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* LEXING */
|
||||
/*****************************************************************************/
|
||||
@ -2085,10 +2095,7 @@ static int compilerAddConstant(Compiler* compiler, Var value) {
|
||||
|
||||
uint32_t index = moduleAddConstant(compiler->parser.vm,
|
||||
compiler->module, value);
|
||||
if (index >= MAX_CONSTANTS) {
|
||||
parseError(compiler, "A module should contain at most %d "
|
||||
"unique constants.", MAX_CONSTANTS);
|
||||
}
|
||||
checkMaxConstantsReached(compiler, index);
|
||||
return (int)index;
|
||||
}
|
||||
|
||||
@ -2289,10 +2296,8 @@ static void compileClass(Compiler* compiler) {
|
||||
moduleSetGlobal(compiler->module, index, VAR_OBJ(cls));
|
||||
|
||||
// Check count exceeded.
|
||||
if (cls_index >= MAX_CONSTANTS || ctor_index >= MAX_CONSTANTS) {
|
||||
parseError(compiler, "A module should contain at most %d "
|
||||
"unique constants.", MAX_CONSTANTS);
|
||||
}
|
||||
checkMaxConstantsReached(compiler, cls_index);
|
||||
checkMaxConstantsReached(compiler, ctor_index);
|
||||
|
||||
// Compile the constructor function.
|
||||
ASSERT(compiler->func->ptr == compiler->module->body->fn, OOPS);
|
||||
@ -2371,10 +2376,7 @@ static void compileFunction(Compiler* compiler, bool is_literal) {
|
||||
int fn_index;
|
||||
Function* func = newFunction(compiler->parser.vm, name, name_length,
|
||||
compiler->module, false, NULL, &fn_index);
|
||||
if (fn_index >= MAX_CONSTANTS) {
|
||||
parseError(compiler, "A module should contain at most %d "
|
||||
"unique constants.", MAX_CONSTANTS);
|
||||
}
|
||||
checkMaxConstantsReached(compiler, fn_index);
|
||||
|
||||
if (!is_literal) {
|
||||
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS);
|
||||
|
482
src/pk_core.c
482
src/pk_core.c
@ -32,10 +32,6 @@
|
||||
static const char* DOCSTRING(fn) = docstring; \
|
||||
static void fn(PKVM* vm)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* CORE PUBLIC API */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Create a new module with the given [name] and returns as a Module* for
|
||||
// internal. Which will be wrapped by pkNewModule to return a pkHandle*.
|
||||
static Module* newModuleInternal(PKVM* vm, const char* name);
|
||||
@ -46,42 +42,58 @@ static void moduleAddFunctionInternal(PKVM* vm, Module* module,
|
||||
const char* name, pkNativeFn fptr,
|
||||
int arity, const char* docstring);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* CORE PUBLIC API */
|
||||
/*****************************************************************************/
|
||||
|
||||
PkHandle* pkNewModule(PKVM* vm, const char* name) {
|
||||
Module* module = newModuleInternal(vm, name);
|
||||
return vmNewHandle(vm, VAR_OBJ(module));
|
||||
}
|
||||
|
||||
PK_PUBLIC void pkModuleAddGlobal(PKVM* vm, PkHandle* module,
|
||||
void pkModuleAddGlobal(PKVM* vm, PkHandle* module,
|
||||
const char* name, PkHandle* value) {
|
||||
__ASSERT(module != NULL, "Argument module was NULL.");
|
||||
__ASSERT(value != NULL, "Argument value was NULL.");
|
||||
__ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
|
||||
"Given handle is not a module.");
|
||||
ASSERT(module != NULL, "Argument module was NULL.");
|
||||
ASSERT(value != NULL, "Argument value was NULL.");
|
||||
ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
|
||||
"Given handle is not a module.");
|
||||
|
||||
moduleAddGlobal(vm, (Module*)AS_OBJ(module->value),
|
||||
name, (uint32_t)strlen(name), value->value);
|
||||
}
|
||||
|
||||
PkHandle* pkModuleGetGlobal(PKVM* vm, PkHandle* module, const char* name) {
|
||||
ASSERT(module != NULL, "Argument module was NULL.");
|
||||
ASSERT(name != NULL, "Argument name was NULL.");
|
||||
ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
|
||||
"Given handle is not a module.");
|
||||
|
||||
Module* module_ = (Module*)AS_OBJ(module->value);
|
||||
int index = moduleGetGlobalIndex(module_, name, (uint32_t)strlen(name));
|
||||
if (index == -1) return NULL;
|
||||
return vmNewHandle(vm, module_->globals.data[index]);
|
||||
}
|
||||
|
||||
void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name,
|
||||
pkNativeFn fptr, int arity) {
|
||||
__ASSERT(module != NULL, "Argument module was NULL.");
|
||||
__ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
|
||||
"Given handle is not a module.");
|
||||
ASSERT(module != NULL, "Argument module was NULL.");
|
||||
ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
|
||||
"Given handle is not a module.");
|
||||
moduleAddFunctionInternal(vm, (Module*)AS_OBJ(module->value),
|
||||
name, fptr, arity,
|
||||
NULL /*TODO: Public API for function docstring.*/);
|
||||
}
|
||||
|
||||
PkHandle* pkGetMainFunction(PKVM* vm, PkHandle* module) {
|
||||
__ASSERT(module != NULL, "Argument module was NULL.");
|
||||
__ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
|
||||
"Given handle is not a module.");
|
||||
ASSERT(module != NULL, "Argument module was NULL.");
|
||||
ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
|
||||
"Given handle is not a module.");
|
||||
Module* _module = (Module*)AS_OBJ(module->value);
|
||||
|
||||
int main_index = moduleGetGlobalIndex(_module, IMPLICIT_MAIN_NAME,
|
||||
(uint32_t)strlen(IMPLICIT_MAIN_NAME));
|
||||
if (main_index == -1) return NULL;
|
||||
ASSERT_INDEX(main_index, _module->globals.count);
|
||||
ASSERT_INDEX(main_index, (int)_module->globals.count);
|
||||
Var main_fn = _module->globals.data[main_index];
|
||||
ASSERT(IS_OBJ_TYPE(main_fn, OBJ_CLOSURE), OOPS);
|
||||
return vmNewHandle(vm, main_fn);
|
||||
@ -110,12 +122,12 @@ PkHandle* pkGetMainFunction(PKVM* vm, PkHandle* module) {
|
||||
// Check for errors in before calling the get arg public api function.
|
||||
#define CHECK_GET_ARG_API_ERRORS() \
|
||||
do { \
|
||||
__ASSERT(vm->fiber != NULL, \
|
||||
ASSERT(vm->fiber != NULL, \
|
||||
"This function can only be called at runtime."); \
|
||||
if (arg != 0) {/* If Native setter, the value would be at fiber->ret */ \
|
||||
__ASSERT(arg > 0 && arg <= ARGC, "Invalid argument index."); \
|
||||
ASSERT(arg > 0 && arg <= ARGC, "Invalid argument index."); \
|
||||
} \
|
||||
__ASSERT(value != NULL, "Argument [value] was NULL."); \
|
||||
ASSERT(value != NULL, "Argument [value] was NULL."); \
|
||||
} while (false)
|
||||
|
||||
// Set error for incompatible type provided as an argument. (TODO: got type).
|
||||
@ -132,7 +144,7 @@ do { \
|
||||
} while (false)
|
||||
|
||||
int pkGetArgc(const PKVM* vm) {
|
||||
__ASSERT(vm->fiber != NULL, "This function can only be called at runtime.");
|
||||
ASSERT(vm->fiber != NULL, "This function can only be called at runtime.");
|
||||
return ARGC;
|
||||
}
|
||||
|
||||
@ -156,8 +168,8 @@ bool pkCheckArgcRange(PKVM* vm, int argc, int min, int max) {
|
||||
}
|
||||
|
||||
PkVar pkGetArg(const PKVM* vm, int arg) {
|
||||
__ASSERT(vm->fiber != NULL, "This function can only be called at runtime.");
|
||||
__ASSERT(arg > 0 || arg <= ARGC, "Invalid argument index.");
|
||||
ASSERT(vm->fiber != NULL, "This function can only be called at runtime.");
|
||||
ASSERT(arg > 0 || arg <= ARGC, "Invalid argument index.");
|
||||
|
||||
return &(ARG(arg));
|
||||
}
|
||||
@ -281,22 +293,22 @@ void pkReturnInstNative(PKVM* vm, void* data, uint32_t id) {
|
||||
|
||||
const char* pkStringGetData(const PkVar value) {
|
||||
const Var str = (*(const Var*)value);
|
||||
__ASSERT(IS_OBJ_TYPE(str, OBJ_STRING), "Value should be of type string.");
|
||||
ASSERT(IS_OBJ_TYPE(str, OBJ_STRING), "Value should be of type string.");
|
||||
return ((String*)AS_OBJ(str))->data;
|
||||
}
|
||||
|
||||
PkVar pkFiberGetReturnValue(const PkHandle* fiber) {
|
||||
__ASSERT(fiber != NULL, "Handle fiber was NULL.");
|
||||
ASSERT(fiber != NULL, "Handle fiber was NULL.");
|
||||
Var fb = fiber->value;
|
||||
__ASSERT(IS_OBJ_TYPE(fb, OBJ_FIBER), "Given handle is not a fiber");
|
||||
ASSERT(IS_OBJ_TYPE(fb, OBJ_FIBER), "Given handle is not a fiber");
|
||||
Fiber* _fiber = (Fiber*)AS_OBJ(fb);
|
||||
return (PkVar)_fiber->ret;
|
||||
}
|
||||
|
||||
bool pkFiberIsDone(const PkHandle* fiber) {
|
||||
__ASSERT(fiber != NULL, "Handle fiber was NULL.");
|
||||
ASSERT(fiber != NULL, "Handle fiber was NULL.");
|
||||
Var fb = fiber->value;
|
||||
__ASSERT(IS_OBJ_TYPE(fb, OBJ_FIBER), "Given handle is not a fiber");
|
||||
ASSERT(IS_OBJ_TYPE(fb, OBJ_FIBER), "Given handle is not a fiber");
|
||||
Fiber* _fiber = (Fiber*)AS_OBJ(fb);
|
||||
return _fiber->state == FIBER_DONE;
|
||||
}
|
||||
@ -399,6 +411,14 @@ static inline bool validateCond(PKVM* vm, bool condition, const char* err) {
|
||||
/* SHARED FUNCTIONS */
|
||||
/*****************************************************************************/
|
||||
|
||||
static void initializeBuiltinFunctions(PKVM* vm);
|
||||
static void initializeCoreModules(PKVM* vm);
|
||||
|
||||
void initializeCore(PKVM* vm) {
|
||||
initializeBuiltinFunctions(vm);
|
||||
initializeCoreModules(vm);
|
||||
}
|
||||
|
||||
Module* getCoreLib(const PKVM* vm, String* name) {
|
||||
Var lib = mapGet(vm->core_libs, VAR_OBJ(name));
|
||||
if (IS_UNDEF(lib)) return NULL;
|
||||
@ -731,6 +751,48 @@ DEF(coreMapRemove,
|
||||
RET(mapRemoveKey(vm, map, key));
|
||||
}
|
||||
|
||||
static void initializeBuiltinFN(PKVM* vm, Closure** bfn, const char* name,
|
||||
int length, int arity, pkNativeFn ptr,
|
||||
const char* docstring) {
|
||||
Function* fn = newFunction(vm, name, length, NULL, true, docstring, NULL);
|
||||
fn->arity = arity;
|
||||
fn->native = ptr;
|
||||
vmPushTempRef(vm, &fn->_super); // fn.
|
||||
*bfn = newClosure(vm, fn);
|
||||
vmPopTempRef(vm); // fn.
|
||||
}
|
||||
|
||||
static void initializeBuiltinFunctions(PKVM* vm) {
|
||||
#define INITIALIZE_BUILTIN_FN(name, fn, argc) \
|
||||
initializeBuiltinFN(vm, &vm->builtins[vm->builtins_count++], name, \
|
||||
(int)strlen(name), argc, fn, DOCSTRING(fn));
|
||||
// General functions.
|
||||
INITIALIZE_BUILTIN_FN("type_name", coreTypeName, 1);
|
||||
INITIALIZE_BUILTIN_FN("help", coreHelp, -1);
|
||||
INITIALIZE_BUILTIN_FN("assert", coreAssert, -1);
|
||||
INITIALIZE_BUILTIN_FN("bin", coreBin, 1);
|
||||
INITIALIZE_BUILTIN_FN("hex", coreHex, 1);
|
||||
INITIALIZE_BUILTIN_FN("yield", coreYield, -1);
|
||||
INITIALIZE_BUILTIN_FN("to_string", coreToString, 1);
|
||||
INITIALIZE_BUILTIN_FN("print", corePrint, -1);
|
||||
INITIALIZE_BUILTIN_FN("input", coreInput, -1);
|
||||
INITIALIZE_BUILTIN_FN("exit", coreExit, -1);
|
||||
|
||||
// String functions.
|
||||
INITIALIZE_BUILTIN_FN("str_sub", coreStrSub, 3);
|
||||
INITIALIZE_BUILTIN_FN("str_chr", coreStrChr, 1);
|
||||
INITIALIZE_BUILTIN_FN("str_ord", coreStrOrd, 1);
|
||||
|
||||
// List functions.
|
||||
INITIALIZE_BUILTIN_FN("list_append", coreListAppend, 2);
|
||||
INITIALIZE_BUILTIN_FN("list_join", coreListJoin, 1);
|
||||
|
||||
// Map functions.
|
||||
INITIALIZE_BUILTIN_FN("map_remove", coreMapRemove, 2);
|
||||
|
||||
#undef INITIALIZE_BUILTIN_FN
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* CORE MODULE METHODS */
|
||||
/*****************************************************************************/
|
||||
@ -744,8 +806,8 @@ static Module* newModuleInternal(PKVM* vm, const char* name) {
|
||||
// Check if any module with the same name already exists and assert to the
|
||||
// hosting application.
|
||||
if (!IS_UNDEF(mapGet(vm->core_libs, VAR_OBJ(_name)))) {
|
||||
__ASSERT(false, stringFormat(vm,
|
||||
"A module named '$' already exists", name)->data);
|
||||
ASSERT(false, stringFormat(vm,
|
||||
"A module named '$' already exists", name)->data);
|
||||
}
|
||||
|
||||
Module* module = newModule(vm, _name, true);
|
||||
@ -1165,64 +1227,10 @@ DEF(stdFiberResume,
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* CORE INITIALIZATION */
|
||||
/*****************************************************************************/
|
||||
|
||||
static void initializeBuiltinFN(PKVM* vm, Closure** bfn, const char* name,
|
||||
int length, int arity, pkNativeFn ptr,
|
||||
const char* docstring) {
|
||||
|
||||
Function* fn = newFunction(vm, name, length, NULL, true, docstring, NULL);
|
||||
fn->arity = arity;
|
||||
fn->native = ptr;
|
||||
|
||||
vmPushTempRef(vm, &fn->_super); // fn.
|
||||
*bfn = newClosure(vm, fn);
|
||||
vmPopTempRef(vm); // fn.
|
||||
}
|
||||
|
||||
void initializeCore(PKVM* vm) {
|
||||
|
||||
#define INITIALIZE_BUILTIN_FN(name, fn, argc) \
|
||||
initializeBuiltinFN(vm, &vm->builtins[vm->builtins_count++], name, \
|
||||
(int)strlen(name), argc, fn, DOCSTRING(fn));
|
||||
|
||||
static void initializeCoreModules(PKVM* vm) {
|
||||
#define MODULE_ADD_FN(module, name, fn, argc) \
|
||||
moduleAddFunctionInternal(vm, module, name, fn, argc, DOCSTRING(fn))
|
||||
|
||||
// Initialize builtin functions.
|
||||
INITIALIZE_BUILTIN_FN("type_name", coreTypeName, 1);
|
||||
|
||||
// TODO: Add 'is' keyword with modules for builtin types.
|
||||
// ex: val is Num; val is null; val is List; val is Range
|
||||
// List.append(l, e) # List is implicitly imported core module.
|
||||
// String.lower(s)
|
||||
|
||||
INITIALIZE_BUILTIN_FN("help", coreHelp, -1);
|
||||
INITIALIZE_BUILTIN_FN("assert", coreAssert, -1);
|
||||
INITIALIZE_BUILTIN_FN("bin", coreBin, 1);
|
||||
INITIALIZE_BUILTIN_FN("hex", coreHex, 1);
|
||||
INITIALIZE_BUILTIN_FN("yield", coreYield, -1);
|
||||
INITIALIZE_BUILTIN_FN("to_string", coreToString, 1);
|
||||
INITIALIZE_BUILTIN_FN("print", corePrint, -1);
|
||||
INITIALIZE_BUILTIN_FN("input", coreInput, -1);
|
||||
INITIALIZE_BUILTIN_FN("exit", coreExit, -1);
|
||||
|
||||
// String functions.
|
||||
INITIALIZE_BUILTIN_FN("str_sub", coreStrSub, 3);
|
||||
INITIALIZE_BUILTIN_FN("str_chr", coreStrChr, 1);
|
||||
INITIALIZE_BUILTIN_FN("str_ord", coreStrOrd, 1);
|
||||
|
||||
// List functions.
|
||||
INITIALIZE_BUILTIN_FN("list_append", coreListAppend, 2);
|
||||
INITIALIZE_BUILTIN_FN("list_join", coreListJoin, 1);
|
||||
|
||||
// Map functions.
|
||||
INITIALIZE_BUILTIN_FN("map_remove", coreMapRemove, 2);
|
||||
|
||||
// Core Modules /////////////////////////////////////////////////////////////
|
||||
|
||||
Module* lang = newModuleInternal(vm, "lang");
|
||||
MODULE_ADD_FN(lang, "clock", stdLangClock, 0);
|
||||
MODULE_ADD_FN(lang, "gc", stdLangGC, 0);
|
||||
@ -1233,31 +1241,31 @@ void initializeCore(PKVM* vm) {
|
||||
#endif
|
||||
|
||||
Module* math = newModuleInternal(vm, "math");
|
||||
MODULE_ADD_FN(math, "floor", stdMathFloor, 1);
|
||||
MODULE_ADD_FN(math, "ceil", stdMathCeil, 1);
|
||||
MODULE_ADD_FN(math, "pow", stdMathPow, 2);
|
||||
MODULE_ADD_FN(math, "sqrt", stdMathSqrt, 1);
|
||||
MODULE_ADD_FN(math, "abs", stdMathAbs, 1);
|
||||
MODULE_ADD_FN(math, "sign", stdMathSign, 1);
|
||||
MODULE_ADD_FN(math, "hash", stdMathHash, 1);
|
||||
MODULE_ADD_FN(math, "sin", stdMathSine, 1);
|
||||
MODULE_ADD_FN(math, "cos", stdMathCosine, 1);
|
||||
MODULE_ADD_FN(math, "tan", stdMathTangent, 1);
|
||||
MODULE_ADD_FN(math, "sinh", stdMathSinh, 1);
|
||||
MODULE_ADD_FN(math, "cosh", stdMathCosh, 1);
|
||||
MODULE_ADD_FN(math, "tanh", stdMathTanh, 1);
|
||||
MODULE_ADD_FN(math, "asin", stdMathArcSine, 1);
|
||||
MODULE_ADD_FN(math, "acos", stdMathArcCosine, 1);
|
||||
MODULE_ADD_FN(math, "atan", stdMathArcTangent, 1);
|
||||
MODULE_ADD_FN(math, "log10", stdMathLog10, 1);
|
||||
MODULE_ADD_FN(math, "round", stdMathRound, 1);
|
||||
MODULE_ADD_FN(math, "log2", stdMathLog2, 1);
|
||||
MODULE_ADD_FN(math, "hypot", stdMathHypot, 2);
|
||||
MODULE_ADD_FN(math, "cbrt", stdMathCbrt, 1);
|
||||
MODULE_ADD_FN(math, "gamma", stdMathGamma, 1);
|
||||
MODULE_ADD_FN(math, "lgamma",stdMathLgamma, 1);
|
||||
MODULE_ADD_FN(math, "erf", stdMathErf, 1);
|
||||
MODULE_ADD_FN(math, "erfc", stdMathErfc, 1);
|
||||
MODULE_ADD_FN(math, "floor", stdMathFloor, 1);
|
||||
MODULE_ADD_FN(math, "ceil", stdMathCeil, 1);
|
||||
MODULE_ADD_FN(math, "pow", stdMathPow, 2);
|
||||
MODULE_ADD_FN(math, "sqrt", stdMathSqrt, 1);
|
||||
MODULE_ADD_FN(math, "abs", stdMathAbs, 1);
|
||||
MODULE_ADD_FN(math, "sign", stdMathSign, 1);
|
||||
MODULE_ADD_FN(math, "hash", stdMathHash, 1);
|
||||
MODULE_ADD_FN(math, "sin", stdMathSine, 1);
|
||||
MODULE_ADD_FN(math, "cos", stdMathCosine, 1);
|
||||
MODULE_ADD_FN(math, "tan", stdMathTangent, 1);
|
||||
MODULE_ADD_FN(math, "sinh", stdMathSinh, 1);
|
||||
MODULE_ADD_FN(math, "cosh", stdMathCosh, 1);
|
||||
MODULE_ADD_FN(math, "tanh", stdMathTanh, 1);
|
||||
MODULE_ADD_FN(math, "asin", stdMathArcSine, 1);
|
||||
MODULE_ADD_FN(math, "acos", stdMathArcCosine, 1);
|
||||
MODULE_ADD_FN(math, "atan", stdMathArcTangent, 1);
|
||||
MODULE_ADD_FN(math, "log10", stdMathLog10, 1);
|
||||
MODULE_ADD_FN(math, "round", stdMathRound, 1);
|
||||
MODULE_ADD_FN(math, "log2", stdMathLog2, 1);
|
||||
MODULE_ADD_FN(math, "hypot", stdMathHypot, 2);
|
||||
MODULE_ADD_FN(math, "cbrt", stdMathCbrt, 1);
|
||||
MODULE_ADD_FN(math, "gamma", stdMathGamma, 1);
|
||||
MODULE_ADD_FN(math, "lgamma", stdMathLgamma, 1);
|
||||
MODULE_ADD_FN(math, "erf", stdMathErf, 1);
|
||||
MODULE_ADD_FN(math, "erfc", stdMathErfc, 1);
|
||||
|
||||
// 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
|
||||
@ -1265,12 +1273,17 @@ void initializeCore(PKVM* vm) {
|
||||
moduleAddGlobal(vm, math, "PI", 2, VAR_NUM(M_PI));
|
||||
|
||||
Module* fiber = newModuleInternal(vm, "Fiber");
|
||||
MODULE_ADD_FN(fiber, "new", stdFiberNew, 1);
|
||||
MODULE_ADD_FN(fiber, "run", stdFiberRun, -1);
|
||||
MODULE_ADD_FN(fiber, "resume", stdFiberResume, -1);
|
||||
MODULE_ADD_FN(fiber, "new", stdFiberNew, 1);
|
||||
MODULE_ADD_FN(fiber, "run", stdFiberRun, -1);
|
||||
MODULE_ADD_FN(fiber, "resume", stdFiberResume, -1);
|
||||
|
||||
#undef MODULE_ADD_FN
|
||||
}
|
||||
|
||||
#undef IS_NUM_BYTE
|
||||
#undef DOCSTRING
|
||||
#undef DEF
|
||||
|
||||
/*****************************************************************************/
|
||||
/* OPERATORS */
|
||||
/*****************************************************************************/
|
||||
@ -1308,17 +1321,6 @@ Var varAdd(PKVM* vm, Var v1, Var v2) {
|
||||
return VAR_OBJ(listJoin(vm, (List*)o1, (List*)o2));
|
||||
}
|
||||
} break;
|
||||
|
||||
case OBJ_MAP:
|
||||
case OBJ_RANGE:
|
||||
case OBJ_MODULE:
|
||||
case OBJ_FUNC:
|
||||
case OBJ_CLOSURE:
|
||||
case OBJ_UPVALUE:
|
||||
case OBJ_FIBER:
|
||||
case OBJ_CLASS:
|
||||
case OBJ_INST:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1522,32 +1524,19 @@ bool varContains(PKVM* vm, Var elem, Var container) {
|
||||
Map* map = (Map*)AS_OBJ(container);
|
||||
return !IS_UNDEF(mapGet(map, elem));
|
||||
} break;
|
||||
|
||||
case OBJ_RANGE:
|
||||
case OBJ_MODULE:
|
||||
case OBJ_FUNC:
|
||||
case OBJ_CLOSURE:
|
||||
case OBJ_UPVALUE:
|
||||
case OBJ_FIBER:
|
||||
case OBJ_CLASS:
|
||||
case OBJ_INST:
|
||||
TODO;
|
||||
}
|
||||
UNREACHABLE();
|
||||
|
||||
VM_SET_ERROR(vm, stringFormat(vm, "Argument of type $ is not iterable.",
|
||||
varTypeName(container)));
|
||||
return VAR_NULL;
|
||||
}
|
||||
|
||||
// TODO: The ERR_NO_ATTRIB() macro should splitted into 2 to for setter and
|
||||
// getter and for the setter, the error message should be "object has no
|
||||
// mutable attribute", to indicate that there might be an attribute with the
|
||||
// name might be exists (but not accessed in a setter).
|
||||
Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
||||
|
||||
// Set error for accessing non-existed attribute.
|
||||
#define ERR_NO_ATTRIB(vm, on, attrib) \
|
||||
VM_SET_ERROR(vm, stringFormat(vm, "'$' object has no attribute named '$'", \
|
||||
varTypeName(on), attrib->data))
|
||||
|
||||
Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
||||
|
||||
if (!IS_OBJ(on)) {
|
||||
VM_SET_ERROR(vm, stringFormat(vm, "$ type is not subscriptable.",
|
||||
varTypeName(on)));
|
||||
@ -1556,8 +1545,7 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
||||
|
||||
Object* obj = AS_OBJ(on);
|
||||
switch (obj->type) {
|
||||
case OBJ_STRING:
|
||||
{
|
||||
case OBJ_STRING: {
|
||||
String* str = (String*)obj;
|
||||
switch (attrib->hash) {
|
||||
|
||||
@ -1572,42 +1560,26 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
||||
|
||||
case CHECK_HASH("strip", 0xfd1b18d1):
|
||||
return VAR_OBJ(stringStrip(vm, str));
|
||||
|
||||
default:
|
||||
ERR_NO_ATTRIB(vm, on, attrib);
|
||||
return VAR_NULL;
|
||||
}
|
||||
} break;
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
case OBJ_LIST:
|
||||
{
|
||||
case OBJ_LIST: {
|
||||
List* list = (List*)obj;
|
||||
switch (attrib->hash) {
|
||||
|
||||
case CHECK_HASH("length", 0x83d03615):
|
||||
return VAR_NUM((double)(list->elements.count));
|
||||
|
||||
default:
|
||||
ERR_NO_ATTRIB(vm, on, attrib);
|
||||
return VAR_NULL;
|
||||
}
|
||||
} break;
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
case OBJ_MAP:
|
||||
{
|
||||
case OBJ_MAP: {
|
||||
// map = { "foo" : 42, "can't access" : 32 }
|
||||
// val = map.foo ## <-- This should be error
|
||||
// Only the map's attributes are accessed here.
|
||||
TODO;
|
||||
UNREACHABLE();
|
||||
}
|
||||
} break;
|
||||
|
||||
case OBJ_RANGE:
|
||||
{
|
||||
case OBJ_RANGE: {
|
||||
Range* range = (Range*)obj;
|
||||
switch (attrib->hash) {
|
||||
|
||||
@ -1623,17 +1595,10 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
||||
|
||||
case CHECK_HASH("last", 0x63e1d819):
|
||||
return VAR_NUM(range->to);
|
||||
|
||||
default:
|
||||
ERR_NO_ATTRIB(vm, on, attrib);
|
||||
return VAR_NULL;
|
||||
}
|
||||
} break;
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
case OBJ_MODULE:
|
||||
{
|
||||
case OBJ_MODULE: {
|
||||
Module* module = (Module*)obj;
|
||||
|
||||
// Search in globals.
|
||||
@ -1642,19 +1607,12 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
||||
ASSERT_INDEX((uint32_t)index, module->globals.count);
|
||||
return module->globals.data[index];
|
||||
}
|
||||
|
||||
ERR_NO_ATTRIB(vm, on, attrib);
|
||||
return VAR_NULL;
|
||||
}
|
||||
} break;
|
||||
|
||||
case OBJ_FUNC:
|
||||
{
|
||||
// Functions aren't first class objects.
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
|
||||
case OBJ_CLOSURE:
|
||||
{
|
||||
case OBJ_CLOSURE: {
|
||||
Closure* closure = (Closure*)obj;
|
||||
switch (attrib->hash) {
|
||||
|
||||
@ -1663,58 +1621,51 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
||||
|
||||
case CHECK_HASH("name", 0x8d39bde6):
|
||||
return VAR_OBJ(newString(vm, closure->fn->name));
|
||||
|
||||
default:
|
||||
ERR_NO_ATTRIB(vm, on, attrib);
|
||||
return VAR_NULL;
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
case OBJ_UPVALUE:
|
||||
// Upvalues aren't first class objects.
|
||||
UNREACHABLE();
|
||||
UNREACHABLE(); // Upvalues aren't first class objects.
|
||||
break;
|
||||
|
||||
case OBJ_FIBER:
|
||||
{
|
||||
Fiber* fb = (Fiber*)obj;
|
||||
switch (attrib->hash) {
|
||||
case OBJ_FIBER: {
|
||||
Fiber* fb = (Fiber*)obj;
|
||||
switch (attrib->hash) {
|
||||
|
||||
case CHECK_HASH("is_done", 0x789c2706):
|
||||
return VAR_BOOL(fb->state == FIBER_DONE);
|
||||
case CHECK_HASH("is_done", 0x789c2706):
|
||||
return VAR_BOOL(fb->state == FIBER_DONE);
|
||||
|
||||
case CHECK_HASH("function", 0x9ed64249):
|
||||
return VAR_OBJ(fb->closure);
|
||||
|
||||
default:
|
||||
ERR_NO_ATTRIB(vm, on, attrib);
|
||||
return VAR_NULL;
|
||||
}
|
||||
UNREACHABLE();
|
||||
case CHECK_HASH("function", 0x9ed64249):
|
||||
return VAR_OBJ(fb->closure);
|
||||
}
|
||||
} break;
|
||||
|
||||
case OBJ_CLASS:
|
||||
TODO;
|
||||
UNREACHABLE();
|
||||
break;
|
||||
|
||||
case OBJ_INST:
|
||||
{
|
||||
case OBJ_INST: {
|
||||
Var value;
|
||||
if (!instGetAttrib(vm, (Instance*)obj, attrib, &value)) {
|
||||
ERR_NO_ATTRIB(vm, on, attrib);
|
||||
return VAR_NULL;
|
||||
if (instGetAttrib(vm, (Instance*)obj, attrib, &value)) {
|
||||
return value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
} break;
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
ERR_NO_ATTRIB(vm, on, attrib);
|
||||
return VAR_NULL;
|
||||
|
||||
#undef ERR_NO_ATTRIB
|
||||
}
|
||||
|
||||
void varSetAttrib(PKVM* vm, Var on, String* attrib, Var value) {
|
||||
|
||||
// Set error for accessing non-existed attribute.
|
||||
#define ERR_NO_ATTRIB(vm, on, attrib) \
|
||||
VM_SET_ERROR(vm, stringFormat(vm, \
|
||||
"'$' object has no mutable attribute named '$'", \
|
||||
varTypeName(on), attrib->data))
|
||||
|
||||
#define ATTRIB_IMMUTABLE(name) \
|
||||
do { \
|
||||
if ((attrib->length == strlen(name) && strcmp(name, attrib->data) == 0)) { \
|
||||
@ -1745,12 +1696,7 @@ do { \
|
||||
return;
|
||||
|
||||
case OBJ_MAP:
|
||||
// Not sure should I allow string values could be accessed with
|
||||
// this way. ex:
|
||||
// map = { "foo" : 42, "can't access" : 32 }
|
||||
// map.foo = 'bar'
|
||||
TODO;
|
||||
|
||||
ERR_NO_ATTRIB(vm, on, attrib);
|
||||
return;
|
||||
|
||||
@ -1763,22 +1709,16 @@ do { \
|
||||
|
||||
case OBJ_MODULE: {
|
||||
Module* module = (Module*)obj;
|
||||
|
||||
// Check globals.
|
||||
int index = moduleGetGlobalIndex(module, attrib->data, attrib->length);
|
||||
if (index != -1) {
|
||||
ASSERT_INDEX((uint32_t)index, module->globals.count);
|
||||
module->globals.data[index] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
ERR_NO_ATTRIB(vm, on, attrib);
|
||||
return;
|
||||
}
|
||||
} break;
|
||||
|
||||
case OBJ_FUNC:
|
||||
// Functions aren't first class objects.
|
||||
UNREACHABLE();
|
||||
UNREACHABLE(); // Functions aren't first class objects.
|
||||
return;
|
||||
|
||||
case OBJ_CLOSURE:
|
||||
@ -1788,8 +1728,7 @@ do { \
|
||||
return;
|
||||
|
||||
case OBJ_UPVALUE:
|
||||
// Upvalues aren't first class objects.
|
||||
UNREACHABLE();
|
||||
UNREACHABLE(); // Upvalues aren't first class objects.
|
||||
return;
|
||||
|
||||
case OBJ_FIBER:
|
||||
@ -1800,8 +1739,7 @@ do { \
|
||||
ERR_NO_ATTRIB(vm, on, attrib);
|
||||
return;
|
||||
|
||||
case OBJ_INST:
|
||||
{
|
||||
case OBJ_INST: {
|
||||
if (!instSetAttrib(vm, (Instance*)obj, attrib, value)) {
|
||||
// If we has error by now, that means the set value type is
|
||||
// incompatible. No need for us to set an other error, just return.
|
||||
@ -1812,17 +1750,15 @@ do { \
|
||||
// If we reached here, that means the attribute exists and we have
|
||||
// updated the value.
|
||||
return;
|
||||
}
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
} break;
|
||||
}
|
||||
UNREACHABLE();
|
||||
|
||||
ERR_NO_ATTRIB(vm, on, attrib);
|
||||
return;
|
||||
|
||||
#undef ATTRIB_IMMUTABLE
|
||||
}
|
||||
|
||||
#undef ERR_NO_ATTRIB
|
||||
}
|
||||
|
||||
Var varGetSubscript(PKVM* vm, Var on, Var key) {
|
||||
if (!IS_OBJ(on)) {
|
||||
@ -1833,8 +1769,7 @@ Var varGetSubscript(PKVM* vm, Var on, Var key) {
|
||||
|
||||
Object* obj = AS_OBJ(on);
|
||||
switch (obj->type) {
|
||||
case OBJ_STRING:
|
||||
{
|
||||
case OBJ_STRING: {
|
||||
int64_t index;
|
||||
String* str = ((String*)obj);
|
||||
if (!validateInteger(vm, key, &index, "List index")) {
|
||||
@ -1845,10 +1780,9 @@ Var varGetSubscript(PKVM* vm, Var on, Var key) {
|
||||
}
|
||||
String* c = newStringLength(vm, str->data + index, 1);
|
||||
return VAR_OBJ(c);
|
||||
}
|
||||
} break;
|
||||
|
||||
case OBJ_LIST:
|
||||
{
|
||||
case OBJ_LIST: {
|
||||
int64_t index;
|
||||
pkVarBuffer* elems = &((List*)obj)->elements;
|
||||
if (!validateInteger(vm, key, &index, "List index")) {
|
||||
@ -1858,10 +1792,9 @@ Var varGetSubscript(PKVM* vm, Var on, Var key) {
|
||||
return VAR_NULL;
|
||||
}
|
||||
return elems->data[index];
|
||||
}
|
||||
} break;
|
||||
|
||||
case OBJ_MAP:
|
||||
{
|
||||
case OBJ_MAP: {
|
||||
Var value = mapGet((Map*)obj, key);
|
||||
if (IS_UNDEF(value)) {
|
||||
|
||||
@ -1876,24 +1809,16 @@ Var varGetSubscript(PKVM* vm, Var on, Var key) {
|
||||
return VAR_NULL;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
} break;
|
||||
|
||||
case OBJ_RANGE:
|
||||
case OBJ_MODULE:
|
||||
case OBJ_FUNC:
|
||||
case OBJ_CLOSURE:
|
||||
case OBJ_UPVALUE:
|
||||
case OBJ_FIBER:
|
||||
case OBJ_CLASS:
|
||||
case OBJ_INST:
|
||||
TODO;
|
||||
UNREACHABLE();
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
UNREACHABLE(); // Not first class objects.
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
VM_SET_ERROR(vm, stringFormat(vm, "$ type is not subscriptable.",
|
||||
varTypeName(on)));
|
||||
return VAR_NULL;
|
||||
}
|
||||
|
||||
void varsetSubscript(PKVM* vm, Var on, Var key, Var value) {
|
||||
@ -1905,22 +1830,16 @@ void varsetSubscript(PKVM* vm, Var on, Var key, Var value) {
|
||||
|
||||
Object* obj = AS_OBJ(on);
|
||||
switch (obj->type) {
|
||||
case OBJ_STRING:
|
||||
VM_SET_ERROR(vm, newString(vm, "String objects are immutable."));
|
||||
return;
|
||||
|
||||
case OBJ_LIST:
|
||||
{
|
||||
case OBJ_LIST: {
|
||||
int64_t index;
|
||||
pkVarBuffer* elems = &((List*)obj)->elements;
|
||||
if (!validateInteger(vm, key, &index, "List index")) return;
|
||||
if (!validateIndex(vm, index, elems->count, "List")) return;
|
||||
elems->data[index] = value;
|
||||
return;
|
||||
}
|
||||
} break;
|
||||
|
||||
case OBJ_MAP:
|
||||
{
|
||||
case OBJ_MAP: {
|
||||
if (IS_OBJ(key) && !isObjectHashable(AS_OBJ(key)->type)) {
|
||||
VM_SET_ERROR(vm, stringFormat(vm, "$ type is not hashable.",
|
||||
varTypeName(key)));
|
||||
@ -1928,27 +1847,14 @@ void varsetSubscript(PKVM* vm, Var on, Var key, Var value) {
|
||||
mapSet(vm, (Map*)obj, key, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} break;
|
||||
|
||||
case OBJ_RANGE:
|
||||
case OBJ_MODULE:
|
||||
case OBJ_FUNC:
|
||||
case OBJ_CLOSURE:
|
||||
case OBJ_UPVALUE:
|
||||
case OBJ_FIBER:
|
||||
case OBJ_CLASS:
|
||||
case OBJ_INST:
|
||||
TODO;
|
||||
UNREACHABLE();
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
VM_SET_ERROR(vm, stringFormat(vm, "$ type is not subscriptable.",
|
||||
varTypeName(on)));
|
||||
return;
|
||||
}
|
||||
|
||||
#undef IS_NUM_BYTE
|
||||
|
||||
#undef DOCSTRING
|
||||
#undef DEF
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#include "pk_common.h"
|
||||
|
||||
// Commonly used c standard headers across the sources. Don't include any
|
||||
// Commonly used C standard headers across the sources. Don't include any
|
||||
// headers that are specific to a single source here, instead include them in
|
||||
// their source files explicitly (can not be implicitly included by another
|
||||
// header). And don't include any C standard headers in any of the pocketlang
|
||||
@ -125,4 +125,45 @@
|
||||
//
|
||||
#define CHECK_HASH(name, hash) hash
|
||||
|
||||
// The formated string to convert double to string. It'll be with the minimum
|
||||
// length string representation of either a regular float or a scientific
|
||||
// notation (at most 15 decimal points).
|
||||
// Reference: https://www.cplusplus.com/reference/cstdio/printf/
|
||||
#define DOUBLE_FMT "%.16g"
|
||||
|
||||
// Double number to string buffer size, used in sprintf with DOUBLE_FMT.
|
||||
// A largest number : "-1.234567890123456e+308"
|
||||
// + 1 fot sign '+' or '-'
|
||||
// + 16 fot significant digits
|
||||
// + 1 for decimal point '.'
|
||||
// + 1 for exponent char 'e'
|
||||
// + 1 for sign of exponent
|
||||
// + 3 for the exponent digits
|
||||
// + 1 for null byte '\0'
|
||||
#define STR_DBL_BUFF_SIZE 24
|
||||
|
||||
// Integer number to string buffer size, used in sprintf with format "%d".
|
||||
// The minimum 32 bit integer = -2147483648
|
||||
// + 1 for sign '-'
|
||||
// + 10 for digits
|
||||
// + 1 for null byte '\0'
|
||||
#define STR_INT_BUFF_SIZE 12
|
||||
|
||||
// Integer number (double) to hex string buffer size.
|
||||
// The maximum value an unsigned 64 bit integer can get is
|
||||
// 0xffffffffffffffff which is 16 characters.
|
||||
// + 16 for hex digits
|
||||
// + 1 for sign '-'
|
||||
// + 2 for '0x' prefix
|
||||
// + 1 for null byte '\0'
|
||||
#define STR_HEX_BUFF_SIZE 20
|
||||
|
||||
// Integer number (double) to bin string buffer size.
|
||||
// The maximum value an unsigned 64 bit integer can get is 0b11111... 64 1s.
|
||||
// + 64 for bin digits
|
||||
// + 1 for sign '-'
|
||||
// + 2 for '0b' prefix
|
||||
// + 1 for null byte '\0'
|
||||
#define STR_BIN_BUFF_SIZE 68
|
||||
|
||||
#endif // PK_INTERNAL
|
||||
|
@ -1242,8 +1242,8 @@ bool instGetAttrib(PKVM* vm, Instance* inst, String* attrib, Var* value) {
|
||||
if (IS_UNDEF(val)) {
|
||||
|
||||
// FIXME: add a list of attribute overrides.
|
||||
if (IS_CSTR_EQ(attrib, "as_string", 9,
|
||||
CHECK_HASH("as_string", 0xbdef4147))) {
|
||||
if ((CHECK_HASH("as_string", 0xbdef4147) == attrib->hash) &&
|
||||
IS_CSTR_EQ(attrib, "as_string", 9)) {
|
||||
*value = VAR_OBJ(toRepr(vm, VAR_OBJ(inst)));
|
||||
return true;
|
||||
}
|
||||
|
@ -137,11 +137,10 @@
|
||||
((s1)->length == (s2)->length) && \
|
||||
(memcmp((const void*)(s1)->data, (const void*)(s2)->data, (s1)->length) == 0))
|
||||
|
||||
// Compare pocket string with c string.
|
||||
#define IS_CSTR_EQ(str, cstr, len, chash) \
|
||||
(((str)->hash == chash) && \
|
||||
((str)->length == len) && \
|
||||
(memcmp((const void*)(str)->data, (const void*)(cstr), len) == 0))
|
||||
// Compare pocket string with C string.
|
||||
#define IS_CSTR_EQ(str, cstr, len) \
|
||||
(((str)->length == len) && \
|
||||
(memcmp((const void*)(str)->data, (const void*)(cstr), len) == 0))
|
||||
|
||||
// Decode types.
|
||||
#define AS_BOOL(value) ((value) == VAR_TRUE)
|
||||
|
@ -1,5 +1,6 @@
|
||||
#!python
|
||||
## Copyright (c) 2020-2021 Thakee Nathees
|
||||
## Copyright (c) 2021-2022 Pocketlang Contributors
|
||||
## Distributed Under The MIT License
|
||||
|
||||
## This will run static checks on the source files, for line length,
|
||||
@ -7,8 +8,7 @@
|
||||
|
||||
import os, sys, re
|
||||
from os import listdir
|
||||
from os.path import (
|
||||
join, abspath, dirname, relpath)
|
||||
from os.path import join, abspath, dirname, relpath
|
||||
|
||||
## The absolute path of this file, when run as a script.
|
||||
## This file is not intended to be included in other files at the moment.
|
||||
@ -49,21 +49,12 @@ SOURCE_DIRS = [
|
||||
"../docs/wasm/",
|
||||
]
|
||||
|
||||
## A list of common header that just copied in different projects.
|
||||
## These common header cannot be re-used because we're trying to achieve
|
||||
## minimalistic with the count of the sources in pocketlang.
|
||||
COMMON_HEADERS = [
|
||||
"../src/pk_common.h",
|
||||
"../cli/common.h",
|
||||
]
|
||||
|
||||
## This global variable will be set to true if any check failed.
|
||||
checks_failed = False
|
||||
|
||||
def main():
|
||||
check_fnv1_hash(to_abs_paths(HASH_CHECK_LIST))
|
||||
check_static(to_abs_paths(SOURCE_DIRS))
|
||||
check_common_header_match(to_abs_paths(COMMON_HEADERS))
|
||||
if checks_failed:
|
||||
sys.exit(1)
|
||||
print("Static checks were passed.")
|
||||
@ -141,26 +132,6 @@ def check_static(dirs):
|
||||
else:
|
||||
is_last_empty = False
|
||||
|
||||
## TODO: Remove this check and resolve the cause.
|
||||
## Assert all the content of the headers list below are the same.
|
||||
## some header are re-used by copying, so changes must be reflect.
|
||||
def check_common_header_match(headers):
|
||||
headers = list(headers)
|
||||
assert len(headers) >= 1
|
||||
|
||||
content = ''
|
||||
with open(headers[0], 'r') as f:
|
||||
content = f.read()
|
||||
|
||||
for i in range(1, len(headers)):
|
||||
with open(headers[i], 'r') as f:
|
||||
if f.read() != content:
|
||||
main_header = to_rel_path(headers[0])
|
||||
curr_header = to_rel_path(headers[i])
|
||||
report_error("File content mismatch: \"%s\" and \"%s\"\n"
|
||||
" These files contants should be the same."
|
||||
%(main_header, curr_header))
|
||||
|
||||
## Returns a formated string of the error location.
|
||||
def location(file, line):
|
||||
return f"{'%-17s'%file} : {'%4s'%line}"
|
||||
|
@ -1,5 +1,6 @@
|
||||
#!python
|
||||
## Copyright (c) 2020-2021 Thakee Nathees
|
||||
## Copyright (c) 2021-2022 Pocketlang Contributors
|
||||
## Distributed Under The MIT License
|
||||
|
||||
import os, sys, platform
|
||||
|
Loading…
Reference in New Issue
Block a user