#tag

#tag is used to attach static metadata to various compile-time objects. This metadata can then be accessed using the runtime.info package.

To tag something, simply place one or more #tags before the binding. The order of the tags are preserved when using them.

The metadata that is attached has to be a compile-time known value, because it will be serialized and placed in the data section of the resulting binary. It could be a numeric, string, structure or array literal for example.

Structures

Here is an example of a structure tagged with a string literal.

#tag "option:hidden"
Value :: struct {
    // ...
}

To access tags on a structure, use the get_type_info function from runtime.info to get the Type_Info of the structure. Then use ->as_struct() to convert it to a Type_Info_Struct. Then you can use the .tags property to access the stored data. It is simply an array of any, which can be used with the utilities for any found in core.misc.

use runtime.info { get_type_info }
use core { printf, misc }

main :: () {
    info := get_type_info(Value)->as_struct();
    for tag in info.tags {
        if tag.type == str {
            value := * misc.any_as(tag, str);
            printf("Value: {}\n", value);
        }
    }
}

Structure members

Value :: struct {
    #tag "a value"
    member_name: i32;
}

To access tags on a structure member, do the same steps as above, and then use the members array on the Type_Info_Struct. On each member's info there is a tags array of that contains all the tags defined the member, in the order they were defined.

use runtime.info { get_type_info }
use core { printf, misc }

main :: () {
    info := get_type_info(Value)->as_struct();
    for member in info.members {
        for tag in member.tags {
            if tag.type == str {
                value := * misc.any_as(tag, str);
                printf("Value: {}\n", value);
            }
        }
    }
}

Unions

Tags on unions behave in exactly the same manner as tags on structures.

Unions Variants

Tags on union variants behave in exactly the same manner as tags on structure members.

Procedures

Tag information for procedures is located in the runtime.info.tagged_procedures array. You can either loop through this array manually, or you can use the helper procedure runtime.info.get_procedures_with_tag.

use runtime.info {get_procedures_with_tag}
use core {printf}

Metadata :: struct { name: str }

#tag Metadata.{ "name is foo" }
foo :: () { }

#tag Metadata.{ "name is bar" }
bar :: () { }


main :: () {
    // Provide the type of the tag.
    procs := get_procedures_with_tag(Metadata);
    for p in procs {
        printf("Procedure is: {}\n", p.func);
        printf("Procedure type is: {}\n", p.type);
        printf("Tag is: {}\n", p.tag);
        printf("Procedure is in package: {}\n", p.pack);
    }
}

Globals

Like tagged procedures, tagged global information lives in runtime.info.tagged_globals. You can either loop through it directly, or use the helper procedure runtime.info.get_globals_with_tag.

use runtime.info {get_globals_with_tag}
use core {printf}

Metadata :: struct { name: str }

#tag Metadata.{ "name is foo" }
foo: i32


main :: () {
    // Provide the type of the tag.
    globs := get_globals_with_tag(Metadata);
    for g in globs {
        printf("Global address is: {}\n", g.data);
        printf("Global type is: {}\n", g.type);
        printf("Tag is: {}\n", g.tag);
        printf("Global is in package: {}\n", g.pack);
    }
}