Write a bunch more docs

This commit is contained in:
K. Lange 2021-02-20 20:44:07 +09:00
parent c5b04d55b1
commit a5ff538dc1
10 changed files with 287 additions and 99 deletions

View File

@ -32,6 +32,7 @@ ALIASES += methodstart{4}="\anchor \1 \htmlonly<\3 class=\"memtitle \4\"><span c
ALIASES += methodstart{5}="\anchor \1 \htmlonly<\3 class=\"memtitle \4\"><span class=\"permalink\"><a href=\"#\1\">_</a></span>\2</\3><div class=\"memitem\"><div class=\"memproto\">\5</div><div class=\"memdoc\">\endhtmlonly" ALIASES += methodstart{5}="\anchor \1 \htmlonly<\3 class=\"memtitle \4\"><span class=\"permalink\"><a href=\"#\1\">_</a></span>\2</\3><div class=\"memitem\"><div class=\"memproto\">\5</div><div class=\"memdoc\">\endhtmlonly"
ALIASES += methodend="\htmlonly</div></div>\endhtmlonly" ALIASES += methodend="\htmlonly</div></div>\endhtmlonly"
ALIASES += bsnote{1}="\htmlonly<div class=\"alert alert-warning\">\endhtmlonly\1\htmlonly</div>\endhtmlonly" ALIASES += bsnote{1}="\htmlonly<div class=\"alert alert-warning\">\endhtmlonly\1\htmlonly</div>\endhtmlonly"
ALIASES += bsnote{2}="\htmlonly<div class=\"alert alert-\1\">\endhtmlonly\2\htmlonly</div>\endhtmlonly"
ALIASES += modulelist{1}="\htmlonly<div class=\"directory\"><table class=\"directory\">\endhtmlonly\1\htmlonly</table></div>\endhtmlonly" ALIASES += modulelist{1}="\htmlonly<div class=\"directory\"><table class=\"directory\">\endhtmlonly\1\htmlonly</table></div>\endhtmlonly"
ALIASES += krkmodule{2}="\htmlonly<tr class=\"autoalternate\"><td class=\"entry\"><span style\"width:16px;display:inline-block;\">&nbsp;</span><span class=\"icona\"><span class=\"icon\">M</span></span>\endhtmlonly@ref \1\htmlonly</td><td class=\"desc\">\endhtmlonly\2\htmlonly</td</tr>\endhtmlonly" ALIASES += krkmodule{2}="\htmlonly<tr class=\"autoalternate\"><td class=\"entry\"><span style\"width:16px;display:inline-block;\">&nbsp;</span><span class=\"icona\"><span class=\"icon\">M</span></span>\endhtmlonly@ref \1\htmlonly</td><td class=\"desc\">\endhtmlonly\2\htmlonly</td</tr>\endhtmlonly"

View File

@ -1,8 +1,11 @@
""" """
JSON parser @brief JSON parser
Provides methods for parsing the JSON data interchange format.
""" """
def loads(s): def loads(s):
'''@brief Parse @p s as a JSON string.'''
let i = 0 let i = 0
let value # okay dumb scoping thing, but we'll assign this to _value later... let value # okay dumb scoping thing, but we'll assign this to _value later...
def peek(): def peek():

View File

