From d5d3d721e72eb718107823cbab73bcd1ce0c90e3 Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Sat, 20 Feb 2021 14:10:36 +0900 Subject: [PATCH] The big documentation system overhaul --- .gitignore | 3 +- Doxyfile | 30 ---- Makefile | 7 + docs/Doxyfile | 39 +++++ docs/DoxygenLayout.xml | 233 +++++++++++++++++++++++++ docs/doxy.css | 355 +++++++++++++++++++++++++++++++++++++++ docs/doxygen_footer.html | 7 + docs/doxygen_header.html | 67 ++++++++ docs/embedding.md | 19 +++ docs/index.md | 3 + docs/tabs-override.css | 354 ++++++++++++++++++++++++++++++++++++++ modules/collections.krk | 11 ++ src/builtins.c | 2 +- src/module_math.c | 71 ++++---- src/vm.c | 23 ++- tools/__init__.krk | 1 + tools/gendoc.krk | 263 +++++++++++++++++++++++++++++ 17 files changed, 1418 insertions(+), 70 deletions(-) delete mode 100644 Doxyfile create mode 100644 docs/Doxyfile create mode 100644 docs/DoxygenLayout.xml create mode 100644 docs/doxy.css create mode 100644 docs/doxygen_footer.html create mode 100644 docs/doxygen_header.html create mode 100644 docs/embedding.md create mode 100644 docs/index.md create mode 100644 docs/tabs-override.css create mode 100644 tools/__init__.krk create mode 100755 tools/gendoc.krk diff --git a/.gitignore b/.gitignore index e09e811..8e42347 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,8 @@ /wasm/ /jupyter/ # Doxygen output -/html/ +/docs/html/ +/docs/mod*.md # Match library files anywhere. *.o *.so diff --git a/Doxyfile b/Doxyfile deleted file mode 100644 index 7a5dcb0..0000000 --- a/Doxyfile +++ /dev/null @@ -1,30 +0,0 @@ -PROJECT_NAME = "Kuroko" -PROJECT_BRIEF = "Bytecode-compiled interpreted programming language." -PROJECT_LOGO = - -# Since we're documenting a C API... -OPTIMIZE_OUTPUT_FOR_C = YES -LAYOUT_FILE = - -# Make docs for interpreter and tools -INPUT = src/ tools/ - -# Ignore rline, since it's a vendored library from ToaruOS -EXCLUDE = src/rline.c src/rline.h - -# Enable the source browser, even if I don't particular like Doxygen's highlighting -SOURCE_BROWSER = YES -GENERATE_HTML = YES - -HTML_OUTPUT = html -HTML_FILE_EXTENSION = .html -HTML_HEADER = -HTML_FOOTER = -HTML_STYLESHEET = -HTML_EXTRA_STYLESHEET = -HTML_EXTRA_FILES = -HTML_COLORSTYLE_HUE = 0 -HTML_COLORSTYLE_SAT = 200 - -# Doxygen will enable latex by default, so let's turn that off. -GENERATE_LATEX = NO diff --git a/Makefile b/Makefile index 00d313a..ffa5ee4 100644 --- a/Makefile +++ b/Makefile @@ -108,6 +108,7 @@ modules/math.so: src/module_math.c libkuroko.so .PHONY: clean clean: @rm -f ${OBJS} ${TARGET} ${MODULES} libkuroko.so src/*.o kuroko.exe ${TOOLS} $(patsubst %,%.exe,${TOOLS}) + @rm -rf docs/html tags: $(wildcard src/*.c) $(wildcard src/*.h) @ctags --c-kinds=+lx src/*.c src/*.h @@ -175,3 +176,9 @@ deb: kuroko libkuroko.so --iteration 0 \ --directories $(libdir)/kuroko rm -r $(DESTDIR) + +.PHONY: docs + +docs: kuroko + ./kuroko tools/gendoc.krk + doxygen docs/Doxyfile diff --git a/docs/Doxyfile b/docs/Doxyfile new file mode 100644 index 0000000..6b644d2 --- /dev/null +++ b/docs/Doxyfile @@ -0,0 +1,39 @@ +PROJECT_NAME = "Kuroko" +PROJECT_BRIEF = "Bytecode-compiled interpreted programming language." +PROJECT_LOGO = + +# Since we're documenting a C API... +OPTIMIZE_OUTPUT_FOR_C = YES +LAYOUT_FILE = docs/DoxygenLayout.xml + +# Make docs for interpreter and tools +INPUT = src/ tools/ docs/ +FILE_PATTERNS = *.c *.h *.md + +# Ignore rline, since it's a vendored library from ToaruOS +EXCLUDE = src/rline.c src/rline.h + +# Enable the source browser, even if I don't particular like Doxygen's highlighting +SOURCE_BROWSER = YES +GENERATE_HTML = YES + +HTML_OUTPUT = docs/html +HTML_FILE_EXTENSION = .html +HTML_HEADER = docs/doxygen_header.html +HTML_FOOTER = docs/doxygen_footer.html +HTML_EXTRA_FILES = docs/doxy.css docs/tabs-override.css +HTML_COLORSTYLE_HUE = 0 +HTML_COLORSTYLE_SAT = 200 + +# Doxygen will enable latex by default, so let's turn that off. +GENERATE_LATEX = NO + +ALIASES += methodstart{4}="\htmlonly<\3 class=\"memtitle \4\" id=\"\1\">_\2
\endhtmlonly" +ALIASES += methodend="\htmlonly
\endhtmlonly" +ALIASES += bsnote{1}="\htmlonly
\endhtmlonly\1\htmlonly
\endhtmlonly" + +ALIASES += modulelist{1}="\htmlonly
\endhtmlonly\1\htmlonly
\endhtmlonly" +ALIASES += krkmodule{2}="\htmlonly M\endhtmlonly@ref \1\htmlonly\endhtmlonly\2\htmlonly\endhtmlonly" + +# These are just really crazy +COLLABORATION_GRAPH = NO diff --git a/docs/DoxygenLayout.xml b/docs/DoxygenLayout.xml new file mode 100644 index 0000000..300f24e --- /dev/null +++ b/docs/DoxygenLayout.xml @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/doxy.css b/docs/doxy.css new file mode 100644 index 0000000..02a79e4 --- /dev/null +++ b/docs/doxy.css @@ -0,0 +1,355 @@ +#main-nav { + height: 40px; + background-color: rgb(33, 37, 41); /* Main bootstrap nav background color */ + border-radius: 5px; + color: #fff; + display: flex; +} +#main-nav li { + list-style: none; + font-size: 14px; +} +#main-menu { + align-items: center; + border-radius: 5px; + height: 100%; + display: flex; + flex-direction: row; + width: 100%; +} +#main-menu>li:last-child { + margin-left: auto; +} +#main-menu div#MSearchBox { + display: flex; + margin-top: 0; + height: 19px; +} +#MSearchBox>span { + top: auto !important; +} +#MSearchBox>span.left { + border-radius: 5px 0px 0px 5px; + background-color: #fff; + background-image: none; +} +#MSearchBox>span>input { + background-image: none; + background-color: #fff; +} +#MSearchBox>span.right { + top: auto; + border-radius: 0px 5px 5px 0px; + background-color: #fff; + background-image: none; +} +.header { + margin-top: 1em; +} +.header a { text-decoration: none; } +.header a:hover { text-decoration: underline; } +.header>.summary { + float: right; + font-size: small; +} +.header>.headertitle { + font-size: 25px; + font-weight: bold; +} +.contents { + margin-bottom: 2rem; +} +.contents a { text-decoration: none; } +.contents a:hover { text-decoration: underline; } +.contents h1 { + font-size: 32px; + font-weight: bold; + margin-top: 1rem; +} +.contents h2 { + font-size: 26px; +} +.contents a { + scroll-margin-top: 4rem; +} +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} +h2.groupheader { + margin-top: 1.75em; +} +.contents .center { + text-align: center; +} +.legend { +} + +h3.classDef, h3.letDef { + font-size: 22px; +} +h3.classDef>em, h3.letDef>em { + font-size: 18px; +} +h3.classDef>b, h3.letDef>b { + font-family: "Monaco", "Menlo", "Ubuntu Mono", "Consolas", "source-code-pro", monospace; +} + +table.memberdecls { + border-spacing: 0px; + padding: 0; +} + +.memItemLeft { white-space: nowrap; } +.memItemRight { width: 100%; } +.mdescLeft, .mdescRight, .memItemLeft, .memItemRight, .memTemplItemLeft, .memTemplItemRight, .memTemplParams { + margin: 4px; + background-color: #fef7f7; + border: none; + padding: 1px 0 0 8px; +} + +.memSeparator { + border-bottom: 1px solid #f9d5d5; + line-height: 1px; + margin: 0; + padding: 0; +} +a.el { + font-weight: bold; + color: rgb(179,21,21); +} + +h2.memtitle, h3.memtitle, h4.memtitle { + padding: .5rem 1rem; + margin-bottom: 0; + background-color: rgba(0,0,0,.03); + border: 1px solid rgba(0,0,0,.125); + border-radius: 5px 5px 0px 0px; + font-family: "Monaco", "Menlo", "Ubuntu Mono", "Consolas", "source-code-pro", monospace; + font-size: 24px; + scroll-margin-top: 4rem; +} +.memtitle.classDef { + background-color: #cfe2ff; +} +.memtitle.exceptionDef { + background-color: #f8d7da; +} +h4.memtitle { + font-size: 22px; +} +div.memitem { + border-radius: 0px 0px 5px 5px; + border: 1px solid rgba(0,0,0,.125); + border-top: none; + padding: 0; + margin-bottom: 0.5rem; +} +div.memproto { + background-color: rgba(0,0,0,.015); + border-bottom: 1px solid rgba(0,0,0,.125); + padding: 0.5rem; + font-size: 17px; + font-family: "Monaco", "Menlo", "Ubuntu Mono", "Consolas", "source-code-pro", monospace; + line-height: 19px; +} +div.memdoc { + padding: 0.5rem 0.5rem 0 0.5rem; +} +.params .paramname { + font-weight: bold; +} +.paramname { + color: #602020; + white-space: nowrap; +} +.params dd { + margin-left: 2rem; +} +.permalink>a { + visibility: hidden; + font-size: 0; +} +.permalink>a::before { + visibility: visible; + font-size: 24px; + content: "#"; + margin-right: 0.25rem; + color: rgb(10,10,10,0.25); +} +.permalink>a:hover::before { + color: rgb(10,10,10,1); +} +.permalink>a:hover { text-decoration: none; } +.contents > hr { + display: none; +} + +.icona { + width: 24px; + height: 22px; + display: inline-block; +} + +.icon { + background-color: #dc3545; + font-weight: bold; + color: #fff; + font-size: 12px; + width: 18px; + border-radius: 4px; + display: inline-block; + text-align: center; +} + +.directory tr:nth-child(odd) { + background-color: rgba(0,0,0,.03); +} +.directory td.desc { + width: 100%; + border-left: 1px solid rgba(0,0,0,0.05); + padding-left: 1rem; +} +.directory td.entry { + white-space: nowrap; + padding-right: 6px; + padding-top: 3px; +} +.arrow { + user-select: none; + cursor: pointer; + font-size: 80%; + display: inline-block; + width: 16px; + height: 22px; +} + +.levels { + white-space: nowrap; + text-align: right; + font-size: 9pt; +} +.levels>span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: #B31515; +} +.qindex { + text-align: center; + color: #fff; + display: none; +} +.qindex>a { +} +.classindex { + width: 100%; +} +.classindex .ah { + display: inline-block; + width: 25px; + height: 25px; + border-radius: 4px; + background-color: rgb(0,0,0,0.05); + color: #602020; + font-weight: bold; +} +.fragment>.line { + font-size: 17px; + font-family: "Monaco", "Menlo", "Ubuntu Mono", "Consolas", "source-code-pro", monospace; + line-height: 19px; + white-space: pre-wrap; +} +.fragment { + margin: 1rem; + background-color: #1f1f1f; + padding: 0.5rem; + border-radius: 5px; + color: #e6e6e6; +} +.fragment a { + color: inherit; + text-decoration: underline; + text-decoration-style: dotted; +} +.fragment>.line { + margin: 0; + padding: 0; + line-height: normal; +} +.fragment>.line span.keyword { color: #33a2e6; } +.fragment>.line span.keywordflow { color: #33a2e6; } +.fragment>.line span.stringliteral { color: #48b048; } +.fragment>.line span.comment { color: #9e9981; font-style: oblique; } +.fragment>.line span.numeric { color: #e62b7f; } +.fragment>.line span.charliteral { color: #e62b7f; } +.fragment>.line span.escape { color: #71cbad; } +.fragment>.line span.keywordtype { color: #e6ce6e; } +.fragment>.line span.preprocessor { color: #e62b7f; } +.fragment>.line>.lineno { + color: #e6ce6e; background-color: #1f1f1f; + border-right: 1px solid rgb(255,255,255,0.5); + padding-right: 0.5rem; +} +.fragment>.line>.lineno a { + text-decoration: none; +} +.ttc { + position: absolute; + display: none; +} +#powerTip { + cursor: default; + white-space: nowrap; + background-color: white; + border: 1px solid #d8d8d8; + border-radius: calc(.3rem - 1px); + box-shadow: 1px 1px 7px black; + display: none; + font-size: smaller; + max-width: 80%; + background-color: rgba(255,255,255,0.9); + padding: 0; + position: absolute; + z-index: 2147483647; +} +#powerTip>.ttname { + background-color: #f0f0f0; + padding: 0.5rem 1rem; + border-bottom: 1px solid #d8d8d8; +} +#powerTip>.ttname a { + text-decoration: none; + color: inherit; +} +#powerTip>.ttdeci { + padding: 0.5rem 1rem; + background-color: #fff; + font-family: "Monaco", "Menlo", "Ubuntu Mono", "Consolas", "source-code-pro", monospace; +} +#powerTip>.ttdoc { + padding: 0.5rem 1rem; + background-color: #fff; +} +#powerTip>.ttdef { + padding: 0.5rem 1rem; + border-top: 1px solid #d8d8d8; + background-color: #f0f0f0; +} +#nav-path ul { + display: flex; + flex-direction: row; +} +#nav-path ul li { + list-style: none; + display: inline-block; + margin: 0.25rem; + margin-left: auto; + margin-right: auto; +} +#nav-path ul li + li::before { + padding-right: 0.5rem; + color: rgb(0,0,0,0.6); + content: '/'; +} diff --git a/docs/doxygen_footer.html b/docs/doxygen_footer.html new file mode 100644 index 0000000..6e98461 --- /dev/null +++ b/docs/doxygen_footer.html @@ -0,0 +1,7 @@ + + + + diff --git a/docs/doxygen_header.html b/docs/doxygen_header.html new file mode 100644 index 0000000..6a65648 --- /dev/null +++ b/docs/doxygen_header.html @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + Docs | Kuroko + + + + $treeview + $search + $mathjax + + + + + +
+
diff --git a/docs/embedding.md b/docs/embedding.md new file mode 100644 index 0000000..0525c03 --- /dev/null +++ b/docs/embedding.md @@ -0,0 +1,19 @@ +## Kuroko C API Documentation {#embedding} +### Getting Started {#getting-started} + + +```c +#include +#include +#include + +int main(int argc, char *argv[]) { + krk_initVM(0); + krk_startModule("__main__"); + krk_interpret("import kuroko\nprint('Kuroko',kuroko.version)\n", 1, "",""); + krk_freeVM(); + return 0; +} +``` + + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..4b43d60 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,3 @@ +# Kuroko Language Reference {#mainpage} + +Hello, world. diff --git a/docs/tabs-override.css b/docs/tabs-override.css new file mode 100644 index 0000000..e02d132 --- /dev/null +++ b/docs/tabs-override.css @@ -0,0 +1,354 @@ +.sm { + position:relative; +} +.sm, +.sm ul, +.sm li { + display:block; + list-style:none; + line-height:normal; + -webkit-tap-highlight-color:rgba(0,0,0,0) +} +.sm>li>h1, +.sm>li>h2, +.sm>li>h3, +.sm>li>h4, +.sm>li>h5, +.sm>li>h6 { + margin:0; + padding:0 +} +.sm ul { + display:none +} +.sm li, +.sm a { + position:relative +} +.sm a { + display:block +} +.sm a.disabled { + cursor:not-allowed +} +.sm:after { + content:"\00a0"; + display:block; + height:0; + font:0px/0 serif; + clear:both; + visibility:hidden; + overflow:hidden +} +.sm, +.sm *, +.sm *:before, +.sm *:after { + -moz-box-sizing:border-box; + -webkit-box-sizing:border-box; + box-sizing:border-box +} +.sm-dox { + +} +.sm-dox a, +.sm-dox a:focus, +.sm-dox a:hover, +.sm-dox a:active { + text-decoration:none; + color: rgba(255,255,255,.55); + outline:none +} +.sm-dox a:hover { + color:#fff; +} +.sm-dox a.current { + color:#D23600 +} +.sm-dox a.disabled { + color:#bbb +} +.sm-dox a span.sub-arrow { + position:absolute; + top:50%; + margin-top:-14px; + left:auto; + right:3px; + width:28px; + height:28px; + overflow:hidden; + font:bold 12px/28px monospace !important; + text-align:center; + background:rgba(255,255,255,0.5); + border-radius:5px +} +.sm-dox a.highlighted span.sub-arrow:before { + display:block; + content:'-' +} +.sm-dox>li:first-child>a, +.sm-dox>li:first-child>:not(ul) a { + border-radius:5px 5px 0 0 +} +.sm-dox>li:last-child>a, +.sm-dox>li:last-child>*:not(ul) a, +.sm-dox>li:last-child>ul, +.sm-dox>li:last-child>ul>li:last-child>a, +.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a, +.sm-dox>li:last-child>ul>li:last-child>ul, +.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a, +.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a, +.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul, +.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a, +.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a, +.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul, +.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a, +.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a, +.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul { + border-radius:0 0 5px 5px +} +.sm-dox>li:last-child>a.highlighted, +.sm-dox>li:last-child>*:not(ul) a.highlighted, +.sm-dox>li:last-child>ul>li:last-child>a.highlighted, +.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a.highlighted, +.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted, +.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted, +.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted, +.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted, +.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted, +.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted { + border-radius:0 +} +.sm-dox ul { + background:rgba(162,162,162,0.1) +} +.sm-dox ul a, +.sm-dox ul a:focus, +.sm-dox ul a:hover, +.sm-dox ul a:active { + font-size:12px; + border-left:8px solid transparent; + line-height:36px; + text-shadow:none; + background-color:white; +} +.sm-dox ul a:hover { + color:#fff; +} +.sm-dox ul ul a, +.sm-dox ul ul a:hover, +.sm-dox ul ul a:focus, +.sm-dox ul ul a:active { + border-left:16px solid transparent +} +.sm-dox ul ul ul a, +.sm-dox ul ul ul a:hover, +.sm-dox ul ul ul a:focus, +.sm-dox ul ul ul a:active { + border-left:24px solid transparent +} +.sm-dox ul ul ul ul a, +.sm-dox ul ul ul ul a:hover, +.sm-dox ul ul ul ul a:focus, +.sm-dox ul ul ul ul a:active { + border-left:32px solid transparent +} +.sm-dox ul ul ul ul ul a, +.sm-dox ul ul ul ul ul a:hover, +.sm-dox ul ul ul ul ul a:focus, +.sm-dox ul ul ul ul ul a:active { + border-left:40px solid transparent +} +@media (min-width: 768px) { + .sm-dox ul { + position:absolute; + width:12em + } + .sm-dox li { + float:left + } + .sm-dox.sm-rtl li { + float:right + } + .sm-dox ul li, + .sm-dox.sm-rtl ul li, + .sm-dox.sm-vertical li { + float:none + } + .sm-dox a { + white-space:nowrap + } + .sm-dox ul a, + .sm-dox.sm-vertical a { + white-space:normal + } + .sm-dox .sm-nowrap>li>a, + .sm-dox .sm-nowrap>li>:not(ul) a { + white-space:nowrap + } + .sm-dox { + padding:0 10px; + line-height:36px + } + .sm-dox a span.sub-arrow { + top:50%; + margin-top:-2px; + right:12px; + width:0; + height:0; + border-width:4px; + border-style:solid dashed dashed dashed; + border-color:rgba(255,255,255,0.5) transparent transparent transparent; + background:transparent; + border-radius:0 + } + .sm-dox a, + .sm-dox a:focus, + .sm-dox a:active, + .sm-dox a:hover, + .sm-dox a.highlighted { + padding:0px 12px; + border-radius:0 !important + } + .sm-dox a:hover { + color:#fff; + } + .sm-dox a:hover span.sub-arrow { + border-color:#fff transparent transparent transparent + } + .sm-dox a.has-submenu { + padding-right:24px + } + .sm-dox li { + border-top:0 + } + .sm-dox>li>ul { + top: 36px !important; + } + .sm-dox>li>ul:before, + .sm-dox>li>ul:after { + content:''; + position:absolute; + top:-18px; + left:30px; + width:0; + height:0; + overflow:hidden; + border-width:9px; + border-style:dashed dashed solid dashed; + border-color:transparent transparent #bbb transparent + } + .sm-dox>li>ul:after { + top:-16px; + left:31px; + border-width:8px; + border-color:transparent transparent #fff transparent + } + .sm-dox ul { + border:1px solid #bbb; + padding:5px 0; + background:#fff; + border-radius:5px !important; + } + .sm-dox ul a span.sub-arrow { + right:8px; + top:50%; + margin-top:-5px; + border-width:5px; + border-color:transparent transparent transparent #555; + border-style:dashed dashed dashed solid + } + .sm-dox ul a, + .sm-dox ul a:hover, + .sm-dox ul a:focus, + .sm-dox ul a:active, + .sm-dox ul a.highlighted { + color:#555; + border:0 !important; + } + .sm-dox ul a:hover { + color: #1e2125; + background-color: #f8f9fa; + } + .sm-dox ul a:hover span.sub-arrow { + border-color:transparent transparent transparent #1e2125 + } + .sm-dox span.scroll-up, + .sm-dox span.scroll-down { + position:absolute; + display:none; + visibility:hidden; + overflow:hidden; + background:#fff; + height:36px + } + .sm-dox span.scroll-up:hover, + .sm-dox span.scroll-down:hover { + background:#eee + } + .sm-dox span.scroll-up:hover span.scroll-up-arrow, + .sm-dox span.scroll-up:hover span.scroll-down-arrow { + border-color:transparent transparent #D23600 transparent + } + .sm-dox span.scroll-down:hover span.scroll-down-arrow { + border-color:#D23600 transparent transparent transparent + } + .sm-dox span.scroll-up-arrow, + .sm-dox span.scroll-down-arrow { + position:absolute; + top:0; + left:50%; + margin-left:-6px; + width:0; + height:0; + overflow:hidden; + border-width:6px; + border-style:dashed dashed solid dashed; + border-color:transparent transparent #555 transparent + } + .sm-dox span.scroll-down-arrow { + top:8px; + border-style:solid dashed dashed dashed; + border-color:#555 transparent transparent transparent + } + .sm-dox.sm-vertical { + padding:10px 0; + border-radius:5px + } + .sm-dox.sm-vertical a { + padding:10px 20px + } + .sm-dox.sm-vertical a:hover, + .sm-dox.sm-vertical a:focus, + .sm-dox.sm-vertical a:active, + .sm-dox.sm-vertical a.highlighted { + background:#fff + } + .sm-dox.sm-vertical a.disabled { + } + .sm-dox.sm-vertical a span.sub-arrow { + right:8px; + top:50%; + margin-top:-5px; + border-width:5px; + border-style:dashed dashed dashed solid; + border-color:transparent transparent transparent #555 + } + .sm-dox.sm-vertical>li>ul:before, + .sm-dox.sm-vertical>li>ul:after { + display:none + } + .sm-dox.sm-vertical ul a { + padding:10px 20px + } + .sm-dox.sm-vertical ul a:hover, + .sm-dox.sm-vertical ul a:focus, + .sm-dox.sm-vertical ul a:active, + .sm-dox.sm-vertical ul a.highlighted { + background:#eee + } + .sm-dox.sm-vertical ul a.disabled { + background:#fff + } +} + diff --git a/modules/collections.krk b/modules/collections.krk index 80012dc..000b8ed 100644 --- a/modules/collections.krk +++ b/modules/collections.krk @@ -1,8 +1,16 @@ +''' +Useful collection types not found in the core interpreter. +''' + class defaultdict(dict): + ''' + Extended mapping type that automatically populates missing keys with values from a factory. + ''' def __init__(self, default_factory=None, *args, **kwargs): super().__init__(*args,**kwargs) self.default_factory = default_factory def __missing__(self, key): + '''Automatically called to create default values when @p key is not found.''' if not self.default_factory: raise KeyError(key) let result = self.default_factory() self.__set__(key, result) @@ -13,6 +21,9 @@ class defaultdict(dict): return super().__get__(key) class deque(): + ''' + Linked list with fast push/pop/enque/deque operations but slow lookup. + ''' def __init__(self, iterable=None, maxlen=None): self._head = None self._tail = None diff --git a/src/builtins.c b/src/builtins.c index b8e0cc7..fe7cc5e 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -358,7 +358,7 @@ void _createAndBind_builtins(void) { krk_defineNative(&vm.baseClasses->moduleClass->methods, ".__repr__", _module_repr); krk_defineNative(&vm.baseClasses->moduleClass->methods, ".__str__", _module_repr); krk_finalizeClass(vm.baseClasses->moduleClass); - vm.baseClasses->moduleClass->docstring = S(""); + vm.baseClasses->moduleClass->docstring = S("Type of imported modules and packages."); vm.builtins = krk_newInstance(vm.baseClasses->moduleClass); krk_attachNamedObject(&vm.modules, "__builtins__", (KrkObj*)vm.builtins); diff --git a/src/module_math.c b/src/module_math.c index 241dadc..62c363a 100644 --- a/src/module_math.c +++ b/src/module_math.c @@ -155,55 +155,58 @@ KrkValue krk_module_onload_math(void) { KrkInstance * module = krk_newInstance(vm.baseClasses->moduleClass); krk_push(OBJECT_VAL(module)); - bind(ceil); - bind(floor); + krk_attachNamedObject(&module->fields, "__doc__",(KrkObj*) + 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(floor)->doc = "Returns the largest integer value not greater than the input."; #ifdef _math_trunc - bind(trunc); + bind(trunc)->doc = "Rounds the input towards zero to an integer."; #endif - bind(exp); + bind(exp)->doc = "Returns the base-e exponentiation of the input."; #ifdef _math_expm1 - bind(expm1); + bind(expm1)->doc = "Equivalent to `exp(x) - 1`."; #endif - bind(log2); - bind(log10); - bind(sqrt); - bind(acos); - bind(asin); - bind(atan); - bind(cos); - bind(sin); - bind(tan); + bind(log2)->doc = "Calculates the base-2 logarithm of the input."; + bind(log10)->doc = "Calculates the base-10 logarithm of the input."; + bind(sqrt)->doc = "Calculates the square root of the input."; + bind(acos)->doc = "Calculates the arc-cosine of the radian input."; + bind(asin)->doc = "Calculates the arc-sine of the radian input."; + bind(atan)->doc = "Calculates the arc-tangent of the radian input."; + bind(cos)->doc = "Calculates the cosine of the radian input."; + bind(sin)->doc = "Calculates the sine of the radian input."; + bind(tan)->doc = "Calculates the tangent of the radian input."; #ifdef _math_acosh - bind(acosh); - bind(asinh); - bind(atanh); + bind(acosh)->doc = "Calculates the inverse hyperbolic cosine of the input."; + bind(asinh)->doc = "Calculates the inverse hyperbolic sine of the input."; + bind(atanh)->doc = "Calculates the inverse hyperbolic tangent of the input."; #endif - bind(cosh); - bind(sinh); - bind(tanh); + bind(cosh)->doc = "Calculates the hyperbolic cosine of the input."; + bind(sinh)->doc = "Calculates the hyperbolic sine of the input."; + bind(tanh)->doc = "Calculates the hyperbolic tangent of the input."; #ifdef _math_erf - bind(erf); - bind(erfc); + bind(erf)->doc = "Calculates the error function of the input."; + bind(erfc)->doc = "Calculates the complementary error function of the input."; #endif #ifdef _math_gamma - bind(gamma); - bind(lgamma); + bind(gamma)->doc = "Calculates the gamma of the input."; + bind(lgamma)->doc = "Calculates the log gamma of the input."; #endif #ifdef _math_copysign - bind(copysign); + bind(copysign)->doc = "Copies the sign from one value to another."; #endif - bind(fmod); + bind(fmod)->doc = "Returns the floating point remainder of the first input over the second."; #ifdef _math_remainder - bind(remainder); + bind(remainder)->doc = "Somehow different from `fmod`."; #endif - bind(log1p); - bind(pow); - bind(atan2); - bind(frexp); + bind(log1p)->doc = "Equivalent to `log(x) + 1`"; + bind(pow)->doc = "Calculates `x^p`"; + bind(atan2)->doc = "Calculates the arctangent of `x` and `y`"; + bind(frexp)->doc = "Converts a floating point input to a fractional and integer component pair, returned as a tuple."; #ifdef isfinite - bind(isfinite); - bind(isinf); - bind(isnan); + bind(isfinite)->doc = "Determines if the input is finite."; + bind(isinf)->doc = "Determines if the input is infinite."; + bind(isnan)->doc = "Determines if the input is the floating point `NaN`."; #endif /** diff --git a/src/vm.c b/src/vm.c index d3e2972..f203fb3 100644 --- a/src/vm.c +++ b/src/vm.c @@ -1220,14 +1220,29 @@ void krk_initVM(int flags) { krk_attachNamedObject(&vm.modules, "kuroko", (KrkObj*)vm.system); krk_attachNamedObject(&vm.system->fields, "__name__", (KrkObj*)S("kuroko")); krk_attachNamedValue(&vm.system->fields, "__file__", NONE_VAL()); /* (built-in) */ + krk_attachNamedObject(&vm.system->fields, "__doc__", (KrkObj*)S("System module.")); krk_attachNamedObject(&vm.system->fields, "version", (KrkObj*)S(KRK_VERSION_MAJOR "." KRK_VERSION_MINOR "." KRK_VERSION_PATCH KRK_VERSION_EXTRA)); krk_attachNamedObject(&vm.system->fields, "buildenv", (KrkObj*)S(KRK_BUILD_COMPILER)); krk_attachNamedObject(&vm.system->fields, "builddate", (KrkObj*)S(KRK_BUILD_DATE)); - krk_defineNative(&vm.system->fields, "getsizeof", krk_getsize); - krk_defineNative(&vm.system->fields, "set_clean_output", krk_setclean); - krk_defineNative(&vm.system->fields, "set_tracing", krk_set_tracing)->doc = "Toggle debugging modes."; - krk_defineNative(&vm.system->fields, "importmodule", krk_import_wrapper)->doc = "Import a module by string name"; + krk_defineNative(&vm.system->fields, "getsizeof", krk_getsize)->doc = "Calculate the approximate size of an object in bytes.\n" + "@arguments value\n\n" + "@param value Value to examine."; + krk_defineNative(&vm.system->fields, "set_clean_output", krk_setclean)->doc = "Disables terminal escapes in some output from the VM.\n" + "@arguments clean=True\n\n" + "@param clean Whether to remove escapes."; + krk_defineNative(&vm.system->fields, "set_tracing", krk_set_tracing)->doc = "Toggle debugging modes.\n" + "@arguments tracing=None,disassembly=None,scantracing=None,stressgc=None\n\n" + "Enables or disables tracing options for the current thread.\n\n" + "@param tracing Enables instruction tracing.\n" + "@param disassembly Prints bytecode disassembly after compilation.\n" + "@param scantracing Prints debug output from the token scanner during compilation.\n" + "@param stressgc Forces a garbage collection cycle on each heap allocation."; + krk_defineNative(&vm.system->fields, "importmodule", krk_import_wrapper)->doc = "Import a module by string name\n" + "@arguments module\n\n" + "Imports the dot-separated module @p module as if it were imported by the @c import statement and returns the resulting module object.\n\n" + "@param module A string with a dot-separated package or module name"; + krk_attachNamedObject(&vm.system->fields, "module", (KrkObj*)vm.baseClasses->moduleClass); krk_attachNamedObject(&vm.system->fields, "path_sep", (KrkObj*)S(PATH_SEP)); KrkValue module_paths = krk_list_of(0,NULL,0); krk_attachNamedValue(&vm.system->fields, "module_paths", module_paths); diff --git a/tools/__init__.krk b/tools/__init__.krk new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tools/__init__.krk @@ -0,0 +1 @@ + diff --git a/tools/gendoc.krk b/tools/gendoc.krk new file mode 100755 index 0000000..76d5564 --- /dev/null +++ b/tools/gendoc.krk @@ -0,0 +1,263 @@ +#!/usr/bin/env kuroko +''' +@brief Tool for dynamically generating documentation files through introspection. + +Imports modules and scans through members to generate Markdown files to feed into +Doxygen. Uses dynamic introspection to obtain member lists and look up function +arguments, docstrings, etc. + +Markdown output is aided by a set of macros defined in the Kuroko API Documentation +Doxyfile. The output should be suitable for use with a normal Doxygen build, but some +additional customization is available. +''' +import fileio +import kuroko +import syntax.highlighter + +let realPrint = print + +let blacklistedMethods = [ + '__func__', + '__repr__', + '__str__', +] + +let specialMethods = { + '__contains__': lambda cls, args: f'{args} in {cls}', + '__init__': lambda cls, args: f'{cls}({args})', + '__get__': lambda cls, args: f'{cls}[{args}]', +} + +class Pair(): + '''Makes a silly sortable pair that can be expanded like a two-tuple.''' + def __init__(left,right): + self.left = left + self.right = right + def __lt__(other): + if self.left == '__init__': return True + return self.left < other.left + def __gt__(other): + if self.left == '__init__': return False + return self.left > other.left + def __iter__(): + let x = -1 + def _(): + x++ + if x == 0: return self.left + elif x == 1: return self.right + else: return _ + return _ + +let modules = [ + # Integrated stuff + '__builtins__', + 'os', + 'kuroko', + 'math', + 'threading', + 'gc', + 'dis', + 'fileio', + 'time', + + # Stuff from modules/ + 'json', + 'collections', + 'string', + + # Other stuff + 'tools.gendoc', +] + +let docString = {} + +def fixup(mod): + if mod.startswith('__'): return '\\' + mod + return mod + +def truncateString(s): + s = s.strip() + if '\n' in s: + s = s.split('\n')[0] + let short = s[:100] + if len(short) < len(s): + return short + '...' + else: + return short + +def fixupDoc(doc): + for line in doc.split('\n'): + if line.strip().startswith('@brief '): + doc = line.strip().replace('@brief ', '', 1).strip() + realPrint('derp:',doc) + break + return doc.replace(',','\\,').replace('<','<').replace('>','>') + +def isExceptionType(cls): + if cls == Exception: return True + let checked = [] + while '__base__' in dir(cls) and cls.__base__ not in checked: + if cls.__base__ == Exception: return True + checked.append(cls.__base__) + cls = cls.__base__ + return False + +def getArgs(func): + if func.__file__ == '': + if '__doc__' in dir(func) and func.__doc__ and '@arguments ' in func.__doc__: + let before, after = func.__doc__.split('@arguments ',1) + let line, rest = after.split('\n',1) if '\n' in after else (after,None) + return line.strip().replace(',','\\,') + return '...' + return '\\,'.join([x for x in func.__args__ if x != 'self']) + +def functionDoc(func): + let doc = func.__doc__ if ('__doc__' in dir(func) and func.__doc__) else '' + if '@arguments ' in doc: + doc = '\n'.join([x for x in doc.split('\n') if '@arguments' not in x]) + return doc + +def processModules(modules): + for modulepath in modules: + # Import the module. + let module = kuroko.importmodule(modulepath) + + let output = fileio.open(f'docs/mod.{modulepath}.md','w') + + realPrint(f"Processing {modulepath}") + + def print(*args): + output.write(' '.join(args)) + output.write('\n') + + print('## ' + fixup(modulepath) + ' {#mod_' + modulepath.replace('.','_') + '}') + if '__doc__' in dir(module) and module.__doc__: + print(module.__doc__.strip()) + docString[modulepath] = truncateString(module.__doc__) + else: + docString[modulepath] = 'TODO' + + def outputFunction(name, func, prefix=None): + # Build the function signature + let args = '' + getArgs(func) + '' + let body = functionDoc(func) + let formatted + let maybePrefix = prefix + '.' if prefix else '' + if prefix and name in specialMethods: + formatted = specialMethods[name](prefix,args) + else: + formatted = maybePrefix + '' + name + '(' + args + ')' + print('\\methodstart{' + maybePrefix + name + ',' + formatted + ',' + ('h4,methodDef' if prefix else 'h3,functionDef') + '}') + if body: print(body) + print('\n\\methodend') + print('') + + def outputConstant(name, val): + print(f'

