added: shorthand syntax for `void` typed union variants
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 28 Nov 2023 18:16:42 +0000 (12:16 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 28 Nov 2023 18:16:42 +0000 (12:16 -0600)
compiler/include/astnodes.h
compiler/src/astnodes.c
core/alloc/memdebug.onyx
core/container/optional.onyx
core/encoding/kdl/kql.onyx
core/encoding/kdl/parser.onyx
core/encoding/kdl/utils.onyx
core/runtime/platform/wasi/wasix_misc.onyx

index e92f9707280d2167d2b97df4209172c72a09b749..0c294da85b9975e627568688a9eafeaf2a4ef14a 100644 (file)
@@ -2037,6 +2037,7 @@ AstNode*          make_symbol(bh_allocator a, OnyxToken* sym);
 AstUnaryOp*       make_cast(bh_allocator a, AstTyped* expr, Type* to);
 AstZeroValue*     make_zero_value(bh_allocator a, OnyxToken *token, Type* type);
 AstStructLiteral* make_optional_literal_some(bh_allocator a, AstTyped *expr, Type* opt_type);
+AstStructLiteral* make_union_variant_of_void(bh_allocator a, Type* union_type, OnyxToken* token, UnionVariant* variant);
 
 void arguments_initialize(Arguments* args);
 b32 fill_in_arguments(Arguments* args, AstNode* provider, char** err_msg, b32 insert_zero_values);
index 0f96e128b98e3c9dfe875f134d017c43cf393160..a8f12e1db5cdbf399a1c0f4378d018427f2b50f3 100644 (file)
@@ -644,6 +644,34 @@ TypeMatch unify_node_and_type_(AstTyped** pnode, Type* type, b32 permanent) {
     }
 
     if (node->kind == Ast_Kind_Unary_Field_Access) {
+        if (type->kind == Type_Kind_Union) {
+            token_toggle_end(node->token);
+            int index = 0;
+            if ((index = shgeti(type->Union.variants, node->token->text)) != -1) {
+                UnionVariant *uv = type->Union.variants[index].value;
+                if (uv->type != &basic_types[Basic_Kind_Void]) {
+                    if (permanent) {
+                        onyx_report_error(node->token->pos, Error_Critical,
+                            "Shorthand union literal syntax '.%s' is not all for this variant, because its type is not void; it is '%s'. Use the longer syntax, '.{ %s = value }'",
+                            node->token->text,
+                            type_get_name(uv->type),
+                            node->token->text);
+                    }
+                    token_toggle_end(node->token);
+                    return TYPE_MATCH_FAILED;
+                }
+
+                if (permanent) {
+                    AstStructLiteral *sl = make_union_variant_of_void(context.ast_alloc, type, node->token, uv);
+                    *pnode = (AstTyped *) sl;
+                }
+
+                token_toggle_end(node->token);
+                return TYPE_MATCH_SUCCESS;
+            }
+            token_toggle_end(node->token);
+        }
+
         AstType* ast_type = type->ast_type;
         AstNode* resolved = try_symbol_resolve_from_node((AstNode *) ast_type, node->token);
         if (resolved == NULL) {
@@ -1655,6 +1683,23 @@ AstStructLiteral* make_optional_literal_some(bh_allocator a, AstTyped *expr, Typ
     return opt_lit;
 }
 
+AstStructLiteral* make_union_variant_of_void(bh_allocator a, Type* union_type, OnyxToken* token, UnionVariant* variant) {
+    AstStructLiteral *lit = onyx_ast_node_new(a, sizeof(AstStructLiteral), Ast_Kind_Struct_Literal);
+    lit->token = token;
+
+    assert(variant->type == &basic_types[Basic_Kind_Void]);
+
+    arguments_initialize(&lit->args);
+    arguments_ensure_length(&lit->args, 2);
+    lit->args.values[0] = (AstTyped *) make_int_literal(a, variant->tag_value);
+    lit->args.values[1] = (AstTyped *) make_zero_value(a, token, variant->type);
+
+    lit->type = union_type;
+    lit->args.values[0]->type = union_type->Union.tag_type;
+
+    lit->flags |= Ast_Flag_Has_Been_Checked;
+    return lit;
+}
 
 
 void arguments_initialize(Arguments* args) {
index 9df3a61eba368c8643cd9d6116aa36b265122ce9..4a5b7969aaf5c305328c8d3d856e8ff00eee181b 100644 (file)
@@ -58,8 +58,8 @@ make :: (a: Allocator, listen_addr: &net.SocketAddress) -> MemDebugState {
     return .{
         a,
         *listen_addr,
-        .{ None = .{} },
-        .{ None = .{} }
+        .None,
+        .None
     };
 }
 
index 56a2045a4fe8c75567301feb9ad7d25a0dc50f61..67041dc726b622499a28e0fc14806f19547f8ef7 100644 (file)
@@ -39,7 +39,7 @@ use core
     from_ptr :: macro (p: &$T) -> ?T {
         p_ := p;
         if p_ do return *p_;
-        return .{ None = .{} };
+        return .None;
     }
 
     #doc """
@@ -53,7 +53,7 @@ use core
 
     #doc "Clears the value in the Optional, zeroing the memory of the value."
     reset :: (o: &?$T) {
-        *o = .{ None = .{} };
+        *o = .None;
     }
 
     #doc "Sets the value in the Optional."
@@ -65,7 +65,7 @@ use core
     and_then :: (o: ?$T, transform: (T) -> ?$R) -> ?R {
         return switch o {
             case v: .Some => transform(v);
-            case #default => .{ None = .{} };
+            case #default => .None;
         };
     }
 
@@ -73,7 +73,7 @@ use core
     transform :: (o: ?$T, transform: (T) -> $R) -> ?R {
         switch o {
             case v: .Some do return .{ Some = transform(v) };
-            case #default do return .{ None = .{} };
+            case #default do return .None;
         }
     }
 
index 4854454a8f1dbca21c828a3e5803740ed71681be..1df3af36070362cbdad04f584d31aff30593cb74 100644 (file)
@@ -414,7 +414,7 @@ parse_matcher :: (p: &QueryParser) -> ? &Matcher {
             m.details << .{
                 accessor = .{ Scope = .{} },
                 op = .Equal,
-                value = .{ None = .{} },
+                value = .None,
             };
 
         } else {
@@ -437,7 +437,7 @@ parse_matcher :: (p: &QueryParser) -> ? &Matcher {
             m.details << .{
                 accessor = .{ Node = .{} },
                 op = .Equal,
-                value = .{ None = .{} },
+                value = .None,
             };
             continue;
         }
index 46f452aa5fe0369541ed3240928be7c4ee28fac4..303f00508b55bdf383e4e1e5e5ba2cd5449bd74e 100644 (file)
@@ -60,7 +60,7 @@ Token :: union {
 
     peek_char :: (self: &#Self) -> ? u32 {
         codepoint_length := utf8.rune_length_from_first_byte(self.doc[self.cursor]);
-        if self.cursor + codepoint_length >= self.doc.length do return .{ None = .{} };
+        if self.cursor + codepoint_length >= self.doc.length do return .None;
         
         value := utf8.decode_rune(string.advance(self.doc, self.cursor));
         return value;
@@ -68,7 +68,7 @@ Token :: union {
 
     eat_char :: (self: &#Self) -> ? u32 {
         codepoint_length := utf8.rune_length_from_first_byte(self.doc[self.cursor]);
-        if self.cursor + codepoint_length >= self.doc.length do return .{ None = .{} };
+        if self.cursor + codepoint_length >= self.doc.length do return .None;
         
         value := utf8.decode_rune(string.advance(self.doc, self.cursor));
         self.cursor += codepoint_length;
@@ -478,7 +478,7 @@ Parse_Error :: union {
             }
         });
 
-        return .{ Ok = .{ None = .{} } };
+        return .{ Ok = .None };
     }
 
     parse_identifier :: (self: &#Self) -> Result(? str, Parse_Error) {
@@ -491,7 +491,7 @@ Parse_Error :: union {
             }
 
             case .EOF {
-                return .{ Ok = .{ None = .{} } };
+                return .{ Ok = .None };
             }
 
             case #default {
index fdbf7a13fd9257da9201d460b7304bc4cacb5557..8c6421a8b83369985e5e5130314600b523ea5f32 100644 (file)
@@ -25,7 +25,7 @@ use core {string}
     create_node :: (d: &Document, name: str) -> &Node {
         return d.allocator->move(Node.{
             node = name,
-            type_annotation = .{ None = .{} },
+            type_annotation = .None,
             values = make([..] Value, d.allocator),
             props = make(Map(str, Value), d.allocator),
             children = make([..] &Node, d.allocator)
index 98f16bcb5779a254eafa3a5be1fedc115d7f16d6..bf1c9bd46c2539daefc28f2f6ce7add38f18573f 100644 (file)
@@ -6,7 +6,7 @@ use core.os
 __futex_wait :: (addr: rawptr, expected: i32, timeout: i32) -> i32 {
     tm: wasi.OptionTimestamp;
     if timeout < 0 {
-        tm = .{ None = .{} };
+        tm = .None;
     } else {
         tm = .{ Some = ~~timeout };
     }