mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-11 15:16:41 +08:00
Merge pull request #31 from ThakeeNathees/more-builtin-fn
gc bugs fixed
This commit is contained in:
commit
b68db7d5fb
35
cli/TODO.txt
35
cli/TODO.txt
@ -1,25 +1,30 @@
|
|||||||
|
|
||||||
// To implement.
|
// To implement.
|
||||||
|
|
||||||
[ ] Implement argparse.
|
- Implement argparse.
|
||||||
[ ] Implement resolve path in cli.
|
- -v --version
|
||||||
|
- emit opcodes
|
||||||
|
- maybe write a similer .pyc file for pocket
|
||||||
|
|
||||||
[ ] Structs.
|
- Ignore line with '\' character.
|
||||||
[ ] Implement math library.
|
- Implement resolve path in cli.
|
||||||
[ ] Single header for embedding.
|
|
||||||
[ ] Implement fiber from script body and vm run fibers (not scripts).
|
- Structs.
|
||||||
|
- Implement math library.
|
||||||
|
- Single header for embedding.
|
||||||
|
- Implement fiber from script body and vm run fibers (not scripts).
|
||||||
Then remove vm's root script.
|
Then remove vm's root script.
|
||||||
[ ] C Integration api (including add core lib from host application).
|
- C Integration api (including add core lib from host application).
|
||||||
[ ] REPL.
|
- REPL.
|
||||||
[ ] compile expression for a script.
|
- compile expression for a script.
|
||||||
[ ] Var handler implement.
|
- Var handler implement.
|
||||||
[ ] Make it possible to override function names.
|
- Make it possible to override function names.
|
||||||
- To do so the functions and global variables should be in the same
|
- To do so the functions and global variables should be in the same
|
||||||
buffer as the property of the script.
|
buffer as the property of the script.
|
||||||
[ ] Hex, binary literals and floats like ".5".
|
- Hex, binary literals and floats like ".5".
|
||||||
[ ] Function docstring property.
|
- Function docstring property.
|
||||||
[ ] Union tagging alter in var.
|
- Union tagging alter in var.
|
||||||
[ ] (future) add structs and maybe enums.
|
- (future) add structs and maybe enums.
|
||||||
|
|
||||||
// Add more.
|
// Add more.
|
||||||
[ ] Compilte core methods.
|
[ ] Compilte core methods.
|
||||||
|
@ -36,8 +36,10 @@ void register_cli_modules(PKVM* vm) {
|
|||||||
PkHandle* path = pkNewModule(vm, "path");
|
PkHandle* path = pkNewModule(vm, "path");
|
||||||
pkModuleAddFunction(vm, path, "abspath", stdPathAbspath, 1);
|
pkModuleAddFunction(vm, path, "abspath", stdPathAbspath, 1);
|
||||||
pkModuleAddFunction(vm, path, "curdir", stdPathCurdir, 0);
|
pkModuleAddFunction(vm, path, "curdir", stdPathCurdir, 0);
|
||||||
|
pkReleaseHandle(vm, path);
|
||||||
|
|
||||||
PkHandle* test = pkNewModule(vm, "test");
|
PkHandle* test = pkNewModule(vm, "test");
|
||||||
pkModuleAddFunction(vm, test, "add", testAdd, 2);
|
pkModuleAddFunction(vm, test, "add", testAdd, 2);
|
||||||
|
pkReleaseHandle(vm, test);
|
||||||
|
|
||||||
}
|
}
|
@ -105,7 +105,6 @@ int main(int argc, char** argv) {
|
|||||||
config.load_script_fn = loadScript;
|
config.load_script_fn = loadScript;
|
||||||
config.resolve_path_fn = resolvePath;
|
config.resolve_path_fn = resolvePath;
|
||||||
|
|
||||||
|
|
||||||
// FIXME: this is temp till arg parse implemented.
|
// FIXME: this is temp till arg parse implemented.
|
||||||
if (argc >= 3 && strcmp(argv[1], "-c") == 0) {
|
if (argc >= 3 && strcmp(argv[1], "-c") == 0) {
|
||||||
PKVM* vm = pkNewVM(&config);
|
PKVM* vm = pkNewVM(&config);
|
||||||
|
@ -14,7 +14,7 @@ extern void js_errorPrint(int type, int line, const char* message);
|
|||||||
extern void js_writeFunction(const char* message);
|
extern void js_writeFunction(const char* message);
|
||||||
extern const char* js_loadScript();
|
extern const char* js_loadScript();
|
||||||
|
|
||||||
void errorPrint(PKVM* vm, PKErrorType type, const char* file, int line,
|
void errorPrint(PKVM* vm, PkErrorType type, const char* file, int line,
|
||||||
const char* message) {
|
const char* message) {
|
||||||
// No need to pass file (since there is only script that'll ever run on the
|
// No need to pass file (since there is only script that'll ever run on the
|
||||||
// browser.
|
// browser.
|
||||||
@ -47,7 +47,7 @@ int runSource(const char* source) {
|
|||||||
config.resolve_path_fn = resolvePath;
|
config.resolve_path_fn = resolvePath;
|
||||||
|
|
||||||
PKVM* vm = pkNewVM(&config);
|
PKVM* vm = pkNewVM(&config);
|
||||||
PKInterpretResult result = pkInterpretSource(vm, source, "@try");
|
PkInterpretResult result = pkInterpretSource(vm, source, "@try");
|
||||||
|
|
||||||
pkFreeVM(vm);
|
pkFreeVM(vm);
|
||||||
|
|
||||||
|
87
src/core.c
87
src/core.c
@ -59,7 +59,7 @@ void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name,
|
|||||||
// 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() \
|
||||||
__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."); \
|
||||||
__ASSERT(value != NULL, "Parameter [value] was NULL."); \
|
__ASSERT(value != NULL, "Parameter [value] was NULL."); \
|
||||||
((void*)0)
|
((void*)0)
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ int pkGetArgc(PKVM* vm) {
|
|||||||
|
|
||||||
PkVar pkGetArg(PKVM* vm, int arg) {
|
PkVar pkGetArg(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));
|
||||||
}
|
}
|
||||||
@ -217,19 +217,23 @@ static inline bool validateIndex(PKVM* vm, int32_t index, int32_t size,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if [var] is string for argument at [arg_ind]. If not set error and
|
// Check if [var] is string for argument at [arg]. If not set error and
|
||||||
// return false.
|
// return false.
|
||||||
static bool validateArgString(PKVM* vm, Var var, String** value, int arg_ind) {
|
#define VALIDATE_ARG_OBJ(m_class, m_type, m_name) \
|
||||||
if (!IS_OBJ(var) || AS_OBJ(var)->type != OBJ_STRING) {
|
static bool validateArg##m_class(PKVM* vm, int arg, m_class** value) { \
|
||||||
String* str_arg = toString(vm, VAR_NUM((double)arg_ind), false);
|
Var var = ARG(arg); \
|
||||||
vmPushTempRef(vm, &str_arg->_super);
|
ASSERT(arg > 0 && arg <= ARGC, OOPS); \
|
||||||
vm->fiber->error = stringFormat(vm, "Expected a string at argument @.",
|
if (!IS_OBJ(var) || AS_OBJ(var)->type != m_type) { \
|
||||||
str_arg, false);
|
char buff[12]; sprintf(buff, "%d", arg); \
|
||||||
vmPopTempRef(vm);
|
vm->fiber->error = stringFormat(vm, "Expected a " m_name \
|
||||||
}
|
" at argument $.", buff, false); \
|
||||||
*value = (String*)AS_OBJ(var);
|
} \
|
||||||
return true;
|
*value = (m_class*)AS_OBJ(var); \
|
||||||
|
return true; \
|
||||||
}
|
}
|
||||||
|
VALIDATE_ARG_OBJ(String, OBJ_STRING, "string")
|
||||||
|
VALIDATE_ARG_OBJ(List, OBJ_LIST, "list")
|
||||||
|
VALIDATE_ARG_OBJ(Map, OBJ_MAP, "map")
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* BUILTIN FUNCTIONS API */
|
/* BUILTIN FUNCTIONS API */
|
||||||
@ -284,6 +288,10 @@ FN_IS_OBJ_TYPE(Function, OBJ_FUNC)
|
|||||||
FN_IS_OBJ_TYPE(Script, OBJ_SCRIPT)
|
FN_IS_OBJ_TYPE(Script, OBJ_SCRIPT)
|
||||||
FN_IS_OBJ_TYPE(UserObj, OBJ_USER)
|
FN_IS_OBJ_TYPE(UserObj, OBJ_USER)
|
||||||
|
|
||||||
|
void coreTypeName(PKVM* vm) {
|
||||||
|
RET(VAR_OBJ(&newString(vm, varTypeName(ARG1))->_super));
|
||||||
|
}
|
||||||
|
|
||||||
void coreAssert(PKVM* vm) {
|
void coreAssert(PKVM* vm) {
|
||||||
int argc = ARGC;
|
int argc = ARGC;
|
||||||
if (argc != 1 && argc != 2) {
|
if (argc != 1 && argc != 2) {
|
||||||
@ -346,12 +354,12 @@ void corePrint(PKVM* vm) {
|
|||||||
vm->config.write_fn(vm, "\n");
|
vm->config.write_fn(vm, "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// string functions
|
// String functions.
|
||||||
// ----------------
|
// -----------------
|
||||||
|
|
||||||
void coreStrLower(PKVM* vm) {
|
void coreStrLower(PKVM* vm) {
|
||||||
String* str;
|
String* str;
|
||||||
if (!validateArgString(vm, ARG1, &str, 1)) return;
|
if (!validateArgString(vm, 1, &str)) return;
|
||||||
|
|
||||||
String* result = newStringLength(vm, str->data, str->length);
|
String* result = newStringLength(vm, str->data, str->length);
|
||||||
char* data = result->data;
|
char* data = result->data;
|
||||||
@ -364,7 +372,7 @@ void coreStrLower(PKVM* vm) {
|
|||||||
|
|
||||||
void coreStrUpper(PKVM* vm) {
|
void coreStrUpper(PKVM* vm) {
|
||||||
String* str;
|
String* str;
|
||||||
if (!validateArgString(vm, ARG1, &str, 1)) return;
|
if (!validateArgString(vm, 1, &str)) return;
|
||||||
|
|
||||||
String* result = newStringLength(vm, str->data, str->length);
|
String* result = newStringLength(vm, str->data, str->length);
|
||||||
char* data = result->data;
|
char* data = result->data;
|
||||||
@ -377,7 +385,7 @@ void coreStrUpper(PKVM* vm) {
|
|||||||
|
|
||||||
void coreStrStrip(PKVM* vm) {
|
void coreStrStrip(PKVM* vm) {
|
||||||
String* str;
|
String* str;
|
||||||
if (!validateArgString(vm, ARG1, &str, 1)) return;
|
if (!validateArgString(vm, 1, &str)) return;
|
||||||
|
|
||||||
const char* start = str->data;
|
const char* start = str->data;
|
||||||
while (*start && isspace(*start)) start++;
|
while (*start && isspace(*start)) start++;
|
||||||
@ -389,6 +397,29 @@ void coreStrStrip(PKVM* vm) {
|
|||||||
RET(VAR_OBJ(&newStringLength(vm, start, (uint32_t)(end - start + 1))->_super));
|
RET(VAR_OBJ(&newStringLength(vm, start, (uint32_t)(end - start + 1))->_super));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List functions.
|
||||||
|
// ---------------
|
||||||
|
void coreListAppend(PKVM* vm) {
|
||||||
|
List* list;
|
||||||
|
if (!validateArgList(vm, 1, &list)) return;
|
||||||
|
Var elem = ARG(2);
|
||||||
|
|
||||||
|
varBufferWrite(&list->elements, vm, elem);
|
||||||
|
RET(VAR_OBJ(&list->_super));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map functions.
|
||||||
|
// --------------
|
||||||
|
|
||||||
|
void coreMapRemove(PKVM* vm) {
|
||||||
|
Map* map;
|
||||||
|
if (!validateArgMap(vm, 1, &map)) return;
|
||||||
|
Var key = ARG(2);
|
||||||
|
|
||||||
|
mapRemoveKey(vm, map, key);
|
||||||
|
RET(VAR_OBJ(&map->_super));
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* CORE MODULE METHODS */
|
/* CORE MODULE METHODS */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -456,6 +487,11 @@ void stdLangGC(PKVM* vm) {
|
|||||||
RET(VAR_NUM((double)garbage));
|
RET(VAR_NUM((double)garbage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A debug function for development (will be removed).
|
||||||
|
void stdLangDebugBreak(PKVM* vm) {
|
||||||
|
DEBUG_BREAK();
|
||||||
|
}
|
||||||
|
|
||||||
// Write function, just like print function but it wont put space between args
|
// Write function, just like print function but it wont put space between args
|
||||||
// and write a new line at the end.
|
// and write a new line at the end.
|
||||||
void stdLangWrite(PKVM* vm) {
|
void stdLangWrite(PKVM* vm) {
|
||||||
@ -488,6 +524,8 @@ void initializeCore(PKVM* vm) {
|
|||||||
(int)strlen(name), argc, fn);
|
(int)strlen(name), argc, fn);
|
||||||
|
|
||||||
// Initialize builtin functions.
|
// Initialize builtin functions.
|
||||||
|
INITALIZE_BUILTIN_FN("type_name", coreTypeName, 1);
|
||||||
|
|
||||||
INITALIZE_BUILTIN_FN("is_null", coreIsNull, 1);
|
INITALIZE_BUILTIN_FN("is_null", coreIsNull, 1);
|
||||||
INITALIZE_BUILTIN_FN("is_bool", coreIsBool, 1);
|
INITALIZE_BUILTIN_FN("is_bool", coreIsBool, 1);
|
||||||
INITALIZE_BUILTIN_FN("is_num", coreIsNum, 1);
|
INITALIZE_BUILTIN_FN("is_num", coreIsNum, 1);
|
||||||
@ -510,12 +548,19 @@ void initializeCore(PKVM* vm) {
|
|||||||
INITALIZE_BUILTIN_FN("str_upper", coreStrUpper, 1);
|
INITALIZE_BUILTIN_FN("str_upper", coreStrUpper, 1);
|
||||||
INITALIZE_BUILTIN_FN("str_strip", coreStrStrip, 1);
|
INITALIZE_BUILTIN_FN("str_strip", coreStrStrip, 1);
|
||||||
|
|
||||||
|
// List functions.
|
||||||
|
INITALIZE_BUILTIN_FN("list_append", coreListAppend, 2);
|
||||||
|
|
||||||
|
// Map functions.
|
||||||
|
INITALIZE_BUILTIN_FN("map_remove", coreMapRemove, 2);
|
||||||
|
|
||||||
// Core Modules /////////////////////////////////////////////////////////////
|
// Core Modules /////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
Script* lang = newModuleInternal(vm, "lang");
|
Script* lang = newModuleInternal(vm, "lang");
|
||||||
moduleAddFunctionInternal(vm, lang, "clock", stdLangClock, 0);
|
moduleAddFunctionInternal(vm, lang, "clock", stdLangClock, 0);
|
||||||
moduleAddFunctionInternal(vm, lang, "gc", stdLangGC, 0);
|
moduleAddFunctionInternal(vm, lang, "gc", stdLangGC, 0);
|
||||||
moduleAddFunctionInternal(vm, lang, "write", stdLangWrite, -1);
|
moduleAddFunctionInternal(vm, lang, "write", stdLangWrite, -1);
|
||||||
|
moduleAddFunctionInternal(vm, lang, "debug_break", stdLangDebugBreak, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@ -543,7 +588,7 @@ Var varAdd(PKVM* vm, Var v1, Var v2) {
|
|||||||
case OBJ_STRING:
|
case OBJ_STRING:
|
||||||
{
|
{
|
||||||
if (o2->type == OBJ_STRING) {
|
if (o2->type == OBJ_STRING) {
|
||||||
return VAR_OBJ(stringFormat(vm, "@@", v1, v2));
|
return VAR_OBJ(stringFormat(vm, "@@", (String*)o1, (String*)o2));
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -623,7 +668,7 @@ Var varModulo(PKVM* vm, Var v1, Var v2) {
|
|||||||
return VAR_NULL;
|
return VAR_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool varGreater(PKVM* vm, Var v1, Var v2) {
|
bool varGreater(Var v1, Var v2) {
|
||||||
double d1, d2;
|
double d1, d2;
|
||||||
if (isNumeric(v1, &d1) && isNumeric(v2, &d2)) {
|
if (isNumeric(v1, &d1) && isNumeric(v2, &d2)) {
|
||||||
return d1 > d2;
|
return d1 > d2;
|
||||||
@ -633,7 +678,7 @@ bool varGreater(PKVM* vm, Var v1, Var v2) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool varLesser(PKVM* vm, Var v1, Var v2) {
|
bool varLesser(Var v1, Var v2) {
|
||||||
double d1, d2;
|
double d1, d2;
|
||||||
if (isNumeric(v1, &d1) && isNumeric(v2, &d2)) {
|
if (isNumeric(v1, &d1) && isNumeric(v2, &d2)) {
|
||||||
return d1 < d2;
|
return d1 < d2;
|
||||||
|
@ -34,8 +34,8 @@ Var varMultiply(PKVM* vm, Var v1, Var v2);
|
|||||||
Var varDivide(PKVM* vm, Var v1, Var v2);
|
Var varDivide(PKVM* vm, Var v1, Var v2);
|
||||||
Var varModulo(PKVM* vm, Var v1, Var v2);
|
Var varModulo(PKVM* vm, Var v1, Var v2);
|
||||||
|
|
||||||
bool varGreater(PKVM* vm, Var v1, Var v2);
|
bool varGreater(Var v1, Var v2);
|
||||||
bool varLesser(PKVM* vm, Var v1, Var v2);
|
bool varLesser(Var v1, Var v2);
|
||||||
|
|
||||||
Var varGetAttrib(PKVM* vm, Var on, String* attrib);
|
Var varGetAttrib(PKVM* vm, Var on, String* attrib);
|
||||||
void varSetAttrib(PKVM* vm, Var on, String* name, Var value);
|
void varSetAttrib(PKVM* vm, Var on, String* name, Var value);
|
||||||
|
23
src/debug.c
23
src/debug.c
@ -9,6 +9,9 @@
|
|||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
|
// To limit maximum elements to be dumpin in a map or a list.
|
||||||
|
#define MAX_DUMP_ELEMENTS 30
|
||||||
|
|
||||||
static const char* op_name[] = {
|
static const char* op_name[] = {
|
||||||
#define OPCODE(name, params, stack) #name,
|
#define OPCODE(name, params, stack) #name,
|
||||||
#include "opcodes.h"
|
#include "opcodes.h"
|
||||||
@ -45,6 +48,12 @@ static void _dumpValue(PKVM* vm, Var value, bool recursive) {
|
|||||||
for (uint32_t i = 0; i < list->elements.count; i++) {
|
for (uint32_t i = 0; i < list->elements.count; i++) {
|
||||||
if (i != 0) printf(", ");
|
if (i != 0) printf(", ");
|
||||||
_dumpValue(vm, list->elements.data[i], true);
|
_dumpValue(vm, list->elements.data[i], true);
|
||||||
|
|
||||||
|
// Terminate the dump if it's too long.
|
||||||
|
if (i >= MAX_DUMP_ELEMENTS) {
|
||||||
|
printf("...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
printf("]");
|
printf("]");
|
||||||
}
|
}
|
||||||
@ -58,11 +67,21 @@ static void _dumpValue(PKVM* vm, Var value, bool recursive) {
|
|||||||
printf("{...}");
|
printf("{...}");
|
||||||
} else {
|
} else {
|
||||||
printf("{");
|
printf("{");
|
||||||
for (uint32_t i = 0; i < map->count; i++) {
|
bool first = true;
|
||||||
if (i != 0) printf(", ");
|
for (uint32_t i = 0; i < map->capacity; i++) {
|
||||||
|
if (IS_UNDEF(map->entries[i].key)) continue;
|
||||||
|
if (!first) printf(", "); first = false;
|
||||||
|
|
||||||
_dumpValue(vm, map->entries[i].key, true);
|
_dumpValue(vm, map->entries[i].key, true);
|
||||||
printf(":");
|
printf(":");
|
||||||
_dumpValue(vm, map->entries[i].value, true);
|
_dumpValue(vm, map->entries[i].value, true);
|
||||||
|
|
||||||
|
// Terminate the dump if it's too long.
|
||||||
|
if (i >= MAX_DUMP_ELEMENTS) {
|
||||||
|
printf("...");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
printf("}");
|
printf("}");
|
||||||
}
|
}
|
||||||
|
90
src/var.c
90
src/var.c
@ -142,8 +142,8 @@ static void blackenObject(Object* obj, PKVM* vm) {
|
|||||||
Map* map = (Map*)obj;
|
Map* map = (Map*)obj;
|
||||||
for (uint32_t i = 0; i < map->capacity; i++) {
|
for (uint32_t i = 0; i < map->capacity; i++) {
|
||||||
if (IS_UNDEF(map->entries[i].key)) continue;
|
if (IS_UNDEF(map->entries[i].key)) continue;
|
||||||
grayObject(vm, AS_OBJ(map->entries[i].key));
|
grayValue(vm, map->entries[i].key);
|
||||||
grayObject(vm, AS_OBJ(map->entries[i].value));
|
grayValue(vm, map->entries[i].value);
|
||||||
}
|
}
|
||||||
vm->bytes_allocated += sizeof(Map);
|
vm->bytes_allocated += sizeof(Map);
|
||||||
vm->bytes_allocated += sizeof(MapEntry) * map->capacity;
|
vm->bytes_allocated += sizeof(MapEntry) * map->capacity;
|
||||||
@ -598,9 +598,17 @@ Var mapRemoveKey(PKVM* vm, Map* self, Var key) {
|
|||||||
// Clear the map if it's empty.
|
// Clear the map if it's empty.
|
||||||
mapClear(vm, self);
|
mapClear(vm, self);
|
||||||
|
|
||||||
} else if (self->capacity > MIN_CAPACITY &&
|
} else if ((self->capacity > MIN_CAPACITY) &&
|
||||||
self->capacity / GROW_FACTOR > self->count / MAP_LOAD_PERCENT * 100) {
|
(self->capacity / (GROW_FACTOR * GROW_FACTOR)) >
|
||||||
uint32_t capacity = self->capacity / GROW_FACTOR;
|
((self->count * 100) / MAP_LOAD_PERCENT)) {
|
||||||
|
|
||||||
|
// We grow the map when it's filled 75% (MAP_LOAD_PERCENT) by 2
|
||||||
|
// (GROW_FACTOR) but we're not shrink the map when it's half filled (ie.
|
||||||
|
// half of the capacity is 75%). Instead we wait till it'll become 1/4 is
|
||||||
|
// filled (1/4 = 1/(GROW_FACTOR*GROW_FACTOR)) to minimize the
|
||||||
|
// reallocations and which is more faster.
|
||||||
|
|
||||||
|
uint32_t capacity = self->capacity / (GROW_FACTOR * GROW_FACTOR);
|
||||||
if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY;
|
if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY;
|
||||||
|
|
||||||
_mapResize(vm, self, capacity);
|
_mapResize(vm, self, capacity);
|
||||||
@ -778,28 +786,44 @@ String* toString(PKVM* vm, Var v, bool recursive) {
|
|||||||
// If recursive return with quotes (ex: [42, "hello", 0..10]).
|
// If recursive return with quotes (ex: [42, "hello", 0..10]).
|
||||||
String* string = newStringLength(vm, ((String*)obj)->data, ((String*)obj)->length);
|
String* string = newStringLength(vm, ((String*)obj)->data, ((String*)obj)->length);
|
||||||
if (!recursive) return string;
|
if (!recursive) return string;
|
||||||
else return stringFormat(vm, "\"@\"", string);
|
vmPushTempRef(vm, &string->_super);
|
||||||
|
String* repr = stringFormat(vm, "\"@\"", string);
|
||||||
|
vmPopTempRef(vm);
|
||||||
|
return repr;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OBJ_LIST: {
|
case OBJ_LIST:
|
||||||
|
{
|
||||||
List* list = (List*)obj;
|
List* list = (List*)obj;
|
||||||
|
if (list->elements.count == 0) return newStringLength(vm, "[]", 2);
|
||||||
|
|
||||||
String* result = newStringLength(vm, "[", 1);
|
String* result = newStringLength(vm, "[", 1);
|
||||||
|
vmPushTempRef(vm, &result->_super); // result
|
||||||
|
|
||||||
for (uint32_t i = 0; i < list->elements.count; i++) {
|
for (uint32_t i = 0; i < list->elements.count; i++) {
|
||||||
const char* fmt = (i != 0) ? "@, @" : "@@";
|
const char* fmt = (i != 0) ? "@, @" : "@@";
|
||||||
|
|
||||||
vmPushTempRef(vm, &result->_super);
|
String* elem_str = toString(vm, list->elements.data[i], true);
|
||||||
result = stringFormat(vm, fmt, result,
|
vmPushTempRef(vm, &elem_str->_super); // elem_str
|
||||||
toString(vm, list->elements.data[i], true));
|
result = stringFormat(vm, fmt, result, elem_str);
|
||||||
vmPopTempRef(vm);
|
vmPopTempRef(vm); // elem_str
|
||||||
|
|
||||||
|
vmPopTempRef(vm); // result (old pointer)
|
||||||
|
vmPushTempRef(vm, &result->_super); // result (old pointer)
|
||||||
}
|
}
|
||||||
return stringFormat(vm, "@]", result);
|
|
||||||
|
result = stringFormat(vm, "@]", result);
|
||||||
|
vmPopTempRef(vm); // result (last pointer)
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OBJ_MAP:
|
case OBJ_MAP:
|
||||||
{
|
{
|
||||||
Map* map = (Map*)obj;
|
Map* map = (Map*)obj;
|
||||||
|
if (map->entries == NULL) return newStringLength(vm, "{}", 2);
|
||||||
|
|
||||||
String* result = newStringLength(vm, "{", 1);
|
String* result = newStringLength(vm, "{", 1);
|
||||||
|
vmPushTempRef(vm, &result->_super); // result
|
||||||
|
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
bool _first = true; // For first element no ',' required.
|
bool _first = true; // For first element no ',' required.
|
||||||
@ -817,34 +841,40 @@ String* toString(PKVM* vm, Var v, bool recursive) {
|
|||||||
if (_done) break;
|
if (_done) break;
|
||||||
|
|
||||||
const char* fmt = (!_first) ? "@, @:@" : "@@:@";
|
const char* fmt = (!_first) ? "@, @:@" : "@@:@";
|
||||||
vmPushTempRef(vm, &result->_super);
|
|
||||||
result = stringFormat(vm, fmt, result,
|
String* key_str = toString(vm, map->entries[i].key, true);
|
||||||
toString(vm, map->entries[i].key, true),
|
vmPushTempRef(vm, &key_str->_super); // key_str
|
||||||
toString(vm, map->entries[i].value, true));
|
|
||||||
vmPopTempRef(vm);
|
String* val_str = toString(vm, map->entries[i].value, true);
|
||||||
|
vmPushTempRef(vm, &val_str->_super); // val_str
|
||||||
|
|
||||||
|
result = stringFormat(vm, fmt, result, key_str, val_str);
|
||||||
|
vmPopTempRef(vm); // val_str
|
||||||
|
vmPopTempRef(vm); // key_str
|
||||||
|
|
||||||
|
vmPopTempRef(vm); // result (old pointer)
|
||||||
|
vmPushTempRef(vm, &result->_super); // result (new pointer)
|
||||||
|
|
||||||
_first = false;
|
_first = false;
|
||||||
i++;
|
i++;
|
||||||
} while (i < map->capacity);
|
} while (i < map->capacity);
|
||||||
|
|
||||||
return stringFormat(vm, "@}", result);
|
result = stringFormat(vm, "@}", result);
|
||||||
|
vmPopTempRef(vm); // result (last pointer)
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OBJ_RANGE:
|
case OBJ_RANGE:
|
||||||
{
|
{
|
||||||
Range* range = (Range*)obj;
|
Range* range = (Range*)obj;
|
||||||
|
|
||||||
String* from = toString(vm, VAR_NUM(range->from), false);
|
// FIXME: Validate I might need some review on the below one.
|
||||||
vmPushTempRef(vm, &from->_super);
|
char buff_from[50];
|
||||||
|
snprintf(buff_from, 50, "%f", range->from);
|
||||||
|
char buff_to[50];
|
||||||
|
snprintf(buff_to, 50, "%f", range->to);
|
||||||
|
|
||||||
String* to = toString(vm, VAR_NUM(range->to), false);
|
return stringFormat(vm, "[Range:$..$]", buff_from, buff_to);
|
||||||
vmPushTempRef(vm, &from->_super);
|
|
||||||
|
|
||||||
String* str = stringFormat(vm, "[Range:@..@]", from, to);
|
|
||||||
vmPopTempRef(vm); // to.
|
|
||||||
vmPopTempRef(vm); // from.
|
|
||||||
|
|
||||||
return str;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case OBJ_SCRIPT: {
|
case OBJ_SCRIPT: {
|
||||||
@ -904,7 +934,7 @@ String* stringFormat(PKVM* vm, const char* fmt, ...) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '@':
|
case '@':
|
||||||
total_length += AS_STRING(va_arg(arg_list, Var))->length;
|
total_length += va_arg(arg_list, String*)->length;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -929,7 +959,7 @@ String* stringFormat(PKVM* vm, const char* fmt, ...) {
|
|||||||
|
|
||||||
case '@':
|
case '@':
|
||||||
{
|
{
|
||||||
String* string = AS_STRING(va_arg(arg_list, Var));
|
String* string = va_arg(arg_list, String*);
|
||||||
memcpy(buff, string->data, string->length);
|
memcpy(buff, string->data, string->length);
|
||||||
buff += string->length;
|
buff += string->length;
|
||||||
} break;
|
} break;
|
||||||
|
127
src/vm.c
127
src/vm.c
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
// The heap size for the next GC will be calculated as the bytes we have
|
// The heap size for the next GC will be calculated as the bytes we have
|
||||||
// allocated so far plus the fill factor of it.
|
// allocated so far plus the fill factor of it.
|
||||||
#define HEAP_FILL_PERCENT 50
|
#define HEAP_FILL_PERCENT 75
|
||||||
|
|
||||||
static void* defaultRealloc(void* memory, size_t new_size, void* user_data) {
|
static void* defaultRealloc(void* memory, size_t new_size, void* user_data) {
|
||||||
if (new_size == 0) {
|
if (new_size == 0) {
|
||||||
@ -109,7 +109,7 @@ void pkFreeVM(PKVM* self) {
|
|||||||
|
|
||||||
// Tell the host application that it forget to release all of it's handles
|
// Tell the host application that it forget to release all of it's handles
|
||||||
// before freeing the VM.
|
// before freeing the VM.
|
||||||
__ASSERT(self->handles != NULL, "Not all handles were released.");
|
__ASSERT(self->handles == NULL, "Not all handles were released.");
|
||||||
|
|
||||||
DEALLOCATE(self, self);
|
DEALLOCATE(self, self);
|
||||||
}
|
}
|
||||||
@ -497,7 +497,7 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
|||||||
#define PUSH(value) (*vm->fiber->sp++ = (value))
|
#define PUSH(value) (*vm->fiber->sp++ = (value))
|
||||||
#define POP() (*(--vm->fiber->sp))
|
#define POP() (*(--vm->fiber->sp))
|
||||||
#define DROP() (--vm->fiber->sp)
|
#define DROP() (--vm->fiber->sp)
|
||||||
#define PEEK() (*(vm->fiber->sp - 1))
|
#define PEEK(off) (*(vm->fiber->sp + (off)))
|
||||||
#define READ_BYTE() (*IP++)
|
#define READ_BYTE() (*IP++)
|
||||||
#define READ_SHORT() (IP+=2, (uint16_t)((IP[-2] << 8) | IP[-1]))
|
#define READ_SHORT() (IP+=2, (uint16_t)((IP[-2] << 8) | IP[-1]))
|
||||||
|
|
||||||
@ -535,7 +535,7 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
|||||||
#if DEBUG_DUMP_CALL_STACK
|
#if DEBUG_DUMP_CALL_STACK
|
||||||
#define DEBUG_CALL_STACK() \
|
#define DEBUG_CALL_STACK() \
|
||||||
do { \
|
do { \
|
||||||
/* system("cls"); */ \
|
system("cls"); \
|
||||||
dumpGlobalValues(vm); \
|
dumpGlobalValues(vm); \
|
||||||
dumpStackFrame(vm); \
|
dumpStackFrame(vm); \
|
||||||
} while (false)
|
} while (false)
|
||||||
@ -603,18 +603,19 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
|||||||
|
|
||||||
OPCODE(LIST_APPEND):
|
OPCODE(LIST_APPEND):
|
||||||
{
|
{
|
||||||
Var elem = POP();
|
Var elem = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||||
Var list = PEEK();
|
Var list = PEEK(-2);
|
||||||
ASSERT(IS_OBJ(list) && AS_OBJ(list)->type == OBJ_LIST, OOPS);
|
ASSERT(IS_OBJ(list) && AS_OBJ(list)->type == OBJ_LIST, OOPS);
|
||||||
varBufferWrite(&((List*)AS_OBJ(list))->elements, vm, elem);
|
varBufferWrite(&((List*)AS_OBJ(list))->elements, vm, elem);
|
||||||
|
POP(); // elem
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
OPCODE(MAP_INSERT):
|
OPCODE(MAP_INSERT):
|
||||||
{
|
{
|
||||||
Var value = POP();
|
Var value = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||||
Var key = POP();
|
Var key = PEEK(-2); // Don't pop yet, we need the reference for gc.
|
||||||
Var on = PEEK();
|
Var on = PEEK(-3);
|
||||||
|
|
||||||
ASSERT(IS_OBJ(on) && AS_OBJ(on)->type == OBJ_MAP, OOPS);
|
ASSERT(IS_OBJ(on) && AS_OBJ(on)->type == OBJ_MAP, OOPS);
|
||||||
|
|
||||||
@ -623,8 +624,11 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
|||||||
} else {
|
} else {
|
||||||
mapSet(vm, (Map*)AS_OBJ(on), key, value);
|
mapSet(vm, (Map*)AS_OBJ(on), key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
varsetSubscript(vm, on, key, value);
|
varsetSubscript(vm, on, key, value);
|
||||||
|
|
||||||
|
POP(); // value
|
||||||
|
POP(); // key
|
||||||
|
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
@ -661,13 +665,13 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
|||||||
OPCODE(STORE_LOCAL_8):
|
OPCODE(STORE_LOCAL_8):
|
||||||
{
|
{
|
||||||
int index = (int)(instruction - OP_STORE_LOCAL_0);
|
int index = (int)(instruction - OP_STORE_LOCAL_0);
|
||||||
rbp[index + 1] = PEEK(); // +1: rbp[0] is return value.
|
rbp[index + 1] = PEEK(-1); // +1: rbp[0] is return value.
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
OPCODE(STORE_LOCAL_N):
|
OPCODE(STORE_LOCAL_N):
|
||||||
{
|
{
|
||||||
uint16_t index = READ_SHORT();
|
uint16_t index = READ_SHORT();
|
||||||
rbp[index + 1] = PEEK(); // +1: rbp[0] is return value.
|
rbp[index + 1] = PEEK(-1); // +1: rbp[0] is return value.
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -683,7 +687,7 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
|||||||
{
|
{
|
||||||
uint16_t index = READ_SHORT();
|
uint16_t index = READ_SHORT();
|
||||||
ASSERT(index < script->globals.count, OOPS);
|
ASSERT(index < script->globals.count, OOPS);
|
||||||
script->globals.data[index] = PEEK();
|
script->globals.data[index] = PEEK(-1);
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -841,16 +845,19 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
|||||||
|
|
||||||
OPCODE(GET_ATTRIB):
|
OPCODE(GET_ATTRIB):
|
||||||
{
|
{
|
||||||
Var on = POP();
|
Var on = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||||
String* name = script->names.data[READ_SHORT()];
|
String* name = script->names.data[READ_SHORT()];
|
||||||
PUSH(varGetAttrib(vm, on, name));
|
Var value = varGetAttrib(vm, on, name);
|
||||||
|
POP(); // on
|
||||||
|
PUSH(value);
|
||||||
|
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
OPCODE(GET_ATTRIB_KEEP):
|
OPCODE(GET_ATTRIB_KEEP):
|
||||||
{
|
{
|
||||||
Var on = PEEK();
|
Var on = PEEK(-1);
|
||||||
String* name = script->names.data[READ_SHORT()];
|
String* name = script->names.data[READ_SHORT()];
|
||||||
PUSH(varGetAttrib(vm, on, name));
|
PUSH(varGetAttrib(vm, on, name));
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
@ -859,28 +866,36 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
|||||||
|
|
||||||
OPCODE(SET_ATTRIB):
|
OPCODE(SET_ATTRIB):
|
||||||
{
|
{
|
||||||
Var value = POP();
|
Var value = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||||
Var on = POP();
|
Var on = PEEK(-2); // Don't pop yet, we need the reference for gc.
|
||||||
String* name = script->names.data[READ_SHORT()];
|
String* name = script->names.data[READ_SHORT()];
|
||||||
varSetAttrib(vm, on, name, value);
|
varSetAttrib(vm, on, name, value);
|
||||||
|
|
||||||
|
POP(); // value
|
||||||
|
POP(); // on
|
||||||
PUSH(value);
|
PUSH(value);
|
||||||
|
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
OPCODE(GET_SUBSCRIPT):
|
OPCODE(GET_SUBSCRIPT):
|
||||||
{
|
{
|
||||||
Var key = POP();
|
Var key = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||||
Var on = POP();
|
Var on = PEEK(-2); // Don't pop yet, we need the reference for gc.
|
||||||
PUSH(varGetSubscript(vm, on, key));
|
Var value = varGetSubscript(vm, on, key);
|
||||||
|
POP(); // key
|
||||||
|
POP(); // on
|
||||||
|
PUSH(value);
|
||||||
|
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
OPCODE(GET_SUBSCRIPT_KEEP):
|
OPCODE(GET_SUBSCRIPT_KEEP):
|
||||||
{
|
{
|
||||||
Var key = *(vm->fiber->sp - 1);
|
Var key = PEEK(-1);
|
||||||
Var on = *(vm->fiber->sp - 2);
|
Var on = PEEK(-2);
|
||||||
PUSH(varGetSubscript(vm, on, key));
|
PUSH(varGetSubscript(vm, on, key));
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
@ -888,14 +903,16 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
|||||||
|
|
||||||
OPCODE(SET_SUBSCRIPT):
|
OPCODE(SET_SUBSCRIPT):
|
||||||
{
|
{
|
||||||
Var value = POP();
|
Var value = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||||
Var key = POP();
|
Var key = PEEK(-2); // Don't pop yet, we need the reference for gc.
|
||||||
Var on = POP();
|
Var on = PEEK(-3); // Don't pop yet, we need the reference for gc.
|
||||||
|
|
||||||
varsetSubscript(vm, on, key, value);
|
varsetSubscript(vm, on, key, value);
|
||||||
CHECK_ERROR();
|
POP(); // value
|
||||||
|
POP(); // key
|
||||||
|
POP(); // on
|
||||||
PUSH(value);
|
PUSH(value);
|
||||||
|
|
||||||
|
CHECK_ERROR();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -924,40 +941,60 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
|||||||
|
|
||||||
OPCODE(ADD):
|
OPCODE(ADD):
|
||||||
{
|
{
|
||||||
Var r = POP(), l = POP();
|
// Don't pop yet, we need the reference for gc.
|
||||||
PUSH(varAdd(vm, l, r));
|
Var r = PEEK(-1), l = PEEK(-2);
|
||||||
|
Var value = varAdd(vm, l, r);
|
||||||
|
POP(); POP(); // r, l
|
||||||
|
PUSH(value);
|
||||||
|
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
OPCODE(SUBTRACT):
|
OPCODE(SUBTRACT):
|
||||||
{
|
{
|
||||||
Var r = POP(), l = POP();
|
// Don't pop yet, we need the reference for gc.
|
||||||
PUSH(varSubtract(vm, l, r));
|
Var r = PEEK(-1), l = PEEK(-2);
|
||||||
|
Var value = varSubtract(vm, l, r);
|
||||||
|
POP(); POP(); // r, l
|
||||||
|
PUSH(value);
|
||||||
|
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
OPCODE(MULTIPLY):
|
OPCODE(MULTIPLY):
|
||||||
{
|
{
|
||||||
Var r = POP(), l = POP();
|
// Don't pop yet, we need the reference for gc.
|
||||||
PUSH(varMultiply(vm, l, r));
|
Var r = PEEK(-1), l = PEEK(-2);
|
||||||
|
Var value = varMultiply(vm, l, r);
|
||||||
|
POP(); POP(); // r, l
|
||||||
|
PUSH(value);
|
||||||
|
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
OPCODE(DIVIDE):
|
OPCODE(DIVIDE):
|
||||||
{
|
{
|
||||||
Var r = POP(), l = POP();
|
// Don't pop yet, we need the reference for gc.
|
||||||
PUSH(varDivide(vm, l, r));
|
Var r = PEEK(-1), l = PEEK(-2);
|
||||||
|
Var value = varMultiply(vm, l, r);
|
||||||
|
POP(); POP(); // r, l
|
||||||
|
PUSH(value);
|
||||||
|
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
|
||||||
OPCODE(MOD):
|
OPCODE(MOD):
|
||||||
{
|
{
|
||||||
Var r = POP(), l = POP();
|
// Don't pop yet, we need the reference for gc.
|
||||||
PUSH(varModulo(vm, l, r));
|
Var r = PEEK(-1), l = PEEK(-2);
|
||||||
|
Var value = varModulo(vm, l, r);
|
||||||
|
POP(); POP(); // r, l
|
||||||
|
PUSH(value);
|
||||||
|
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
@ -985,7 +1022,7 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
|||||||
OPCODE(LT):
|
OPCODE(LT):
|
||||||
{
|
{
|
||||||
Var r = POP(), l = POP();
|
Var r = POP(), l = POP();
|
||||||
PUSH(VAR_BOOL(varLesser(vm, l, r)));
|
PUSH(VAR_BOOL(varLesser(l, r)));
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
@ -993,7 +1030,7 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
|||||||
OPCODE(LTEQ):
|
OPCODE(LTEQ):
|
||||||
{
|
{
|
||||||
Var r = POP(), l = POP();
|
Var r = POP(), l = POP();
|
||||||
bool lteq = varLesser(vm, l, r);
|
bool lteq = varLesser(l, r);
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
|
|
||||||
if (!lteq) {
|
if (!lteq) {
|
||||||
@ -1008,7 +1045,7 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
|||||||
OPCODE(GT):
|
OPCODE(GT):
|
||||||
{
|
{
|
||||||
Var r = POP(), l = POP();
|
Var r = POP(), l = POP();
|
||||||
PUSH(VAR_BOOL(varGreater(vm, l, r)));
|
PUSH(VAR_BOOL(varGreater(l, r)));
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
@ -1016,7 +1053,7 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
|||||||
OPCODE(GTEQ):
|
OPCODE(GTEQ):
|
||||||
{
|
{
|
||||||
Var r = POP(), l = POP();
|
Var r = POP(), l = POP();
|
||||||
bool gteq = varGreater(vm, l, r);
|
bool gteq = varGreater(l, r);
|
||||||
CHECK_ERROR();
|
CHECK_ERROR();
|
||||||
|
|
||||||
if (!gteq) {
|
if (!gteq) {
|
||||||
@ -1030,11 +1067,13 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
|||||||
|
|
||||||
OPCODE(RANGE):
|
OPCODE(RANGE):
|
||||||
{
|
{
|
||||||
Var to = POP();
|
Var to = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||||
Var from = POP();
|
Var from = PEEK(-2); // Don't pop yet, we need the reference for gc.
|
||||||
if (!IS_NUM(from) || !IS_NUM(to)) {
|
if (!IS_NUM(from) || !IS_NUM(to)) {
|
||||||
RUNTIME_ERROR(newString(vm, "Range arguments must be number."));
|
RUNTIME_ERROR(newString(vm, "Range arguments must be number."));
|
||||||
}
|
}
|
||||||
|
POP(); // to
|
||||||
|
POP(); // from
|
||||||
PUSH(VAR_OBJ(newRange(vm, AS_NUM(from), AS_NUM(to))));
|
PUSH(VAR_OBJ(newRange(vm, AS_NUM(from), AS_NUM(to))));
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
from lang import clock
|
from lang import clock
|
||||||
|
|
||||||
def fib(n)
|
def fib(n)
|
||||||
if n < 2 then return 1 end
|
if n < 2 then return n end
|
||||||
return fib(n - 1) + fib(n - 2)
|
return fib(n - 1) + fib(n - 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import time
|
import time
|
||||||
|
|
||||||
def fib(n):
|
def fib(n):
|
||||||
if n < 2: return 1
|
if n < 2: return n
|
||||||
return fib(n - 1) + fib(n - 2)
|
return fib(n - 1) + fib(n - 2)
|
||||||
|
|
||||||
start = time.process_time()
|
start = time.process_time()
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
def fib(n)
|
def fib(n)
|
||||||
if n < 2 then
|
if n < 2 then
|
||||||
1
|
n
|
||||||
else
|
else
|
||||||
fib(n - 1) + fib(n - 2)
|
fib(n - 1) + fib(n - 2)
|
||||||
end
|
end
|
||||||
|
12
test/benchmark/fib/fib.wren
Normal file
12
test/benchmark/fib/fib.wren
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
class Fib {
|
||||||
|
static get(n) {
|
||||||
|
if (n < 2) return n
|
||||||
|
return get(n - 1) + get(n - 2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var start = System.clock
|
||||||
|
for (i in 0..10) {
|
||||||
|
System.print(Fib.get(28))
|
||||||
|
}
|
||||||
|
System.print("elapsed: %(System.clock - start)")
|
10
test/benchmark/for/for.js
Normal file
10
test/benchmark/for/for.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
var start = +new Date();
|
||||||
|
|
||||||
|
list = []
|
||||||
|
for (var i = 0; i < 10000000; i++) { list.push(i) }
|
||||||
|
sum = 0
|
||||||
|
for (var i = 0; i < list.length; i++) { sum += list[i]; }
|
||||||
|
console.log(sum)
|
||||||
|
|
||||||
|
var end = +new Date();
|
||||||
|
console.log('elapsed: ' + (end - start)/1000 + 's');
|
11
test/benchmark/for/for.pk
Normal file
11
test/benchmark/for/for.pk
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from lang import clock
|
||||||
|
|
||||||
|
start = clock()
|
||||||
|
|
||||||
|
list = []
|
||||||
|
for i in 0..10000000 do list_append(list, i) end
|
||||||
|
sum = 0
|
||||||
|
for i in list do sum += i end
|
||||||
|
print(sum)
|
||||||
|
|
||||||
|
print("elapsed:", clock() - start)
|
11
test/benchmark/for/for.py
Normal file
11
test/benchmark/for/for.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from time import process_time as clock
|
||||||
|
|
||||||
|
start = clock()
|
||||||
|
|
||||||
|
list = []
|
||||||
|
for i in range(10000000): list.append(i)
|
||||||
|
sum = 0
|
||||||
|
for i in list: sum += i
|
||||||
|
print(sum)
|
||||||
|
|
||||||
|
print("elapsed:", clock() - start)
|
10
test/benchmark/for/for.rb
Normal file
10
test/benchmark/for/for.rb
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
start = Time.now
|
||||||
|
|
||||||
|
list = []
|
||||||
|
for i in 0...10000000 do list.append(i) end
|
||||||
|
sum = 0
|
||||||
|
for i in list do sum += i end
|
||||||
|
puts sum
|
||||||
|
|
||||||
|
puts "elapsed: " + (Time.now - start).to_s + ' s'
|
10
test/benchmark/for/for.wren
Normal file
10
test/benchmark/for/for.wren
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
var start = System.clock
|
||||||
|
|
||||||
|
var list = []
|
||||||
|
for (i in 0...10000000) list.add(i)
|
||||||
|
var sum = 0
|
||||||
|
for (i in list) sum = sum + i
|
||||||
|
System.print(sum)
|
||||||
|
|
||||||
|
System.print("elapsed: %(System.clock - start)")
|
Loading…
Reference in New Issue
Block a user