// File: /workspace/github_cpp_makefile_star2_O2/tsoding[P]wcc/src/./wcc_main.cpp
// Function: main
int main(int argc, char *argv[])
{
    auto target = Target::Wat;

    Args args = {argc, argv};
    args.shift();

    while (args.argc > 0) {
        String_View flag = cstr_as_string_view(*args.argv);

        if (!flag.has_prefix("-"_sv)) {
            break;
        }

        args.shift();

        if (flag == "--target"_sv || flag == "-t"_sv) {
            if (args.empty()) {
                usage(stderr);
                println(stderr, "ERROR: No value provided for flag `", flag, "`");
                exit(1);
            }

            auto custom_target_name = cstr_as_string_view(args.shift());
            auto custom_target = target_by_name(custom_target_name);
            if (!custom_target.has_value) {
                usage(stderr);
                println(stderr, "ERROR: Unknown target `", custom_target_name, "`");
                exit(1);
            }

            target = custom_target.unwrap;
        } else if (flag == "--help"_sv || flag == "-h"_sv) {
            usage(stdout);
            exit(0);
        } else {
            usage(stderr);
            println(stderr, "ERROR: Unknown flag `", flag, "`");
            exit(1);
        }
    }

    if (args.empty()) {
        usage(stderr);
        println(stderr, "ERROR: No input file provided");
        exit(1);
    }

    // TODO: Can we use Linear_Memory for read the input file instead of relying on malloc called by read_file_as_string_view()
    const char *input_filepath = args.shift();
    auto input = unwrap_or_panic(
        read_file_as_string_view(input_filepath),
        "Could not read file `", input_filepath, "`: ", strerror(errno));

    Linear_Memory memory = {};
    memory.capacity = 1024 * 1024 * 1024;
    memory.buffer = (uint8_t*) malloc(sizeof(uint8_t) * memory.capacity);

    Reporter reporter = {};
    reporter.filename = cstr_as_string_view(input_filepath);
    reporter.input = input;

    // TODO: Can we use Linear_Memory for collecting tokens instead of Dynamic_Array
    Alexer alexer = {};
    alexer.input = input;
    alexer.reporter = reporter;
    alexer.tokenize();

    if (target == Target::Tokens) {
        alexer.dump_tokens();
        return 0;
    }

    Parser parser = {};
    parser.memory = &memory;
    parser.reporter = reporter;
    parser.tokens = {alexer.tokens.size, alexer.tokens.data};
    Module module = parser.parse_module();
    assert(parser.tokens.count == 0 && "The tokens were not fully parsed");

    if (target == Target::Ast) {
        println(stdout, module);
        return 0;
    }

    Type_Checker type_checker = {};
    type_checker.memory = &memory;
    type_checker.reporter = reporter;
    type_checker.check_types_of_module(&module);

    Wat_Compiler wat_compiler = {};
    wat_compiler.memory = &memory;
    wat_compiler.reporter = reporter;

    S_Expr *wat = wat_compiler.compile_module(module);

    if (target == Target::Wat) {
        println(stdout, wat);
        return 0;
    }

    println(stdout, "Unsupported target `", target, "`");
    return 1;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x148, %rsp            # imm = 0x148
movq %rsi, %r14
movl %edi, %r15d
addq $0x8, %r14
xorl %eax, %eax
leaq -0xa0(%rbp), %r12
movq %rax, %rbx
cmpl $0x2, %r15d
jl 0x589a
movq (%r14), %rdi
callq 0x12a8
movq %rax, -0xa0(%rbp)
movq %rdx, -0x98(%rbp)
movq %r12, %rdi
pushq $0x1
popq %rsi
leaq 0x4423(%rip), %rdx      # 0x9c41
callq 0x6b16
testb %al, %al
je 0x58a4
movq %r12, %rdi
pushq $0x8
popq %rsi
leaq 0x440f(%rip), %rdx      # 0x9c43
callq 0x5b90
testb %al, %al
jne 0x5857
movq %r12, %rdi
pushq $0x2
popq %rsi
leaq 0x4402(%rip), %rdx      # 0x9c4c
callq 0x5b90
testb %al, %al
je 0x5ad9
cmpl $0x2, %r15d
je 0x5a76
movq %r12, %rbx
movq 0x8(%r14), %rdi
callq 0x12a8
movq %rax, %r12
movq %rdx, %r13
movq %rax, %rdi
movq %rdx, %rsi
callq 0x56e3
testb $0x1, %al
je 0x5aa6
shrq $0x20, %rax
addq $0x10, %r14
addl $-0x2, %r15d
movq %rbx, %r12
jmp 0x57ee
cmpl $0x1, %r15d
je 0x5b4f
movq (%r14), %r12
leaq -0xb8(%rbp), %r14
movq %r14, %rdi
movq %r12, %rsi
callq 0x12e0
callq 0x1040
movl (%rax), %edi
callq 0x1060
movq 0x10(%r14), %rcx
movq %rcx, 0x10(%rsp)
movups (%r14), %xmm0
movups %xmm0, (%rsp)
leaq 0x43ec(%rip), %rdi      # 0x9cc9
leaq 0x43fb(%rip), %rdx      # 0x9cdf
movq %r12, %rsi
movq %rax, %rcx
callq 0x6b88
movq %rax, %r14
movq %rdx, %r15
andq $0x0, -0x50(%rbp)
movq $0x40000000, -0x58(%rbp) # imm = 0x40000000
movl $0x40000000, %edi       # imm = 0x40000000
callq 0x1110
movq %rax, -0x48(%rbp)
movq %r12, %rdi
callq 0x12a8
movq %rax, %r12
movq %rdx, %r13
leaq -0xa0(%rbp), %rdi
andq $0x0, 0x20(%rdi)
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rdi)
movq %r14, (%rdi)
movq %r15, 0x8(%rdi)
movq %r14, 0x28(%rdi)
movq %r15, 0x30(%rdi)
movq %rax, 0x38(%rdi)
movq %rdx, 0x40(%rdi)
callq 0x243e
movq %rbx, %rax
cmpl $0x2, %eax
jne 0x5966
leaq -0xa0(%rbp), %rdi
callq 0x2ca4
jmp 0x5a62
leaq -0x58(%rbp), %rcx
movq %r12, %rax
leaq -0x150(%rbp), %r12
movq %rcx, (%r12)
movq %r14, 0x18(%r12)
movq %r15, 0x20(%r12)
movq %rax, -0x38(%rbp)
movq %rax, 0x28(%r12)
movq %r13, 0x30(%r12)
movups -0x88(%rbp), %xmm0
movups %xmm0, 0x8(%r12)
movq %r12, %rdi
callq 0x3ebc
movq %rax, -0x40(%rbp)
cmpq $0x0, 0x8(%r12)
jne 0x5b72
movq %rax, %rsi
movq %rbx, %rax
cmpl $0x1, %eax
jne 0x59d4
movq 0x85f9(%rip), %rax      # 0xdfc0
movq (%rax), %rdi
callq 0x6bc3
jmp 0x5a62
xorps %xmm0, %xmm0
leaq -0x118(%rbp), %rdi
movups %xmm0, 0x28(%rdi)
leaq -0x58(%rbp), %rax
movq %rax, (%rdi)
movq %r14, 0x8(%rdi)
movq %r15, 0x10(%rdi)
movq -0x38(%rbp), %r12
movq %r12, 0x18(%rdi)
movq %r13, 0x20(%rdi)
movq %rsi, -0x30(%rbp)
leaq -0x40(%rbp), %rsi
callq 0x236a
leaq -0xe0(%rbp), %rdi
leaq -0x58(%rbp), %rax
movq %rax, (%rdi)
movq %r14, 0x8(%rdi)
movq %r15, 0x10(%rdi)
movq %r12, 0x18(%rdi)
movq %r13, 0x20(%rdi)
movq -0x30(%rbp), %rsi
callq 0x558a
movq %rbx, %rdx
movq 0x8585(%rip), %rcx      # 0xdfc0
movq (%rcx), %rdi
testl %edx, %edx
je 0x5a5a
leaq 0x4303(%rip), %rsi      # 0x9d4c
leaq 0x2c45(%rip), %rcx      # 0x8695
callq 0x6c01
pushq $0x1
popq %rax
jmp 0x5a64
movq %rax, %rsi
callq 0x6be2
xorl %eax, %eax
addq $0x148, %rsp            # imm = 0x148
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x8563(%rip), %rbx      # 0xdfe0
movq (%rbx), %rdi
callq 0x5761
movq (%rbx), %rdi
movq -0xa0(%rbp), %rdx
movq -0x98(%rbp), %rcx
leaq 0x41b2(%rip), %rsi      # 0x9c4f
leaq 0x2bf1(%rip), %r8       # 0x8695
jmp 0x5acc
movq 0x8533(%rip), %rbx      # 0xdfe0
movq (%rbx), %rdi
callq 0x5761
movq (%rbx), %rdi
leaq 0x41b4(%rip), %rsi      # 0x9c73
leaq 0x2bcf(%rip), %r8       # 0x8695
movq %r12, %rdx
movq %r13, %rcx
callq 0x6b40
pushq $0x1
popq %rdi
callq 0x10f0
leaq 0x41ab(%rip), %rdx      # 0x9c8b
leaq -0xa0(%rbp), %rdi
pushq $0x6
popq %rsi
callq 0x5b90
testb %al, %al
jne 0x5b0d
leaq 0x4198(%rip), %rdx      # 0x9c92
leaq -0xa0(%rbp), %rdi
pushq $0x2
popq %rsi
callq 0x5b90
testb %al, %al
je 0x5b23
movq 0x84ac(%rip), %rax      # 0xdfc0
movq (%rax), %rdi
callq 0x5761
xorl %edi, %edi
callq 0x10f0
movq 0x84b6(%rip), %rbx      # 0xdfe0
movq (%rbx), %rdi
callq 0x5761
movq (%rbx), %rdi
movq -0xa0(%rbp), %rdx
movq -0x98(%rbp), %rcx
leaq 0x414b(%rip), %rsi      # 0x9c95
jmp 0x5a9d
movq 0x848a(%rip), %rbx      # 0xdfe0
movq (%rbx), %rdi
callq 0x5761
movq (%rbx), %rdi
leaq 0x4143(%rip), %rsi      # 0x9cab
callq 0x6af7
jmp 0x5ad1
leaq 0x416a(%rip), %rdi      # 0x9ce3
leaq 0x41a2(%rip), %rsi      # 0x9d22
leaq 0x41ae(%rip), %rcx      # 0x9d35
pushq $0x74
popq %rdx
callq 0x1090
nop