more standard library documentation
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 14 Feb 2023 03:58:55 +0000 (21:58 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 14 Feb 2023 03:58:55 +0000 (21:58 -0600)
core/intrinsics/onyx.onyx
core/misc/arg_parse.onyx
core/misc/method_ops.onyx
core/onyx/cptr.onyx
core/threads/thread.onyx

index ff06000579f4ab5d1b12197ee098f4bf793b0a78..5476a04684a555dc100167630d1a7e3bb4e89b10 100644 (file)
@@ -1,7 +1,14 @@
 package core.intrinsics.onyx
 
+//
+// Special intrinsic function that initializes a value.
+// This is generally used on structure to execute their
+// default initializer expressions.
 __initialize :: (val: ^$T)      -> void #intrinsic ---
 
+//
+// Helpful macro to create an initialized value.
+// Mostly pointless now that T.{} does the same thing.
 init :: macro ($T: type_expr) -> T {
     __initialize :: __initialize
 
index 623e857c542b1a2da0c01b4f352521af4ddac65e..032b4b0fafad9824950b7c9d53f558413d107428 100644 (file)
@@ -1,5 +1,27 @@
 package core.arg_parse
 
+//
+// This is currently a very basic argument parsing library.
+// The options are given through a structure like so:
+//
+//     Options :: struct {
+//         @"--option_1"
+//         option_1: str;
+//     
+//         @"--option_2", "-o2"
+//         option_2: bool;
+//     }
+//
+//     main :: (args) => {
+//         o: Options;
+//         arg_parse.arg_parse(args, ^o);
+//     }
+//
+// Options that are strings and integers expect an argument after
+// them to specify their value. Options that are bool default to
+// false and are true if one or more of the option values are present.
+//
+
 use core
 
 arg_parse :: (c_args: [] cstr, output: any) -> bool {
index 9862aea839c71ad11e518c822f0db4ce457abb97..1e347dec8bf8adeb0a87b3c30ba549a2e9b2e80d 100644 (file)
@@ -1,5 +1,24 @@
 package core
 
+//
+// This file defines an optional language feature called method operators.
+// Instead of defining an operator overload using the #operator directive,
+// one can simply define a __op method in the structure to define how to
+// perform the operations. For example,
+//
+//     Vec2 :: struct { x, y: f32 }
+//
+//     #inject Vec2 {
+//         __add :: (v1, v2: Vec2) => Vec2.{ v1.x + v2.x, v1.y + v2.y };
+//     }
+//
+// This is an optional language feature because it currently significantly
+// affects compile-time, on average adding 30% to the total compilation time.
+// To enable this feature, add this somewhere:
+//
+//     #inject runtime.vars.Onyx_Enable_Operator_Methods :: true
+//
+
 #local {
     __HasEqMethod     :: interface (t: $T, r: $R) { T.__eq(t, r); }
     __HasNeMethod     :: interface (t: $T, r: $R) { T.__ne(t, r); }
index a27aab1d20a03880b98032760515352bf31915a4..80fb096cd752c884943decb92eb30b96cdeefba9 100644 (file)
@@ -1,22 +1,42 @@
 package core
 
+//
+// Sometimes when interfacing with libraries from C, it is really helpful
+// to be able to represent pointers to things outside of the bounds of the
+// WASM memory. For one concrete example, glGetString takes an enum and
+// procudes a character pointer to a static string with that enum's name.
+// Without this library, it would be impossible to access this memory,
+// without first copying it into the WASM memory. That requires a lot of
+// overhead, so instead this library allows Onxy to access memory outside
+// the normal bounds.
+//
+// cptr(T) is a C-pointer to a value of type T. It has a couple useful
+// methods, namely: read(), extract_str(), and to_rawptr().
+//
+
 @conv.Custom_Format.{ #solidify cptr.format {T=T} }
 cptr :: struct (T: type_expr) {
     data: u64;
 }
 
 #inject cptr {
+    //
+    // Creates a new C-pointer from an Onyx pointer.
     make :: macro (ptr: ^$T) -> cptr(T) {
         __cptr_make :: __cptr_make
         return .{ __cptr_make(ptr) };
     }
 
+    //
+    // Extract the data out of a C pointer into a buffer in the Onyx memory.
     read :: (this: cptr($T)) -> T {
         buf: [sizeof T] u8;
         __cptr_read(this.data, ~~buf, sizeof T);
         return *cast(^T) buf;
     }
 
+    //
+    // Helper procedures for quickly reading an integer of various sizes.
     read_u8  :: (this: cptr(u8))  => __cptr_read_u8(this.data);
     read_u16 :: (this: cptr(u16)) => __cptr_read_u16(this.data);
     read_u32 :: (this: cptr(u32)) => __cptr_read_u32(this.data);
@@ -26,6 +46,7 @@ cptr :: struct (T: type_expr) {
     read_i32 :: (this: cptr(i32)) => cast(i32) __cptr_read_u32(this.data);
     read_i64 :: (this: cptr(i64)) => cast(i64) __cptr_read_u64(this.data);
 
+    //
     // When given a non-zero-sized dest, this procedure
     // fills the dest buffer with the contents of the string
     // up to the number bytes in the dest buffer. This
@@ -34,6 +55,9 @@ cptr :: struct (T: type_expr) {
     // using __cptr_read_u8 would be slow compared to strlen().
     extract_str :: (this: cptr(u8), dest: [] u8) => __cptr_extract_str(this.data, dest);
 
+    //
+    // This procedure attempts to convert a C-pointer back into an
+    // Onyx pointer, if the pointer lives with the Onyx memory space.
     to_rawptr :: (this: cptr($T)) -> ^T {
         // I'm treating NULL as more of a concept, than as an actual value here,
         // because if something returns a NULL pointer, it should logically map
@@ -54,6 +78,9 @@ cptr :: struct (T: type_expr) {
     }
 }
 
+
+//
+// Allows for pointer addition.
 #operator + macro (p: cptr($T), v: i32) -> cptr(T) {
     return .{ p.data + ~~(v * sizeof T) };
 }
index 3e7823a253e158b5823a36ef2609a4c2ef5e0689..c234a834d4e2bf144e157fc45934595cf377492e 100644 (file)
@@ -9,13 +9,24 @@ use core.intrinsics.atomics
     thread_map     : Map(Thread_ID, ^Thread);
 }
 
+//
+// 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.
 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.
 spawn :: (t: ^Thread, data: ^$T, func: (^T) -> void) {
     sync.scoped_mutex(^thread_mutex);
 
@@ -33,6 +44,10 @@ spawn :: (t: ^Thread, data: ^$T, func: (^T) -> void) {
     runtime.__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.
 join :: (t: ^Thread) {
     while t.alive {
         #if runtime.Wait_Notify_Available {
@@ -44,6 +59,9 @@ join :: (t: ^Thread) {
     }
 }
 
+//
+// 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;
 
@@ -53,10 +71,16 @@ 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.
 __initialize :: () {
     thread_map->init();
 }
 
+//
+// Special procedure that is called when a thread exits,
+// or by kill() above.
 __exited :: (id: i32) {
     sync.scoped_mutex(^thread_mutex);