@ -368,6 +368,22 @@ static KrkValue _property_doc(int argc, KrkValue argv[], int hasKw) {
return NONE_VAL(); return NONE_VAL();
} }
static KrkValue _property_name(int argc, KrkValue argv[], int hasKw) {
if (argc != 1 || !IS_PROPERTY(argv[0])) return krk_runtimeError(vm.exceptions->typeError, "?");
KrkValue method = AS_PROPERTY(argv[0])->method;
if (IS_NATIVE(method) && AS_NATIVE(method)->name) {
return OBJECT_VAL(krk_copyString(AS_NATIVE(method)->name, strlen(AS_NATIVE(method)->name)));
} else if (IS_CLOSURE(method)) {
return OBJECT_VAL(AS_CLOSURE(method)->function->name);
}
return NONE_VAL();
}
static KrkValue _property_method(int argc, KrkValue argv[], int hasKw) {
if (argc != 1 || !IS_PROPERTY(argv[0])) return krk_runtimeError(vm.exceptions->typeError, "?");
return AS_PROPERTY(argv[0])->method;
}
_noexport _noexport
void _createAndBind_builtins(void) { void _createAndBind_builtins(void) {
vm.baseClasses->objectClass = krk_newClass(S("object"), NULL); vm.baseClasses->objectClass = krk_newClass(S("object"), NULL);
@ -402,6 +418,8 @@ void _createAndBind_builtins(void) {
krk_makeClass(vm.builtins, &vm.baseClasses->propertyClass, "Property", vm.baseClasses->objectClass); krk_makeClass(vm.builtins, &vm.baseClasses->propertyClass, "Property", vm.baseClasses->objectClass);
krk_defineNative(&vm.baseClasses->propertyClass->methods, ".__repr__", _property_repr); krk_defineNative(&vm.baseClasses->propertyClass->methods, ".__repr__", _property_repr);
krk_defineNative(&vm.baseClasses->propertyClass->methods, ":__doc__", _property_doc); krk_defineNative(&vm.baseClasses->propertyClass->methods, ":__doc__", _property_doc);
krk_defineNative(&vm.baseClasses->propertyClass->methods, ":__name__", _property_name);
krk_defineNative(&vm.baseClasses->propertyClass->methods, ":__method__", _property_method);
krk_finalizeClass(vm.baseClasses->propertyClass); krk_finalizeClass(vm.baseClasses->propertyClass);
krk_makeClass(vm.builtins, &Helper, "Helper", vm.baseClasses->objectClass); krk_makeClass(vm.builtins, &Helper, "Helper", vm.baseClasses->objectClass);

View File

@ -206,7 +206,12 @@ KRK_FUNC(dis,{
krk_runtimeError(vm.exceptions->typeError, "Can not disassemble built-in method of '%s'", krk_typeName(AS_BOUND_METHOD(argv[0])->receiver)); krk_runtimeError(vm.exceptions->typeError, "Can not disassemble built-in method of '%s'", krk_typeName(AS_BOUND_METHOD(argv[0])->receiver));
} }
} else if (IS_CLASS(argv[0])) { } else if (IS_CLASS(argv[0])) {
krk_runtimeError(vm.exceptions->typeError, "todo: class disassembly"); KrkValue code;
if (krk_tableGet(&AS_CLASS(argv[0])->fields, OBJECT_VAL(S("__func__")), &code) && IS_CLOSURE(code)) {
KrkFunction * func = AS_CLOSURE(code)->function;
krk_disassembleCodeObject(stdout, func, AS_CLASS(argv[0])->name->chars);
}
/* TODO Methods! */
} else { } else {
krk_runtimeError(vm.exceptions->typeError, "Don't know how to disassemble '%s'", krk_typeName(argv[0])); krk_runtimeError(vm.exceptions->typeError, "Don't know how to disassemble '%s'", krk_typeName(argv[0]));
} }
@ -221,6 +226,9 @@ void _createAndBind_disMod(void) {
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("dis")); krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("dis"));
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL()); krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
krk_attachNamedObject(&module->fields, "__doc__", krk_attachNamedObject(&module->fields, "__doc__",
(KrkObj*)S("Provides tools for disassembling bytecode.")); (KrkObj*)S("@brief Provides tools for disassembling bytecode."));
BIND_FUNC(module, dis); BIND_FUNC(module, dis)->doc = "@brief Disassemble an object.\n"
"@arguments obj\n\n"
"Dumps a disassembly of the bytecode in the code object associated with @p obj. "
"If @p obj can not be disassembled, a @ref TypeError is raised.";
} }

View File

