working on package documentation
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 22 Nov 2023 19:00:51 +0000 (13:00 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Wed, 22 Nov 2023 19:00:51 +0000 (13:00 -0600)
14 files changed:
bin/install.sh
compiler/include/astnodes.h
compiler/src/doc.c
compiler/src/parser.c
core/alloc/alloc.onyx
core/alloc/arena.onyx
core/alloc/atomic.onyx
core/alloc/fixed.onyx
core/alloc/gc.onyx
core/alloc/logging.onyx
core/alloc/memdebug.onyx
core/alloc/pool.onyx
core/alloc/ring.onyx
core/doc/doc.onyx

index bca321f9918743f1667d7fcfed791742e4c86ad5..b97b2c6207db7d2d55949313e3dd15143e037ff2 100755 (executable)
@@ -208,7 +208,7 @@ initOS() {
 initRuntime() {
     printf "${green}Please choose a WebAssembly runtime to use with your Onyx installation.\n${reset}"
 
-    echo "1) Wasmer: An industry standard WebAssembly runtime. Very fast."
+    echo "1) Wasmer: An industry standard WebAssembly runtime. Very fast. (default)"
     echo "2) OVM: A custom, lightweight runtime made for Onyx. Supports debugging. Slower than Wasmer."
     echo "3) None: Omit using a runtime and only use Onyx as a compiler to WebAssembly."
 
@@ -218,7 +218,7 @@ initRuntime() {
         1) RUNTIME="wasmer"; break ;; 
         2) RUNTIME="ovm"; break ;; 
         3) RUNTIME="none"; break ;; 
-        *) echo "Invalid choice. Quitting."; exit 1 ;;
+        *) echo "Invalid choice. Defaulting to 'wasmer'."; RUNTIME="wasmer" ;;
     esac
 }
 
