added: `#doc` sets notes on procedures
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 20 Mar 2023 21:29:43 +0000 (16:29 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 24 Mar 2023 01:51:04 +0000 (20:51 -0500)
compiler/include/astnodes.h
compiler/include/parser.h
compiler/src/doc.c
compiler/src/parser.c
core/container/iter.onyx
core/container/map.onyx
core/encoding/base64.onyx
core/hash/hash.onyx

index 4569d8566d90d9a706c7bb801979dd5996fca157..f41112b092ed26a6e41876ef265014715aa21d52 100644 (file)
@@ -1046,7 +1046,7 @@ struct AstDistinctType {
 };
 
 // Top level nodes
-struct AstBinding       { AstTyped_base; AstNode* node; };
+struct AstBinding       { AstTyped_base; AstNode* node; OnyxToken *documentation; };
 struct AstAlias         { AstTyped_base; AstTyped* alias; };
 struct AstInclude       { AstNode_base;  AstTyped* name_node; char* name; };
 struct AstInjection     {
index 76961fd98e2080f7bb240052bddab9e8203c4cce..bdeede544c8395fbc5734e4bc4514e575ea6146c 100644 (file)
@@ -47,6 +47,11 @@ typedef struct OnyxParser {
     // in other files.
     u32 overload_count;
 
+    // Used by `#doc` directives to store their documentation
+    // string. This is then used by binding nodes to capture
+    // documentation.
+    OnyxToken *last_documentation_token;
+
     u16 tag_depth : 16;
 
     b32 hit_unexpected_token : 1;
index 5ec29f8321dfcdfb4ba43c5d708afed53bf6329d..5dd7333440f6998b64cfd266c6d4cb0e38ce7779 100644 (file)
@@ -337,6 +337,14 @@ static void write_entity_header(bh_buffer *buffer, AstBinding *binding, OnyxFile
 
 static b32 write_doc_procedure(bh_buffer *buffer, AstBinding *binding, AstNode *proc);
 
+static void write_doc_notes(bh_buffer *buffer, AstBinding *binding) {
+    if (!binding || !binding->documentation) {
+        write_cstring(buffer, "");
+    } else {
+        write_string(buffer, binding->documentation->length, binding->documentation->text);
+    }
+}
+
 static b32 write_doc_function(bh_buffer *buffer, AstBinding *binding, AstNode *proc) {
     AstFunction *func = (void *) proc;
     if (func->kind == Ast_Kind_Macro) {
@@ -346,7 +354,7 @@ static b32 write_doc_function(bh_buffer *buffer, AstBinding *binding, AstNode *p
     write_entity_header(buffer, binding, func->token->pos);
 
     // Notes
-    write_cstring(buffer, "");
+    write_doc_notes(buffer, binding);
 
     // Flags
     bh_buffer_write_u32(buffer, proc->kind == Ast_Kind_Macro ? Doc_Procedure_Flag_Macro : 0);
@@ -378,7 +386,7 @@ static b32 write_doc_overloaded_function(bh_buffer *buffer, AstBinding *binding,
     write_entity_header(buffer, binding, ofunc->token->pos);
 
     // Notes
-    write_cstring(buffer, "");
+    write_doc_notes(buffer, binding);
 
     // Flags
     bh_buffer_write_u32(buffer, Doc_Procedure_Flag_Overloaded);
@@ -414,7 +422,7 @@ static b32 write_doc_polymorphic_proc(bh_buffer *buffer, AstBinding *binding, As
     write_entity_header(buffer, binding, func->token->pos);
     
     // Notes
-    write_cstring(buffer, "");
+    write_doc_notes(buffer, binding);
 
     // Flags
     bh_buffer_write_u32(buffer, proc->kind == Ast_Kind_Macro ? Doc_Procedure_Flag_Macro : 0);
index c10afe1d1f45f78dbcd23e9c8ed2e34c67a38cdb..2ae6a7843802d12510096777915f69bbca5e7c1a 100644 (file)
@@ -3525,7 +3525,7 @@ static void parse_top_level_statement(OnyxParser* parser) {
                 // This is a future feature I want to add to the language, proper docstrings.
                 // For now (and so I start documenting thing...), #doc can be used anywhere
                 // at top level, followed by a string to add a doc string.
-                expect_token(parser, Token_Type_Literal_String);
+                parser->last_documentation_token = expect_token(parser, Token_Type_Literal_String);
                 return;
             }
             else {
@@ -3567,6 +3567,11 @@ submit_binding_to_entities:
     {
         if (!binding) return;
 
+        if (parser->last_documentation_token) {
+            binding->documentation = parser->last_documentation_token;
+            parser->last_documentation_token = NULL;
+        }
+
         //
         // If this binding is inside an #inject block,
         // swap the binding node for an injection node
@@ -3717,6 +3722,7 @@ OnyxParser onyx_parser_create(bh_allocator alloc, OnyxTokenizer *tokenizer) {
     parser.tag_depth = 0;
     parser.overload_count = 0;
     parser.injection_point = NULL;
+    parser.last_documentation_token = NULL;
 
     parser.polymorph_context = (PolymorphicContext) {
         .root_node = NULL,
index bc08cf930e455122004939600cd84c65a2b20b47..ec7e10d57f43c6e9fb12aa769fb8d799940d46b0 100644 (file)
@@ -28,29 +28,31 @@ use core.intrinsics.types {type_is_struct}
 
 
 
-//
-// The standard function to convert something to an Iterator.
-// For-loops currently do not use this function to determine
-// how to iterate over something unknown, but that could be
-// a feature down the line.
+#doc """
+    The standard function to convert something to an Iterator.
+    For-loops currently do not use this function to determine
+    how to iterate over something unknown, but that could be
+    a feature down the line.
+"""
 as_iter :: #match -> Iterator {}
 
-//
-// Helper interface to test if something can be passed to
-// as_iter successfully.
+#doc """
+    Helper interface to test if something can be passed to
+    as_iter successfully.
+"""
 Iterable :: interface (t: $T) {
     { as_iter(t) } -> Iterator;
 }
 
-//
-// Helper function to get the next value out of an iterator.
+#doc "Helper function to get the next value out of an iterator."
 next :: (it: Iterator) -> (it.Iter_Type, bool) {
     return it.next(it.data);
 }
 
-//
-// Helper function to close an iterator, if a close function
-// is defined.
+#doc """
+    Helper function to close an iterator, if a close function
+    is defined.
+"""
 close :: (it: Iterator) {
     if it.close != null_proc {
         it.close(it.data);
@@ -102,8 +104,7 @@ HasAsIter :: interface (t: $T) {
 // Most of these procedures come in two variants,
 // one that takes a context paramter, and one that does not.
 
-//
-// Only yields the values for which the predicate is true.
+#doc "Only yields the values for which the predicate is true."
 filter :: #match #local {}
 
 #overload
@@ -149,9 +150,10 @@ filter :: (it: Iterator($T), ctx: $Ctx, predicate: (T, Ctx) -> bool) =>
         fi => { close(fi.iterator); });
 
 
-//
-// Transforms every value that comes out of an iterator
-// using the transform function.
+#doc """
+    Transforms every value that comes out of an iterator
+    using the transform function.
+"""
 map :: #match #local {}
 
 #overload
@@ -187,8 +189,7 @@ map :: (it: Iterator($T), ctx: $Ctx, transform: (T, Ctx) -> $R) =>
         mi => { close(mi.iterator); })
 
 
-//
-// Only yields the first `count` values, then closes.
+#doc "Only yields the first `count` values, then closes."
 take :: (it: Iterator($T), count: u32) -> Iterator(T) {
     return generator(
         &.{ iterator = it, remaining = count },
@@ -206,8 +207,7 @@ take :: (it: Iterator($T), count: u32) -> Iterator(T) {
 }
 
 
-//
-// Yields values while the predicate returns true.
+#doc "Yields values while the predicate returns true."
 take_while :: (it: Iterator($T), predicate: (T) -> bool) -> Iterator(T) {
     return generator(
         &.{ iterator = it, predicate = predicate },
@@ -223,8 +223,7 @@ take_while :: (it: Iterator($T), predicate: (T) -> bool) -> Iterator(T) {
 }
 
 
-//
-// Discards the first `count` values and yields all remaining values,
+#doc "Discards the first `count` values and yields all remaining values."
 skip :: (it: Iterator($T), count: u32) -> Iterator(T) {
     return generator(
         &.{ iterator = it, to_skip = count, skipped = false },
@@ -247,8 +246,7 @@ skip :: (it: Iterator($T), count: u32) -> Iterator(T) {
 }
 
 
-//
-// Discards values while the predicate is true, then yields all values.
+#doc "Discards values while the predicate is true, then yields all values."
 skip_while :: #match #local {}
 
 #overload
@@ -304,9 +302,10 @@ skip_while :: (it: Iterator($T), ctx: $Ctx, predicate: (T, Ctx) -> bool) -> Iter
 }
 
 
-//
-// Combines two iterators into one by yielding a Pair of
-// the value from each of the iterators.
+#doc """
+    Combines two iterators into one by yielding a Pair of
+    the value from each of the iterators.
+"""
 zip :: (left_iterator: Iterator($T), right_iterator: Iterator($R)) -> Iterator(Pair(T, R)) {
     return generator(
         &.{ left_iter = left_iterator, right_iter = right_iterator },
@@ -322,9 +321,11 @@ zip :: (left_iterator: Iterator($T), right_iterator: Iterator($R)) -> Iterator(P
 }
 
 
-//
-// Combines iterators by first yielding all values from
-// one, then yielding all values from the next, and so on.
+
+#doc """
+    Combines iterators by first yielding all values from
+    one, then yielding all values from the next, and so on.
+"""
 concat :: (iters: ..Iterator($T)) -> Iterator(T) {
     return generator(
         &.{
@@ -353,16 +354,17 @@ concat :: (iters: ..Iterator($T)) -> Iterator(T) {
         });
 }
 
-//
-// Yields the same value indefinitely. Useful with iter.zip.
+#doc "Yields the same value indefinitely. Useful with `iter.zip`."
 const :: (value: $T) -> Iterator(T) {
     return generator(&.{ v = value }, c => (c.v, true));
 }
 
 
-//
-// Yields a value that contains: 1) the value from the iterator,
-// and 2) an incrementing integer.
+#doc """
+    Yields a value that contains:
+        1) the value from the iterator,
+        2) an incrementing integer.
+"""
 enumerate :: #match #local {}
 
 #overload
@@ -394,23 +396,26 @@ enumerate :: (it: Iterator($T), start_index: i32 = 0) -> Iterator(Enumeration_Va
 
 
 
-//
-// Extract the next value out of an iterator. Closes it when
-// the iterator is out of values, if no_close is false.
+#doc """
+    Extract the next value out of an iterator. Closes it when
+    the iterator is out of values, if no_close is false.
+"""
 take_one :: (it: Iterator($T), no_close := false) -> (T, bool) {
     ret, cont := next(it);
     if !cont && !no_close { close(it); }
     return ret, cont;
 }
 
-// Macro that allows you to extract elements from an iterator in a simple way:
-//
-// value: i32;
-// iterator: Iterator(i32) = ...;
-//
-// if #(value) << iterator {
-//     ...iterater closed...
-// }
+#doc """
+    Macro that allows you to extract elements from an iterator in a simple way:
+    
+    value: i32;
+    iterator: Iterator(i32) = ...;
+    
+    if #(value) << iterator {
+        ...iterater closed...
+    }
+"""
 #operator << macro (dest: Code, it: Iterator($T)) -> bool {
     take_one :: take_one
 
@@ -429,15 +434,16 @@ take_one :: (it: Iterator($T), no_close := false) -> (T, bool) {
 #overload
 as_iter :: from_array
 
-//
-// `from_array` has two almost identical implementations,
-// but the details are important here. Normally, `from_array`
-// returns an iterator by value, unless the array is of
-// structures, then it returns an iterator by pointer.
-// This seems weird, but in practice it is closer to what
-// you want, as you don't want to have to copy every structure
-// out of the array. While for primitives, you don't want to
-// dereference it everywhere.
+#doc """
+    `from_array` has two almost identical implementations,
+    but the details are important here. Normally, `from_array`
+    returns an iterator by value, unless the array is of
+    structures, then it returns an iterator by pointer.
+    This seems weird, but in practice it is closer to what
+    you want, as you don't want to have to copy every structure
+    out of the array. While for primitives, you don't want to
+    dereference it everywhere.
+"""
 from_array :: #match #local {}
 
 #overload
@@ -483,9 +489,10 @@ from_array :: (arr: [] $T) => generator(
 );
 
 
-//
-// Iterators created from pointers to dynamic arrays are
-// special, because they support the #remove directive.
+#doc """
+    Iterators created from pointers to dynamic arrays are
+    special, because they support the #remove directive.
+"""
 #local
 generic_dynamic_array_as_iter :: (x: &[..] $T, $access: Code, $return_type: type_expr) => {
     Context :: struct (T: type_expr) {
@@ -563,10 +570,11 @@ as_iter :: (r: range) => generator(
 // Iterator reducing
 //
 
-//
-// Incremently calls `combine` on the yielded value and the
-// accumulated value, producing a new accumulated value. Returns
-// the final accumulated value.
+#doc """
+    Incremently calls `combine` on the yielded value and the
+    accumulated value, producing a new accumulated value. Returns
+    the final accumulated value.
+"""
 fold :: #match #local {}
 
 #overload
@@ -583,8 +591,7 @@ fold :: (it: Iterator($T), initial_value: $R, combine: (T, R) -> R) -> R {
 }
 
 
-//
-// Returns how many times the `cond` was true.
+#doc "Returns how many times the `cond` was true."
 count :: #match #local {}
 
 #overload
@@ -600,8 +607,7 @@ count :: (it: Iterator($T), cond: (T) -> bool) -> i32 {
 
 
 
-//
-// Returns if `cond` returned true for *any* yielded value.
+#doc "Returns if `cond` returned true for *any* yielded value."
 some :: #match #local {}
 
 #overload
@@ -615,8 +621,7 @@ some :: (it: Iterator($T), cond: (T) -> bool) -> bool {
 }
 
 
-//
-// Returns if `cond` returned true for *all* yielded values.
+#doc "Returns if `cond` returned true for *all* yielded values."
 every :: #match #local {}
 
 #overload
@@ -630,9 +635,10 @@ every :: (it: Iterator($T), cond: (T) -> bool) -> bool {
 }
 
 
-//
-// Places all yielded values into a dynamically allocated array,
-// using the allocator provided (context.allocator by default).
+#doc """
+    Places all yielded values into a dynamically allocated array,
+    using the allocator provided (context.allocator by default).
+"""
 to_array :: (it: Iterator($T), allocator := context.allocator) -> [..] T {
     arr := array.make(T, allocator=allocator);
     for v: it do array.push(&arr, v);
@@ -641,17 +647,18 @@ to_array :: (it: Iterator($T), allocator := context.allocator) -> [..] T {
 }
 
 
-//
-// Produces an iterator that first yields all values from the
-// first iterable, combined with the first yield value from the
-// second iterable. Then, steps the second iterable, and repeats.
-//
-// For example,
-//
-//      iter.prod(1 .. 4, 1 .. 3)
-//
-// Would yield:
-//      (1, 1), (2, 1), (3, 1), (1, 2), (2, 2), (3, 2)
+#doc """
+    Produces an iterator that first yields all values from the
+    first iterable, combined with the first yield value from the
+    second iterable. Then, steps the second iterable, and repeats.
+   
+    For example,
+   
+         iter.prod(1 .. 4, 1 .. 3)
+   
+    Would yield:
+         (1, 1), (2, 1), (3, 1), (1, 2), (2, 2), (3, 2)
+"""
 prod :: #match #local {}
 
 #overload
@@ -691,14 +698,15 @@ prod :: (x: $I1/Iterable, y_iter: Iterator($Y)) => {
 }
 
 
-//
-// Simple iterator comprehensions, in the same vein
-// as Pythons comprehension syntax.
-// 
-// Python:
-//     results = [it * 2 for it in [1, 2, 3, 4, 5]]
-// Onyx:
-//     results := iter.comp(u32.[1, 2, 3, 4, 5], #(it * 2));
+#doc """
+    Simple iterator comprehensions, in the same vein
+    as Pythons comprehension syntax.
+    
+    Python:
+        results = [it * 2 for it in [1, 2, 3, 4, 5]]
+    Onyx:
+        results := iter.comp(u32.[1, 2, 3, 4, 5], #(it * 2));
+"""
 comp :: #match #local {}
 
 #overload
@@ -727,13 +735,14 @@ comp :: macro (i: $I/Iterable, value: Code) =>
     #this_package.comp(#this_package.as_iter(i), value);
 
 
-//
-// Using the polymorph solving system, you can write type
-// free versions of arbitrary iterators. This is used
-// heavily by many of the functions defined above.
-//
-// Maybe at some point an alternate allocator would be good
-// for this? For now, I think the temporary allocator is sufficient.
+#doc """
+    Using the polymorph solving system, you can write type
+    free versions of arbitrary iterators. This is used
+    heavily by many of the functions defined above.
+    
+    Maybe at some point an alternate allocator would be good
+    for this? For now, I think the temporary allocator is sufficient.
+"""
 generator :: #match #local {}
 
 #overload
@@ -820,14 +829,14 @@ generator_no_copy :: (ctx: &$Ctx, gen: (&Ctx) -> ($T, bool), close: (&Ctx) -> vo
         return .{c, #solidify next {T=it.Iter_Type}, #solidify close {T=it.Iter_Type}};
     }
 
-    //
-    // Allows you to easily write a parallelized for-loop over an iterator.
-    // For example,
-    //
-    //     iter.parallel_for(1 .. 100, 4, &.{}) {
-    //         printf("Thread {} has {}!\n", context.thread_id, it);
-    //     }
-    //
+    #doc """
+        Allows you to easily write a parallelized for-loop over an iterator.
+        For example,
+        
+            iter.parallel_for(1 .. 100, 4, &.{}) {
+                printf("Thread {} has {}!\n", context.thread_id, it);
+            }
+    """
     parallel_for :: #match #local {}
 
     #overload
index f3a927d059ce2b1552620039f5bcfa473051b199..1d69cf40cef47f3749fb9a2282f9030fe66c9cd3 100644 (file)
@@ -4,9 +4,9 @@ use core {array, hash, memory, math, conv, Optional}
 use core.intrinsics.onyx { __initialize }
 
 #doc """
-   Map is a generic hash-map implementation that uses chaining.
-   Values can be of any type. Keys must of a type that supports
-   the core.hash.hash, and the '==' operator.
+    Map is a generic hash-map implementation that uses chaining.
+    Values can be of any type. Keys must of a type that supports
+    the core.hash.hash, and the '==' operator.
 """
 @conv.Custom_Format.{ #solidify format_map {K=Key_Type, V=Value_Type} }
 Map :: struct (Key_Type: type_expr, Value_Type: type_expr) where ValidKey(Key_Type) {
@@ -70,8 +70,7 @@ make :: macro ($Key: type_expr, $Value: type_expr, default := Value.{}) -> Map(K
     return map;
 }
 
-//
-// Initializes a map.
+#doc "Initializes a map."
 init :: (use map: &Map($K, $V), default := V.{}) {
     __initialize(map);
 
@@ -84,20 +83,21 @@ init :: (use map: &Map($K, $V), default := V.{}) {
     array.init(&entries, allocator=allocator);
 }
 
-//
-// Allows for deletion of a Map using delete(&map).
+#doc "Allows for deletion of a Map using `delete(&map)`."
 #match builtin.delete core.map.free
 
-//
-// Destroys a map and frees all memory.
+#doc """
+    Destroys a map and frees all memory.
+"""
 free :: (use map: &Map) {
     if hashes.data != null  do memory.free_slice(&hashes, allocator=allocator);
     if entries.data != null do array.free(&entries);
 }
 
-//
-// Sets the value at the specified key, or creates a new entry
-// if the key was not already present.
+#doc """
+    Sets the value at the specified key, or creates a new entry
+    if the key was not already present.
+"""
 put :: (use map: &Map, key: map.Key_Type, value: map.Value_Type) {
     lr := lookup(map, key);
 
@@ -112,20 +112,21 @@ put :: (use map: &Map, key: map.Key_Type, value: map.Value_Type) {
     if full(map) do grow(map);
 }
 
-//
-// Returns true if the map contains the key.
+#doc """
+    Returns true if the map contains the key.
+"""
 has :: (use map: &Map, key: map.Key_Type) -> bool {
     lr := lookup(map, key);
     return lr.entry_index >= 0;
 }
 
-//
-// Returns the value at the specified key, or map.default_value if
-// the key is not present.
-//
-// This is subject to change with the addition of Optional to the
-// standard library.
-//
+#doc """
+    Returns the value at the specified key, or map.default_value if
+    the key is not present.
+
+    This is subject to change with the addition of Optional to the
+    standard library.
+"""
 get :: (use map: &Map, key: map.Key_Type) -> map.Value_Type {
     lr := lookup(map, key);
     if lr.entry_index >= 0 do return entries[lr.entry_index].value;
@@ -133,9 +134,10 @@ get :: (use map: &Map, key: map.Key_Type) -> map.Value_Type {
     return default_value;
 }
 
-//
-// Returns a pointer to the value at the specified key, or null if
-// the key is not present.
+#doc """
+    Returns a pointer to the value at the specified key, or null if
+    the key is not present.
+"""
 get_ptr :: (use map: &Map, key: map.Key_Type) -> &map.Value_Type {
     lr := lookup(map, key);
     if lr.entry_index >= 0 do return &entries[lr.entry_index].value;
@@ -143,10 +145,11 @@ get_ptr :: (use map: &Map, key: map.Key_Type) -> &map.Value_Type {
     return null;
 }
 
-//
-// Returns a pointer to the value at the specified key. If the key
-// is not in the map, a new value is created and inserted, then the
-// pointer to that value is returned.
+#doc """
+    Returns a pointer to the value at the specified key. If the key
+    is not in the map, a new value is created and inserted, then the
+    pointer to that value is returned.
+"""
 get_ptr_or_create :: (use map: &Map, key: map.Key_Type) -> &map.Value_Type {
     lr := lookup(map, key);
     if lr.entry_index < 0 {
@@ -157,10 +160,11 @@ get_ptr_or_create :: (use map: &Map, key: map.Key_Type) -> &map.Value_Type {
     return &entries[lr.entry_index].value;
 }
 
-//
-// Returns an Optional of the value at the specified key. The Optional
-// has a value if the key is present, otherwise the optional does not
-// have a value.
+#doc """
+    Returns an Optional of the value at the specified key. The Optional
+    has a value if the key is present, otherwise the optional does not
+    have a value.
+"""
 get_opt :: (use map: &Map, key: map.Key_Type) -> ?map.Value_Type {
     lr := lookup(map, key);
     if lr.entry_index >= 0 do return Optional.make(entries[lr.entry_index].value);
@@ -168,8 +172,7 @@ get_opt :: (use map: &Map, key: map.Key_Type) -> ?map.Value_Type {
     return .{};
 }
 
-//
-// Removes an entry from the map.
+#doc "Removes an entry from the map."
 delete :: (use map: &Map, key: map.Key_Type) {
     lr := lookup(map, key);
     if lr.entry_index < 0 do return;
@@ -211,23 +214,24 @@ update :: macro (map: ^Map, key: map.Key_Type, body: Code) {
     }
 }
 
-//
-// Removes all entries from the hash map. Does NOT
-// modify memory, so be wary of dangling pointers!
+#doc """
+    Removes all entries from the hash map. Does NOT
+    modify memory, so be wary of dangling pointers!
+"""
 clear :: (use map: &Map) {
     for i: 0 .. hashes.count do hashes.data[i] = -1;
     entries.count = 0;
 }
 
-//
-// Returns if the map does not contain any elements.
+#doc "Returns if the map does not contain any elements."
 empty :: (use map: &Map) -> bool {
     return entries.count == 0;
 }
 
-//
-// Helper procedure to nicely format a Map when printing.
-// Rarely ever called directly, instead used by conv.format_any.
+#doc """
+    Helper procedure to nicely format a Map when printing.
+    Rarely ever called directly, instead used by conv.format_any.
+"""
 format_map :: (output: &conv.Format_Output, format: &conv.Format, x: &Map($K, $V)) {
     if format.pretty_printing {
         output->write("{\n");
@@ -246,14 +250,14 @@ format_map :: (output: &conv.Format_Output, format: &conv.Format, x: &Map($K, $V
     }
 }
 
-//
-// Quickly create a Map with some entries.
-//
-//     Map.literal(str, i32, .[
-//         .{ "test", 123 },
-//         .{ "foo",  456 },
-//     ]);
-//
+#doc """
+    Quickly create a Map with some entries.
+   
+        Map.literal(str, i32, .[
+            .{ "test", 123 },
+            .{ "foo",  456 },
+        ]);
+"""
 literal :: ($Key: type_expr, $Value: type_expr, values: [] MapLiteralValue(Key, Value)) => {
     m := core.map.make(Key, Value);
     for & values {
@@ -269,9 +273,10 @@ MapLiteralValue :: struct (K: type_expr, V: type_expr) {
     value: V;
 }
 
-//
-// Produces an iterator that yields all values of the map,
-// in an unspecified order, as Map is unordered.
+#doc """
+    Produces an iterator that yields all values of the map,
+    in an unspecified order, as Map is unordered.
+"""
 as_iter :: (m: &Map) =>
     core.iter.generator(
         &.{ m = m, i = 0 },
index e1153c39d35b1a8be6c2041e57dbff7ea506c1c7..e8345cd5108d5de2b9dab3ef741e6bb44ebb626d 100644 (file)
@@ -9,10 +9,11 @@ use core {array}
 // standards.
 //
 
-//
-// Encodes the given data in base64 into a new buffer, allocated
-// from the allocator provided. It is the callers responsibilty
-// to free this memory.
+#doc """
+    Encodes the given data in base64 into a new buffer, allocated
+    from the allocator provided. It is the callers responsibilty
+    to free this memory.
+"""
 encode :: (data: [] u8, allocator := context.allocator) -> [] u8 {
     out := array.make(u8, allocator=allocator);
 
@@ -46,9 +47,10 @@ encode :: (data: [] u8, allocator := context.allocator) -> [] u8 {
     return out;
 }
 
-//
-// Decodes the given base64 data into a new buffer, allocated
-// from the allocator provided.
+#doc """
+    Decodes the given base64 data into a new buffer, allocated
+    from the allocator provided.
+"""
 decode :: (data: [] u8, allocator := context.allocator) -> [] u8 {
     if data.count % 4 != 0 do return null_str;
 
index b3345d506ade10266af118b5a8cbc2d76eedf80c..2639ec24e197623dad366550b5b2b5a9be32e57f 100644 (file)
@@ -6,19 +6,19 @@ package core.hash
 // core.hash.hash instead.
 to_u32 :: hash
 
-//
-// This overloaded procedure defines how to hash something.
-// It is used throughout the standard library to hash values.
-// There are many overloads to it in the standard library, and
-// more can be added using #overload. Or, a hash method can be
-// defined for a structure or distinct type.
-//
-//     Person :: struct {
-//         hash :: (p: Person) {
-//             return // ...
-//         }
-//     }
-//
+#doc """
+    This overloaded procedure defines how to hash something.
+    It is used throughout the standard library to hash values.
+    There are many overloads to it in the standard library, and
+    more can be added using #overload. Or, a hash method can be
+    defined for a structure or distinct type.
+   
+        Person :: struct {
+            hash :: (p: Person) {
+                return // ...
+            }
+        }
+"""
 hash :: #match -> u32 {
     // Does this need to have a higher precedence value?
     // Because if I wanted to have a custom type as the key