-
Notifications
You must be signed in to change notification settings - Fork 0
Metaprogramming
One can use the insert directive to automatically generate getter and setter functions. This is an elementary example for didactic purposes, but one can extrapolate this example to do much more complex metaprogramming.
generate_getters_and_setters :: ($T: Type) -> string {
builder: String_Builder;
info := type_info(T);
for member: info.members {
print("%\n", type_of(member.type));
print_to_builder(*builder, "get_% :: (s: %) -> type_of(s.%) { return s.%; }\n",
member.name, T, member.name, member.name);
print_to_builder(*builder, "set_% :: (s: *%, val: type_of(s.%)) { s.% = val; }\n",
member.name, T, member.name, member.name);
}
s := builder_to_string(*builder);
return s;
}
#insert -> string {
return generate_getters_and_setters(Person);
}
Given the following Person struct as an example:
Person :: struct {
name: string;
age: int;
}
The following code generated by the function would result in this:
get_name :: (s: Person) -> type_of(s.name) { return s.name; }
set_name :: (s: *Person, val: type_of(s.name)) { s.name = val; }
get_age :: (s: Person) -> type_of(s.age) { return s.age; }
set_age :: (s: *Person, val: type_of(s.age)) { s.age = val; }
Applying #no_reset macro allows one to initialize complex data structures at compile time easily without the need of complex assembly language macros like in C++. Here is a simple example of #no_reset directive.
#no_reset array: [5] int;
#run {
array[0] = 1;
array[1] = 10;
array[2] = 3;
array[3] = 5;
array[4] = 700;
}
Applying #no_reset macro allows one to initialize complex data structures at compile time easily without the need of complex assembly language macros like in C++. In this example, one can load a binary NNUE file into memory and populate the data structures at compile time.
#run load_model("orange7_8_24.nnue");
#no_reset nnue: NNUE #align 64;
NNUE :: struct {
feature_weights: [2][9][90][128] s16;
feature_biases: [128] s16;
output_weights: [2][128] s16;
output_bias: s32;
}
load_model :: (filename: string) {
print("loading file %\n", filename);
weights, success := read_entire_file(filename);
assert(success, "File % not found.", filename);
memcpy(*nnue, *weights[0], size_of(NNUE));
free(weights);
}