classes were removed temproarly

to implement classes properly and support methods I had to remove
the older class syntax temproarly.
This commit is contained in:
Thakee Nathees 2022-04-20 13:54:45 +05:30
parent 48102123af
commit 29be68fc86
10 changed files with 72 additions and 154 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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:

View File

@ -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)

View File

@ -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;

View File

@ -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.

View File

@ -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();

View File

@ -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]")

View File

@ -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.

View File

@ -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')