packages feed

nova-nix-0.6.0.0: cbits/nn_lambda.h

/*
 * nn_lambda.h - Lambda closure structs for nova-nix.
 *
 * Stores lambda closures entirely in C: captured environment (nn_env_t*),
 * body bytecode index, and formal parameter specification.  Replaces
 * StablePtr NixValue for VLambda on the GHC heap (~25% of remaining
 * heap after M6) with a C-native tag 9 in the thunk system.
 *
 * Formals are stored as a type tag (Name/Set/NamedSet) plus an array
 * of (symbol, has_default, default_bc_idx) entries for set patterns.
 * Interned symbols avoid any string allocation - pointer equality
 * for name comparison.
 *
 * Lambda structs are malloc'd and tracked for bulk cleanup via
 * nn_lambda_free_all().  Formal entry arrays use malloc (small, typ.
 * 1-20 entries).  All freed at evaluation end.
 *
 * Lifecycle: constructed during evaluation, freed via
 * nn_lambda_free_all() at arena teardown.  Not thread-safe.
 */

#ifndef NN_LAMBDA_H
#define NN_LAMBDA_H

#include <stdint.h>

/* Forward declarations */
struct nn_env;

/* --- Formals type tags --- */

#define NN_FORMALS_NAME      0   /* x: body */
#define NN_FORMALS_SET       1   /* { a, b, ... }: body */
#define NN_FORMALS_NAMED_SET 2   /* x@{ a, b, ... }: body */

/* --- Types --- */

/* A single formal entry: name + optional default bytecode index. */
typedef struct nn_formal_entry {
    uint32_t name_sym;       /* interned symbol ID */
    uint32_t has_default;    /* 0 = required, 1 = has default */
    uint32_t default_bc_idx; /* bytecode index of default (valid if has_default) */
} nn_formal_entry_t;

/* Lambda closure: env + body + formals specification.
 * Packed for minimal size (pointers first, then uint32s, then small fields).
 * 28 bytes on 64-bit (no padding). */
typedef struct nn_lambda {
    struct nn_env         *env;          /* captured closure environment */
    nn_formal_entry_t     *entries;      /* formal entries (malloc'd, or NULL) */
    uint32_t               body_bc_idx;  /* bytecode index of lambda body */
    uint32_t               name_sym;     /* symbol for Name/NamedSet binding */
    uint16_t               formal_count; /* number of formal entries */
    uint8_t                formals_type; /* NN_FORMALS_NAME/SET/NAMED_SET */
    uint8_t                allow_extra;  /* 1 if ellipsis (...) present */
} nn_lambda_t;

/* --- Lifecycle --- */

/* Allocate a new lambda closure.  The entries array is allocated
 * internally (formal_count entries).  Fill entries via
 * nn_lambda_set_entry() after construction.
 * Returns NULL on allocation failure. */
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);

/* Set a formal entry at the given index (for construction).
 * Index must be < formal_count. */
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);

/* Free all tracked lambda structs (arena-style cleanup).
 * Also frees all entries arrays.
 * Call once at evaluation end. */
void nn_lambda_free_all(void);

/* --- Accessors --- */

struct nn_env *nn_lambda_env(const nn_lambda_t *lam);
uint32_t       nn_lambda_body(const nn_lambda_t *lam);
uint8_t        nn_lambda_formals_type(const nn_lambda_t *lam);
uint32_t       nn_lambda_name_sym(const nn_lambda_t *lam);
uint8_t        nn_lambda_allow_extra(const nn_lambda_t *lam);
uint16_t       nn_lambda_formal_count(const nn_lambda_t *lam);

/* Read formal entry fields by index (must be < formal_count). */
uint32_t nn_lambda_entry_name(const nn_lambda_t *lam, uint16_t idx);
uint32_t nn_lambda_entry_has_default(const nn_lambda_t *lam, uint16_t idx);
uint32_t nn_lambda_entry_default(const nn_lambda_t *lam, uint16_t idx);

#endif /* NN_LAMBDA_H */