cleanup: better printing of 'Optional(T)' as '? T'
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 5 Mar 2023 23:09:19 +0000 (17:09 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 5 Mar 2023 23:09:19 +0000 (17:09 -0600)
compiler/src/polymorph.h
core/builtin.onyx
core/container/optional.onyx
core/conv/format.onyx

index c9576c9f67db43ab892f3ca2f1b72852b85461c8..b9b296a6d69df15dfd03a5a960730024a6a5a4d1 100644 (file)
@@ -1039,6 +1039,16 @@ char* build_poly_struct_name(AstPolyStructType* ps_type, Type* cs_type) {
     char name_buf[256];
     fori (i, 0, 256) name_buf[i] = 0;
 
+
+    // Special case for `? T`
+    if (cs_type->Struct.constructed_from == builtin_optional_type) {
+        strncat(name_buf, "? ", 255);
+        strncat(name_buf, type_get_name(cs_type->Struct.poly_sln[0].type), 255);
+
+        return bh_aprintf(global_heap_allocator, "%s", name_buf);
+    }
+
+
     strncat(name_buf, ps_type->name, 255);
     strncat(name_buf, "(", 255);
     bh_arr_each(AstPolySolution, ptype, cs_type->Struct.poly_sln) {
@@ -1117,6 +1127,8 @@ Type* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(AstPolySoluti
         Type* cs_type = type_build_from_ast(context.ast_alloc, (AstType *) concrete_struct);
         if (!cs_type) return NULL;
 
+        cs_type->Struct.constructed_from = (AstType *) ps_type;
+        
         if (cs_type->Struct.poly_sln == NULL) cs_type->Struct.poly_sln = bh_arr_copy(global_heap_allocator, slns);
         if (cs_type->Struct.name == NULL)     cs_type->Struct.name = build_poly_struct_name(ps_type, cs_type);
 
index 2781f82efc888f030aaffdd89f43e19e5fb6b1d5..7e34c99251bd800d944db4af58f5fa6a1fe1368c 100644 (file)
@@ -397,7 +397,12 @@ Iterator :: struct (Iter_Type: type_expr) {
 
 
 //
-// nocheckin DOCUMENT THIS
+// 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;
index b02a0e023613ae94d2fbfb6f8b28633e288caf88..2b697c73022c0d70df86845773302d3f20912307 100644 (file)
@@ -18,8 +18,8 @@ package core
         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 })
+        ((x: $T) => (?T).{ has_value = true, value = x }),
+        ($T: type_expr, x: T) => ((?T).{ has_value = true, value = x })
     }
 
     #doc """
@@ -27,38 +27,38 @@ package core
         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).{}; 
+    empty :: macro (T: type_expr) => (?T).{}; 
 
     #doc """
         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 {
+    value_or :: (o: ?$T, default: T) -> T {
         if !o.has_value do return default;
         return o.value;
     }
 
     #doc "Clears the value in the Optional, zeroing the memory of the value."
-    reset :: (o: ^Optional) {
+    reset :: (o: ^?$T) {
         o.has_value = false;
-        core.memory.set(^o.value, 0, sizeof o.Value_Type);
+        core.memory.set(^o.value, 0, sizeof T);
     }
 
     #doc "Sets the value in the Optional."
-    set :: (o: ^Optional, value: o.Value_Type) {
+    set :: (o: ^?$T, value: T) {
         o.has_value = true;
         o.value = value;
     }
 
     #doc "Monadic chaining operation."
-    and_then :: (o: Optional($T), transform: (T) -> Optional($R)) -> Optional(R) {
-        if !o.has_value do return .{ false };
+    and_then :: (o: ?$T, transform: (T) -> ?$R) -> ?R {
+        if !o.has_value do return .{};
         return transform(o.value);
     }
 
     #doc "Changes the value inside the optional, if present."
-    transform :: (o: Optional($T), transform: (T) -> $R) -> Optional(R) {
-        if !o.has_value do return .{ false };
+    transform :: (o: ?$T, transform: (T) -> $R) -> ?R {
+        if !o.has_value do return .{};
         return Optional.make(transform(o.value));
     }
 
@@ -66,7 +66,7 @@ package core
         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) {
+    or_else :: (o: ?$T, generate: () -> ?T) -> ?T {
         if o.has_value do return o;
         return generate();
     }
@@ -76,30 +76,30 @@ package core
         If not, an assertion is thrown and the context's assert
         handler must take care of it.
     """
-    unwrap :: (o: Optional) -> o.Value_Type {
+    unwrap :: (o: ?$T) -> T {
         if o.has_value do return o.value;
         assert(false, "Unwrapping empty Optional.");
     }
 
-    or_return :: macro (o: Optional($T)) -> T {
+    or_return :: macro (o: ?$T) -> T {
         value := o;
         if value.has_value do return value.value;
 
         return #from_enclosing .{};
     }
 
-    hash :: (o: Optional($T/core.hash.Hashable)) -> u32 {
+    hash :: (o: ?$T/core.hash.Hashable) -> u32 {
         if !o.has_value do return 0;
         return core.hash.to_u32(o.value);
     }
 }
 
-#operator == (o1, o2: Optional($T)) -> bool {
+#operator == (o1, o2: ?$T) -> bool {
     if o1.has_value != o2.has_value do return false;
     if !o1.has_value do return true;
     return o1.value == o2.value;
 }
 
 #overload
-__implicit_bool_cast :: macro (o: Optional) => o.has_value;
+__implicit_bool_cast :: macro (o: ?$T) => o.has_value;
 
index 95a6738a4cc9499fe897e7f6eab80c7a400f20fc..2b0dee6daeaf718a54922093cdfe1700d17c4d73 100644 (file)
@@ -541,8 +541,11 @@ format_any :: (output: ^Format_Output, formatting: ^Format, v: any) {
                     opt := cast(^?bool) v.data;
 
                     if opt.has_value {
+                        format := *formatting;
+                        format.quote_strings = true;
+
                         output->write("Some(");
-                        format_any(output, formatting, .{ ~~(cast(^u8) v.data + s.members[1].offset), s.members[1].type });
+                        format_any(output, ^format, .{ ~~(cast(^u8) v.data + s.members[1].offset), s.members[1].type });
                         output->write(")");
 
                     } else {