/* =====================================
 * Generated by Mod-c 0.26.5
 * MODULE codegen_header
 * ===================================== */

#include "codegen_header.h"

void codegen_header(CodegenContext ctx);

/**
 * Mod-c
 * By M. Scott Reynolds
 * Date 11 July 2026
 *
 * codegen_header.mc - Generate header file from AST.
 *
 * Generation of C header files (.h) for the -H option.
 * Only emits the exported surface of a program/module.
 */
#include "dynbuf.h"
#include "stddef.h"
#include "stdlib.h"
#include "codegen_common.h"
#include "ttype.h"
#include "node.h"
#include "Lexer.h"
#include "version.h"
#include "stdio.h"
/**
 * Emit Header PROCEDURE or FUNCTION declaration.
 * All treated as a prototype.
 */
static void codegen_header_proc_or_func(const Node* n, CodegenContext ctx)
{
    if (n == nil)
    {
                return;
    }
    codegen_common_proc_or_func(n, ctx);
    dynbuf_append_char((ctx).out, ';');
    dynbuf_append((ctx).out, "\n");
}

/**
 * Generate header exported declaration
 */
static void codegen_header_emit_exported(const Node* n, CodegenContext ctx)
{
    if (n == nil)
    {
                return;
    }
    if ((((*n)).kind == NODE_LET_DECL || ((*n)).kind == NODE_VAR_DECL || ((*n)).kind == NODE_CONST_DECL))
    {
        if ((((*n)).var_decl).is_exported)
        {
            integer i = 0;
            emit_indent((ctx).out, (ctx).indent);
            dynbuf_append((ctx).out, "/* === LET/VAR/CONST EXPORT === */\n");
            {
                const long long __for_end_l78 = (long long)((((*n)).var_decl).count - 1);
                for (i = 0; (long long)(i) <= __for_end_l78; i++)
                {
                    {
                        const Node* item_l79_c13 = (((*n)).var_decl).items[i];
                        if (item_l79_c13 == nil)
                        {
                                                        /* INVARIANT (on loop exit) */
                            continue;
                        }
                        if (i > 0)
                        {
                            emit_indent((ctx).out, (ctx).indent);
                        }
                        if ((((*n)).var_decl).is_extern)
                        {
                            dynbuf_append((ctx).out, "extern ");
                        }
                        if (((*n)).kind == NODE_LET_DECL || ((*n)).kind == NODE_CONST_DECL)
                        {
                            dynbuf_append((ctx).out, "const ");
                        }
                        emit_var_decl((ctx).out, (((*item_l79_c13)).var_item).name, (((*item_l79_c13)).var_item).name_len, (((*item_l79_c13)).var_item).item_type);
                        if (!(((*n)).var_decl).is_extern)
                        {
                            if ((((*item_l79_c13)).var_item).initializer != nil)
                            {
                                dynbuf_append((ctx).out, " = ");
                                codegen_common_expr((((*item_l79_c13)).var_item).initializer, ctx);
                            }
                            else
                            {
                                dynbuf_append((ctx).out, " = {0}");
                            }
                        }
                        dynbuf_append((ctx).out, ";\n");
                        dynbuf_append_char((ctx).out, '\n');
                    }
                }
            }
        }
    }
    else if (((*n)).kind == NODE_PROC_DECL || ((*n)).kind == NODE_FUNC_DECL)
    {
        if ((((*n)).proc_decl).is_exported)
        {
            emit_indent((ctx).out, (ctx).indent);
            dynbuf_append((ctx).out, "/* === PROC/FUNC EXPORT === */\n");
            codegen_header_proc_or_func(n, ctx);
            dynbuf_append_char((ctx).out, '\n');
        }
    }
    else if (((*n)).kind == NODE_TYPE_DECL)
    {
        if ((((*n)).type_decl).is_exported || ((((*n)).type_decl).name != nil && type_is_portable_rebindable((((*n)).type_decl).name, (((*n)).type_decl).name_len) && !(((*n)).type_decl).is_forward && !(((*n)).type_decl).is_extern))
        {
            emit_indent((ctx).out, (ctx).indent);
            dynbuf_append((ctx).out, "/* === TYPE EXPORT === */\n");
            codegen_common_type_decl(n, ctx);
            dynbuf_append_char((ctx).out, '\n');
        }
    }
    else if (((*n)).kind == NODE_DOC_COMMENT)
    {
        emit_doc_comment_as_c((ctx).out, n);
        dynbuf_append_char((ctx).out, '\n');
    }
}

