mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-11 07:00:58 +08:00
some comments were added (#169)
This commit is contained in:
parent
bcfa4de706
commit
6e02e021bc
@ -74,7 +74,7 @@ const char* getObjName(uint32_t id) {
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
#include "thirdparty/cwalk/cwalk.h"
|
#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"
|
#include "thirdparty/dirent/dirent.h"
|
||||||
#else
|
#else
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
@ -4,20 +4,14 @@ Add '.title' attribute to string
|
|||||||
|
|
||||||
// To implement.
|
// To implement.
|
||||||
|
|
||||||
- make assert as a keyword (like python) and disable it on release build.
|
|
||||||
|
|
||||||
- implement 'lang.getMaxCallDepth()' (default=1000 like python) and
|
- 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
|
- change or add => to_string() to value.as_string
|
||||||
and add as_repr, as_bool.
|
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 utf8 support.
|
||||||
- Implement gdb like debugger (add color print for readability).
|
- Implement gdb like debugger (add color print for readability).
|
||||||
- Complete all the TODO; macros.
|
- Complete all the TODO; macros.
|
||||||
@ -30,6 +24,11 @@ Add '.title' attribute to string
|
|||||||
- To do so the functions and global variables should be in the same
|
- To do so the functions and global variables should be in the same
|
||||||
buffer as the property of the script.
|
buffer as the property of the script.
|
||||||
- Union tagging alter in var.
|
- 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.
|
// Add more.
|
||||||
- Single header for embedding (script in pk, require file IO).
|
- Single header for embedding (script in pk, require file IO).
|
||||||
@ -66,3 +65,6 @@ implement, and nothing would be work as expected.
|
|||||||
... _f() // _f not defined (no closure).
|
... _f() // _f not defined (no closure).
|
||||||
... end
|
... end
|
||||||
Error: Expected an expression // expected Name '_f' not defined.
|
Error: Expected an expression // expected Name '_f' not defined.
|
||||||
|
|
||||||
|
Update: The above code just terminates in repl without printing any
|
||||||
|
error messages.
|
||||||
|
@ -73,7 +73,8 @@ typedef struct PkHandle PkHandle;
|
|||||||
|
|
||||||
// A temproary pointer to the pocketlang variable. This pointer is acquired
|
// A temproary pointer to the pocketlang variable. This pointer is acquired
|
||||||
// from the pocketlang's current stack frame and the pointer will become
|
// 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;
|
typedef void* PkVar;
|
||||||
|
|
||||||
// Type enum of the pocketlang variables, this can be used to get the type
|
// 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.
|
// the native instance.
|
||||||
typedef void (*pkInstFreeFn) (PKVM* vm, void* instance, uint32_t id);
|
typedef void (*pkInstFreeFn) (PKVM* vm, void* instance, uint32_t id);
|
||||||
|
|
||||||
// A function callback to get the name of the native instance from pocketlang,
|
// A function callback to get the type name of the native instance from
|
||||||
// using it's [id]. The returned string won't be copied by pocketlang so it's
|
// pocketlang, using it's [id]. The returned string won't be copied by
|
||||||
// expected to be alived since the instance is alive and recomended to return
|
// pocketlang so it's expected to be alived since the instance is alive and
|
||||||
// a C literal string.
|
// recomended to return a C literal string.
|
||||||
typedef const char* (*pkInstNameFn) (uint32_t id);
|
typedef const char* (*pkInstNameFn) (uint32_t id);
|
||||||
|
|
||||||
// A get arribute callback, called by pocket VM when trying to get an attribute
|
// 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);
|
PK_PUBLIC void* pkGetUserData(const PKVM* vm);
|
||||||
|
|
||||||
// Create a new handle for the [value]. This is useful to keep the [value]
|
// 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
|
// 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);
|
PK_PUBLIC PkHandle* pkNewHandle(PKVM* vm, PkVar value);
|
||||||
|
|
||||||
// Return the PkVar pointer in the handle, the returned pointer will be valid
|
// Return the PkVar pointer in the handle, the returned pointer will be valid
|
||||||
|
@ -195,7 +195,7 @@ static _Keyword _keywords[] = {
|
|||||||
{ "continue", 8, TK_CONTINUE },
|
{ "continue", 8, TK_CONTINUE },
|
||||||
{ "return", 6, TK_RETURN },
|
{ "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 compileStatement(Compiler* compiler);
|
||||||
static void compileBlockBody(Compiler* compiler, BlockType type);
|
static void compileBlockBody(Compiler* compiler, BlockType type);
|
||||||
|
|
||||||
// Compile a type and return it's index in the script's types buffer.
|
// Compile a class and return it's index in the script's types buffer.
|
||||||
static int compileType(Compiler* compiler) {
|
static int compileClass(Compiler* compiler) {
|
||||||
|
|
||||||
// Consume the name of the type.
|
// Consume the name of the type.
|
||||||
consume(compiler, TK_NAME, "Expected a type name.");
|
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);
|
parseError(compiler, "Name '%.*s' already exists.", name_len, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new type.
|
// Create a new class.
|
||||||
Class* type = newClass(compiler->vm, compiler->script,
|
Class* cls = newClass(compiler->vm, compiler->script,
|
||||||
name, (uint32_t)name_len);
|
name, (uint32_t)name_len);
|
||||||
type->ctor->arity = 0;
|
cls->ctor->arity = 0;
|
||||||
|
|
||||||
// Check count exceeded.
|
// Check count exceeded.
|
||||||
int fn_index = (int)compiler->script->functions.count - 1;
|
int fn_index = (int)compiler->script->functions.count - 1;
|
||||||
@ -1959,8 +1959,8 @@ static int compileType(Compiler* compiler) {
|
|||||||
MAX_FUNCTIONS);
|
MAX_FUNCTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ty_index = (int)(compiler->script->classes.count - 1);
|
int cls_index = (int)(compiler->script->classes.count - 1);
|
||||||
if (ty_index == MAX_CLASSES) {
|
if (cls_index == MAX_CLASSES) {
|
||||||
parseError(compiler, "A script should contain at most %d types.",
|
parseError(compiler, "A script should contain at most %d types.",
|
||||||
MAX_CLASSES);
|
MAX_CLASSES);
|
||||||
}
|
}
|
||||||
@ -1968,12 +1968,12 @@ static int compileType(Compiler* compiler) {
|
|||||||
// Compile the constructor function.
|
// Compile the constructor function.
|
||||||
ASSERT(compiler->func->ptr == compiler->script->body, OOPS);
|
ASSERT(compiler->func->ptr == compiler->script->body, OOPS);
|
||||||
Func curr_fn;
|
Func curr_fn;
|
||||||
compilerPushFunc(compiler, &curr_fn, type->ctor, fn_index);
|
compilerPushFunc(compiler, &curr_fn, cls->ctor, fn_index);
|
||||||
compilerEnterBlock(compiler);
|
compilerEnterBlock(compiler);
|
||||||
|
|
||||||
// Push an instance on the stack.
|
// Push an instance on the stack.
|
||||||
emitOpcode(compiler, OP_PUSH_INSTANCE);
|
emitOpcode(compiler, OP_PUSH_INSTANCE);
|
||||||
emitByte(compiler, ty_index);
|
emitByte(compiler, cls_index);
|
||||||
|
|
||||||
skipNewLines(compiler);
|
skipNewLines(compiler);
|
||||||
TokenType next = peek(compiler);
|
TokenType next = peek(compiler);
|
||||||
@ -1989,8 +1989,8 @@ static int compileType(Compiler* compiler) {
|
|||||||
|
|
||||||
// TODO: Add a string compare macro.
|
// TODO: Add a string compare macro.
|
||||||
String* new_name = compiler->script->names.data[f_index];
|
String* new_name = compiler->script->names.data[f_index];
|
||||||
for (uint32_t i = 0; i < type->field_names.count; i++) {
|
for (uint32_t i = 0; i < cls->field_names.count; i++) {
|
||||||
String* prev = compiler->script->names.data[type->field_names.data[i]];
|
String* prev = compiler->script->names.data[cls->field_names.data[i]];
|
||||||
if (new_name->hash == prev->hash && new_name->length == prev->length &&
|
if (new_name->hash == prev->hash && new_name->length == prev->length &&
|
||||||
memcmp(new_name->data, prev->data, prev->length) == 0) {
|
memcmp(new_name->data, prev->data, prev->length) == 0) {
|
||||||
parseError(compiler, "Class field with name '%s' already exists.",
|
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 the assignment expression.
|
||||||
consume(compiler, TK_EQ, "Expected an assignment after field name.");
|
consume(compiler, TK_EQ, "Expected an assignment after field name.");
|
||||||
@ -2011,7 +2011,7 @@ static int compileType(Compiler* compiler) {
|
|||||||
skipNewLines(compiler);
|
skipNewLines(compiler);
|
||||||
next = peek(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);
|
compilerExitBlock(compiler);
|
||||||
|
|
||||||
@ -2352,7 +2352,7 @@ static void compilerImportAll(Compiler* compiler, Script* script) {
|
|||||||
ASSERT(script != NULL, OOPS);
|
ASSERT(script != NULL, OOPS);
|
||||||
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS);
|
ASSERT(compiler->scope_depth == DEPTH_GLOBAL, OOPS);
|
||||||
|
|
||||||
// Import all types.
|
// Import all classes.
|
||||||
for (uint32_t i = 0; i < script->classes.count; i++) {
|
for (uint32_t i = 0; i < script->classes.count; i++) {
|
||||||
uint32_t name_ind = script->classes.data[i]->name;
|
uint32_t name_ind = script->classes.data[i]->name;
|
||||||
String* name = script->names.data[name_ind];
|
String* name = script->names.data[name_ind];
|
||||||
@ -2742,7 +2742,7 @@ static void compileTopLevelStatement(Compiler* compiler) {
|
|||||||
compiler->is_last_call = false;
|
compiler->is_last_call = false;
|
||||||
|
|
||||||
if (match(compiler, TK_CLASS)) {
|
if (match(compiler, TK_CLASS)) {
|
||||||
compileType(compiler);
|
compileClass(compiler);
|
||||||
|
|
||||||
} else if (match(compiler, TK_NATIVE)) {
|
} else if (match(compiler, TK_NATIVE)) {
|
||||||
compileFunction(compiler, FN_NATIVE);
|
compileFunction(compiler, FN_NATIVE);
|
||||||
|
@ -810,8 +810,6 @@ static void moduleAddFunctionInternal(PKVM* vm, Script* script,
|
|||||||
fn->arity = arity;
|
fn->arity = arity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: make the below module functions as PK_DOC(name, doc);
|
|
||||||
|
|
||||||
// 'lang' library methods.
|
// 'lang' library methods.
|
||||||
// -----------------------
|
// -----------------------
|
||||||
|
|
||||||
@ -1189,7 +1187,7 @@ DEF(stdFiberRun,
|
|||||||
}
|
}
|
||||||
|
|
||||||
DEF(stdFiberResume,
|
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. "
|
"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.") {
|
"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;
|
Script* scr = (Script*)obj;
|
||||||
|
|
||||||
// Search in types.
|
// Search in classes.
|
||||||
int index = scriptGetClass(scr, attrib->data, attrib->length);
|
int index = scriptGetClass(scr, attrib->data, attrib->length);
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
ASSERT_INDEX((uint32_t)index, scr->classes.count);
|
ASSERT_INDEX((uint32_t)index, scr->classes.count);
|
||||||
|
@ -46,7 +46,7 @@ Var varBitNot(PKVM* vm, Var v); // Returns ~v.
|
|||||||
bool varGreater(Var v1, Var v2); // Returns v1 > v2.
|
bool varGreater(Var v1, Var v2); // Returns v1 > v2.
|
||||||
bool varLesser(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);
|
bool varContains(PKVM* vm, Var elem, Var container);
|
||||||
|
|
||||||
// Returns the attribute named [attrib] on the variable [on].
|
// Returns the attribute named [attrib] on the variable [on].
|
||||||
|
21
src/pk_var.c
21
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);
|
type->name = scriptAddName(scr, vm, name, length);
|
||||||
pkUintBufferInit(&type->field_names);
|
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* ty_name = scr->names.data[type->name];
|
||||||
String* dollar = newStringLength(vm, "$", 1);
|
String* dollar = newStringLength(vm, "$", 1);
|
||||||
vmPushTempRef(vm, &dollar->_super); // dollar
|
vmPushTempRef(vm, &dollar->_super); // dollar
|
||||||
@ -531,7 +532,7 @@ Instance* newInstance(PKVM* vm, Class* ty, bool initialize) {
|
|||||||
vmPushTempRef(vm, &inst->_super); // inst.
|
vmPushTempRef(vm, &inst->_super); // inst.
|
||||||
|
|
||||||
ASSERT(ty->name < ty->owner->names.count, OOPS);
|
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->is_native = false;
|
||||||
|
|
||||||
Inst* ins = ALLOCATE(vm, Inst);
|
Inst* ins = ALLOCATE(vm, Inst);
|
||||||
@ -555,9 +556,9 @@ Instance* newInstanceNative(PKVM* vm, void* data, uint32_t id) {
|
|||||||
inst->native_id = id;
|
inst->native_id = id;
|
||||||
|
|
||||||
if (vm->config.inst_name_fn != NULL) {
|
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 {
|
} else {
|
||||||
inst->name = "$(?)";
|
inst->ty_name = "$(?)";
|
||||||
}
|
}
|
||||||
|
|
||||||
inst->native = data;
|
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 scriptAddName(Script* self, PKVM* vm, const char* name,
|
||||||
uint32_t length) {
|
uint32_t length) {
|
||||||
|
|
||||||
for (uint32_t i = 0; i < self->names.count; i++) {
|
for (uint32_t i = 0; i < self->names.count; i++) {
|
||||||
String* _name = self->names.data[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) {
|
if (vm->config.inst_set_attrib_fn) {
|
||||||
// Temproarly change the fiber's "return address" to points to the
|
// Temproarly change the fiber's "return address" to points to the
|
||||||
// below var 'ret' so that the users can use 'pkGetArg...()' function
|
// below var 'attrib_ptr' so that the users can use 'pkGetArg...()'
|
||||||
// to validate and get the attribute.
|
// 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* temp = vm->fiber->ret;
|
||||||
Var attrib_ptr = value;
|
Var attrib_ptr = value;
|
||||||
|
|
||||||
@ -1612,8 +1615,8 @@ static void _toStringInternal(PKVM* vm, const Var v, pkByteBuffer* buff,
|
|||||||
{
|
{
|
||||||
const Instance* inst = (const Instance*)obj;
|
const Instance* inst = (const Instance*)obj;
|
||||||
pkByteBufferWrite(buff, vm, '[');
|
pkByteBufferWrite(buff, vm, '[');
|
||||||
pkByteBufferAddString(buff, vm, inst->name,
|
pkByteBufferAddString(buff, vm, inst->ty_name,
|
||||||
(uint32_t)strlen(inst->name));
|
(uint32_t)strlen(inst->ty_name));
|
||||||
pkByteBufferWrite(buff, vm, ':');
|
pkByteBufferWrite(buff, vm, ':');
|
||||||
|
|
||||||
if (!inst->is_native) {
|
if (!inst->is_native) {
|
||||||
|
12
src/pk_var.h
12
src/pk_var.h
@ -9,7 +9,7 @@
|
|||||||
#include "pk_buffers.h"
|
#include "pk_buffers.h"
|
||||||
#include "pk_internal.h"
|
#include "pk_internal.h"
|
||||||
|
|
||||||
/** @file
|
/**
|
||||||
* A simple dynamic type system library for small dynamic typed languages using
|
* A simple dynamic type system library for small dynamic typed languages using
|
||||||
* a technique called NaN-tagging (optional). The method is inspired from the
|
* a technique called NaN-tagging (optional). The method is inspired from the
|
||||||
* wren (https://wren.io/) an awesome language written by Bob Nystrom 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.
|
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 {
|
struct Script {
|
||||||
Object _super;
|
Object _super;
|
||||||
|
|
||||||
@ -395,14 +397,14 @@ typedef struct {
|
|||||||
struct Instance {
|
struct Instance {
|
||||||
Object _super;
|
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.
|
uint32_t native_id; //< Unique ID of this native instance.
|
||||||
|
|
||||||
union {
|
union {
|
||||||
void* native; //< C struct pointer. // TODO:
|
void* native; //< C struct pointer. // TODO:
|
||||||
Inst* ins; //< Module instance pointer.
|
Inst* ins; //< Module instance pointer.
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user