changec tag syntax for struct members; added top-level #tag
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 7 Oct 2021 04:15:31 +0000 (23:15 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 7 Oct 2021 04:15:31 +0000 (23:15 -0500)
include/astnodes.h
src/astnodes.c
src/checker.c
src/entities.c
src/parser.c
src/symres.c

index 02f0c1be3bc9014eaddecbca722a482668de87ef..1e975011d1ffe4ac1c293be5d32aeecde51f7af5 100644 (file)
@@ -38,6 +38,7 @@
     NODE(DirectiveOperator)    \
     NODE(DirectiveExport)      \
     NODE(DirectiveDefined)     \
+    NODE(DirectiveTag)         \
                                \
     NODE(Return)               \
     NODE(Jump)                 \
@@ -192,6 +193,7 @@ typedef enum AstKind {
     Ast_Kind_Directive_Operator,
     Ast_Kind_Directive_Export,
     Ast_Kind_Directive_Defined,
+    Ast_Kind_Directive_Tag,
     Ast_Kind_Call_Site,
 
     Ast_Kind_Code_Block,
@@ -1049,6 +1051,13 @@ struct AstDirectiveDefined {
     b32 is_defined: 1;
 };
 
+struct AstDirectiveTag {
+    AstNode_base;
+
+    AstTyped* expr;
+    AstTyped* tag;
+};
+
 struct AstNote {
     AstNode_base;
 };
index 1563aee262c316bd34dbac7f7b614ad422b012e7..991bd3dd02b984c83d0cb3e1969c6137719d1134 100644 (file)
@@ -86,6 +86,7 @@ static const char* ast_node_names[] = {
     "OPERATOR OVERLOAD",
     "EXPORT",
     "DEFINED",
+    "TAG",
     "CALL SITE",
 
     "CODE BLOCK",
index 57586d732c4bccaee0e4018399c2bc53f3542807..215a1c51439f01c8b53af61e68f3c5bc0733bdb8 100644 (file)
@@ -2197,6 +2197,62 @@ CheckStatus check_process_directive(AstNode* directive) {
             YIELD(directive->token->pos, "Waiting for export type to be known.");
     }
 
+    if (directive->kind == Ast_Kind_Directive_Tag) {
+        AstDirectiveTag *tag = (AstDirectiveTag *) directive;
+
+        CHECK(expression, &tag->tag);
+
+        switch (tag->expr->kind) {
+            case Ast_Kind_Struct_Type: {
+                AstStructType* st = (AstStructType *) tag->expr;
+
+                if (st->meta_tags == NULL) bh_arr_new(global_heap_allocator, st->meta_tags, 1);
+                bh_arr_push(st->meta_tags, tag->tag);
+
+                return Check_Complete;
+            }
+
+            case Ast_Kind_Field_Access: {
+                AstFieldAccess* fa = (AstFieldAccess *) tag->expr;
+
+                if (fa->expr->kind == Ast_Kind_Struct_Type) {
+                    AstStructType* st = (AstStructType *) fa->expr;
+                    Type* s_type = type_build_from_ast(context.ast_alloc, (AstType *) st);
+
+                    bh_arr_each(AstStructMember *, smem, st->members) {
+                        if (token_equals((*smem)->token, fa->token)) {
+                            bh_arr(AstTyped *) tags = (*smem)->meta_tags;
+
+                            if (tags == NULL) bh_arr_new(global_heap_allocator, tags, 1);
+                            bh_arr_push(tags, tag->tag);
+
+                            (*smem)->meta_tags = tags;
+
+                            bh_arr_each(StructMember *, smem_type, s_type->Struct.memarr) {
+                                if (token_text_equals((*smem)->token, (*smem_type)->name)) {
+                                    (*smem_type)->meta_tags = tags;
+                                    break;
+                                }
+                            }
+
+                            return Check_Complete;
+                        }
+                    }
+
+                    onyx_report_error(fa->token->pos, "'%b' is not a member of '%s'.",
+                        fa->token->text, fa->token->length,
+                        st->name);
+                    return Check_Error;
+                }
+            }
+
+            default: {
+                onyx_report_error(tag->token->pos, "Cannot tag this.");
+                return Check_Error;
+            }
+        }
+    }
+
     return Check_Success;
 }
 
index ed209a28982edbd137d049cc074b5dcc304f8738..6d4569a8fd439eff9bc090876fab4fec2247ba5d 100644 (file)
@@ -327,6 +327,7 @@ void add_entities_for_node(bh_arr(Entity *) *target_arr, AstNode* node, Scope* s
 
         case Ast_Kind_Directive_Export:
         case Ast_Kind_Directive_Add_Overload:
+        case Ast_Kind_Directive_Tag:
         case Ast_Kind_Directive_Operator: {
             ent.type = Entity_Type_Process_Directive;
             ent.expr = (AstTyped *) node;
index 38762521007ef7a2f95723a5f55f4585ba8fea45..0f776f3d0b3f1ab50cd6320a046c0beef9547966 100644 (file)
@@ -1947,15 +1947,15 @@ static AstStructType* parse_struct(OnyxParser* parser) {
 
         } else {
             bh_arr(AstTyped *) meta_tags=NULL;
-            while (parse_possible_directive(parser, "tag")) {
-                expect_token(parser, '(');
+            while (parser->curr->type == '[') {
+                expect_token(parser, '[');
 
                 AstTyped* expr = parse_expression(parser, 0);
 
                 if (meta_tags == NULL) bh_arr_new(global_heap_allocator, meta_tags, 1);
                 bh_arr_push(meta_tags, expr);
 
-                expect_token(parser, ')');
+                expect_token(parser, ']');
             }
 
             bh_arr_clear(member_list_temp);
@@ -2827,6 +2827,17 @@ static void parse_top_level_statement(OnyxParser* parser) {
                 ENTITY_SUBMIT(export);
                 return;
             }
+            else if (parse_possible_directive(parser, "tag")) {
+                AstDirectiveTag *tag = make_node(AstDirectiveTag, Ast_Kind_Directive_Tag);
+                tag->token = dir_token;
+
+                tag->expr = parse_expression(parser, 0);
+                expect_token(parser, ',');
+                tag->tag = parse_expression(parser, 0);
+
+                ENTITY_SUBMIT(tag);
+                return;
+            }
             else {
                 OnyxToken* directive_token = expect_token(parser, '#');
                 OnyxToken* symbol_token = expect_token(parser, Token_Type_Symbol);
index 97c7702ca9cbfdb0e9b3809a3fd31b95e7e5b4af..e2c630dddcae5acbcc181c298427b21e02f345e8 100644 (file)
@@ -1184,6 +1184,13 @@ static SymresStatus symres_process_directive(AstNode* directive) {
 
             break;
         }
+
+        case Ast_Kind_Directive_Tag: {
+            AstDirectiveTag *tag = (AstDirectiveTag *) directive;
+            SYMRES(expression, &tag->tag);
+            SYMRES(expression, &tag->expr);
+            break;
+        }
     }
 
     return Symres_Success;