Merge pull request #198 from ThakeeNathees/minor-refactor

Yet another refactor.
This commit is contained in:
Thakee Nathees 2022-04-15 10:11:36 +05:30 committed by GitHub
commit ec569aba74
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 268 additions and 425 deletions

View File

@ -28,8 +28,7 @@
// The internal assertion macro, this will print error and break regardless of // The internal assertion macro, this will print error and break regardless of
// the build target (debug or release). Use ASSERT() for debug assertion and // the build target (debug or release). Use ASSERT() for debug assertion and
// use __ASSERT() for TODOs and assertions in public methods (to indicate that // use __ASSERT() for TODOs.
// the host application did something wrong).
#define __ASSERT(condition, message) \ #define __ASSERT(condition, message) \
do { \ do { \
if (!(condition)) { \ if (!(condition)) { \
@ -111,45 +110,4 @@
#define TODO __ASSERT(false, "TODO: It hasn't implemented yet.") #define TODO __ASSERT(false, "TODO: It hasn't implemented yet.")
#define OOPS "Oops a bug!! report please." #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 #endif //PK_COMMON_H

View File

@ -242,8 +242,15 @@ PK_PUBLIC void pkReleaseHandle(PKVM* vm, PkHandle* handle);
PK_PUBLIC void pkModuleAddGlobal(PKVM* vm, PkHandle* module, PK_PUBLIC void pkModuleAddGlobal(PKVM* vm, PkHandle* module,
const char* name, PkHandle* value); 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 // 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. // 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, PK_PUBLIC void pkModuleAddFunction(PKVM* vm, PkHandle* module,
const char* name, const char* name,
pkNativeFn fptr, int arity); pkNativeFn fptr, int arity);

View File

@ -28,8 +28,7 @@
// The internal assertion macro, this will print error and break regardless of // The internal assertion macro, this will print error and break regardless of
// the build target (debug or release). Use ASSERT() for debug assertion and // the build target (debug or release). Use ASSERT() for debug assertion and
// use __ASSERT() for TODOs and assertions in public methods (to indicate that // use __ASSERT() for TODOs.
// the host application did something wrong).
#define __ASSERT(condition, message) \ #define __ASSERT(condition, message) \
do { \ do { \
if (!(condition)) { \ if (!(condition)) { \
@ -111,45 +110,4 @@
#define TODO __ASSERT(false, "TODO: It hasn't implemented yet.") #define TODO __ASSERT(false, "TODO: It hasn't implemented yet.")
#define OOPS "Oops a bug!! report please." #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 #endif //PK_COMMON_H

View File

@ -607,6 +607,16 @@ static void resolveError(Compiler* compiler, int line, const char* fmt, ...) {
va_end(args); 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 */ /* LEXING */
/*****************************************************************************/ /*****************************************************************************/
@ -2085,10 +2095,7 @@ static int compilerAddConstant(Compiler* compiler, Var value) {
uint32_t index = moduleAddConstant(compiler->parser.vm, uint32_t index = moduleAddConstant(compiler->parser.vm,
compiler->module, value); compiler->module, value);
if (index >= MAX_CONSTANTS) { checkMaxConstantsReached(compiler, index);
parseError(compiler, "A module should contain at most %d "
"unique constants.", MAX_CONSTANTS);
}
return (int)index; return (int)index;
} }
@ -2289,10 +2296,8 @@ static void compileClass(Compiler* compiler) {
moduleSetGlobal(compiler->module, index, VAR_OBJ(cls)); moduleSetGlobal(compiler->module, index, VAR_OBJ(cls));
// Check count exceeded. // Check count exceeded.
if (cls_index >= MAX_CONSTANTS || ctor_index >= MAX_CONSTANTS) { checkMaxConstantsReached(compiler, cls_index);
parseError(compiler, "A module should contain at most %d " checkMaxConstantsReached(compiler, ctor_index);
"unique constants.", MAX_CONSTANTS);
}
// Compile the constructor function. // Compile the constructor function.
ASSERT(compiler->func->ptr == compiler->module->body->fn, OOPS); ASSERT(compiler->func->ptr == compiler->module->body->fn, OOPS);
@ -2371,10 +2376,7 @@ static void compileFunction(Compiler* compiler, bool is_literal) {
int fn_index; int fn_index;
Function* func = newFunction(compiler->parser.vm, name, name_length, Function* func = newFunction(compiler->parser.vm, name, name_length,
compiler->module, false, NULL, &fn_index); compiler->module, false, NULL, &fn_index);
if (fn_index >= MAX_CONSTANTS) { checkMaxConstantsReached(compiler, fn_index);
parseError(compiler, "A module should contain at most %d "
"unique constants.", MAX_CONSTANTS);
}
if (!is_literal) { if (!is_literal) {
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS); ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS);

View File

@ -32,10 +32,6 @@
static const char* DOCSTRING(fn) = docstring; \ static const char* DOCSTRING(fn) = docstring; \
static void fn(PKVM* vm) static void fn(PKVM* vm)
/*****************************************************************************/
/* CORE PUBLIC API */
/*****************************************************************************/
// Create a new module with the given [name] and returns as a Module* for // 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*. // internal. Which will be wrapped by pkNewModule to return a pkHandle*.
static Module* newModuleInternal(PKVM* vm, const char* name); static Module* newModuleInternal(PKVM* vm, const char* name);
@ -46,42 +42,58 @@ static void moduleAddFunctionInternal(PKVM* vm, Module* module,
const char* name, pkNativeFn fptr, const char* name, pkNativeFn fptr,
int arity, const char* docstring); int arity, const char* docstring);
/*****************************************************************************/
/* CORE PUBLIC API */
/*****************************************************************************/
PkHandle* pkNewModule(PKVM* vm, const char* name) { PkHandle* pkNewModule(PKVM* vm, const char* name) {
Module* module = newModuleInternal(vm, name); Module* module = newModuleInternal(vm, name);
return vmNewHandle(vm, VAR_OBJ(module)); 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) { const char* name, PkHandle* value) {
__ASSERT(module != NULL, "Argument module was NULL."); ASSERT(module != NULL, "Argument module was NULL.");
__ASSERT(value != NULL, "Argument value was NULL."); ASSERT(value != NULL, "Argument value was NULL.");
__ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE), ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
"Given handle is not a module."); "Given handle is not a module.");
moduleAddGlobal(vm, (Module*)AS_OBJ(module->value), moduleAddGlobal(vm, (Module*)AS_OBJ(module->value),
name, (uint32_t)strlen(name), value->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, void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name,
pkNativeFn fptr, int arity) { pkNativeFn fptr, int arity) {
__ASSERT(module != NULL, "Argument module was NULL."); ASSERT(module != NULL, "Argument module was NULL.");
__ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE), ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
"Given handle is not a module."); "Given handle is not a module.");
moduleAddFunctionInternal(vm, (Module*)AS_OBJ(module->value), moduleAddFunctionInternal(vm, (Module*)AS_OBJ(module->value),
name, fptr, arity, name, fptr, arity,
NULL /*TODO: Public API for function docstring.*/); NULL /*TODO: Public API for function docstring.*/);
} }
PkHandle* pkGetMainFunction(PKVM* vm, PkHandle* module) { PkHandle* pkGetMainFunction(PKVM* vm, PkHandle* module) {
__ASSERT(module != NULL, "Argument module was NULL."); ASSERT(module != NULL, "Argument module was NULL.");
__ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE), ASSERT(IS_OBJ_TYPE(module->value, OBJ_MODULE),
"Given handle is not a module."); "Given handle is not a module.");
Module* _module = (Module*)AS_OBJ(module->value); Module* _module = (Module*)AS_OBJ(module->value);
int main_index = moduleGetGlobalIndex(_module, IMPLICIT_MAIN_NAME, int main_index = moduleGetGlobalIndex(_module, IMPLICIT_MAIN_NAME,
(uint32_t)strlen(IMPLICIT_MAIN_NAME)); (uint32_t)strlen(IMPLICIT_MAIN_NAME));
if (main_index == -1) return NULL; 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]; Var main_fn = _module->globals.data[main_index];
ASSERT(IS_OBJ_TYPE(main_fn, OBJ_CLOSURE), OOPS); ASSERT(IS_OBJ_TYPE(main_fn, OBJ_CLOSURE), OOPS);
return vmNewHandle(vm, main_fn); 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. // Check for errors in before calling the get arg public api function.
#define CHECK_GET_ARG_API_ERRORS() \ #define CHECK_GET_ARG_API_ERRORS() \
do { \ do { \
__ASSERT(vm->fiber != NULL, \ ASSERT(vm->fiber != NULL, \
"This function can only be called at runtime."); \ "This function can only be called at runtime."); \
if (arg != 0) {/* If Native setter, the value would be at fiber->ret */ \ 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) } while (false)
// Set error for incompatible type provided as an argument. (TODO: got type). // Set error for incompatible type provided as an argument. (TODO: got type).
@ -132,7 +144,7 @@ do { \
} while (false) } while (false)
int pkGetArgc(const PKVM* vm) { 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; return ARGC;
} }
@ -156,8 +168,8 @@ bool pkCheckArgcRange(PKVM* vm, int argc, int min, int max) {
} }
PkVar pkGetArg(const PKVM* vm, int arg) { PkVar pkGetArg(const PKVM* vm, int arg) {
__ASSERT(vm->fiber != NULL, "This function can only be called at runtime."); ASSERT(vm->fiber != NULL, "This function can only be called at runtime.");
__ASSERT(arg > 0 || arg <= ARGC, "Invalid argument index."); ASSERT(arg > 0 || arg <= ARGC, "Invalid argument index.");
return &(ARG(arg)); return &(ARG(arg));
} }
@ -281,22 +293,22 @@ void pkReturnInstNative(PKVM* vm, void* data, uint32_t id) {
const char* pkStringGetData(const PkVar value) { const char* pkStringGetData(const PkVar value) {
const Var str = (*(const Var*)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; return ((String*)AS_OBJ(str))->data;
} }
PkVar pkFiberGetReturnValue(const PkHandle* fiber) { PkVar pkFiberGetReturnValue(const PkHandle* fiber) {
__ASSERT(fiber != NULL, "Handle fiber was NULL."); ASSERT(fiber != NULL, "Handle fiber was NULL.");
Var fb = fiber->value; 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); Fiber* _fiber = (Fiber*)AS_OBJ(fb);
return (PkVar)_fiber->ret; return (PkVar)_fiber->ret;
} }
bool pkFiberIsDone(const PkHandle* fiber) { bool pkFiberIsDone(const PkHandle* fiber) {
__ASSERT(fiber != NULL, "Handle fiber was NULL."); ASSERT(fiber != NULL, "Handle fiber was NULL.");
Var fb = fiber->value; 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); Fiber* _fiber = (Fiber*)AS_OBJ(fb);
return _fiber->state == FIBER_DONE; return _fiber->state == FIBER_DONE;
} }
@ -399,6 +411,14 @@ static inline bool validateCond(PKVM* vm, bool condition, const char* err) {
/* SHARED FUNCTIONS */ /* 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) { Module* getCoreLib(const PKVM* vm, String* name) {
Var lib = mapGet(vm->core_libs, VAR_OBJ(name)); Var lib = mapGet(vm->core_libs, VAR_OBJ(name));
if (IS_UNDEF(lib)) return NULL; if (IS_UNDEF(lib)) return NULL;
@ -731,6 +751,48 @@ DEF(coreMapRemove,
RET(mapRemoveKey(vm, map, key)); 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 */ /* 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 // Check if any module with the same name already exists and assert to the
// hosting application. // hosting application.
if (!IS_UNDEF(mapGet(vm->core_libs, VAR_OBJ(_name)))) { if (!IS_UNDEF(mapGet(vm->core_libs, VAR_OBJ(_name)))) {
__ASSERT(false, stringFormat(vm, ASSERT(false, stringFormat(vm,
"A module named '$' already exists", name)->data); "A module named '$' already exists", name)->data);
} }
Module* module = newModule(vm, _name, true); Module* module = newModule(vm, _name, true);
@ -1165,64 +1227,10 @@ DEF(stdFiberResume,
} }
} }
/*****************************************************************************/ static void initializeCoreModules(PKVM* vm) {
/* 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));
#define MODULE_ADD_FN(module, name, fn, argc) \ #define MODULE_ADD_FN(module, name, fn, argc) \
moduleAddFunctionInternal(vm, module, name, fn, argc, DOCSTRING(fn)) 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* lang = newModuleInternal(vm, "lang");
MODULE_ADD_FN(lang, "clock", stdLangClock, 0); MODULE_ADD_FN(lang, "clock", stdLangClock, 0);
MODULE_ADD_FN(lang, "gc", stdLangGC, 0); MODULE_ADD_FN(lang, "gc", stdLangGC, 0);
@ -1233,31 +1241,31 @@ void initializeCore(PKVM* vm) {
#endif #endif
Module* math = newModuleInternal(vm, "math"); Module* math = newModuleInternal(vm, "math");
MODULE_ADD_FN(math, "floor", stdMathFloor, 1); MODULE_ADD_FN(math, "floor", stdMathFloor, 1);
MODULE_ADD_FN(math, "ceil", stdMathCeil, 1); MODULE_ADD_FN(math, "ceil", stdMathCeil, 1);
MODULE_ADD_FN(math, "pow", stdMathPow, 2); MODULE_ADD_FN(math, "pow", stdMathPow, 2);
MODULE_ADD_FN(math, "sqrt", stdMathSqrt, 1); MODULE_ADD_FN(math, "sqrt", stdMathSqrt, 1);
MODULE_ADD_FN(math, "abs", stdMathAbs, 1); MODULE_ADD_FN(math, "abs", stdMathAbs, 1);
MODULE_ADD_FN(math, "sign", stdMathSign, 1); MODULE_ADD_FN(math, "sign", stdMathSign, 1);
MODULE_ADD_FN(math, "hash", stdMathHash, 1); MODULE_ADD_FN(math, "hash", stdMathHash, 1);
MODULE_ADD_FN(math, "sin", stdMathSine, 1); MODULE_ADD_FN(math, "sin", stdMathSine, 1);
MODULE_ADD_FN(math, "cos", stdMathCosine, 1); MODULE_ADD_FN(math, "cos", stdMathCosine, 1);
MODULE_ADD_FN(math, "tan", stdMathTangent, 1); MODULE_ADD_FN(math, "tan", stdMathTangent, 1);
MODULE_ADD_FN(math, "sinh", stdMathSinh, 1); MODULE_ADD_FN(math, "sinh", stdMathSinh, 1);
MODULE_ADD_FN(math, "cosh", stdMathCosh, 1); MODULE_ADD_FN(math, "cosh", stdMathCosh, 1);
MODULE_ADD_FN(math, "tanh", stdMathTanh, 1); MODULE_ADD_FN(math, "tanh", stdMathTanh, 1);
MODULE_ADD_FN(math, "asin", stdMathArcSine, 1); MODULE_ADD_FN(math, "asin", stdMathArcSine, 1);
MODULE_ADD_FN(math, "acos", stdMathArcCosine, 1); MODULE_ADD_FN(math, "acos", stdMathArcCosine, 1);
MODULE_ADD_FN(math, "atan", stdMathArcTangent, 1); MODULE_ADD_FN(math, "atan", stdMathArcTangent, 1);
MODULE_ADD_FN(math, "log10", stdMathLog10, 1); MODULE_ADD_FN(math, "log10", stdMathLog10, 1);
MODULE_ADD_FN(math, "round", stdMathRound, 1); MODULE_ADD_FN(math, "round", stdMathRound, 1);
MODULE_ADD_FN(math, "log2", stdMathLog2, 1); MODULE_ADD_FN(math, "log2", stdMathLog2, 1);
MODULE_ADD_FN(math, "hypot", stdMathHypot, 2); MODULE_ADD_FN(math, "hypot", stdMathHypot, 2);
MODULE_ADD_FN(math, "cbrt", stdMathCbrt, 1); MODULE_ADD_FN(math, "cbrt", stdMathCbrt, 1);
MODULE_ADD_FN(math, "gamma", stdMathGamma, 1); MODULE_ADD_FN(math, "gamma", stdMathGamma, 1);
MODULE_ADD_FN(math, "lgamma",stdMathLgamma, 1); MODULE_ADD_FN(math, "lgamma", stdMathLgamma, 1);
MODULE_ADD_FN(math, "erf", stdMathErf, 1); MODULE_ADD_FN(math, "erf", stdMathErf, 1);
MODULE_ADD_FN(math, "erfc", stdMathErfc, 1); MODULE_ADD_FN(math, "erfc", stdMathErfc, 1);
// Note that currently it's mutable (since it's a global variable, not // 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 // 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)); moduleAddGlobal(vm, math, "PI", 2, VAR_NUM(M_PI));
Module* fiber = newModuleInternal(vm, "Fiber"); Module* fiber = newModuleInternal(vm, "Fiber");
MODULE_ADD_FN(fiber, "new", stdFiberNew, 1); MODULE_ADD_FN(fiber, "new", stdFiberNew, 1);
MODULE_ADD_FN(fiber, "run", stdFiberRun, -1); MODULE_ADD_FN(fiber, "run", stdFiberRun, -1);
MODULE_ADD_FN(fiber, "resume", stdFiberResume, -1); MODULE_ADD_FN(fiber, "resume", stdFiberResume, -1);
#undef MODULE_ADD_FN
} }
#undef IS_NUM_BYTE
#undef DOCSTRING
#undef DEF
/*****************************************************************************/ /*****************************************************************************/
/* OPERATORS */ /* OPERATORS */
/*****************************************************************************/ /*****************************************************************************/
@ -1308,17 +1321,6 @@ Var varAdd(PKVM* vm, Var v1, Var v2) {
return VAR_OBJ(listJoin(vm, (List*)o1, (List*)o2)); return VAR_OBJ(listJoin(vm, (List*)o1, (List*)o2));
} }
} break; } 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); Map* map = (Map*)AS_OBJ(container);
return !IS_UNDEF(mapGet(map, elem)); return !IS_UNDEF(mapGet(map, elem));
} break; } 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 Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
// 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).
// Set error for accessing non-existed attribute.
#define ERR_NO_ATTRIB(vm, on, attrib) \ #define ERR_NO_ATTRIB(vm, on, attrib) \
VM_SET_ERROR(vm, stringFormat(vm, "'$' object has no attribute named '$'", \ VM_SET_ERROR(vm, stringFormat(vm, "'$' object has no attribute named '$'", \
varTypeName(on), attrib->data)) varTypeName(on), attrib->data))
Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
if (!IS_OBJ(on)) { if (!IS_OBJ(on)) {
VM_SET_ERROR(vm, stringFormat(vm, "$ type is not subscriptable.", VM_SET_ERROR(vm, stringFormat(vm, "$ type is not subscriptable.",
varTypeName(on))); varTypeName(on)));
@ -1556,8 +1545,7 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
Object* obj = AS_OBJ(on); Object* obj = AS_OBJ(on);
switch (obj->type) { switch (obj->type) {
case OBJ_STRING: case OBJ_STRING: {
{
String* str = (String*)obj; String* str = (String*)obj;
switch (attrib->hash) { switch (attrib->hash) {
@ -1572,42 +1560,26 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
case CHECK_HASH("strip", 0xfd1b18d1): case CHECK_HASH("strip", 0xfd1b18d1):
return VAR_OBJ(stringStrip(vm, str)); 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; List* list = (List*)obj;
switch (attrib->hash) { switch (attrib->hash) {
case CHECK_HASH("length", 0x83d03615): case CHECK_HASH("length", 0x83d03615):
return VAR_NUM((double)(list->elements.count)); 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 } // map = { "foo" : 42, "can't access" : 32 }
// val = map.foo ## <-- This should be error // val = map.foo ## <-- This should be error
// Only the map's attributes are accessed here. // Only the map's attributes are accessed here.
TODO; TODO;
UNREACHABLE(); } break;
}
case OBJ_RANGE: case OBJ_RANGE: {
{
Range* range = (Range*)obj; Range* range = (Range*)obj;
switch (attrib->hash) { switch (attrib->hash) {
@ -1623,17 +1595,10 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
case CHECK_HASH("last", 0x63e1d819): case CHECK_HASH("last", 0x63e1d819):
return VAR_NUM(range->to); 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; Module* module = (Module*)obj;
// Search in globals. // Search in globals.
@ -1642,19 +1607,12 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
ASSERT_INDEX((uint32_t)index, module->globals.count); ASSERT_INDEX((uint32_t)index, module->globals.count);
return module->globals.data[index]; return module->globals.data[index];
} }
} break;
ERR_NO_ATTRIB(vm, on, attrib);
return VAR_NULL;
}
case OBJ_FUNC: case OBJ_FUNC:
{ break;
// Functions aren't first class objects.
UNREACHABLE();
}
case OBJ_CLOSURE: case OBJ_CLOSURE: {
{
Closure* closure = (Closure*)obj; Closure* closure = (Closure*)obj;
switch (attrib->hash) { switch (attrib->hash) {
@ -1663,58 +1621,51 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
case CHECK_HASH("name", 0x8d39bde6): case CHECK_HASH("name", 0x8d39bde6):
return VAR_OBJ(newString(vm, closure->fn->name)); return VAR_OBJ(newString(vm, closure->fn->name));
default:
ERR_NO_ATTRIB(vm, on, attrib);
return VAR_NULL;
} }
} } break;
case OBJ_UPVALUE: case OBJ_UPVALUE:
// Upvalues aren't first class objects. UNREACHABLE(); // Upvalues aren't first class objects.
UNREACHABLE(); break;
case OBJ_FIBER: case OBJ_FIBER: {
{ Fiber* fb = (Fiber*)obj;
Fiber* fb = (Fiber*)obj; switch (attrib->hash) {
switch (attrib->hash) {
case CHECK_HASH("is_done", 0x789c2706): case CHECK_HASH("is_done", 0x789c2706):
return VAR_BOOL(fb->state == FIBER_DONE); return VAR_BOOL(fb->state == FIBER_DONE);
case CHECK_HASH("function", 0x9ed64249): case CHECK_HASH("function", 0x9ed64249):
return VAR_OBJ(fb->closure); return VAR_OBJ(fb->closure);
default:
ERR_NO_ATTRIB(vm, on, attrib);
return VAR_NULL;
}
UNREACHABLE();
} }
} break;
case OBJ_CLASS: case OBJ_CLASS:
TODO; TODO;
UNREACHABLE(); break;
case OBJ_INST: case OBJ_INST: {
{
Var value; Var value;
if (!instGetAttrib(vm, (Instance*)obj, attrib, &value)) { if (instGetAttrib(vm, (Instance*)obj, attrib, &value)) {
ERR_NO_ATTRIB(vm, on, attrib); return value;
return VAR_NULL;
} }
return value; } break;
}
default:
UNREACHABLE();
} }
UNREACHABLE(); ERR_NO_ATTRIB(vm, on, attrib);
return VAR_NULL;
#undef ERR_NO_ATTRIB
} }
void varSetAttrib(PKVM* vm, Var on, String* attrib, Var value) { 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) \ #define ATTRIB_IMMUTABLE(name) \
do { \ do { \
if ((attrib->length == strlen(name) && strcmp(name, attrib->data) == 0)) { \ if ((attrib->length == strlen(name) && strcmp(name, attrib->data) == 0)) { \
@ -1745,12 +1696,7 @@ do { \
return; return;
case OBJ_MAP: 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; TODO;
ERR_NO_ATTRIB(vm, on, attrib); ERR_NO_ATTRIB(vm, on, attrib);
return; return;
@ -1763,22 +1709,16 @@ do { \
case OBJ_MODULE: { case OBJ_MODULE: {
Module* module = (Module*)obj; Module* module = (Module*)obj;
// Check globals.
int index = moduleGetGlobalIndex(module, attrib->data, attrib->length); int index = moduleGetGlobalIndex(module, attrib->data, attrib->length);
if (index != -1) { if (index != -1) {
ASSERT_INDEX((uint32_t)index, module->globals.count); ASSERT_INDEX((uint32_t)index, module->globals.count);
module->globals.data[index] = value; module->globals.data[index] = value;
return; return;
} }
} break;
ERR_NO_ATTRIB(vm, on, attrib);
return;
}
case OBJ_FUNC: case OBJ_FUNC:
// Functions aren't first class objects. UNREACHABLE(); // Functions aren't first class objects.
UNREACHABLE();
return; return;
case OBJ_CLOSURE: case OBJ_CLOSURE:
@ -1788,8 +1728,7 @@ do { \
return; return;
case OBJ_UPVALUE: case OBJ_UPVALUE:
// Upvalues aren't first class objects. UNREACHABLE(); // Upvalues aren't first class objects.
UNREACHABLE();
return; return;
case OBJ_FIBER: case OBJ_FIBER:
@ -1800,8 +1739,7 @@ do { \
ERR_NO_ATTRIB(vm, on, attrib); ERR_NO_ATTRIB(vm, on, attrib);
return; return;
case OBJ_INST: case OBJ_INST: {
{
if (!instSetAttrib(vm, (Instance*)obj, attrib, value)) { if (!instSetAttrib(vm, (Instance*)obj, attrib, value)) {
// If we has error by now, that means the set value type is // 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. // 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 // If we reached here, that means the attribute exists and we have
// updated the value. // updated the value.
return; return;
} } break;
default:
UNREACHABLE();
} }
UNREACHABLE();
ERR_NO_ATTRIB(vm, on, attrib);
return;
#undef ATTRIB_IMMUTABLE #undef ATTRIB_IMMUTABLE
}
#undef ERR_NO_ATTRIB #undef ERR_NO_ATTRIB
}
Var varGetSubscript(PKVM* vm, Var on, Var key) { Var varGetSubscript(PKVM* vm, Var on, Var key) {
if (!IS_OBJ(on)) { if (!IS_OBJ(on)) {
@ -1833,8 +1769,7 @@ Var varGetSubscript(PKVM* vm, Var on, Var key) {
Object* obj = AS_OBJ(on); Object* obj = AS_OBJ(on);
switch (obj->type) { switch (obj->type) {
case OBJ_STRING: case OBJ_STRING: {
{
int64_t index; int64_t index;
String* str = ((String*)obj); String* str = ((String*)obj);
if (!validateInteger(vm, key, &index, "List index")) { 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); String* c = newStringLength(vm, str->data + index, 1);
return VAR_OBJ(c); return VAR_OBJ(c);
} } break;
case OBJ_LIST: case OBJ_LIST: {
{
int64_t index; int64_t index;
pkVarBuffer* elems = &((List*)obj)->elements; pkVarBuffer* elems = &((List*)obj)->elements;
if (!validateInteger(vm, key, &index, "List index")) { if (!validateInteger(vm, key, &index, "List index")) {
@ -1858,10 +1792,9 @@ Var varGetSubscript(PKVM* vm, Var on, Var key) {
return VAR_NULL; return VAR_NULL;
} }
return elems->data[index]; return elems->data[index];
} } break;
case OBJ_MAP: case OBJ_MAP: {
{
Var value = mapGet((Map*)obj, key); Var value = mapGet((Map*)obj, key);
if (IS_UNDEF(value)) { if (IS_UNDEF(value)) {
@ -1876,24 +1809,16 @@ Var varGetSubscript(PKVM* vm, Var on, Var key) {
return VAR_NULL; return VAR_NULL;
} }
return value; return value;
} } break;
case OBJ_RANGE:
case OBJ_MODULE:
case OBJ_FUNC: case OBJ_FUNC:
case OBJ_CLOSURE:
case OBJ_UPVALUE: case OBJ_UPVALUE:
case OBJ_FIBER: UNREACHABLE(); // Not first class objects.
case OBJ_CLASS:
case OBJ_INST:
TODO;
UNREACHABLE();
default:
UNREACHABLE();
} }
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) { 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); Object* obj = AS_OBJ(on);
switch (obj->type) { switch (obj->type) {
case OBJ_STRING: case OBJ_LIST: {
VM_SET_ERROR(vm, newString(vm, "String objects are immutable."));
return;
case OBJ_LIST:
{
int64_t index; int64_t index;
pkVarBuffer* elems = &((List*)obj)->elements; pkVarBuffer* elems = &((List*)obj)->elements;
if (!validateInteger(vm, key, &index, "List index")) return; if (!validateInteger(vm, key, &index, "List index")) return;
if (!validateIndex(vm, index, elems->count, "List")) return; if (!validateIndex(vm, index, elems->count, "List")) return;
elems->data[index] = value; elems->data[index] = value;
return; return;
} } break;
case OBJ_MAP: case OBJ_MAP: {
{
if (IS_OBJ(key) && !isObjectHashable(AS_OBJ(key)->type)) { if (IS_OBJ(key) && !isObjectHashable(AS_OBJ(key)->type)) {
VM_SET_ERROR(vm, stringFormat(vm, "$ type is not hashable.", VM_SET_ERROR(vm, stringFormat(vm, "$ type is not hashable.",
varTypeName(key))); varTypeName(key)));
@ -1928,27 +1847,14 @@ void varsetSubscript(PKVM* vm, Var on, Var key, Var value) {
mapSet(vm, (Map*)obj, key, value); mapSet(vm, (Map*)obj, key, value);
} }
return; return;
} } break;
case OBJ_RANGE:
case OBJ_MODULE:
case OBJ_FUNC: case OBJ_FUNC:
case OBJ_CLOSURE:
case OBJ_UPVALUE: case OBJ_UPVALUE:
case OBJ_FIBER:
case OBJ_CLASS:
case OBJ_INST:
TODO;
UNREACHABLE();
default:
UNREACHABLE(); UNREACHABLE();
} }
UNREACHABLE(); VM_SET_ERROR(vm, stringFormat(vm, "$ type is not subscriptable.",
varTypeName(on)));
return;
} }
#undef IS_NUM_BYTE
#undef DOCSTRING
#undef DEF

View File

@ -11,7 +11,7 @@
#include "pk_common.h" #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 // headers that are specific to a single source here, instead include them in
// their source files explicitly (can not be implicitly included by another // 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 // header). And don't include any C standard headers in any of the pocketlang
@ -125,4 +125,45 @@
// //
#define CHECK_HASH(name, hash) hash #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 #endif // PK_INTERNAL

View File

@ -1242,8 +1242,8 @@ bool instGetAttrib(PKVM* vm, Instance* inst, String* attrib, Var* value) {
if (IS_UNDEF(val)) { if (IS_UNDEF(val)) {
// FIXME: add a list of attribute overrides. // FIXME: add a list of attribute overrides.
if (IS_CSTR_EQ(attrib, "as_string", 9, if ((CHECK_HASH("as_string", 0xbdef4147) == attrib->hash) &&
CHECK_HASH("as_string", 0xbdef4147))) { IS_CSTR_EQ(attrib, "as_string", 9)) {
*value = VAR_OBJ(toRepr(vm, VAR_OBJ(inst))); *value = VAR_OBJ(toRepr(vm, VAR_OBJ(inst)));
return true; return true;
} }

View File

@ -137,11 +137,10 @@
((s1)->length == (s2)->length) && \ ((s1)->length == (s2)->length) && \
(memcmp((const void*)(s1)->data, (const void*)(s2)->data, (s1)->length) == 0)) (memcmp((const void*)(s1)->data, (const void*)(s2)->data, (s1)->length) == 0))
// Compare pocket string with c string. // Compare pocket string with C string.
#define IS_CSTR_EQ(str, cstr, len, chash) \ #define IS_CSTR_EQ(str, cstr, len) \
(((str)->hash == chash) && \ (((str)->length == len) && \
((str)->length == len) && \ (memcmp((const void*)(str)->data, (const void*)(cstr), len) == 0))
(memcmp((const void*)(str)->data, (const void*)(cstr), len) == 0))
// Decode types. // Decode types.
#define AS_BOOL(value) ((value) == VAR_TRUE) #define AS_BOOL(value) ((value) == VAR_TRUE)

View File

@ -1,5 +1,6 @@
#!python #!python
## Copyright (c) 2020-2021 Thakee Nathees ## Copyright (c) 2020-2021 Thakee Nathees
## Copyright (c) 2021-2022 Pocketlang Contributors
## Distributed Under The MIT License ## Distributed Under The MIT License
## This will run static checks on the source files, for line length, ## This will run static checks on the source files, for line length,
@ -7,8 +8,7 @@
import os, sys, re import os, sys, re
from os import listdir from os import listdir
from os.path import ( from os.path import join, abspath, dirname, relpath
join, abspath, dirname, relpath)
## The absolute path of this file, when run as a script. ## 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. ## This file is not intended to be included in other files at the moment.
@ -49,21 +49,12 @@ SOURCE_DIRS = [
"../docs/wasm/", "../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. ## This global variable will be set to true if any check failed.
checks_failed = False checks_failed = False
def main(): def main():
check_fnv1_hash(to_abs_paths(HASH_CHECK_LIST)) check_fnv1_hash(to_abs_paths(HASH_CHECK_LIST))
check_static(to_abs_paths(SOURCE_DIRS)) check_static(to_abs_paths(SOURCE_DIRS))
check_common_header_match(to_abs_paths(COMMON_HEADERS))
if checks_failed: if checks_failed:
sys.exit(1) sys.exit(1)
print("Static checks were passed.") print("Static checks were passed.")
@ -141,26 +132,6 @@ def check_static(dirs):
else: else:
is_last_empty = False 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. ## Returns a formated string of the error location.
def location(file, line): def location(file, line):
return f"{'%-17s'%file} : {'%4s'%line}" return f"{'%-17s'%file} : {'%4s'%line}"

View File

@ -1,5 +1,6 @@
#!python #!python
## Copyright (c) 2020-2021 Thakee Nathees ## Copyright (c) 2020-2021 Thakee Nathees
## Copyright (c) 2021-2022 Pocketlang Contributors
## Distributed Under The MIT License ## Distributed Under The MIT License
import os, sys, platform import os, sys, platform