From: Brendan Hansen Date: Sun, 5 Mar 2023 21:46:27 +0000 (-0600) Subject: new: made `?T` mean `Optional(T)` X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=5db7dcbfa7a52b1e220eac74e972c344665889b5;p=onyx.git new: made `?T` mean `Optional(T)` --- diff --git a/compiler/include/astnodes.h b/compiler/include/astnodes.h index f078fbc6..714c2e04 100644 --- a/compiler/include/astnodes.h +++ b/compiler/include/astnodes.h @@ -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; diff --git a/compiler/src/builtins.c b/compiler/src/builtins.c index 6992124f..156a967e 100644 --- a/compiler/src/builtins.c +++ b/compiler/src/builtins.c @@ -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."); diff --git a/compiler/src/parser.c b/compiler/src/parser.c index dee10bd9..b7188438 100644 --- a/compiler/src/parser.c +++ b/compiler/src/parser.c @@ -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 **) ¶ms[0]; + break; + } + case '#': { if (parse_possible_directive(parser, "Self")) { if (parser->injection_point == NULL) { diff --git a/core/builtin.onyx b/core/builtin.onyx index 55540402..2781f82e 100644 --- a/core/builtin.onyx +++ b/core/builtin.onyx @@ -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. diff --git a/core/container/map.onyx b/core/container/map.onyx index 2e84faf2..b44ed0c8 100644 --- a/core/container/map.onyx +++ b/core/container/map.onyx @@ -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); diff --git a/core/container/optional.onyx b/core/container/optional.onyx index 92a18794..b02a0e02 100644 --- a/core/container/optional.onyx +++ b/core/container/optional.onyx @@ -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 { diff --git a/core/conv/format.onyx b/core/conv/format.onyx index 388254e4..95a6738a 100644 --- a/core/conv/format.onyx +++ b/core/conv/format.onyx @@ -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(" { "); diff --git a/scripts/run_tests.onyx b/scripts/run_tests.onyx index eafb1cb4..51075be2 100644 --- a/scripts/run_tests.onyx +++ b/scripts/run_tests.onyx @@ -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];