typetui 0.2.1

A terminal-based typing test.
Documentation
main :: () {
    print("Type info for int:\n");
    print("  Size: %\n", size_of(int));
    print("  Alignment: %\n", align_of(int));
    
    print("\nType info for Player:\n");
    print("  Size: %\n", size_of(Player));
    print("  Alignment: %\n", align_of(Player));
    
    player := Player.{"Test", 100, 50, .{0, 0}};
    print_struct_info(player);
    
    print("\nType checks:\n");
    print("  int is type: %\n", type_is_integer(int));
    print("  float is type: %\n", type_is_float(float32));
    print("  Player is struct: %\n", type_is_struct(Player));
    
    numbers: [..]int;
    defer array_reset(*numbers);
    for 1..5 array_add(*numbers, it);
    
    print("\nGeneric max: %\n", generic_max(numbers));
    
    floats: [..]float64;
    defer array_reset(*floats);
    for 1..5 array_add(*floats, it * 1.5);
    print("Generic max float: %\n", generic_max(floats));
    
    print("\nCompile-time factorial of 5: %\n", FACTORIAL_5);
    print("Compile-time fibonacci of 10: %\n", FIBONACCI_10);
    
    arr: [ARRAY_SIZE]int;
    print("Array of size %: %\n", ARRAY_SIZE, arr);
    
    int_container := Container(int).{value = 42};
    print_container(int_container);
    
    str_container := Container(string).{value = "Hello"};
    print_container(str_container);
    
    baked_add := bake add_with_offset(10);
    print("Baked add(5): %\n", baked_add(5));
    
    print("\nFor expansion:\n");
    print_names(*player);
    
    print("\nAuto struct print:\n");
    auto_print(player);
    
    any_value: Any = player;
    handle_any(any_value);
    
    print("\nJSON-like output:\n");
    serialize_like_json(player);
}

Player :: struct {
    name: string;
    health: int;
    mana: int;
    position: Vector2;
}

Vector2 :: struct {
    x: float;
    y: float;
}

print_struct_info :: (s: $T) {
    ti := type_info(T);
    if ti.type != .STRUCT {
        print("Not a struct\n");
        return;
    }
    
    info := cast(*Type_Info_Struct) ti;
    print("Struct '%' has % members:\n", info.name, info.members.count);
    
    for info.members {
        print("  %: % (offset %)\n", it.name, it.type, it.offset_in_bytes);
    }
}

generic_max :: (arr: []$T) -> T {
    if arr.count == 0 return T.{};
    
    max_val := arr[0];
    for arr {
        if it > max_val max_val = it;
    }
    return max_val;
}

Container :: struct ($T: Type) {
    value: T;
}

print_container :: (c: Container($T)) {
    print("Container<%>: %\n", T, c.value);
}

factorial :: ($n: int) -> int #expand {
    #if n == 0 {
        return 1;
    } else {
        return n * factorial(n - 1);
    }
}

fibonacci :: ($n: int) -> int #expand {
    #if n <= 1 {
        return n;
    } else {
        return fibonacci(n - 1) + fibonacci(n - 2);
    }
}

FACTORIAL_5 :: #run factorial(5);
FIBONACCI_10 :: #run fibonacci(10);

ARRAY_SIZE :: #run 10 + 5;

add_with_offset :: (offset: int, x: int) -> int {
    return x + offset;
}

bake :: (proc: (int, int) -> int, offset: int) -> (int) -> int {
    return (x: int) -> int {
        return proc(offset, x);
    };
}

print_names :: (s: *$T) #expand {
    #insert #run -> string {
        ti := type_info(T);
        if ti.type != .STRUCT return "";
        
        info := cast(*Type_Info_Struct) ti;
        builder: String_Builder;
        
        for info.members {
            print_to_builder(*builder, "print(\"%: %\\n\", s.%);\n", 
                it.name, it.name);
        }
        
        return builder_to_string(*builder);
    };
}

auto_print :: (s: $T) {
    ti := type_info(T);
    if ti.type != .STRUCT {
        print("%\n", s);
        return;
    }
    
    info := cast(*Type_Info_Struct) ti;
    print("% {\n", info.name);
    
    for info.members {
        print("  % = ", it.name);
        print("<?>\n");
    }
    print("}\n");
}

handle_any :: (value: Any) {
    print("Any type: %\n", value.type);
    
    if value.type == type_info(int) {
        ptr := cast(*int) value.value_pointer;
        print("  As int: %\n", ptr.*);
    } else if value.type == type_info(string) {
        ptr := cast(*string) value.value_pointer;
        print("  As string: %\n", ptr.*);
    }
}

serialize_like_json :: (s: $T) {
    ti := type_info(T);
    if ti.type != .STRUCT {
        print("\"%\"", s);
        return;
    }
    
    info := cast(*Type_Info_Struct) ti;
    print("{\n");
    
    for info.members {
        print("  \"%\": ", it.name);
        print("<?>");
        if it_index < info.members.count - 1 print(",");
        print("\n");
    }
    
    print("}\n");
}

type_is_integer :: ($T: Type) -> bool #expand {
    ti := type_info(T);
    return ti.type == .INTEGER;
}

type_is_float :: ($T: Type) -> bool #expand {
    ti := type_info(T);
    return ti.type == .FLOAT;
}

type_is_struct :: ($T: Type) -> bool #expand {
    ti := type_info(T);
    return ti.type == .STRUCT;
}

#import "Basic";