mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-05 20:26:53 +08:00
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:
parent
48102123af
commit
29be68fc86
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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]")
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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')
|
||||
|
Loading…
Reference in New Issue
Block a user