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

#include "codegen_dbc.h"

void codegen_dbc(void);

/**
 * Mod-c
 * By M. Scott Reynolds
 * Date 18 April 2026
 *
 * codegen_dbc.c - Desing By Contract routines.	
 */
#include "stddef.h"
#include "dynbuf.h"
#include "node.h"
#include "codegen_common.h"
/**
 * Generate REQUIRE clauses
 */
void codegen_dbc_emit_requires(const Node* n, CodegenContext ctx)
{
    size_t i = 0;
    if (n == nil || ((*n)).kind != NODE_BLOCK || (((*n)).block).require_count == 0 || (ctx).dbc_off)
    {
                return;
    }
    {
        const long long __for_end_l36 = (long long)((((*n)).block).require_count);
        for (i = 1; (long long)(i) <= __for_end_l36; i++)
        {
            {
                const pNode e_l37_c8 = (((*n)).block).requires[i - 1];
                if ((ctx).debug_enabled)
                {
                    emit_indent((ctx).out, (ctx).indent);
                    dynbuf_append((ctx).out, "/* REQUIRE */\n");
                }
                emit_indent((ctx).out, (ctx).indent);
                dynbuf_append((ctx).out, "assert(");
                codegen_common_expr(e_l37_c8, ctx);
                dynbuf_append((ctx).out, "); /* precondition */\n");
            }
        }
    }
}

/**
 * Generate ENSURE clauses
 */
void codegen_dbc_emit_ensures(const Node* n, CodegenContext ctx)
{
    size_t i = 0;
    if (n == nil || ((*n)).kind != NODE_BLOCK || (((*n)).block).ensure_count == 0 || (ctx).dbc_off)
    {
                return;
    }
    {
        const long long __for_end_l62 = (long long)((((*n)).block).ensure_count);
        for (i = 1; (long long)(i) <= __for_end_l62; i++)
        {
            {
                const pNode e_l63_c8 = (((*n)).block).ensures[i - 1];
                if ((ctx).debug_enabled)
                {
                    emit_indent((ctx).out, (ctx).indent);
                    dynbuf_append((ctx).out, "/* ENSURE */\n");
                }
                emit_indent((ctx).out, (ctx).indent);
                dynbuf_append((ctx).out, "assert(");
                codegen_common_expr(e_l63_c8, ctx);
                dynbuf_append((ctx).out, "); /* postcodition */\n");
            }
        }
    }
}

/**
 * Emit Ensures to Func
 */
void codegen_dbc_emit_ensures_to_func(CodegenContext ctx)
{
    CodegenContext current = ctx;
    const Node* target_func_l82_c17 = (ctx).enclosing_func;
    if ((ctx).dbc_off)
    {
                return;
    }
    while ((current).parent_ctx != nil)
    {
        {
            if ((current).parent_node != nil && ((*(current).parent_node)).kind == NODE_BLOCK)
            {
                if ((((*(current).parent_node)).block).ensure_count > 0)
                {
                    dynbuf_append((ctx).out, "/* ENSURE (on return) */\n");
                    codegen_dbc_emit_ensures((current).parent_node, current);
                }
            }
            if ((current).enclosing_func != nil && (current).parent_node == target_func_l82_c17)
            {
                                /* INVARIANT (on loop exit) */
                break;
            }
            current = (*(current).parent_ctx);
        }
    }
}

/**
 * Emit INVARIANT checks for a loop node.
 * Called at the "invariant point" inside the generated loop (before body for most loops).
 */
void codegen_dbc_emit_invariants(const Node* n, CodegenContext ctx)
{
    pNode* invs = nil;
    size_t count = 0;
    size_t i = 0;
    if (n == nil || (ctx).dbc_off)
    {
                return;
    }
    if (((*n)).kind == NODE_WHILE)
    {
        invs = (((*n)).while_stmt).invariants;
        count = (((*n)).while_stmt).invariant_count;
    }
    else if (((*n)).kind == NODE_FOR)
    {
        invs = (((*n)).for_stmt).invariants;
        count = (((*n)).for_stmt).invariant_count;
    }
    else if (((*n)).kind == NODE_REPEAT_UNTIL)
    {
        invs = (((*n)).repeat_until).invariants;
        count = (((*n)).repeat_until).invariant_count;
    }
    else if (((*n)).kind == NODE_LOOP)
    {
        invs = (((*n)).loop_stmt).invariants;
        count = (((*n)).loop_stmt).invariant_count;
    }
    else
    {
                return;
    }
    {
        const long long __for_end_l137 = (long long)(count);
        for (i = 1; (long long)(i) <= __for_end_l137; i++)
        {
            {
                const pNode e_l138_c8 = invs[i - 1];
                if ((ctx).debug_enabled)
                {
                    emit_indent((ctx).out, (ctx).indent);
                    dynbuf_append((ctx).out, "/* INVARIANT */\n");
                }
                emit_indent((ctx).out, (ctx).indent);
                dynbuf_append((ctx).out, "assert(");
                codegen_common_expr(e_l138_c8, ctx);
                dynbuf_append((ctx).out, "); /* invariant */\n");
            }
        }
    }
}

/**
 * Emit invariants for the loop being exited (called before BREAK/CONTINUE).
 * Mirros the structure of the defers_to_loop wlaker.
 */
void codegen_dbc_emit_invariants_to_loop(CodegenContext ctx)
{
    CodegenContext current = ctx;
    if ((ctx).dbc_off)
    {
                return;
    }
    while ((current).parent_ctx != nil)
    {
        {
            if ((current).parent_node != nil)
            {
                if (((*(current).parent_node)).kind == NODE_WHILE || ((*(current).parent_node)).kind == NODE_FOR || ((*(current).parent_node)).kind == NODE_REPEAT_UNTIL || ((*(current).parent_node)).kind == NODE_LOOP)
                {
                    emit_indent((ctx).out, (ctx).indent);
                    dynbuf_append((ctx).out, "/* INVARIANT (on loop exit) */\n");
                    codegen_dbc_emit_invariants((current).parent_node, current);
                                        /* INVARIANT (on loop exit) */
                    break;
                }
            }
            current = (*(current).parent_ctx);
        }
    }
}


void codegen_dbc(void)
{
}
