// File: /workspace/github_cpp_makefile_star2_O1/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
movq %rsi, %r14
movl %edi, %r15d
addq $0x8, %r14
decl %r15d
xorl %ebx, %ebx
testl %r15d, %r15d
jle 0x6d2f
movq (%r14), %r12
movq %r12, %rdi
callq 0x1070
testq %rax, %rax
je 0x6d25
cmpb $0x2d, (%r12)
jne 0x6d25
movq %rax, %r13
cmpq $0x8, %rax
jne 0x6cc1
movq %r12, %rdi
leaq 0x4f78(%rip), %rsi      # 0xbc2d
movq %r13, %rdx
callq 0x10c0
testl %eax, %eax
je 0x6ce5
cmpq $0x2, %r13
jne 0x6f86
movq %r12, %rdi
leaq 0x4f61(%rip), %rsi      # 0xbc36
movq %r13, %rdx
callq 0x10c0
testl %eax, %eax
jne 0x6f86
cmpl $0x1, %r15d
je 0x6fef
movq 0x8(%r14), %r12
movq %r12, %rdi
callq 0x1070
movq %rax, %r13
movq %rax, %rdi
movq %r12, %rsi
callq 0x6b58
movq %rax, %rbx
testb $0x1, %bl
je 0x6fd4
addl $-0x2, %r15d
addq $0x10, %r14
shrq $0x20, %rbx
movb $0x1, %al
jmp 0x6d27
xorl %eax, %eax
testb %al, %al
jne 0x6c7a
testl %r15d, %r15d
je 0x703f
movq (%r14), %r13
leaq -0xa8(%rbp), %r15
movq %r15, %rdi
movq %r13, %rsi
callq 0x12db
callq 0x1040
movl (%rax), %edi
callq 0x1060
testb $0x1, (%r15)
je 0x705f
movq -0xa0(%rbp), %r15
movq -0x98(%rbp), %r14
xorps %xmm0, %xmm0
movaps %xmm0, -0x50(%rbp)
movq $0x0, -0x40(%rbp)
movq $0x40000000, -0x50(%rbp) # imm = 0x40000000
movl $0x40000000, %edi       # imm = 0x40000000
callq 0x1110
movq %rax, -0x40(%rbp)
movq %r13, %rdi
callq 0x1070
movq %rax, %r12
leaq -0xf0(%rbp), %rdi
xorps %xmm0, %xmm0
movaps %xmm0, (%rdi)
movaps %xmm0, 0x20(%rdi)
movaps %xmm0, 0x30(%rdi)
movaps %xmm0, 0x10(%rdi)
movq %r15, (%rdi)
movq %r14, 0x8(%rdi)
movq %r15, 0x28(%rdi)
movq %r14, 0x30(%rdi)
movq %rax, 0x38(%rdi)
movq %r13, 0x40(%rdi)
callq 0x285c
cmpl $0x2, %ebx
jne 0x6dec
leaq -0xf0(%rbp), %rdi
callq 0x31ce
jmp 0x6f72
movq %r12, %rax
leaq -0x160(%rbp), %r12
xorps %xmm0, %xmm0
movaps %xmm0, (%r12)
movaps %xmm0, 0x10(%r12)
movaps %xmm0, 0x20(%r12)
leaq -0x50(%rbp), %rcx
movq %rcx, (%r12)
movq %r15, 0x18(%r12)
movq %r14, 0x20(%r12)
movq %rax, -0x38(%rbp)
movq %rax, 0x28(%r12)
movq %r13, 0x30(%r12)
movq -0xd8(%rbp), %rax
movq -0xd0(%rbp), %rcx
movq %rax, 0x8(%r12)
movq %rcx, 0x10(%r12)
movq %r12, %rdi
callq 0x4ad4
cmpq $0x0, 0x8(%r12)
jne 0x7084
movq %rax, %rdx
cmpl $0x1, %ebx
jne 0x6e8b
movq 0x9163(%rip), %rax      # 0xffc8
movq (%rax), %rbx
leaq 0x3b2a(%rip), %rsi      # 0xa999
leaq 0x35cb(%rip), %rcx      # 0xa441
movq %rbx, %rdi
callq 0x7435
movl $0xa, %edi
movq %rbx, %rsi
jmp 0x6f6d
xorps %xmm0, %xmm0
movaps %xmm0, -0x90(%rbp)
movaps %xmm0, -0x80(%rbp)
movaps %xmm0, -0x70(%rbp)
movq $0x0, -0x60(%rbp)
leaq -0x50(%rbp), %rax
movq %rax, -0x90(%rbp)
movq %r15, -0x88(%rbp)
movq %r14, -0x80(%rbp)
movq -0x38(%rbp), %rax
movq %rax, -0x78(%rbp)
movq %r13, -0x58(%rbp)
movq %r13, -0x70(%rbp)
movq %rdx, -0x30(%rbp)
testq %rdx, %rdx
je 0x6ef4
leaq -0x90(%rbp), %r13
movq -0x30(%rbp), %r12
movq %r13, %rdi
movq %r12, %rsi
callq 0x252a
movq 0x30(%r12), %r12
testq %r12, %r12
jne 0x6edf
leaq -0x120(%rbp), %rdi
xorps %xmm0, %xmm0
movaps %xmm0, (%rdi)
movaps %xmm0, 0x10(%rdi)
leaq -0x50(%rbp), %rax
movq %rax, (%rdi)
movq %r15, 0x8(%rdi)
movq %r14, 0x10(%rdi)
movq -0x38(%rbp), %rax
movq %rax, 0x18(%rdi)
movq -0x58(%rbp), %rax
movq %rax, 0x20(%rdi)
movq -0x30(%rbp), %rsi
callq 0x6938
movq 0x9094(%rip), %rcx      # 0xffc8
movq (%rcx), %r14
testl %ebx, %ebx
je 0x6f5a
leaq 0x4df4(%rip), %rsi      # 0xbd36
leaq 0x3738(%rip), %rcx      # 0xa681
movq %r14, %rdi
movl %ebx, %edx
callq 0x82fe
movl $0x1, %eax
jmp 0x6f74
movq %r14, %rdi
movq %rax, %rsi
callq 0x4b5c
movl $0xa, %edi
movq %r14, %rsi
callq 0x1100
xorl %eax, %eax
addq $0x138, %rsp            # imm = 0x138
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
cmpq $0x6, %r13
jne 0x6fa2
leaq 0x4ce2(%rip), %rsi      # 0xbc75
movq %r12, %rdi
movq %r13, %rdx
callq 0x10c0
testl %eax, %eax
je 0x6fbe
cmpq $0x2, %r13
jne 0x700a
leaq 0x4ccd(%rip), %rsi      # 0xbc7c
movq %r12, %rdi
movq %r13, %rdx
callq 0x10c0
testl %eax, %eax
jne 0x700a
movq 0x9003(%rip), %rax      # 0xffc8
movq (%rax), %rdi
callq 0x6bf1
xorl %edi, %edi
callq 0x10f0
movq 0x9005(%rip), %rbx      # 0xffe0
movq (%rbx), %rdi
callq 0x6bf1
movq (%rbx), %rdi
leaq 0x4c70(%rip), %rsi      # 0xbc5d
jmp 0x7023
movq 0x8fea(%rip), %rbx      # 0xffe0
movq (%rbx), %rdi
callq 0x6bf1
movq (%rbx), %rdi
leaq 0x4c31(%rip), %rsi      # 0xbc39
jmp 0x7023
movq 0x8fcf(%rip), %rbx      # 0xffe0
movq (%rbx), %rdi
callq 0x6bf1
movq (%rbx), %rdi
leaq 0x4c5c(%rip), %rsi      # 0xbc7f
leaq 0x3657(%rip), %r8       # 0xa681
movq %r13, %rdx
movq %r12, %rcx
callq 0x827d
movl $0x1, %edi
callq 0x10f0
movq 0x8f9a(%rip), %rbx      # 0xffe0
movq (%rbx), %rdi
callq 0x6bf1
movq (%rbx), %rdi
leaq 0x4c3d(%rip), %rsi      # 0xbc95
callq 0x8244
jmp 0x7035
movq 0x8f7a(%rip), %rcx      # 0xffe0
movq (%rcx), %rdi
leaq 0x4c43(%rip), %rsi      # 0xbcb3
leaq 0x4c52(%rip), %rcx      # 0xbcc9
movq %r13, %rdx
movq %rax, %r8
callq 0x91e8
jmp 0x7035
leaq 0x4c42(%rip), %rdi      # 0xbccd
leaq 0x4c7a(%rip), %rsi      # 0xbd0c
leaq 0x4c86(%rip), %rcx      # 0xbd1f
movl $0x74, %edx
callq 0x1090
nop