mirror of
https://github.com/zekexiao/pocketlang.git
synced 2025-03-04 05:05:57 +08:00
Merge pull request #250 from ThakeeNathees/docstring
docstrings support added
This commit is contained in:
commit
8e6f347009
@ -117,8 +117,10 @@
|
||||
|
||||
// A macro to declare a function, with docstring, which is defined as
|
||||
// _pk_doc_<fn> = docstring; That'll used to generate function help text.
|
||||
#define DEF(fn, docstring) \
|
||||
static const char* DOCSTRING(fn) = docstring; \
|
||||
// [signature] is the function name and parameter names with type information.
|
||||
// ex: `io.open(path:String, mode:String) -> io.File`
|
||||
#define DEF(fn, signature, docstring) \
|
||||
static const char* DOCSTRING(fn) = signature "\n\n" docstring; \
|
||||
static void fn(PKVM* vm)
|
||||
|
||||
#endif //PK_COMMON_H
|
||||
|
@ -2629,6 +2629,14 @@ static int compileClass(Compiler* compiler) {
|
||||
emitOpcode(compiler, OP_CREATE_CLASS);
|
||||
emitShort(compiler, cls_index);
|
||||
|
||||
skipNewLines(compiler);
|
||||
if (match(compiler, TK_STRING)) {
|
||||
Token* str = &compiler->parser.previous;
|
||||
int index = compilerAddConstant(compiler, str->value);
|
||||
String* docstring = moduleGetStringAt(compiler->module, index);
|
||||
cls->docstring = docstring->data;
|
||||
}
|
||||
|
||||
skipNewLines(compiler);
|
||||
while (!compiler->parser.has_syntax_error && !match(compiler, TK_END)) {
|
||||
|
||||
@ -2846,6 +2854,14 @@ static void compileFunction(Compiler* compiler, FuncType fn_type) {
|
||||
func->arity = argc;
|
||||
compilerChangeStack(compiler, argc);
|
||||
|
||||
skipNewLines(compiler);
|
||||
if (match(compiler, TK_STRING)) {
|
||||
Token* str = &compiler->parser.previous;
|
||||
int index = compilerAddConstant(compiler, str->value);
|
||||
String* docstring = moduleGetStringAt(compiler->module, index);
|
||||
func->docstring = docstring->data;
|
||||
}
|
||||
|
||||
compileBlockBody(compiler, BLOCK_FUNC);
|
||||
|
||||
if (fn_type == FUNC_CONSTRUCTOR) {
|
||||
|
134
src/core/core.c
134
src/core/core.c
@ -272,7 +272,7 @@ static void _collectMethods(PKVM* vm, List* list, Class* cls) {
|
||||
/*****************************************************************************/
|
||||
|
||||
DEF(coreHelp,
|
||||
"help([fn:Closure]) -> null\n"
|
||||
"help([value:Closure|Class]) -> Null",
|
||||
"It'll print the docstring the object and return.") {
|
||||
|
||||
int argc = ARGC;
|
||||
@ -290,11 +290,12 @@ DEF(coreHelp,
|
||||
// TODO: Extend help() to work with modules and classes.
|
||||
// Add docstring (like python) to support it in pocketlang.
|
||||
|
||||
Closure* closure;
|
||||
if (!validateArgClosure(vm, 1, &closure)) return;
|
||||
|
||||
// If there ins't an io function callback, we're done.
|
||||
if (vm->config.stdout_write == NULL) RET(VAR_NULL);
|
||||
Var value = ARG(1);
|
||||
|
||||
if (IS_OBJ_TYPE(value, OBJ_CLOSURE)) {
|
||||
Closure* closure = (Closure*) AS_OBJ(value);
|
||||
// If there ins't an io function callback, we're done.
|
||||
|
||||
if (closure->fn->docstring != NULL) {
|
||||
vm->config.stdout_write(vm, closure->fn->docstring);
|
||||
@ -304,11 +305,25 @@ DEF(coreHelp,
|
||||
vm->config.stdout_write(vm, closure->fn->name);
|
||||
vm->config.stdout_write(vm, "()' doesn't have a docstring.\n");
|
||||
}
|
||||
} else if (IS_OBJ_TYPE(value, OBJ_CLASS)) {
|
||||
Class* cls = (Class*) AS_OBJ(value);
|
||||
if (cls->docstring != NULL) {
|
||||
vm->config.stdout_write(vm, cls->docstring);
|
||||
vm->config.stdout_write(vm, "\n\n");
|
||||
} else {
|
||||
vm->config.stdout_write(vm, "class '");
|
||||
vm->config.stdout_write(vm, cls->name->data);
|
||||
vm->config.stdout_write(vm, "' doesn't have a docstring.\n");
|
||||
}
|
||||
} else {
|
||||
RET_ERR(newString(vm, "Expected a closure or class to get help."));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DEF(coreDir,
|
||||
"dir(v:var) -> List[String]\n"
|
||||
"dir(v:Var) -> List[String]",
|
||||
"It'll return all the elements of the variable [v]. If [v] is a module "
|
||||
"it'll return the names of globals, functions, and classes. If it's an "
|
||||
"instance it'll return all the attributes and methods.") {
|
||||
@ -377,7 +392,7 @@ DEF(coreDir,
|
||||
}
|
||||
|
||||
DEF(coreAssert,
|
||||
"assert(condition:bool [, msg:string]) -> void\n"
|
||||
"assert(condition:Bool [, msg:String]) -> Null",
|
||||
"If the condition is false it'll terminate the current fiber with the "
|
||||
"optional error message") {
|
||||
|
||||
@ -408,7 +423,7 @@ DEF(coreAssert,
|
||||
}
|
||||
|
||||
DEF(coreBin,
|
||||
"bin(value:num) -> string\n"
|
||||
"bin(value:Number) -> String",
|
||||
"Returns as a binary value string with '0b' prefix.") {
|
||||
|
||||
int64_t value;
|
||||
@ -439,7 +454,7 @@ DEF(coreBin,
|
||||
}
|
||||
|
||||
DEF(coreHex,
|
||||
"hex(value:num) -> string\n"
|
||||
"hex(value:Number) -> String",
|
||||
"Returns as a hexadecimal value string with '0x' prefix.") {
|
||||
|
||||
int64_t value;
|
||||
@ -466,7 +481,7 @@ DEF(coreHex,
|
||||
}
|
||||
|
||||
DEF(coreYield,
|
||||
"yield([value]) -> var\n"
|
||||
"yield([value:Var]) -> Var",
|
||||
"Return the current function with the yield [value] to current running "
|
||||
"fiber. If the fiber is resumed, it'll run from the next statement of the "
|
||||
"yield() call. If the fiber resumed with with a value, the return value of "
|
||||
@ -481,7 +496,7 @@ DEF(coreYield,
|
||||
}
|
||||
|
||||
DEF(coreToString,
|
||||
"str(value:var) -> string\n"
|
||||
"str(valueVar) -> String",
|
||||
"Returns the string representation of the value.") {
|
||||
|
||||
String* str = varToString(vm, ARG(1), false);
|
||||
@ -490,7 +505,7 @@ DEF(coreToString,
|
||||
}
|
||||
|
||||
DEF(coreChr,
|
||||
"chr(value:num) -> string\n"
|
||||
"chr(value:Num) -> String",
|
||||
"Returns the ASCII string value of the integer argument.") {
|
||||
|
||||
int64_t num;
|
||||
@ -505,7 +520,7 @@ DEF(coreChr,
|
||||
}
|
||||
|
||||
DEF(coreOrd,
|
||||
"ord(value:string) -> num\n"
|
||||
"ord(value:String) -> Number",
|
||||
"Returns integer value of the given ASCII character.") {
|
||||
|
||||
String* c;
|
||||
@ -519,7 +534,7 @@ DEF(coreOrd,
|
||||
}
|
||||
|
||||
DEF(coreMin,
|
||||
"min(a:var, b:var) -> Bool\n"
|
||||
"min(a:Var, b:Var) -> Bool",
|
||||
"Returns minimum of [a] and [b].") {
|
||||
|
||||
Var a = ARG(1), b = ARG(2);
|
||||
@ -531,7 +546,7 @@ DEF(coreMin,
|
||||
}
|
||||
|
||||
DEF(coreMax,
|
||||
"max(a:var, b:var) -> Bool\n"
|
||||
"max(a:var, b:var) -> Bool",
|
||||
"Returns maximum of [a] and [b].") {
|
||||
|
||||
Var a = ARG(1), b = ARG(2);
|
||||
@ -543,7 +558,7 @@ DEF(coreMax,
|
||||
}
|
||||
|
||||
DEF(corePrint,
|
||||
"print(...) -> void\n"
|
||||
"print(...) -> Null",
|
||||
"Write each argument as space seperated, to the stdout and ends with a "
|
||||
"newline.") {
|
||||
|
||||
@ -562,7 +577,7 @@ DEF(corePrint,
|
||||
}
|
||||
|
||||
DEF(coreInput,
|
||||
"input([msg:var]) -> string\n"
|
||||
"input([msg:Var]) -> String",
|
||||
"Read a line from stdin and returns it without the line ending. Accepting "
|
||||
"an optional argument [msg] and prints it before reading.") {
|
||||
|
||||
@ -591,7 +606,7 @@ DEF(coreInput,
|
||||
}
|
||||
|
||||
DEF(coreExit,
|
||||
"exit([value:num]) -> null\n"
|
||||
"exit([value:Number]) -> Null",
|
||||
"Exit the process with an optional exit code provided by the argument "
|
||||
"[value]. The default exit code is would be 0.") {
|
||||
|
||||
@ -613,7 +628,7 @@ DEF(coreExit,
|
||||
// ---------------
|
||||
|
||||
DEF(coreListAppend,
|
||||
"list_append(self:List, value:var) -> List\n"
|
||||
"list_append(self:List, value:Var) -> List",
|
||||
"Append the [value] to the list [self] and return the list.") {
|
||||
|
||||
List* list;
|
||||
@ -627,7 +642,7 @@ DEF(coreListAppend,
|
||||
// TODO: currently it takes one argument (to test string interpolation).
|
||||
// Add join delimeter as an optional argument.
|
||||
DEF(coreListJoin,
|
||||
"list_join(self:List) -> String\n"
|
||||
"list_join(self:List) -> String",
|
||||
"Concatinate the elements of the list and return as a string.") {
|
||||
|
||||
List* list;
|
||||
@ -732,7 +747,7 @@ void moduleAddFunctionInternal(PKVM* vm, Module* module,
|
||||
// 'lang' library methods.
|
||||
|
||||
DEF(stdLangGC,
|
||||
"lang.gc() -> num\n"
|
||||
"lang.gc() -> Number",
|
||||
"Trigger garbage collection and return the amount of bytes cleaned.") {
|
||||
|
||||
size_t bytes_before = vm->bytes_allocated;
|
||||
@ -742,7 +757,7 @@ DEF(stdLangGC,
|
||||
}
|
||||
|
||||
DEF(stdLangDisas,
|
||||
"lang.disas(fn:Closure) -> String\n"
|
||||
"lang.disas(fn:Closure) -> String",
|
||||
"Returns the disassembled opcode of the function [fn].") {
|
||||
|
||||
// TODO: support dissasemble class constructors and module main body.
|
||||
@ -757,7 +772,7 @@ DEF(stdLangDisas,
|
||||
}
|
||||
|
||||
DEF(stdLangBackTrace,
|
||||
"lang.backtrace() -> String\n"
|
||||
"lang.backtrace() -> String",
|
||||
"Returns the backtrace as a string, each line is formated as "
|
||||
"'<function>;<file>;<line>\n'.") {
|
||||
|
||||
@ -806,7 +821,7 @@ DEF(stdLangBackTrace,
|
||||
}
|
||||
|
||||
DEF(stdLangModules,
|
||||
"lang.modules() -> List\n"
|
||||
"lang.modules() -> List",
|
||||
"Returns the list of all registered modules.") {
|
||||
|
||||
List* list = newList(vm, 8);
|
||||
@ -822,7 +837,7 @@ DEF(stdLangModules,
|
||||
|
||||
#ifdef DEBUG
|
||||
DEF(stdLangDebugBreak,
|
||||
"lang.debug_break() -> null\n"
|
||||
"lang.debug_break() -> Null",
|
||||
"A debug function for development (will be removed).") {
|
||||
|
||||
DEBUG_BREAK();
|
||||
@ -928,19 +943,19 @@ static void _ctorFiber(PKVM* vm) {
|
||||
#define SELF (vm->fiber->self)
|
||||
|
||||
DEF(_objTypeName,
|
||||
"Object.typename() -> String\n"
|
||||
"Object.typename() -> String",
|
||||
"Returns the type name of the object.") {
|
||||
RET(VAR_OBJ(newString(vm, varTypeName(SELF))));
|
||||
}
|
||||
|
||||
DEF(_objRepr,
|
||||
"Object._repr() -> String\n"
|
||||
"Object._repr() -> String",
|
||||
"Returns the repr string of the object.") {
|
||||
RET(VAR_OBJ(toRepr(vm, SELF)));
|
||||
}
|
||||
|
||||
DEF(_numberTimes,
|
||||
"Number.times(f:fn)\n"
|
||||
"Number.times(f:Closure)",
|
||||
"Iterate the function [f] n times. Here n is the integral value of the "
|
||||
"number. If the number is not an integer the floor value will be taken.") {
|
||||
|
||||
@ -960,21 +975,21 @@ DEF(_numberTimes,
|
||||
}
|
||||
|
||||
DEF(_numberIsint,
|
||||
"Number.isint() -> bool\n"
|
||||
"Number.isint() -> Bool",
|
||||
"Returns true if the number is a whold number, otherwise false.") {
|
||||
double n = AS_NUM(SELF);
|
||||
RET(VAR_BOOL(floor(n) == n));
|
||||
}
|
||||
|
||||
DEF(_numberIsbyte,
|
||||
"Number.isbyte() -> bool\n"
|
||||
"Number.isbyte() -> bool",
|
||||
"Returns true if the number is an integer and is between 0x00 and 0xff.") {
|
||||
double n = AS_NUM(SELF);
|
||||
RET(VAR_BOOL((floor(n) == n) && (0x00 <= n && n <= 0xff)));
|
||||
}
|
||||
|
||||
DEF(_stringFind,
|
||||
"String.find(sub:String[, start:Number=0]) -> Number\n"
|
||||
"String.find(sub:String[, start:Number=0]) -> Number",
|
||||
"Returns the first index of the substring [sub] found from the "
|
||||
"[start] index") {
|
||||
|
||||
@ -1006,7 +1021,7 @@ DEF(_stringFind,
|
||||
}
|
||||
|
||||
DEF(_stringReplace,
|
||||
"String.replace(old:Sttring, new:String[, count:Number=-1]) -> String\n"
|
||||
"String.replace(old:Sttring, new:String[, count:Number=-1]) -> String",
|
||||
"Returns a copy of the string where [count] occurrence of the substring "
|
||||
"[old] will be replaced with [new]. If [count] == -1 all the occurrence "
|
||||
"will be replaced.") {
|
||||
@ -1031,7 +1046,7 @@ DEF(_stringReplace,
|
||||
}
|
||||
|
||||
DEF(_stringSplit,
|
||||
"String.split(sep:String) -> List\n"
|
||||
"String.split(sep:String) -> List",
|
||||
"Split the string into a list of string seperated by [sep] delimeter.") {
|
||||
|
||||
String* sep;
|
||||
@ -1045,28 +1060,28 @@ DEF(_stringSplit,
|
||||
}
|
||||
|
||||
DEF(_stringStrip,
|
||||
"String.strip() -> String\n"
|
||||
"String.strip() -> String",
|
||||
"Returns a copy of the string where the leading and trailing whitespace "
|
||||
"removed.") {
|
||||
RET(VAR_OBJ(stringStrip(vm, (String*) AS_OBJ(SELF))));
|
||||
}
|
||||
|
||||
DEF(_stringLower,
|
||||
"String.lower() -> String\n"
|
||||
"String.lower() -> String",
|
||||
"Returns a copy of the string where all the characters are converted to "
|
||||
"lower case letters.") {
|
||||
RET(VAR_OBJ(stringLower(vm, (String*) AS_OBJ(SELF))));
|
||||
}
|
||||
|
||||
DEF(_stringUpper,
|
||||
"String.lower() -> String\n"
|
||||
"String.lower() -> String",
|
||||
"Returns a copy of the string where all the characters are converted to "
|
||||
"upper case letters.") {
|
||||
RET(VAR_OBJ(stringUpper(vm, (String*) AS_OBJ(SELF))));
|
||||
}
|
||||
|
||||
DEF(_stingStartswith,
|
||||
"String.startswith(prefix: String | List) -> Bool\n"
|
||||
"String.startswith(prefix: String | List) -> Bool",
|
||||
"Returns true if the string starts the specified prefix.") {
|
||||
|
||||
Var prefix = ARG(1);
|
||||
@ -1097,7 +1112,7 @@ DEF(_stingStartswith,
|
||||
}
|
||||
|
||||
DEF(_stingEndswith,
|
||||
"String.endswith(suffix: String | List) -> Bool\n"
|
||||
"String.endswith(suffix: String | List) -> Bool",
|
||||
"Returns true if the string ends with the specified suffix.") {
|
||||
|
||||
Var suffix = ARG(1);
|
||||
@ -1132,7 +1147,7 @@ DEF(_stingEndswith,
|
||||
}
|
||||
|
||||
DEF(_listAppend,
|
||||
"List.append(value:var) -> List\n"
|
||||
"List.append(value:Var) -> List",
|
||||
"Append the [value] to the list and return the List.") {
|
||||
|
||||
ASSERT(IS_OBJ_TYPE(SELF, OBJ_LIST), OOPS);
|
||||
@ -1142,7 +1157,7 @@ DEF(_listAppend,
|
||||
}
|
||||
|
||||
DEF(_listInsert,
|
||||
"List.insert(index:Number, value:var) -> null\n"
|
||||
"List.insert(index:Number, value:Var) -> Null",
|
||||
"Insert the element at the given index. The index should be "
|
||||
"0 <= index <= list.length.") {
|
||||
|
||||
@ -1159,7 +1174,7 @@ DEF(_listInsert,
|
||||
}
|
||||
|
||||
DEF(_listPop,
|
||||
"List.pop(index=-1) -> var\n"
|
||||
"List.pop(index:Number=-1) -> Var",
|
||||
"Removes the last element of the list and return it.") {
|
||||
|
||||
ASSERT(IS_OBJ_TYPE(SELF, OBJ_LIST), OOPS);
|
||||
@ -1184,7 +1199,7 @@ DEF(_listPop,
|
||||
}
|
||||
|
||||
DEF(_listFind,
|
||||
"List.find(value:var) -> Number\n"
|
||||
"List.find(value:Var) -> Number",
|
||||
"Find the value and return its index. If the vlaue not exists "
|
||||
"it'll return -1.") {
|
||||
|
||||
@ -1204,20 +1219,20 @@ DEF(_listFind,
|
||||
}
|
||||
|
||||
DEF(_listClear,
|
||||
"List.clear() -> null\n"
|
||||
"List.clear() -> Null",
|
||||
"Removes all the entries in the list.") {
|
||||
listClear(vm, (List*) AS_OBJ(SELF));
|
||||
}
|
||||
|
||||
DEF(_mapClear,
|
||||
"Map.clear() -> null\n"
|
||||
"Map.clear() -> Null",
|
||||
"Removes all the entries in the map.") {
|
||||
Map* self = (Map*) AS_OBJ(SELF);
|
||||
mapClear(vm, self);
|
||||
}
|
||||
|
||||
DEF(_mapGet,
|
||||
"Map.get(key:var, default=null) -> var\n"
|
||||
"Map.get(key:Var, default=Null) -> Var",
|
||||
"Returns the key if its in the map, otherwise the default value will "
|
||||
"be returned.") {
|
||||
|
||||
@ -1233,7 +1248,7 @@ DEF(_mapGet,
|
||||
}
|
||||
|
||||
DEF(_mapHas,
|
||||
"Map.has(key:var) -> Bool\n"
|
||||
"Map.has(key:Var) -> Bool",
|
||||
"Returns true if the key exists.") {
|
||||
|
||||
Map* self = (Map*)AS_OBJ(SELF);
|
||||
@ -1242,7 +1257,7 @@ DEF(_mapHas,
|
||||
}
|
||||
|
||||
DEF(_mapPop,
|
||||
"Map.pop(key:var) -> var\n"
|
||||
"Map.pop(key:Var) -> Var",
|
||||
"Pops the value at the key and return it.") {
|
||||
|
||||
Map* self = (Map*)AS_OBJ(SELF);
|
||||
@ -1254,7 +1269,7 @@ DEF(_mapPop,
|
||||
}
|
||||
|
||||
DEF(_fiberRun,
|
||||
"Fiber.run(...) -> var\n"
|
||||
"Fiber.run(...) -> Var",
|
||||
"Runs the fiber's function with the provided arguments and returns it's "
|
||||
"return value or the yielded value if it's yielded.") {
|
||||
|
||||
@ -1272,7 +1287,7 @@ DEF(_fiberRun,
|
||||
}
|
||||
|
||||
DEF(_fiberResume,
|
||||
"Fiber.resume() -> var\n"
|
||||
"Fiber.resume() -> Var",
|
||||
"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.") {
|
||||
|
||||
@ -1918,6 +1933,13 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
||||
Closure* closure = (Closure*)obj;
|
||||
switch (attrib->hash) {
|
||||
|
||||
case CHECK_HASH("_docs", 0x8fb536a9):
|
||||
if (closure->fn->docstring) {
|
||||
return VAR_OBJ(newString(vm, closure->fn->docstring));
|
||||
} else {
|
||||
return VAR_OBJ(newString(vm, ""));
|
||||
}
|
||||
|
||||
case CHECK_HASH("arity", 0x3e96bd7a):
|
||||
return VAR_NUM((double)(closure->fn->arity));
|
||||
|
||||
@ -1942,9 +1964,17 @@ Var varGetAttrib(PKVM* vm, Var on, String* attrib) {
|
||||
}
|
||||
} break;
|
||||
|
||||
case OBJ_CLASS:
|
||||
// TODO:
|
||||
break;
|
||||
case OBJ_CLASS: {
|
||||
Class* cls = (Class*) obj;
|
||||
if (attrib->hash == CHECK_HASH("_docs", 0x8fb536a9)) {
|
||||
if (cls->docstring) {
|
||||
return VAR_OBJ(newString(vm, cls->docstring));
|
||||
} else {
|
||||
return VAR_OBJ(newString(vm, ""));
|
||||
}
|
||||
}
|
||||
|
||||
} break;
|
||||
|
||||
case OBJ_INST: {
|
||||
Instance* inst = (Instance*)obj;
|
||||
|
@ -245,19 +245,19 @@ void pkRegisterModule(PKVM* vm, PkHandle* module) {
|
||||
}
|
||||
|
||||
void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name,
|
||||
pkNativeFn fptr, int arity) {
|
||||
pkNativeFn fptr, int arity, const char* docstring) {
|
||||
CHECK_HANDLE_TYPE(module, OBJ_MODULE);
|
||||
CHECK_ARG_NULL(fptr);
|
||||
|
||||
moduleAddFunctionInternal(vm, (Module*)AS_OBJ(module->value),
|
||||
name, fptr, arity,
|
||||
NULL /*TODO: Public API for function docstring.*/);
|
||||
name, fptr, arity, docstring);
|
||||
}
|
||||
|
||||
PkHandle* pkNewClass(PKVM* vm, const char* name,
|
||||
PkHandle* base_class, PkHandle* module,
|
||||
pkNewInstanceFn new_fn,
|
||||
pkDeleteInstanceFn delete_fn) {
|
||||
pkDeleteInstanceFn delete_fn,
|
||||
const char* docstring) {
|
||||
CHECK_ARG_NULL(module);
|
||||
CHECK_ARG_NULL(name);
|
||||
CHECK_HANDLE_TYPE(module, OBJ_MODULE);
|
||||
@ -270,7 +270,7 @@ PkHandle* pkNewClass(PKVM* vm, const char* name,
|
||||
|
||||
Class* class_ = newClass(vm, name, (int)strlen(name),
|
||||
super, (Module*)AS_OBJ(module->value),
|
||||
NULL, NULL);
|
||||
docstring, NULL);
|
||||
class_->new_fn = new_fn;
|
||||
class_->delete_fn = delete_fn;
|
||||
|
||||
@ -282,7 +282,7 @@ PkHandle* pkNewClass(PKVM* vm, const char* name,
|
||||
|
||||
void pkClassAddMethod(PKVM* vm, PkHandle* cls,
|
||||
const char* name,
|
||||
pkNativeFn fptr, int arity) {
|
||||
pkNativeFn fptr, int arity, const char* docstring) {
|
||||
CHECK_ARG_NULL(cls);
|
||||
CHECK_ARG_NULL(fptr);
|
||||
CHECK_HANDLE_TYPE(cls, OBJ_CLASS);
|
||||
@ -294,7 +294,7 @@ void pkClassAddMethod(PKVM* vm, PkHandle* cls,
|
||||
Class* class_ = (Class*)AS_OBJ(cls->value);
|
||||
|
||||
Function* fn = newFunction(vm, name, (int)strlen(name),
|
||||
class_->owner, true, NULL, NULL);
|
||||
class_->owner, true, docstring, NULL);
|
||||
vmPushTempRef(vm, &fn->_super); // fn.
|
||||
|
||||
fn->arity = arity;
|
||||
|
@ -504,6 +504,7 @@ Class* newClass(PKVM* vm, const char* name, int length,
|
||||
|
||||
cls->class_of = PK_INSTANCE;
|
||||
cls->super_class = super;
|
||||
cls->docstring = docstring;
|
||||
|
||||
// Builtin types doesn't belongs to a module.
|
||||
if (module != NULL) {
|
||||
|
@ -55,6 +55,17 @@ extern "C" {
|
||||
#define PK_PUBLIC
|
||||
#endif
|
||||
|
||||
// Returns the docstring of the function, which is a static const char* defined
|
||||
// just above the function by the DEF() macro below.
|
||||
#define PK_DOCS(fn) _pk_doc_##fn
|
||||
|
||||
// A macro to declare a function, with docstring, which is defined as
|
||||
// _pk_doc_<fn> = docstring; That'll used to generate function help text.
|
||||
// [signature] is the function name and parameter names with type information.
|
||||
// ex: `io.open(path:String, mode:String) -> io.File`
|
||||
#define PKDEF(fn, signature, docstring) \
|
||||
static const char* PK_DOCS(fn) = signature "\n\n" docstring; \
|
||||
static void fn(PKVM* vm)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* POCKETLANG TYPEDEFS & CALLBACKS */
|
||||
@ -276,22 +287,28 @@ PK_PUBLIC void pkRegisterModule(PKVM* vm, PkHandle* module);
|
||||
// Add a native function to the given module. If [arity] is -1 that means
|
||||
// the function has variadic parameters and use pkGetArgc() to get the argc.
|
||||
// Note that the function will be added as a global variable of the module.
|
||||
// [docstring] is optional and could be omitted with NULL.
|
||||
PK_PUBLIC void pkModuleAddFunction(PKVM* vm, PkHandle* module,
|
||||
const char* name,
|
||||
pkNativeFn fptr, int arity);
|
||||
pkNativeFn fptr, int arity,
|
||||
const char* docstring);
|
||||
|
||||
// Create a new class on the [module] with the [name] and return it.
|
||||
// If the [base_class] is NULL by default it'll set to "Object" class.
|
||||
// [docstring] is optional and could be omitted with NULL.
|
||||
PK_PUBLIC PkHandle* pkNewClass(PKVM* vm, const char* name,
|
||||
PkHandle* base_class, PkHandle* module,
|
||||
pkNewInstanceFn new_fn,
|
||||
pkDeleteInstanceFn delete_fn);
|
||||
pkDeleteInstanceFn delete_fn,
|
||||
const char* docstring);
|
||||
|
||||
// Add a native method to the given class. If the [arity] is -1 that means
|
||||
// the method has variadic parameters and use pkGetArgc() to get the argc.
|
||||
// [docstring] is optional and could be omitted with NULL.
|
||||
PK_PUBLIC void pkClassAddMethod(PKVM* vm, PkHandle* cls,
|
||||
const char* name,
|
||||
pkNativeFn fptr, int arity);
|
||||
pkNativeFn fptr, int arity,
|
||||
const char* docstring);
|
||||
|
||||
// It'll compile the pocket [source] for the module which result all the
|
||||
// functions and classes in that [source] to register on the module.
|
||||
|
@ -42,7 +42,8 @@ void _termEventDelete(PKVM* vm, void* event) {
|
||||
pkRealloc(vm, event, 0);
|
||||
}
|
||||
|
||||
void _termEventGetter(PKVM* vm) {
|
||||
PKDEF(_termEventGetter,
|
||||
"term.Event@getter() -> Var", "") {
|
||||
const char* name;
|
||||
if (!pkValidateSlotString(vm, 1, &name, NULL)) return;
|
||||
|
||||
@ -168,41 +169,60 @@ void _registerEnums(PKVM* vm, PkHandle* term) {
|
||||
|
||||
}
|
||||
|
||||
void _termInit(PKVM* vm) {
|
||||
PKDEF(_termInit,
|
||||
"term.init(capture_events:Bool) -> Null",
|
||||
"Initialize terminal with raw mode for tui applications, set "
|
||||
"[capture_events] true to enable event handling.") {
|
||||
bool capture_events;
|
||||
if (!pkValidateSlotBool(vm, 1, &capture_events)) return;
|
||||
term_init(capture_events);
|
||||
}
|
||||
|
||||
void _termCleanup(PKVM* vm) {
|
||||
PKDEF(_termCleanup,
|
||||
"term.cleanup() -> Null",
|
||||
"Cleanup and resotre the last terminal state.") {
|
||||
term_cleanup();
|
||||
}
|
||||
|
||||
void _termIsatty(PKVM* vm) {
|
||||
PKDEF(_termIsatty,
|
||||
"term.isatty() -> Bool",
|
||||
"Returns true if both stdin and stdout are tty.") {
|
||||
pkSetSlotBool(vm, 0, term_isatty());
|
||||
}
|
||||
|
||||
void _termNewScreenBuffer(PKVM* vm) {
|
||||
PKDEF(_termNewScreenBuffer,
|
||||
"term.new_screen_buffer() -> Null",
|
||||
"Switch to an alternative screen buffer.") {
|
||||
term_new_screen_buffer();
|
||||
}
|
||||
|
||||
void _termRestoreScreenBuffer(PKVM* vm) {
|
||||
PKDEF(_termRestoreScreenBuffer,
|
||||
"term.restore_screen_buffer() -> Null",
|
||||
"Restore the alternative buffer which was created with "
|
||||
"term.new_screen_buffer()") {
|
||||
term_restore_screen_buffer();
|
||||
}
|
||||
|
||||
void _termGetSize(PKVM* vm) {
|
||||
PKDEF(_termGetSize,
|
||||
"term.getsize() -> types.Vector",
|
||||
"Returns the screen size.") {
|
||||
pkReserveSlots(vm, 2);
|
||||
term_Vec size = term_getsize();
|
||||
_setSlotVector(vm, 0, 1, size.x, size.y);
|
||||
}
|
||||
|
||||
void _termGetPosition(PKVM* vm) {
|
||||
PKDEF(_termGetPosition,
|
||||
"term.getposition() -> types.Vector",
|
||||
"Returns the cursor position in the screen on a zero based coordinate.") {
|
||||
pkReserveSlots(vm, 2);
|
||||
term_Vec pos = term_getposition();
|
||||
_setSlotVector(vm, 0, 1, pos.x, pos.y);
|
||||
}
|
||||
|
||||
void _termSetPosition(PKVM* vm) {
|
||||
PKDEF(_termSetPosition,
|
||||
"term.setposition(pos:types.Vector | {x, y}) -> Null",
|
||||
"Set cursor position at the [position] in the screen no a zero"
|
||||
"based coordinate.") {
|
||||
double x, y;
|
||||
|
||||
int argc = pkGetArgc(vm);
|
||||
@ -224,7 +244,10 @@ void _termSetPosition(PKVM* vm) {
|
||||
term_setposition(pos);
|
||||
}
|
||||
|
||||
void _termReadEvent(PKVM* vm) {
|
||||
PKDEF(_termReadEvent,
|
||||
"term.read_event(event:term.Event) -> Bool",
|
||||
"Read an event and update the argument [event] and return true."
|
||||
"If no event was read it'll return false.") {
|
||||
pkReserveSlots(vm, 3);
|
||||
pkSetSlotHandle(vm, 2, _cls_term_event);
|
||||
if (!pkValidateSlotInstanceOf(vm, 1, 2)) return;
|
||||
@ -233,9 +256,10 @@ void _termReadEvent(PKVM* vm) {
|
||||
pkSetSlotBool(vm, 0, term_read_event(event));
|
||||
}
|
||||
|
||||
// On windows it'll set stdout to binary mode, on other platforms this function
|
||||
// won't make make any difference.
|
||||
void _termBinaryMode(PKVM* vm) {
|
||||
PKDEF(_termBinaryMode,
|
||||
"term.binary_mode() -> Null",
|
||||
"On windows it'll set stdout to binary mode, on other platforms this "
|
||||
"function won't make make any difference.") {
|
||||
#ifdef _WIN32
|
||||
(void) _setmode(_fileno(stdout), _O_BINARY);
|
||||
#endif
|
||||
@ -249,25 +273,29 @@ void registerModuleTerm(PKVM* vm) {
|
||||
PkHandle* term = pkNewModule(vm, "term");
|
||||
|
||||
_registerEnums(vm, term);
|
||||
pkModuleAddFunction(vm, term, "init", _termInit, 1);
|
||||
pkModuleAddFunction(vm, term, "cleanup", _termCleanup, 0);
|
||||
pkModuleAddFunction(vm, term, "isatty", _termIsatty, 0);
|
||||
pkModuleAddFunction(vm, term, "new_screen_buffer", _termNewScreenBuffer, 0);
|
||||
pkModuleAddFunction(vm, term, "restore_screen_buffer", _termRestoreScreenBuffer, 0);
|
||||
pkModuleAddFunction(vm, term, "getsize", _termGetSize, 0);
|
||||
pkModuleAddFunction(vm, term, "getposition", _termGetPosition, 0);
|
||||
pkModuleAddFunction(vm, term, "setposition", _termSetPosition, -1);
|
||||
pkModuleAddFunction(vm, term, "read_event", _termReadEvent, 1);
|
||||
REGISTER_FN(term, "init", _termInit, 1);
|
||||
REGISTER_FN(term, "cleanup", _termCleanup, 0);
|
||||
REGISTER_FN(term, "isatty", _termIsatty, 0);
|
||||
REGISTER_FN(term, "new_screen_buffer", _termNewScreenBuffer, 0);
|
||||
REGISTER_FN(term, "restore_screen_buffer", _termRestoreScreenBuffer, 0);
|
||||
REGISTER_FN(term, "getsize", _termGetSize, 0);
|
||||
REGISTER_FN(term, "getposition", _termGetPosition, 0);
|
||||
REGISTER_FN(term, "setposition", _termSetPosition, -1);
|
||||
REGISTER_FN(term, "read_event", _termReadEvent, 1);
|
||||
|
||||
_cls_term_event = pkNewClass(vm, "Event", NULL, term, _termEventNew, _termEventDelete);
|
||||
pkClassAddMethod(vm, _cls_term_event, "@getter", _termEventGetter, 1);
|
||||
_cls_term_event = pkNewClass(vm, "Event", NULL, term,
|
||||
_termEventNew, _termEventDelete,
|
||||
"The terminal event type, that'll be used at term.read_event function to "
|
||||
"fetch events.");
|
||||
|
||||
ADD_METHOD(_cls_term_event, "@getter", _termEventGetter, 1);
|
||||
|
||||
pkModuleAddSource(vm, term, ext_term_pk);
|
||||
|
||||
// This is required for language server. Since we need to send '\r\n' to
|
||||
// the lsp client but windows will change '\n' to '\r\n' and it'll become
|
||||
// '\r\r\n', binary mode will prevent this.
|
||||
pkModuleAddFunction(vm, term, "binary_mode", _termBinaryMode, 0);
|
||||
REGISTER_FN(term, "binary_mode", _termBinaryMode, 0);
|
||||
|
||||
pkRegisterModule(vm, term);
|
||||
pkReleaseHandle(vm, term);
|
||||
|
@ -22,9 +22,9 @@ typedef void* (*pkRealloc_t)(PKVM*, void*, size_t);
|
||||
typedef void (*pkReleaseHandle_t)(PKVM*, PkHandle*);
|
||||
typedef PkHandle* (*pkNewModule_t)(PKVM*, const char*);
|
||||
typedef void (*pkRegisterModule_t)(PKVM*, PkHandle*);
|
||||
typedef void (*pkModuleAddFunction_t)(PKVM*, PkHandle*, const char*, pkNativeFn, int);
|
||||
typedef PkHandle* (*pkNewClass_t)(PKVM*, const char*, PkHandle*, PkHandle*, pkNewInstanceFn, pkDeleteInstanceFn);
|
||||
typedef void (*pkClassAddMethod_t)(PKVM*, PkHandle*, const char*, pkNativeFn, int);
|
||||
typedef void (*pkModuleAddFunction_t)(PKVM*, PkHandle*, const char*, pkNativeFn, int, const char*);
|
||||
typedef PkHandle* (*pkNewClass_t)(PKVM*, const char*, PkHandle*, PkHandle*, pkNewInstanceFn, pkDeleteInstanceFn, const char*);
|
||||
typedef void (*pkClassAddMethod_t)(PKVM*, PkHandle*, const char*, pkNativeFn, int, const char*);
|
||||
typedef void (*pkModuleAddSource_t)(PKVM*, PkHandle*, const char*);
|
||||
typedef PkResult (*pkRunString_t)(PKVM*, const char*);
|
||||
typedef PkResult (*pkRunFile_t)(PKVM*, const char*);
|
||||
@ -133,6 +133,7 @@ typedef struct {
|
||||
|
||||
#define PK_API_INIT_FN_NAME "pkInitApi"
|
||||
#define PK_EXPORT_FN_NAME "pkExportModule"
|
||||
|
||||
#define PK_CLEANUP_FN_NAME "pkCleanupModule"
|
||||
|
||||
typedef void (*pkInitApiFn)(PkNativeApi*);
|
||||
|
@ -31,6 +31,12 @@
|
||||
#define REPORT_ERRNO(fn) \
|
||||
pkSetRuntimeErrorFmt(vm, "C." #fn " errno:%i - %s.", errno, strerror(errno))
|
||||
|
||||
#define REGISTER_FN(module, name, fn, argc) \
|
||||
pkModuleAddFunction(vm, module, name, fn, argc, PK_DOCS(fn))
|
||||
|
||||
#define ADD_METHOD(cls, name, fn, argc) \
|
||||
pkClassAddMethod(vm, cls, name, fn, argc, PK_DOCS(fn));
|
||||
|
||||
/*****************************************************************************/
|
||||
/* SHARED FUNCTIONS */
|
||||
/*****************************************************************************/
|
||||
|
@ -25,7 +25,9 @@ void _deleteDummy(PKVM* vm, void* ptr) {
|
||||
pkRealloc(vm, ptr, 0);
|
||||
}
|
||||
|
||||
DEF(_dummyInit, "") {
|
||||
DEF(_dummyInit,
|
||||
"dummy.Dummy._init(n:Number)",
|
||||
"Initialize a dummy instance with [n].") {
|
||||
double val;
|
||||
if (!pkValidateSlotNumber(vm, 1, &val)) return;
|
||||
|
||||
@ -33,7 +35,8 @@ DEF(_dummyInit, "") {
|
||||
self->val = val;
|
||||
}
|
||||
|
||||
DEF(_dummyGetter, "") {
|
||||
DEF(_dummyGetter, "dummy.Dummy.@getter()", "") {
|
||||
|
||||
const char* name = pkGetSlotString(vm, 1, NULL);
|
||||
Dummy* self = (Dummy*)pkGetSelf(vm);
|
||||
if (strcmp("val", name) == 0) {
|
||||
@ -42,7 +45,7 @@ DEF(_dummyGetter, "") {
|
||||
}
|
||||
}
|
||||
|
||||
DEF(_dummySetter, "") {
|
||||
DEF(_dummySetter, "dummy.Dummy.@setter()", "") {
|
||||
const char* name = pkGetSlotString(vm, 1, NULL);
|
||||
Dummy* self = (Dummy*)pkGetSelf(vm);
|
||||
if (strcmp("val", name) == 0) {
|
||||
@ -53,7 +56,9 @@ DEF(_dummySetter, "") {
|
||||
}
|
||||
}
|
||||
|
||||
DEF(_dummyAdd, "") {
|
||||
DEF(_dummyAdd,
|
||||
"dummy.Dummy.+(other:dummy.Dummy) -> dummy.Dummy",
|
||||
"Adds two dummy instances.") {
|
||||
Dummy* self = (Dummy*) pkGetSelf(vm);
|
||||
|
||||
pkReserveSlots(vm, 4); // Now we have slots [0, 1, 2, 3].
|
||||
@ -72,7 +77,9 @@ DEF(_dummyAdd, "") {
|
||||
if (!pkNewInstance(vm, 2, 0, 1, 3)) return;
|
||||
}
|
||||
|
||||
DEF(_dummyEq, "") {
|
||||
DEF(_dummyEq,
|
||||
"dummy.Dummy.==(other:dummy.Dummy) -> Bool",
|
||||
"Check if two dummy instances are the equal.") {
|
||||
|
||||
// TODO: Currently there is no way of getting another native instance
|
||||
// So, it's impossible to check self == other. So for now checking with
|
||||
@ -84,7 +91,9 @@ DEF(_dummyEq, "") {
|
||||
pkSetSlotBool(vm, 0, value == self->val);
|
||||
}
|
||||
|
||||
DEF(_dummyGt, "") {
|
||||
DEF(_dummyGt,
|
||||
"dummy.Dummy.>(other:dummy.Dummy) -> Bool",
|
||||
"Check if the dummy instance is greater than [other].") {
|
||||
|
||||
// TODO: Currently there is no way of getting another native instance
|
||||
// So, it's impossible to check self == other. So for now checking with
|
||||
@ -97,7 +106,7 @@ DEF(_dummyGt, "") {
|
||||
}
|
||||
|
||||
DEF(_dummyMethod,
|
||||
"Dummy.a_method(n1:num, n2:num) -> num\n"
|
||||
"Dummy.a_method(n1:Number, n2:Number) -> Number",
|
||||
"A dummy method to check dummy method calls. Will take 2 number arguments "
|
||||
"and return the multiplication.") {
|
||||
|
||||
@ -109,7 +118,7 @@ DEF(_dummyMethod,
|
||||
}
|
||||
|
||||
DEF(_dummyFunction,
|
||||
"dummy.afunc(s1:str, s2:str) -> str\n"
|
||||
"dummy.afunc(s1:String, s2:String) -> String",
|
||||
"A dummy function the'll return s2 + s1.") {
|
||||
|
||||
const char *s1, *s2;
|
||||
@ -120,8 +129,8 @@ DEF(_dummyFunction,
|
||||
}
|
||||
|
||||
DEF(_dummyCallNative,
|
||||
"dummy.call_native(f:fn) -> void\n"
|
||||
"Calls the function 'f' with arguments 'foo', 42, false.") {
|
||||
"dummy.call_native(fn:Closure) -> Null",
|
||||
"Calls the function 'fn' with arguments 'foo', 42, false.") {
|
||||
if (!pkValidateSlotType(vm, 1, PK_CLOSURE)) return;
|
||||
|
||||
pkReserveSlots(vm, 5); // Now we have slots [0, 1, 2, 3, 4].
|
||||
@ -134,7 +143,7 @@ DEF(_dummyCallNative,
|
||||
}
|
||||
|
||||
DEF(_dummyCallMethod,
|
||||
"dummy.call_method(o:Obj, method:str, a1, a2) -> \n"
|
||||
"dummy.call_method(o:Var, method:String, a1:Var, a2:Var) -> Var",
|
||||
"Calls the method int the object [o] with two arguments [a1] and [a2].") {
|
||||
const char* method;
|
||||
if (!pkValidateSlotString(vm, 2, &method, NULL)) return;
|
||||
@ -152,19 +161,20 @@ void registerModuleDummy(PKVM* vm) {
|
||||
|
||||
PkHandle* dummy = pkNewModule(vm, "dummy");
|
||||
|
||||
pkModuleAddFunction(vm, dummy, "afunc", _dummyFunction, 2);
|
||||
pkModuleAddFunction(vm, dummy, "call_native", _dummyCallNative, 1);
|
||||
pkModuleAddFunction(vm, dummy, "call_method", _dummyCallMethod, 4);
|
||||
REGISTER_FN(dummy, "afunc", _dummyFunction, 2);
|
||||
REGISTER_FN(dummy, "call_native", _dummyCallNative, 1);
|
||||
REGISTER_FN(dummy, "call_method", _dummyCallMethod, 4);
|
||||
|
||||
PkHandle* cls_dummy = pkNewClass(vm, "Dummy", NULL, dummy,
|
||||
_newDummy, _deleteDummy);
|
||||
pkClassAddMethod(vm, cls_dummy, "_init", _dummyInit, 1);
|
||||
pkClassAddMethod(vm, cls_dummy, "@getter", _dummyGetter, 1);
|
||||
pkClassAddMethod(vm, cls_dummy, "@setter", _dummySetter, 2);
|
||||
pkClassAddMethod(vm, cls_dummy, "+", _dummyAdd, 1);
|
||||
pkClassAddMethod(vm, cls_dummy, "==", _dummyEq, 1);
|
||||
pkClassAddMethod(vm, cls_dummy, ">", _dummyGt, 1);
|
||||
pkClassAddMethod(vm, cls_dummy, "a_method", _dummyMethod, 2);
|
||||
_newDummy, _deleteDummy, NULL);
|
||||
ADD_METHOD(cls_dummy, "_init", _dummyInit, 1);
|
||||
ADD_METHOD(cls_dummy, "@getter", _dummyGetter, 1);
|
||||
ADD_METHOD(cls_dummy, "@setter", _dummySetter, 2);
|
||||
ADD_METHOD(cls_dummy, "+", _dummyAdd, 1);
|
||||
ADD_METHOD(cls_dummy, "==", _dummyEq, 1);
|
||||
ADD_METHOD(cls_dummy, ">", _dummyGt, 1);
|
||||
ADD_METHOD(cls_dummy, "a_method", _dummyMethod, 2);
|
||||
|
||||
pkReleaseHandle(vm, cls_dummy);
|
||||
|
||||
pkRegisterModule(vm, dummy);
|
||||
|
@ -12,7 +12,7 @@
|
||||
#endif
|
||||
|
||||
DEF(_ioWrite,
|
||||
"io.write(stream:var, bytes:String) -> null\n"
|
||||
"io.write(stream:Var, bytes:String) -> Null",
|
||||
"Warning: the function is subjected to be changed anytime soon.\n"
|
||||
"Write [bytes] string to the stream. stream should be any of io.stdin, "
|
||||
"io.stdout, io.stderr.") {
|
||||
@ -46,14 +46,14 @@ DEF(_ioWrite,
|
||||
}
|
||||
|
||||
DEF(_ioFlush,
|
||||
"io.flush() -> null\n"
|
||||
"io.flush() -> Null",
|
||||
"Warning: the function is subjected to be changed anytime soon.\n"
|
||||
"Flush stdout buffer.\n") {
|
||||
"Flush stdout buffer.") {
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
DEF(_ioGetc,
|
||||
"io.getc() -> String\n"
|
||||
"io.getc() -> String",
|
||||
"Read a single character from stdin and return it.") {
|
||||
char c = (char) fgetc(stdin);
|
||||
pkSetSlotStringLength(vm, 0, &c, 1);
|
||||
@ -129,7 +129,21 @@ void _fileDelete(PKVM* vm, void* ptr) {
|
||||
/* FILE MODULE FUNCTIONS */
|
||||
/*****************************************************************************/
|
||||
|
||||
DEF(_fileOpen, "") {
|
||||
DEF(_fileOpen,
|
||||
"io.File.open(path:String, mode:String) -> Null",
|
||||
"Opens a file at the [path] with the [mode]. Path should be either "
|
||||
"absolute or relative to the current working directory. and [mode] can be"
|
||||
"'r', 'w', 'a' in combination with 'b' (binary) and/or '+' (extended).\n"
|
||||
"\n"
|
||||
" mode | If already exists | If does not exist |\n"
|
||||
" -----+-------------------+-------------------|\n"
|
||||
" 'r' | read from start | failure to open |\n"
|
||||
" 'w' | destroy contents | create new |\n"
|
||||
" 'a' | write to end | create new |\n"
|
||||
" 'r+' | read from start | error |\n"
|
||||
" 'w+' | destroy contents | create new |\n"
|
||||
" 'a+' | write to end | create new |\n"
|
||||
"") {
|
||||
|
||||
int argc = pkGetArgc(vm);
|
||||
if (!pkCheckArgcRange(vm, argc, 1, 2)) return;
|
||||
@ -181,7 +195,10 @@ DEF(_fileOpen, "") {
|
||||
}
|
||||
}
|
||||
|
||||
DEF(_fileRead, "") {
|
||||
DEF(_fileRead,
|
||||
"io.File.read(count:Number) -> String",
|
||||
"Reads [count] number of bytes from the file and return it as String."
|
||||
"If the count is -1 it'll read till the end of file and return it.") {
|
||||
|
||||
int argc = pkGetArgc(vm);
|
||||
if (!pkCheckArgcRange(vm, argc, 0, 1)) return;
|
||||
@ -265,7 +282,10 @@ L_done:
|
||||
|
||||
// Note that fgetline is not standard in older version of C. so we're defining
|
||||
// something similler.
|
||||
DEF(_fileGetLine, "") {
|
||||
DEF(_fileGetLine,
|
||||
"io.File.getline() -> String",
|
||||
"Reads a line from the file and return it as string. This function can only "
|
||||
"be used for files that are opened with text mode.") {
|
||||
File* file = (File*) pkGetSelf(vm);
|
||||
|
||||
if (file->closed) {
|
||||
@ -316,7 +336,10 @@ L_done:
|
||||
return;
|
||||
}
|
||||
|
||||
DEF(_fileWrite, "") {
|
||||
DEF(_fileWrite,
|
||||
"io.File.write(data:String) -> Null",
|
||||
"Write the [data] to the file. Since pocketlang string support any valid"
|
||||
"byte value in it's string, binary data can also be written with strings.") {
|
||||
|
||||
File* file = (File*) pkGetSelf(vm);
|
||||
const char* text; uint32_t length;
|
||||
@ -342,7 +365,9 @@ DEF(_fileWrite, "") {
|
||||
}
|
||||
}
|
||||
|
||||
DEF(_fileClose, "") {
|
||||
DEF(_fileClose,
|
||||
"io.File.close()",
|
||||
"Closes the opend file.") {
|
||||
|
||||
File* file = (File*) pkGetSelf(vm);
|
||||
|
||||
@ -362,8 +387,12 @@ DEF(_fileClose, "") {
|
||||
}
|
||||
|
||||
DEF(_fileSeek,
|
||||
"io.File.seek(offset:int, whence:int) -> null\n"
|
||||
"") {
|
||||
"io.File.seek(offset:Number, whence:Number) -> Null",
|
||||
"Move the file read/write offset. where [offset] is the offset from "
|
||||
"[whence] which should be any of the bellow three.\n"
|
||||
" 0: Begining of the file.\n"
|
||||
" 1: Current position.\n"
|
||||
" 2: End of the file.") {
|
||||
|
||||
int argc = pkGetArgc(vm);
|
||||
if (!pkCheckArgcRange(vm, argc, 1, 2)) return;
|
||||
@ -392,7 +421,9 @@ DEF(_fileSeek,
|
||||
}
|
||||
}
|
||||
|
||||
DEF(_fileTell, "") {
|
||||
DEF(_fileTell,
|
||||
"io.File.tell() -> Number",
|
||||
"Returns the read/write position of the file.") {
|
||||
File* file = (File*) pkGetSelf(vm);
|
||||
|
||||
if (file->closed) {
|
||||
@ -404,11 +435,22 @@ DEF(_fileTell, "") {
|
||||
pkSetSlotNumber(vm, 0, (double) ftell(file->fp));
|
||||
}
|
||||
|
||||
// open(path, mode='r') is equal to:
|
||||
//
|
||||
// from io import File
|
||||
// return File().open(path, mode)
|
||||
DEF(_open, NULL /* == _fileOpen */) {
|
||||
// TODO: The docstring is copyied from io.File.open() this violates DRY.
|
||||
DEF(_open,
|
||||
"open(path:String, mode:String) -> Null",
|
||||
"Opens a file at the [path] with the [mode]. Path should be either "
|
||||
"absolute or relative to the current working directory. and [mode] can be"
|
||||
"'r', 'w', 'a' in combination with 'b' (binary) and/or '+' (extended).\n"
|
||||
"\n"
|
||||
" mode | If already exists | If does not exist |\n"
|
||||
" -----+-------------------+-------------------|\n"
|
||||
" 'r' | read from start | failure to open |\n"
|
||||
" 'w' | destroy contents | create new |\n"
|
||||
" 'a' | write to end | create new |\n"
|
||||
" 'r+' | read from start | error |\n"
|
||||
" 'w+' | destroy contents | create new |\n"
|
||||
" 'a+' | write to end | create new |\n"
|
||||
"") {
|
||||
pkReserveSlots(vm, 3);
|
||||
|
||||
// slots[1] = path
|
||||
@ -431,7 +473,7 @@ void registerModuleIO(PKVM* vm) {
|
||||
|
||||
PkHandle* io = pkNewModule(vm, "io");
|
||||
|
||||
pkRegisterBuiltinFn(vm, "open", _open, -1, DOCSTRING(_fileOpen));
|
||||
pkRegisterBuiltinFn(vm, "open", _open, -1, DOCSTRING(_open));
|
||||
|
||||
pkReserveSlots(vm, 2);
|
||||
pkSetSlotHandle(vm, 0, io); // slot[0] = io
|
||||
@ -442,24 +484,27 @@ void registerModuleIO(PKVM* vm) {
|
||||
pkSetSlotNumber(vm, 1, 2); // slot[1] = 2
|
||||
pkSetAttribute(vm, 0, "stderr", 1); // slot[0].stderr = slot[1]
|
||||
|
||||
pkModuleAddFunction(vm, io, "write", _ioWrite, 2);
|
||||
pkModuleAddFunction(vm, io, "flush", _ioFlush, 0);
|
||||
pkModuleAddFunction(vm, io, "getc", _ioGetc, 0);
|
||||
REGISTER_FN(io, "write", _ioWrite, 2);
|
||||
REGISTER_FN(io, "flush", _ioFlush, 0);
|
||||
REGISTER_FN(io, "getc", _ioGetc, 0);
|
||||
|
||||
PkHandle* cls_file = pkNewClass(vm, "File", NULL, io, _fileNew, _fileDelete);
|
||||
pkClassAddMethod(vm, cls_file, "open", _fileOpen, -1);
|
||||
pkClassAddMethod(vm, cls_file, "read", _fileRead, -1);
|
||||
pkClassAddMethod(vm, cls_file, "write", _fileWrite, 1);
|
||||
pkClassAddMethod(vm, cls_file, "getline", _fileGetLine, 0);
|
||||
pkClassAddMethod(vm, cls_file, "close", _fileClose, 0);
|
||||
pkClassAddMethod(vm, cls_file, "seek", _fileSeek, -1);
|
||||
pkClassAddMethod(vm, cls_file, "tell", _fileTell, 0);
|
||||
PkHandle* cls_file = pkNewClass(vm, "File", NULL, io,
|
||||
_fileNew, _fileDelete,
|
||||
"A simple file type.");
|
||||
|
||||
ADD_METHOD(cls_file, "open", _fileOpen, -1);
|
||||
ADD_METHOD(cls_file, "read", _fileRead, -1);
|
||||
ADD_METHOD(cls_file, "write", _fileWrite, 1);
|
||||
ADD_METHOD(cls_file, "getline", _fileGetLine, 0);
|
||||
ADD_METHOD(cls_file, "close", _fileClose, 0);
|
||||
ADD_METHOD(cls_file, "seek", _fileSeek, -1);
|
||||
ADD_METHOD(cls_file, "tell", _fileTell, 0);
|
||||
pkReleaseHandle(vm, cls_file);
|
||||
|
||||
// A convinent function to read file by io.readfile(path).
|
||||
pkModuleAddSource(vm, io,
|
||||
"## Reads a file and return it's content as string.\n"
|
||||
"def readfile(filepath)\n"
|
||||
" \"Reads a file and return it's content as string\""
|
||||
" fp = File()\n"
|
||||
" fp.open(filepath, 'r')\n"
|
||||
" text = fp.read()\n"
|
||||
|
@ -160,7 +160,7 @@ static cJSON* _pocketToCJson(PKVM* vm, Var item) {
|
||||
}
|
||||
|
||||
DEF(_jsonParse,
|
||||
"json.parse(json_str:String) -> var\n"
|
||||
"json.parse(json_str:String) -> Var",
|
||||
"Parse a json string into pocket lang object.") {
|
||||
|
||||
const char* string;
|
||||
@ -186,7 +186,7 @@ DEF(_jsonParse,
|
||||
}
|
||||
|
||||
DEF(_jsonPrint,
|
||||
"json.print(value:Var[, pretty:Bool=false])\n"
|
||||
"json.print(value:Var, pretty:Bool=false)",
|
||||
"Render a pocketlang value into text. Takes an optional argument pretty, if "
|
||||
"true it'll pretty print the output.") {
|
||||
|
||||
@ -225,8 +225,8 @@ DEF(_jsonPrint,
|
||||
void registerModuleJson(PKVM* vm) {
|
||||
PkHandle* json = pkNewModule(vm, "json");
|
||||
|
||||
pkModuleAddFunction(vm, json, "parse", _jsonParse, 1);
|
||||
pkModuleAddFunction(vm, json, "print", _jsonPrint, -1);
|
||||
REGISTER_FN(json, "parse", _jsonParse, 1);
|
||||
REGISTER_FN(json, "print", _jsonPrint, -1);
|
||||
|
||||
pkRegisterModule(vm, json);
|
||||
pkReleaseHandle(vm, json);
|
||||
|
@ -14,7 +14,8 @@
|
||||
#define PK_PI 3.14159265358979323846
|
||||
|
||||
DEF(stdMathFloor,
|
||||
"floor(value:num) -> num\n") {
|
||||
"math.floor(value:Numberber) -> Numberber",
|
||||
"Return the floor value.") {
|
||||
|
||||
double num;
|
||||
if (!pkValidateSlotNumber(vm, 1, &num)) return;
|
||||
@ -22,7 +23,8 @@ DEF(stdMathFloor,
|
||||
}
|
||||
|
||||
DEF(stdMathCeil,
|
||||
"ceil(value:num) -> num\n") {
|
||||
"math.ceil(value:Number) -> Number",
|
||||
"Returns the ceiling value.") {
|
||||
|
||||
double num;
|
||||
if (!pkValidateSlotNumber(vm, 1, &num)) return;
|
||||
@ -30,7 +32,8 @@ DEF(stdMathCeil,
|
||||
}
|
||||
|
||||
DEF(stdMathPow,
|
||||
"pow(a:num, b:num) -> num\n") {
|
||||
"math.pow(a:Number, b:Number) -> Number",
|
||||
"Returns the power 'b' of 'a' similler to a**b.") {
|
||||
|
||||
double num, ex;
|
||||
if (!pkValidateSlotNumber(vm, 1, &num)) return;
|
||||
@ -39,7 +42,8 @@ DEF(stdMathPow,
|
||||
}
|
||||
|
||||
DEF(stdMathSqrt,
|
||||
"sqrt(value:num) -> num\n") {
|
||||
"math.sqrt(value:Number) -> Number",
|
||||
"Returns the square root of the value") {
|
||||
|
||||
double num;
|
||||
if (!pkValidateSlotNumber(vm, 1, &num)) return;
|
||||
@ -47,7 +51,8 @@ DEF(stdMathSqrt,
|
||||
}
|
||||
|
||||
DEF(stdMathAbs,
|
||||
"abs(value:num) -> num\n") {
|
||||
"math.abs(value:Number) -> Number",
|
||||
"Returns the absolute value.") {
|
||||
|
||||
double num;
|
||||
if (!pkValidateSlotNumber(vm, 1, &num)) return;
|
||||
@ -56,7 +61,8 @@ DEF(stdMathAbs,
|
||||
}
|
||||
|
||||
DEF(stdMathSign,
|
||||
"sign(value:num) -> num\n") {
|
||||
"math.sign(value:Number) -> Number",
|
||||
"return the sign of the which is one of (+1, 0, -1).") {
|
||||
|
||||
double num;
|
||||
if (!pkValidateSlotNumber(vm, 1, &num)) return;
|
||||
@ -67,7 +73,7 @@ DEF(stdMathSign,
|
||||
}
|
||||
|
||||
DEF(stdMathSine,
|
||||
"sin(rad:num) -> num\n"
|
||||
"math.sin(rad:Number) -> Number",
|
||||
"Return the sine value of the argument [rad] which is an angle expressed "
|
||||
"in radians.") {
|
||||
|
||||
@ -77,7 +83,7 @@ DEF(stdMathSine,
|
||||
}
|
||||
|
||||
DEF(stdMathCosine,
|
||||
"cos(rad:num) -> num\n"
|
||||
"math.cos(rad:Number) -> Number",
|
||||
"Return the cosine value of the argument [rad] which is an angle expressed "
|
||||
"in radians.") {
|
||||
|
||||
@ -87,7 +93,7 @@ DEF(stdMathCosine,
|
||||
}
|
||||
|
||||
DEF(stdMathTangent,
|
||||
"tan(rad:num) -> num\n"
|
||||
"math.tan(rad:Number) -> Number",
|
||||
"Return the tangent value of the argument [rad] which is an angle expressed "
|
||||
"in radians.") {
|
||||
|
||||
@ -97,7 +103,7 @@ DEF(stdMathTangent,
|
||||
}
|
||||
|
||||
DEF(stdMathSinh,
|
||||
"sinh(val) -> val\n"
|
||||
"math.sinh(val:Number) -> Number",
|
||||
"Return the hyperbolic sine value of the argument [val].") {
|
||||
|
||||
double val;
|
||||
@ -106,7 +112,7 @@ DEF(stdMathSinh,
|
||||
}
|
||||
|
||||
DEF(stdMathCosh,
|
||||
"cosh(val) -> val\n"
|
||||
"math.cosh(val:Number) -> Number",
|
||||
"Return the hyperbolic cosine value of the argument [val].") {
|
||||
|
||||
double val;
|
||||
@ -115,7 +121,7 @@ DEF(stdMathCosh,
|
||||
}
|
||||
|
||||
DEF(stdMathTanh,
|
||||
"tanh(val) -> val\n"
|
||||
"math.tanh(val:Number) -> Number",
|
||||
"Return the hyperbolic tangent value of the argument [val].") {
|
||||
|
||||
double val;
|
||||
@ -124,7 +130,7 @@ DEF(stdMathTanh,
|
||||
}
|
||||
|
||||
DEF(stdMathArcSine,
|
||||
"asin(num) -> num\n"
|
||||
"math.asin(num:Number) -> Number",
|
||||
"Return the arcsine value of the argument [num] which is an angle "
|
||||
"expressed in radians.") {
|
||||
|
||||
@ -139,7 +145,7 @@ DEF(stdMathArcSine,
|
||||
}
|
||||
|
||||
DEF(stdMathArcCosine,
|
||||
"acos(num) -> num\n"
|
||||
"math.acos(num:Number) -> Number",
|
||||
"Return the arc cosine value of the argument [num] which is "
|
||||
"an angle expressed in radians.") {
|
||||
|
||||
@ -154,7 +160,7 @@ DEF(stdMathArcCosine,
|
||||
}
|
||||
|
||||
DEF(stdMathArcTangent,
|
||||
"atan(num) -> num\n"
|
||||
"math.atan(num:Number) -> Number",
|
||||
"Return the arc tangent value of the argument [num] which is "
|
||||
"an angle expressed in radians.") {
|
||||
|
||||
@ -164,7 +170,7 @@ DEF(stdMathArcTangent,
|
||||
}
|
||||
|
||||
DEF(stdMathLog10,
|
||||
"log10(value:num) -> num\n"
|
||||
"math.log10(value:Number) -> Number",
|
||||
"Return the logarithm to base 10 of argument [value]") {
|
||||
|
||||
double num;
|
||||
@ -173,7 +179,7 @@ DEF(stdMathLog10,
|
||||
}
|
||||
|
||||
DEF(stdMathRound,
|
||||
"round(value:num) -> num\n"
|
||||
"math.round(value:Number) -> Number",
|
||||
"Round to nearest integer, away from zero and return the number.") {
|
||||
|
||||
double num;
|
||||
@ -182,7 +188,7 @@ DEF(stdMathRound,
|
||||
}
|
||||
|
||||
DEF(stdMathRand,
|
||||
"rand() -> num\n"
|
||||
"math.rand() -> Number",
|
||||
"Return a random runber in the range of 0..0x7fff.") {
|
||||
|
||||
// RAND_MAX is implementation dependent but is guaranteed to be at least
|
||||
@ -205,24 +211,24 @@ void registerModuleMath(PKVM* vm) {
|
||||
pkSetSlotNumber(vm, 1, PK_PI); // slot[1] = 3.14
|
||||
pkSetAttribute(vm, 0, "PI", 1); // slot[0].PI = slot[1]
|
||||
|
||||
pkModuleAddFunction(vm, math, "floor", stdMathFloor, 1);
|
||||
pkModuleAddFunction(vm, math, "ceil", stdMathCeil, 1);
|
||||
pkModuleAddFunction(vm, math, "pow", stdMathPow, 2);
|
||||
pkModuleAddFunction(vm, math, "sqrt", stdMathSqrt, 1);
|
||||
pkModuleAddFunction(vm, math, "abs", stdMathAbs, 1);
|
||||
pkModuleAddFunction(vm, math, "sign", stdMathSign, 1);
|
||||
pkModuleAddFunction(vm, math, "sin", stdMathSine, 1);
|
||||
pkModuleAddFunction(vm, math, "cos", stdMathCosine, 1);
|
||||
pkModuleAddFunction(vm, math, "tan", stdMathTangent, 1);
|
||||
pkModuleAddFunction(vm, math, "sinh", stdMathSinh, 1);
|
||||
pkModuleAddFunction(vm, math, "cosh", stdMathCosh, 1);
|
||||
pkModuleAddFunction(vm, math, "tanh", stdMathTanh, 1);
|
||||
pkModuleAddFunction(vm, math, "asin", stdMathArcSine, 1);
|
||||
pkModuleAddFunction(vm, math, "acos", stdMathArcCosine, 1);
|
||||
pkModuleAddFunction(vm, math, "atan", stdMathArcTangent, 1);
|
||||
pkModuleAddFunction(vm, math, "log10", stdMathLog10, 1);
|
||||
pkModuleAddFunction(vm, math, "round", stdMathRound, 1);
|
||||
pkModuleAddFunction(vm, math, "rand", stdMathRand, 0);
|
||||
REGISTER_FN(math, "floor", stdMathFloor, 1);
|
||||
REGISTER_FN(math, "ceil", stdMathCeil, 1);
|
||||
REGISTER_FN(math, "pow", stdMathPow, 2);
|
||||
REGISTER_FN(math, "sqrt", stdMathSqrt, 1);
|
||||
REGISTER_FN(math, "abs", stdMathAbs, 1);
|
||||
REGISTER_FN(math, "sign", stdMathSign, 1);
|
||||
REGISTER_FN(math, "sin", stdMathSine, 1);
|
||||
REGISTER_FN(math, "cos", stdMathCosine, 1);
|
||||
REGISTER_FN(math, "tan", stdMathTangent, 1);
|
||||
REGISTER_FN(math, "sinh", stdMathSinh, 1);
|
||||
REGISTER_FN(math, "cosh", stdMathCosh, 1);
|
||||
REGISTER_FN(math, "tanh", stdMathTanh, 1);
|
||||
REGISTER_FN(math, "asin", stdMathArcSine, 1);
|
||||
REGISTER_FN(math, "acos", stdMathArcCosine, 1);
|
||||
REGISTER_FN(math, "atan", stdMathArcTangent, 1);
|
||||
REGISTER_FN(math, "log10", stdMathLog10, 1);
|
||||
REGISTER_FN(math, "round", stdMathRound, 1);
|
||||
REGISTER_FN(math, "rand", stdMathRand, 0);
|
||||
|
||||
pkRegisterModule(vm, math);
|
||||
pkReleaseHandle(vm, math);
|
||||
|
@ -175,7 +175,7 @@ bool osGetExeFilePath(char* buff, int size) {
|
||||
|
||||
// Yes both 'os' and 'path' have getcwd functions.
|
||||
DEF(_osGetCWD,
|
||||
"os.getcwd() -> String\n"
|
||||
"os.getcwd() -> String",
|
||||
"Returns the current working directory") {
|
||||
char cwd[MAX_PATH_LEN];
|
||||
if (getcwd(cwd, sizeof(cwd)) == NULL) {
|
||||
@ -185,7 +185,7 @@ DEF(_osGetCWD,
|
||||
}
|
||||
|
||||
DEF(_osChdir,
|
||||
"os.chdir(path:String)\n"
|
||||
"os.chdir(path:String)",
|
||||
"Change the current working directory") {
|
||||
|
||||
const char* path;
|
||||
@ -195,7 +195,7 @@ DEF(_osChdir,
|
||||
}
|
||||
|
||||
DEF(_osMkdir,
|
||||
"os.mkdir(path:String)\n"
|
||||
"os.mkdir(path:String)",
|
||||
"Creates a directory at the path. The path should be valid.") {
|
||||
|
||||
const char* path;
|
||||
@ -213,7 +213,7 @@ DEF(_osMkdir,
|
||||
}
|
||||
|
||||
DEF(_osRmdir,
|
||||
"os.rmdir(path:String)\n"
|
||||
"os.rmdir(path:String)",
|
||||
"Removes an empty directory at the path.") {
|
||||
|
||||
const char* path;
|
||||
@ -222,7 +222,7 @@ DEF(_osRmdir,
|
||||
}
|
||||
|
||||
DEF(_osUnlink,
|
||||
"os.rmdir(path:String)\n"
|
||||
"os.rmdir(path:String)",
|
||||
"Removes a file at the path.") {
|
||||
|
||||
const char* path;
|
||||
@ -231,7 +231,7 @@ DEF(_osUnlink,
|
||||
}
|
||||
|
||||
DEF(_osModitime,
|
||||
"os.moditime(path:String) -> Number\n"
|
||||
"os.moditime(path:String) -> Number",
|
||||
"Returns the modified timestamp of the file.") {
|
||||
const char* path;
|
||||
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
|
||||
@ -243,7 +243,7 @@ DEF(_osModitime,
|
||||
}
|
||||
|
||||
DEF(_osFileSize,
|
||||
"os.filesize(path:String) -> Number\n"
|
||||
"os.filesize(path:String) -> Number",
|
||||
"Returns the file size in bytes.") {
|
||||
const char* path;
|
||||
|
||||
@ -260,7 +260,7 @@ DEF(_osFileSize,
|
||||
}
|
||||
|
||||
DEF(_osSystem,
|
||||
"os.system(cmd:String) -> Number\n"
|
||||
"os.system(cmd:String) -> Number",
|
||||
"Execute the command in a subprocess, Returns the exit code of the child "
|
||||
"process.") {
|
||||
const char* cmd;
|
||||
@ -278,7 +278,7 @@ DEF(_osSystem,
|
||||
}
|
||||
|
||||
DEF(_osGetenv,
|
||||
"os.getenv(name:String) -> String\n"
|
||||
"os.getenv(name:String) -> String",
|
||||
"Returns the environment variable as String if it exists otherwise it'll "
|
||||
"return null.") {
|
||||
|
||||
@ -295,7 +295,7 @@ DEF(_osGetenv,
|
||||
}
|
||||
|
||||
DEF(_osExepath,
|
||||
"os.exepath() -> String\n"
|
||||
"os.exepath() -> String",
|
||||
"Returns the path of the pocket interpreter executable.") {
|
||||
|
||||
char buff[MAX_PATH_LEN];
|
||||
@ -320,16 +320,16 @@ void registerModuleOS(PKVM* vm) {
|
||||
pkSetSlotString(vm, 1, OS_NAME); // slots[1] = "windows"
|
||||
pkSetAttribute(vm, 0, "NAME", 1); // os.NAME = "windows"
|
||||
|
||||
pkModuleAddFunction(vm, os, "getcwd", _osGetCWD, 0);
|
||||
pkModuleAddFunction(vm, os, "chdir", _osChdir, 1);
|
||||
pkModuleAddFunction(vm, os, "mkdir", _osMkdir, 1);
|
||||
pkModuleAddFunction(vm, os, "rmdir", _osRmdir, 1);
|
||||
pkModuleAddFunction(vm, os, "unlink", _osUnlink, 1);
|
||||
pkModuleAddFunction(vm, os, "moditime", _osModitime, 1);
|
||||
pkModuleAddFunction(vm, os, "filesize", _osFileSize, 1);
|
||||
pkModuleAddFunction(vm, os, "system", _osSystem, 1);
|
||||
pkModuleAddFunction(vm, os, "getenv", _osGetenv, 1);
|
||||
pkModuleAddFunction(vm, os, "exepath", _osExepath, 0);
|
||||
REGISTER_FN(os, "getcwd", _osGetCWD, 0);
|
||||
REGISTER_FN(os, "chdir", _osChdir, 1);
|
||||
REGISTER_FN(os, "mkdir", _osMkdir, 1);
|
||||
REGISTER_FN(os, "rmdir", _osRmdir, 1);
|
||||
REGISTER_FN(os, "unlink", _osUnlink, 1);
|
||||
REGISTER_FN(os, "moditime", _osModitime, 1);
|
||||
REGISTER_FN(os, "filesize", _osFileSize, 1);
|
||||
REGISTER_FN(os, "system", _osSystem, 1);
|
||||
REGISTER_FN(os, "getenv", _osGetenv, 1);
|
||||
REGISTER_FN(os, "exepath", _osExepath, 0);
|
||||
|
||||
// TODO:
|
||||
// - Implement makedirs which recursively mkdir().
|
||||
|
@ -225,7 +225,9 @@ static inline size_t pathAbs(const char* path, char* buff, size_t buffsz) {
|
||||
/* PATH MODULE FUNCTIONS */
|
||||
/*****************************************************************************/
|
||||
|
||||
DEF(_pathGetCWD, "") {
|
||||
DEF(_pathGetCWD,
|
||||
"path.getcwd() -> String",
|
||||
"Returns the current working directory.") {
|
||||
char cwd[MAX_PATH_LEN];
|
||||
if (getcwd(cwd, sizeof(cwd)) == NULL) {
|
||||
// TODO: Handle error.
|
||||
@ -233,7 +235,9 @@ DEF(_pathGetCWD, "") {
|
||||
pkSetSlotString(vm, 0, cwd);
|
||||
}
|
||||
|
||||
DEF(_pathAbspath, "") {
|
||||
DEF(_pathAbspath,
|
||||
"path.abspath(path:String) -> String",
|
||||
"Returns the absolute path of the [path].") {
|
||||
const char* path;
|
||||
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
|
||||
|
||||
@ -242,7 +246,10 @@ DEF(_pathAbspath, "") {
|
||||
pkSetSlotStringLength(vm, 0, abspath, len);
|
||||
}
|
||||
|
||||
DEF(_pathRelpath, "") {
|
||||
DEF(_pathRelpath,
|
||||
"path.relpath(path:String, from:String) -> String",
|
||||
"Returns the relative path of the [path] argument from the [from] "
|
||||
"directory.") {
|
||||
const char* path, * from;
|
||||
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
|
||||
if (!pkValidateSlotString(vm, 2, &from, NULL)) return;
|
||||
@ -259,7 +266,10 @@ DEF(_pathRelpath, "") {
|
||||
pkSetSlotStringLength(vm, 0, result, len);
|
||||
}
|
||||
|
||||
DEF(_pathJoin, "") {
|
||||
DEF(_pathJoin,
|
||||
"path.join(...) -> String",
|
||||
"Joins path with path seperator and return it. The maximum count of paths "
|
||||
"which can be joined for a call is " TOSTRING(MAX_JOIN_PATHS) ".") {
|
||||
const char* paths[MAX_JOIN_PATHS + 1]; // +1 for NULL.
|
||||
int argc = pkGetArgc(vm);
|
||||
|
||||
@ -280,7 +290,9 @@ DEF(_pathJoin, "") {
|
||||
pkSetSlotStringLength(vm, 0, result, len);
|
||||
}
|
||||
|
||||
DEF(_pathNormpath, "") {
|
||||
DEF(_pathNormpath,
|
||||
"path.normpath(path:String) -> String",
|
||||
"Returns the normalized path of the [path].") {
|
||||
const char* path;
|
||||
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
|
||||
|
||||
@ -289,7 +301,9 @@ DEF(_pathNormpath, "") {
|
||||
pkSetSlotStringLength(vm, 0, result, len);
|
||||
}
|
||||
|
||||
DEF(_pathBaseName, "") {
|
||||
DEF(_pathBaseName,
|
||||
"path.basename(path:String) -> String",
|
||||
"Returns the final component for the path") {
|
||||
const char* path;
|
||||
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
|
||||
|
||||
@ -299,7 +313,9 @@ DEF(_pathBaseName, "") {
|
||||
pkSetSlotStringLength(vm, 0, base_name, (uint32_t)length);
|
||||
}
|
||||
|
||||
DEF(_pathDirName, "") {
|
||||
DEF(_pathDirName,
|
||||
"path.dirname(path:String) -> String",
|
||||
"Returns the directory of the path.") {
|
||||
const char* path;
|
||||
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
|
||||
|
||||
@ -308,14 +324,18 @@ DEF(_pathDirName, "") {
|
||||
pkSetSlotStringLength(vm, 0, path, (uint32_t)length);
|
||||
}
|
||||
|
||||
DEF(_pathIsPathAbs, "") {
|
||||
DEF(_pathIsPathAbs,
|
||||
"path.isabspath(path:String) -> Bool",
|
||||
"Returns true if the path is absolute otherwise false.") {
|
||||
const char* path;
|
||||
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
|
||||
|
||||
pkSetSlotBool(vm, 0, cwk_path_is_absolute(path));
|
||||
}
|
||||
|
||||
DEF(_pathGetExtension, "") {
|
||||
DEF(_pathGetExtension,
|
||||
"path.getext(path:String) -> String",
|
||||
"Returns the file extension of the path.") {
|
||||
const char* path;
|
||||
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
|
||||
|
||||
@ -328,25 +348,33 @@ DEF(_pathGetExtension, "") {
|
||||
}
|
||||
}
|
||||
|
||||
DEF(_pathExists, "") {
|
||||
DEF(_pathExists,
|
||||
"path.exists(path:String) -> String",
|
||||
"Returns true if the file exists.") {
|
||||
const char* path;
|
||||
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
|
||||
pkSetSlotBool(vm, 0, pathIsExists(path));
|
||||
}
|
||||
|
||||
DEF(_pathIsFile, "") {
|
||||
DEF(_pathIsFile,
|
||||
"path.isfile(path:String) -> Bool",
|
||||
"Returns true if the path is a file.") {
|
||||
const char* path;
|
||||
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
|
||||
pkSetSlotBool(vm, 0, pathIsFile(path));
|
||||
}
|
||||
|
||||
DEF(_pathIsDir, "") {
|
||||
DEF(_pathIsDir,
|
||||
"path.isdir(path:String) -> Bool",
|
||||
"Returns true if the path is a directory.") {
|
||||
const char* path;
|
||||
if (!pkValidateSlotString(vm, 1, &path, NULL)) return;
|
||||
pkSetSlotBool(vm, 0, pathIsDir(path));
|
||||
}
|
||||
|
||||
DEF(_pathListDir, "") {
|
||||
DEF(_pathListDir,
|
||||
"path.listdir(path:String='.') -> List",
|
||||
"Returns all the entries in the directory at the [path].") {
|
||||
|
||||
int argc = pkGetArgc(vm);
|
||||
if (!pkCheckArgcRange(vm, argc, 0, 1)) return;
|
||||
@ -411,19 +439,19 @@ void registerModulePath(PKVM* vm) {
|
||||
|
||||
PkHandle* path = pkNewModule(vm, "path");
|
||||
|
||||
pkModuleAddFunction(vm, path, "getcwd", _pathGetCWD, 0);
|
||||
pkModuleAddFunction(vm, path, "abspath", _pathAbspath, 1);
|
||||
pkModuleAddFunction(vm, path, "relpath", _pathRelpath, 2);
|
||||
pkModuleAddFunction(vm, path, "join", _pathJoin, -1);
|
||||
pkModuleAddFunction(vm, path, "normpath", _pathNormpath, 1);
|
||||
pkModuleAddFunction(vm, path, "basename", _pathBaseName, 1);
|
||||
pkModuleAddFunction(vm, path, "dirname", _pathDirName, 1);
|
||||
pkModuleAddFunction(vm, path, "isabspath", _pathIsPathAbs, 1);
|
||||
pkModuleAddFunction(vm, path, "getext", _pathGetExtension, 1);
|
||||
pkModuleAddFunction(vm, path, "exists", _pathExists, 1);
|
||||
pkModuleAddFunction(vm, path, "isfile", _pathIsFile, 1);
|
||||
pkModuleAddFunction(vm, path, "isdir", _pathIsDir, 1);
|
||||
pkModuleAddFunction(vm, path, "listdir", _pathListDir, -1);
|
||||
REGISTER_FN(path, "getcwd", _pathGetCWD, 0);
|
||||
REGISTER_FN(path, "abspath", _pathAbspath, 1);
|
||||
REGISTER_FN(path, "relpath", _pathRelpath, 2);
|
||||
REGISTER_FN(path, "join", _pathJoin, -1);
|
||||
REGISTER_FN(path, "normpath", _pathNormpath, 1);
|
||||
REGISTER_FN(path, "basename", _pathBaseName, 1);
|
||||
REGISTER_FN(path, "dirname", _pathDirName, 1);
|
||||
REGISTER_FN(path, "isabspath", _pathIsPathAbs, 1);
|
||||
REGISTER_FN(path, "getext", _pathGetExtension, 1);
|
||||
REGISTER_FN(path, "exists", _pathExists, 1);
|
||||
REGISTER_FN(path, "isfile", _pathIsFile, 1);
|
||||
REGISTER_FN(path, "isdir", _pathIsDir, 1);
|
||||
REGISTER_FN(path, "listdir", _pathListDir, -1);
|
||||
|
||||
pkRegisterModule(vm, path);
|
||||
pkReleaseHandle(vm, path);
|
||||
|
@ -19,20 +19,20 @@
|
||||
#endif
|
||||
|
||||
DEF(_timeEpoch,
|
||||
"time() -> num\n"
|
||||
"time() -> Number",
|
||||
"Returns the number of seconds since the Epoch, 1970-01-01 "
|
||||
"00:00:00 +0000 (UTC).") {
|
||||
pkSetSlotNumber(vm, 0, (double) time(NULL));
|
||||
}
|
||||
|
||||
DEF(_timeClock,
|
||||
"clock() -> num\n"
|
||||
"clock() -> Number",
|
||||
"Returns the number of clocks passed divied by CLOCKS_PER_SEC.") {
|
||||
pkSetSlotNumber(vm, 0, (double) clock() / CLOCKS_PER_SEC);
|
||||
}
|
||||
|
||||
DEF(_timeSleep,
|
||||
"sleep(t:num) -> num\n"
|
||||
"sleep(t:num) -> Number",
|
||||
"Sleep for [t] milliseconds.") {
|
||||
|
||||
double t;
|
||||
@ -54,9 +54,9 @@ DEF(_timeSleep,
|
||||
void registerModuleTime(PKVM* vm) {
|
||||
PkHandle* time = pkNewModule(vm, "time");
|
||||
|
||||
pkModuleAddFunction(vm, time, "epoch", _timeEpoch, 0);
|
||||
pkModuleAddFunction(vm, time, "sleep", _timeSleep, 1);
|
||||
pkModuleAddFunction(vm, time, "clock", _timeClock, 0);
|
||||
REGISTER_FN(time, "epoch", _timeEpoch, 0);
|
||||
REGISTER_FN(time, "sleep", _timeSleep, 1);
|
||||
REGISTER_FN(time, "clock", _timeClock, 0);
|
||||
|
||||
pkRegisterModule(vm, time);
|
||||
pkReleaseHandle(vm, time);
|
||||
|
@ -13,7 +13,7 @@
|
||||
#endif
|
||||
|
||||
DEF(_typesHashable,
|
||||
"types.hashable(value:Var) -> Bool\n"
|
||||
"types.hashable(value:Var) -> Bool",
|
||||
"Returns true if the [value] is hashable.") {
|
||||
|
||||
// Get argument 1 directly.
|
||||
@ -26,7 +26,7 @@ DEF(_typesHashable,
|
||||
}
|
||||
|
||||
DEF(_typesHash,
|
||||
"types.hash(value:Var) -> Number\n"
|
||||
"types.hash(value:Var) -> Number",
|
||||
"Returns the hash of the [value]") {
|
||||
|
||||
// Get argument 1 directly.
|
||||
@ -56,7 +56,11 @@ static void _bytebuffDelete(PKVM* vm, void* buff) {
|
||||
pkRealloc(vm, buff, 0);
|
||||
}
|
||||
|
||||
DEF(_bytebuffReserve, "") {
|
||||
DEF(_bytebuffReserve,
|
||||
"types.ByteBuffer.reserve(count:Number) -> Null",
|
||||
"Reserve [count] number of bytes internally. This is use full if the final "
|
||||
"size of the buffer is known beforehand to avoid reduce the number of "
|
||||
"re-allocations.") {
|
||||
double size;
|
||||
if (!pkValidateSlotNumber(vm, 1, &size)) return;
|
||||
|
||||
@ -65,7 +69,10 @@ DEF(_bytebuffReserve, "") {
|
||||
}
|
||||
|
||||
// buff.fill(data, count)
|
||||
DEF(_bytebuffFill, "") {
|
||||
DEF(_bytebuffFill,
|
||||
"types.ByteBuffer.fill(value:Number) -> Null",
|
||||
"Fill the buffer with the given byte value. Note that the value must be in "
|
||||
"between 0 and 0xff inclusive.") {
|
||||
uint32_t n;
|
||||
if (!pkValidateSlotInteger(vm, 1, &n)) return;
|
||||
if (n < 0x00 || n > 0xff) {
|
||||
@ -81,14 +88,20 @@ DEF(_bytebuffFill, "") {
|
||||
pkByteBufferFill(self, vm, (uint8_t) n, (int) count);
|
||||
}
|
||||
|
||||
DEF(_bytebuffClear, "") {
|
||||
DEF(_bytebuffClear,
|
||||
"types.ByteBuffer.clear() -> Null",
|
||||
"Clear the buffer values.") {
|
||||
// TODO: Should I also zero or reduce the capacity?
|
||||
pkByteBuffer* self = pkGetSelf(vm);
|
||||
self->count = 0;
|
||||
}
|
||||
|
||||
// Returns the length of bytes were written.
|
||||
DEF(_bytebuffWrite, "") {
|
||||
DEF(_bytebuffWrite,
|
||||
"types.ByteBuffer.write(data:Number|String) -> Null",
|
||||
"Writes the data to the buffer. If the [data] is a number that should be in "
|
||||
"between 0 and 0xff inclusively. If the [data] is a string all the bytes "
|
||||
"of the string will be written to the buffer.") {
|
||||
pkByteBuffer* self = pkGetSelf(vm);
|
||||
|
||||
PkVarType type = pkGetSlotType(vm, 1);
|
||||
@ -135,7 +148,8 @@ DEF(_bytebuffWrite, "") {
|
||||
|
||||
}
|
||||
|
||||
DEF(_bytebuffSubscriptGet, "") {
|
||||
DEF(_bytebuffSubscriptGet,
|
||||
"types.ByteBuffer.[](index:Number)", "") {
|
||||
double index;
|
||||
if (!pkValidateSlotNumber(vm, 1, &index)) return;
|
||||
if (floor(index) != index) {
|
||||
@ -154,7 +168,8 @@ DEF(_bytebuffSubscriptGet, "") {
|
||||
|
||||
}
|
||||
|
||||
DEF(_bytebuffSubscriptSet, "") {
|
||||
DEF(_bytebuffSubscriptSet,
|
||||
"types.ByteBuffer.[]=(index:Number, value:Number)", "") {
|
||||
double index, value;
|
||||
if (!pkValidateSlotNumber(vm, 1, &index)) return;
|
||||
if (!pkValidateSlotNumber(vm, 2, &value)) return;
|
||||
@ -184,12 +199,16 @@ DEF(_bytebuffSubscriptSet, "") {
|
||||
|
||||
}
|
||||
|
||||
DEF(_bytebuffString, "") {
|
||||
DEF(_bytebuffString,
|
||||
"types.ByteBuffer.string() -> String",
|
||||
"Returns the buffered values as String.") {
|
||||
pkByteBuffer* self = pkGetSelf(vm);
|
||||
pkSetSlotStringLength(vm, 0, self->data, self->count);
|
||||
}
|
||||
|
||||
DEF(_bytebuffCount, "") {
|
||||
DEF(_bytebuffCount,
|
||||
"types.ByteBuffer.count() -> Number",
|
||||
"Returns the number of bytes that have written to the buffer.") {
|
||||
pkByteBuffer* self = pkGetSelf(vm);
|
||||
pkSetSlotNumber(vm, 0, self->count);
|
||||
}
|
||||
@ -212,7 +231,8 @@ static void _vectorDelete(PKVM* vm, void* vec) {
|
||||
pkRealloc(vm, vec, 0);
|
||||
}
|
||||
|
||||
DEF(_vectorInit, "") {
|
||||
DEF(_vectorInit,
|
||||
"types.Vector._init()", "") {
|
||||
int argc = pkGetArgc(vm);
|
||||
if (!pkCheckArgcRange(vm, argc, 0, 3)) return;
|
||||
|
||||
@ -237,7 +257,8 @@ DEF(_vectorInit, "") {
|
||||
|
||||
}
|
||||
|
||||
DEF(_vectorGetter, "") {
|
||||
DEF(_vectorGetter,
|
||||
"types.Vector.@getter()", "") {
|
||||
const char* name; uint32_t length;
|
||||
if (!pkValidateSlotString(vm, 1, &name, &length)) return;
|
||||
|
||||
@ -256,7 +277,8 @@ DEF(_vectorGetter, "") {
|
||||
}
|
||||
}
|
||||
|
||||
DEF(_vectorSetter, "") {
|
||||
DEF(_vectorSetter,
|
||||
"types.Vector.@setter()", "") {
|
||||
const char* name; uint32_t length;
|
||||
if (!pkValidateSlotString(vm, 1, &name, &length)) return;
|
||||
|
||||
@ -279,7 +301,8 @@ DEF(_vectorSetter, "") {
|
||||
}
|
||||
}
|
||||
|
||||
DEF(_vectorRepr, "") {
|
||||
DEF(_vectorRepr,
|
||||
"types.Vector._repr()", "") {
|
||||
Vector* vec = pkGetSelf(vm);
|
||||
pkSetSlotStringFmt(vm, 0, "[%g, %g, %g]", vec->x, vec->y, vec->z);
|
||||
}
|
||||
@ -291,29 +314,36 @@ DEF(_vectorRepr, "") {
|
||||
void registerModuleTypes(PKVM* vm) {
|
||||
PkHandle* types = pkNewModule(vm, "types");
|
||||
|
||||
pkModuleAddFunction(vm, types, "hashable", _typesHashable, 1);
|
||||
pkModuleAddFunction(vm, types, "hash", _typesHash, 1);
|
||||
REGISTER_FN(types, "hashable", _typesHashable, 1);
|
||||
REGISTER_FN(types, "hash", _typesHash, 1);
|
||||
|
||||
PkHandle* cls_byte_buffer = pkNewClass(vm, "ByteBuffer", NULL, types,
|
||||
_bytebuffNew, _bytebuffDelete);
|
||||
_bytebuffNew, _bytebuffDelete,
|
||||
"A simple dynamically allocated byte buffer type. This can be used for "
|
||||
"constructing larger strings without allocating and adding smaller "
|
||||
"intermeidate strings.");
|
||||
|
||||
ADD_METHOD(cls_byte_buffer, "[]", _bytebuffSubscriptGet, 1);
|
||||
ADD_METHOD(cls_byte_buffer, "[]=", _bytebuffSubscriptSet, 2);
|
||||
ADD_METHOD(cls_byte_buffer, "reserve", _bytebuffReserve, 1);
|
||||
ADD_METHOD(cls_byte_buffer, "fill", _bytebuffFill, 2);
|
||||
ADD_METHOD(cls_byte_buffer, "clear", _bytebuffClear, 0);
|
||||
ADD_METHOD(cls_byte_buffer, "write", _bytebuffWrite, 1);
|
||||
ADD_METHOD(cls_byte_buffer, "string", _bytebuffString, 0);
|
||||
ADD_METHOD(cls_byte_buffer, "count", _bytebuffCount, 0);
|
||||
|
||||
pkClassAddMethod(vm, cls_byte_buffer, "[]", _bytebuffSubscriptGet, 1);
|
||||
pkClassAddMethod(vm, cls_byte_buffer, "[]=", _bytebuffSubscriptSet, 2);
|
||||
pkClassAddMethod(vm, cls_byte_buffer, "reserve", _bytebuffReserve, 1);
|
||||
pkClassAddMethod(vm, cls_byte_buffer, "fill", _bytebuffFill, 2);
|
||||
pkClassAddMethod(vm, cls_byte_buffer, "clear", _bytebuffClear, 0);
|
||||
pkClassAddMethod(vm, cls_byte_buffer, "write", _bytebuffWrite, 1);
|
||||
pkClassAddMethod(vm, cls_byte_buffer, "string", _bytebuffString, 0);
|
||||
pkClassAddMethod(vm, cls_byte_buffer, "count", _bytebuffCount, 0);
|
||||
pkReleaseHandle(vm, cls_byte_buffer);
|
||||
|
||||
// TODO: add move mthods.
|
||||
PkHandle* cls_vector = pkNewClass(vm, "Vector", NULL, types,
|
||||
_vectorNew, _vectorDelete);
|
||||
pkClassAddMethod(vm, cls_vector, "_init", _vectorInit, -1);
|
||||
pkClassAddMethod(vm, cls_vector, "@getter", _vectorGetter, 1);
|
||||
pkClassAddMethod(vm, cls_vector, "@setter", _vectorSetter, 2);
|
||||
pkClassAddMethod(vm, cls_vector, "_repr", _vectorRepr, 0);
|
||||
_vectorNew, _vectorDelete,
|
||||
"A simple vector type contains x, y, and z components.");
|
||||
|
||||
ADD_METHOD(cls_vector, "_init", _vectorInit, -1);
|
||||
ADD_METHOD(cls_vector, "@getter", _vectorGetter, 1);
|
||||
ADD_METHOD(cls_vector, "@setter", _vectorSetter, 2);
|
||||
ADD_METHOD(cls_vector, "_repr", _vectorRepr, 0);
|
||||
|
||||
pkReleaseHandle(vm, cls_vector);
|
||||
|
||||
pkRegisterModule(vm, types);
|
||||
|
@ -173,6 +173,17 @@ b = 'vb'; d = 'vd'; f = 'vf'
|
||||
assert("a ${ b + ' c ${d + " e ${f}"}' }" == "a vb c vd e vf")
|
||||
assert("$b$d$f" == "vbvdvf")
|
||||
|
||||
def foo()
|
||||
"a docstring to test"
|
||||
end
|
||||
assert(foo._docs == "a docstring to test")
|
||||
|
||||
class Foo
|
||||
"Testing for
|
||||
class docstring"
|
||||
end
|
||||
assert(Foo._docs == "Testing for\n class docstring")
|
||||
|
||||
|
||||
# If we got here, that means all test were passed.
|
||||
print('All TESTS PASSED')
|
||||
|
@ -19,9 +19,9 @@ typedef void* (*pkRealloc_t)(PKVM*, void*, size_t);
|
||||
typedef void (*pkReleaseHandle_t)(PKVM*, PkHandle*);
|
||||
typedef PkHandle* (*pkNewModule_t)(PKVM*, const char*);
|
||||
typedef void (*pkRegisterModule_t)(PKVM*, PkHandle*);
|
||||
typedef void (*pkModuleAddFunction_t)(PKVM*, PkHandle*, const char*, pkNativeFn, int);
|
||||
typedef PkHandle* (*pkNewClass_t)(PKVM*, const char*, PkHandle*, PkHandle*, pkNewInstanceFn, pkDeleteInstanceFn);
|
||||
typedef void (*pkClassAddMethod_t)(PKVM*, PkHandle*, const char*, pkNativeFn, int);
|
||||
typedef void (*pkModuleAddFunction_t)(PKVM*, PkHandle*, const char*, pkNativeFn, int, const char*);
|
||||
typedef PkHandle* (*pkNewClass_t)(PKVM*, const char*, PkHandle*, PkHandle*, pkNewInstanceFn, pkDeleteInstanceFn, const char*);
|
||||
typedef void (*pkClassAddMethod_t)(PKVM*, PkHandle*, const char*, pkNativeFn, int, const char*);
|
||||
typedef void (*pkModuleAddSource_t)(PKVM*, PkHandle*, const char*);
|
||||
typedef PkResult (*pkRunString_t)(PKVM*, const char*);
|
||||
typedef PkResult (*pkRunFile_t)(PKVM*, const char*);
|
||||
@ -235,16 +235,16 @@ void pkRegisterModule(PKVM* vm, PkHandle* module) {
|
||||
pk_api.pkRegisterModule_ptr(vm, module);
|
||||
}
|
||||
|
||||
void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name, pkNativeFn fptr, int arity) {
|
||||
pk_api.pkModuleAddFunction_ptr(vm, module, name, fptr, arity);
|
||||
void pkModuleAddFunction(PKVM* vm, PkHandle* module, const char* name, pkNativeFn fptr, int arity, const char* docstring) {
|
||||
pk_api.pkModuleAddFunction_ptr(vm, module, name, fptr, arity, docstring);
|
||||
}
|
||||
|
||||
PkHandle* pkNewClass(PKVM* vm, const char* name, PkHandle* base_class, PkHandle* module, pkNewInstanceFn new_fn, pkDeleteInstanceFn delete_fn) {
|
||||
return pk_api.pkNewClass_ptr(vm, name, base_class, module, new_fn, delete_fn);
|
||||
PkHandle* pkNewClass(PKVM* vm, const char* name, PkHandle* base_class, PkHandle* module, pkNewInstanceFn new_fn, pkDeleteInstanceFn delete_fn, const char* docstring) {
|
||||
return pk_api.pkNewClass_ptr(vm, name, base_class, module, new_fn, delete_fn, docstring);
|
||||
}
|
||||
|
||||
void pkClassAddMethod(PKVM* vm, PkHandle* cls, const char* name, pkNativeFn fptr, int arity) {
|
||||
pk_api.pkClassAddMethod_ptr(vm, cls, name, fptr, arity);
|
||||
void pkClassAddMethod(PKVM* vm, PkHandle* cls, const char* name, pkNativeFn fptr, int arity, const char* docstring) {
|
||||
pk_api.pkClassAddMethod_ptr(vm, cls, name, fptr, arity, docstring);
|
||||
}
|
||||
|
||||
void pkModuleAddSource(PKVM* vm, PkHandle* module, const char* source) {
|
||||
|
Loading…
Reference in New Issue
Block a user