started working on a auto-documentation output
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 26 Aug 2020 17:42:20 +0000 (12:42 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 26 Aug 2020 17:42:20 +0000 (12:42 -0500)
13 files changed:
Makefile
core/builtin.onyx
core/random.onyx
core/string.onyx
core/wasi.onyx
docs/api_design [new file with mode: 0644]
docs/plan
include/onyxdoc.h [new file with mode: 0644]
onyx
progs/wasi_test.onyx
src/onyx.c
src/onyxdoc.c [new file with mode: 0644]
src/onyxsymres.c

index fa739ddaa69ea581d9d4cc81271c171da1d2230b..5024779245de6187b97cb3a6b616ef7bf245e5a0 100644 (file)
--- 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
index 08522136d93d265a43d34395c518bd8bf4acb94e..e0854492d86b182e638cb8ad98ef9db49c8c9417 100644 (file)
@@ -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
index d23b7f87a0d5ef1196e378676f1bf1cadf329cf0..ab51581439b3624a0b4ead864843fccdc9bc37c3 100644 (file)
@@ -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
index 401978a241cdaf9948f7b8f17a5c78b2c55ecdb1..f768239d14b077359ec8b3e32c078a3c09dbe45b 100644 (file)
@@ -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;
index 027dbf6e03c6271b36da766bca5cb50749ba02b6..5ca3d59743901bc017d63ee14974b2824921dc3a 100644 (file)
@@ -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 (file)
index 0000000..d11d4f7
--- /dev/null
@@ -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
index 7407f8977c91cbc6bc917b556ddf7872c91ef59e..1a21eaf21a02aaa2adfdc9f447b43ace4f84a71a 100644 (file)
--- 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 (file)
index 0000000..b3b3ba7
--- /dev/null
@@ -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 bccaf50ad41258e955097e2d80bab0fd3f89470f..e9ba9510d82409729dad4b5c96d015f22ca6beb5 100755 (executable)
Binary files a/onyx and b/onyx differ
index 1110f0d74562487ca2c5f030a2bcc49dba74bd93..567d3434c320bc7c8b6f19790e061873a1ca057b 100644 (file)
@@ -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
index 62a8cc7e9f5afbc67b6935cb0ec74fff84a75639..3234249cdcd3d4ccffd62b7ff52dacc16cd29323 100644 (file)
@@ -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 <target file>] [-ast] [-verbose] <input files>\n"
+    "\tonyx [-o <target file>] [-verbose] <input files>\n"
+    "\tonyx doc <input files>\n"
     "\tonyx -help\n"
     "\nFlags:\n"
     "\t-o <target_file>        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 (file)
index 0000000..918f6e8
--- /dev/null
@@ -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, " = <default>", 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, "<unimplemented printing>", 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
+}
index bb0d3875f0a094e0463796f191a34fa26b5acabd..9a36b114c73eac3af463b9eacd4c4d4d2a00466e 100644 (file)
@@ -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);
         }
     }