mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-11 07:00:58 +08:00
gc bugs fixed
- popping operands from the stack was too early -fixed - some temproary string objects weren't pushed to the vm's temp root -fixed - and some minor bug fixed
This commit is contained in:
parent
79a3700284
commit
df93b2c1ec
35
cli/TODO.txt
35
cli/TODO.txt
@ -1,25 +1,30 @@
|
||||
|
||||
// To implement.
|
||||
|
||||
[ ] Implement argparse.
|
||||
[ ] Implement resolve path in cli.
|
||||
- Implement argparse.
|
||||
- -v --version
|
||||
- emit opcodes
|
||||
- maybe write a similer .pyc file for pocket
|
||||
|
||||
[ ] Structs.
|
||||
[ ] Implement math library.
|
||||
[ ] Single header for embedding.
|
||||
[ ] Implement fiber from script body and vm run fibers (not scripts).
|
||||
- Ignore line with '\' character.
|
||||
- Implement resolve path in cli.
|
||||
|
||||
- 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.
|
||||
[ ] C Integration api (including add core lib from host application).
|
||||
[ ] REPL.
|
||||
[ ] compile expression for a script.
|
||||
[ ] Var handler implement.
|
||||
[ ] Make it possible to override function names.
|
||||
- C Integration api (including add core lib from host application).
|
||||
- REPL.
|
||||
- compile expression for a script.
|
||||
- Var handler implement.
|
||||
- Make it possible to override function names.
|
||||
- To do so the functions and global variables should be in the same
|
||||
buffer as the property of the script.
|
||||
[ ] Hex, binary literals and floats like ".5".
|
||||
[ ] Function docstring property.
|
||||
[ ] Union tagging alter in var.
|
||||
[ ] (future) add structs and maybe enums.
|
||||
- Hex, binary literals and floats like ".5".
|
||||
- Function docstring property.
|
||||
- Union tagging alter in var.
|
||||
- (future) add structs and maybe enums.
|
||||
|
||||
// Add more.
|
||||
[ ] Compilte core methods.
|
||||
|
@ -36,8 +36,10 @@ void register_cli_modules(PKVM* vm) {
|
||||
PkHandle* path = pkNewModule(vm, "path");
|
||||
pkModuleAddFunction(vm, path, "abspath", stdPathAbspath, 1);
|
||||
pkModuleAddFunction(vm, path, "curdir", stdPathCurdir, 0);
|
||||
pkReleaseHandle(vm, path);
|
||||
|
||||
PkHandle* test = pkNewModule(vm, "test");
|
||||
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.resolve_path_fn = resolvePath;
|
||||
|
||||
|
||||
// FIXME: this is temp till arg parse implemented.
|
||||
if (argc >= 3 && strcmp(argv[1], "-c") == 0) {
|
||||
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 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) {
|
||||
// No need to pass file (since there is only script that'll ever run on the
|
||||
// browser.
|
||||
@ -47,7 +47,7 @@ int runSource(const char* source) {
|
||||
config.resolve_path_fn = resolvePath;
|
||||
|
||||
PKVM* vm = pkNewVM(&config);
|
||||
PKInterpretResult result = pkInterpretSource(vm, source, "@try");
|
||||
PkInterpretResult result = pkInterpretSource(vm, source, "@try");
|
||||
|
||||
pkFreeVM(vm);
|
||||
|
||||
|
89
src/core.c
89
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.
|
||||
#define CHECK_GET_ARG_API_ERRORS() \
|
||||
__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."); \
|
||||
((void*)0)
|
||||
|
||||
@ -79,7 +79,7 @@ int pkGetArgc(PKVM* vm) {
|
||||
|
||||
PkVar pkGetArg(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(arg > 0 || arg <= ARGC, "Invalid argument index.");
|
||||
|
||||
return &(ARG(arg));
|
||||
}
|
||||
@ -217,19 +217,23 @@ static inline bool validateIndex(PKVM* vm, int32_t index, int32_t size,
|
||||
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.
|
||||
static bool validateArgString(PKVM* vm, Var var, String** value, int arg_ind) {
|
||||
if (!IS_OBJ(var) || AS_OBJ(var)->type != OBJ_STRING) {
|
||||
String* str_arg = toString(vm, VAR_NUM((double)arg_ind), false);
|
||||
vmPushTempRef(vm, &str_arg->_super);
|
||||
vm->fiber->error = stringFormat(vm, "Expected a string at argument @.",
|
||||
str_arg, false);
|
||||
vmPopTempRef(vm);
|
||||
}
|
||||
*value = (String*)AS_OBJ(var);
|
||||
return true;
|
||||
}
|
||||
#define VALIDATE_ARG_OBJ(m_class, m_type, m_name) \
|
||||
static bool validateArg##m_class(PKVM* vm, int arg, m_class** value) { \
|
||||
Var var = ARG(arg); \
|
||||
ASSERT(arg > 0 && arg <= ARGC, OOPS); \
|
||||
if (!IS_OBJ(var) || AS_OBJ(var)->type != m_type) { \
|
||||
char buff[12]; sprintf(buff, "%d", arg); \
|
||||
vm->fiber->error = stringFormat(vm, "Expected a " m_name \
|
||||
" at argument $.", buff, false); \
|
||||
} \
|
||||
*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 */
|
||||
@ -284,6 +288,10 @@ FN_IS_OBJ_TYPE(Function, OBJ_FUNC)
|
||||
FN_IS_OBJ_TYPE(Script, OBJ_SCRIPT)
|
||||
FN_IS_OBJ_TYPE(UserObj, OBJ_USER)
|
||||
|
||||
void coreTypeName(PKVM* vm) {
|
||||
RET(VAR_OBJ(&newString(vm, varTypeName(ARG1))->_super));
|
||||
}
|
||||
|
||||
void coreAssert(PKVM* vm) {
|
||||
int argc = ARGC;
|
||||
if (argc != 1 && argc != 2) {
|
||||
@ -346,12 +354,12 @@ void corePrint(PKVM* vm) {
|
||||
vm->config.write_fn(vm, "\n");
|
||||
}
|
||||
|
||||
// string functions
|
||||
// ----------------
|
||||
// String functions.
|
||||
// -----------------
|
||||
|
||||
void coreStrLower(PKVM* vm) {
|
||||
String* str;
|
||||
if (!validateArgString(vm, ARG1, &str, 1)) return;
|
||||
if (!validateArgString(vm, 1, &str)) return;
|
||||
|
||||
String* result = newStringLength(vm, str->data, str->length);
|
||||
char* data = result->data;
|
||||
@ -364,7 +372,7 @@ void coreStrLower(PKVM* vm) {
|
||||
|
||||
void coreStrUpper(PKVM* vm) {
|
||||
String* str;
|
||||
if (!validateArgString(vm, ARG1, &str, 1)) return;
|
||||
if (!validateArgString(vm, 1, &str)) return;
|
||||
|
||||
String* result = newStringLength(vm, str->data, str->length);
|
||||
char* data = result->data;
|
||||
@ -377,7 +385,7 @@ void coreStrUpper(PKVM* vm) {
|
||||
|
||||
void coreStrStrip(PKVM* vm) {
|
||||
String* str;
|
||||
if (!validateArgString(vm, ARG1, &str, 1)) return;
|
||||
if (!validateArgString(vm, 1, &str)) return;
|
||||
|
||||
const char* start = str->data;
|
||||
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));
|
||||
}
|
||||
|
||||
// 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 */
|
||||
/*****************************************************************************/
|
||||
@ -456,6 +487,11 @@ void stdLangGC(PKVM* vm) {
|
||||
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
|
||||
// and write a new line at the end.
|
||||
void stdLangWrite(PKVM* vm) {
|
||||
@ -488,6 +524,8 @@ void initializeCore(PKVM* vm) {
|
||||
(int)strlen(name), argc, fn);
|
||||
|
||||
// Initialize builtin functions.
|
||||
INITALIZE_BUILTIN_FN("type_name", coreTypeName, 1);
|
||||
|
||||
INITALIZE_BUILTIN_FN("is_null", coreIsNull, 1);
|
||||
INITALIZE_BUILTIN_FN("is_bool", coreIsBool, 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_strip", coreStrStrip, 1);
|
||||
|
||||
// List functions.
|
||||
INITALIZE_BUILTIN_FN("list_append", coreListAppend, 2);
|
||||
|
||||
// Map functions.
|
||||
INITALIZE_BUILTIN_FN("map_remove", coreMapRemove, 2);
|
||||
|
||||
// Core Modules /////////////////////////////////////////////////////////////
|
||||
|
||||
Script* lang = newModuleInternal(vm, "lang");
|
||||
moduleAddFunctionInternal(vm, lang, "clock", stdLangClock, 0);
|
||||
moduleAddFunctionInternal(vm, lang, "gc", stdLangGC, 0);
|
||||
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:
|
||||
{
|
||||
if (o2->type == OBJ_STRING) {
|
||||
return VAR_OBJ(stringFormat(vm, "@@", v1, v2));
|
||||
return VAR_OBJ(stringFormat(vm, "@@", (String*)o1, (String*)o2));
|
||||
}
|
||||
} break;
|
||||
|
||||
@ -623,7 +668,7 @@ Var varModulo(PKVM* vm, Var v1, Var v2) {
|
||||
return VAR_NULL;
|
||||
}
|
||||
|
||||
bool varGreater(PKVM* vm, Var v1, Var v2) {
|
||||
bool varGreater(Var v1, Var v2) {
|
||||
double d1, d2;
|
||||
if (isNumeric(v1, &d1) && isNumeric(v2, &d2)) {
|
||||
return d1 > d2;
|
||||
@ -633,7 +678,7 @@ bool varGreater(PKVM* vm, Var v1, Var v2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool varLesser(PKVM* vm, Var v1, Var v2) {
|
||||
bool varLesser(Var v1, Var v2) {
|
||||
double d1, d2;
|
||||
if (isNumeric(v1, &d1) && isNumeric(v2, &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 varModulo(PKVM* vm, Var v1, Var v2);
|
||||
|
||||
bool varGreater(PKVM* vm, Var v1, Var v2);
|
||||
bool varLesser(PKVM* vm, Var v1, Var v2);
|
||||
bool varGreater(Var v1, Var v2);
|
||||
bool varLesser(Var v1, Var v2);
|
||||
|
||||
Var varGetAttrib(PKVM* vm, Var on, String* attrib);
|
||||
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 "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[] = {
|
||||
#define OPCODE(name, params, stack) #name,
|
||||
#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++) {
|
||||
if (i != 0) printf(", ");
|
||||
_dumpValue(vm, list->elements.data[i], true);
|
||||
|
||||
// Terminate the dump if it's too long.
|
||||
if (i >= MAX_DUMP_ELEMENTS) {
|
||||
printf("...");
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf("]");
|
||||
}
|
||||
@ -58,11 +67,21 @@ static void _dumpValue(PKVM* vm, Var value, bool recursive) {
|
||||
printf("{...}");
|
||||
} else {
|
||||
printf("{");
|
||||
for (uint32_t i = 0; i < map->count; i++) {
|
||||
if (i != 0) printf(", ");
|
||||
bool first = true;
|
||||
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);
|
||||
printf(":");
|
||||
_dumpValue(vm, map->entries[i].value, true);
|
||||
|
||||
// Terminate the dump if it's too long.
|
||||
if (i >= MAX_DUMP_ELEMENTS) {
|
||||
printf("...");
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
printf("}");
|
||||
}
|
||||
|
90
src/var.c
90
src/var.c
@ -142,8 +142,8 @@ static void blackenObject(Object* obj, PKVM* vm) {
|
||||
Map* map = (Map*)obj;
|
||||
for (uint32_t i = 0; i < map->capacity; i++) {
|
||||
if (IS_UNDEF(map->entries[i].key)) continue;
|
||||
grayObject(vm, AS_OBJ(map->entries[i].key));
|
||||
grayObject(vm, AS_OBJ(map->entries[i].value));
|
||||
grayValue(vm, map->entries[i].key);
|
||||
grayValue(vm, map->entries[i].value);
|
||||
}
|
||||
vm->bytes_allocated += sizeof(Map);
|
||||
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.
|
||||
mapClear(vm, self);
|
||||
|
||||
} else if (self->capacity > MIN_CAPACITY &&
|
||||
self->capacity / GROW_FACTOR > self->count / MAP_LOAD_PERCENT * 100) {
|
||||
uint32_t capacity = self->capacity / GROW_FACTOR;
|
||||
} else if ((self->capacity > MIN_CAPACITY) &&
|
||||
(self->capacity / (GROW_FACTOR * 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;
|
||||
|
||||
_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]).
|
||||
String* string = newStringLength(vm, ((String*)obj)->data, ((String*)obj)->length);
|
||||
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;
|
||||
if (list->elements.count == 0) return newStringLength(vm, "[]", 2);
|
||||
|
||||
String* result = newStringLength(vm, "[", 1);
|
||||
vmPushTempRef(vm, &result->_super); // result
|
||||
|
||||
for (uint32_t i = 0; i < list->elements.count; i++) {
|
||||
const char* fmt = (i != 0) ? "@, @" : "@@";
|
||||
|
||||
vmPushTempRef(vm, &result->_super);
|
||||
result = stringFormat(vm, fmt, result,
|
||||
toString(vm, list->elements.data[i], true));
|
||||
vmPopTempRef(vm);
|
||||
String* elem_str = toString(vm, list->elements.data[i], true);
|
||||
vmPushTempRef(vm, &elem_str->_super); // elem_str
|
||||
result = stringFormat(vm, fmt, result, elem_str);
|
||||
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:
|
||||
{
|
||||
Map* map = (Map*)obj;
|
||||
if (map->entries == NULL) return newStringLength(vm, "{}", 2);
|
||||
|
||||
String* result = newStringLength(vm, "{", 1);
|
||||
vmPushTempRef(vm, &result->_super); // result
|
||||
|
||||
uint32_t i = 0;
|
||||
bool _first = true; // For first element no ',' required.
|
||||
@ -817,34 +841,40 @@ String* toString(PKVM* vm, Var v, bool recursive) {
|
||||
if (_done) break;
|
||||
|
||||
const char* fmt = (!_first) ? "@, @:@" : "@@:@";
|
||||
vmPushTempRef(vm, &result->_super);
|
||||
result = stringFormat(vm, fmt, result,
|
||||
toString(vm, map->entries[i].key, true),
|
||||
toString(vm, map->entries[i].value, true));
|
||||
vmPopTempRef(vm);
|
||||
|
||||
String* key_str = toString(vm, map->entries[i].key, true);
|
||||
vmPushTempRef(vm, &key_str->_super); // key_str
|
||||
|
||||
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;
|
||||
i++;
|
||||
} while (i < map->capacity);
|
||||
|
||||
return stringFormat(vm, "@}", result);
|
||||
result = stringFormat(vm, "@}", result);
|
||||
vmPopTempRef(vm); // result (last pointer)
|
||||
return result;
|
||||
}
|
||||
|
||||
case OBJ_RANGE:
|
||||
{
|
||||
Range* range = (Range*)obj;
|
||||
|
||||
String* from = toString(vm, VAR_NUM(range->from), false);
|
||||
vmPushTempRef(vm, &from->_super);
|
||||
// FIXME: Validate I might need some review on the below one.
|
||||
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);
|
||||
vmPushTempRef(vm, &from->_super);
|
||||
|
||||
String* str = stringFormat(vm, "[Range:@..@]", from, to);
|
||||
vmPopTempRef(vm); // to.
|
||||
vmPopTempRef(vm); // from.
|
||||
|
||||
return str;
|
||||
return stringFormat(vm, "[Range:$..$]", buff_from, buff_to);
|
||||
}
|
||||
|
||||
case OBJ_SCRIPT: {
|
||||
@ -904,7 +934,7 @@ String* stringFormat(PKVM* vm, const char* fmt, ...) {
|
||||
break;
|
||||
|
||||
case '@':
|
||||
total_length += AS_STRING(va_arg(arg_list, Var))->length;
|
||||
total_length += va_arg(arg_list, String*)->length;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -929,7 +959,7 @@ String* stringFormat(PKVM* vm, const char* fmt, ...) {
|
||||
|
||||
case '@':
|
||||
{
|
||||
String* string = AS_STRING(va_arg(arg_list, Var));
|
||||
String* string = va_arg(arg_list, String*);
|
||||
memcpy(buff, string->data, string->length);
|
||||
buff += string->length;
|
||||
} break;
|
||||
|
135
src/vm.c
135
src/vm.c
@ -29,7 +29,7 @@
|
||||
|
||||
// The heap size for the next GC will be calculated as the bytes we have
|
||||
// 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) {
|
||||
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
|
||||
// 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);
|
||||
}
|
||||
@ -497,7 +497,7 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
#define PUSH(value) (*vm->fiber->sp++ = (value))
|
||||
#define POP() (*(--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_SHORT() (IP+=2, (uint16_t)((IP[-2] << 8) | IP[-1]))
|
||||
|
||||
@ -533,11 +533,11 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
#endif
|
||||
|
||||
#if DEBUG_DUMP_CALL_STACK
|
||||
#define DEBUG_CALL_STACK() \
|
||||
do { \
|
||||
/* system("cls"); */ \
|
||||
dumpGlobalValues(vm); \
|
||||
dumpStackFrame(vm); \
|
||||
#define DEBUG_CALL_STACK() \
|
||||
do { \
|
||||
system("cls"); \
|
||||
dumpGlobalValues(vm); \
|
||||
dumpStackFrame(vm); \
|
||||
} while (false)
|
||||
#else
|
||||
#define DEBUG_CALL_STACK() ((void*)0)
|
||||
@ -603,18 +603,19 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
|
||||
OPCODE(LIST_APPEND):
|
||||
{
|
||||
Var elem = POP();
|
||||
Var list = PEEK();
|
||||
Var elem = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||
Var list = PEEK(-2);
|
||||
ASSERT(IS_OBJ(list) && AS_OBJ(list)->type == OBJ_LIST, OOPS);
|
||||
varBufferWrite(&((List*)AS_OBJ(list))->elements, vm, elem);
|
||||
POP(); // elem
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
OPCODE(MAP_INSERT):
|
||||
{
|
||||
Var value = POP();
|
||||
Var key = POP();
|
||||
Var on = PEEK();
|
||||
Var value = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||
Var key = PEEK(-2); // Don't pop yet, we need the reference for gc.
|
||||
Var on = PEEK(-3);
|
||||
|
||||
ASSERT(IS_OBJ(on) && AS_OBJ(on)->type == OBJ_MAP, OOPS);
|
||||
|
||||
@ -623,8 +624,11 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
} else {
|
||||
mapSet(vm, (Map*)AS_OBJ(on), key, value);
|
||||
}
|
||||
|
||||
varsetSubscript(vm, on, key, value);
|
||||
|
||||
POP(); // value
|
||||
POP(); // key
|
||||
|
||||
CHECK_ERROR();
|
||||
DISPATCH();
|
||||
}
|
||||
@ -661,13 +665,13 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
OPCODE(STORE_LOCAL_8):
|
||||
{
|
||||
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();
|
||||
}
|
||||
OPCODE(STORE_LOCAL_N):
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
@ -683,7 +687,7 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
{
|
||||
uint16_t index = READ_SHORT();
|
||||
ASSERT(index < script->globals.count, OOPS);
|
||||
script->globals.data[index] = PEEK();
|
||||
script->globals.data[index] = PEEK(-1);
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
@ -841,16 +845,19 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
|
||||
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()];
|
||||
PUSH(varGetAttrib(vm, on, name));
|
||||
Var value = varGetAttrib(vm, on, name);
|
||||
POP(); // on
|
||||
PUSH(value);
|
||||
|
||||
CHECK_ERROR();
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
OPCODE(GET_ATTRIB_KEEP):
|
||||
{
|
||||
Var on = PEEK();
|
||||
Var on = PEEK(-1);
|
||||
String* name = script->names.data[READ_SHORT()];
|
||||
PUSH(varGetAttrib(vm, on, name));
|
||||
CHECK_ERROR();
|
||||
@ -859,28 +866,36 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
|
||||
OPCODE(SET_ATTRIB):
|
||||
{
|
||||
Var value = POP();
|
||||
Var on = POP();
|
||||
Var value = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||
Var on = PEEK(-2); // Don't pop yet, we need the reference for gc.
|
||||
String* name = script->names.data[READ_SHORT()];
|
||||
varSetAttrib(vm, on, name, value);
|
||||
|
||||
POP(); // value
|
||||
POP(); // on
|
||||
PUSH(value);
|
||||
|
||||
CHECK_ERROR();
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
OPCODE(GET_SUBSCRIPT):
|
||||
{
|
||||
Var key = POP();
|
||||
Var on = POP();
|
||||
PUSH(varGetSubscript(vm, on, key));
|
||||
Var key = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||
Var on = PEEK(-2); // Don't pop yet, we need the reference for gc.
|
||||
Var value = varGetSubscript(vm, on, key);
|
||||
POP(); // key
|
||||
POP(); // on
|
||||
PUSH(value);
|
||||
|
||||
CHECK_ERROR();
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
OPCODE(GET_SUBSCRIPT_KEEP):
|
||||
{
|
||||
Var key = *(vm->fiber->sp - 1);
|
||||
Var on = *(vm->fiber->sp - 2);
|
||||
Var key = PEEK(-1);
|
||||
Var on = PEEK(-2);
|
||||
PUSH(varGetSubscript(vm, on, key));
|
||||
CHECK_ERROR();
|
||||
DISPATCH();
|
||||
@ -888,14 +903,16 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
|
||||
OPCODE(SET_SUBSCRIPT):
|
||||
{
|
||||
Var value = POP();
|
||||
Var key = POP();
|
||||
Var on = POP();
|
||||
|
||||
Var value = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||
Var key = PEEK(-2); // Don't pop yet, we need the reference for gc.
|
||||
Var on = PEEK(-3); // Don't pop yet, we need the reference for gc.
|
||||
varsetSubscript(vm, on, key, value);
|
||||
CHECK_ERROR();
|
||||
POP(); // value
|
||||
POP(); // key
|
||||
POP(); // on
|
||||
PUSH(value);
|
||||
|
||||
CHECK_ERROR();
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
@ -924,40 +941,60 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
|
||||
OPCODE(ADD):
|
||||
{
|
||||
Var r = POP(), l = POP();
|
||||
PUSH(varAdd(vm, l, r));
|
||||
// Don't pop yet, we need the reference for gc.
|
||||
Var r = PEEK(-1), l = PEEK(-2);
|
||||
Var value = varAdd(vm, l, r);
|
||||
POP(); POP(); // r, l
|
||||
PUSH(value);
|
||||
|
||||
CHECK_ERROR();
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
OPCODE(SUBTRACT):
|
||||
{
|
||||
Var r = POP(), l = POP();
|
||||
PUSH(varSubtract(vm, l, r));
|
||||
// Don't pop yet, we need the reference for gc.
|
||||
Var r = PEEK(-1), l = PEEK(-2);
|
||||
Var value = varSubtract(vm, l, r);
|
||||
POP(); POP(); // r, l
|
||||
PUSH(value);
|
||||
|
||||
CHECK_ERROR();
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
OPCODE(MULTIPLY):
|
||||
{
|
||||
Var r = POP(), l = POP();
|
||||
PUSH(varMultiply(vm, l, r));
|
||||
// Don't pop yet, we need the reference for gc.
|
||||
Var r = PEEK(-1), l = PEEK(-2);
|
||||
Var value = varMultiply(vm, l, r);
|
||||
POP(); POP(); // r, l
|
||||
PUSH(value);
|
||||
|
||||
CHECK_ERROR();
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
OPCODE(DIVIDE):
|
||||
{
|
||||
Var r = POP(), l = POP();
|
||||
PUSH(varDivide(vm, l, r));
|
||||
// Don't pop yet, we need the reference for gc.
|
||||
Var r = PEEK(-1), l = PEEK(-2);
|
||||
Var value = varMultiply(vm, l, r);
|
||||
POP(); POP(); // r, l
|
||||
PUSH(value);
|
||||
|
||||
CHECK_ERROR();
|
||||
DISPATCH();
|
||||
}
|
||||
|
||||
OPCODE(MOD):
|
||||
{
|
||||
Var r = POP(), l = POP();
|
||||
PUSH(varModulo(vm, l, r));
|
||||
// Don't pop yet, we need the reference for gc.
|
||||
Var r = PEEK(-1), l = PEEK(-2);
|
||||
Var value = varModulo(vm, l, r);
|
||||
POP(); POP(); // r, l
|
||||
PUSH(value);
|
||||
|
||||
CHECK_ERROR();
|
||||
DISPATCH();
|
||||
}
|
||||
@ -985,7 +1022,7 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
OPCODE(LT):
|
||||
{
|
||||
Var r = POP(), l = POP();
|
||||
PUSH(VAR_BOOL(varLesser(vm, l, r)));
|
||||
PUSH(VAR_BOOL(varLesser(l, r)));
|
||||
CHECK_ERROR();
|
||||
DISPATCH();
|
||||
}
|
||||
@ -993,7 +1030,7 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
OPCODE(LTEQ):
|
||||
{
|
||||
Var r = POP(), l = POP();
|
||||
bool lteq = varLesser(vm, l, r);
|
||||
bool lteq = varLesser(l, r);
|
||||
CHECK_ERROR();
|
||||
|
||||
if (!lteq) {
|
||||
@ -1008,7 +1045,7 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
OPCODE(GT):
|
||||
{
|
||||
Var r = POP(), l = POP();
|
||||
PUSH(VAR_BOOL(varGreater(vm, l, r)));
|
||||
PUSH(VAR_BOOL(varGreater(l, r)));
|
||||
CHECK_ERROR();
|
||||
DISPATCH();
|
||||
}
|
||||
@ -1016,7 +1053,7 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
OPCODE(GTEQ):
|
||||
{
|
||||
Var r = POP(), l = POP();
|
||||
bool gteq = varGreater(vm, l, r);
|
||||
bool gteq = varGreater(l, r);
|
||||
CHECK_ERROR();
|
||||
|
||||
if (!gteq) {
|
||||
@ -1030,11 +1067,13 @@ PkInterpretResult vmRunScript(PKVM* vm, Script* _script) {
|
||||
|
||||
OPCODE(RANGE):
|
||||
{
|
||||
Var to = POP();
|
||||
Var from = POP();
|
||||
Var to = PEEK(-1); // Don't pop yet, we need the reference for gc.
|
||||
Var from = PEEK(-2); // Don't pop yet, we need the reference for gc.
|
||||
if (!IS_NUM(from) || !IS_NUM(to)) {
|
||||
RUNTIME_ERROR(newString(vm, "Range arguments must be number."));
|
||||
}
|
||||
POP(); // to
|
||||
POP(); // from
|
||||
PUSH(VAR_OBJ(newRange(vm, AS_NUM(from), AS_NUM(to))));
|
||||
DISPATCH();
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
from lang import clock
|
||||
|
||||
def fib(n)
|
||||
if n < 2 then return 1 end
|
||||
if n < 2 then return n end
|
||||
return fib(n - 1) + fib(n - 2)
|
||||
end
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import time
|
||||
|
||||
def fib(n):
|
||||
if n < 2: return 1
|
||||
if n < 2: return n
|
||||
return fib(n - 1) + fib(n - 2)
|
||||
|
||||
start = time.process_time()
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
def fib(n)
|
||||
if n < 2 then
|
||||
1
|
||||
n
|
||||
else
|
||||
fib(n - 1) + fib(n - 2)
|
||||
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