#ifndef TACKY_H
#define TACKY_H

#include <stdbool.h>
#include "../parser/parser.h"

typedef enum {
    TACKY_VAL_CONSTANT,
    TACKY_VAL_VAR
} TackyValKind;

typedef struct {
    TackyValKind kind;
    int constant;      // valid if kind == TACKY_VAL_CONSTANT
    char *var_name;    // valid if kind == TACKY_VAL_VAR
    bool owns_name;
} TackyVal;

typedef enum {
    TACKY_UN_NEGATE,
    TACKY_UN_COMPLEMENT,
    TACKY_UN_NOT
} TackyUnaryOp;

typedef enum {
    TACKY_BIN_ADD,
    TACKY_BIN_SUB,
    TACKY_BIN_MUL,
    TACKY_BIN_DIV,
    TACKY_BIN_REM,
    TACKY_BIN_EQUAL,
    TACKY_BIN_NOT_EQUAL,
    TACKY_BIN_LESS,
    TACKY_BIN_LESS_EQUAL,
    TACKY_BIN_GREATER,
    TACKY_BIN_GREATER_EQUAL
} TackyBinaryOp;

typedef enum {
    TACKY_INSTR_RETURN,
    TACKY_INSTR_UNARY,
    TACKY_INSTR_BINARY,
    TACKY_INSTR_COPY,
    TACKY_INSTR_JUMP,
    TACKY_INSTR_JUMP_IF_ZERO,
    TACKY_INSTR_JUMP_IF_NOT_ZERO,
    TACKY_INSTR_LABEL
} TackyInstrKind;

typedef struct TackyInstr {
    TackyInstrKind kind;
    TackyVal ret_val;
    TackyUnaryOp un_op;
    TackyVal un_src;
    char *un_dst; // destination variable name

    TackyBinaryOp bin_op;
    TackyVal bin_src1;
    TackyVal bin_src2;
    char *bin_dst; // destination variable name for binary

    TackyVal copy_src;
    char *copy_dst;

    char *jump_target;
    TackyVal cond_val;

    char *label;

    struct TackyInstr *next;
} TackyInstr;

typedef struct {
    char *name;         // function name
    TackyInstr *body;   // linked list of instructions
} TackyFunction;

typedef struct {
    TackyFunction *fn;
} TackyProgram;

TackyProgram *tacky_from_ast(ASTNode *ast);

void tacky_print_txt(TackyProgram *p);
void tacky_print_json(TackyProgram *p);

void tacky_free(TackyProgram *p);

#endif
