nix-super/src/libexpr/c/nix_api_value.cc
2024-03-28 10:46:39 +01:00

454 lines
11 KiB
C++

#include "attr-set.hh"
#include "config.hh"
#include "eval.hh"
#include "gc/gc.h"
#include "globals.hh"
#include "primops.hh"
#include "value.hh"
#include "nix_api_expr.h"
#include "nix_api_expr_internal.h"
#include "nix_api_util.h"
#include "nix_api_util_internal.h"
#include "nix_api_value.h"
#ifdef HAVE_BOEHMGC
#define GC_INCLUDE_NEW 1
#include "gc_cpp.h"
#endif
// Helper function to throw an exception if value is null
static const nix::Value &check_value_not_null(const Value *value) {
if (!value) {
throw std::runtime_error("Value is null");
}
return *((const nix::Value *)value);
}
static nix::Value &check_value_not_null(Value *value) {
if (!value) {
throw std::runtime_error("Value is null");
}
return *((nix::Value *)value);
}
PrimOp *nix_alloc_primop(nix_c_context *context, PrimOpFun fun, int arity,
const char *name, const char **args, const char *doc) {
if (context)
context->last_err_code = NIX_OK;
try {
auto fun2 = (nix::PrimOpFun)fun;
auto p = new
#ifdef HAVE_BOEHMGC
(GC)
#endif
nix::PrimOp{.name = name,
.args = {},
.arity = (size_t)arity,
.doc = doc,
.fun = fun2};
if (args)
for (size_t i = 0; args[i]; i++)
p->args.emplace_back(*args);
nix_gc_incref(nullptr, p);
return (PrimOp *)p;
}
NIXC_CATCH_ERRS_NULL
}
nix_err nix_register_primop(nix_c_context *context, PrimOp *primOp) {
if (context)
context->last_err_code = NIX_OK;
try {
nix::RegisterPrimOp r(std::move(*((nix::PrimOp *)primOp)));
}
NIXC_CATCH_ERRS
}
Value *nix_alloc_value(nix_c_context *context, State *state) {
if (context)
context->last_err_code = NIX_OK;
try {
Value *res = state->state.allocValue();
nix_gc_incref(nullptr, res);
return res;
}
NIXC_CATCH_ERRS_NULL
}
ValueType nix_get_type(nix_c_context *context, const Value *value) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
using namespace nix;
switch (v.type()) {
case nThunk:
return NIX_TYPE_THUNK;
case nInt:
return NIX_TYPE_INT;
case nFloat:
return NIX_TYPE_FLOAT;
case nBool:
return NIX_TYPE_BOOL;
case nString:
return NIX_TYPE_STRING;
case nPath:
return NIX_TYPE_PATH;
case nNull:
return NIX_TYPE_NULL;
case nAttrs:
return NIX_TYPE_ATTRS;
case nList:
return NIX_TYPE_LIST;
case nFunction:
return NIX_TYPE_FUNCTION;
case nExternal:
return NIX_TYPE_EXTERNAL;
}
return NIX_TYPE_NULL;
}
NIXC_CATCH_ERRS_RES(NIX_TYPE_NULL);
}
const char *nix_get_typename(nix_c_context *context, const Value *value) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
auto s = nix::showType(v);
return strdup(s.c_str());
}
NIXC_CATCH_ERRS_NULL
}
bool nix_get_bool(nix_c_context *context, const Value *value) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
assert(v.type() == nix::nBool);
return v.boolean;
}
NIXC_CATCH_ERRS_RES(false);
}
const char *nix_get_string(nix_c_context *context, const Value *value) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
assert(v.type() == nix::nString);
return v.string.s;
}
NIXC_CATCH_ERRS_NULL
}
const char *nix_get_path_string(nix_c_context *context, const Value *value) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
assert(v.type() == nix::nPath);
return v._path;
}
NIXC_CATCH_ERRS_NULL
}
unsigned int nix_get_list_size(nix_c_context *context, const Value *value) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
assert(v.type() == nix::nList);
return v.listSize();
}
NIXC_CATCH_ERRS_RES(0);
}
unsigned int nix_get_attrs_size(nix_c_context *context, const Value *value) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
assert(v.type() == nix::nAttrs);
return v.attrs->size();
}
NIXC_CATCH_ERRS_RES(0);
}
double nix_get_float(nix_c_context *context, const Value *value) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
assert(v.type() == nix::nFloat);
return v.fpoint;
}
NIXC_CATCH_ERRS_RES(NAN);
}
int64_t nix_get_int(nix_c_context *context, const Value *value) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
assert(v.type() == nix::nInt);
return v.integer;
}
NIXC_CATCH_ERRS_RES(0);
}
ExternalValue *nix_get_external(nix_c_context *context, Value *value) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
assert(v.type() == nix::nExternal);
return (ExternalValue *)v.external;
}
NIXC_CATCH_ERRS_NULL;
}
Value *nix_get_list_byidx(nix_c_context *context, const Value *value,
State *state, unsigned int ix) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
assert(v.type() == nix::nList);
auto *p = v.listElems()[ix];
nix_gc_incref(nullptr, p);
state->state.forceValue(*p, nix::noPos);
return (Value *)p;
}
NIXC_CATCH_ERRS_NULL
}
Value *nix_get_attr_byname(nix_c_context *context, const Value *value,
State *state, const char *name) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
assert(v.type() == nix::nAttrs);
nix::Symbol s = state->state.symbols.create(name);
auto attr = v.attrs->get(s);
if (attr) {
nix_gc_incref(nullptr, attr->value);
state->state.forceValue(*attr->value, nix::noPos);
return attr->value;
}
nix_set_err_msg(context, NIX_ERR_KEY, "missing attribute");
return nullptr;
}
NIXC_CATCH_ERRS_NULL
}
bool nix_has_attr_byname(nix_c_context *context, const Value *value,
State *state, const char *name) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
assert(v.type() == nix::nAttrs);
nix::Symbol s = state->state.symbols.create(name);
auto attr = v.attrs->get(s);
if (attr)
return true;
return false;
}
NIXC_CATCH_ERRS_RES(false);
}
Value *nix_get_attr_byidx(nix_c_context *context, const Value *value,
State *state, unsigned int i, const char **name) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
const nix::Attr &a = (*v.attrs)[i];
*name = ((const std::string &)(state->state.symbols[a.name])).c_str();
nix_gc_incref(nullptr, a.value);
state->state.forceValue(*a.value, nix::noPos);
return a.value;
}
NIXC_CATCH_ERRS_NULL
}
const char *nix_get_attr_name_byidx(nix_c_context *context, const Value *value,
State *state, unsigned int i) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
const nix::Attr &a = (*v.attrs)[i];
return ((const std::string &)(state->state.symbols[a.name])).c_str();
}
NIXC_CATCH_ERRS_NULL
}
nix_err nix_set_bool(nix_c_context *context, Value *value, bool b) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
v.mkBool(b);
}
NIXC_CATCH_ERRS
}
// todo string context
nix_err nix_set_string(nix_c_context *context, Value *value, const char *str) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
v.mkString(std::string_view(str));
}
NIXC_CATCH_ERRS
}
nix_err nix_set_path_string(nix_c_context *context, Value *value,
const char *str) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
v.mkPath(std::string_view(str));
}
NIXC_CATCH_ERRS
}
nix_err nix_set_float(nix_c_context *context, Value *value, double d) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
v.mkFloat(d);
}
NIXC_CATCH_ERRS
}
nix_err nix_set_int(nix_c_context *context, Value *value, int64_t i) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
v.mkInt(i);
}
NIXC_CATCH_ERRS
}
nix_err nix_set_null(nix_c_context *context, Value *value) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
v.mkNull();
}
NIXC_CATCH_ERRS
}
nix_err nix_set_external(nix_c_context *context, Value *value,
ExternalValue *val) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
auto r = (nix::ExternalValueBase *)val;
v.mkExternal(r);
}
NIXC_CATCH_ERRS
}
nix_err nix_make_list(nix_c_context *context, State *s, Value *value,
unsigned int size) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
s->state.mkList(v, size);
}
NIXC_CATCH_ERRS
}
nix_err nix_set_list_byidx(nix_c_context *context, Value *value,
unsigned int ix, Value *elem) {
if (context)
context->last_err_code = NIX_OK;
try {
// todo: assert that this is a list
auto &v = check_value_not_null(value);
auto &e = check_value_not_null(elem);
v.listElems()[ix] = &e;
}
NIXC_CATCH_ERRS
}
nix_err nix_set_primop(nix_c_context *context, Value *value, PrimOp *p) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
v.mkPrimOp((nix::PrimOp *)p);
}
NIXC_CATCH_ERRS
}
nix_err nix_copy_value(nix_c_context *context, Value *value, Value *source) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
auto &s = check_value_not_null(source);
v = s;
}
NIXC_CATCH_ERRS
}
nix_err nix_make_attrs(nix_c_context *context, Value *value,
BindingsBuilder *b) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
v.mkAttrs(b->builder);
}
NIXC_CATCH_ERRS
}
BindingsBuilder *nix_make_bindings_builder(nix_c_context *context, State *state,
size_t capacity) {
if (context)
context->last_err_code = NIX_OK;
try {
auto bb = state->state.buildBindings(capacity);
return new
#if HAVE_BOEHMGC
(NoGC)
#endif
BindingsBuilder{std::move(bb)};
}
NIXC_CATCH_ERRS_NULL
}
nix_err nix_bindings_builder_insert(nix_c_context *context, BindingsBuilder *b,
const char *name, Value *value) {
if (context)
context->last_err_code = NIX_OK;
try {
auto &v = check_value_not_null(value);
nix::Symbol s = b->builder.state.symbols.create(name);
b->builder.insert(s, &v);
}
NIXC_CATCH_ERRS
}
void nix_bindings_builder_free(BindingsBuilder *bb) {
#if HAVE_BOEHMGC
GC_FREE((nix::BindingsBuilder *)bb);
#else
delete (nix::BindingsBuilder *)bb;
#endif
}