/**
 * Walk the AST, create header file, and emit only exported declarations.
 */
static void codegen_header_program(const Node* n, CodegenContext ctx)
{
    const char* header_type = "UNKNOWN";
    if (n == nil || ((*n)).kind != NODE_PROGRAM)
    {
        fprintf(stderr, "ERROR: codegen_header_program: expected PROGRAM node\n");
                return;
    }
    header_type = "UNKNOWN";
    if ((((*n)).program_decl).unit_kind == TOK_KEYWORD_PROGRAM)
    {
        header_type = "PROGRAM";
    }
    else if ((((*n)).program_decl).unit_kind == TOK_KEYWORD_MODULE)
    {
        header_type = "MODULE";
    }
    dynbuf_append((ctx).out, "/* =====================================\n");
    dynbuf_append((ctx).out, " * Generated by Mod-c ");
    dynbuf_append((ctx).out, VERSION_BASE);
    dynbuf_append((ctx).out, "\n");
    dynbuf_append((ctx).out, " * HEADER ");
    dynbuf_appendn((ctx).out, (((*n)).program_decl).name, (((*n)).program_decl).name_len);
    dynbuf_append_char((ctx).out, ' ');
    dynbuf_append((ctx).out, header_type);
    dynbuf_append_char((ctx).out, '\n');
    dynbuf_append((ctx).out, " * ===================================== */\n\n");
    dynbuf_append((ctx).out, "#ifndef MODC_");
    dynbuf_append((ctx).out, header_type);
    dynbuf_append_char((ctx).out, '_');
    dynbuf_appendn((ctx).out, (((*n)).program_decl).name, (((*n)).program_decl).name_len);
    dynbuf_append((ctx).out, "_H\n");
    dynbuf_append((ctx).out, "#define MODC_");
    dynbuf_append((ctx).out, header_type);
    dynbuf_append_char((ctx).out, '_');
    dynbuf_appendn((ctx).out, (((*n)).program_decl).name, (((*n)).program_decl).name_len);
    dynbuf_append((ctx).out, "_H\n\n");
    codegen_emit_c_prelude((ctx).out, n);
    if ((((*n)).program_decl).decls != nil)
    {
        size_t i = 0;
        {
            const long long __for_end_l200 = (long long)((((*n)).program_decl).count - 1);
            for (i = 0; (long long)(i) <= __for_end_l200; i++)
            {
                {
                    const Node* d_l201_c9 = (((*n)).program_decl).decls[i];
                    if (((*d_l201_c9)).kind == NODE_IMPORT)
                    {
                        dynbuf_append((ctx).out, "/* === IMPORT === */\n");
                        codegen_common_import(d_l201_c9, ctx);
                        dynbuf_append_char((ctx).out, '\n');
                    }
                    else
                    {
                        codegen_header_emit_exported(d_l201_c9, ctx);
                    }
                }
            }
        }
    }
    codegen_common_module_prototype(n, ctx);
    dynbuf_append((ctx).out, "#endif /* MODC_");
    dynbuf_append((ctx).out, header_type);
    dynbuf_append_char((ctx).out, '_');
    dynbuf_appendn((ctx).out, (((*n)).program_decl).name, (((*n)).program_decl).name_len);
    dynbuf_append((ctx).out, "_H */\n");
}

/**
 * Generate a C header file from the given AST.
 * This is the entry point called when TARGET_HEADER is
 * selected.
 */

void codegen_header(CodegenContext ctx)
{
    if ((ctx).ast == nil || (ctx).out == nil)
    {
        fprintf(stderr, "FATAL ERROR: codegen_header: NULL argument\n");
        exit(1);
    }
    codegen_header_program((ctx).ast, ctx);
}
