changed: converted documentation to `#doc`
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 21 Mar 2023 13:58:33 +0000 (08:58 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 24 Mar 2023 01:51:04 +0000 (20:51 -0500)
core/builtin.onyx
core/conv/conv.onyx
core/conv/format.onyx
core/conv/parse.onyx
core/misc/any_utils.onyx
core/sync/barrier.onyx
core/sync/condition_variable.onyx
core/sync/mutex.onyx
core/sync/once.onyx
core/sync/semaphore.onyx
core/threads/thread.onyx

index f0ab09446c6f8ee915c164b5dcbe6e893662a401..2d354a2be5ea2a8b0e6099b3e8cf11da5c12fe59 100644 (file)
@@ -58,16 +58,17 @@ range :: struct {
 // casts to all other pointer types.
 null :: cast(rawptr) 0
 
-//
-// `null_proc` is a special function that breaks the normal rules of type
-// checking. `null_proc`, or any procedure marked with `#null`, is assignable
-// to any function type, regardless of if the types match. For example,
-//
-//     f: (i32) -> i32 = null_proc;
-//
-// Even though `null_proc` is a `() -> void` function, it bypasses that check
-// and gets assigned to `f`. If f is called, there will be a runtime exception.
-// This is by design.
+#doc """
+    `null_proc` is a special function that breaks the normal rules of type
+    checking. `null_proc`, or any procedure marked with `#null`, is assignable
+    to any function type, regardless of if the types match. For example,
+    
+        f: (i32) -> i32 = null_proc;
+    
+    Even though `null_proc` is a `() -> void` function, it bypasses that check
+    and gets assigned to `f`. If f is called, there will be a runtime exception.
+    This is by design.
+"""
 null_proc :: () -> void #null ---
 
 //
@@ -364,28 +365,29 @@ cfree   :: (ptr: rawptr)            => raw_free(context.allocator, ptr);
 }
 
 
-//
-// Represents a generic "iterator" or "generator" of a specific
-// type. Can be used in a for-loop natively.
-//
-// `data` is used for contextual information and is passed to
-// the `next`, `close`, and `remove` procedures.
-//
-// `next` is used to extract the next value out of the iterator.
-// It returns the next value, and a continuation flag. If the
-// flag is false, the value should be ignored and iteration should
-// stop.
-//
-// `close` should called when the iterator has ended. This is
-// done automatically in for-loops, and in the `core.iter` library.
-// In for-loops, `close` is called no matter which way the for-loop
-// exits (`break`, `return`, etc). Using this rule, iterator can
-// be used to create "resources" that automatically close when you
-// are done with them.
-//
-// `remove` is used to tell the iterator to remove the last value
-// returned from some underlying data store. Invoked automatically
-// using the `#remove` directive in a for-loop.
+#doc """
+   Represents a generic "iterator" or "generator" of a specific
+   type. Can be used in a for-loop natively.
+   
+   `data` is used for contextual information and is passed to
+   the `next`, `close`, and `remove` procedures.
+   
+   `next` is used to extract the next value out of the iterator.
+   It returns the next value, and a continuation flag. If the
+   flag is false, the value should be ignored and iteration should
+   stop.
+   
+   `close` should called when the iterator has ended. This is
+   done automatically in for-loops, and in the `core.iter` library.
+   In for-loops, `close` is called no matter which way the for-loop
+   exits (`break`, `return`, etc). Using this rule, iterator can
+   be used to create "resources" that automatically close when you
+   are done with them.
+   
+   `remove` is used to tell the iterator to remove the last value
+   returned from some underlying data store. Invoked automatically
+   using the `#remove` directive in a for-loop.
+"""
 Iterator :: struct (Iter_Type: type_expr) {
     data:   rawptr;
     next:   (data: rawptr) -> (Iter_Type, bool);
@@ -394,13 +396,14 @@ Iterator :: struct (Iter_Type: type_expr) {
 }
 
 
-//
-// Optional represents the possibility of a value being empty, without
-// resorting to pointers and null-pointers. Most of the functionality
-// for Optional is defined in core/containers/optional.onyx. This
-// definition exists here because the compiler use it as the template
-// for types like '? i32'. In other words, '? i32' is equivalent to
-// 'Optional(i32)'.
+#doc """
+    Optional represents the possibility of a value being empty, without
+    resorting to pointers and null-pointers. Most of the functionality
+    for Optional is defined in core/containers/optional.onyx. This
+    definition exists here because the compiler use it as the template
+    for types like '? i32'. In other words, '? i32' is equivalent to
+    'Optional(i32)'.
+"""
 Optional :: struct (Value_Type: type_expr) {
     has_value: bool;
     value: Value_Type;
@@ -408,11 +411,12 @@ Optional :: struct (Value_Type: type_expr) {
 
 
 
-//
-// This structure represents the result of a '#callsite' expression. Currently,
-// #callsite is only valid (and parsed) as a default value for a procedure parameter.
-// It allows the function to get the address of the calling site, which can be
-// used for error printing, unique hashes, and much more.
+#doc """
+    This structure represents the result of a '#callsite' expression. Currently,
+    #callsite is only valid (and parsed) as a default value for a procedure parameter.
+    It allows the function to get the address of the calling site, which can be
+    used for error printing, unique hashes, and much more.
+"""
 CallSite :: struct {
     file   : str;
     line   : u32;
@@ -420,31 +424,34 @@ CallSite :: struct {
 }
 
 
-//
-// This structure is used to represent any value in the language.
-// It contains a pointer to the data, and the type of the value.
-// Using the `core.misc` library, you can easily manipulate `any`s
-// and build runtime polymorphism.
+#doc """
+    This structure is used to represent any value in the language.
+    It contains a pointer to the data, and the type of the value.
+    Using the `core.misc` library, you can easily manipulate `any`s
+    and build runtime polymorphism.
+"""
 any :: struct {
     data: rawptr;
     type: type_expr;
 }
 
-//
-// Represents a code block that can be passed around at compile-time.
-// This is commonly used with macros or polymorphic procedures to create
-// very power extensions to the syntax.
+#doc """
+    Represents a code block that can be passed around at compile-time.
+    This is commonly used with macros or polymorphic procedures to create
+    very power extensions to the syntax.
+"""
 Code :: struct {_:i32;}
 
 
-//
-// Define aliases for common datastructures in the core library, if the core library is available.
-// I'm on the fence about keeping this, as the programmer may want to use these names for their own
-// structures, but for the moment I don't see any harm. I'm also thinking about removing the '[..]'
-// syntax for dynamic arrays and just make them like Map's and Set's, i.e. Array(T). This would
-// remove some confusion around the 3 different array types as dynamic arrays would clearly just be
-// normal structures. With the recent addition of macros and iterators, there really wouldn't be much
-// difference anyway.
+#doc """
+    Define aliases for common datastructures in the core library, if the core library is available.
+    I'm on the fence about keeping this, as the programmer may want to use these names for their own
+    structures, but for the moment I don't see any harm. I'm also thinking about removing the '[..]'
+    syntax for dynamic arrays and just make them like Map's and Set's, i.e. Array(T). This would
+    remove some confusion around the 3 different array types as dynamic arrays would clearly just be
+    normal structures. With the recent addition of macros and iterators, there really wouldn't be much
+    difference anyway.
+"""
 #if #defined((package core.map).Map) {
     Map :: (package core.map).Map;
 }
@@ -454,26 +461,30 @@ Code :: struct {_:i32;}
 }
 
 
-//
-// This procedure is a special compiler generated procedure that initializes all the data segments
-// in the program. It should only be called once, by the main thread, at the start of execution. It
-// is undefined behaviour if it is called more than once.
+#doc """
+    This procedure is a special compiler generated procedure that initializes all the data segments
+    in the program. It should only be called once, by the main thread, at the start of execution. It
+    is undefined behaviour if it is called more than once.
+"""
 __initialize_data_segments :: () -> void ---
 
-//
-// This is also a special compiler generated procedure that calls all procedures specified with
-// #init, in the specified order. It should theoretically only be called once on the main thread.
+#doc """
+    This is a special compiler generated procedure that calls all procedures specified with `#init`
+    in the specified order. It should theoretically only be called once on the main thread.
+"""
 __run_init_procedures :: () -> void ---
 
-//
-// This overloaded procedure allow you to define an implicit rule for how to convert any value
-// into a boolean. A default is provided for ALL pointer types and array types, but this can
-// be used for structures or distinct types.
+#doc """
+    This overloaded procedure allow you to define an implicit rule for how to convert any value
+    into a boolean. A default is provided for ALL pointer types and array types, but this can
+    be used for structures or distinct types.
+"""
 __implicit_bool_cast :: #match -> bool {}
 
-//
-// Defines all options for changing the memory layout, imports and exports,
-// and more of an Onyx binary.
+#doc """
+    Defines all options for changing the memory layout, imports and exports,
+    and more of an Onyx binary.
+"""
 Link_Options :: struct {
     // By default the memory layout of a binary is:
     //   reserved | static-data | stack | heap
@@ -527,15 +538,16 @@ Link_Options :: struct {
 }
 
 
-//
-// Special type used to represent a package at runtime.
-// For example,
-//
-//     x: package_id = package main
-//
-// Currently, there is not much you can do with this; it is
-// only used by the runtime.info library if you want to filter
-// tags based on which package they are coming from.
+#doc """
+    Special type used to represent a package at runtime.
+    For example,
+   
+        x: package_id = package main
+   
+    Currently, there is not much you can do with this; it is
+    only used by the runtime.info library if you want to filter
+    tags based on which package they are coming from.
+"""
 package_id :: #distinct u32
 
 //
index e3975f64bba3582002fa500dd9f3685f9330928e..b65b738ad0aca8333afb99337d9cd8abb0a15d91 100644 (file)
@@ -4,10 +4,11 @@ Enable_Custom_Formatters :: true
 
 use core {string, math}
 
-//
-// Converts a string into an integer. Works with positive and
-// negative integers. If given a pointer to a string, will
-// modify the string to extract the integer part.
+#doc """
+    Converts a string into an integer. Works with positive and
+    negative integers. If given a pointer to a string, will
+    modify the string to extract the integer part.
+"""
 str_to_i64 :: #match #local {}
 
 #overload
@@ -66,8 +67,7 @@ str_to_i64 :: (s: &str, base: u32 = 10) -> i64 {
 }
 
 
-//
-// Converts a string to a floating point number.
+#doc "Converts a string to a floating point number."
 str_to_f64 :: #match #local {}
 
 #overload
@@ -143,11 +143,12 @@ str_to_f64 :: (s: &str) -> f64 {
 }
 
 
-//
-// Converts an integer into a string using the buffer provided.
-// Supports upto base 64. If prefix is true, binary numbers are
-// prefixed with '0b' and hexadecimal numbers are prefixed with
-// '0x'.
+#doc """
+    Converts an integer into a string using the buffer provided.
+    Supports upto base 64. If prefix is true, binary numbers are
+    prefixed with '0b' and hexadecimal numbers are prefixed with
+    '0x'.
+"""
 i64_to_str :: (n: i64, base: u64, buf: [] u8, min_length := 0, prefix := false) -> str {
     is_neg := false;
     if n < 0 && base == 10 {
@@ -213,9 +214,10 @@ i64_to_str :: (n: i64, base: u64, buf: [] u8, min_length := 0, prefix := false)
 }
 
 
-//
-// Converts an unsigned number into a string using the buffer provided.
-// Behaves like i64_to_str.
+#doc """
+    Converts an unsigned number into a string using the buffer provided.
+    Behaves like i64_to_str.
+"""
 u64_to_str :: (n: u64, base: u64, buf: [] u8, min_length := 0, prefix := false) -> str {
     c: [&] u8 = &buf[buf.count - 1];
     len := 0;
@@ -268,12 +270,13 @@ u64_to_str :: (n: u64, base: u64, buf: [] u8, min_length := 0, prefix := false)
     return str.{ data = c + 1, count = len };
 }
 
-//
-// Converts a floating point number into a string, using
-// the buffer provided.
-//
-// This is better than what used to be, but still relies on converting the integer
-// part of the float to an integer, which could overflow.
+#doc """
+    Converts a floating point number into a string, using
+    the buffer provided.
+   
+    This is better than what used to be, but still relies on converting the integer
+    part of the float to an integer, which could overflow.
+"""
 f64_to_str :: (f: f64, buf: [] u8, digits_after_decimal := 4) -> str {
     if math.is_nan(f) {
         return format(buf, "NaN");
index 59a4c196c71d4888aa5743a425a61fc7531b0e17..668b8e67385b6c7d61da45be436b11ef84b98b76 100644 (file)
@@ -7,10 +7,11 @@ use core {map, string, array, math}
     custom_parsers   : Map(type_expr, #type (rawptr, str, Allocator) -> bool);
 }
 
-//
-// This procedure is run before main() as it is an #init procedure.
-// It looks for all custom formatting and parsing definitions and
-// registers them to be used in format_any and parse_any.
+#doc """
+    This procedure is run before main() as it is an #init procedure.
+    It looks for all custom formatting and parsing definitions and
+    registers them to be used in format_any and parse_any.
+"""
 custom_formatters_initialized :: #init () {
     map.init(&custom_formatters, default=null_proc);
     map.init(&custom_parsers,    default=null_proc);
@@ -55,72 +56,76 @@ custom_formatters_initialized :: #init () {
     }
 }
 
-//
-// Registers a formatting function for a particular type. This type is
-// inferred from the type of the third argument in the given function.
+#doc """
+    Registers a formatting function for a particular type. This type is
+    inferred from the type of the third argument in the given function.
+"""
 register_custom_formatter :: (formatter: (&Format_Output, &Format, &$T) -> void) {
     custom_formatters[T] = formatter;
 }
 
 
-//
-// Registers a parsing function for a particular type. This type is
-// inferred from the type of the first argument in the given function.
+#doc """
+    Registers a parsing function for a particular type. This type is
+    inferred from the type of the first argument in the given function.
+"""
 register_custom_parser :: (parser: (&$T, str, Allocator) -> bool) {
     custom_parsers[T] = parser;
 }
 
 
-//
-// Tag-type used to specify how to format a structure.
-//
-//     @conv.Custom_Format.{ format_structure }
-//     TheStructure :: struct { ... }
-//
+#doc """
+    Tag-type used to specify how to format a structure.
+   
+        @conv.Custom_Format.{ format_structure }
+        TheStructure :: struct { ... }
+"""
 Custom_Format :: struct {
     format: (&Format_Output, &Format, rawptr) -> void;
 }
 
 
-//
-// Tag-type used to specify that a certain procedure should be used
-// to format a type.
-//
-//     @conv.Custom_Format_Proc.{ TheStructure }
-//     format_structure :: (output: &conv.Format_Output, format: &conv.Format, data: &TheStructure) { ... }
-//
+#doc """
+    Tag-type used to specify that a certain procedure should be used
+    to format a type.
+   
+        @conv.Custom_Format_Proc.{ TheStructure }
+        format_structure :: (output: &conv.Format_Output, format: &conv.Format, data: &TheStructure) { ... }
+"""
 Custom_Format_Proc :: struct {
     type: type_expr;
 }
 
 
-//
-// Tag-type used to specify how to parse a structure.
-//
-//     @conv.Custom_Parse.{ parse_structure }
-//     TheStructure :: struct { ... }
-//
+#doc """
+    Tag-type used to specify how to parse a structure.
+   
+        @conv.Custom_Parse.{ parse_structure }
+        TheStructure :: struct { ... }
+"""
 Custom_Parse :: struct {
     parse: (rawptr, str, Allocator) -> bool;
 }
 
 
-//
-// Tag-type used to specify that a certain procedure should be used
-// to parse a type.
-//
-//     @conv.Custom_Parse_Proc.{ TheStructure }
-//     parse_structure :: (data: &TheStructure, input: str, allocator: Allocator) -> bool { ... }
-//
+#doc """
+    Tag-type used to specify that a certain procedure should be used
+    to parse a type.
+   
+        @conv.Custom_Parse_Proc.{ TheStructure }
+        parse_structure :: (data: &TheStructure, input: str, allocator: Allocator) -> bool { ... }
+   
+"""
 Custom_Parse_Proc :: struct {
     type: type_expr;
 }
 
-//
-// Passed to any custom formatter. Wraps outputting data to any source,
-// using a `flush` callback function. Use `write` to output a string.
-// When the internal buffer is filled, `flush` is called to empty the
-// buffer to the final destination.
+#doc """
+    Passed to any custom formatter. Wraps outputting data to any source,
+    using a `flush` callback function. Use `write` to output a string.
+    When the internal buffer is filled, `flush` is called to empty the
+    buffer to the final destination.
+"""
 Format_Output :: struct {
     data: [&] u8;
     count: u32;
@@ -164,8 +169,7 @@ Format_Flush_Callback :: struct {
 }
 
 
-//
-// Formatting options passed to a custom formatter.
+#doc "Formatting options passed to a custom formatter."
 Format :: struct {
     pretty_printing      := false;        // p
     quote_strings        := false;        // "
@@ -194,9 +198,10 @@ str_format :: format
 str_format_va :: format_va
 
 
-//
-// Formats a string using the provided arguments and format specified string.
-// This has many overloads to make it easy to work with.
+#doc """
+    Formats a string using the provided arguments and format specified string.
+    This has many overloads to make it easy to work with.
+"""
 format :: #match {}
 
 #overload
@@ -228,8 +233,9 @@ format :: (buffer: &dyn_str, format: str, va: ..any) -> str {
     return *buffer;
 }
 
-//
-// Like format(), but takes the arguments as an array of `any`s, not a variadic argument array.
+#doc """
+    Like `format`, but takes the arguments as an array of `any`s, not a variadic argument array.
+"""
 format_va :: #match {}
 
 #overload
@@ -396,10 +402,11 @@ format_va :: (output: &Format_Output, format: str, va: [] any) -> str {
 }
 
 
-//
-// This procedure converts any value into a string, using the type information system.
-// If a custom formatter is specified for the type, that is used instead.
-// This procedure is generally not used directly; instead, through format or format_va.
+#doc """
+    This procedure converts any value into a string, using the type information system.
+    If a custom formatter is specified for the type, that is used instead.
+    This procedure is generally not used directly; instead, through format or format_va.
+"""
 format_any :: (output: &Format_Output, formatting: &Format, v: any) {
     use package runtime.info
     array :: package core.array;
index d0f7fe1e3fa779271f855c136d04bac5cd19b1f1..9156de0d8f6d0bd82aa3b40a9b41936ebc06cbe7 100644 (file)
@@ -2,9 +2,10 @@ package core.conv
 
 use core {map, string, array, math}
 
-//
-// Parses many different types from a string into a value.
-// Uses a custom parser if one has been specified for the type given.
+#doc """
+    Parses many different types from a string into a value.
+    Uses a custom parser if one has been specified for the type given.
+"""
 parse_any :: #match {}
 
 #overload
index 31d0235182563d000bb716207d74bbd0994c78cb..c6c71cd2d2aab26fb7642593708c2ef403d87153 100644 (file)
@@ -24,8 +24,7 @@ any_as :: (a: any, $T: type_expr) -> &T {
     return cast(&T) a.data;
 }
 
-//
-// Dereference a pointer any.
+#doc "Dereference a pointer any."
 any_dereference :: (v: any) -> any {
     t := get_type_info(v.type);
     if t.kind == .Pointer {
@@ -36,8 +35,8 @@ any_dereference :: (v: any) -> any {
     return v;
 }
 
-//
-// Subscript an array-like any.
+
+#doc "Subscript an array-like any."
 any_subscript :: (v: any, index: i32) -> any {
     base_ptr, elem_type, count := any_as_array(v);
     if index >= count || index < 0 {
@@ -50,8 +49,7 @@ any_subscript :: (v: any, index: i32) -> any {
     };
 }
 
-//
-// Select a member from an any.
+#doc "Select a member from an any."
 any_selector :: (v: any, member_name: str) -> any {
     t := get_type_info(v.type);
     if t.kind == .Struct {
@@ -64,8 +62,7 @@ any_selector :: (v: any, member_name: str) -> any {
     return .{null, void};
 }
 
-//
-// This selector works with selecting "foo.bar.joe"
+#doc "Like `any_selector`, but works with selecting \"foo.bar.joe\"."
 any_nested_selector :: (v: any, member_name: str) -> any {
     t := get_type_info(v.type);
     if t.kind != .Struct do return .{};
@@ -86,20 +83,20 @@ any_nested_selector :: (v: any, member_name: str) -> any {
     return .{null, void};
 }
 
-//
-// Convert a structure or pointer to a structure to a Map with
-// keys representing the fields of the structure, and values
-// representing the value of each field.
-//
-//     T :: struct {
-//         x := 123;
-//         y := "test";
-//     }
-//     
-//     m := any_to_map(T.{});
-//
-// `m` would have two keys, "x" and "y".
-//
+#doc """
+    Convert a structure or pointer to a structure to a Map with
+    keys representing the fields of the structure, and values
+    representing the value of each field.
+   
+        T :: struct {
+            x := 123;
+            y := "test";
+        }
+        
+        m := any_to_map(T.{});
+   
+    `m` would have two keys, "x" and "y".
+"""
 any_to_map :: (v: any) -> (Map(str, any), success: bool) {
     vals := v;
     if get_type_info(vals.type).kind == .Pointer {
@@ -119,8 +116,7 @@ any_to_map :: (v: any) -> (Map(str, any), success: bool) {
     return out, true;
 }
 
-//
-// Creates an iterator out of an array-like any.
+#doc "Creates an iterator out of an array-like any."
 any_iter :: (arr: any) -> Iterator(any) {
     base_ptr, elem_type, count := any_as_array(arr);
     if count == 0 {
index eae7d7e398ff77ffd66484f75fed614da003cd8f..d64115fc9fcf5e8e5950faeeff9025c02f2afac3 100644 (file)
@@ -13,9 +13,10 @@ package core.sync
 // continue processing.
 //
 
-//
-// Represents a generational barrier, so the same barrier
-// can be used safely multiple times.
+#doc """
+    Represents a generational barrier, so the same barrier
+    can be used safely multiple times.
+"""
 Barrier :: struct {
     mutex : Mutex;
     cond  : Condition_Variable;
@@ -25,8 +26,8 @@ Barrier :: struct {
     thread_count : i32;
 }
 
-//
-// Initializes a new generational barrier with `thread_count` threads.
+
+#doc "Initializes a new generational barrier with `thread_count` threads."
 barrier_init :: (b: &Barrier, thread_count: i32) {
     mutex_init(&b.mutex);
     condition_init(&b.cond);
@@ -36,16 +37,17 @@ barrier_init :: (b: &Barrier, thread_count: i32) {
     b.thread_count = thread_count;
 }
 
-//
-// Destroys a generational barrier.
+
+#doc "Destroys a generational barrier."
 barrier_destroy :: (b: &Barrier) {
     mutex_destroy(&b.mutex);
     condition_destroy(&b.cond);
 }
 
-//
-// Signals that a thread has reached the barrier.
-// The last thread to reach the barrier will wake up all other threads.
+#doc """
+    Signals that a thread has reached the barrier.
+    The last thread to reach the barrier will wake up all other threads.
+"""
 barrier_wait :: (b: &Barrier) {
     mutex_lock(&b.mutex);
     defer mutex_unlock(&b.mutex);
index 82447f6e1df1a1e8b0760ef8541c5315079b957b..d53f00c8fd3d9ac3d6f00db1080fa1801463604a 100644 (file)
@@ -2,26 +2,22 @@ package core.sync
 
 // TODO: Free the semaphores after they are used.
 
-//
-// A condition variable is used to implement a queue of threads
-// waiting for a condition to be true. Each thread joins the queue
-// using `condition_wait`. Then, another thread can signal that
-// the condition has changed and can "wake up" the first thread in
-// the queue using `condition_signal`. Alternatively, all threads
-// can be woken up using `condition_broadcast`.
-//
-// Condition variables are generally used to prevent spin checking
-// a condition and waiting for it to change. Instead, the thread
-// joins a wait-queue, and leave it up to another thread to wake
-// it up to continue processing. However sadly, in WebAssembly this
-// is not possible because with the atomic_wait and atomic_notify
-// instructions, which currently are not supported by any runtime
-// outside of the browser.
-//
-
-//
-// Represents a condition variable, with a mutex used to
-// protect the queue operations.
+#doc """
+    A condition variable is used to implement a queue of threads
+    waiting for a condition to be true. Each thread joins the queue
+    using `condition_wait`. Then, another thread can signal that
+    the condition has changed and can "wake up" the first thread in
+    the queue using `condition_signal`. Alternatively, all threads
+    can be woken up using `condition_broadcast`.
+   
+    Condition variables are generally used to prevent spin checking
+    a condition and waiting for it to change. Instead, the thread
+    joins a wait-queue, and leave it up to another thread to wake
+    it up to continue processing. However sadly, in WebAssembly this
+    is not possible because with the atomic_wait and atomic_notify
+    instructions, which currently are not supported by any runtime
+    outside of the browser.
+"""
 Condition_Variable :: struct {
     Node :: struct {
         semaphore : Semaphore;
@@ -32,25 +28,24 @@ Condition_Variable :: struct {
     queue: &Node;
 }
 
-//
-// Initializes a new condition variable.
+#doc "Initializes a new condition variable."
 condition_init :: (c: &Condition_Variable) {
     mutex_init(&c.mutex);
     c.queue = null;
 }
 
-//
-// Destroys a condition variable.
+#doc "Destroys a condition variable."
 condition_destroy :: (c: &Condition_Variable) {
     if c.queue != null do condition_broadcast(c);
 
     mutex_destroy(&c.mutex);
 }
 
-//
-// Enters the thread in the wait-queue of the condition variable.
-// If `m` is not null, the mutex will first be released before
-// entering the queue, and then relocked before returning.
+#doc """
+    Enters the thread in the wait-queue of the condition variable.
+    If `m` is not null, the mutex will first be released before
+    entering the queue, and then relocked before returning.
+"""
 condition_wait :: (c: &Condition_Variable, m: &Mutex) {
     node: Condition_Variable.Node;
 
@@ -65,8 +60,8 @@ condition_wait :: (c: &Condition_Variable, m: &Mutex) {
     if m != null do mutex_lock(m);
 }
 
-//
-// Wakes up one thread from the wait-queue.
+
+#doc "Wakes up one thread from the wait-queue."
 condition_signal :: (c: &Condition_Variable) {
     scoped_mutex(&c.mutex);
 
@@ -76,8 +71,8 @@ condition_signal :: (c: &Condition_Variable) {
     }
 }
 
-//
-// Wakes up all threads from the wait-queue.
+
+#doc "Wakes up all threads from the wait-queue."
 condition_broadcast :: (c: &Condition_Variable) {
     scoped_mutex(&c.mutex);
 
index fd9089979708a5efcaee42408dcb9bd4882ab7e8..1705612d9d459d01d0526e08a16033a2961f5ea3 100644 (file)
@@ -3,51 +3,51 @@ package core.sync
 use core.intrinsics.atomics
 use core.thread { Thread_ID }
 
-//
-// A mutex represents a resource that can only be held by one
-// thread at a time. It is used to create sections of code that
-// only one thread can be in at a time.
-//
-// Mutexes in WebAssembly are very cheap, because they simply
-// use the atomic_cmpxchg intrinsic to operate. This only uses
-// memory, so no real resource allocation is necessary.
-//
-// `lock` has two states: 0, and 1.
-//    0 means unlocked
-//    1 means locked
-//
-// To lock it:
-//    Try to store 1 if the value was already 0
-//    Otherwise, if it was already 1, wait until it goes to 0.
-//
-// To unlock it:
-//    Atomically set it to 0.
-//    Notify at most 1 other thread about this change.
-//
+#doc """
+    A mutex represents a resource that can only be held by one
+    thread at a time. It is used to create sections of code that
+    only one thread can be in at a time.
+   
+    Mutexes in WebAssembly are very cheap, because they simply
+    use the atomic_cmpxchg intrinsic to operate. This only uses
+    memory, so no real resource allocation is necessary.
+   
+    `lock` has two states: 0, and 1.
+    0 means unlocked, 1 means locked
+   
+    To lock it:
+        Try to store 1 if the value was already 0.
+        Otherwise, if it was already 1, wait until it goes to 0.
+   
+    To unlock it:
+        Atomically set it to 0.
+        Notify at most 1 other thread about this change.
+"""
 Mutex :: struct {
     lock  : i32;
     owner : Thread_ID;
 }
 
-//
-// Initializes a new mutex.
+
+#doc "Initializes a new mutex."
 mutex_init :: (m: &Mutex) {
     m.lock = 0;
     m.owner = -1;
 }
 
-//
-// Destroys a mutex.
+
+#doc "Destroys a mutex."
 mutex_destroy :: (m: &Mutex) {
     m.lock = -1;
     m.owner = -1;
 }
 
-//
-// Locks a mutex. If the mutex is currently held by another thread,
-// this function enters a spin loop until the mutex is unlocked.
-// In a JavaScript based implementation, the __atomic_wait intrinsic
-// is used to avoid having to spin loop.
+#doc """
+    Locks a mutex. If the mutex is currently held by another thread,
+    this function enters a spin loop until the mutex is unlocked.
+    In a JavaScript based implementation, the __atomic_wait intrinsic
+    is used to avoid having to spin loop.
+"""
 mutex_lock :: (m: &Mutex) {
     while __atomic_cmpxchg(&m.lock, 0, 1) == 1 {
         if m.owner == context.thread_id do return;
@@ -68,10 +68,11 @@ mutex_lock :: (m: &Mutex) {
     m.owner = context.thread_id;
 }
 
-//
-// Unlocks a mutex, if the calling thread currently holds the mutex.
-// In a JavaScript based implementation, the __atomic_notify intrinsic
-// is used to wake up one waiting thread.
+#doc """
+    Unlocks a mutex, if the calling thread currently holds the mutex.
+    In a JavaScript based implementation, the __atomic_notify intrinsic
+    is used to wake up one waiting thread.
+"""
 mutex_unlock :: (m: &Mutex) {
     if m.owner != context.thread_id do return;
     
@@ -83,17 +84,17 @@ mutex_unlock :: (m: &Mutex) {
     }
 }
 
-//
-// Helpful macro for making a particular block be protected by a macro.
-//
-//     m: sync.Mutx;
-//     sync.mutex_init(&m);
-//
-//     {
-//        sync.scoped_mutex(&m);
-//        // Everything here is done by one thread at a time.
-//     }
-//
+#doc """
+    Helpful macro for making a particular block be protected by a macro.
+   
+        m: sync.Mutx;
+        sync.mutex_init(&m);
+        
+        {
+           sync.scoped_mutex(&m);
+           // Everything here is done by one thread at a time.
+        }
+"""
 scoped_mutex :: macro (m: &Mutex) {
     ml :: mutex_lock
     mu :: mutex_unlock
@@ -102,17 +103,17 @@ scoped_mutex :: macro (m: &Mutex) {
     defer mu(m);
 }
 
-//
-// Abstracts the pattern decribed in scoped_mutex by automatically
-// calling scoped_mutex in the block of code given.
-//
-//     m: sync.Mutx;
-//     sync.mutex_init(&m);
-//
-//     sync.critical_section(&m) {
-//        // Everything here is done by one thread at a time.
-//     }
-//
+#doc """
+    Abstracts the pattern decribed in scoped_mutex by automatically
+    calling scoped_mutex in the block of code given.
+   
+        m: sync.Mutx;
+        sync.mutex_init(&m);
+        
+        sync.critical_section(&m) {
+           // Everything here is done by one thread at a time.
+        }
+"""
 critical_section :: macro (m: &Mutex, body: Code) -> i32 {
     scoped_mutex :: scoped_mutex;
     scoped_mutex(m);
index 8c182bda427a16597abb6756514137c3d4de92d2..1e711951899eb2ddbd63adb982287efe27502ed5 100644 (file)
@@ -5,8 +5,7 @@ package core.sync
 // function only once. It is simply a flag with a mutex.
 //
 
-//
-// Represents something will only happen once.
+#doc "Represents something will only happen once."
 Once :: struct {
     done: bool;
     mutex: Mutex;
@@ -14,8 +13,7 @@ Once :: struct {
 
 #inject Once.exec :: #match #local {}
 
-//
-// Run a function with no arguments once.
+#doc "Run a function with no arguments once."
 #overload
 Once.exec :: (o: &Once, f: () -> $R) {
     scoped_mutex(&o.mutex);
@@ -25,8 +23,7 @@ Once.exec :: (o: &Once, f: () -> $R) {
     f();
 }
 
-//
-// Run a function with one argument once.
+#doc "Run a function with one argument once."
 #overload
 Once.exec :: (o: &Once, ctx: $Ctx, f: (Ctx) -> $R) {
     scoped_mutex(&o.mutex);
index d7df97a18dd96939ac91c20cbec515116ceec025..3314e7b8bc8e5ef5438da92d4e612e7bd2b3976a 100644 (file)
@@ -2,44 +2,43 @@ package core.sync
 
 use core.intrinsics.atomics
 
-//
-// A semaphore represents a counter that can only be incremented
-// and decremented by one thread at a time. "Waiting" on a semaphore
-// means decrementing the counter by 1 if it is greater than 0, otherwise
-// waiting until the counter is incremented. "Posting" on a semaphore
-// means incrementing the counter by a certain value, in turn releasing
-// other threads that might have been waiting for the value to change.
-//
-// Semaphores are generally used for controlling access to shared
-// resources. For a contrived example, say only 4 threads can use
-// a given network connection at a time. A semaphore would be created
-// with a value of 4. When a thread wants to use the network connection,
-// it would use `semaphore_wait` to obtain the resource, or wait if
-// the network is currently available. When it is done using the
-// network, it would call `semaphore_post` to release the resource,
-// allowing another thread to use it.
-//
+#doc """
+    A semaphore represents a counter that can only be incremented
+    and decremented by one thread at a time. "Waiting" on a semaphore
+    means decrementing the counter by 1 if it is greater than 0, otherwise
+    waiting until the counter is incremented. "Posting" on a semaphore
+    means incrementing the counter by a certain value, in turn releasing
+    other threads that might have been waiting for the value to change.
+   
+    Semaphores are generally used for controlling access to shared
+    resources. For a contrived example, say only 4 threads can use
+    a given network connection at a time. A semaphore would be created
+    with a value of 4. When a thread wants to use the network connection,
+    it would use `semaphore_wait` to obtain the resource, or wait if
+    the network is currently available. When it is done using the
+    network, it would call `semaphore_post` to release the resource,
+    allowing another thread to use it.
+"""
 Semaphore :: struct {
     mutex   : Mutex;
     counter : i32;
 }
 
-//
-// Initializes a semaphore with the specified value.
+#doc "Initializes a semaphore with the specified value."
 semaphore_init :: (s: &Semaphore, value: i32) {
     s.counter = value;
 
     mutex_init(&s.mutex);
 }
 
-//
-// Destroys a semaphore.
+
+#doc "Destroys a semaphore."
 semaphore_destroy :: (s: &Semaphore) {
     mutex_destroy(&s.mutex);
 }
 
-//
-// Increment the counter in a semaphore by `count`.
+
+#doc "Increment the counter in a semaphore by `count`."
 semaphore_post :: (s: &Semaphore, count := 1) {
     if count == 0 do return;
     
@@ -54,8 +53,7 @@ semaphore_post :: (s: &Semaphore, count := 1) {
     }
 }
 
-//
-// Waits until the thread is able to decrement one from the semaphore.
+#doc "Waits until the thread is able to decrement one from the semaphore."
 semaphore_wait :: (s: &Semaphore) {
     while true {
         mutex_lock(&s.mutex);
index 327ac513d63c952d9347cbc17c9a0509b7f95abc..cf0b69cb85c068f78d213a1ced392964b59c8449 100644 (file)
@@ -9,24 +9,26 @@ use core.intrinsics.atomics
     thread_map     : Map(Thread_ID, &Thread);
 }
 
-//
-// An id of a thread.
+
+#doc "An id of a thread."
 Thread_ID :: #type i32
 
-//
-// Represents a thread. Currently, this is very simple; just the id
-// of the thread and whether or not it is alive.
+#doc """
+    Represents a thread. Currently, this is very simple; just the id
+    of the thread and whether or not it is alive.
+"""
 Thread :: struct {
     id    : Thread_ID;
     alive : bool;
 }
 
-//
-// Spawns a new thread using the runtime.__spawn_thread function.
-// The primary job of this function is to create the thread-local
-// storage and stack for the new thread, and pass those on.
-// Currently the stack size is not controllable, but that could
-// be remedied.
+#doc """
+    Spawns a new thread using the runtime.__spawn_thread function.
+    The primary job of this function is to create the thread-local
+    storage and stack for the new thread, and pass those on.
+    Currently the stack size is not controllable, but that could
+    be remedied.
+"""
 spawn :: (t: &Thread, data: &$T, func: (&T) -> void) {
     sync.scoped_mutex(&thread_mutex);
 
@@ -44,10 +46,11 @@ spawn :: (t: &Thread, data: &$T, func: (&T) -> void) {
     runtime.platform.__spawn_thread(t.id, tls_base, stack_base, func, data);
 }
 
-//
-// Waits for a thread to finish before returning.
-// If the thread was not alive in the first place,
-// immediately return.
+#doc """
+    Waits for a thread to finish before returning.
+    If the thread was not alive in the first place,
+    immediately return.
+"""
 join :: (t: &Thread) {
     while t.alive {
         #if runtime.Wait_Notify_Available {
@@ -59,9 +62,10 @@ join :: (t: &Thread) {
     }
 }
 
-//
-// Forcefully kill a thread using runtime.__kill_thread.
-// Does nothing if the thread was not alive.
+#doc """
+    Forcefully kill a thread using runtime.__kill_thread.
+    Does nothing if the thread was not alive.
+"""
 kill :: (t: &Thread) -> i32 {
     if !t.alive do return -1;
 
@@ -71,16 +75,18 @@ kill :: (t: &Thread) -> i32 {
     return 1;
 }
 
-//
-// Special procedure that should only be called once globally
-// that initialize the map of thread ids to thread data.
+#doc """
+    Special procedure that should only be called once globally
+    that initialize the map of thread ids to thread data.
+"""
 __initialize :: () {
     thread_map->init();
 }
 
-//
-// Special procedure that is called when a thread exits,
-// or by kill() above.
+#doc """
+    Special procedure that is called when a thread exits,
+    or by kill() above.
+"""
 __exited :: (id: i32) {
     sync.scoped_mutex(&thread_mutex);