// File: 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
subq $0x290, %rsp            # imm = 0x290
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl $0x0, -0x14(%rbp)
movl -0x8(%rbp), %eax
movl %eax, -0x28(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x20(%rbp)
leaq -0x28(%rbp), %rdi
callq 0xbef0
cmpl $0x0, -0x28(%rbp)
jle 0x9b1d
movq -0x20(%rbp), %rax
movq (%rax), %rdi
callq 0x1310
movq %rax, -0x38(%rbp)
movq %rdx, -0x30(%rbp)
leaq 0x66d9(%rip), %rdi      # 0xff55
movl $0x1, %esi
callq 0x12e0
movq %rax, -0x48(%rbp)
movq %rdx, -0x40(%rbp)
movq -0x48(%rbp), %rsi
movq -0x40(%rbp), %rdx
leaq -0x38(%rbp), %rdi
callq 0xbf20
testb $0x1, %al
jne 0x98a8
jmp 0x9b1d
leaq -0x28(%rbp), %rdi
callq 0xbef0
leaq 0x669f(%rip), %rdi      # 0xff57
movl $0x8, %esi
callq 0x12e0
movq %rax, -0x58(%rbp)
movq %rdx, -0x50(%rbp)
movq -0x58(%rbp), %rsi
movq -0x50(%rbp), %rdx
leaq -0x38(%rbp), %rdi
callq 0xa0b0
testb $0x1, %al
jne 0x9912
leaq 0x667a(%rip), %rdi      # 0xff60
movl $0x2, %esi
callq 0x12e0
movq %rax, -0x68(%rbp)
movq %rdx, -0x60(%rbp)
movq -0x68(%rbp), %rsi
movq -0x60(%rbp), %rdx
leaq -0x38(%rbp), %rdi
callq 0xa0b0
testb $0x1, %al
jne 0x9912
jmp 0x9a32
leaq -0x28(%rbp), %rdi
callq 0xbfa0
testb $0x1, %al
jne 0x9921
jmp 0x996f
movq 0xa6b8(%rip), %rax      # 0x13fe0
movq (%rax), %rdi
callq 0x97a0
movq 0xa6a9(%rip), %rax      # 0x13fe0
movq (%rax), %rdi
movq -0x38(%rbp), %rax
movq %rax, -0x78(%rbp)
movq -0x30(%rbp), %rax
movq %rax, -0x70(%rbp)
movq -0x78(%rbp), %rdx
movq -0x70(%rbp), %rcx
leaq 0x660a(%rip), %rsi      # 0xff63
leaq 0x4f7d(%rip), %r8       # 0xe8dd
callq 0xbfc0
movl $0x1, %edi
callq 0x1120
leaq -0x28(%rbp), %rdi
callq 0xbef0
movq %rax, %rdi
callq 0x1310
movq %rax, -0x88(%rbp)
movq %rdx, -0x80(%rbp)
movq -0x88(%rbp), %rax
movq %rax, -0xa0(%rbp)
movq -0x80(%rbp), %rax
movq %rax, -0x98(%rbp)
movq -0xa0(%rbp), %rdi
movq -0x98(%rbp), %rsi
callq 0x96c0
movq %rax, -0x90(%rbp)
testb $0x1, -0x90(%rbp)
jne 0x9a24
movq 0xa612(%rip), %rax      # 0x13fe0
movq (%rax), %rdi
callq 0x97a0
movq 0xa603(%rip), %rax      # 0x13fe0
movq (%rax), %rdi
movq -0x88(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq -0x80(%rbp), %rax
movq %rax, -0xa8(%rbp)
movq -0xb0(%rbp), %rdx
movq -0xa8(%rbp), %rcx
leaq 0x6579(%rip), %rsi      # 0xff87
leaq 0x4ec8(%rip), %r8       # 0xe8dd
callq 0xbfc0
movl $0x1, %edi
callq 0x1120
movl -0x8c(%rbp), %eax
movl %eax, -0x14(%rbp)
jmp 0x9b18
leaq 0x6566(%rip), %rdi      # 0xff9f
movl $0x6, %esi
callq 0x12e0
movq %rax, -0xc0(%rbp)
movq %rdx, -0xb8(%rbp)
movq -0xc0(%rbp), %rsi
movq -0xb8(%rbp), %rdx
leaq -0x38(%rbp), %rdi
callq 0xa0b0
testb $0x1, %al
jne 0x9aa8
leaq 0x6533(%rip), %rdi      # 0xffa6
movl $0x2, %esi
callq 0x12e0
movq %rax, -0xd0(%rbp)
movq %rdx, -0xc8(%rbp)
movq -0xd0(%rbp), %rsi
movq -0xc8(%rbp), %rdx
leaq -0x38(%rbp), %rdi
callq 0xa0b0
testb $0x1, %al
jne 0x9aa8
jmp 0x9abe
movq 0xa511(%rip), %rax      # 0x13fc0
movq (%rax), %rdi
callq 0x97a0
xorl %edi, %edi
callq 0x1120
movq 0xa51b(%rip), %rax      # 0x13fe0
movq (%rax), %rdi
callq 0x97a0
movq 0xa50c(%rip), %rax      # 0x13fe0
movq (%rax), %rdi
movq -0x38(%rbp), %rax
movq %rax, -0xe0(%rbp)
movq -0x30(%rbp), %rax
movq %rax, -0xd8(%rbp)
movq -0xe0(%rbp), %rdx
movq -0xd8(%rbp), %rcx
leaq 0x64a7(%rip), %rsi      # 0xffa9
leaq 0x4dd4(%rip), %r8       # 0xe8dd
callq 0xbfc0
movl $0x1, %edi
callq 0x1120
jmp 0x9857
leaq -0x28(%rbp), %rdi
callq 0xbfa0
testb $0x1, %al
jne 0x9b2c
jmp 0x9b5b
movq 0xa4ad(%rip), %rax      # 0x13fe0
movq (%rax), %rdi
callq 0x97a0
movq 0xa49e(%rip), %rax      # 0x13fe0
movq (%rax), %rdi
leaq 0x6473(%rip), %rsi      # 0xffbf
callq 0xbeb0
movl $0x1, %edi
callq 0x1120
leaq -0x28(%rbp), %rdi
callq 0xbef0
movq %rax, -0xe8(%rbp)
movq -0xe8(%rbp), %rsi
leaq -0x110(%rbp), %rdi
callq 0x1370
movq -0xe8(%rbp), %rax
movq %rax, -0x270(%rbp)
callq 0x1040
movl (%rax), %edi
callq 0x1070
movq -0x270(%rbp), %rsi
movq %rax, %rcx
leaq -0x110(%rbp), %rax
leaq 0x642d(%rip), %rdi      # 0xffdd
leaq 0x643c(%rip), %rdx      # 0xfff3
movq (%rax), %r8
movq %r8, (%rsp)
movq 0x8(%rax), %r8
movq %r8, 0x8(%rsp)
movq 0x10(%rax), %rax
movq %rax, 0x10(%rsp)
callq 0xc030
movq %rax, -0xf8(%rbp)
movq %rdx, -0xf0(%rbp)
leaq -0x128(%rbp), %rdi
xorl %esi, %esi
movl $0x18, %edx
callq 0x10b0
movq $0x40000000, -0x128(%rbp) # imm = 0x40000000
movq -0x128(%rbp), %rdi
shlq $0x0, %rdi
callq 0x1140
movq %rax, -0x118(%rbp)
leaq -0x148(%rbp), %rdi
xorl %esi, %esi
movl $0x20, %edx
callq 0x10b0
movq -0xe8(%rbp), %rdi
callq 0x1310
movq %rax, -0x158(%rbp)
movq %rdx, -0x150(%rbp)
movq -0x158(%rbp), %rax
movq %rax, -0x138(%rbp)
movq -0x150(%rbp), %rax
movq %rax, -0x130(%rbp)
movq -0xf8(%rbp), %rax
movq %rax, -0x148(%rbp)
movq -0xf0(%rbp), %rax
movq %rax, -0x140(%rbp)
leaq -0x1a0(%rbp), %rdi
xorl %esi, %esi
movl $0x48, %edx
callq 0x10b0
movq -0xf8(%rbp), %rax
movq %rax, -0x1a0(%rbp)
movq -0xf0(%rbp), %rax
movq %rax, -0x198(%rbp)
movq -0x148(%rbp), %rax
movq %rax, -0x178(%rbp)
movq -0x140(%rbp), %rax
movq %rax, -0x170(%rbp)
movq -0x138(%rbp), %rax
movq %rax, -0x168(%rbp)
movq -0x130(%rbp), %rax
movq %rax, -0x160(%rbp)
leaq -0x1a0(%rbp), %rdi
callq 0x33d0
cmpl $0x2, -0x14(%rbp)
jne 0x9d0e
leaq -0x1a0(%rbp), %rdi
callq 0x42e0
movl $0x0, -0x4(%rbp)
jmp 0x9f6a
leaq -0x1d8(%rbp), %rdi
xorl %esi, %esi
movl $0x38, %edx
callq 0x10b0
leaq -0x128(%rbp), %rax
movq %rax, -0x1d8(%rbp)
movq -0x148(%rbp), %rax
movq %rax, -0x1c0(%rbp)
movq -0x140(%rbp), %rax
movq %rax, -0x1b8(%rbp)
movq -0x138(%rbp), %rax
movq %rax, -0x1b0(%rbp)
movq -0x130(%rbp), %rax
movq %rax, -0x1a8(%rbp)
movq -0x188(%rbp), %rax
movq %rax, -0x1e8(%rbp)
movq -0x180(%rbp), %rax
movq %rax, -0x1e0(%rbp)
movq -0x1e8(%rbp), %rax
movq %rax, -0x1d0(%rbp)
movq -0x1e0(%rbp), %rax
movq %rax, -0x1c8(%rbp)
leaq -0x1d8(%rbp), %rdi
callq 0x6780
movq %rax, -0x1f0(%rbp)
xorl %eax, %eax
cmpq $0x0, -0x1d0(%rbp)
movb %al, -0x271(%rbp)
jne 0x9dce
movb $0x1, %al
movb %al, -0x271(%rbp)
jmp 0x9dce
movb -0x271(%rbp), %al
testb $0x1, %al
jne 0x9dda
jmp 0x9ddc
jmp 0x9dfb
leaq 0x6235(%rip), %rdi      # 0x10018
leaq 0x626d(%rip), %rsi      # 0x10057
movl $0x74, %edx
leaq 0x6274(%rip), %rcx      # 0x1006a
callq 0x10c0
cmpl $0x1, -0x14(%rbp)
jne 0x9e31
movq 0xa1b8(%rip), %rax      # 0x13fc0
movq (%rax), %rdi
movq -0x1f0(%rbp), %rax
movq %rax, -0x1f8(%rbp)
movq -0x1f8(%rbp), %rsi
callq 0xc0a0
movl $0x0, -0x4(%rbp)
jmp 0x9f6a
leaq -0x230(%rbp), %rdi
xorl %esi, %esi
movl $0x38, %edx
callq 0x10b0
leaq -0x128(%rbp), %rax
movq %rax, -0x230(%rbp)
movq -0x148(%rbp), %rax
movq %rax, -0x228(%rbp)
movq -0x140(%rbp), %rax
movq %rax, -0x220(%rbp)
movq -0x138(%rbp), %rax
movq %rax, -0x218(%rbp)
movq -0x130(%rbp), %rax
movq %rax, -0x210(%rbp)
leaq -0x230(%rbp), %rdi
leaq -0x1f0(%rbp), %rsi
callq 0x3020
leaq -0x258(%rbp), %rdi
xorl %esi, %esi
movl $0x28, %edx
callq 0x10b0
leaq -0x128(%rbp), %rax
movq %rax, -0x258(%rbp)
movq -0x148(%rbp), %rax
movq %rax, -0x250(%rbp)
movq -0x140(%rbp), %rax
movq %rax, -0x248(%rbp)
movq -0x138(%rbp), %rax
movq %rax, -0x240(%rbp)
movq -0x130(%rbp), %rax
movq %rax, -0x238(%rbp)
movq -0x1f0(%rbp), %rax
movq %rax, -0x268(%rbp)
movq -0x268(%rbp), %rsi
leaq -0x258(%rbp), %rdi
callq 0x9450
movq %rax, -0x260(%rbp)
cmpl $0x0, -0x14(%rbp)
jne 0x9f43
movq 0xa095(%rip), %rax      # 0x13fc0
movq (%rax), %rdi
movq -0x260(%rbp), %rsi
callq 0xc0e0
movl $0x0, -0x4(%rbp)
jmp 0x9f6a
movq 0xa076(%rip), %rax      # 0x13fc0
movq (%rax), %rdi
movl -0x14(%rbp), %edx
leaq 0x612a(%rip), %rsi      # 0x10081
leaq 0x497f(%rip), %rcx      # 0xe8dd
callq 0xc120
movl $0x1, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x290, %rsp            # imm = 0x290
popq %rbp
retq
nopw %cs:(%rax,%rax)