// File: /workspace/github_cpp_makefile_star2_O3/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 $0x138, %rsp            # imm = 0x138
movl %edi, %r15d
leaq 0x8(%rsi), %r13
xorl %r14d, %r14d
cmpl $0x2, %edi
jl 0x6ae5
movq %rsi, %r14
movq (%r13), %rbx
movq %rbx, %rdi
callq 0x1070
testq %rax, %rax
je 0x6af5
movq %rax, %r12
addl $-0x2, %r15d
movq %r14, %r13
addq $0x18, %r13
xorl %r14d, %r14d
cmpb $0x2d, (%rbx)
jne 0x6af8
cmpq $0x2, %r12
je 0x6a7b
cmpq $0x8, %r12
jne 0x6d37
movabsq $0x7465677261742d2d, %rax # imm = 0x7465677261742D2D
cmpq %rax, (%rbx)
je 0x6a86
jmp 0x6d52
cmpw $0x742d, (%rbx)         # imm = 0x742D
jne 0x6d87
testl %r15d, %r15d
je 0x6d1c
movq -0x8(%r13), %rbx
movq %rbx, %rdi
callq 0x1070
movq %rax, %r12
movq %rax, %rdi
movq %rbx, %rsi
callq 0x6923
movq %rax, %r14
testb $0x1, %r14b
je 0x6d01
leal 0x2(%r15), %eax
shrq $0x20, %r14
cmpl $0x4, %eax
jb 0x6ae5
movq (%r13), %rbx
movq %rbx, %rdi
callq 0x1070
movq %rax, %r12
addl $-0x2, %r15d
addq $0x10, %r13
testq %rax, %rax
jne 0x6a4e
jmp 0x6af8
cmpl $0x1, %r15d
je 0x6dc9
movq (%r13), %rbx
jmp 0x6af8
xorl %r14d, %r14d
leaq -0xb0(%rbp), %r15
movq %r15, %rdi
movq %rbx, %rsi
callq 0x12db
callq 0x1040
movl (%rax), %edi
callq 0x1060
testb $0x1, (%r15)
je 0x6da4
movq -0xa8(%rbp), %r13
movq -0xa0(%rbp), %r12
xorl %eax, %eax
movq %rax, -0x58(%rbp)
movq $0x40000000, -0x60(%rbp) # imm = 0x40000000
movl $0x40000000, %edi       # imm = 0x40000000
callq 0x1110
movq %rax, -0x50(%rbp)
movq %rbx, %rdi
callq 0x1070
movq %rax, %r15
leaq -0xf8(%rbp), %rdi
xorl %eax, %eax
movq %rax, 0x20(%rdi)
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rdi)
movq %r13, (%rdi)
movq %r12, 0x8(%rdi)
movq %r13, 0x28(%rdi)
movq %r12, -0x40(%rbp)
movq %r12, 0x30(%rdi)
movq %r15, 0x38(%rdi)
movq %rbx, 0x40(%rdi)
callq 0x2864
cmpl $0x2, %r14d
jne 0x6ba0
leaq -0xf8(%rbp), %rdi
callq 0x320a
jmp 0x6ced
leaq -0x60(%rbp), %rax
leaq -0x158(%rbp), %r12
movq %rax, (%r12)
movq %r13, -0x48(%rbp)
movq %r13, 0x18(%r12)
movq -0x40(%rbp), %r13
movq %r13, 0x20(%r12)
movq %r15, -0x38(%rbp)
movq %r15, 0x28(%r12)
movq %rbx, 0x30(%r12)
movups -0xe0(%rbp), %xmm0
movups %xmm0, 0x8(%r12)
movq %r12, %rdi
callq 0x48ca
cmpq $0x0, 0x8(%r12)
jne 0x6de9
movq %rax, %rdx
cmpl $0x1, %r14d
jne 0x6c1e
movq 0x83c8(%rip), %rax      # 0xefc8
movq (%rax), %rbx
leaq 0x2daf(%rip), %rsi      # 0x99b9
leaq 0x2850(%rip), %rcx      # 0x9461
movq %rbx, %rdi
callq 0x7199
jmp 0x6ce0
xorps %xmm0, %xmm0
movups %xmm0, -0x70(%rbp)
leaq -0x60(%rbp), %rcx
movq %rcx, -0x98(%rbp)
movq -0x48(%rbp), %r15
movq %r15, -0x90(%rbp)
movq %r13, -0x88(%rbp)
movq -0x38(%rbp), %rax
movq %rax, -0x80(%rbp)
movq %rbx, -0x78(%rbp)
movq %rdx, -0x30(%rbp)
testq %rdx, %rdx
je 0x6c77
leaq -0x98(%rbp), %r13
movq -0x30(%rbp), %r12
movq %r13, %rdi
movq %r12, %rsi
callq 0x252c
movq 0x30(%r12), %r12
testq %r12, %r12
jne 0x6c62
leaq -0x120(%rbp), %rdi
leaq -0x60(%rbp), %rax
movq %rax, (%rdi)
movq %r15, 0x8(%rdi)
movq -0x40(%rbp), %rax
movq %rax, 0x10(%rdi)
movq -0x38(%rbp), %rax
movq %rax, 0x18(%rdi)
movq %rbx, 0x20(%rdi)
movq -0x30(%rbp), %rsi
callq 0x6756
movq 0x831b(%rip), %rcx      # 0xefc8
movq (%rcx), %rbx
testl %r14d, %r14d
je 0x6cd5
leaq 0x409a(%rip), %rsi      # 0xad56
leaq 0x29de(%rip), %rcx      # 0x96a1
movq %rbx, %rdi
movl %r14d, %edx
callq 0x7fce
movl $0x1, %eax
jmp 0x6cef
movq %rbx, %rdi
movq %rax, %rsi
callq 0x4952
movl $0xa, %edi
movq %rbx, %rsi
callq 0x1100
xorl %eax, %eax
addq $0x138, %rsp            # imm = 0x138
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x82d8(%rip), %r14      # 0xefe0
movq (%r14), %rdi
callq 0x6998
movq (%r14), %rdi
leaq 0x3f63(%rip), %rsi      # 0xac7d
jmp 0x6d6b
movq 0x82bd(%rip), %r14      # 0xefe0
movq (%r14), %rdi
callq 0x6998
movq (%r14), %rdi
leaq 0x3f24(%rip), %rsi      # 0xac59
jmp 0x6d6b
cmpq $0x6, %r12
jne 0x6d52
movl $0x65682d2d, %eax       # imm = 0x65682D2D
xorl (%rbx), %eax
movzwl 0x4(%rbx), %ecx
xorl $0x706c, %ecx           # imm = 0x706C
orl %eax, %ecx
je 0x6d8e
movq 0x8287(%rip), %r14      # 0xefe0
movq (%r14), %rdi
callq 0x6998
movq (%r14), %rdi
leaq 0x3f34(%rip), %rsi      # 0xac9f
leaq 0x292f(%rip), %r8       # 0x96a1
movq %r12, %rdx
movq %rbx, %rcx
callq 0x7f4d
movl $0x1, %edi
callq 0x10f0
cmpw $0x682d, (%rbx)         # imm = 0x682D
jne 0x6d52
movq 0x8233(%rip), %rax      # 0xefc8
movq (%rax), %rdi
callq 0x6998
xorl %edi, %edi
callq 0x10f0
movq 0x8235(%rip), %rcx      # 0xefe0
movq (%rcx), %rdi
leaq 0x3f1e(%rip), %rsi      # 0xacd3
leaq 0x3f2d(%rip), %rcx      # 0xace9
movq %rbx, %rdx
movq %rax, %r8
callq 0x8e7e
jmp 0x6d7d
movq 0x8210(%rip), %rbx      # 0xefe0
movq (%rbx), %rdi
callq 0x6998
movq (%rbx), %rdi
leaq 0x3ed3(%rip), %rsi      # 0xacb5
callq 0x7f14
jmp 0x6d7d
leaq 0x3efd(%rip), %rdi      # 0xaced
leaq 0x3f35(%rip), %rsi      # 0xad2c
leaq 0x3f41(%rip), %rcx      # 0xad3f
movl $0x74, %edx
callq 0x1090