diff --git a/cli/modules.c b/cli/modules.c index 0580242..ed735a9 100644 --- a/cli/modules.c +++ b/cli/modules.c @@ -74,7 +74,7 @@ const char* getObjName(uint32_t id) { /*****************************************************************************/ #include "thirdparty/cwalk/cwalk.h" - #if defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__)) +#if defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__)) #include "thirdparty/dirent/dirent.h" #else #include diff --git a/docs/TODO.txt b/docs/TODO.txt index 90d82a2..5ab721b 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -4,19 +4,13 @@ Add '.title' attribute to string // To implement. -- make assert as a keyword (like python) and disable it on release build. - - implement 'lang.getMaxCallDepth()' (default=1000 like python) and - setMaxCallDepth(val) to change stack size at runtime. + setMaxCallDepth(val) to change stack size at runtime. (at: pushCallFrame()) + +- make assert as a keyword (like python) and disable it on release build. - change or add => to_string() to value.as_string and add as_repr, as_bool. - -- literal function recursive call. - fn = func(a, b) - this(a, b) // Something like this. - fn(a, b) // May be closure support? - end - Implement utf8 support. - Implement gdb like debugger (add color print for readability). @@ -30,6 +24,11 @@ Add '.title' attribute to string - To do so the functions and global variables should be in the same buffer as the property of the script. - Union tagging alter in var. +- literal function recursive call. + fn = func(a, b) + this(a, b) // Something like this. + fn(a, b) // May be closure support? + end // Add more. - Single header for embedding (script in pk, require file IO). @@ -65,4 +64,7 @@ implement, and nothing would be work as expected. ... _f = func() ... _f() // _f not defined (no closure). ... end - Error: Expected an expression // expected Name '_f' not defined. \ No newline at end of file + Error: Expected an expression // expected Name '_f' not defined. + + Update: The above code just terminates in repl without printing any + error messages. diff --git a/src/include/pocketlang.h b/src/include/pocketlang.h index 7e747aa..ae717bb 100644 --- a/src/include/pocketlang.h +++ b/src/include/pocketlang.h @@ -73,7 +73,8 @@ typedef struct PkHandle PkHandle; // A temproary pointer to the pocketlang variable. This pointer is acquired // from the pocketlang's current stack frame and the pointer will become -// dangling once after the stack frame is popped. +// dangling once the stack frame is popped. If you want to keep the value +// alive use `pkNewHandle()`. typedef void* PkVar; // Type enum of the pocketlang variables, this can be used to get the type @@ -160,10 +161,10 @@ typedef PkStringPtr (*pkReadFn) (PKVM* vm); // the native instance. typedef void (*pkInstFreeFn) (PKVM* vm, void* instance, uint32_t id); -// A function callback to get the name of the native instance from pocketlang, -// using it's [id]. The returned string won't be copied by pocketlang so it's -// expected to be alived since the instance is alive and recomended to return -// a C literal string. +// A function callback to get the type name of the native instance from +// pocketlang, using it's [id]. The returned string won't be copied by +// pocketlang so it's expected to be alived since the instance is alive and +// recomended to return a C literal string. typedef const char* (*pkInstNameFn) (uint32_t id); // A get arribute callback, called by pocket VM when trying to get an attribute @@ -226,9 +227,10 @@ PK_PUBLIC void pkSetUserData(PKVM* vm, void* user_data); PK_PUBLIC void* pkGetUserData(const PKVM* vm); // Create a new handle for the [value]. This is useful to keep the [value] -// alive once it acquired from the stack. Do not use the [value] once +// alive once it acquired from the stack. **DO NOT** use the [value] once // creating a new handle for it instead get the value from the handle by -// using pkGetHandleValue() function. +// using pkGetHandleValue() function (otherwise the [value] would become a +// dangling pointer once it's stack frame is popped). PK_PUBLIC PkHandle* pkNewHandle(PKVM* vm, PkVar value); // Return the PkVar pointer in the handle, the returned pointer will be valid diff --git a/src/pk_compiler.c b/src/pk_compiler.c index aa0fe4a..ceecb99 100644 --- a/src/pk_compiler.c +++ b/src/pk_compiler.c @@ -195,7 +195,7 @@ static _Keyword _keywords[] = { { "continue", 8, TK_CONTINUE }, { "return", 6, TK_RETURN }, - { NULL, 0, (TokenType)(0) }, // Sentinel to mark the end of the array + { NULL, 0, (TokenType)(0) }, // Sentinel to mark the end of the array. }; /*****************************************************************************/ @@ -1935,8 +1935,8 @@ typedef enum { static void compileStatement(Compiler* compiler); static void compileBlockBody(Compiler* compiler, BlockType type); -// Compile a type and return it's index in the script's types buffer. -static int compileType(Compiler* compiler) { +// Compile a class and return it's index in the script's types buffer. +static int compileClass(Compiler* compiler) { // Consume the name of the type. consume(compiler, TK_NAME, "Expected a type name."); @@ -1947,10 +1947,10 @@ static int compileType(Compiler* compiler) { parseError(compiler, "Name '%.*s' already exists.", name_len, name); } - // Create a new type. - Class* type = newClass(compiler->vm, compiler->script, - name, (uint32_t)name_len); - type->ctor->arity = 0; + // Create a new class. + Class* cls = newClass(compiler->vm, compiler->script, + name, (uint32_t)name_len); + cls->ctor->arity = 0; // Check count exceeded. int fn_index = (int)compiler->script->functions.count - 1; @@ -1959,8 +1959,8 @@ static int compileType(Compiler* compiler) { MAX_FUNCTIONS); } - int ty_index = (int)(compiler->script->classes.count - 1); - if (ty_index == MAX_CLASSES) { + int cls_index = (int)(compiler->script->classes.count - 1); + if (cls_index == MAX_CLASSES) { parseError(compiler, "A script should contain at most %d types.", MAX_CLASSES); } @@ -1968,12 +1968,12 @@ static int compileType(Compiler* compiler) { // Compile the constructor function. ASSERT(compiler->func->ptr == compiler->script->body, OOPS); Func curr_fn; - compilerPushFunc(compiler, &curr_fn, type->ctor, fn_index); + compilerPushFunc(compiler, &curr_fn, cls->ctor, fn_index); compilerEnterBlock(compiler); // Push an instance on the stack. emitOpcode(compiler, OP_PUSH_INSTANCE); - emitByte(compiler, ty_index); + emitByte(compiler, cls_index); skipNewLines(compiler); TokenType next = peek(compiler); @@ -1989,8 +1989,8 @@ static int compileType(Compiler* compiler) { // TODO: Add a string compare macro. String* new_name = compiler->script->names.data[f_index]; - for (uint32_t i = 0; i < type->field_names.count; i++) { - String* prev = compiler->script->names.data[type->field_names.data[i]]; + for (uint32_t i = 0; i < cls->field_names.count; i++) { + String* prev = compiler->script->names.data[cls->field_names.data[i]]; if (new_name->hash == prev->hash && new_name->length == prev->length && memcmp(new_name->data, prev->data, prev->length) == 0) { parseError(compiler, "Class field with name '%s' already exists.", @@ -1998,7 +1998,7 @@ static int compileType(Compiler* compiler) { } } - pkUintBufferWrite(&type->field_names, compiler->vm, f_index); + pkUintBufferWrite(&cls->field_names, compiler->vm, f_index); // Consume the assignment expression. consume(compiler, TK_EQ, "Expected an assignment after field name."); @@ -2011,7 +2011,7 @@ static int compileType(Compiler* compiler) { skipNewLines(compiler); next = peek(compiler); } - consume(compiler, TK_END, "Expected 'end' after type declaration end."); + consume(compiler, TK_END, "Expected 'end' after a class declaration end."); compilerExitBlock(compiler); @@ -2352,7 +2352,7 @@ static void compilerImportAll(Compiler* compiler, Script* script) { ASSERT(script != NULL, OOPS); ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS); - // Import all types. + // Import all classes. for (uint32_t i = 0; i < script->classes.count; i++) { uint32_t name_ind = script->classes.data[i]->name; String* name = script->names.data[name_ind]; @@ -2742,7 +2742,7 @@ static void compileTopLevelStatement(Compiler* compiler) { compiler->is_last_call = false; if (match(compiler, TK_CLASS)) { - compileType(compiler); + compileClass(compiler); } else if (match(compiler, TK_NATIVE)) { compileFunction(compiler, FN_NATIVE); diff --git a/src/pk_core.c b/src/pk_core.c index 8bf9f03..56e854a 100644 --- a/src/pk_core.c +++ b/src/pk_core.c @@ -810,8 +810,6 @@ static void moduleAddFunctionInternal(PKVM* vm, Script* script, fn->arity = arity; } -// TODO: make the below module functions as PK_DOC(name, doc); - // 'lang' library methods. // ----------------------- @@ -1189,7 +1187,7 @@ DEF(stdFiberRun, } DEF(stdFiberResume, - "fiber_resume(fb:Fiber) -> var\n" + "resume(fb:Fiber) -> var\n" "Resumes a yielded function from a previous call of fiber_run() function. " "Return it's return value or the yielded value if it's yielded.") { @@ -1678,7 +1676,7 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) { { Script* scr = (Script*)obj; - // Search in types. + // Search in classes. int index = scriptGetClass(scr, attrib->data, attrib->length); if (index != -1) { ASSERT_INDEX((uint32_t)index, scr->classes.count); diff --git a/src/pk_core.h b/src/pk_core.h index f5ff55f..0cebbeb 100644 --- a/src/pk_core.h +++ b/src/pk_core.h @@ -46,7 +46,7 @@ Var varBitNot(PKVM* vm, Var v); // Returns ~v. bool varGreater(Var v1, Var v2); // Returns v1 > v2. bool varLesser(Var v1, Var v2); // Returns v1 < v2. -// Returns elem in container. +// Returns [elem] in [container]. bool varContains(PKVM* vm, Var elem, Var container); // Returns the attribute named [attrib] on the variable [on]. diff --git a/src/pk_var.c b/src/pk_var.c index 7972ed1..90d6705 100644 --- a/src/pk_var.c +++ b/src/pk_var.c @@ -506,7 +506,8 @@ Class* newClass(PKVM* vm, Script* scr, const char* name, uint32_t length) { type->name = scriptAddName(scr, vm, name, length); pkUintBufferInit(&type->field_names); - // Can't use '$' in string format. (TODO) + // Can't use '$' in string format, since it has a special meaning. + // TODO: escape the character. String* ty_name = scr->names.data[type->name]; String* dollar = newStringLength(vm, "$", 1); vmPushTempRef(vm, &dollar->_super); // dollar @@ -531,7 +532,7 @@ Instance* newInstance(PKVM* vm, Class* ty, bool initialize) { vmPushTempRef(vm, &inst->_super); // inst. ASSERT(ty->name < ty->owner->names.count, OOPS); - inst->name = ty->owner->names.data[ty->name]->data; + inst->ty_name = ty->owner->names.data[ty->name]->data; inst->is_native = false; Inst* ins = ALLOCATE(vm, Inst); @@ -555,9 +556,9 @@ Instance* newInstanceNative(PKVM* vm, void* data, uint32_t id) { inst->native_id = id; if (vm->config.inst_name_fn != NULL) { - inst->name = vm->config.inst_name_fn(id); + inst->ty_name = vm->config.inst_name_fn(id); } else { - inst->name = "$(?)"; + inst->ty_name = "$(?)"; } inst->native = data; @@ -1078,7 +1079,7 @@ void freeObject(PKVM* vm, Object* self) { } uint32_t scriptAddName(Script* self, PKVM* vm, const char* name, - uint32_t length) { + uint32_t length) { for (uint32_t i = 0; i < self->names.count; i++) { String* _name = self->names.data[i]; @@ -1236,8 +1237,10 @@ bool instSetAttrib(PKVM* vm, Instance* inst, String* attrib, Var value) { if (vm->config.inst_set_attrib_fn) { // Temproarly change the fiber's "return address" to points to the - // below var 'ret' so that the users can use 'pkGetArg...()' function - // to validate and get the attribute. + // below var 'attrib_ptr' so that the users can use 'pkGetArg...()' + // function to validate and get the attribute (users should use 0 as the + // index of the argument since it's at the return address and we cannot + // ensure fiber->ret[1] will be in bounds). Var* temp = vm->fiber->ret; Var attrib_ptr = value; @@ -1612,8 +1615,8 @@ static void _toStringInternal(PKVM* vm, const Var v, pkByteBuffer* buff, { const Instance* inst = (const Instance*)obj; pkByteBufferWrite(buff, vm, '['); - pkByteBufferAddString(buff, vm, inst->name, - (uint32_t)strlen(inst->name)); + pkByteBufferAddString(buff, vm, inst->ty_name, + (uint32_t)strlen(inst->ty_name)); pkByteBufferWrite(buff, vm, ':'); if (!inst->is_native) { diff --git a/src/pk_var.h b/src/pk_var.h index a45daf5..0ab1164 100644 --- a/src/pk_var.h +++ b/src/pk_var.h @@ -9,7 +9,7 @@ #include "pk_buffers.h" #include "pk_internal.h" -/** @file +/** * A simple dynamic type system library for small dynamic typed languages using * a technique called NaN-tagging (optional). The method is inspired from the * wren (https://wren.io/) an awesome language written by Bob Nystrom the @@ -277,6 +277,8 @@ struct Range { double to; //< End of the range exclusive. }; +// In pocketlang, the terms Script and Module are interchangable. (Consider +// renaming it to Module to be consistance with the terms). struct Script { Object _super; @@ -395,14 +397,14 @@ typedef struct { struct Instance { Object _super; - const char* name; //< Name of the type it belongs to. + const char* ty_name; //< Name of the type it belongs to. - bool is_native; //< True if it's a native type instance. + bool is_native; //< True if it's a native type instance. uint32_t native_id; //< Unique ID of this native instance. union { - void* native; //< C struct pointer. // TODO: - Inst* ins; //< Module instance pointer. + void* native; //< C struct pointer. // TODO: + Inst* ins; //< Module instance pointer. }; };