#include "codegen.h"
#include "helpers.h"
#include <stdio.h>

void codegen(Node node, bool emit_type) {
    switch(node.type) {
    case NODE_FUNCTION_CALL:
        codegen_function_call(node.function_call);
        break;
    case NODE_FUNCTION_DECL:
        codegen_function_decl(node.function_decl);
        break;
    case NODE_FUNCTION_IMPL:
        codegen_function_impl(node.function_impl);
        break;
    case NODE_ARG_DECL:
        codegen_arg_decl(node.arg_decl, emit_type);
        break;
    case NODE_REFERENCE:
        codegen_reference(node.reference, emit_type);
        break;
    case NODE_NUMBER:
        codegen_number(node.number, emit_type);
        break;
    case NODE_RETURN:
        codegen_return(node.ret);
        break;
    default:
        syntax_error("unexpected node %c", node.type);
    }
}

void codegen_function_call(FunctionCall node) {
    printf("call $%s(", node.name);
    // printf("FunctionCall(%s", node.function_call.name);
    /*if(Nodes_size(&node.function_call.args) > 0)
        printf(", ");*/
    for(size_t i = 0; i < Nodes_size(&node.args); i++) {
        const Node* arg = Nodes_at(&node.args, i);
        codegen(*arg, true);

        if(arg != Nodes_back(&node.args)) {
            printf(", ");
        }
    }
    printf(")\n");
}

void codegen_function_decl(FunctionDecl node) {
    printf("FunctionDecl(%s, %s, ", node.type, node.name);
    for(size_t i = 0; i < Nodes_size(&node.args); i++) {
        const Node* arg = Nodes_at(&node.args, i);
        codegen(*arg, true);

        if(arg != Nodes_back(&node.args)) {
            printf(", ");
        }
    }
    printf(")\n");
}

void codegen_function_impl(FunctionImpl node) {
    printf("export function %s $%s(", node.type, node.name);
    for(size_t i = 0; i < Nodes_size(&node.args); i++) {
        const Node* arg = Nodes_at(&node.args, i);
        codegen(*arg, true);

        if(arg != Nodes_back(&node.args)) {
            printf(", ");
        }
    }
    printf(") {\n@start\n\t");

    for(size_t i = 0; i < Nodes_size(&node.body); i++) {
        const Node* n = Nodes_at(&node.body, i);
        codegen(*n, true);

        if(n != Nodes_back(&node.body)) {
            printf("\t");
        }
    }

    printf("\t\n}\n");
}

void codegen_arg_decl(ArgDecl node, bool emit_type) {
    // printf("ArgDecl(%s, %s)", node.arg_decl.type, node.arg_decl.name);
    if(emit_type) {
        printf("%s ", node.type);
    }
    printf("%%%s", node.name);
}

void codegen_reference(Reference node, bool emit_type) {
    // printf("Reference(%s)", node.reference.name);
    if(emit_type) {
        printf("%s ", node.type);
    }
    printf("%%%s", node.name);
}

void codegen_number(Number node, bool emit_type) {
    // printf("Number(%llu)", node.number.value);
    if(emit_type) {
        printf("w ");
    }
    printf("%d", node.value);
}

void codegen_return(Return node) {
    printf("ret ");
    if(node.value != NULL) {
        codegen(*node.value, false);
    }
}