@ -483,29 +483,45 @@ void _createAndBind_fileioMod(void) {
krk_attachNamedObject(&vm.modules, "fileio", (KrkObj*)module); krk_attachNamedObject(&vm.modules, "fileio", (KrkObj*)module);
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("fileio")); krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("fileio"));
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL()); krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
krk_attachNamedObject(&module->fields, "__doc__", krk_attachNamedObject(&module->fields, "__doc__", (KrkObj*)S(
(KrkObj*)S("Provides access to C <stdio> buffered file I/O functions.")); "@brief Provides access to C <stdio> buffered file I/O functions.\n\n"
"The @c fileio module provides classes and functions for reading "
"and writing files using the system's buffer I/O interfaces, as "
"well as classes for listing the contents of directories."
));
/* Define a class to represent files. (Should this be a helper method?) */ /* Define a class to represent files. (Should this be a helper method?) */
krk_makeClass(module, &File, "File", vm.baseClasses->objectClass); krk_makeClass(module, &File, "File", vm.baseClasses->objectClass);
File->docstring = S(
"Interface to a buffered file stream."
);
File->allocSize = sizeof(struct File); File->allocSize = sizeof(struct File);
File->_ongcsweep = _file_sweep; File->_ongcsweep = _file_sweep;
/* Add methods to it... */ /* Add methods to it... */
BIND_METHOD(File,read); BIND_METHOD(File,read)->doc = "@brief Read from the stream.\n"
BIND_METHOD(File,readline); "@arguments bytes=-1\n\n"
BIND_METHOD(File,readlines); "Reads up to @p bytes bytes from the stream. If @p bytes is @c -1 then reading "
BIND_METHOD(File,write); "will continue until the system returns _end of file_.";
BIND_METHOD(File,close); BIND_METHOD(File,readline)->doc = "@brief Read one line from the stream.";
BIND_METHOD(File,flush); BIND_METHOD(File,readlines)->doc = "@brief Read the entire stream and return a list of lines.";
BIND_METHOD(File,write)->doc = "@brief Write to the stream.\n"
"@arguments data\n\n"
"Writes the contents of @p data to the stream.";
BIND_METHOD(File,close)->doc = "@brief Close the stream and flush any remaining buffered writes.";
BIND_METHOD(File,flush)->doc = "@brief Flush unbuffered writes to the stream.";
BIND_METHOD(File,__str__); BIND_METHOD(File,__str__);
BIND_METHOD(File,__init__); BIND_METHOD(File,__init__)->doc = "@bsnote{%File objects can not be initialized using this constructor. "
"Use the <a class=\"el\" href=\"#open\">open()</a> function instead.}";
BIND_METHOD(File,__enter__); BIND_METHOD(File,__enter__);
BIND_METHOD(File,__exit__); BIND_METHOD(File,__exit__);
krk_defineNative(&File->methods, ".__repr__", FUNC_NAME(File,__str__)); krk_defineNative(&File->methods, ".__repr__", FUNC_NAME(File,__str__));
krk_finalizeClass(File); krk_finalizeClass(File);
krk_makeClass(module, &BinaryFile, "BinaryFile", File); krk_makeClass(module, &BinaryFile, "BinaryFile", File);
BinaryFile->docstring = S(
"Equivalent to @ref File but using @ref bytes instead of string @ref str."
);
BIND_METHOD(BinaryFile,read); BIND_METHOD(BinaryFile,read);
BIND_METHOD(BinaryFile,readline); BIND_METHOD(BinaryFile,readline);
BIND_METHOD(BinaryFile,readlines); BIND_METHOD(BinaryFile,readlines);
@ -513,14 +529,18 @@ void _createAndBind_fileioMod(void) {
krk_finalizeClass(BinaryFile); krk_finalizeClass(BinaryFile);
krk_makeClass(module, &Directory, "Directory", vm.baseClasses->objectClass); krk_makeClass(module, &Directory, "Directory", vm.baseClasses->objectClass);
Directory->docstring = S(
"Represents an opened file system directory."
);
Directory->allocSize = sizeof(struct Directory); Directory->allocSize = sizeof(struct Directory);
Directory->_ongcsweep = _dir_sweep; Directory->_ongcsweep = _dir_sweep;
BIND_METHOD(Directory,__repr__); BIND_METHOD(Directory,__repr__);
BIND_METHOD(Directory,__iter__); BIND_METHOD(Directory,__iter__)->doc = "@brief Iterates over the contents of the directory.\n\n"
BIND_METHOD(Directory,__call__); "Each iteration returns @ref dict with two entries: <i>\"name\"</i> and <i>\"inode\"</i>.";
BIND_METHOD(Directory,__call__)->doc = "@brief Yields one iteration through the directory.";
BIND_METHOD(Directory,__enter__); BIND_METHOD(Directory,__enter__);
BIND_METHOD(Directory,__exit__); BIND_METHOD(Directory,__exit__)->doc = "@brief Closes the directory upon exit from a @c with block.";
BIND_METHOD(Directory,close); BIND_METHOD(Directory,close)->doc = "@brief Close the directory.\n\nFurther reads can not be made after the directory has been closed.";
krk_finalizeClass(Directory); krk_finalizeClass(Directory);
/* Make an instance for stdout, stderr, and stdin */ /* Make an instance for stdout, stderr, and stdin */
@ -529,6 +549,13 @@ void _createAndBind_fileioMod(void) {
makeFileInstance(module, "stderr", stderr); makeFileInstance(module, "stderr", stderr);
/* Our base will be the open method */ /* Our base will be the open method */
BIND_FUNC(module,open); BIND_FUNC(module,open)->doc = "@brief Open a file.\n"
BIND_FUNC(module,opendir); "@arguments path,mode=\"r\"\n\n"
"Opens @p path using the modestring @p mode. Supported modestring characters depend on the system implementation. "
"If the last character of @p mode is @c 'b' a @ref BinaryFile will be returned. If the file could not be opened, "
"an @ref IOError will be raised.";
BIND_FUNC(module,opendir)->doc = "@brief Open a directory for scanning.\n"
"@arguments path\n\n"
"Opens the directory at @p path and returns a @ref Directory object. If @p path could not be opened or is not "
"a directory, @ref IOError will be raised.";
} }

View File

@ -338,10 +338,15 @@ void _createAndBind_gcMod(void) {
krk_attachNamedObject(&vm.modules, "gc", (KrkObj*)gcModule); krk_attachNamedObject(&vm.modules, "gc", (KrkObj*)gcModule);
krk_attachNamedObject(&gcModule->fields, "__name__", (KrkObj*)S("gc")); krk_attachNamedObject(&gcModule->fields, "__name__", (KrkObj*)S("gc"));
krk_attachNamedValue(&gcModule->fields, "__file__", NONE_VAL()); krk_attachNamedValue(&gcModule->fields, "__file__", NONE_VAL());
krk_defineNative(&gcModule->fields, "collect", krk_collectGarbage_wrapper);
krk_defineNative(&gcModule->fields, "generations", krk_generations);
krk_defineNative(&gcModule->fields, "pause", _gc_pause);
krk_defineNative(&gcModule->fields, "resume", _gc_resume);
krk_attachNamedObject(&gcModule->fields, "__doc__", krk_attachNamedObject(&gcModule->fields, "__doc__",
(KrkObj*)S("Namespace containing methods for controlling the garbge collector.")); (KrkObj*)S("@brief Namespace containing methods for controlling the garbge collector."));
krk_defineNative(&gcModule->fields, "collect", krk_collectGarbage_wrapper)->doc =
"@brief Triggers one cycle of garbage collection.";
krk_defineNative(&gcModule->fields, "generations", krk_generations)->doc =
"@brief Returns a 4-tuple of the counts of objects in each stage of garbage collection.";
krk_defineNative(&gcModule->fields, "pause", _gc_pause)->doc =
"@brief Disables automatic garbage collection until @ref resume is called.";
krk_defineNative(&gcModule->fields, "resume", _gc_resume)->doc =
"@brief Re-enable automatic garbage collection after it was stopped by @ref pause ";
} }

