diff --git a/cli/TODO.txt b/cli/TODO.txt index fea3a00..617107a 100644 --- a/cli/TODO.txt +++ b/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. diff --git a/cli/cli_modules.c b/cli/cli_modules.c index 5aee559..feb9651 100644 --- a/cli/cli_modules.c +++ b/cli/cli_modules.c @@ -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); } \ No newline at end of file diff --git a/cli/main.c b/cli/main.c index 0fe44c4..84ed727 100644 --- a/cli/main.c +++ b/cli/main.c @@ -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); diff --git a/docs/try/main.c b/docs/try/main.c index 30080c7..6dfe0bb 100644 --- a/docs/try/main.c +++ b/docs/try/main.c @@ -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); diff --git a/src/core.c b/src/core.c index 6c5a1c8..0c2a1c5 100644 --- a/src/core.c +++ b/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; diff --git a/src/core.h b/src/core.h index 1b42721..312a394 100644 --- a/src/core.h +++ b/src/core.h @@ -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); diff --git a/src/debug.c b/src/debug.c index 310074b..7a3dd1d 100644 --- a/src/debug.c +++ b/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("}"); } diff --git a/src/var.c b/src/var.c index 5195d4b..fc5b754 100644 --- a/src/var.c +++ b/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; diff --git a/src/vm.c b/src/vm.c index 82d1ef6..e884b01 100644 --- a/src/vm.c +++ b/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(); } diff --git a/test/benchmark/fib/fib.pk b/test/benchmark/fib/fib.pk index ca5aac3..e46ffd0 100644 --- a/test/benchmark/fib/fib.pk +++ b/test/benchmark/fib/fib.pk @@ -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 diff --git a/test/benchmark/fib/fib.py b/test/benchmark/fib/fib.py index 768ac58..dece963 100644 --- a/test/benchmark/fib/fib.py +++ b/test/benchmark/fib/fib.py @@ -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() diff --git a/test/benchmark/fib/fib.rb b/test/benchmark/fib/fib.rb index 96a3009..61cde40 100644 --- a/test/benchmark/fib/fib.rb +++ b/test/benchmark/fib/fib.rb @@ -1,7 +1,7 @@ def fib(n) if n < 2 then - 1 + n else fib(n - 1) + fib(n - 2) end diff --git a/test/benchmark/fib/fib.wren b/test/benchmark/fib/fib.wren new file mode 100644 index 0000000..62adee7 --- /dev/null +++ b/test/benchmark/fib/fib.wren @@ -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)") \ No newline at end of file diff --git a/test/benchmark/for/for.js b/test/benchmark/for/for.js new file mode 100644 index 0000000..f0ea1f0 --- /dev/null +++ b/test/benchmark/for/for.js @@ -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'); \ No newline at end of file diff --git a/test/benchmark/for/for.pk b/test/benchmark/for/for.pk new file mode 100644 index 0000000..fced6ec --- /dev/null +++ b/test/benchmark/for/for.pk @@ -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) diff --git a/test/benchmark/for/for.py b/test/benchmark/for/for.py new file mode 100644 index 0000000..cc8c9ee --- /dev/null +++ b/test/benchmark/for/for.py @@ -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) diff --git a/test/benchmark/for/for.rb b/test/benchmark/for/for.rb new file mode 100644 index 0000000..d8fc32c --- /dev/null +++ b/test/benchmark/for/for.rb @@ -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' diff --git a/test/benchmark/for/for.wren b/test/benchmark/for/for.wren new file mode 100644 index 0000000..1ce8bd5 --- /dev/null +++ b/test/benchmark/for/for.wren @@ -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)") \ No newline at end of file