mirror of
https://github.com/NixOS/nix.git
synced 2024-11-24 07:42:27 +00:00
libexpr: add C bindings
This commit is contained in:
parent
1d41600498
commit
e76652a5d3
@ -897,6 +897,10 @@ void Value::mkStringMove(const char * s, const NixStringContext & context)
|
||||
copyContextToValue(*this, context);
|
||||
}
|
||||
|
||||
void Value::mkPath(std::string_view path)
|
||||
{
|
||||
mkPath(makeImmutableString(path));
|
||||
}
|
||||
|
||||
void Value::mkPath(const SourcePath & path)
|
||||
{
|
||||
|
141
src/libexpr/nix_api_expr.cc
Normal file
141
src/libexpr/nix_api_expr.cc
Normal file
@ -0,0 +1,141 @@
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "config.hh"
|
||||
#include "eval.hh"
|
||||
#include "globals.hh"
|
||||
#include "util.hh"
|
||||
|
||||
#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
|
||||
#define GC_INCLUDE_NEW 1
|
||||
#include "gc_cpp.h"
|
||||
#endif
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
Expr *nix_parse_expr_from_string(nix_c_context *context, State *state,
|
||||
const char *expr, const char *path,
|
||||
GCRef *ref) {
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
Expr *result = state->state.parseExprFromString(
|
||||
expr, state->state.rootPath(nix::CanonPath(path)));
|
||||
if (ref)
|
||||
ref->ptr = result;
|
||||
return result;
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
nix_err nix_expr_eval(nix_c_context *context, State *state, Expr *expr,
|
||||
Value *value) {
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
state->state.eval((nix::Expr *)expr, *(nix::Value *)value);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_value_call(nix_c_context *context, State *state, Value *fn,
|
||||
Value *arg, Value *value) {
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
state->state.callFunction(*(nix::Value *)fn, *(nix::Value *)arg,
|
||||
*(nix::Value *)value, nix::noPos);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_value_force(nix_c_context *context, State *state, Value *value) {
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
state->state.forceValue(*(nix::Value *)value, nix::noPos);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_value_force_deep(nix_c_context *context, State *state,
|
||||
Value *value) {
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
state->state.forceValueDeep(*(nix::Value *)value);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
State *nix_state_create(nix_c_context *context, const char **searchPath_c,
|
||||
Store *store) {
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
nix::Strings searchPath;
|
||||
if (searchPath_c != nullptr)
|
||||
for (size_t i = 0; searchPath_c[i] != nullptr; i++)
|
||||
searchPath.push_back(searchPath_c[i]);
|
||||
|
||||
return new State{
|
||||
nix::EvalState(nix::SearchPath::parse(searchPath), store->ptr)};
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
void nix_state_free(State *state) { delete state; }
|
||||
|
||||
GCRef *nix_gc_ref(nix_c_context *context, void *obj) {
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
#if HAVE_BOEHMGC
|
||||
return new (NoGC) GCRef{obj};
|
||||
#else
|
||||
return new GCRef{obj};
|
||||
#endif
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
void nix_gc_free(GCRef *ref) {
|
||||
#if HAVE_BOEHMGC
|
||||
GC_FREE(ref);
|
||||
#else
|
||||
delete ref;
|
||||
#endif
|
||||
}
|
||||
|
||||
void nix_gc_register_finalizer(void *obj, void *cd,
|
||||
void (*finalizer)(void *obj, void *cd)) {
|
||||
#ifdef HAVE_BOEHMGC
|
||||
GC_REGISTER_FINALIZER(obj, finalizer, cd, 0, 0);
|
||||
#endif
|
||||
}
|
176
src/libexpr/nix_api_expr.h
Normal file
176
src/libexpr/nix_api_expr.h
Normal file
@ -0,0 +1,176 @@
|
||||
#ifndef NIX_API_EXPR_H
|
||||
#define NIX_API_EXPR_H
|
||||
/** @file
|
||||
* @brief Main entry for the libexpr C bindings
|
||||
*/
|
||||
|
||||
#include "nix_api_store.h"
|
||||
#include "nix_api_util.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// cffi start
|
||||
|
||||
// Type definitions
|
||||
/**
|
||||
* @brief Represents a parsed nix Expression, can be evaluated into a Value.
|
||||
*
|
||||
* Owned by the GC.
|
||||
*/
|
||||
typedef void Expr; // nix::Expr
|
||||
/**
|
||||
* @brief Represents a nix evaluator state.
|
||||
*
|
||||
* Multiple can be created for multi-threaded
|
||||
* operation.
|
||||
*/
|
||||
typedef struct State State; // nix::EvalState
|
||||
/**
|
||||
* @brief Represents a nix value.
|
||||
*
|
||||
* Owned by the GC.
|
||||
*/
|
||||
typedef void Value; // nix::Value
|
||||
/**
|
||||
* @brief Reference for the GC
|
||||
*
|
||||
* Nix uses a garbage collector that may not be able to see into
|
||||
* your stack and heap. Keep GCRef objects around for every
|
||||
* garbage-collected object that you want to keep alive.
|
||||
*/
|
||||
typedef struct GCRef GCRef; // void*
|
||||
|
||||
// Function propotypes
|
||||
/**
|
||||
* @brief Initializes the Nix expression evaluator.
|
||||
*
|
||||
* This function should be called before creating a State.
|
||||
* This function can be called multiple times.
|
||||
*
|
||||
* @param[out] context Optional, stores error information
|
||||
* @return NIX_OK if the initialization was successful, an error code otherwise.
|
||||
*/
|
||||
nix_err nix_libexpr_init(nix_c_context *context);
|
||||
|
||||
/**
|
||||
* @brief Parses a Nix expression from a string.
|
||||
*
|
||||
* The returned expression is owned by the garbage collector.
|
||||
* Pass a gcref to keep a reference.
|
||||
*
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] state Evaluator state.
|
||||
* @param[in] expr The Nix expression to parse.
|
||||
* @param[in] path The file path to associate with the expression.
|
||||
* @param[out] ref Optional, will store a reference to the returned value.
|
||||
* @return A parsed expression or NULL on failure.
|
||||
*/
|
||||
Expr *nix_parse_expr_from_string(nix_c_context *context, State *state,
|
||||
const char *expr, const char *path,
|
||||
GCRef *ref);
|
||||
|
||||
/**
|
||||
* @brief Evaluates a parsed Nix expression.
|
||||
*
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] state The state of the evaluation.
|
||||
* @param[in] expr The Nix expression to evaluate.
|
||||
* @param[in] value The result of the evaluation.
|
||||
* @return NIX_OK if the evaluation was successful, an error code otherwise.
|
||||
*/
|
||||
nix_err nix_expr_eval(nix_c_context *context, State *state, Expr *expr,
|
||||
Value *value);
|
||||
|
||||
/**
|
||||
* @brief Calls a Nix function with an argument.
|
||||
*
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] state The state of the evaluation.
|
||||
* @param[in] fn The Nix function to call.
|
||||
* @param[in] arg The argument to pass to the function.
|
||||
* @param[out] value The result of the function call.
|
||||
* @return NIX_OK if the function call was successful, an error code otherwise.
|
||||
*/
|
||||
nix_err nix_value_call(nix_c_context *context, State *state, Value *fn,
|
||||
Value *arg, Value *value);
|
||||
|
||||
/**
|
||||
* @brief Forces the evaluation of a Nix value.
|
||||
*
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] state The state of the evaluation.
|
||||
* @param[in,out] value The Nix value to force.
|
||||
* @return NIX_OK if the force operation was successful, an error code
|
||||
* otherwise.
|
||||
*/
|
||||
nix_err nix_value_force(nix_c_context *context, State *state, Value *value);
|
||||
|
||||
/**
|
||||
* @brief Forces the deep evaluation of a Nix value.
|
||||
*
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] state The state of the evaluation.
|
||||
* @param[in,out] value The Nix value to force.
|
||||
* @return NIX_OK if the deep force operation was successful, an error code
|
||||
* otherwise.
|
||||
*/
|
||||
nix_err nix_value_force_deep(nix_c_context *context, State *state,
|
||||
Value *value);
|
||||
|
||||
/**
|
||||
* @brief Creates a new Nix state.
|
||||
*
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] searchPath The NIX_PATH.
|
||||
* @param[in] store The Nix store to use.
|
||||
* @return A new Nix state or NULL on failure.
|
||||
*/
|
||||
State *nix_state_create(nix_c_context *context, const char **searchPath,
|
||||
Store *store);
|
||||
|
||||
/**
|
||||
* @brief Frees a Nix state.
|
||||
*
|
||||
* Does not fail.
|
||||
*
|
||||
* @param[in] state The state to free.
|
||||
*/
|
||||
void nix_state_free(State *state);
|
||||
|
||||
/**
|
||||
* @brief Creates a new garbage collector reference.
|
||||
*
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] obj The object to create a reference for.
|
||||
* @return A new garbage collector reference or NULL on failure.
|
||||
*/
|
||||
GCRef *nix_gc_ref(nix_c_context *context, void *obj);
|
||||
|
||||
/**
|
||||
* @brief Frees a garbage collector reference.
|
||||
*
|
||||
* Does not fail.
|
||||
*
|
||||
* @param[in] ref The reference to free.
|
||||
*/
|
||||
void nix_gc_free(GCRef *ref);
|
||||
|
||||
/**
|
||||
* @brief Register a callback that gets called when the object is garbage
|
||||
* collected.
|
||||
* @note objects can only have a single finalizer. This function overwrites
|
||||
* silently.
|
||||
* @param[in] obj the object to watch
|
||||
* @param[in] cd the data to pass to the finalizer
|
||||
* @param[in] finalizer the callback function, called with obj and cd
|
||||
*/
|
||||
void nix_gc_register_finalizer(void *obj, void *cd,
|
||||
void (*finalizer)(void *obj, void *cd));
|
||||
|
||||
// cffi end
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NIX_API_EXPR_H
|
17
src/libexpr/nix_api_expr_internal.h
Normal file
17
src/libexpr/nix_api_expr_internal.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef NIX_API_EXPR_INTERNAL_H
|
||||
#define NIX_API_EXPR_INTERNAL_H
|
||||
|
||||
// forward declaration
|
||||
namespace nix {
|
||||
class EvalState;
|
||||
};
|
||||
|
||||
struct State {
|
||||
nix::EvalState state;
|
||||
};
|
||||
|
||||
struct GCRef {
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
#endif // NIX_API_EXPR_INTERNAL_H
|
198
src/libexpr/nix_api_external.cc
Normal file
198
src/libexpr/nix_api_external.cc
Normal file
@ -0,0 +1,198 @@
|
||||
#include "attr-set.hh"
|
||||
#include "config.hh"
|
||||
#include "eval.hh"
|
||||
#include "gc/gc.h"
|
||||
#include "globals.hh"
|
||||
#include "value.hh"
|
||||
|
||||
#include "nix_api_expr.h"
|
||||
#include "nix_api_expr_internal.h"
|
||||
#include "nix_api_external.h"
|
||||
#include "nix_api_util.h"
|
||||
#include "nix_api_util_internal.h"
|
||||
#include "nix_api_value.h"
|
||||
#include "value/context.hh"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#ifdef HAVE_BOEHMGC
|
||||
#define GC_INCLUDE_NEW 1
|
||||
#include "gc_cpp.h"
|
||||
#endif
|
||||
|
||||
struct nix_returned_string {
|
||||
std::string str;
|
||||
};
|
||||
|
||||
struct nix_printer {
|
||||
std::ostream &s;
|
||||
};
|
||||
|
||||
struct nix_string_context {
|
||||
nix::NixStringContext &ctx;
|
||||
};
|
||||
|
||||
nix_returned_string *nix_external_alloc_string(const char *c) {
|
||||
return new nix_returned_string{c};
|
||||
}
|
||||
void nix_external_dealloc_string(nix_returned_string *str) { delete str; }
|
||||
|
||||
nix_err nix_external_print(nix_c_context *context, nix_printer *printer,
|
||||
const char *c) {
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
printer->s << c;
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
nix_err nix_external_add_string_context(nix_c_context *context,
|
||||
nix_string_context *ctx,
|
||||
const char *c) {
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
auto r = nix::NixStringContextElem::parse(c);
|
||||
ctx->ctx.insert(r);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
class NixCExternalValue : public nix::ExternalValueBase {
|
||||
NixCExternalValueDesc &desc;
|
||||
void *v;
|
||||
|
||||
public:
|
||||
NixCExternalValue(NixCExternalValueDesc &desc, void *v) : desc(desc), v(v){};
|
||||
void *get_ptr() { return v; }
|
||||
/**
|
||||
* Print out the value
|
||||
*/
|
||||
virtual std::ostream &print(std::ostream &str) const override {
|
||||
nix_printer p{str};
|
||||
desc.print(v, &p);
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a simple string describing the type
|
||||
*/
|
||||
virtual std::string showType() const override {
|
||||
std::unique_ptr<nix_returned_string> r(desc.showType(v));
|
||||
return std::move(r->str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string to be used in builtins.typeOf
|
||||
*/
|
||||
virtual std::string typeOf() const override {
|
||||
std::unique_ptr<nix_returned_string> r(desc.typeOf(v));
|
||||
return std::move(r->str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Coerce the value to a string.
|
||||
*/
|
||||
virtual std::string coerceToString(const nix::Pos &pos,
|
||||
nix::NixStringContext &context,
|
||||
bool copyMore,
|
||||
bool copyToStore) const override {
|
||||
if (!desc.coerceToString) {
|
||||
return nix::ExternalValueBase::coerceToString(pos, context, copyMore,
|
||||
copyToStore);
|
||||
}
|
||||
nix_string_context ctx{context};
|
||||
// todo: pos, errors
|
||||
std::unique_ptr<nix_returned_string> r(
|
||||
desc.coerceToString(v, &ctx, copyMore, copyToStore));
|
||||
if (!r) {
|
||||
return nix::ExternalValueBase::coerceToString(pos, context, copyMore,
|
||||
copyToStore);
|
||||
}
|
||||
return std::move(r->str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare to another value of the same type.
|
||||
*/
|
||||
virtual bool operator==(const ExternalValueBase &b) const override {
|
||||
if (!desc.equal) {
|
||||
return false;
|
||||
}
|
||||
auto r = dynamic_cast<const NixCExternalValue *>(&b);
|
||||
if (!r)
|
||||
return false;
|
||||
return desc.equal(v, r->v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the value as JSON.
|
||||
*/
|
||||
virtual nlohmann::json
|
||||
printValueAsJSON(nix::EvalState &state, bool strict,
|
||||
nix::NixStringContext &context,
|
||||
bool copyToStore = true) const override {
|
||||
if (!desc.printValueAsJSON) {
|
||||
return nix::ExternalValueBase::printValueAsJSON(state, strict, context,
|
||||
copyToStore);
|
||||
}
|
||||
nix_string_context ctx{context};
|
||||
std::unique_ptr<nix_returned_string> r(
|
||||
desc.printValueAsJSON((State *)&state, strict, &ctx, copyToStore));
|
||||
if (!r) {
|
||||
return nix::ExternalValueBase::printValueAsJSON(state, strict, context,
|
||||
copyToStore);
|
||||
}
|
||||
return nlohmann::json::parse(r->str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the value as XML.
|
||||
*/
|
||||
virtual void printValueAsXML(nix::EvalState &state, bool strict,
|
||||
bool location, nix::XMLWriter &doc,
|
||||
nix::NixStringContext &context,
|
||||
nix::PathSet &drvsSeen,
|
||||
const nix::PosIdx pos) const override {
|
||||
if (!desc.printValueAsXML) {
|
||||
return nix::ExternalValueBase::printValueAsXML(
|
||||
state, strict, location, doc, context, drvsSeen, pos);
|
||||
}
|
||||
nix_string_context ctx{context};
|
||||
desc.printValueAsXML((State *)&state, strict, location, &doc, &ctx,
|
||||
&drvsSeen, *reinterpret_cast<const uint32_t *>(&pos));
|
||||
}
|
||||
|
||||
virtual ~NixCExternalValue() override{};
|
||||
};
|
||||
|
||||
ExternalValue *nix_create_external_value(nix_c_context *context,
|
||||
NixCExternalValueDesc *desc, void *v,
|
||||
GCRef *gc) {
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
auto ret = new
|
||||
#ifdef HAVE_BOEHMGC
|
||||
(GC)
|
||||
#endif
|
||||
NixCExternalValue(*desc, v);
|
||||
if (gc)
|
||||
gc->ptr = ret;
|
||||
return (ExternalValue *)ret;
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
void *nix_get_external_value_content(nix_c_context *context, ExternalValue *b) {
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
auto r = dynamic_cast<NixCExternalValue *>((nix::ExternalValueBase *)b);
|
||||
if (r)
|
||||
return r->get_ptr();
|
||||
return nullptr;
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
195
src/libexpr/nix_api_external.h
Normal file
195
src/libexpr/nix_api_external.h
Normal file
@ -0,0 +1,195 @@
|
||||
#ifndef NIX_API_EXTERNAL_H
|
||||
#define NIX_API_EXTERNAL_H
|
||||
/** @file
|
||||
* @brief libexpr C bindings dealing with external values
|
||||
*/
|
||||
|
||||
#include "nix_api_expr.h"
|
||||
#include "nix_api_util.h"
|
||||
#include "nix_api_value.h"
|
||||
#include "stdbool.h"
|
||||
#include "stddef.h"
|
||||
#include "stdint.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// cffi start
|
||||
|
||||
/**
|
||||
* @brief Represents a string meant for consumption by nix.
|
||||
*/
|
||||
typedef struct nix_returned_string nix_returned_string;
|
||||
/**
|
||||
* @brief Wraps a stream that can output multiple string pieces.
|
||||
*/
|
||||
typedef struct nix_printer nix_printer;
|
||||
/**
|
||||
* @brief A list of string context items
|
||||
*/
|
||||
typedef struct nix_string_context nix_string_context;
|
||||
|
||||
/**
|
||||
* @brief Allocate a nix_returned_string from a const char*.
|
||||
*
|
||||
* Copies the passed string.
|
||||
* @param[in] c The string to copy
|
||||
* @returns A nix_returned_string*
|
||||
*/
|
||||
nix_returned_string *nix_external_alloc_string(const char *c);
|
||||
|
||||
/**
|
||||
* @brief Deallocate a nix_returned_string
|
||||
*
|
||||
* There's generally no need to call this, since
|
||||
* returning the string will pass ownership to nix,
|
||||
* but you can use it in case of errors.
|
||||
* @param[in] str The string to deallocate
|
||||
*/
|
||||
void nix_external_dealloc_string(nix_returned_string *str);
|
||||
|
||||
/**
|
||||
* Print to the nix_printer
|
||||
*
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param printer The nix_printer to print to
|
||||
* @param[in] str The string to print
|
||||
* @returns NIX_OK if everything worked
|
||||
*/
|
||||
nix_err nix_external_print(nix_c_context *context, nix_printer *printer,
|
||||
const char *str);
|
||||
|
||||
/**
|
||||
* Add string context to the nix_string_context object
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] string_context The nix_string_context to add to
|
||||
* @param[in] c The context string to add
|
||||
* @returns NIX_OK if everything worked
|
||||
*/
|
||||
nix_err nix_external_add_string_context(nix_c_context *context,
|
||||
nix_string_context *string_context,
|
||||
const char *c);
|
||||
|
||||
/**
|
||||
* @brief Definition for a class of external values
|
||||
*
|
||||
* Create and implement one of these, then pass it to nix_create_external_value
|
||||
* Make sure to keep it alive while the external value lives.
|
||||
*
|
||||
* Optional functions can be set to NULL
|
||||
*
|
||||
* @see nix_create_external_value
|
||||
*/
|
||||
typedef struct NixCExternalValueDesc {
|
||||
/**
|
||||
* @brief Called when printing the external value
|
||||
*
|
||||
* @param[in] self the void* passed to nix_create_external_value
|
||||
* @param[out] printer The printer to print to, pass to nix_external_print
|
||||
*/
|
||||
void (*print)(void *self, nix_printer *printer);
|
||||
/**
|
||||
* @brief Called on :t
|
||||
* @param[in] self the void* passed to nix_create_external_value
|
||||
* @returns a nix_returned_string, ownership passed to nix
|
||||
*/
|
||||
nix_returned_string *(*showType)(void *self); // std::string
|
||||
/**
|
||||
* @brief Called on `builtins.typeOf`
|
||||
* @param self the void* passed to nix_create_external_value
|
||||
* @returns a nix_returned_string, ownership passed to nix
|
||||
*/
|
||||
nix_returned_string *(*typeOf)(void *self); // std::string
|
||||
/**
|
||||
* @brief Called on "${str}" and builtins.toString.
|
||||
*
|
||||
* The latter with coerceMore=true
|
||||
* Optional, the default is to throw an error.
|
||||
* @param[in] self the void* passed to nix_create_external_value
|
||||
* @param[out] c writable string context for the resulting string
|
||||
* @param[in] coerceMore boolean, try to coerce to strings in more cases
|
||||
* instead of throwing an error
|
||||
* @param[in] copyToStore boolean, whether to copy referenced paths to store
|
||||
* or keep them as-is
|
||||
* @returns a nix_returned_string, ownership passed to nix. Optional,
|
||||
* returning NULL will make the conversion throw an error.
|
||||
*/
|
||||
nix_returned_string *(*coerceToString)(void *self, nix_string_context *c,
|
||||
int coerceMore, int copyToStore);
|
||||
/**
|
||||
* @brief Try to compare two external values
|
||||
*
|
||||
* Optional, the default is always false.
|
||||
* If the other object was not a Nix C external value, this comparison will
|
||||
* also return false
|
||||
* @param[in] self the void* passed to nix_create_external_value
|
||||
* @param[in] other the void* passed to the other object's
|
||||
* nix_create_external_value
|
||||
* @returns true if the objects are deemed to be equal
|
||||
*/
|
||||
int (*equal)(void *self, void *other);
|
||||
/**
|
||||
* @brief Convert the external value to json
|
||||
*
|
||||
* Optional, the default is to throw an error
|
||||
* @param[in] state The evaluator state
|
||||
* @param[in] strict boolean Whether to force the value before printing
|
||||
* @param[out] c writable string context for the resulting string
|
||||
* @param[in] copyToStore whether to copy referenced paths to store or keep
|
||||
* them as-is
|
||||
* @returns string that gets parsed as json. Optional, returning NULL will
|
||||
* make the conversion throw an error.
|
||||
*/
|
||||
nix_returned_string *(*printValueAsJSON)(State *, int strict,
|
||||
nix_string_context *c,
|
||||
bool copyToStore);
|
||||
/**
|
||||
* @brief Convert the external value to XML
|
||||
*
|
||||
* Optional, the default is to throw an error
|
||||
* @todo The mechanisms for this call are incomplete. There are no C
|
||||
* bindings to work with XML, pathsets and positions.
|
||||
* @param[in] state The evaluator state
|
||||
* @param[in] strict boolean Whether to force the value before printing
|
||||
* @param[in] location boolean Whether to include position information in the
|
||||
* xml
|
||||
* @param[out] doc XML document to output to
|
||||
* @param[out] c writable string context for the resulting string
|
||||
* @param[in,out] drvsSeen a path set to avoid duplicating derivations
|
||||
* @param[in] pos The position of the call.
|
||||
*/
|
||||
void (*printValueAsXML)(State *, int strict, int location, void *doc,
|
||||
nix_string_context *c, void *drvsSeen, int pos);
|
||||
} NixCExternalValueDesc;
|
||||
|
||||
/**
|
||||
* @brief Create an external value, that can be given to nix_set_external
|
||||
*
|
||||
* Pass a gcref to keep a reference.
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] desc a NixCExternalValueDesc, you should keep this alive as long
|
||||
* as the ExternalValue lives
|
||||
* @param[in] v the value to store
|
||||
* @param[out] ref Optional, will store a reference to the returned value.
|
||||
* @returns external value, owned by the garbage collector
|
||||
* @see nix_set_external
|
||||
*/
|
||||
ExternalValue *nix_create_external_value(nix_c_context *context,
|
||||
NixCExternalValueDesc *desc, void *v,
|
||||
GCRef *ref);
|
||||
|
||||
/**
|
||||
* @brief Extract the pointer from a nix c external value.
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] b The external value
|
||||
* @returns The pointer, or null if the external value was not from nix c.
|
||||
* @see nix_get_external
|
||||
*/
|
||||
void *nix_get_external_value_content(nix_c_context *context, ExternalValue *b);
|
||||
|
||||
// cffi end
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NIX_API_EXTERNAL_H
|
439
src/libexpr/nix_api_value.cc
Normal file
439
src/libexpr/nix_api_value.cc
Normal file
@ -0,0 +1,439 @@
|
||||
#include "attr-set.hh"
|
||||
#include "config.hh"
|
||||
#include "eval.hh"
|
||||
#include "gc/gc.h"
|
||||
#include "globals.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,
|
||||
GCRef *ref) {
|
||||
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 = {}, .doc = doc, .fun = fun2};
|
||||
if (args)
|
||||
for (size_t i = 0; args[i]; i++)
|
||||
p->args.emplace_back(*args);
|
||||
if (ref)
|
||||
ref->ptr = p;
|
||||
return (PrimOp *)p;
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
Value *nix_alloc_value(nix_c_context *context, State *state, GCRef *ref) {
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
Value *res = state->state.allocValue();
|
||||
if (ref)
|
||||
ref->ptr = 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_double(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,
|
||||
unsigned int ix, GCRef *ref) {
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
auto &v = check_value_not_null(value);
|
||||
assert(v.type() == nix::nList);
|
||||
return (Value *)v.listElems()[ix];
|
||||
}
|
||||
NIXC_CATCH_ERRS_NULL
|
||||
}
|
||||
|
||||
Value *nix_get_attr_byname(nix_c_context *context, const Value *value,
|
||||
State *state, const char *name, GCRef *ref) {
|
||||
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) {
|
||||
if (ref)
|
||||
ref->ptr = attr->value;
|
||||
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,
|
||||
GCRef *ref) {
|
||||
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();
|
||||
if (ref)
|
||||
ref->ptr = a.value;
|
||||
return a.value;
|
||||
}
|
||||
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_double(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_set_thunk(nix_c_context *context, State *s, Value *value,
|
||||
Expr *expr) {
|
||||
if (context)
|
||||
context->last_err_code = NIX_OK;
|
||||
try {
|
||||
auto &v = check_value_not_null(value);
|
||||
s->state.mkThunk_(v, (nix::Expr *)expr);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
typedef std::shared_ptr<nix::BindingsBuilder> BindingsBuilder_Inner;
|
||||
|
||||
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);
|
||||
nix::BindingsBuilder &builder = **(BindingsBuilder_Inner *)b;
|
||||
v.mkAttrs(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);
|
||||
auto res = new BindingsBuilder_Inner();
|
||||
*res = std::allocate_shared<nix::BindingsBuilder>(
|
||||
traceable_allocator<nix::BindingsBuilder>(), bb);
|
||||
return res;
|
||||
}
|
||||
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 {
|
||||
nix::BindingsBuilder &builder = **(BindingsBuilder_Inner *)b;
|
||||
auto &v = check_value_not_null(value);
|
||||
nix::Symbol s = builder.state.symbols.create(name);
|
||||
builder.insert(s, &v);
|
||||
}
|
||||
NIXC_CATCH_ERRS
|
||||
}
|
||||
|
||||
void nix_bindings_builder_unref(BindingsBuilder *bb) {
|
||||
delete (BindingsBuilder_Inner *)bb;
|
||||
}
|
355
src/libexpr/nix_api_value.h
Normal file
355
src/libexpr/nix_api_value.h
Normal file
@ -0,0 +1,355 @@
|
||||
#ifndef NIX_API_VALUE_H
|
||||
#define NIX_API_VALUE_H
|
||||
|
||||
/** @file
|
||||
* @brief libexpr C bindings dealing with values
|
||||
*/
|
||||
|
||||
#include "nix_api_util.h"
|
||||
#include "stdbool.h"
|
||||
#include "stddef.h"
|
||||
#include "stdint.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
// cffi start
|
||||
|
||||
// Type definitions
|
||||
typedef enum {
|
||||
NIX_TYPE_THUNK,
|
||||
NIX_TYPE_INT,
|
||||
NIX_TYPE_FLOAT,
|
||||
NIX_TYPE_BOOL,
|
||||
NIX_TYPE_STRING,
|
||||
NIX_TYPE_PATH,
|
||||
NIX_TYPE_NULL,
|
||||
NIX_TYPE_ATTRS,
|
||||
NIX_TYPE_LIST,
|
||||
NIX_TYPE_FUNCTION,
|
||||
NIX_TYPE_EXTERNAL
|
||||
} ValueType;
|
||||
|
||||
// forward declarations
|
||||
typedef void Value;
|
||||
typedef void Expr;
|
||||
typedef struct State State;
|
||||
typedef struct GCRef GCRef;
|
||||
// type defs
|
||||
/** @brief Stores an under-construction set of bindings
|
||||
* Reference-counted
|
||||
* @see nix_make_bindings_builder, nix_bindings_builder_unref, nix_make_attrs
|
||||
* @see nix_bindings_builder_insert
|
||||
*/
|
||||
typedef void BindingsBuilder;
|
||||
|
||||
/** @brief PrimOp function
|
||||
*
|
||||
* Owned by the GC
|
||||
* @see nix_alloc_primop, nix_set_primop
|
||||
*/
|
||||
typedef struct PrimOp PrimOp;
|
||||
/** @brief External Value
|
||||
*
|
||||
* Owned by the GC
|
||||
* @see nix_api_external.h
|
||||
*/
|
||||
typedef struct ExternalValue ExternalValue;
|
||||
|
||||
/** @brief Function pointer for primops
|
||||
* @param[in] state Evaluator state
|
||||
* @param[in] pos position of function call
|
||||
* @param[in] args list of arguments
|
||||
* @param[out] v return value
|
||||
* @see nix_alloc_primop, nix_set_primop
|
||||
*/
|
||||
typedef void (*PrimOpFun)(State *state, int pos, Value **args, Value *v);
|
||||
|
||||
/** @brief Allocate a primop
|
||||
*
|
||||
* Owned by the GC
|
||||
* Pass a gcref to keep a reference.
|
||||
*
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] fun callback
|
||||
* @param[in] arity expected amount of function arguments
|
||||
* @param[in] name function name
|
||||
* @param[in] args array of argument names
|
||||
* @param[in] doc optional, documentation for this primop
|
||||
* @param[out] ref Optional, will store a reference to the returned value.
|
||||
* @return primop, or null in case of errors
|
||||
* @see nix_set_primop
|
||||
*/
|
||||
PrimOp *nix_alloc_primop(nix_c_context *context, PrimOpFun fun, int arity,
|
||||
const char *name, const char **args, const char *doc,
|
||||
GCRef *ref);
|
||||
|
||||
// Function prototypes
|
||||
|
||||
/** @brief Allocate a Nix value
|
||||
*
|
||||
* Owned by the GC
|
||||
* Pass a gcref to keep a reference.
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] state nix evaluator state
|
||||
* @param[out] ref Optional, will store a reference to the returned value.
|
||||
* @return value, or null in case of errors
|
||||
*
|
||||
*/
|
||||
Value *nix_alloc_value(nix_c_context *context, State *state, GCRef *ref);
|
||||
/** @name Getters
|
||||
*/
|
||||
/**@{*/
|
||||
/** @brief Get value type
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return type of nix value
|
||||
*/
|
||||
ValueType nix_get_type(nix_c_context *context, const Value *value);
|
||||
/** @brief Get type name of value
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return type name, owned string
|
||||
* @todo way to free the result
|
||||
*/
|
||||
const char *nix_get_typename(nix_c_context *context, const Value *value);
|
||||
|
||||
/** @brief Get boolean value
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return true or false, error info via context
|
||||
*/
|
||||
bool nix_get_bool(nix_c_context *context, const Value *value);
|
||||
/** @brief Get string
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return string
|
||||
* @return NULL in case of error.
|
||||
*/
|
||||
const char *nix_get_string(nix_c_context *context, const Value *value);
|
||||
/** @brief Get path as string
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return string
|
||||
* @return NULL in case of error.
|
||||
*/
|
||||
const char *nix_get_path_string(nix_c_context *context, const Value *value);
|
||||
/** @brief Get the length of a list
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return length of list, error info via context
|
||||
*/
|
||||
unsigned int nix_get_list_size(nix_c_context *context, const Value *value);
|
||||
/** @brief Get the element count of an attrset
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return attrset element count, error info via context
|
||||
*/
|
||||
unsigned int nix_get_attrs_size(nix_c_context *context, const Value *value);
|
||||
/** @brief Get float value in 64 bits
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return float contents, error info via context
|
||||
*/
|
||||
double nix_get_double(nix_c_context *context, const Value *value);
|
||||
/** @brief Get int value
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return int contents, error info via context
|
||||
*/
|
||||
int64_t nix_get_int(nix_c_context *context, const Value *value);
|
||||
/** @brief Get external reference
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @return reference to external, NULL in case of error
|
||||
*/
|
||||
ExternalValue *nix_get_external(nix_c_context *context, Value *);
|
||||
|
||||
/** @brief Get the ix'th element of a list
|
||||
*
|
||||
* Pass a gcref to keep a reference.
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @param[in] ix list element to get
|
||||
* @param[out] ref Optional, will store a reference to the returned value.
|
||||
* @return value, NULL in case of errors
|
||||
*/
|
||||
Value *nix_get_list_byidx(nix_c_context *context, const Value *value,
|
||||
unsigned int ix, GCRef *ref);
|
||||
/** @brief Get an attr by name
|
||||
*
|
||||
* Pass a gcref to keep a reference.
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @param[in] state nix evaluator state
|
||||
* @param[in] name attribute name
|
||||
* @param[out] ref Optional, will store a reference to the returned value.
|
||||
* @return value, NULL in case of errors
|
||||
*/
|
||||
Value *nix_get_attr_byname(nix_c_context *context, const Value *value,
|
||||
State *state, const char *name, GCRef *ref);
|
||||
|
||||
/** @brief Check if an attribute name exists on a value
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @param[in] state nix evaluator state
|
||||
* @param[in] name attribute name
|
||||
* @return value, NULL in case of errors
|
||||
*/
|
||||
bool nix_has_attr_byname(nix_c_context *context, const Value *value,
|
||||
State *state, const char *name);
|
||||
|
||||
/** @brief Get an attribute by index in the sorted bindings
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] value Nix value to inspect
|
||||
* @param[in] state nix evaluator state
|
||||
* @param[in] i attribute index
|
||||
* @param[out] name will store a pointer to the attribute name
|
||||
* @return value, NULL in case of errors
|
||||
*/
|
||||
Value *nix_get_attr_byidx(nix_c_context *context, const Value *value,
|
||||
State *state, unsigned int i, const char **name,
|
||||
GCRef *ref);
|
||||
/**@}*/
|
||||
/** @name Setters
|
||||
*/
|
||||
/**@{*/
|
||||
/** @brief Set boolean value
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] value Nix value to modify
|
||||
* @param[in] b the boolean value
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_set_bool(nix_c_context *context, Value *value, bool b);
|
||||
/** @brief Set a string
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] value Nix value to modify
|
||||
* @param[in] str the string, copied
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_set_string(nix_c_context *context, Value *value, const char *str);
|
||||
/** @brief Set a path
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] value Nix value to modify
|
||||
* @param[in] str the path string, copied
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_set_path_string(nix_c_context *context, Value *value,
|
||||
const char *str);
|
||||
/** @brief Set a double
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] value Nix value to modify
|
||||
* @param[in] d the double
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_set_double(nix_c_context *context, Value *value, double d);
|
||||
/** @brief Set an int
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] value Nix value to modify
|
||||
* @param[in] i the int
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_set_int(nix_c_context *context, Value *value, int64_t i);
|
||||
/** @brief Set null
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] value Nix value to modify
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_set_null(nix_c_context *context, Value *value);
|
||||
/** @brief Set an external value
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] value Nix value to modify
|
||||
* @param[in] val the external value to set. Will be GC-referenced by the value.
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_set_external(nix_c_context *context, Value *value,
|
||||
ExternalValue *val);
|
||||
/** @brief Allocate a list
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] value Nix value to modify
|
||||
* @param[in] size size of list
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_make_list(nix_c_context *context, State *s, Value *value,
|
||||
unsigned int size);
|
||||
/** @brief Manipulate a list by index
|
||||
*
|
||||
* Don't do this mid-computation.
|
||||
* @pre your list should be at least 'ix+1' items long
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] value Nix value to modify
|
||||
* @param[in] ix index to manipulate
|
||||
* @param[in] elem the value to set, will be gc-referenced by the value
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_set_list_byidx(nix_c_context *context, Value *value,
|
||||
unsigned int ix, Value *elem);
|
||||
/** @brief Create an attribute set from a bindings builder
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] value Nix value to modify
|
||||
* @param[in] b bindings builder to use. Make sure to unref this afterwards.
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_make_attrs(nix_c_context *context, Value *value,
|
||||
BindingsBuilder *b);
|
||||
/** @brief Set primop
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] value Nix value to modify
|
||||
* @param[in] op primop, will be gc-referenced by the value
|
||||
* @see nix_alloc_primop
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_set_primop(nix_c_context *context, Value *value, PrimOp *op);
|
||||
/** @brief Copy from another value
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] value Nix value to modify
|
||||
* @param[in] source value to copy from
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_copy_value(nix_c_context *context, Value *value, Value *source);
|
||||
/** @brief Make a thunk from an expr.
|
||||
*
|
||||
* Expr will be evaluated when the value is forced
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[out] value Nix value to modify
|
||||
* @param[in] expr the expr to thunk
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_set_thunk(nix_c_context *context, State *s, Value *value,
|
||||
Expr *expr);
|
||||
/**@}*/
|
||||
|
||||
/** @brief Create a bindings builder
|
||||
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] state nix evaluator state
|
||||
* @param[in] capacity how many bindings you'll add. Don't exceed.
|
||||
* @return owned reference to a bindings builder. Make sure to unref when you're
|
||||
done.
|
||||
*/
|
||||
BindingsBuilder *nix_make_bindings_builder(nix_c_context *context, State *state,
|
||||
size_t capacity);
|
||||
/** @brief Insert bindings into a builder
|
||||
* @param[out] context Optional, stores error information
|
||||
* @param[in] builder BindingsBuilder to insert into
|
||||
* @param[in] name attribute name, copied into the symbol store
|
||||
* @param[in] value value to give the binding
|
||||
* @return error code, NIX_OK on success.
|
||||
*/
|
||||
nix_err nix_bindings_builder_insert(nix_c_context *context,
|
||||
BindingsBuilder *builder, const char *name,
|
||||
Value *value);
|
||||
/** @brief Unref a bindings builder
|
||||
*
|
||||
* Does not fail.
|
||||
* It'll be deallocated when all references are gone.
|
||||
* @param[in] builder the builder to unref
|
||||
*/
|
||||
void nix_bindings_builder_unref(BindingsBuilder *builder);
|
||||
|
||||
// cffi end
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // NIX_API_VALUE_H
|
@ -44,7 +44,7 @@ SearchPath::Elem SearchPath::Elem::parse(std::string_view rawElem)
|
||||
}
|
||||
|
||||
|
||||
SearchPath parseSearchPath(const Strings & rawElems)
|
||||
SearchPath SearchPath::parse(const Strings & rawElems)
|
||||
{
|
||||
SearchPath res;
|
||||
for (auto & rawElem : rawElems)
|
||||
|
@ -328,6 +328,7 @@ public:
|
||||
}
|
||||
|
||||
void mkPath(const SourcePath & path);
|
||||
void mkPath(std::string_view path);
|
||||
|
||||
inline void mkPath(InputAccessor * accessor, const char * path)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user