index 95ab9110fc13ae2f4533bcdc34dfbb1147dba7c1..24b9bd9ba96d41cc632d6d0a67c6e14b58c8c6b4 100644 (file)
@@ -1735,6 +1735,9 @@ struct Package {
     // 'use package' statements have to be reevaluated to pull in the new symbols.
     bh_arr(Entity *) use_package_entities;
 
+    // NOTE: This tracks all #package_doc statements used for this package.
+    bh_arr(OnyxToken *) doc_strings;
+
     // NOTE: These are entities that are stored in packages marked with `#allow_stale_code`.
     // These entities are flushed to the entity heap when the package has been explicit used
     // somewhere.
index 00150c297a5d65da1db5f5bf530b0c42e4d1daab..0181402693d848649658a3c4add07d11fac3225b 100644 (file)
@@ -391,7 +391,9 @@ static void write_type_node(bh_buffer *buffer, void *vnode) {
             return;
 
         case Ast_Kind_Typeof:
-            bh_buffer_write_string(buffer, "_TYPEOF_");
+            bh_buffer_write_string(buffer, (char *) type_get_name(
+                type_build_from_ast(context.ast_alloc, (AstType *) node)
+            ));
             return;
 
         case Ast_Kind_Alias:
@@ -939,6 +941,12 @@ void onyx_docs_emit_odoc(const char *dest) {
         fori (j, 0, bh_arr_length(p->sub_packages)) {
             bh_buffer_write_u32(&doc_buffer, (u32) p->sub_packages[j] - 1);
         }
+
+        bh_buffer_write_u32(&doc_buffer, bh_arr_length(p->doc_strings));
+        bh_arr_each(OnyxToken *, ptkn, p->doc_strings) {
+            OnyxToken *tkn = *ptkn;
+            write_string(&doc_buffer, tkn->length, tkn->text);
+        }
     }
 
     //
index 123cc07467ddaafc91d02576f717380bb2d98605..a9ef24a8ae0377386a501631f220599fcdd5411b 100644 (file)
@@ -4057,6 +4057,12 @@ void onyx_parse(OnyxParser *parser) {
         bh_arr_push(parser->alternate_entity_placement_stack, &parser->package->buffered_entities);
     }
 
+    while (parse_possible_directive(parser, "package_doc")) {
+        OnyxToken *doc_string = expect_token(parser, Token_Type_Literal_String);
+
+        bh_arr_push(parser->package->doc_strings, doc_string);
+    }
+
     parse_top_level_statements_until(parser, Token_Type_End_Stream);
 
     parser->current_scope = parser->current_scope->parent;
index 7b98a6600533d0411472db6af97475f85ef10190..080bc61a935a821ed6490dfedae7df20b381425c 100644 (file)
@@ -13,6 +13,7 @@ package core.alloc
 use core.memory
 use core.intrinsics.types {type_is_function}
 
+#doc "Overloaded procedure for converting something to an Allocator."
 as_allocator :: #match {
     macro (a: Allocator) => a
 }
@@ -95,11 +96,19 @@ temp_state     : arena.ArenaState;
 #thread_local
 temp_allocator : Allocator;
 
+#doc """
+    Initializes the thread-local temporary allocator.
+
+    You do not need to call this. It is called automatically on thread initialization.
+"""
 init_temp_allocator :: () {
     temp_state = arena.make(heap_allocator, TEMPORARY_ALLOCATOR_SIZE);
     temp_allocator = as_allocator(&temp_state);
 }
 
+#doc """
+    Resets the temporary allocator, effectively freeing all allocations made in the temporary allocator.
+"""
 clear_temp_allocator :: () {
     arena.clear(&temp_state);
 }
index d602b5441cd1762dee65d7e98af56235b74b6798..edfb86428e24621342a46048995608ab88af2bc7 100644 (file)
@@ -1,23 +1,27 @@
 package core.alloc.arena
+#package_doc """
+    This allocator is mostly used for making many fixed-size
+    allocation (i.e. allocations that will not need to change
+    in size, such as game entities or position structs). The
+    power of this allocator over the heap allocator for this
+    purpose is that it is much faster, since the logic is
+    simpler. Another power of this allocator over something
+    such as a dynamic array is that the dynamic array could
+    relocate and cause any pointers to the data inside to
+    become invalidated; this is definitely not behaviour you
+    want. This arena allocator can grow as large as needed,
+    while guaranteeing that the memory inside of it will
+    never move.
+"""
 
 use core
 
-// This allocator is mostly used for making many fixed-size
-// allocation (i.e. allocations that will not need to change
-// in size, such as game entities or position structs). The
-// power of this allocator over the heap allocator for this
-// purpose is that it is much faster, since the logic is
-// simpler. Another power of this allocator over something
-// such as a dynamic array is that the dynamic array could
-// relocate and cause any pointers to the data inside to
-// become invalidated; this is definitely not behaviour you
-// want. This arena allocator can grow as large as needed,
-// while guaranteeing that the memory inside of it will
-// never move.
-
 // Deprecated struct 'ArenaState'. Use 'Arena' instead.
 ArenaState :: Arena
 
+#doc """
+    Stores internal details used during arena allocations.
+"""
 Arena :: struct {
     backing_allocator : Allocator;
 
@@ -28,6 +32,7 @@ Arena :: struct {
     arena_size : u32;
 }
 
+#local
 ArenaBlock :: struct { next : &ArenaBlock; }
 
 #local
@@ -89,7 +94,12 @@ arena_alloc_proc :: (data: rawptr, aa: AllocationAction, size: u32, align: u32,
     return null;
 }
 
-// @Note // `arena_size` must be at least 4
+#doc """
+    Makes a new arena.
+
+    `arena_size` specifies the size of each individual arena page, which must be at least 4 bytes
+    in size (but should be quite a bit large).
+"""
 make :: (backing: Allocator, arena_size: u32) -> Arena {
     assert(arena_size >= 4, "Arena size was expected to be at least 4 bytes.");
     
@@ -114,6 +124,9 @@ make_allocator :: (rs: &Arena) -> Allocator {
     };
 }
 
+#doc """
+    Frees all pages in an arena.
+"""
 free :: (arena: &Arena) {
     walker := arena.first_arena;
     trailer := walker;
@@ -128,7 +141,9 @@ free :: (arena: &Arena) {
     arena.size          = 0;
 }
 
-#doc "Clears and frees every page, except for first page."
+#doc """
+    Clears and frees every page, except for first page.
+"""
 clear :: (arena: &Arena) {
     walker := arena.first_arena.next;
 
@@ -142,6 +157,9 @@ clear :: (arena: &Arena) {
     arena.size = sizeof rawptr;
 }
 
+#doc """
+    Returns the number of pages in the arena.
+"""
 get_allocated_arenas :: (arena: &Arena) -> u32 {
     arenas := 0;
     walker := arena.first_arena;
@@ -153,10 +171,27 @@ get_allocated_arenas :: (arena: &Arena) -> u32 {
     return arenas;
 }
 
+#doc """
+    Returns the number of bytes used by the arena.
+"""
 get_allocated_bytes :: (arena: &Arena) -> u32 {
     return get_allocated_arenas(arena) * (arena.arena_size - 1) + arena.size;
 }
 
+#doc """
+    Creates an arena allocator and automatically applies it to the context's allocator
+    in the current scope.
+
+        foo :: () {
+            alloc.arena.auto();
+
+            // Lazily allocate everything, knowing that it will
+            // be freed when this function returns.
+            for 100 {
+                s := string.alloc_copy("Make a copy of me!");
+            }
+        }
+"""
 auto :: #match {
     macro (size := 32 * 1024, $dest: Code = [](context.allocator)) {
         use core.alloc {arena, heap_allocator}
@@ -182,6 +217,19 @@ auto :: #match {
     }
 }
 
+#doc """
+    Creates an arena allocator to be used as the temporary allocator
+    in the code block.
+
+        foo :: () {
+            alloc.arena.auto_temp() {
+                for 1000 {
+                    // Will be automatically freed
+                    x := new_temp(i32);
+                }
+            }
+        }
+"""
 auto_temp :: macro (body: Code) -> i32 {
     use core.alloc {arena, heap_allocator}
     a := arena.make(heap_allocator, 32 * 1024);
index 00bd6a3e94115a5fe7b2c6bbf81a6d5aa74a281c..874cc14075a3ced621834c8b9faa92d33504d5a8 100644 (file)
@@ -1,22 +1,31 @@
 package core.alloc.atomic
+#package_doc """
+    AtomicAllocator wraps another allocator in a mutex, 
+    ensuring that every allocation is thread-safe. This 
+    is not needed for the general purpose heap allocator, 
+    as that already has a thread-safe implementation.
+"""
 
 // This can only be used when the core.sync package exists.
 #if #defined(package core.sync) {
 
-//
-// AtomicAllocator wraps another allocator in a mutex,
-// ensuring that every allocation is thread-safe. This
-// is not needed for the general purpose heap allocator,
-// as that already has a thread-safe implementation.
 
 use core.alloc
 use core.sync
 
+#doc """
+    Stores internal details used by the atomic allocator.
+
+    Simply the wrapped allocator and the mutex.
+"""
 AtomicAllocator :: struct {
     a: Allocator;
     m: sync.Mutex;
 }
 
+#doc """
+    Creates a new AtomicAllocator over an existing allocator.
+"""
 make :: (a: Allocator) -> AtomicAllocator {
     atomic: AtomicAllocator = .{ a = a };
 
@@ -25,6 +34,9 @@ make :: (a: Allocator) -> AtomicAllocator {
     return atomic;
 }
 
+#doc """
+    Makes an allocator out of the atomic allocator state.
+"""
 make_allocator :: (atomic: &AtomicAllocator) =>
     Allocator.{ atomic, atomic_alloc };
 
index ac37b4e83b7f6c07b36a7d0b53eaf0b72d4d71be..2cbd98a9106f3021d449db3b66e6680014531e38 100644 (file)
@@ -1,17 +1,19 @@
 package core.alloc.fixed
+#package_doc """
+    This allocator is very simple. It is simply a bump allocator from
+    a fixed size buffer. It cannot free or resize, and will return null
+    when it has used all memory in the buffer given to it.
+    
+    This kind of allocator is useful for temporary string building or
+    similar circumstances, where you know that the needed memory size
+    will not be exceeded, but you don't what to deal with potential
+    slowness of a general heap allocator. By using this allocator, you
+    can continue to use the same code that does allocations like normal,
+    but can get the speed increase of a simple allocation strategy.
+"""
 
 use core
 
-// This allocator is very simple. It is simply a bump allocator from
-// a fixed size buffer. It cannot free or resize, and will return null
-// when it has used all memory in the buffer given to it.
-//
-// This kind of allocator is useful for temporary string building or
-// similar circumstances, where you know that the needed memory size
-// will not be exceeded, but you don't what to deal with potential
-// slowness of a general heap allocator. By using this allocator, you
-// can continue to use the same code that does allocations like normal,
-// but can get the speed increase of a simple allocation strategy.
 
 FixedAllocator :: struct {
     buffer: [] u8;
index 3fbec3fedcfb64a17b3bb5cca4abe5828fc72bb1..7fea7ed6ac29c95eab09c64e475cdeddc5bd198b 100644 (file)
@@ -1,20 +1,19 @@
 package core.alloc.gc
-
-//
-// "Garbage collection" is not somthing Onyx has. Even things
-// like reference counted pointers is not something Onyx can
-// do, because of Onyx's simpler semantics. That being said,
-// with custom allocators and some careful design, GC is
-// "achievable". This allocator wraps another allocator. With
-// each allocation, a little extra space is allocated to build
-// a linked list of all allocations made. This way, when the
-// memory is done being used, everything can be freed automatically.
-//
-// The `auto` macro makes this allocator very easy to use:
-//
-//   core.alloc.gc.auto() {
-//       // Every allocation here will automatically be freed
-//   }
+#package_doc """
+    "Garbage collection" is not somthing Onyx has. Even things
+    like reference counted pointers is not something Onyx can
+    do, because of Onyx's simpler semantics. That being said,
+    with custom allocators and some careful design, GC is
+    "achievable". This allocator wraps another allocator. With
+    each allocation, a little extra space is allocated to build
+    a linked list of all allocations made. This way, when the
+    memory is done being used, everything can be freed automatically.
+
+    The `auto` macro makes this allocator very easy to use:
+        core.alloc.gc.auto() {
+            // Every allocation here will automatically be freed
+        }
+"""
 
 
 use runtime
@@ -158,6 +157,10 @@ GC_Manually_Free_Magic_Number :: 0xface1337
     return cast([&] GCLink, newptr) + 1;
 }
 
+#doc """
+    Removes an allocation from the garbage collectors tracking list,
+    so it will not be freed automatically.
+"""
 untrack :: (ptr: rawptr) -> bool {
     link: &GCLink = (cast([&] GCLink) ptr) - 1;
 
index 786b43b2238133ee6f7cf7785cd4cfc95f6dc67a..6fcf972f5f554ad5440801d20c5f21c09137623b 100644 (file)
@@ -1,8 +1,10 @@
 package core.alloc.log
+#package_doc """
+    This allocator simply wraps another allocator and
+    prints every allocation/deallocation made by that 
+    allocator.
+"""
 
-// This allocator simply wraps another allocator and
-// prints every allocation/deallocation made by that 
-// allocator.
 
 use core
 use runtime
index 0c7f9c4093dd9d619b274ef2d7d36ed7dbcc85d7..c47440a8e825419611cef86186793e312ca65c55 100644 (file)
@@ -1,5 +1,15 @@
 package core.alloc.memdebug
 #allow_stale_code
+#package_doc """
+    The memory debugger allocator wraps an existing allocator (normally the heap allocator),
+    and reports on a TCP socket all of the allocation operations done to the underlying
+    allocator. This listener on this socket can use this information to show useful information
+    about the memory usage in the program.
+
+    This is best used when it starts at the very beginning of the program.
+    The easiest way to use this is to define MEMDEBUG in runtime.vars,
+    or pass -DMEMDEBUG on the command line. 
+"""
 
 use core {Result}
 use core.alloc
index 4677c6ba7d442210cd2c2c7482deaf8b805fc08b..d8c94cf0f05972b27f526ded12478619b653e696 100644 (file)
@@ -1,18 +1,19 @@
 package core.alloc.pool
+#package_doc """
+    A pool allocator is an O(1) allocator that is capable of allocating and freeing.
+    It is able to do both in constant time because it maintains a linked list of all
+    the free elements in the pool. When an element is requested the first element of
+    linked list is returned and the list is updated. When an element is freed, it
+    becomes the first element. The catch with this strategy however, is that all of
+    the allocations must be of the same size. This would not be an allocator to use
+    when dealing with heterogenous data, but when doing homogenous data, such as
+    game entities, this allocator is great. It allows you to allocate and free as
+    many times as you want, without worrying about fragmentation or slow allocators.
+    Just make sure you don't allocate more than the pool can provide.
+"""
 
 use core
 
-// A pool allocator is an O(1) allocator that is capable of allocating and freeing.
-// It is able to do both in constant time because it maintains a linked list of all
-// the free elements in the pool. When an element is requested the first element of
-// linked list is returned and the list is updated. When an element is freed, it
-// becomes the first element. The catch with this strategy however, is that all of
-// the allocations must be of the same size. This would not be an allocator to use
-// when dealing with heterogenous data, but when doing homogenous data, such as
-// game entities, this allocator is great. It allows you to allocate and free as
-// many times as you want, without worrying about fragmentation or slow allocators.
-// Just make sure you don't allocate more than the pool can provide.
-
 PoolAllocator :: struct (Elem: type_expr) {
     buffer     : [] Elem;
     first_free : &Elem;
index 2111e5d00909ab02f7dd421883b14b894efa7639..bb61a540d7b040eedf41899c676b41453ae67160 100644 (file)
@@ -1,17 +1,18 @@
 package core.alloc.ring
+#package_doc """
+    This allocator is great for temporary memory, such as returning
+    a pointer from a function, or storing a formatted string. The
+    memory allocated using this allocator does not need to be freed.
+    The idea is that as you keep allocating you will "wrap around"
+    and start writing over memory that was allocated before. For this
+    reason, it is not safe to use this for any kind of permanent
+    allocation. Also, be wary that you provide this allocator with
+    a buffer big enough to store as much data as you are going to need
+    at any given time. 
+"""
 
 use core
 
-// This allocator is great for temporary memory, such as returning
-// a pointer from a function, or storing a formatted string. The
-// memory allocated using this allocator does not need to be freed.
-// The idea is that as you keep allocating you will "wrap around"
-// and start writing over memory that was allocated before. For this
-// reason, it is not safe to use this for any kind of permanent
-// allocation. Also, be wary that you provide this allocator with
-// a buffer big enough to store as much data as you are going to need
-// at any given time. 
-
 RingState :: struct {
     base_ptr : rawptr;
     size     : u32;
index 8335e5a0ab264ae49952b7273cbb932216f76cbd..d3c053837d834e04a2c368d2c4908ad1a49857d5 100644 (file)
@@ -54,6 +54,8 @@ Doc_Package :: struct {
 
     parent: Id;
     subpackages: [] Id;
+
+    notes: [] str;
 }
 
 Doc_Entity :: struct {