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

#include "symtab.h"

void symtab(void);

/** symtab.mc
 * Symbol Table Definition
 *
 * Scoped symbol tables for semantic analysis.
 * Each table is one scope; parent links form a chain.
 */
#include "arena.h"
#include "symbol.h"
#include "symkind.h"
#include "stddef.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "node.h"
/** One lexical scope */
/**
 * Report a fatal symbol-table error and exit.
 * Location-aware errors come later (tsemantic.mc + Node.token).
 */
void symtab_fatal(TSymbol* symbol, const char* msg)
{
    if (symbol != nil && ((*symbol)).decl != nil)
    {
        node_print(((*symbol)).decl, 0);
    }
    fprintf(stderr, "ERROR: symtab: %s\n", msg);
    exit(1);
}

/**
 * Create a new scope. parent may be nil (program/module scope).
 */
pTSymbolTable symtab_create(Arena* arena, pTSymbolTable parent)
{
    pTSymbolTable table = {0};
    if (arena == nil)
    {
        symtab_fatal(nil, "symtab_create: NULL arena");
    }
    table = (pTSymbolTable)arena_alloc(arena, ((integer)sizeof(TSymbolTable)));
    ((*table)).parent = parent;
    ((*table)).symbols = nil;
    ((*table)).count = 0;
    ((*table)).capacity = 0;
    /* return value captured before defers */
    pTSymbolTable __ret_l64 = table;
    return __ret_l64;
}

/**
 * Compare identifier spelling (length + bytes). No case folding.
 */
static bool symtab_names_equal(const char* a_name, size_t a_len, const char* b_name, size_t b_len)
{
    if (a_name == nil || b_name == nil)
    {
        /* return value captured before defers */
        bool __ret_l75 = false;
        return __ret_l75;
    }
    else if (a_len != b_len)
    {
        /* return value captured before defers */
        bool __ret_l77 = false;
        return __ret_l77;
    }
    else
    {
        /* return value captured before defers */
        bool __ret_l79 = memcmp(a_name, b_name, a_len) == 0;
        return __ret_l79;
    }
}

/**
 * Look up a name in the current scope only.
 * @return symbol, or nil if not found.
 */
pTSymbol symtab_lookup_current(pTSymbolTable table, const char* name, size_t name_len)
{
    size_t i = 0;
    if (table == nil || name == nil || name_len == 0)
    {
        /* return value captured before defers */
        pTSymbol __ret_l94 = nil;
        return __ret_l94;
    }
    {
        const long long __for_end_l97 = (long long)(((*table)).count);
        for (i = 1; (long long)(i) <= __for_end_l97; i++)
        {
            {
                const pTSymbol sym_l98_c10 = ((*table)).symbols[i - 1];
                if (sym_l98_c10 != nil && symtab_names_equal(((*sym_l98_c10)).name, ((*sym_l98_c10)).name_len, name, name_len))
                {
                    /* return value captured before defers */
                    pTSymbol __ret_l100 = sym_l98_c10;
                    return __ret_l100;
                }
            }
        }
    }
    /* return value captured before defers */
    pTSymbol __ret_l104 = nil;
    return __ret_l104;
}

/**
 * Look up a name in the current scope, then parent scopes.
 * @return symbol, or nil if not found.
 */
pTSymbol symtab_lookup(pTSymbolTable table, const char* name, size_t name_len)
{
    pTSymbolTable current = table;
    pTSymbol sym = nil;
    if (table == nil || name == nil || name_len == 0)
    {
        /* return value captured before defers */
        pTSymbol __ret_l119 = nil;
        return __ret_l119;
    }
    while (current != nil)
    {
        {
            sym = symtab_lookup_current(current, name, name_len);
            if (sym != nil)
            {
                /* return value captured before defers */
                pTSymbol __ret_l125 = sym;
                return __ret_l125;
            }
            current = ((*current)).parent;
        }
    }
    /* return value captured before defers */
    pTSymbol __ret_l130 = nil;
    return __ret_l130;
}

/**
 * Insert a symbol into the current scope.
 * Fatal on duplicate name in this scope.
 */
