package main

TypeKind :: enum {
    Integer,
    Float,
    Pointer,
    Array,
}

Type :: struct {
    kind: TypeKind,
    bit_size: u8,
    is_signed: bool,
    pointer_to: ^Type,
    array_of: ^Type,
    array_size: u64,
}

FunctionType :: struct {
    name: [dynamic]u8,
    return_type: ^Type,
    parameter_types: [dynamic]^Type,
}

compare_types :: proc(a: ^Type, b: ^Type) -> (ret: bool) {
    ret = a != nil && b != nil && a.kind == b.kind && a.bit_size == b.bit_size && a.is_signed == b.is_signed
    if ret == false {
        return
    }

    if a.kind == .Pointer {
        ret = compare_types(a.pointer_to, b.pointer_to)
    } else if a.kind == .Array {
        ret = a.array_size == b.array_size && compare_types(a.array_of, b.array_of)
    }
    return
}

compare_function_types :: proc(a: ^FunctionType, b: ^FunctionType) -> (ret: bool) {
    ret = a != nil && b != nil && compare_types(a.return_type, b.return_type)
    if ret {
        for &arg, i in a.parameter_types {
            if !compare_types(arg, b.parameter_types[i]) {
                ret = false
                break
            }
        }
    }
    return
}

function_type_create :: proc() -> (ret: ^FunctionType) {
    ret = new(FunctionType)
    return
}

type_create_integer :: proc(bit_size: u8, signed: bool) -> (ret: ^Type) {
    ret = new(Type)
    ret.kind = .Integer
    ret.bit_size = bit_size
    ret.is_signed = signed
    return
}

type_create_float :: proc(bit_size: u8) -> (ret: ^Type) {
    ret = new(Type)
    ret.kind = .Float
    ret.bit_size = bit_size
    ret.is_signed = true
    return
}

type_create_pointer :: proc(to: ^Type) -> (ret: ^Type) {
    ret = new(Type)
    ret.kind = .Pointer
    ret.pointer_to = to
    return
}

type_create_array :: proc(of: ^Type, size: u64) -> (ret: ^Type) {
    ret = new(Type)
    ret.kind = .Array
    ret.array_of = of
    ret.array_size = size
    return
}
