#ifndef ASSEMBLY_H
#define ASSEMBLY_H

#include "../tacky/tacky.h"
#include <stdio.h>

typedef enum {
    ASM_MOV,
    ASM_RET,
    ASM_NEG,
    ASM_NOT,
    ASM_ADD_ECX_EAX,
    ASM_SUB_EAX_ECX,
    ASM_IMUL_ECX_EAX,
    ASM_IDIV_ECX,
    ASM_MOV_EDX_EAX,
    ASM_XCHG_EAX_ECX,
    ASM_CLTD,
    ASM_CMP,
    ASM_SETCC,
    ASM_JMP,
    ASM_JCC,
    ASM_LABEL,
} AssemblyInstructionType;

typedef enum {
    ASM_COND_E,
    ASM_COND_NE,
    ASM_COND_L,
    ASM_COND_LE,
    ASM_COND_G,
    ASM_COND_GE,
    ASM_COND_NONE
} AssemblyCondCode;

typedef enum {
    OPERAND_IMMEDIATE,
    OPERAND_REGISTER,
    OPERAND_MEM_RBP_OFFSET
} OperandType;

typedef struct {
    OperandType type;
    int value;  
} Operand;

typedef struct AssemblyInstruction {
    AssemblyInstructionType type;
    Operand src;
    Operand dst;
    AssemblyCondCode cond;
    char *label;
    struct AssemblyInstruction *next;
} AssemblyInstruction;

typedef struct {
    char *name;
    AssemblyInstruction *instructions;
    int stack_size;
} AssemblyFunction;

typedef struct {
    AssemblyFunction *function;
} AssemblyProgram;

AssemblyProgram *generate_assembly(TackyProgram *tacky);
void print_assembly(AssemblyProgram *program);
void free_assembly(AssemblyProgram *program);
char *get_output_assembly_path(const char *source_file);
void write_assembly_to_file(AssemblyProgram *program, const char *source_file);
void write_assembly_to_stream(AssemblyProgram *program, FILE *stream);

#endif 
