mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-02-05 20:26:53 +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"
|
||||
#if defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__))
|
||||
#if defined(_WIN32) && (defined(_MSC_VER) || defined(__TINYC__))
|
||||
#include "thirdparty/dirent/dirent.h"
|
||||
#else
|
||||
#include <dirent.h>
|
||||
|
@ -4,20 +4,14 @@ 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).
|
||||
- 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
|
||||
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).
|
||||
@ -66,3 +65,6 @@ implement, and nothing would be work as expected.
|
||||
... _f() // _f not defined (no closure).
|
||||
... end
|
||||
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
|
||||
// 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
|
||||
|
@ -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,
|
||||
// Create a new class.
|
||||
Class* cls = newClass(compiler->vm, compiler->script,
|
||||
name, (uint32_t)name_len);
|
||||
type->ctor->arity = 0;
|
||||
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);
|
||||
|
@ -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);
|
||||
|
@ -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].
|
||||
|
19
src/pk_var.c
19
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;
|
||||
@ -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) {
|
||||
|
@ -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,7 +397,7 @@ 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.
|
||||
uint32_t native_id; //< Unique ID of this native instance.
|
||||
|
Loading…
Reference in New Issue
Block a user