let {name} = \htmlonly {val!r} \\endhtmlonly

\n') + + def outputOther(name, val): + print(f'

let {name} = {type(val).__name__}

\n') + + def outputClass(name, cls): + let classType = 'exceptionDef' if isExceptionType(cls) else 'classDef' + let superclass = cls.__base__.__name__ if cls.__base__ else '' + let formatted = f'class {name}({superclass})' + print('\\methodstart{' + name + ',' + formatted + ',h3,' + classType + '}') + if '__doc__' in dir(cls) and isinstance(cls.__doc__,str): + print('

' + cls.__doc__ + '

') + let seen = [] + let methods = [] + for member in dir(cls): + if member in blacklistedMethods: continue + realPrint(cls,member) + let obj + try: + obj = getattr(cls,member) + if cls.__base__ and member in dir(cls.__base__) and getattr(cls.__base__,member) == obj: continue + except: + continue + if isinstance(obj, function) and member not in seen: + seen.append(member) + methods.append(Pair(member,obj)) + if methods: + methods.sort() + for methodName, method in methods: + outputFunction(methodName, method, prefix=name) + print('\\methodend') + + def dumpModule(name, thing): + let functions = [] + let classes = [] + let constants = [] + let exceptions = [] + let other = [] + + for member in dir(thing): + if not member.startswith('_'): + let obj = getattr(thing,member) + if isinstance(obj, function): + functions.append(Pair(member,obj)) + else if isinstance(obj, type): + if isExceptionType(obj): + exceptions.append(Pair(member,obj)) + else: + classes.append(Pair(member,obj)) + else if isinstance(obj, (int,str,float,bool,type(None))): + constants.append(Pair(member,obj)) + else if isinstance(obj, kuroko.module): + continue # Skip top-level modules as these are almost definitely imports + else: + other.append(Pair(member,obj)) + + if classes: + print('\n### Classes\n') + classes.sort() + for name, cls in classes: + outputClass(name, cls) + + if functions: + print('\n### Functions\n') + functions.sort() + for name, func in functions: + outputFunction(name, func) + + if exceptions: + print('\n### Exceptions\n') + exceptions.sort() + for name, cls in exceptions: + outputClass(name, cls) + + if constants: + print('\n### Constants\n') + constants.sort() + for name, val in constants: + outputConstant(name,val) + + if other: + print('\n### Other Members\n') + other.sort() + for name, val in other: + outputOther(name, val) + + dumpModule(modulepath,module) + + output.close() + + with fileio.open('docs/modulelist.md','w') as output: + output.write( + '# Module List {#modulelist}\n' + '\n' + 'Here is a list of documented modules:\n' + '\n' + '\\modulelist{\n' + ) + + modules.sort() + + for module in modules: + output.write(' \\krkmodule{mod_' + fixup(module).replace('.','_') + ',' + fixupDoc(docString[module]) + '}\n') + + output.write('}\n') + +if __name__ == '__main__': + processModules(modules)