2023-07-14 16:53:30 +03:00
|
|
|
#include <cstring>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#include "eval.hh"
|
2024-07-12 16:37:54 +03:00
|
|
|
#include "eval-gc.hh"
|
2023-07-14 16:53:30 +03:00
|
|
|
#include "globals.hh"
|
2024-06-14 19:41:09 +03:00
|
|
|
#include "eval-settings.hh"
|
2023-07-14 16:53:30 +03:00
|
|
|
|
|
|
|
#include "nix_api_expr.h"
|
|
|
|
#include "nix_api_expr_internal.h"
|
|
|
|
#include "nix_api_store.h"
|
|
|
|
#include "nix_api_store_internal.h"
|
|
|
|
#include "nix_api_util.h"
|
|
|
|
#include "nix_api_util_internal.h"
|
|
|
|
|
|
|
|
#ifdef HAVE_BOEHMGC
|
2023-07-28 11:49:21 +03:00
|
|
|
#include <mutex>
|
2023-07-14 16:53:30 +03:00
|
|
|
#define GC_INCLUDE_NEW 1
|
|
|
|
#include "gc_cpp.h"
|
|
|
|
#endif
|
|
|
|
|
2023-08-28 17:45:02 +03:00
|
|
|
nix_err nix_libexpr_init(nix_c_context * context)
|
|
|
|
{
|
|
|
|
if (context)
|
|
|
|
context->last_err_code = NIX_OK;
|
|
|
|
{
|
|
|
|
auto ret = nix_libutil_init(context);
|
|
|
|
if (ret != NIX_OK)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
{
|
|
|
|
auto ret = nix_libstore_init(context);
|
|
|
|
if (ret != NIX_OK)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
try {
|
|
|
|
nix::initGC();
|
|
|
|
}
|
|
|
|
NIXC_CATCH_ERRS
|
2023-07-14 16:53:30 +03:00
|
|
|
}
|
|
|
|
|
2024-01-10 12:58:35 +02:00
|
|
|
nix_err nix_expr_eval_from_string(
|
2024-06-13 19:51:58 +03:00
|
|
|
nix_c_context * context, EvalState * state, const char * expr, const char * path, nix_value * value)
|
2023-08-28 17:45:02 +03:00
|
|
|
{
|
|
|
|
if (context)
|
|
|
|
context->last_err_code = NIX_OK;
|
|
|
|
try {
|
|
|
|
nix::Expr * parsedExpr = state->state.parseExprFromString(expr, state->state.rootPath(nix::CanonPath(path)));
|
2024-06-13 19:51:58 +03:00
|
|
|
state->state.eval(parsedExpr, value->value);
|
|
|
|
state->state.forceValue(value->value, nix::noPos);
|
2023-08-28 17:45:02 +03:00
|
|
|
}
|
|
|
|
NIXC_CATCH_ERRS
|
2023-07-14 16:53:30 +03:00
|
|
|
}
|
|
|
|
|
2024-06-13 19:51:58 +03:00
|
|
|
nix_err nix_value_call(nix_c_context * context, EvalState * state, Value * fn, nix_value * arg, nix_value * value)
|
2023-08-28 17:45:02 +03:00
|
|
|
{
|
|
|
|
if (context)
|
|
|
|
context->last_err_code = NIX_OK;
|
|
|
|
try {
|
2024-06-13 19:51:58 +03:00
|
|
|
state->state.callFunction(fn->value, arg->value, value->value, nix::noPos);
|
|
|
|
state->state.forceValue(value->value, nix::noPos);
|
2023-08-28 17:45:02 +03:00
|
|
|
}
|
|
|
|
NIXC_CATCH_ERRS
|
2023-07-14 16:53:30 +03:00
|
|
|
}
|
|
|
|
|
2024-06-13 19:51:58 +03:00
|
|
|
nix_err nix_value_call_multi(nix_c_context * context, EvalState * state, nix_value * fn, size_t nargs, nix_value ** args, nix_value * value)
|
2024-05-23 20:55:32 +03:00
|
|
|
{
|
|
|
|
if (context)
|
|
|
|
context->last_err_code = NIX_OK;
|
|
|
|
try {
|
2024-06-13 19:51:58 +03:00
|
|
|
state->state.callFunction(fn->value, nargs, (nix::Value * *)args, value->value, nix::noPos);
|
|
|
|
state->state.forceValue(value->value, nix::noPos);
|
2024-05-23 20:55:32 +03:00
|
|
|
}
|
|
|
|
NIXC_CATCH_ERRS
|
|
|
|
}
|
|
|
|
|
2024-06-13 19:51:58 +03:00
|
|
|
nix_err nix_value_force(nix_c_context * context, EvalState * state, nix_value * value)
|
2023-08-28 17:45:02 +03:00
|
|
|
{
|
|
|
|
if (context)
|
|
|
|
context->last_err_code = NIX_OK;
|
|
|
|
try {
|
2024-06-13 19:51:58 +03:00
|
|
|
state->state.forceValue(value->value, nix::noPos);
|
2023-08-28 17:45:02 +03:00
|
|
|
}
|
|
|
|
NIXC_CATCH_ERRS
|
2023-07-14 16:53:30 +03:00
|
|
|
}
|
|
|
|
|
2024-06-13 19:51:58 +03:00
|
|
|
nix_err nix_value_force_deep(nix_c_context * context, EvalState * state, nix_value * value)
|
2023-08-28 17:45:02 +03:00
|
|
|
{
|
|
|
|
if (context)
|
|
|
|
context->last_err_code = NIX_OK;
|
|
|
|
try {
|
2024-06-13 19:51:58 +03:00
|
|
|
state->state.forceValueDeep(value->value);
|
2023-08-28 17:45:02 +03:00
|
|
|
}
|
|
|
|
NIXC_CATCH_ERRS
|
2023-07-14 16:53:30 +03:00
|
|
|
}
|
|
|
|
|
2024-04-13 18:35:15 +03:00
|
|
|
EvalState * nix_state_create(nix_c_context * context, const char ** lookupPath_c, Store * store)
|
2023-08-28 17:45:02 +03:00
|
|
|
{
|
|
|
|
if (context)
|
|
|
|
context->last_err_code = NIX_OK;
|
|
|
|
try {
|
2024-04-13 18:35:15 +03:00
|
|
|
nix::Strings lookupPath;
|
|
|
|
if (lookupPath_c != nullptr)
|
|
|
|
for (size_t i = 0; lookupPath_c[i] != nullptr; i++)
|
|
|
|
lookupPath.push_back(lookupPath_c[i]);
|
2023-08-28 17:45:02 +03:00
|
|
|
|
2024-06-14 19:41:09 +03:00
|
|
|
void * p = ::operator new(
|
|
|
|
sizeof(EvalState),
|
|
|
|
static_cast<std::align_val_t>(alignof(EvalState)));
|
|
|
|
auto * p2 = static_cast<EvalState *>(p);
|
|
|
|
new (p) EvalState {
|
|
|
|
.settings = nix::EvalSettings{
|
|
|
|
nix::settings.readOnlyMode,
|
|
|
|
},
|
|
|
|
.state = nix::EvalState(
|
|
|
|
nix::LookupPath::parse(lookupPath),
|
|
|
|
store->ptr,
|
|
|
|
p2->settings),
|
|
|
|
};
|
|
|
|
loadConfFile(p2->settings);
|
|
|
|
return p2;
|
2023-08-28 17:45:02 +03:00
|
|
|
}
|
|
|
|
NIXC_CATCH_ERRS_NULL
|
2023-07-14 16:53:30 +03:00
|
|
|
}
|
|
|
|
|
2024-01-10 12:58:35 +02:00
|
|
|
void nix_state_free(EvalState * state)
|
2023-08-28 17:45:02 +03:00
|
|
|
{
|
|
|
|
delete state;
|
|
|
|
}
|
2023-07-14 16:53:30 +03:00
|
|
|
|
2023-07-28 11:49:21 +03:00
|
|
|
#ifdef HAVE_BOEHMGC
|
|
|
|
std::unordered_map<
|
2023-08-28 17:45:02 +03:00
|
|
|
const void *,
|
|
|
|
unsigned int,
|
|
|
|
std::hash<const void *>,
|
2023-07-28 11:49:21 +03:00
|
|
|
std::equal_to<const void *>,
|
2023-08-28 17:45:02 +03:00
|
|
|
traceable_allocator<std::pair<const void * const, unsigned int>>>
|
2023-07-28 11:49:21 +03:00
|
|
|
nix_refcounts;
|
|
|
|
|
|
|
|
std::mutex nix_refcount_lock;
|
|
|
|
|
2023-08-28 17:45:02 +03:00
|
|
|
nix_err nix_gc_incref(nix_c_context * context, const void * p)
|
|
|
|
{
|
|
|
|
if (context)
|
|
|
|
context->last_err_code = NIX_OK;
|
|
|
|
try {
|
|
|
|
std::scoped_lock lock(nix_refcount_lock);
|
|
|
|
auto f = nix_refcounts.find(p);
|
|
|
|
if (f != nix_refcounts.end()) {
|
|
|
|
f->second++;
|
|
|
|
} else {
|
|
|
|
nix_refcounts[p] = 1;
|
|
|
|
}
|
2023-07-28 17:21:29 +03:00
|
|
|
}
|
2023-08-28 17:45:02 +03:00
|
|
|
NIXC_CATCH_ERRS
|
2023-07-14 16:53:30 +03:00
|
|
|
}
|
|
|
|
|
2023-08-28 17:45:02 +03:00
|
|
|
nix_err nix_gc_decref(nix_c_context * context, const void * p)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (context)
|
|
|
|
context->last_err_code = NIX_OK;
|
|
|
|
try {
|
|
|
|
std::scoped_lock lock(nix_refcount_lock);
|
|
|
|
auto f = nix_refcounts.find(p);
|
|
|
|
if (f != nix_refcounts.end()) {
|
|
|
|
if (--f->second == 0)
|
|
|
|
nix_refcounts.erase(f);
|
|
|
|
} else
|
|
|
|
throw std::runtime_error("nix_gc_decref: object was not referenced");
|
|
|
|
}
|
|
|
|
NIXC_CATCH_ERRS
|
2023-07-28 11:49:21 +03:00
|
|
|
}
|
|
|
|
|
2023-08-28 17:45:02 +03:00
|
|
|
void nix_gc_now()
|
|
|
|
{
|
|
|
|
GC_gcollect();
|
|
|
|
}
|
2023-07-28 14:47:54 +03:00
|
|
|
|
2023-07-14 16:53:30 +03:00
|
|
|
#else
|
2024-04-04 22:24:42 +03:00
|
|
|
nix_err nix_gc_incref(nix_c_context * context, const void *)
|
2023-08-28 17:45:02 +03:00
|
|
|
{
|
|
|
|
if (context)
|
|
|
|
context->last_err_code = NIX_OK;
|
|
|
|
return NIX_OK;
|
2023-07-28 17:21:29 +03:00
|
|
|
}
|
2024-04-04 22:24:42 +03:00
|
|
|
nix_err nix_gc_decref(nix_c_context * context, const void *)
|
2023-08-28 17:45:02 +03:00
|
|
|
{
|
|
|
|
if (context)
|
|
|
|
context->last_err_code = NIX_OK;
|
|
|
|
return NIX_OK;
|
2023-07-28 17:21:29 +03:00
|
|
|
}
|
2023-07-28 14:47:54 +03:00
|
|
|
void nix_gc_now() {}
|
2023-07-14 16:53:30 +03:00
|
|
|
#endif
|
|
|
|
|
2024-06-13 19:21:04 +03:00
|
|
|
nix_err nix_value_incref(nix_c_context * context, nix_value *x)
|
|
|
|
{
|
|
|
|
return nix_gc_incref(context, (const void *) x);
|
|
|
|
}
|
|
|
|
nix_err nix_value_decref(nix_c_context * context, nix_value *x)
|
|
|
|
{
|
|
|
|
return nix_gc_decref(context, (const void *) x);
|
|
|
|
}
|
|
|
|
|
2023-08-28 17:45:02 +03:00
|
|
|
void nix_gc_register_finalizer(void * obj, void * cd, void (*finalizer)(void * obj, void * cd))
|
|
|
|
{
|
2023-07-14 16:53:30 +03:00
|
|
|
#ifdef HAVE_BOEHMGC
|
2023-08-28 17:45:02 +03:00
|
|
|
GC_REGISTER_FINALIZER(obj, finalizer, cd, 0, 0);
|
2023-07-14 16:53:30 +03:00
|
|
|
#endif
|
|
|
|
}
|