From: Brendan Hansen Date: Wed, 26 Aug 2020 17:42:20 +0000 (-0500) Subject: started working on a auto-documentation output X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=c5c4004067226f14860162af9b4940864c146d00;p=onyx.git started working on a auto-documentation output --- diff --git a/Makefile b/Makefile index fa739dda..50247792 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ OBJ_FILES=\ build/onyxmsgs.o \ build/onyxutils.o \ build/onyxwasm.o \ + build/onyxdoc.o \ build/onyx.o CC=gcc diff --git a/core/builtin.onyx b/core/builtin.onyx index 08522136..e0854492 100644 --- a/core/builtin.onyx +++ b/core/builtin.onyx @@ -34,5 +34,5 @@ free :: proc (use a: Allocator, ptr: rawptr) { context : struct { allocator : Allocator; - temp_allocator : Allocator; + temp_allocator : Allocator; } \ No newline at end of file diff --git a/core/random.onyx b/core/random.onyx index d23b7f87..ab515814 100644 --- a/core/random.onyx +++ b/core/random.onyx @@ -4,9 +4,9 @@ package random seed := 8675309 random_seed :: proc (s: u32) do seed = s; -random :: proc -> u32 { - seed = seed * 5831 + 102847; - return seed; +random :: proc (s := ^seed) -> u32 { + *s = *s * 5831 + 102847; + return *s; } random_between :: proc (lo: i32, hi: i32) -> i32 do return random() % (hi + 1 - lo) + lo; \ No newline at end of file diff --git a/core/string.onyx b/core/string.onyx index 401978a2..f768239d 100644 --- a/core/string.onyx +++ b/core/string.onyx @@ -46,6 +46,9 @@ string_concat :: proc (a: Allocator, s1: string, s2: string) -> string { string_free :: proc (a: Allocator, s: string) do free(a, s.data); +// This is an example doc string +// You can have as many comments as you want +// It documents the string_split function string_split :: proc (a: Allocator, str: string, delim: u8) -> []string { delim_count := 0; for i: 0, str.count do if str.data[i] == delim do delim_count += 1; diff --git a/core/wasi.onyx b/core/wasi.onyx index 027dbf6e..5ca3d597 100644 --- a/core/wasi.onyx +++ b/core/wasi.onyx @@ -1,7 +1,7 @@ package wasi use package main as main -use package builtin { string } +use package builtin use package memory Size :: #type u32; @@ -465,6 +465,9 @@ sock_shutdown :: proc #export "_start" { memory_init(); + context.allocator = heap_allocator; + context.temp_allocator = heap_allocator; + argc : Size; argv_buf_size : Size; diff --git a/docs/api_design b/docs/api_design new file mode 100644 index 00000000..d11d4f74 --- /dev/null +++ b/docs/api_design @@ -0,0 +1,33 @@ + The Onyx Standard Library +--------------------------------------------------------------------------- + +Through Onyx has only one compilation target, WebAssembly 32-bit, there are +fundamentally two different use cases: in a browser, or with WASI. Both of +these use cases are to be treated as equally important. To accommodate for +their very different runtimes, a common standard library must be established +that they can share the functionality. + +The standard high level topics to cover are: + - standard output + - allocation + - standard math functions + - strings + - files + - utility functions + * random + * clock + + + + + + + + +Package main: + main :: proc (args: [] cstring) -> i32 + +Package string: + string_split :: proc (a: Allocator, s: string, delim: u8) -> [] string + at /usr/share/onyx/core/string.onyx:50,0 + Auto documentation for string_split diff --git a/docs/plan b/docs/plan index 7407f897..1a21eaf2 100644 --- a/docs/plan +++ b/docs/plan @@ -216,6 +216,8 @@ HOW: [X] default parameters - Must be the last parameters + [X] Basic documentation outputter + [ ] #file and #line directives - string and u32 respectively that represent the current file and line number where the directive is @@ -228,6 +230,9 @@ HOW: - struct member names - array length + [ ] Clean up error messages + - Stop using Msg_Type_Literal everywhere and be more specific + [ ] 'use' enums and packages at an arbitrary scope [ ] convert to using an 'atom' like table diff --git a/include/onyxdoc.h b/include/onyxdoc.h new file mode 100644 index 00000000..b3b3ba73 --- /dev/null +++ b/include/onyxdoc.h @@ -0,0 +1,29 @@ +#ifndef ONYXDOC_H +#define ONYXDOC_H + +#include "bh.h" +#include "onyxastnodes.h" + +typedef struct DocEntry { + OnyxFilePos pos; + char* def; + char* additional; +} DocEntry; + +typedef struct DocPackage { + const char* name; + + bh_arr(DocEntry) public_entries; + bh_arr(DocEntry) private_entries; +} DocPackage; + +typedef struct OnyxDocumentation { + bh_arena doc_arena; + + bh_arr(DocPackage) package_docs; +} OnyxDocumentation; + +OnyxDocumentation onyx_docs_generate(ProgramInfo* prog); +void onyx_docs_write(OnyxDocumentation* doc); + +#endif \ No newline at end of file diff --git a/onyx b/onyx index bccaf50a..e9ba9510 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/wasi_test.onyx b/progs/wasi_test.onyx index 1110f0d7..567d3434 100644 --- a/progs/wasi_test.onyx +++ b/progs/wasi_test.onyx @@ -18,8 +18,9 @@ use package core use package memory use package wasi use package intrinsics +use package random -print_u64_with_base :: proc (n_: u64, base := 10l) { +print_u64 :: proc (n_: u64, base := 10l) { n := n_; str: [256] u8; for i: 0, 256 do str[i] = #char "\0"; @@ -77,7 +78,7 @@ print_u8 :: proc (s: cstring) -> u32 { print :: proc #overloaded { print_string, print_u8 } print_rights :: proc (rights: Rights) { - print_u64_with_base(cast(u64) rights, 2l); + print_u64(cast(u64) rights, 2l); print("\n"); if rights & Rights.DataSync != cast(Rights) 0 do print("DataSync\n"); @@ -134,10 +135,10 @@ readdir :: proc (fd: FileDescriptor) { print("\n"); print("\td_namlen: "); - print_u64_with_base(cast(u64) dirent.d_namlen, 16l); + print_u64(cast(u64) dirent.d_namlen, 16l); print("\n"); print("\td_type: "); - print_u64_with_base(cast(u64) dirent.d_type, 16l); + print_u64(cast(u64) dirent.d_type, 16l); print("\n"); bufused -= sizeof DirEnt + dirent.d_namlen; @@ -208,6 +209,11 @@ make_i32_arr :: proc (a := heap_allocator, len := 10) -> [] i32 { } main :: proc (args: []cstring) { + now : Timestamp; + clock_time_get(ClockID.Realtime, cast(Timestamp) 1, ^now); + + random_seed(cast(u32) now); + sb := string_builder_make(heap_allocator, 256); timer := timer_start(); @@ -233,12 +239,12 @@ main :: proc (args: []cstring) { if err := path_open(3, LookupFlags.SymLinkFollow, string_make(args.data[1]), cast(OFlags) 0, Rights.DataSync | Rights.Write | Rights.Read | Rights.Tell | Rights.Seek | Rights.Advise | Rights.PathOpen | Rights.PathCreateFile, Rights.DataSync | Rights.Write | Rights.Read | Rights.Tell | Rights.Seek | Rights.Advise | Rights.PathOpen | Rights.PathCreateFile, FDFlags.Sync, ^fd); err != Errno.Success { print("Failed to open file\n"); print("Error code: "); - print_u64_with_base(cast(u64) err, 16l); + print_u64(cast(u64) err, 16l); proc_exit(1); } defer fd_close(fd); - print_u64_with_base(cast(u64) fd, 16l); + print_u64(cast(u64) fd, 16l); print("\n"); filelen : Filesize; @@ -247,13 +253,13 @@ main :: proc (args: []cstring) { proc_exit(1); } print("the size is: "); - print_u64_with_base(cast(u64) filelen); + print_u64(cast(u64) filelen); print("\n"); sum := 0l; for i: 0, 20000 do if is_prime(i) do sum += cast(u64) i; print("Sum of primes less than 20000 is: "); - print_u64_with_base(sum); + print_u64(sum); print("\n"); matches := string_split(heap_allocator, "This is a test string to test splitting. It surprisingly works very well.", #char " "); @@ -282,7 +288,7 @@ main :: proc (args: []cstring) { case #default { print("Unexpected token: "); - print_u64_with_base(cast(u64) tokens.data[i].data[0], 16l); + print_u64(cast(u64) tokens.data[i].data[0], 16l); print("\n"); // This breaks out of the for loop @@ -342,14 +348,14 @@ main :: proc (args: []cstring) { foobar(10, 1230); sl := make_i32_arr(); - print_u64_with_base(cast(u64) sl.count); + print_u64(cast(u64) sl.count); } foobar :: proc (a: i32, b := 1, c := 5l) { - print_u64_with_base(cast(u64) a); + print_u64(cast(u64) a); print("\n"); - print_u64_with_base(cast(u64) b, 16l); + print_u64(cast(u64) b, 16l); print("\n"); - print_u64_with_base(c); + print_u64(c); print("\n"); } \ No newline at end of file diff --git a/src/onyx.c b/src/onyx.c index 62a8cc7e..3234249c 100644 --- a/src/onyx.c +++ b/src/onyx.c @@ -8,6 +8,7 @@ #include "onyxsempass.h" #include "onyxutils.h" #include "onyxwasm.h" +#include "onyxdoc.h" #define VERSION "0.1" @@ -16,7 +17,8 @@ static const char* docstring = "Onyx compiler version " VERSION "\n" "The compiler for the Onyx programming language.\n" "\n" "Usage:\n" - "\tonyx [-o ] [-ast] [-verbose] \n" + "\tonyx [-o ] [-verbose] \n" + "\tonyx doc \n" "\tonyx -help\n" "\nFlags:\n" "\t-o Specify the target file (default: out.wasm)\n" @@ -26,7 +28,7 @@ static const char* docstring = "Onyx compiler version " VERSION "\n" typedef enum CompileAction { ONYX_COMPILE_ACTION_COMPILE, - ONYX_COMPILE_ACTION_CHECK_ERRORS, + ONYX_COMPILE_ACTION_DOCUMENT, ONYX_COMPILE_ACTION_PRINT_HELP, } CompileAction; @@ -35,7 +37,6 @@ typedef struct OnyxCompileOptions { CompileAction action; u32 verbose_output : 1; - u32 print_ast : 1; bh_arr(const char *) included_folders; bh_arr(const char *) files; @@ -48,7 +49,6 @@ static OnyxCompileOptions compile_opts_parse(bh_allocator alloc, int argc, char .action = ONYX_COMPILE_ACTION_PRINT_HELP, .verbose_output = 0, - .print_ast = 0, .files = NULL, .target_file = "out.wasm", @@ -61,26 +61,26 @@ static OnyxCompileOptions compile_opts_parse(bh_allocator alloc, int argc, char bh_arr_push(options.included_folders, "."); fori(i, 1, argc) { - if (!strcmp(argv[i], "-help")) { + if (!strcmp(argv[i], "doc") && i == 1) { + options.action = ONYX_COMPILE_ACTION_DOCUMENT; + } + else if (!strcmp(argv[i], "-help")) { options.action = ONYX_COMPILE_ACTION_PRINT_HELP; break; } else if (!strcmp(argv[i], "-o")) { - options.action = ONYX_COMPILE_ACTION_COMPILE; options.target_file = argv[++i]; } - else if (!strcmp(argv[i], "-ast")) { - options.print_ast = 1; - } else if (!strcmp(argv[i], "-verbose")) { options.verbose_output = 1; } else if (!strcmp(argv[i], "-I")) { - options.action = ONYX_COMPILE_ACTION_COMPILE; bh_arr_push(options.included_folders, argv[++i]); } else { - options.action = ONYX_COMPILE_ACTION_COMPILE; + if (options.action == ONYX_COMPILE_ACTION_PRINT_HELP) + options.action = ONYX_COMPILE_ACTION_COMPILE; + bh_arr_push(options.files, argv[i]); } } @@ -381,6 +381,12 @@ static i32 onyx_compile(CompilerState* compiler_state) { return ONYX_COMPILER_PROGRESS_FAILED_SEMPASS; } + if (compiler_state->options->action == ONYX_COMPILE_ACTION_DOCUMENT) { + OnyxDocumentation docs = onyx_docs_generate(&compiler_state->prog_info); + onyx_docs_write(&docs); + + return ONYX_COMPILER_PROGRESS_SUCCESS; + } // NOTE: Generate WASM instructions if (compiler_state->options->verbose_output) @@ -430,6 +436,7 @@ int main(int argc, char *argv[]) { return 1; case ONYX_COMPILE_ACTION_COMPILE: + case ONYX_COMPILE_ACTION_DOCUMENT: compiler_progress = onyx_compile(&compile_state); break; diff --git a/src/onyxdoc.c b/src/onyxdoc.c new file mode 100644 index 00000000..918f6e8c --- /dev/null +++ b/src/onyxdoc.c @@ -0,0 +1,216 @@ +#include "onyxdoc.h" +#include "onyxutils.h" +#include "onyxtypes.h" + +static i32 cmp_doc_entry(const void * a, const void * b) { + DocEntry* d1 = (DocEntry *) a; + DocEntry* d2 = (DocEntry *) b; + + return strncmp(d1->def, d2->def, 1024); +} + +static i32 cmp_doc_package(const void * a, const void * b) { + DocPackage* d1 = (DocPackage *) a; + DocPackage* d2 = (DocPackage *) b; + + return strncmp(d1->name, d2->name, 1024); +} + +static char* node_to_doc_def(const char* sym, AstNode *node, bh_allocator a) { + static char buf[1024]; + memset(buf, 0, 1023); + + strncat(buf, sym, 1023); + strncat(buf, " :: ", 1023); + + switch (node->kind) { + case Ast_Kind_Function: { + strncat(buf, "proc (", 1023); + + AstFunction *func = (AstFunction *) node; + bh_arr_each(AstParam, param, func->params) { + if (param != func->params) + strncat(buf, ", ", 1023); + + token_toggle_end(param->local->token); + strncat(buf, param->local->token->text, 1023); + token_toggle_end(param->local->token); + + strncat(buf, ": ", 1023); + + strncat(buf, type_get_name(param->local->type), 1023); + + if (param->default_value != NULL) { + strncat(buf, " = ", 1023); + } + } + + strncat(buf, ")", 1023); + + if (func->type->Function.return_type != &basic_types[Basic_Kind_Void]) { + strncat(buf, " -> ", 1023); + strncat(buf, type_get_name(func->type->Function.return_type), 1023); + } + + break; + } + + case Ast_Kind_Struct_Type: { + strncat(buf, "struct { ", 1023); + + AstStructType* st = (AstStructType *) node; + bh_arr_each(AstStructMember *, smem, st->members) { + + token_toggle_end((*smem)->token); + strncat(buf, (*smem)->token->text, 1023); + token_toggle_end((*smem)->token); + + strncat(buf, ": ", 1023); + + strncat(buf, type_get_name((*smem)->type), 1023); + + strncat(buf, "; ", 1023); + } + + strncat(buf, "}", 1023); + break; + } + + case Ast_Kind_Basic_Type: + case Ast_Kind_Array_Type: + case Ast_Kind_Type_Alias: + case Ast_Kind_Slice_Type: { + strncat(buf, type_get_name(type_build_from_ast(global_heap_allocator, (AstType *) node)), 1023); + break; + } + + default: { + strncat(buf, "", 1023); + } + } + + return bh_strdup(a, buf); +} + +static DocPackage doc_package_create(Package* p, bh_allocator a) { + DocPackage dp; + dp.name = p->name; + dp.public_entries = NULL; + dp.private_entries = NULL; + + bh_arr_new(global_heap_allocator, dp.public_entries, 16); + bh_arr_new(global_heap_allocator, dp.private_entries, 16); + + bh_table_each_start(AstNode *, p->scope->symbols) + DocEntry de; + de.pos = value->token->pos; + de.def = node_to_doc_def(key, value, a); + de.additional = NULL; + + bh_arr_push(dp.public_entries, de); + bh_table_each_end; + + bh_table_each_start(AstNode *, p->private_scope->symbols) + DocEntry de; + de.pos = value->token->pos; + de.def = node_to_doc_def(key, value, a); + de.additional = NULL; + + bh_arr_push(dp.private_entries, de); + bh_table_each_end; + + qsort(dp.public_entries, bh_arr_length(dp.public_entries), sizeof(DocEntry), cmp_doc_entry); + qsort(dp.private_entries, bh_arr_length(dp.private_entries), sizeof(DocEntry), cmp_doc_entry); + + return dp; +} + +OnyxDocumentation onyx_docs_generate(ProgramInfo* prog) { + OnyxDocumentation doc; + + bh_arena_init(&doc.doc_arena, global_heap_allocator, 16 * 1024); + bh_allocator a = bh_arena_allocator(&doc.doc_arena); + + doc.package_docs = NULL; + bh_arr_new(global_heap_allocator, doc.package_docs, 16); + + bh_table_each_start(Package *, prog->packages); + DocPackage dp = doc_package_create(value, a); + bh_arr_push(doc.package_docs, dp); + bh_table_each_end; + + qsort(doc.package_docs, bh_arr_length(doc.package_docs), sizeof(DocPackage), cmp_doc_package); + + return doc; +} + +void onyx_docs_write(OnyxDocumentation* doc) { + // NOTE: Disabling fancy line printing until I can make it better + #if 0 + bh_arr_each(DocPackage, dp, doc->package_docs) { + bh_printf("Package '%s'\n", dp->name); + + if (bh_arr_length(dp->public_entries) > 0) { + bh_printf("\xe2\x94\x9c\xe2\x94\x80 Public symbols\n"); + bh_arr_each(DocEntry, de, dp->public_entries) { + bh_printf("\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80 %s\n", de->def); + + if (de->pos.filename != NULL) + bh_printf("\xe2\x94\x82 \xe2\x94\x82 at %s:%d,%d\n", de->pos.filename, de->pos.line, de->pos.column); + else + bh_printf("\xe2\x94\x82 \xe2\x94\x82 compiler built-in\n"); + + bh_printf("\xe2\x94\x82 \xe2\x94\x82\n"); + } + } + + if (bh_arr_length(dp->private_entries) > 0) { + bh_printf("\xe2\x94\x9c\xe2\x94\x80 Private symbols\n"); + bh_arr_each(DocEntry, de, dp->private_entries) { + bh_printf("\xe2\x94\x82 \xe2\x94\x9c\xe2\x94\x80 %s\n", de->def); + if (de->pos.filename != NULL) + bh_printf("\xe2\x94\x82 \xe2\x94\x82 at %s:%d,%d\n", de->pos.filename, de->pos.line, de->pos.column); + else + bh_printf("\xe2\x94\x82 \xe2\x94\x82 compiler built-in\n"); + + bh_printf("\xe2\x94\x82 \xe2\x94\x82\n"); + } + + bh_printf("\n"); + } + } + #else + bh_arr_each(DocPackage, dp, doc->package_docs) { + bh_printf("Package '%s'\n", dp->name); + + if (bh_arr_length(dp->public_entries) > 0) { + bh_printf(" Public symbols\n"); + bh_arr_each(DocEntry, de, dp->public_entries) { + bh_printf(" %s\n", de->def); + + if (de->pos.filename != NULL) + bh_printf(" at %s:%d,%d\n", de->pos.filename, de->pos.line, de->pos.column); + else + bh_printf(" compiler built-in\n"); + + bh_printf(" \n"); + } + } + + if (bh_arr_length(dp->private_entries) > 0) { + bh_printf(" Private symbols\n"); + bh_arr_each(DocEntry, de, dp->private_entries) { + bh_printf(" %s\n", de->def); + if (de->pos.filename != NULL) + bh_printf(" at %s:%d,%d\n", de->pos.filename, de->pos.line, de->pos.column); + else + bh_printf(" compiler built-in\n"); + + bh_printf(" \n"); + } + + bh_printf("\n"); + } + } + #endif +} diff --git a/src/onyxsymres.c b/src/onyxsymres.c index bb0d3875..9a36b114 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -568,7 +568,7 @@ static void symres_use_package(AstUsePackage* package) { pac_node->package = p; pac_node->token = package->alias; - symbol_introduce(semstate.curr_package->scope, package->alias, (AstNode *) pac_node); + symbol_introduce(semstate.curr_package->include_scope, package->alias, (AstNode *) pac_node); } if (package->only != NULL) { @@ -582,7 +582,7 @@ static void symres_use_package(AstUsePackage* package) { return; } - symbol_introduce(semstate.curr_package->scope, (*alias)->alias, thing); + symbol_introduce(semstate.curr_package->include_scope, (*alias)->alias, thing); } }