From f908aa518d80693924388a349cca85be9a899a34 Mon Sep 17 00:00:00 2001 From: Thakee Nathees Date: Sun, 5 Jun 2022 18:10:31 +0530 Subject: [PATCH] docstrings support added for native functions --- src/core/common.h | 6 +- src/core/compiler.c | 16 ++++ src/core/core.c | 146 ++++++++++++++++++++++--------------- src/core/public.c | 14 ++-- src/core/value.c | 1 + src/include/pocketlang.h | 23 +++++- src/libs/ext_term.c | 78 +++++++++++++------- src/libs/gen/nativeapi.h | 13 ++-- src/libs/libs.h | 6 ++ src/libs/std_dummy.c | 54 ++++++++------ src/libs/std_io.c | 105 ++++++++++++++++++-------- src/libs/std_json.c | 8 +- src/libs/std_math.c | 78 +++++++++++--------- src/libs/std_os.c | 40 +++++----- src/libs/std_path.c | 80 +++++++++++++------- src/libs/std_time.c | 12 +-- src/libs/std_types.c | 90 +++++++++++++++-------- tests/lang/basics.pk | 11 +++ tests/native/dl/pknative.c | 18 ++--- 19 files changed, 515 insertions(+), 284 deletions(-) diff --git a/src/core/common.h b/src/core/common.h index f887ad3..96e15d5 100644 --- a/src/core/common.h +++ b/src/core/common.h @@ -117,8 +117,10 @@ // A macro to declare a function, with docstring, which is defined as // _pk_doc_ = 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 diff --git a/src/core/compiler.c b/src/core/compiler.c index 0aa0c09..4abed5f 100644 --- a/src/core/compiler.c +++ b/src/core/compiler.c @@ -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) { diff --git a/src/core/core.c b/src/core/core.c index 193fb0c..a404d77 100644 --- a/src/core/core.c +++ b/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,25 +290,40 @@ 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 (closure->fn->docstring != NULL) { - vm->config.stdout_write(vm, closure->fn->docstring); - vm->config.stdout_write(vm, "\n\n"); + 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); + vm->config.stdout_write(vm, "\n\n"); + } else { + vm->config.stdout_write(vm, "function '"); + 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 { - vm->config.stdout_write(vm, "function '"); - vm->config.stdout_write(vm, closure->fn->name); - vm->config.stdout_write(vm, "()' doesn't have a docstring.\n"); + 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 " "';;\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; diff --git a/src/core/public.c b/src/core/public.c index 2f67661..3601492 100644 --- a/src/core/public.c +++ b/src/core/public.c @@ -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; diff --git a/src/core/value.c b/src/core/value.c index 90c1bc6..3db314f 100644 --- a/src/core/value.c +++ b/src/core/value.c @@ -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) { diff --git a/src/include/pocketlang.h b/src/include/pocketlang.h index 11e5258..1c89d3a 100644 --- a/src/include/pocketlang.h +++ b/src/include/pocketlang.h @@ -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_ = 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. diff --git a/src/libs/ext_term.c b/src/libs/ext_term.c index eda4a6a..64eeb16 100644 --- a/src/libs/ext_term.c +++ b/src/libs/ext_term.c @@ -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); diff --git a/src/libs/gen/nativeapi.h b/src/libs/gen/nativeapi.h index 865cfdb..efabc1d 100644 --- a/src/libs/gen/nativeapi.h +++ b/src/libs/gen/nativeapi.h @@ -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*); @@ -131,9 +131,10 @@ typedef struct { pkImportModule_t pkImportModule_ptr; } PkNativeApi; -#define PK_API_INIT_FN_NAME "pkInitApi" -#define PK_EXPORT_FN_NAME "pkExportModule" -#define PK_CLEANUP_FN_NAME "pkCleanupModule" +#define PK_API_INIT_FN_NAME "pkInitApi" +#define PK_EXPORT_FN_NAME "pkExportModule" + +#define PK_CLEANUP_FN_NAME "pkCleanupModule" typedef void (*pkInitApiFn)(PkNativeApi*); typedef PkHandle* (*pkExportModuleFn)(PKVM*); diff --git a/src/libs/libs.h b/src/libs/libs.h index ce92f70..8a07879 100644 --- a/src/libs/libs.h +++ b/src/libs/libs.h @@ -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 */ /*****************************************************************************/ diff --git a/src/libs/std_dummy.c b/src/libs/std_dummy.c index 4d164a3..43d8d62 100644 --- a/src/libs/std_dummy.c +++ b/src/libs/std_dummy.c @@ -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); diff --git a/src/libs/std_io.c b/src/libs/std_io.c index b2017a6..c60491c 100644 --- a/src/libs/std_io.c +++ b/src/libs/std_io.c @@ -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" diff --git a/src/libs/std_json.c b/src/libs/std_json.c index 50c7f57..41ab232 100644 --- a/src/libs/std_json.c +++ b/src/libs/std_json.c @@ -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); diff --git a/src/libs/std_math.c b/src/libs/std_math.c index b70e7c0..eaf550c 100644 --- a/src/libs/std_math.c +++ b/src/libs/std_math.c @@ -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); diff --git a/src/libs/std_os.c b/src/libs/std_os.c index 728dd0f..3f55d90 100644 --- a/src/libs/std_os.c +++ b/src/libs/std_os.c @@ -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(). diff --git a/src/libs/std_path.c b/src/libs/std_path.c index db1373f..714ea82 100644 --- a/src/libs/std_path.c +++ b/src/libs/std_path.c @@ -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); diff --git a/src/libs/std_time.c b/src/libs/std_time.c index 1068567..ec4343e 100644 --- a/src/libs/std_time.c +++ b/src/libs/std_time.c @@ -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); diff --git a/src/libs/std_types.c b/src/libs/std_types.c index 7ff10db..f270e5c 100644 --- a/src/libs/std_types.c +++ b/src/libs/std_types.c @@ -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); diff --git a/tests/lang/basics.pk b/tests/lang/basics.pk index bdb0dfc..b8b812e 100644 --- a/tests/lang/basics.pk +++ b/tests/lang/basics.pk @@ -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') diff --git a/tests/native/dl/pknative.c b/tests/native/dl/pknative.c index 76cdf9e..00a5995 100644 --- a/tests/native/dl/pknative.c +++ b/tests/native/dl/pknative.c @@ -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) {