View File

@ -158,55 +158,89 @@ KrkValue krk_module_onload_math(void) {
krk_attachNamedObject(&module->fields, "__doc__",(KrkObj*) krk_attachNamedObject(&module->fields, "__doc__",(KrkObj*)
S("Provides access to floating-point mathematical functions from the system `libm`.")); S("Provides access to floating-point mathematical functions from the system `libm`."));
bind(ceil)->doc = "Returns the smallest integer value not less than the input."; bind(ceil)->doc = "Returns the smallest integer value not less than the input.\n"
bind(floor)->doc = "Returns the largest integer value not greater than the input."; "@arguments x";
bind(floor)->doc = "Returns the largest integer value not greater than the input.\n"
"@arguments x";
#ifdef _math_trunc #ifdef _math_trunc
bind(trunc)->doc = "Rounds the input towards zero to an integer."; bind(trunc)->doc = "Rounds the input towards zero to an integer.\n"
"@arguments x";
#endif #endif
bind(exp)->doc = "Returns the base-e exponentiation of the input."; bind(exp)->doc = "Returns the base-e exponentiation of the input.\n"
"@arguments x";
#ifdef _math_expm1 #ifdef _math_expm1
bind(expm1)->doc = "Equivalent to `exp(x) - 1`."; bind(expm1)->doc = "Equivalent to `exp(x) - 1`.\n"
"@arguments x";
#endif #endif
bind(log2)->doc = "Calculates the base-2 logarithm of the input."; bind(log2)->doc = "Calculates the base-2 logarithm of the input.\n"
bind(log10)->doc = "Calculates the base-10 logarithm of the input."; "@arguments x";
bind(sqrt)->doc = "Calculates the square root of the input."; bind(log10)->doc = "Calculates the base-10 logarithm of the input.\n"
bind(acos)->doc = "Calculates the arc-cosine of the radian input."; "@arguments x";
bind(asin)->doc = "Calculates the arc-sine of the radian input."; bind(sqrt)->doc = "Calculates the square root of the input.\n"
bind(atan)->doc = "Calculates the arc-tangent of the radian input."; "@arguments x";
bind(cos)->doc = "Calculates the cosine of the radian input."; bind(acos)->doc = "Calculates the arc-cosine of the radian input.\n"
bind(sin)->doc = "Calculates the sine of the radian input."; "@arguments x";
bind(tan)->doc = "Calculates the tangent of the radian input."; bind(asin)->doc = "Calculates the arc-sine of the radian input.\n"
"@arguments x";
bind(atan)->doc = "Calculates the arc-tangent of the radian input.\n"
"@arguments x";
bind(cos)->doc = "Calculates the cosine of the radian input.\n"
"@arguments x";
bind(sin)->doc = "Calculates the sine of the radian input.\n"
"@arguments x";
bind(tan)->doc = "Calculates the tangent of the radian input.\n"
"@arguments x";
#ifdef _math_acosh #ifdef _math_acosh
bind(acosh)->doc = "Calculates the inverse hyperbolic cosine of the input."; bind(acosh)->doc = "Calculates the inverse hyperbolic cosine of the input.\n"
bind(asinh)->doc = "Calculates the inverse hyperbolic sine of the input."; "@arguments x";
bind(atanh)->doc = "Calculates the inverse hyperbolic tangent of the input."; bind(asinh)->doc = "Calculates the inverse hyperbolic sine of the input.\n"
"@arguments x";
bind(atanh)->doc = "Calculates the inverse hyperbolic tangent of the input.\n"
"@arguments x";
#endif #endif
bind(cosh)->doc = "Calculates the hyperbolic cosine of the input."; bind(cosh)->doc = "Calculates the hyperbolic cosine of the input.\n"
bind(sinh)->doc = "Calculates the hyperbolic sine of the input."; "@arguments x";
bind(tanh)->doc = "Calculates the hyperbolic tangent of the input."; bind(sinh)->doc = "Calculates the hyperbolic sine of the input.\n"
"@arguments x";
bind(tanh)->doc = "Calculates the hyperbolic tangent of the input.\n"
"@arguments x";
#ifdef _math_erf #ifdef _math_erf
bind(erf)->doc = "Calculates the error function of the input."; bind(erf)->doc = "Calculates the error function of the input.\n"
bind(erfc)->doc = "Calculates the complementary error function of the input."; "@arguments x";
bind(erfc)->doc = "Calculates the complementary error function of the input.\n"
"@arguments x";
#endif #endif
#ifdef _math_gamma #ifdef _math_gamma
bind(gamma)->doc = "Calculates the gamma of the input."; bind(gamma)->doc = "Calculates the gamma of the input.\n"
bind(lgamma)->doc = "Calculates the log gamma of the input."; "@arguments x";
bind(lgamma)->doc = "Calculates the log gamma of the input.\n"
"@arguments x";
#endif #endif
#ifdef _math_copysign #ifdef _math_copysign
bind(copysign)->doc = "Copies the sign from one value to another."; bind(copysign)->doc = "Copies the sign from @p x to @p y\n"
"@arguments x,y";
#endif #endif
bind(fmod)->doc = "Returns the floating point remainder of the first input over the second."; bind(fmod)->doc = "Returns the floating point remainder of @p x over @p y\n"
"@arguments x,y";
#ifdef _math_remainder #ifdef _math_remainder
bind(remainder)->doc = "Somehow different from `fmod`."; bind(remainder)->doc = "Somehow different from `fmod`.";
#endif #endif
bind(log1p)->doc = "Equivalent to `log(x) + 1`"; bind(log1p)->doc = "Equivalent to `log(x) + 1`\n"
bind(pow)->doc = "Calculates `x^p`"; "@arguments x";
bind(atan2)->doc = "Calculates the arctangent of `x` and `y`"; bind(pow)->doc = "Calculates `x^p`\n"
bind(frexp)->doc = "Converts a floating point input to a fractional and integer component pair, returned as a tuple."; "@arguments x,p";
bind(atan2)->doc = "Calculates the arctangent of `x` and `y`\n"
"@arguments x,y";
bind(frexp)->doc = "Converts a floating point input to a fractional and integer component pair, returned as a tuple.\n"
"@arguments x\n"
"@returns @ref tuple of two @ref int";
#ifdef isfinite #ifdef isfinite
bind(isfinite)->doc = "Determines if the input is finite."; bind(isfinite)->doc = "Determines if the input is finite.\n"
bind(isinf)->doc = "Determines if the input is infinite."; "@arguments x\n";
bind(isnan)->doc = "Determines if the input is the floating point `NaN`."; bind(isinf)->doc = "Determines if the input is infinite.\n"
"@arguments x\n";
bind(isnan)->doc = "Determines if the input is the floating point `NaN`.\n"
"@arguments x\n";
#endif #endif
/** /**

145
src/os.c
View File

@ -355,7 +355,11 @@ KRK_FUNC(sync,{
KRK_FUNC(kill,{ KRK_FUNC(kill,{
FUNCTION_TAKES_EXACTLY(2); FUNCTION_TAKES_EXACTLY(2);
return INTEGER_VAL(kill(AS_INTEGER(argv[0]), AS_INTEGER(argv[1]))); int result = kill(AS_INTEGER(argv[0]), AS_INTEGER(argv[1]));
if (result == -1) {
return krk_runtimeError(OSError, strerror(errno));
}
return INTEGER_VAL(result);
}) })
KRK_FUNC(fork,{ KRK_FUNC(fork,{
@ -454,7 +458,7 @@ KRK_FUNC(execle,{
}) })
KRK_FUNC(execv,{ KRK_FUNC(execv,{
FUNCTION_TAKES_AT_LEAST(1); FUNCTION_TAKES_EXACTLY(2);
CHECK_ARG(0,str,KrkString*,filename); CHECK_ARG(0,str,KrkString*,filename);
CHECK_ARG(1,list,KrkList*,args); CHECK_ARG(1,list,KrkList*,args);
char ** argp; char ** argp;
@ -467,7 +471,7 @@ KRK_FUNC(execv,{
}) })
KRK_FUNC(execvp,{ KRK_FUNC(execvp,{
FUNCTION_TAKES_AT_LEAST(1); FUNCTION_TAKES_EXACTLY(2);
CHECK_ARG(0,str,KrkString*,path); CHECK_ARG(0,str,KrkString*,path);
CHECK_ARG(1,list,KrkList*,args); CHECK_ARG(1,list,KrkList*,args);
char ** argp; char ** argp;
@ -486,7 +490,7 @@ void _createAndBind_osMod(void) {
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("os")); krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("os"));
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL()); krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
krk_attachNamedObject(&module->fields, "__doc__", krk_attachNamedObject(&module->fields, "__doc__",
(KrkObj*)S("Provides access to low-level system operations.")); (KrkObj*)S("@brief Provides access to low-level system operations."));
#ifdef _WIN32 #ifdef _WIN32
krk_attachNamedObject(&module->fields, "name", (KrkObj*)S("nt")); krk_attachNamedObject(&module->fields, "name", (KrkObj*)S("nt"));
@ -546,51 +550,120 @@ void _createAndBind_osMod(void) {
#endif #endif
krk_makeClass(module, &OSError, "OSError", vm.exceptions->baseException); krk_makeClass(module, &OSError, "OSError", vm.exceptions->baseException);
OSError->docstring = S(
"Raised when system functions return a failure code. @p Exception.arg will provide a textual description of the error."
);
krk_finalizeClass(OSError); krk_finalizeClass(OSError);
BIND_FUNC(module,uname); BIND_FUNC(module,uname)->doc = "@brief Returns a @ref dict of attributes describing the current platform.\n\n"
BIND_FUNC(module,system); "On POSIX platforms, the result should match the contents and layout of a standard @c uname() call. "
BIND_FUNC(module,getcwd); "On Windows, values are synthesized from available information.";
BIND_FUNC(module,chdir); BIND_FUNC(module,system)->doc = "@brief Call the system shell.\n"
BIND_FUNC(module,getpid); "@arguments cmd\n\n"
BIND_FUNC(module,strerror); "Runs @p cmd using the system shell and returns the platform-dependent return value.";
BIND_FUNC(module,abort); BIND_FUNC(module,getcwd)->doc = "@brief Get the name of the current working directory.";
BIND_FUNC(module,remove); BIND_FUNC(module,chdir)->doc = "@brief Change the current working directory.\n"
BIND_FUNC(module,truncate); "@arguments newcwd\n\n"
BIND_FUNC(module,dup); "Attempts to change the working directory to @p newcwd. Raises @ref OSError on failure.";
BIND_FUNC(module,dup2); BIND_FUNC(module,getpid)->doc = "@brief Obtain the system process identifier.";
BIND_FUNC(module,isatty); BIND_FUNC(module,strerror)->doc = "@brief Convert an integer error code to a string.\n"
BIND_FUNC(module,lseek); "@arguments errorno\n\n"
BIND_FUNC(module,open); "Provides the string description for the error code specified by @p errorno.";
BIND_FUNC(module,close); BIND_FUNC(module,abort)->doc = "@brief Abort the current process.\n\n"
BIND_FUNC(module,read); "@bsnote{This will exit the interpreter without calling cleanup routines.}";
BIND_FUNC(module,write); BIND_FUNC(module,remove)->doc = "@brief Delete a file.\n"
"@arguments path\n\n"
"Attempts to delete the file at @p path.";
BIND_FUNC(module,truncate)->doc = "@brief Resize a file.\n"
"@arguments path,length\n\n"
"Attempts to resize the file at @p path to @p length bytes.";
BIND_FUNC(module,dup)->doc = "@brief Duplicate a file descriptor.\n"
"@arguments fd\n\n"
"Returns a new file descriptor pointing to the same file as @p fd.";
BIND_FUNC(module,dup2)->doc = "@brief Duplicate a file descriptor.\n"
"@arguments oldfd,newfd\n\n"
"Like @ref dup but the new file descriptor is placed at @p newfd.\n";
BIND_FUNC(module,isatty)->doc = "@brief Determine if a file descriptor is a terminal.\n"
"@arguments fd\n\n"
"Returns a @ref bool indicating whether the open file descriptor @p fd refers to a terminal.";
BIND_FUNC(module,lseek)->doc = "@brief Seek an open file descriptor.\n"
"@arguments fd,pos,how\n\n"
"Seeks the open file descriptor @p fd by @p pos bytes as specified in @p how. "
"Use the values @c SEEK_SET, @c SEEK_CUR, and @c SEEK_END for @p how.";
BIND_FUNC(module,open)->doc = "@brief Open a file.\n"
"@arguments path,flags,mode=0o777\n\n"
"Opens the file at @p path with the specified @p flags and @p mode. Returns a file descriptor.\n\n"
"@bsnote{Not to be confused with <a class=\"el\" href=\"mod_fileio.html#open\">fileio.open</a>}";
BIND_FUNC(module,close)->doc = "@brief Close an open file descriptor.\n"
"@arguments fd";
BIND_FUNC(module,read)->doc = "@brief Read from an open file descriptor.\n"
"@arguments fd,n\n\n"
"Reads at most @p n bytes from the open file descriptor @p fd.";
BIND_FUNC(module,write)->doc = "@brief Write to an open file descriptor.\n"
"@arguments fd,data\n\n"
"Writes the @ref bytes object @p data to the open file descriptor @p fd.";
BIND_FUNC(module,execl); BIND_FUNC(module,execl)->doc = "@brief Replace the current process.\n"
BIND_FUNC(module,execle); "@arguments path,[args...]\n\n"
BIND_FUNC(module,execlp); "The @c exec* family of functions replaces the calling process's image with a new one. "
BIND_FUNC(module,execv); "@c execl takes a @p path to a binary and an arbitrary number of @ref str arguments to "
BIND_FUNC(module,execvp); "pass to the new executable.";
BIND_FUNC(module,execle)->doc = "@brief Replace the current process.\n"
"@arguments path,[args...],env\n\n"
"The @c exec* family of functions replaces the calling process's image with a new one. "
"@c execle takes a @p path to a binary, an arbitrary number of @ref str arguments to "
"pass to the new executable, and @ref list of @c 'KEY=VALUE' pairs to set as the new "
"environment.";
BIND_FUNC(module,execlp)->doc = "@brief Replace the current process.\n"
"@arguments filename,[args...]\n\n"
"The @c exec* family of functions replaces the calling process's image with a new one. "
"@c execlp takes a @p filename of a binary and an arbitrary number of @ref str arguments to "
"pass to the new executable. @p filename will be searched for in @c $PATH.";
BIND_FUNC(module,execv)->doc = "@brief Replace the current process.\n"
"@arguments path,args\n\n"
"The @c exec* family of functions replaces the calling process's image with a new one. "
"@c execv takes a @p path to a binary and a @ref list @p args of @ref str arguments to "
"pass to the new executable.";
BIND_FUNC(module,execvp)->doc = "@brief Replace the current process.\n"
"@arguments filename,args\n\n"
"The @c exec* family of functions replaces the calling process's image with a new one. "
"@c execvp takes a @p filename of a binary and a @ref list @p args of @ref str arguments to "
"pass to the new executable. @p filename will be searched for in @c $PATH.";
DO_INT(F_OK); DO_INT(F_OK);
DO_INT(R_OK); DO_INT(R_OK);
DO_INT(W_OK); DO_INT(W_OK);
DO_INT(X_OK); DO_INT(X_OK);
BIND_FUNC(module,access); BIND_FUNC(module,access)->doc = "@brief Determine if a file can be accessed.\n"
"@arguments path,mask\n\n"
"Use the values @c F_OK, @c R_OK, @c W_OK, and @c X_OK to construct @p mask and check if the current "
"process has sufficient access rights to perform the requested operations on the file "
"at @p path.";
#ifndef _WIN32 #ifndef _WIN32
BIND_FUNC(module,pipe); BIND_FUNC(module,pipe)->doc = "@brief Create a pipe.\n\n"
BIND_FUNC(module,kill); "Creates a _pipe_, returning a two-tuple of file descriptors for the read and write ends respectively.";
BIND_FUNC(module,fork); BIND_FUNC(module,kill)->doc = "@brief Send a signal to a process.\n"
BIND_FUNC(module,symlink); "@arguments pid,signum\n\n"
BIND_FUNC(module,sync); "Send the signal @p signum to the process at @p pid.\n";
BIND_FUNC(module,fork)->doc = "@brief Fork the current process.\n\n"
"Returns the PID of the new child process in the original process and @c 0 in the child.";
BIND_FUNC(module,symlink)->doc = "@brief Create a symbolic link.\n"
"@arguments src,dst\n\n"
"Creates a symbolic link at @p src pointing to @p dst.";
BIND_FUNC(module,sync)->doc = "@brief Commit filesystem caches to disk.";
BIND_FUNC(module,tcgetpgrp); BIND_FUNC(module,tcgetpgrp)->doc = "@brief Get the terminal foreground process group.\n"
BIND_FUNC(module,tcsetpgrp); "@arguments fd\n\n"
BIND_FUNC(module,ttyname); "Return the PID representing the foreground process group of the terminal specified by the file descriptor @p fd.";
BIND_FUNC(module,tcsetpgrp)->doc = "@brief %Set the terminal foreground process group.\n"
"@arguments fd,pgrp\n\n"
"%Set the PID representing the foreground process group of the terminal specified by the file descriptor @p fd to @p pgrp.";
BIND_FUNC(module,ttyname)->doc = "@brief Get the path to a terminal device.\n"
"@arguments fd\n\n"
"Returns a @ref str representing the path to the terminal device provided by the file descriptor @p fd.";
#endif #endif
_loadEnviron(module); _loadEnviron(module);
} }

View File

@ -39,8 +39,14 @@ void _createAndBind_timeMod(void) {
krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("time")); krk_attachNamedObject(&module->fields, "__name__", (KrkObj*)S("time"));
krk_attachNamedValue(&module->fields, "__file__", NONE_VAL()); krk_attachNamedValue(&module->fields, "__file__", NONE_VAL());
krk_attachNamedObject(&module->fields, "__doc__", krk_attachNamedObject(&module->fields, "__doc__",
(KrkObj*)S("Provides timekeeping functions.")); (KrkObj*)S("@brief Provides timekeeping functions."));
BIND_FUNC(module,sleep); BIND_FUNC(module,sleep)->doc = "@brief Pause execution of the current thread.\n"
BIND_FUNC(module,time); "@arguments secs\n\n"
"Uses the system @c usleep() function to sleep for @p secs seconds, which may be a @ref float or @ref int. "
"The available precision is platform-dependent.";
BIND_FUNC(module,time)->doc = "@brief Return the elapsed seconds since the system epoch.\n\n"
"Returns a @ref float representation of the number of seconds since the platform's epoch date. "
"On POSIX platforms, this is the number of seconds since 1 January 1970. "
"The precision of the return value is platform-dependent.";
} }

View File

@ -87,10 +87,12 @@ let modules = [
let docString = {} let docString = {}
def fixup(mod): def fixup(mod):
'''Escapes some characters in module names to make better page IDs.'''
if mod.startswith('__'): return '\\' + mod if mod.startswith('__'): return '\\' + mod
return mod return mod
def truncateString(s): def truncateString(s):
'''If @p s is longer than 100 characters, truncate it with an ellipsis.'''
s = s.strip() s = s.strip()
if '\n' in s: if '\n' in s:
s = s.split('\n')[0] s = s.split('\n')[0]
@ -101,14 +103,15 @@ def truncateString(s):
return short return short
def fixupDoc(doc): def fixupDoc(doc):
'''Cleans up docstring contents for display in the module list.'''
for line in doc.split('\n'): for line in doc.split('\n'):
if line.strip().startswith('@brief '): if line.strip().startswith('@brief '):
doc = line.strip().replace('@brief ', '', 1).strip() doc = line.strip().replace('@brief ', '', 1).strip()
realPrint('derp:',doc)
break break
return doc.replace(',','\\,').replace('<','&lt;').replace('>','&gt;') return doc.replace(',','\\,').replace('<','&lt;').replace('>','&gt;')
def isExceptionType(cls): def isExceptionType(cls):
'''Determines if @p cls is an @c Exception type by examining its superclass chain.'''
if cls == Exception: return True if cls == Exception: return True
let checked = [] let checked = []
while '__base__' in dir(cls) and cls.__base__ not in checked: while '__base__' in dir(cls) and cls.__base__ not in checked:
@ -118,6 +121,7 @@ def isExceptionType(cls):
return False return False
def getArgs(func): def getArgs(func):
'''Extract the arguments of either a managed (@c func.__args__) or native (from an `@arguments` docstring) function.'''
if func.__file__ == '<builtin>': if func.__file__ == '<builtin>':
if '__doc__' in dir(func) and func.__doc__ and '@arguments ' in func.__doc__: if '__doc__' in dir(func) and func.__doc__ and '@arguments ' in func.__doc__:
let before, after = func.__doc__.split('@arguments ',1) let before, after = func.__doc__.split('@arguments ',1)
@ -127,6 +131,7 @@ def getArgs(func):
return '\\,'.join([x for x in func.__args__ if x != 'self']) return '\\,'.join([x for x in func.__args__ if x != 'self'])
def functionDoc(func): def functionDoc(func):
'''Extracts the docstring from a function and removes markup that Doxygen will choke on.'''
let doc = func.__doc__ if ('__doc__' in dir(func) and func.__doc__) else '' let doc = func.__doc__ if ('__doc__' in dir(func) and func.__doc__) else ''
if '@arguments ' in doc: if '@arguments ' in doc:
doc = '\n'.join([x for x in doc.split('\n') if '@arguments' not in x]) doc = '\n'.join([x for x in doc.split('\n') if '@arguments' not in x])
@ -152,13 +157,13 @@ def processModules(modules):
else: else:
docString[modulepath] = 'TODO' docString[modulepath] = 'TODO'
def outputFunction(name, func, prefix=None): def outputFunction(name, func, prefix=None, paren=True):
# Build the function signature # Build the function signature
let _args = getArgs(func) let _args = getArgs(func)
let args = ('<i>' + _args + '</i>') if _args else '' let args = ('<i>' + _args + '</i>') if _args else ''
let body = functionDoc(func) let body = functionDoc(func)
let maybePrefix = prefix + '.' if prefix else '' let maybePrefix = prefix + '.' if prefix else ''
let formatted = maybePrefix + '<b>' + name + '</b>(' + args + ')' let formatted = maybePrefix + '<b>' + name + '</b>' + (f'({args})' if paren else args)
let maybeDetail = '' let maybeDetail = ''
if prefix and name in specialMethods: if prefix and name in specialMethods:
maybeDetail = ',' + formatted maybeDetail = ',' + formatted
@ -183,6 +188,7 @@ def processModules(modules):
print('<p>' + cls.__doc__ + '</p>') print('<p>' + cls.__doc__ + '</p>')
let seen = [] let seen = []
let methods = [] let methods = []
let properties = []
for member in dir(cls): for member in dir(cls):
if member in blacklistedMethods: continue if member in blacklistedMethods: continue
realPrint(cls,member) realPrint(cls,member)
@ -195,10 +201,17 @@ def processModules(modules):
if isinstance(obj, function) and member not in seen: if isinstance(obj, function) and member not in seen:
seen.append(member) seen.append(member)
methods.append(Pair(member,obj)) methods.append(Pair(member,obj))
else if isinstance(obj, Property) and member not in seen:
seen.append(member)
properties.append(Pair(member,obj.__method__))
if methods: if methods:
methods.sort() methods.sort()
for methodName, method in methods: for methodName, method in methods:
outputFunction(methodName, method, prefix=name) outputFunction(methodName, method, prefix=name)
if properties:
properties.sort()
for propName, method in properties:
outputFunction(propName, method, prefix=name, paren=False)
print('\\methodend') print('\\methodend')
def dumpModule(name, thing): def dumpModule(name, thing):