new: made `?T` mean `Optional(T)`
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 5 Mar 2023 21:46:27 +0000 (15:46 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 5 Mar 2023 21:46:27 +0000 (15:46 -0600)
compiler/include/astnodes.h
compiler/src/builtins.c
compiler/src/parser.c
core/builtin.onyx
core/container/map.onyx
core/container/optional.onyx
core/conv/format.onyx
scripts/run_tests.onyx

index f078fbc657fef01b60cb756109991ab070570532..714c2e049e58340761766b36be673b4181564247 100644 (file)
@@ -1689,6 +1689,7 @@ extern Type     *builtin_vararg_type_type;
 extern AstTyped *builtin_context_variable;
 extern AstType  *builtin_allocator_type;
 extern AstType  *builtin_iterator_type;
+extern AstType  *builtin_optional_type;
 extern AstType  *builtin_callsite_type;
 extern AstType  *builtin_any_type;
 extern AstType  *builtin_code_type;
index 6992124f0357c827760ab1d025e769ecf2e6e346..156a967e7c0045f572698ff9b180c5a4bfbdfbf2 100644 (file)
@@ -56,6 +56,7 @@ Type     *builtin_vararg_type_type;
 AstTyped *builtin_context_variable;
 AstType  *builtin_allocator_type;
 AstType  *builtin_iterator_type;
+AstType  *builtin_optional_type;
 AstType  *builtin_callsite_type;
 AstType  *builtin_any_type;
 AstType  *builtin_code_type;
@@ -430,6 +431,12 @@ void initialize_builtins(bh_allocator a) {
         return;
     }
 
+    builtin_optional_type = (AstType *) symbol_raw_resolve(p->scope, "Optional");
+    if (builtin_optional_type == NULL) {
+        onyx_report_error((OnyxFilePos) { 0 }, Error_Critical, "'Optional' struct not found in builtin package.");
+        return;
+    }
+
     builtin_callsite_type = (AstType *) symbol_raw_resolve(p->scope, "CallSite");
     if (builtin_callsite_type == NULL) {
         onyx_report_error((OnyxFilePos) { 0 }, Error_Critical, "'CallSite' struct not found in builtin package.");
index dee10bd9427294ceb5f8ac9c28fb64c47776f1c1..b71884383c89c6fb811c2725a3083c80b2f54616 100644 (file)
@@ -568,6 +568,7 @@ static AstTyped* parse_factor(OnyxParser* parser) {
             break;
         }
 
+        case '?':
         case '[': {
             AstType *type = parse_type(parser);
             retval = (AstTyped *) type;
@@ -1977,6 +1978,23 @@ static AstType* parse_type(OnyxParser* parser) {
                 break;
             }
 
+            case '?': {
+                assert(builtin_optional_type);
+
+                bh_arr(AstNode *) params = NULL;
+                bh_arr_new(global_heap_allocator, params, 1);
+                bh_arr_set_length(params, 1);
+
+                AstPolyCallType* pc_type = make_node(AstPolyCallType, Ast_Kind_Poly_Call_Type);
+                pc_type->token = expect_token(parser, '?');
+                pc_type->callee = builtin_optional_type;
+                pc_type->params = params;
+                *next_insertion = (AstType *) pc_type;
+
+                next_insertion = (AstType **) &params[0];
+                break;
+            }
+
             case '#': {
                 if (parse_possible_directive(parser, "Self")) {
                     if (parser->injection_point == NULL) {
index 55540402e0504c22ac3787dfc8b125d0dc6e3ebd..2781f82efc888f030aaffdd89f43e19e5fb6b1d5 100644 (file)
@@ -396,6 +396,15 @@ Iterator :: struct (Iter_Type: type_expr) {
 }
 
 
+//
+// nocheckin DOCUMENT THIS
+Optional :: struct (Value_Type: type_expr) {
+    has_value: bool;
+    value: Value_Type;
+}
+
+
+
 //
 // This structure represents the result of a '#callsite' expression. Currently,
 // #callsite is only valid (and parsed) as a default value for a procedure parameter.
index 2e84faf2e2ab8c8c84b5e1b1a420d303be98cd64..b44ed0c891cb9fbe68a790be635eeb17b2f834f3 100644 (file)
@@ -160,7 +160,7 @@ get_ptr_or_create :: (use map: ^Map, key: map.Key_Type) -> ^map.Value_Type {
 // 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) -> Optional(map.Value_Type) {
+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);
 
index 92a18794ecaf51870b00394feb27715f57a2fbbd..b02a0e023613ae94d2fbfb6f8b28633e288caf88 100644 (file)
@@ -11,18 +11,6 @@ package core
 // used by Map and Set in their `get_opt` function. In theory, it should
 // be used in many more places, instead of returning `.{}`.
 
-#doc """
-    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;
-    value: Value_Type;
-}
-
 #inject Optional {
     #doc """
         Helper procedure for creating an Optional with a value.
@@ -104,14 +92,6 @@ Optional :: struct (Value_Type: type_expr) {
         if !o.has_value do return 0;
         return core.hash.to_u32(o.value);
     }
-
-    format :: (o: ^conv.Format_Output, format: ^conv.Format, opt: ^Optional($T)) {
-        if opt.has_value {
-            conv.format(o, "Some({\"})", opt.value);
-        } else {
-            o->write("None");
-        }
-    }
 }
 
 #operator == (o1, o2: Optional($T)) -> bool {
index 388254e4da3c32405c461784aa1436acc9dffae7..95a6738a4cc9499fe897e7f6eab80c7a400f20fc 100644 (file)
@@ -537,6 +537,21 @@ format_any :: (output: ^Format_Output, formatting: ^Format, v: any) {
             if info.kind == .Struct {
                 s := cast(^Type_Info_Struct) info;
 
+                if s.constructed_from == Optional {
+                    opt := cast(^?bool) v.data;
+
+                    if opt.has_value {
+                        output->write("Some(");
+                        format_any(output, formatting, .{ ~~(cast(^u8) v.data + s.members[1].offset), s.members[1].type });
+                        output->write(")");
+
+                    } else {
+                        output->write("None");
+                    }
+
+                    return;
+                }
+
                 if s.name.count > 0 {
                     output->write(s.name);
                     output->write(" { ");
index eafb1cb4a37d7b9a1ba903e8659d6f5ce76ba6da..51075be27fa4eea8d80b7d51ab56d1e0121618fc 100644 (file)
@@ -126,7 +126,7 @@ main :: (args) => {
         args: [] str;
         if thread_data.compile_only {
             printf("[{}]  Compiling test {}...\n", context.thread_id, it.source_file);
-            args = .[it.source_file];
+            args = .["build", it.source_file];
         } else {
             printf("[{}]  Running test {}...\n", context.thread_id, it.source_file);
             args = .["run", it.source_file];