From: Brendan Hansen Date: Sun, 5 Mar 2023 23:09:19 +0000 (-0600) Subject: cleanup: better printing of 'Optional(T)' as '? T' X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=ad2f3a7502ca7291e513ac407a84fea80f2073f1;p=onyx.git cleanup: better printing of 'Optional(T)' as '? T' --- diff --git a/compiler/src/polymorph.h b/compiler/src/polymorph.h index c9576c9f..b9b296a6 100644 --- a/compiler/src/polymorph.h +++ b/compiler/src/polymorph.h @@ -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); diff --git a/core/builtin.onyx b/core/builtin.onyx index 2781f82e..7e34c992 100644 --- a/core/builtin.onyx +++ b/core/builtin.onyx @@ -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; diff --git a/core/container/optional.onyx b/core/container/optional.onyx index b02a0e02..2b697c73 100644 --- a/core/container/optional.onyx +++ b/core/container/optional.onyx @@ -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; diff --git a/core/conv/format.onyx b/core/conv/format.onyx index 95a6738a..2b0dee6d 100644 --- a/core/conv/format.onyx +++ b/core/conv/format.onyx @@ -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 {