added `#this_package`; cleaned up code with new feature
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 31 Jan 2023 21:13:10 +0000 (15:13 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 31 Jan 2023 21:13:10 +0000 (15:13 -0600)
compiler/include/astnodes.h
compiler/src/astnodes.c
compiler/src/checker.c
compiler/src/clone.c
compiler/src/entities.c
compiler/src/parser.c
compiler/src/symres.c
core/container/array.onyx
core/container/iter.onyx
core/container/optional.onyx

index f70ae309d2426a174feb7435a505a5d7d0666192..b9b06986edc58f13c6cd628e218a36b6e4b03b94 100644 (file)
@@ -44,6 +44,7 @@
     NODE(DirectiveRemove)      \
     NODE(DirectiveFirst)       \
     NODE(DirectiveExportName)  \
+    NODE(DirectiveThisPackage) \
                                \
     NODE(Return)               \
     NODE(Jump)                 \
@@ -221,6 +222,7 @@ typedef enum AstKind {
     Ast_Kind_Directive_Remove,
     Ast_Kind_Directive_First,
     Ast_Kind_Directive_Export_Name,
+    Ast_Kind_Directive_This_Package,
     Ast_Kind_Call_Site,
 
     Ast_Kind_Code_Block,
index 2f1e7ddea863fe7947de7cf49b9f933ad01cc2ba..d35b4d5c62be234231d6dc1a03d063663d8f3df4 100644 (file)
@@ -99,6 +99,7 @@ static const char* ast_node_names[] = {
     "REMOVE",
     "FIRST",
     "EXPORT NAME",
+    "THIS PACKAGE",
     "CALL SITE",
 
     "CODE BLOCK",
index c0f58c246b8cbe037c8d1ef0d6c01abb99057beb..2d35aa34de017e3f38223d1d35cf6180af0e8208 100644 (file)
@@ -2171,6 +2171,10 @@ CheckStatus check_expression(AstTyped** pexpr) {
             if (expr->type == NULL) YIELD(expr->token->pos, "Waiting to know string literals type. This is a weird one...") ;
             break;
 
+        case Ast_Kind_Directive_This_Package:
+            YIELD(expr->token->pos, "Waiting to resolve #this_package.");
+            break;
+
         case Ast_Kind_File_Contents: break;
         case Ast_Kind_Overloaded_Function: break;
         case Ast_Kind_Enum_Value: break;
index 6b708f8e781ec26e6c54c57818348c305a2af230..627319470dcbab87e3b39ef759e4abe2f77225e4 100644 (file)
@@ -29,6 +29,7 @@ static inline b32 should_clone(AstNode* node) {
         case Ast_Kind_Basic_Type:
         case Ast_Kind_Enum_Type:
         case Ast_Kind_Enum_Value:
+        case Ast_Kind_Directive_This_Package: // Not copied, because it should depend on where it was written, not where a macro/polymorphic function was expanded.
             return 0;
 
         default: return 1;
index f679db1f41b201f41ed108b34d334c5cced7d19f..745ae4ae964c833fef96b8304df614f97b5907a7 100644 (file)
@@ -368,6 +368,7 @@ void add_entities_for_node(bh_arr(Entity *) *target_arr, AstNode* node, Scope* s
         case Ast_Kind_Directive_Operator:
         case Ast_Kind_Directive_Init:
         case Ast_Kind_Directive_Library:
+        case Ast_Kind_Directive_This_Package:
         case Ast_Kind_Injection: {
             ent.type = Entity_Type_Process_Directive;
             ent.expr = (AstTyped *) node;
index ba93e0a401ca270ab9c1d89daf83d6e2739bb452..9c8ff9cdd940c849e55f9677cd7735f154b5e69d 100644 (file)
@@ -791,6 +791,15 @@ static AstTyped* parse_factor(OnyxParser* parser) {
                 retval = (AstTyped *) export_name;
                 break;
             }
+            else if (parse_possible_directive(parser, "this_package")) {
+                AstPackage *this_package = make_node(AstPackage, Ast_Kind_Directive_This_Package);
+                this_package->token = parser->curr - 1;
+                this_package->type_node = builtin_package_id_type;
+                ENTITY_SUBMIT(this_package);
+
+                retval = (AstTyped *) this_package;
+                break;
+            }
 
             onyx_report_error(parser->curr->pos, Error_Critical, "Invalid directive in expression.");
             return NULL;
index 38e848953fe276558353ec41d8e1001282a5ad26..fbca2f71f4735e8a143a254069524299c9f7aedc 100644 (file)
@@ -7,13 +7,15 @@
 // :EliminatingSymres - notes the places where too much work is being done in symbol resolution
 
 // Variables used during the symbol resolution phase.
-static Scope*       curr_scope    = NULL;
+static Scope*       current_scope    = NULL;
 static b32 report_unresolved_symbols = 1;
 static b32 resolved_a_symbol         = 0;
 
 // Everything related to waiting on is imcomplete at the moment.
 static Entity* waiting_on         = NULL;
 
+static Entity* current_entity = NULL;
+
 #define SYMRES(kind, ...) do { \
     SymresStatus ss = symres_ ## kind (__VA_ARGS__); \
     if (ss > Symres_Errors_Start) return ss;         \
@@ -73,21 +75,21 @@ static SymresStatus symres_constraint(AstConstraint* constraint);
 static SymresStatus symres_polyquery(AstPolyQuery *query);
 
 static void scope_enter(Scope* new_scope) {
-    curr_scope = new_scope;
+    current_scope = new_scope;
 }
 
 static void scope_leave() {
-    curr_scope = curr_scope->parent;
+    current_scope = current_scope->parent;
 }
 
 static SymresStatus symres_symbol(AstNode** symbol_node) {
     OnyxToken* token = (*symbol_node)->token;
-    AstNode* res = symbol_resolve(curr_scope, token);
+    AstNode* res = symbol_resolve(current_scope, token);
 
     if (!res) { // :SymresStall
         if (report_unresolved_symbols) {
             token_toggle_end(token);
-            char *closest = find_closest_symbol_in_scope_and_parents(curr_scope, token->text);
+            char *closest = find_closest_symbol_in_scope_and_parents(current_scope, token->text);
             token_toggle_end(token);
 
             if (closest) onyx_report_error(token->pos, Error_Critical, "Unable to resolve symbol '%b'. Did you mean '%s'?", token->text, token->length, closest);
@@ -261,7 +263,7 @@ static SymresStatus symres_local(AstLocal** local) {
     SYMRES(type, &(*local)->type_node);
 
     if ((*local)->token != NULL)
-        symbol_introduce(curr_scope, (*local)->token, (AstNode *) *local);
+        symbol_introduce(current_scope, (*local)->token, (AstNode *) *local);
 
     return Symres_Success;
 }
@@ -632,9 +634,9 @@ static SymresStatus symres_expression(AstTyped** expr) {
             break;
 
         case Ast_Kind_Do_Block: {
-            Scope* old_curr_scope = curr_scope;
+            Scope* old_current_scope = current_scope;
             SYMRES(block, ((AstDoBlock *) *expr)->block);
-            curr_scope = old_curr_scope;
+            current_scope = old_current_scope;
             break;
         }
 
@@ -691,7 +693,7 @@ static SymresStatus symres_if(AstIfWhile* ifnode) {
 
     } else {
         if (ifnode->initialization != NULL) {
-            ifnode->scope = scope_create(context.ast_alloc, curr_scope, ifnode->token->pos);
+            ifnode->scope = scope_create(context.ast_alloc, current_scope, ifnode->token->pos);
             scope_enter(ifnode->scope);
 
             SYMRES(statement_chain, &ifnode->initialization);
@@ -711,7 +713,7 @@ static SymresStatus symres_if(AstIfWhile* ifnode) {
 
 static SymresStatus symres_while(AstIfWhile* whilenode) {
     if (whilenode->initialization != NULL) {
-        whilenode->scope = scope_create(context.ast_alloc, curr_scope, whilenode->token->pos);
+        whilenode->scope = scope_create(context.ast_alloc, current_scope, whilenode->token->pos);
         scope_enter(whilenode->scope);
 
         SYMRES(statement_chain, &whilenode->initialization);
@@ -728,7 +730,7 @@ static SymresStatus symres_while(AstIfWhile* whilenode) {
 }
 
 static SymresStatus symres_for(AstFor* fornode) {
-    fornode->scope = scope_create(context.ast_alloc, curr_scope, fornode->token->pos);
+    fornode->scope = scope_create(context.ast_alloc, current_scope, fornode->token->pos);
     scope_enter(fornode->scope);
     SYMRES(expression, &fornode->iter);
     SYMRES(local, &fornode->var);
@@ -751,7 +753,7 @@ static SymresStatus symres_case(AstSwitchCase *casenode) {
 
 static SymresStatus symres_switch(AstSwitch* switchnode) {
     if (switchnode->initialization != NULL) {
-        switchnode->scope = scope_create(context.ast_alloc, curr_scope, switchnode->token->pos);
+        switchnode->scope = scope_create(context.ast_alloc, current_scope, switchnode->token->pos);
         scope_enter(switchnode->scope);
 
         SYMRES(statement_chain, &switchnode->initialization);
@@ -793,7 +795,7 @@ static SymresStatus symres_use(AstUse* use) {
         SYMRES(package, package);
 
         if (!use->entity) {
-            add_entities_for_node(NULL, (AstNode *) use, curr_scope, NULL);
+            add_entities_for_node(NULL, (AstNode *) use, current_scope, NULL);
         }
 
         package_track_use_package(package->package, use->entity);
@@ -820,14 +822,14 @@ static SymresStatus symres_use(AstUse* use) {
     }
 
     if (used_scope) {
-        if (used_scope == curr_scope) return Symres_Success;
+        if (used_scope == current_scope) return Symres_Success;
 
         if (use->only == NULL) {
             OnyxFilePos pos = { 0 };
             if (use->token != NULL)
                 pos = use->token->pos;
 
-            scope_include(curr_scope, used_scope, pos);
+            scope_include(current_scope, used_scope, pos);
 
         } else {
             bh_arr_each(QualifiedUse, qu, use->only) {
@@ -843,7 +845,7 @@ static SymresStatus symres_use(AstUse* use) {
                     }
                 }
 
-                symbol_introduce(curr_scope, qu->as_name, thing);
+                symbol_introduce(current_scope, qu->as_name, thing);
             }
         }
 
@@ -871,7 +873,7 @@ static SymresStatus symres_use(AstUse* use) {
         fori (i, 0, shlen(st->Struct.members)) {
             StructMember* value = st->Struct.members[i].value;
             AstFieldAccess* fa = make_field_access(context.ast_alloc, use_expr, value->name);
-            symbol_raw_introduce(curr_scope, value->name, use->token->pos, (AstNode *) fa);
+            symbol_raw_introduce(current_scope, value->name, use->token->pos, (AstNode *) fa);
         }
 
         return Symres_Success;
@@ -993,13 +995,13 @@ static SymresStatus symres_statement_chain(AstNode** walker) {
 static SymresStatus symres_block(AstBlock* block) {
     if (block->rules & Block_Rule_New_Scope) {
         if (block->scope == NULL)
-            block->scope = scope_create(context.ast_alloc, curr_scope, block->token->pos);
+            block->scope = scope_create(context.ast_alloc, current_scope, block->token->pos);
 
         scope_enter(block->scope);
     }
 
     if (block->binding_scope != NULL)
-        scope_include(curr_scope, block->binding_scope, block->token->pos);
+        scope_include(current_scope, block->binding_scope, block->token->pos);
 
     if (block->body) {
         AstNode** start = &block->body;
@@ -1044,7 +1046,7 @@ SymresStatus symres_function_header(AstFunction* func) {
     func->flags |= Ast_Flag_Comptime;
 
     if (func->scope == NULL)
-        func->scope = scope_create(context.ast_alloc, curr_scope, func->token->pos);
+        func->scope = scope_create(context.ast_alloc, current_scope, func->token->pos);
 
     if (func->constraints.constraints != NULL && func->constraints.constraints_met == 0) {
         bh_arr_each(AstConstraint *, constraint, func->constraints.constraints) {
@@ -1066,7 +1068,7 @@ SymresStatus symres_function_header(AstFunction* func) {
     }
 
     bh_arr_each(AstParam, param, func->params) {
-        symbol_introduce(curr_scope, param->local->token, (AstNode *) param->local);
+        symbol_introduce(current_scope, param->local->token, (AstNode *) param->local);
     }
 
     bh_arr_each(AstParam, param, func->params) {
@@ -1086,8 +1088,8 @@ SymresStatus symres_function_header(AstFunction* func) {
             // what the ramifications of that is.
             assert((*node)->kind == Ast_Kind_Static_If || (*node)->kind == Ast_Kind_File_Contents);
 
-            // Need to curr_scope->parent because curr_scope is the function body scope.
-            Scope *scope = curr_scope->parent;
+            // Need to current_scope->parent because current_scope is the function body scope.
+            Scope *scope = current_scope->parent;
 
             if ((*node)->kind == Ast_Kind_Static_If) {
                 AstIf *static_if = (AstIf *) *node;
@@ -1164,7 +1166,7 @@ SymresStatus symres_function(AstFunction* func) {
                     fori (i, 0, shlen(st->Struct.members)) {
                         StructMember* value = st->Struct.members[i].value;
                         AstFieldAccess* fa = make_field_access(context.ast_alloc, (AstTyped *) param->local, value->name);
-                        symbol_raw_introduce(curr_scope, value->name, param->local->token->pos, (AstNode *) fa);
+                        symbol_raw_introduce(current_scope, value->name, param->local->token->pos, (AstNode *) fa);
                     }
 
                     param->use_processed = 1;
@@ -1238,7 +1240,7 @@ static SymresStatus symres_enum(AstEnumType* enum_node) {
 
     if (enum_node->scope == NULL) {
         enum_node->backing_type = type_build_from_ast(context.ast_alloc, enum_node->backing);
-        enum_node->scope = scope_create(context.ast_alloc, curr_scope, enum_node->token->pos);
+        enum_node->scope = scope_create(context.ast_alloc, current_scope, enum_node->token->pos);
 
         type_build_from_ast(context.ast_alloc, (AstType *) enum_node);
     }
@@ -1359,7 +1361,7 @@ static SymresStatus symres_struct_defaults(AstType* t) {
 
 static SymresStatus symres_polyproc(AstFunction* pp) {
     pp->flags |= Ast_Flag_Comptime;
-    pp->parent_scope_of_poly_proc = curr_scope;
+    pp->parent_scope_of_poly_proc = current_scope;
     return Symres_Success;
 }
 
@@ -1507,6 +1509,13 @@ static SymresStatus symres_process_directive(AstNode* directive) {
             add_entities_for_node(NULL, (AstNode *) binding, scope, pac);
             return Symres_Complete;
         }
+
+        case Ast_Kind_Directive_This_Package: {
+            AstPackage *package = (AstPackage *) directive;
+            package->kind = Ast_Kind_Package;
+            package->package = current_entity->package;
+            return Symres_Complete;
+        }
     }
 
     return Symres_Success;
@@ -1601,7 +1610,7 @@ static SymresStatus symres_polyquery(AstPolyQuery *query) {
             if (pp->kind == PPK_Baked_Value && pp->idx == idx) goto skip_introducing_symbol;
         }
 
-        symbol_introduce(curr_scope, param->local->token, (AstNode *) param->local);
+        symbol_introduce(current_scope, param->local->token, (AstNode *) param->local);
 
     skip_introducing_symbol:
         idx++;
@@ -1627,7 +1636,7 @@ static SymresStatus symres_polyquery(AstPolyQuery *query) {
 
 static SymresStatus symres_foreign_block(AstForeignBlock *fb) {
     if (fb->scope == NULL)
-        fb->scope = scope_create(context.ast_alloc, curr_scope, fb->token->pos);
+        fb->scope = scope_create(context.ast_alloc, current_scope, fb->token->pos);
 
     bh_arr_each(Entity *, pent, fb->captured_entities) {
         Entity *ent = *pent;
@@ -1705,6 +1714,7 @@ static SymresStatus symres_file_contents(AstFileContents* fc) {
 }
 
 void symres_entity(Entity* ent) {
+    current_entity = ent;
     if (ent->scope) scope_enter(ent->scope);
 
     report_unresolved_symbols = context.cycle_detected;
@@ -1714,7 +1724,7 @@ void symres_entity(Entity* ent) {
 
     switch (ent->type) {
         case Entity_Type_Binding: {
-            symbol_introduce(curr_scope, ent->binding->token, ent->binding->node);
+            symbol_introduce(current_scope, ent->binding->token, ent->binding->node);
             track_declaration_for_tags((AstNode *) ent->binding);
 
             package_reinsert_use_packages(ent->package);
@@ -1777,5 +1787,6 @@ void symres_entity(Entity* ent) {
         ent->state = next_state;
     }
 
-    curr_scope = NULL;
+    current_scope = NULL;
+    current_entity = NULL;
 }
index 960016fd71cb28b2a732400166980bdc6c7c5b8d..725f021ff6c3d0816ccb2a2ce37e84db764a9025 100644 (file)
@@ -320,6 +320,12 @@ contains :: #match #locked {
     }
 }
 
+// Tests if array is empty.
+// Normally this is unneeded, as arrays have a 'truthiness'
+// that depends on their count. For example, instead of saying:
+//     if array.empty(arr) { ... }
+// You can simply say:
+//     if !arr { ... }
 empty :: (arr: [] $T) => arr.count == 0;
 
 // Uses '+' to sum.
@@ -329,12 +335,16 @@ sum :: (arr: [] $T, start: T = 0) -> T {
     return sum;
 }
 
+// Uses '*' to multiply.
 product :: (arr: [] $T, start: T = 1) -> T {
     prod := start;
     for it: arr do prod *= it;
     return prod;
 }
 
+// Uses '+' to add the elements together.
+// Then use '/ i32' to divide by the number of elements.
+// Both of these are assumed to work.
 average :: (arr: [] $T) -> T {
     sum := cast(T) 0;
     for it: *arr do sum += it;
@@ -364,7 +374,8 @@ sort :: (arr: [] $T, cmp: (T, T) -> i32) -> [] T {
         x := arr.data[i];
         j := i - 1;
 
-        // @ShortCircuitLogicalOps // This is written this way because '&&' does not short circuit right now.
+        // @ShortCircuitLogicalOps
+        // This is written this way because '&&' does not short circuit right now.
         while j >= 0 {
             if cmp(arr.data[j], x) > 0 {
                 arr.data[j + 1] = arr.data[j];
@@ -490,23 +501,10 @@ fold :: macro (arr: [] $T, init: $R, body: Code) -> R {
     return acc;
 }
 
-/*
-map :: #match #locked {
-    macro (arr: [] $T, f: (^T) -> void)                do for ^it: arr do f(it);,
-    macro (arr: [] $T, f: (T) -> T)                    do for ^it: arr do *it = f(*it);,
-    macro (arr: [] $T, body: Code)                     do for ^it: arr do #unquote body;,
-    macro (arr: [] $T, data: $R, f: (^T, R) -> void)   do for ^it: arr do f(it, data);,
-    macro (arr: [] $T, data: $R, f: (T, R) -> T)       do for ^it: arr do *it = f(*it, data);,
-}
-*/
-
 every :: #match #local {}
 
 #overload
-every :: macro (arr: [] $T, predicate: (T) -> bool) -> bool {
-    every :: every
-    return every(arr, #(predicate(it)));
-}
+every :: macro (arr: [] $T, predicate: (T) -> bool) => #this_package.every(arr, #(predicate(it)));
 
 #overload
 every :: macro (arr: [] $T, predicate_body: Code) -> bool {
@@ -519,10 +517,7 @@ every :: macro (arr: [] $T, predicate_body: Code) -> bool {
 some :: #match #local {}
 
 #overload
-some :: macro (arr: [] $T, predicate: (T) -> bool) -> bool {
-    some :: some
-    return every(arr, #(predicate(it)));
-}
+some :: macro (arr: [] $T, predicate: (T) -> bool) => #this_package.some(arr, #(predicate(it)));
 
 #overload
 some :: macro (arr: [] $T/type_is_struct, predicate_body: Code) -> bool {
@@ -629,17 +624,16 @@ first :: #match #locked {
     }
 }
 
-count_where :: #match #locked {
-    macro (arr: [] $T, predicate: (T) -> bool) -> u32 {
-        count_where :: count_where
-        return count_where(arr, #(predicate(it)));
-    },
+count_where :: #match #local {}
 
-    macro (arr: [] $T, predicate_body: Code) -> u32 {
-        count: u32 = 0;
-        for arr {
-            if #unquote predicate_body do count += 1;
-        }
-        return count;
+#overload
+count_where :: macro (arr: [] $T, predicate: (T) -> bool) => #this_package.count_where(arr, #(predicate(it)));
+
+#overload
+count_where :: macro (arr: [] $T, predicate_body: Code) -> u32 {
+    count: u32 = 0;
+    for arr {
+        if #unquote predicate_body do count += 1;
     }
+    return count;
 }
index 4015d4e3356e4f5fe8b09595620a3a84b8d1b7fd..93d63bd43ee8341b30dbc5ca06f6616a46369488 100644 (file)
@@ -527,11 +527,8 @@ const :: (value: $T) -> Iterator(T) {
 enumerate :: #match #local {}
 
 #overload
-enumerate :: macro (it: $T/Iterable, start_index: i32 = 0) => {
-    as_iter :: as_iter
-    enumerate :: enumerate
-    return enumerate(as_iter(it), start_index);
-}
+enumerate :: macro (it: $T/Iterable, start_index: i32 = 0) =>
+    #this_package.enumerate(#this_package.as_iter(it), start_index);
 
 #overload
 enumerate :: (it: Iterator($T), start_index: i32 = 0) -> Iterator(Enumeration_Value(T)) {
@@ -722,10 +719,8 @@ fold :: #match #local {}
 
 // @Cleanup // some way to shorten this would be nice
 #overload
-fold :: macro (it: $T/Iterable, init: $R, combine: $S) => {
-    fold :: fold
-    return fold(as_iter(it), init, combine);
-}
+fold :: macro (it: $T/Iterable, init: $R, combine: $S) =>
+    #this_package.fold(#this_package.as_iter(it), init, combine);
 
 #overload
 fold :: (it: Iterator($T), initial_value: $R, combine: (T, R) -> R) -> R {
@@ -739,10 +734,8 @@ fold :: (it: Iterator($T), initial_value: $R, combine: (T, R) -> R) -> R {
 count :: #match #local {}
 
 #overload
-count :: macro (it: $T/Iterable, cond: $F) => {
-    count :: count
-    return count(as_iter(it), cond);
-}
+count :: macro (it: $T/Iterable, cond: $F) =>
+    #this_package.count(#this_package.as_iter(it), cond);
 
 #overload
 count :: (it: Iterator($T), cond: (T) -> bool) -> i32 {
@@ -754,11 +747,8 @@ count :: (it: Iterator($T), cond: (T) -> bool) -> i32 {
 some :: #match #local {}
 
 #overload
-some :: macro (it: $T/Iterable, cond: $F) => {
-    some :: some
-    as_iter :: as_iter
-    return some(as_iter(it), cond);
-}
+some :: macro (it: $T/Iterable, cond: $F) =>
+    #this_package.some(#this_package.as_iter(it), cond);
 
 #overload
 some :: (it: Iterator($T), cond: (T) -> bool) -> bool {
@@ -769,11 +759,8 @@ some :: (it: Iterator($T), cond: (T) -> bool) -> bool {
 every :: #match #local {}
 
 #overload
-every :: macro (it: $T/Iterable, cond: $F) => {
-    every :: every
-    as_iter :: as_iter
-    return every(as_iter(it), cond);
-}
+every :: macro (it: $T/Iterable, cond: $F) =>
+    #this_package.every(#this_package.as_iter(it), cond);
 
 #overload
 every :: (it: Iterator($T), cond: (T) -> bool) -> bool {
@@ -852,11 +839,8 @@ comp :: macro (i: Iterator($V), value: Code) => {
 }
 
 #overload
-comp :: macro (i: $I/Iterable, value: Code) => {
-    as_iter :: as_iter
-    comp        :: comp
-    return comp(as_iter(i), value);
-}
+comp :: macro (i: $I/Iterable, value: Code) =>
+    #this_package.comp(#this_package.as_iter(i), value);
 
 
 //
@@ -905,11 +889,8 @@ generator_no_copy :: (ctx: ^$Ctx, gen: (^Ctx) -> ($T, bool), close: (^Ctx) -> vo
     distributor :: #match #local {}
 
     #overload
-    distributor :: macro (it: $T/Iterable) => {
-        distributor :: distributor;
-        as_iter :: as_iter;
-        return distributor(as_iter(it));
-    }
+    distributor :: macro (it: $T/Iterable) =>
+        #this_package.distributor(#this_package.as_iter(it));
 
     #overload
     distributor :: (it: Iterator) -> Iterator(it.Iter_Type) {
@@ -952,20 +933,20 @@ generator_no_copy :: (ctx: ^$Ctx, gen: (^Ctx) -> ($T, bool), close: (^Ctx) -> vo
 
     #overload
     parallel_for :: macro (iterable: $I/Iterable, thread_count: u32, thread_data: ^$Ctx, body: Code) {
-        parallel_for :: parallel_for;
-        as_iter  :: as_iter;
-
-        parallel_for(as_iter(iterable), thread_count, thread_data, body);
+        #this_package.parallel_for(
+            #this_package.as_iter(iterable),
+            thread_count,
+            thread_data,
+            body
+        );
     }
 
     #overload
     parallel_for :: macro (iter: Iterator($T), thread_count: u32, thread_data: ^$Ctx, body: Code) {
         use core {thread, alloc}
-        distributor :: distributor;
-        as_iter :: as_iter;
 
         if thread_count != 0 {
-            dist := distributor(iter);
+            dist := #this_package.distributor(iter);
             t_data := ^.{iter = ^dist, data = thread_data};
 
             threads := alloc.array_from_stack(thread.Thread, thread_count - 1);
index 0d51e3d271695f0de6e9de0b258bd2a8329738ec..36283f4051c194f3c69cbfbce7aae59323a85ca4 100644 (file)
@@ -1,5 +1,20 @@
 package core
 
+// Optional is helper type that encapsulates the idea of an empty
+// value, without resorting to null pointers. Optionals are usually
+// provided as a return value from procedures that could fail. There
+// are several helper methods that you can use to make it easier to
+// work with optionals.
+
+// Because Optional is a newer addition to the standard library of Onyx,
+// much of the standard library does not use it. Currently it is only
+// used by Map and Set in their `get_opt` function. In theory, it should
+// be used in many more places, instead of returning `.{}`.
+
+// Optional(T) is a simply a structure with a flag of whether or not
+// the optional contains a value. When the `has_value` is true, the
+// `value` member will be populated with an initialized value.
+// Otherwise, `value` should be a zeroed buffer.
 @conv.Custom_Format.{ #solidify format {T=Value_Type} }
 Optional :: struct (Value_Type: type_expr) {
     has_value: bool;
@@ -7,33 +22,52 @@ Optional :: struct (Value_Type: type_expr) {
 }
 
 #inject Optional {
-    make  :: (x: $T) => Optional(T).{ has_value = true, value = x };
+    // Helper procedure for creating an Optional with a value.
+    // Pass a type as the first argument to force the type, otherwise
+    // the type will be inferred from the parameter type.
+    make :: #match #locked {
+        ((x: $T) => Optional(T).{ has_value = true, value = x }),
+        ($T: type_expr, x: T) => (Optional(T).{ has_value = true, value = x })
+    }
+
+    // Create an empty Optional of a certain type. This procedure
+    // is mostly useless, because you can use `.{}` in type inferred
+    // places to avoid having to specify the type.
+    empty :: macro (T: type_expr) => Optional(T).{}; 
 
+    // Extracts the value from the Optional, or uses a default if
+    // no value is present.
     value_or :: (o: Optional, default: o.Value_Type) -> o.Value_Type {
         if !o.has_value do return default;
         return o.value;
     }
 
+    // Clears the value in the Optional, zeroing the memory of the value.
     reset :: (o: ^Optional) {
         o.has_value = false;
         core.memory.set(^o.value, 0, sizeof o.Value_Type);
     }
 
+    // Sets the value in the Optional.
     set :: (o: ^Optional, value: o.Value_Type) {
         o.has_value = true;
         o.value = value;
     }
 
+    // Monadic chaining operation.
     and_then :: (o: Optional($T), transform: (T) -> Optional($R)) -> Optional(R) {
         if !o.has_value do return .{ false };
         return transform(o.value);
     }
 
+    // Changes the value inside the optional, if present.
     transform :: (o: Optional($T), transform: (T) -> $R) -> Optional(R) {
         if !o.has_value do return .{ false };
         return Optional.make(transform(o.value));
     }
 
+    // Like `value_or`, but instead of providing a value, you
+    // provide a function to generate a value.
     or_else :: (o: Optional($T), generate: () -> Optional(T)) -> Optional(T) {
         if o.has_value do return o;
         return generate();