diff --git a/src/pk_compiler.c b/src/pk_compiler.c index 064ad5c..d4c9835 100644 --- a/src/pk_compiler.c +++ b/src/pk_compiler.c @@ -2271,88 +2271,28 @@ static void compileBlockBody(Compiler* compiler, BlockType type); // Compile a class and return it's index in the module's types buffer. static void compileClass(Compiler* compiler) { + ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS); + + TODO; //< compileClass Function is in-compilete. + // Consume the name of the type. consume(compiler, TK_NAME, "Expected a type name."); const char* name = compiler->parser.previous.start; int name_len = compiler->parser.previous.length; + int name_line = compiler->parser.previous.line; // Create a new class. - int cls_index, ctor_index; - Class* cls = newClass(compiler->parser.vm, compiler->module, - name, (uint32_t)name_len, &cls_index, &ctor_index); - cls->ctor->fn->arity = 0; - - // FIXME: - // Temproary patch for moving functions and classes to constant buffer. - ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS); - int index = compilerAddVariable(compiler, - compiler->parser.previous.start, - compiler->parser.previous.length, - compiler->parser.previous.line); - moduleSetGlobal(compiler->module, index, VAR_OBJ(cls)); + int cls_index; + Class* cls = newClass(compiler->parser.vm, name, name_len, + compiler->module, NULL, &cls_index); // Check count exceeded. checkMaxConstantsReached(compiler, cls_index); - checkMaxConstantsReached(compiler, ctor_index); - // Compile the constructor function. - ASSERT(compiler->func->ptr == compiler->module->body->fn, OOPS); - Func curr_fn; - compilerPushFunc(compiler, &curr_fn, cls->ctor->fn); - compilerEnterBlock(compiler); + // Compile all the methods and constructors. + TODO; - // Push an instance on the stack. - emitOpcode(compiler, OP_PUSH_INSTANCE); - emitShort(compiler, cls_index); - - skipNewLines(compiler); - TokenType next = peek(compiler); - while (next != TK_END && next != TK_EOF) { - - // Compile field name. - consume(compiler, TK_NAME, "Expected a type name."); - const char* f_name = compiler->parser.previous.start; - int f_len = compiler->parser.previous.length; - - int f_index = 0; - String* new_name = moduleAddString(compiler->module, compiler->parser.vm, - f_name, f_len, &f_index); - - for (uint32_t i = 0; i < cls->field_names.count; i++) { - String* prev = moduleGetStringAt(compiler->module, - cls->field_names.data[i]); - ASSERT(prev != NULL, OOPS); - if (IS_STR_EQ(new_name, prev)) { - parseError(compiler, "Class field with name '%s' already exists.", - new_name->data); - } - } - - pkUintBufferWrite(&cls->field_names, compiler->parser.vm, f_index); - - // Consume the assignment expression. - consume(compiler, TK_EQ, "Expected an assignment after field name."); - compileExpression(compiler); // Assigned value. - consumeEndStatement(compiler); - - // At this point the stack top would be the expression. - emitOpcode(compiler, OP_INST_APPEND); - - skipNewLines(compiler); - next = peek(compiler); - } consume(compiler, TK_END, "Expected 'end' after a class declaration end."); - - // The instance pushed by the OP_PUSH_INSTANCE instruction is at the top - // of the stack, return it (Constructor will return the instance). Note that - // the emitFunctionEnd function will also add a return instruction but that's - // for functions which doesn't return anything explicitly. This return won't - // change compiler's stack size because it won't pop the return value. - emitOpcode(compiler, OP_RETURN); - - compilerExitBlock(compiler); - emitFunctionEnd(compiler); - compilerPopFunc(compiler); } // Compile a function and return it's index in the module's function buffer. diff --git a/src/pk_core.c b/src/pk_core.c index b10b7e6..82b07ad 100644 --- a/src/pk_core.c +++ b/src/pk_core.c @@ -1205,7 +1205,9 @@ static void initializeCoreModules(PKVM* vm) { // modify the PI, like in python. moduleAddGlobal(vm, math, "PI", 2, VAR_NUM(M_PI)); - NEW_MODULE(fiber, "Fiber"); + // FIXME: + // Temproarly rename the fiber to move it to the builtin type classes. + NEW_MODULE(fiber, "_Fiber"); MODULE_ADD_FN(fiber, "new", stdFiberNew, 1); MODULE_ADD_FN(fiber, "run", stdFiberRun, -1); MODULE_ADD_FN(fiber, "resume", stdFiberResume, -1); diff --git a/src/pk_debug.c b/src/pk_debug.c index 3fb0088..f907227 100644 --- a/src/pk_debug.c +++ b/src/pk_debug.c @@ -141,10 +141,13 @@ void dumpFunctionCode(PKVM* vm, Function* func) { PRINT("]\n"); break; } - case OP_PUSH_MAP: NO_ARGS(); break; - case OP_LIST_APPEND: NO_ARGS(); break; - case OP_MAP_INSERT: NO_ARGS(); break; - case OP_INST_APPEND: NO_ARGS(); break; + case OP_PUSH_MAP: + case OP_PUSH_SELF: + case OP_LIST_APPEND: + case OP_MAP_INSERT: + case OP_INST_APPEND: + NO_ARGS(); + break; case OP_PUSH_LOCAL_0: case OP_PUSH_LOCAL_1: diff --git a/src/pk_opcodes.h b/src/pk_opcodes.h index c6eaf38..b1cae8a 100644 --- a/src/pk_opcodes.h +++ b/src/pk_opcodes.h @@ -40,6 +40,9 @@ OPCODE(PUSH_LIST, 2, 1) // Push a new map to construct from literal. OPCODE(PUSH_MAP, 0, 1) +// Push the self of the current method on the stack. +OPCODE(PUSH_SELF, 0, 1) + // Push a new instance to the stack. // param: 1 byte index. OPCODE(PUSH_INSTANCE, 1, 1) diff --git a/src/pk_value.c b/src/pk_value.c index 9a4c3d6..de892ec 100644 --- a/src/pk_value.c +++ b/src/pk_value.c @@ -263,6 +263,7 @@ static void popMarkedObjectsInternal(Object* obj, PKVM* vm) { // Mark call frames. for (int i = 0; i < fiber->frame_count; i++) { markObject(vm, (Object*)&fiber->frames[i].closure->_super); + markValue(vm, fiber->frames[i].self); } vm->bytes_allocated += sizeof(CallFrame) * fiber->frame_capacity; @@ -501,38 +502,28 @@ Fiber* newFiber(PKVM* vm, Closure* closure) { return fiber; } -Class* newClass(PKVM* vm, Module* module, const char* name, uint32_t length, - int* cls_index, int* ctor_index) { +Class* newClass(PKVM* vm, const char* name, int length, + Module* module, const char* docstring, + int* cls_index) { Class* cls = ALLOCATE(vm, Class); varInitObject(&cls->_super, vm, OBJ_CLASS); vmPushTempRef(vm, &cls->_super); // class. - uint32_t _cls_index = moduleAddConstant(vm, module, VAR_OBJ(cls)); - if (cls_index) *cls_index = (int)_cls_index; - - pkUintBufferInit(&cls->field_names); - cls->owner = module; + cls->owner = NULL; cls->docstring = NULL; - cls->name = moduleAddString(module, vm, name, length, NULL); + cls->ctor = NULL; - // Since characters '@' and '$' are special in stringFormat, and they - // currently cannot be escaped (TODO), a string (char array) created - // for that character and passed as C string format. - char special[2] = { SPECIAL_NAME_CHAR, '\0' }; - String* ctor_name = stringFormat(vm, "$(Ctor:@)", special, cls->name); - - // Constructor. - vmPushTempRef(vm, &ctor_name->_super); // ctor_name. - { - Function* ctor_fn = newFunction(vm, ctor_name->data, ctor_name->length, - module, false, NULL, ctor_index); - vmPushTempRef(vm, &ctor_fn->_super); // ctor_fn. - cls->ctor = newClosure(vm, ctor_fn); - vmPopTempRef(vm); // ctor_fn. + // Builtin types doesn't belongs to a module. + if (module != NULL) { + cls->name = moduleAddString(module, vm, name, length, NULL); + int _cls_index = moduleAddConstant(vm, module, VAR_OBJ(cls)); + if (cls_index) *cls_index = _cls_index; + moduleAddGlobal(vm, module, name, length, VAR_OBJ(cls)); + } else { + cls->name = newStringLength(vm, name, (uint32_t)length); } - vmPopTempRef(vm); // ctor_name. vmPopTempRef(vm); // class. return cls; diff --git a/src/pk_value.h b/src/pk_value.h index ba2d24c..a316962 100644 --- a/src/pk_value.h +++ b/src/pk_value.h @@ -428,6 +428,7 @@ typedef struct { const uint8_t* ip; //< Pointer to the next instruction byte code. const Closure* closure; //< Closure of the frame. Var* rbp; //< Stack base pointer. (%rbp) + Var self; //< Self reference of the current method. } CallFrame; typedef enum { @@ -544,6 +545,12 @@ Range* newRange(PKVM* vm, double from, double to); Module* newModule(PKVM* vm); +Closure* newClosure(PKVM* vm, Function* fn); + +Upvalue* newUpvalue(PKVM* vm, Var* value); + +Fiber* newFiber(PKVM* vm, Closure* closure); + // FIXME: // The docstring should be allocated and stored in the module's constants // as a string if it's not a native function. (native function's docs are @@ -555,18 +562,12 @@ Function* newFunction(PKVM* vm, const char* name, int length, bool is_native, const char* docstring, int* fn_index); -Closure* newClosure(PKVM* vm, Function* fn); - -Upvalue* newUpvalue(PKVM* vm, Var* value); - -Fiber* newFiber(PKVM* vm, Closure* closure); - -// FIXME: -// Same fix has to applied as newFunction() (see above). -// -// Allocate new Class object and return Class* with name [name]. -Class* newClass(PKVM* vm, Module* scr, const char* name, uint32_t length, - int* cls_index, int* ctor_index); +// If the module is not NULL, the name and the class object will be added to +// the module's constant pool. The class will be added to the modules global +// as well. +Class* newClass(PKVM* vm, const char* name, int length, + Module* module, const char* docstring, + int* cls_index); // Allocate new instance with of the base [type]. Note that if [initialize] is // false, the field value buffer of the instance would be un initialized (ie. diff --git a/src/pk_vm.c b/src/pk_vm.c index f92cd52..bd5fd7e 100644 --- a/src/pk_vm.c +++ b/src/pk_vm.c @@ -555,6 +555,7 @@ static inline void pushCallFrame(PKVM* vm, const Closure* closure, Var* rbp) { frame->rbp = rbp; frame->closure = closure; frame->ip = closure->fn->fn->opcodes.data; + frame->self = VAR_UNDEFINED; } static inline void reuseCallFrame(PKVM* vm, const Closure* closure) { @@ -709,6 +710,7 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber_) { register const uint8_t* ip; register Var* rbp; //< Stack base pointer register. + register Var* self; //< Points to the self in the current call frame. register CallFrame* frame; //< Current call frame. register Module* module; //< Currently executing module. register Fiber* fiber = fiber_; @@ -770,6 +772,7 @@ static PkResult runFiber(PKVM* vm, Fiber* fiber_) { frame = &fiber->frames[fiber->frame_count-1]; \ ip = frame->ip; \ rbp = frame->rbp; \ + self = &frame->self; \ module = frame->closure->fn->owner; \ } while (false) @@ -848,6 +851,12 @@ L_vm_main_loop: DISPATCH(); } + OPCODE(PUSH_SELF): + { + PUSH(*self); + DISPATCH(); + } + OPCODE(PUSH_INSTANCE): { uint8_t index = READ_SHORT(); diff --git a/tests/lang/class.pk b/tests/lang/class.pk index 93792b9..13e5e7c 100644 --- a/tests/lang/class.pk +++ b/tests/lang/class.pk @@ -1,36 +1,9 @@ -## TODO: Implement ctor with va arg to -## initialize, fields. -class _Vec - x = 0 - y = 0 -end +## Note that classes are being implemented and temproarly +## the classes cannot be compiled. -def Vec(x, y) - ret = _Vec() - ret.x = x; ret.y = y - return ret -end -def vecAdd(v1, v2) - return Vec(v1.x + v2.x, - v1.y + v2.y) -end -v1 = Vec(1, 2); assert(v1.x == 1 and v1.y == 2) -v2 = Vec(3, 4); assert(v2.x == 3 and v2.y == 4) -v3 = vecAdd(v1, v2) -assert(v3.x == 4 and v3.y == 6) - -class Test - fn = null - val = Vec(12, 32) -end - -test = Test() -test.fn = to_string -res = test.fn(test.val) -assert(res == "[_Vec: x=12, y=32]") diff --git a/tests/lang/fibers.pk b/tests/lang/fibers.pk index aacaa2e..0a6a79a 100644 --- a/tests/lang/fibers.pk +++ b/tests/lang/fibers.pk @@ -3,10 +3,10 @@ def f0() yield("yield value") end -import Fiber +import _Fiber -fiber = Fiber.new(f0) -yield_value = Fiber.run(fiber) +fiber = _Fiber.new(f0) +yield_value = _Fiber.run(fiber) assert(yield_value == "yield value") assert(!fiber.is_done) @@ -14,9 +14,9 @@ def f1() assert(yield("y") == "r") yield() end -fiber = Fiber.new(f1) -assert(Fiber.run(fiber) == "y") -Fiber.resume(fiber, "r") +fiber = _Fiber.new(f1) +assert(_Fiber.run(fiber) == "y") +_Fiber.resume(fiber, "r") assert(!fiber.is_done) def f2(p1, p2, p3) @@ -27,11 +27,11 @@ def f2(p1, p2, p3) return p1 + p2 * p3 end -fiber = Fiber.new(f2) -p3 = Fiber.run(fiber, 1, 2, 3); assert(p3 == 3) -p2 = Fiber.resume(fiber, 'r1'); assert(p2 == 2) -p1 = Fiber.resume(fiber, 'r2'); assert(p1 == 1) -pa = Fiber.resume(fiber, 'r3'); assert(pa == 7) +fiber = _Fiber.new(f2) +p3 = _Fiber.run(fiber, 1, 2, 3); assert(p3 == 3) +p2 = _Fiber.resume(fiber, 'r1'); assert(p2 == 2) +p1 = _Fiber.resume(fiber, 'r2'); assert(p1 == 1) +pa = _Fiber.resume(fiber, 'r3'); assert(pa == 7) assert(fiber.is_done) # If we got here, that means all test were passed. diff --git a/tests/lang/import.pk b/tests/lang/import.pk index d023488..1dbdd47 100644 --- a/tests/lang/import.pk +++ b/tests/lang/import.pk @@ -13,10 +13,6 @@ import "basics.pk" ## will import all import "controlflow.pk" as if_test from "functions.pk" import f1, f2 as fn2, f3 -import "class.pk" as class_ -assert(class_.Vec(42, 3.14).y == 3.14) -(vec = class_._Vec()).x = 'a'; assert(vec.x == 'a') - ## If it has a module name it'll bind to that name. import 'import/module.pk' assert(module_name.get_module_name() == 'module_name')