void symtab_define(Arena* arena, pTSymbolTable table, pTSymbol symbol)
{
    pTSymbol existing = nil;
    if (arena == nil)
    {
        symtab_fatal(nil, "symtab_define: NULL arena");
    }
    else if (table == nil)
    {
        symtab_fatal(nil, "symtab_define: NULL table");
    }
    else if (symbol == nil)
    {
        symtab_fatal(nil, "symtab_define: NULL symbol");
    }
    else if (((*symbol)).name == nil || ((*symbol)).name_len == 0)
    {
        symtab_fatal(symbol, "symtab_define: symbol has no name");
    }
    existing = symtab_lookup_current(table, ((*symbol)).name, ((*symbol)).name_len);
    if (existing != nil)
    {
        fprintf(stderr, "ERROR: symtab_define: duplicate '%.*s' (%s) in scope\n", (int)((*symbol)).name_len, ((*symbol)).name, symbol_kind_name(((*symbol)).kind));
        exit(1);
    }
    arena_append_ptr(arena, (ppvoid)(&((*table)).symbols), &((*table)).count, &((*table)).capacity, (pvoid)symbol);
}

/**
 * Insert or rebind a LET symbol in the current scope.
 * Rebinds when an existing LET has the same name; fatal on any other kind.
 */
void symtab_define_let(Arena* arena, pTSymbolTable table, pTSymbol symbol)
{
    pTSymbol existing = nil;
    size_t i = 0;
    if (arena == nil)
    {
        symtab_fatal(nil, "symtab_define_let: NULL arena");
    }
    else if (table == nil)
    {
        symtab_fatal(nil, "symtab_define_let: NULL table");
    }
    else if (symbol == nil)
    {
        symtab_fatal(nil, "symtab_define_let: NULL symbol");
    }
    else if (((*symbol)).name == nil || ((*symbol)).name_len == 0)
    {
        symtab_fatal(symbol, "symtab_define_let: symbol has no name");
    }
    existing = symtab_lookup_current(table, ((*symbol)).name, ((*symbol)).name_len);
    if (existing == nil)
    {
        arena_append_ptr(arena, (ppvoid)(&((*table)).symbols), &((*table)).count, &((*table)).capacity, (pvoid)symbol);
                return;
    }
    if (((*existing)).kind == SYM_KIND_LET)
    {
        {
            const long long __for_end_l191 = (long long)(((*table)).count);
            for (i = 1; (long long)(i) <= __for_end_l191; i++)
            {
                {
                    if (((*table)).symbols[i - 1] == existing)
                    {
                        ((*table)).symbols[i - 1] = symbol;
                                                return;
                    }
                }
            }
        }
        symtab_fatal(symbol, "symtab_define_let: internal error: LET symbol mising from table");
    }
    if (((*symbol)).decl != nil)
    {
        node_print(((*symbol)).decl, 0);
    }
    fprintf(stderr, "ERROR: symtab_define_let: cannot bind LET '%.*s' over existing %s\n", (int)((*symbol)).name_len, ((*symbol)).name, symbol_kind_name(((*existing)).kind));
    exit(1);
}

/**
 * Replace an existing symbol in the current scope (IMPORT refinement).
 */
void symtab_refine_symbol(Arena* arena, pTSymbolTable table, pTSymbol existing, pTSymbol replacement)
{
    size_t i = 0;
    if (arena == nil)
    {
        symtab_fatal(nil, "symtab_refine_symbol: NULL arena");
    }
    else if (table == nil)
    {
        symtab_fatal(nil, "symtab_refine_symbol: NULL table");
    }
    else if (existing == nil || replacement == nil)
    {
        symtab_fatal(nil, "symtab_refine_symbol: NULL symbol");
    }
    {
        const long long __for_end_l225 = (long long)(((*table)).count);
        for (i = 1; (long long)(i) <= __for_end_l225; i++)
        {
            {
                if (((*table)).symbols[i - 1] == existing)
                {
                    ((*table)).symbols[i - 1] = replacement;
                                        return;
                }
            }
        }
    }
    symtab_fatal(existing, "symtab_refine_symbol; symbol not found in current scope");
}


void symtab(void)
{
}
