packages feed

nova-nix-0.6.0.0: cbits/nn_lambda.c

/*
 * nn_lambda.c - Lambda closure structs for nova-nix.
 *
 * Each nn_lambda_t is a malloc'd struct holding the closure env,
 * body bytecode index, and formals specification.  Tracked in a
 * global array for bulk cleanup at evaluation end.
 */

#include "nn_lambda.h"
#include "nn_assert.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* --- Global tracking for bulk cleanup --- */

static nn_lambda_t **g_tracked = NULL;
static uint32_t g_tracked_count = 0;
static uint32_t g_tracked_cap   = 0;

static void nn_lambda_track(nn_lambda_t *lam)
{
    if (g_tracked_count >= g_tracked_cap) {
        uint32_t new_cap = g_tracked_cap ? g_tracked_cap * 2 : 256;
        nn_lambda_t **new_arr = (nn_lambda_t **)realloc(
            g_tracked, (size_t)new_cap * sizeof(nn_lambda_t *));
        if (!new_arr) {
            fprintf(stderr, "nn_lambda_track: realloc failed\n");
            abort();
        }
        g_tracked = new_arr;
        g_tracked_cap = new_cap;
    }
    g_tracked[g_tracked_count++] = lam;
}

/* --- Lifecycle --- */

nn_lambda_t *
nn_lambda_new(struct nn_env *env, uint32_t body_bc_idx,
              uint8_t formals_type, uint32_t name_sym,
              uint8_t allow_extra, uint16_t formal_count)
{
    nn_lambda_t *lam = (nn_lambda_t *)malloc(sizeof(nn_lambda_t));
    if (!lam) return NULL;

    lam->env          = env;
    lam->body_bc_idx  = body_bc_idx;
    lam->formals_type = formals_type;
    lam->name_sym     = name_sym;
    lam->allow_extra  = allow_extra;
    lam->formal_count = formal_count;

    if (formal_count > 0) {
        lam->entries = (nn_formal_entry_t *)malloc(
            (size_t)formal_count * sizeof(nn_formal_entry_t));
        if (!lam->entries) {
            free(lam);
            return NULL;
        }
        memset(lam->entries, 0,
               (size_t)formal_count * sizeof(nn_formal_entry_t));
    } else {
        lam->entries = NULL;
    }

    nn_lambda_track(lam);
    return lam;
}

void
nn_lambda_set_entry(nn_lambda_t *lam, uint16_t idx,
                    uint32_t name_sym, uint32_t has_default,
                    uint32_t default_bc_idx)
{
    NN_ASSERT(idx < lam->formal_count, "nn_lambda_set_entry: idx out of bounds");
    lam->entries[idx].name_sym       = name_sym;
    lam->entries[idx].has_default    = has_default;
    lam->entries[idx].default_bc_idx = default_bc_idx;
}

void
nn_lambda_free_all(void)
{
    uint32_t i;
    for (i = 0; i < g_tracked_count; i++) {
        free(g_tracked[i]->entries);
        free(g_tracked[i]);
    }
    free(g_tracked);
    g_tracked = NULL;
    g_tracked_count = 0;
    g_tracked_cap = 0;
}

/* --- Accessors --- */

struct nn_env *
nn_lambda_env(const nn_lambda_t *lam)
{
    return lam->env;
}

uint32_t
nn_lambda_body(const nn_lambda_t *lam)
{
    return lam->body_bc_idx;
}

uint8_t
nn_lambda_formals_type(const nn_lambda_t *lam)
{
    return lam->formals_type;
}

uint32_t
nn_lambda_name_sym(const nn_lambda_t *lam)
{
    return lam->name_sym;
}

uint8_t
nn_lambda_allow_extra(const nn_lambda_t *lam)
{
    return lam->allow_extra;
}

uint16_t
nn_lambda_formal_count(const nn_lambda_t *lam)
{
    return lam->formal_count;
}

uint32_t
nn_lambda_entry_name(const nn_lambda_t *lam, uint16_t idx)
{
    NN_ASSERT(lam->entries != NULL && idx < lam->formal_count,
              "nn_lambda_entry_name: idx out of bounds or no formals");
    return lam->entries[idx].name_sym;
}

uint32_t
nn_lambda_entry_has_default(const nn_lambda_t *lam, uint16_t idx)
{
    NN_ASSERT(lam->entries != NULL && idx < lam->formal_count,
              "nn_lambda_entry_has_default: idx out of bounds or no formals");
    return lam->entries[idx].has_default;
}

uint32_t
nn_lambda_entry_default(const nn_lambda_t *lam, uint16_t idx)
{
    NN_ASSERT(lam->entries != NULL && idx < lam->formal_count,
              "nn_lambda_entry_default: idx out of bounds or no formals");
    return lam->entries[idx].default_bc_idx;
}