mirror of
https://github.com/NixOS/nix
synced 2025-06-28 05:21:16 +02:00
Merge remote-tracking branch 'origin/master' into flip-coroutines
This commit is contained in:
commit
257470b58d
342 changed files with 6839 additions and 2721 deletions
|
@ -134,7 +134,7 @@ std::pair<SourcePath, uint32_t> findPackageFilename(EvalState & state, Value & v
|
|||
return {SourcePath{path.accessor, CanonPath(fn.substr(0, colon))}, lineno};
|
||||
} catch (std::invalid_argument & e) {
|
||||
fail();
|
||||
abort();
|
||||
unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include "eval.hh"
|
||||
#include "eval-inline.hh"
|
||||
#include "store-api.hh"
|
||||
// Need specialization involving `SymbolStr` just in this one module.
|
||||
#include "strings-inline.hh"
|
||||
|
||||
namespace nix::eval_cache {
|
||||
|
||||
|
@ -326,7 +328,7 @@ struct AttrDb
|
|||
case AttrType::Bool:
|
||||
return {{rowId, queryAttribute.getInt(2) != 0}};
|
||||
case AttrType::Int:
|
||||
return {{rowId, int_t{queryAttribute.getInt(2)}}};
|
||||
return {{rowId, int_t{NixInt{queryAttribute.getInt(2)}}}};
|
||||
case AttrType::ListOfStrings:
|
||||
return {{rowId, tokenizeString<std::vector<std::string>>(queryAttribute.getStr(2), "\t")}};
|
||||
case AttrType::Missing:
|
||||
|
@ -469,7 +471,7 @@ Value & AttrCursor::forceValue()
|
|||
else if (v.type() == nBool)
|
||||
cachedValue = {root->db->setBool(getKey(), v.boolean()), v.boolean()};
|
||||
else if (v.type() == nInt)
|
||||
cachedValue = {root->db->setInt(getKey(), v.integer()), int_t{v.integer()}};
|
||||
cachedValue = {root->db->setInt(getKey(), v.integer().value), int_t{v.integer()}};
|
||||
else if (v.type() == nAttrs)
|
||||
; // FIXME: do something?
|
||||
else
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "error.hh"
|
||||
#include "environment-variables.hh"
|
||||
#include "eval-settings.hh"
|
||||
#include "config-global.hh"
|
||||
#include "serialise.hh"
|
||||
#include "eval-gc.hh"
|
||||
|
||||
|
@ -98,6 +100,12 @@ void initGC()
|
|||
gcCyclesAfterInit = GC_get_gc_no();
|
||||
#endif
|
||||
|
||||
// NIX_PATH must override the regular setting
|
||||
// See the comment in applyConfig
|
||||
if (auto nixPathEnv = getEnv("NIX_PATH")) {
|
||||
globalConfig.set("nix-path", concatStringsSep(" ", EvalSettings::parseNixPath(nixPathEnv.value())));
|
||||
}
|
||||
|
||||
gcInitialised = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace nix {
|
|||
|
||||
/* Very hacky way to parse $NIX_PATH, which is colon-separated, but
|
||||
can contain URLs (e.g. "nixpkgs=https://bla...:foo=https://"). */
|
||||
static Strings parseNixPath(const std::string & s)
|
||||
Strings EvalSettings::parseNixPath(const std::string & s)
|
||||
{
|
||||
Strings res;
|
||||
|
||||
|
@ -48,10 +48,7 @@ EvalSettings::EvalSettings(bool & readOnlyMode, EvalSettings::LookupPathHooks lo
|
|||
: readOnlyMode{readOnlyMode}
|
||||
, lookupPathHooks{lookupPathHooks}
|
||||
{
|
||||
auto var = getEnv("NIX_PATH");
|
||||
if (var) nixPath = parseNixPath(*var);
|
||||
|
||||
var = getEnv("NIX_ABORT_ON_WARN");
|
||||
auto var = getEnv("NIX_ABORT_ON_WARN");
|
||||
if (var && (var == "1" || var == "yes" || var == "true"))
|
||||
builtinsAbortOnWarn = true;
|
||||
}
|
||||
|
|
|
@ -47,6 +47,8 @@ struct EvalSettings : Config
|
|||
|
||||
static bool isPseudoUrl(std::string_view s);
|
||||
|
||||
static Strings parseNixPath(const std::string & s);
|
||||
|
||||
static std::string resolvePseudoUrl(std::string_view url);
|
||||
|
||||
LookupPathHooks lookupPathHooks;
|
||||
|
@ -63,7 +65,7 @@ struct EvalSettings : Config
|
|||
extern "C" typedef void (*ValueInitialiser) (EvalState & state, Value & v);
|
||||
```
|
||||
|
||||
The [Nix C++ API documentation](@docroot@/contributing/documentation.md#api-documentation) has more details on evaluator internals.
|
||||
The [Nix C++ API documentation](@docroot@/development/documentation.md#api-documentation) has more details on evaluator internals.
|
||||
|
||||
- `builtins.exec` *arguments*
|
||||
|
||||
|
@ -71,25 +73,30 @@ struct EvalSettings : Config
|
|||
)"};
|
||||
|
||||
Setting<Strings> nixPath{
|
||||
this, getDefaultNixPath(), "nix-path",
|
||||
this, {}, "nix-path",
|
||||
R"(
|
||||
List of search paths to use for [lookup path](@docroot@/language/constructs/lookup-path.md) resolution.
|
||||
This setting determines the value of
|
||||
[`builtins.nixPath`](@docroot@/language/builtins.md#builtins-nixPath) and can be used with [`builtins.findFile`](@docroot@/language/builtins.md#builtins-findFile).
|
||||
|
||||
The default value is
|
||||
- The configuration setting is overridden by the [`NIX_PATH`](@docroot@/command-ref/env-common.md#env-NIX_PATH)
|
||||
environment variable.
|
||||
- `NIX_PATH` is overridden by [specifying the setting as the command line flag](@docroot@/command-ref/conf-file.md#command-line-flags) `--nix-path`.
|
||||
- Any current value is extended by the [`-I` option](@docroot@/command-ref/opt-common.md#opt-I) or `--extra-nix-path`.
|
||||
|
||||
```
|
||||
$HOME/.nix-defexpr/channels
|
||||
nixpkgs=$NIX_STATE_DIR/profiles/per-user/root/channels/nixpkgs
|
||||
$NIX_STATE_DIR/profiles/per-user/root/channels
|
||||
```
|
||||
If the respective paths are accessible, the default values are:
|
||||
|
||||
It can be overridden with the [`NIX_PATH` environment variable](@docroot@/command-ref/env-common.md#env-NIX_PATH) or the [`-I` command line option](@docroot@/command-ref/opt-common.md#opt-I).
|
||||
- `$HOME/.nix-defexpr/channels`
|
||||
- `nixpkgs=$NIX_STATE_DIR/profiles/per-user/root/channels/nixpkgs`
|
||||
- `$NIX_STATE_DIR/profiles/per-user/root/channels`
|
||||
|
||||
See [`NIX_STATE_DIR`](@docroot@/command-ref/env-common.md#env-NIX_STATE_DIR) for details.
|
||||
|
||||
> **Note**
|
||||
>
|
||||
> If [pure evaluation](#conf-pure-eval) is enabled, `nixPath` evaluates to the empty list `[ ]`.
|
||||
> If [restricted evaluation](@docroot@/command-ref/conf-file.md#conf-restrict-eval) is enabled, the default value is empty.
|
||||
>
|
||||
> If [pure evaluation](#conf-pure-eval) is enabled, `builtins.nixPath` *always* evaluates to the empty list `[ ]`.
|
||||
)", {}, false};
|
||||
|
||||
Setting<std::string> currentSystem{
|
||||
|
@ -178,7 +185,11 @@ struct EvalSettings : Config
|
|||
)"};
|
||||
|
||||
Setting<bool> useEvalCache{this, true, "eval-cache",
|
||||
"Whether to use the flake evaluation cache."};
|
||||
R"(
|
||||
Whether to use the flake evaluation cache.
|
||||
Certain commands won't have to evaluate when invoked for the second time with a particular version of a flake.
|
||||
Intermediate results are not cached.
|
||||
)"};
|
||||
|
||||
Setting<bool> ignoreExceptionsDuringTry{this, false, "ignore-try",
|
||||
R"(
|
||||
|
|
|
@ -149,7 +149,7 @@ std::string_view showType(ValueType type, bool withArticle)
|
|||
case nFloat: return WA("a", "float");
|
||||
case nThunk: return WA("a", "thunk");
|
||||
}
|
||||
abort();
|
||||
unreachable();
|
||||
}
|
||||
|
||||
|
||||
|
@ -215,7 +215,7 @@ static Symbol getName(const AttrName & name, EvalState & state, Env & env)
|
|||
static constexpr size_t BASE_ENV_SIZE = 128;
|
||||
|
||||
EvalState::EvalState(
|
||||
const LookupPath & _lookupPath,
|
||||
const LookupPath & lookupPathFromArguments,
|
||||
ref<Store> store,
|
||||
const fetchers::Settings & fetchSettings,
|
||||
const EvalSettings & settings,
|
||||
|
@ -331,12 +331,21 @@ EvalState::EvalState(
|
|||
vStringSymlink.mkString("symlink");
|
||||
vStringUnknown.mkString("unknown");
|
||||
|
||||
/* Initialise the Nix expression search path. */
|
||||
/* Construct the Nix expression search path. */
|
||||
assert(lookupPath.elements.empty());
|
||||
if (!settings.pureEval) {
|
||||
for (auto & i : _lookupPath.elements)
|
||||
for (auto & i : lookupPathFromArguments.elements) {
|
||||
lookupPath.elements.emplace_back(LookupPath::Elem {i});
|
||||
for (auto & i : settings.nixPath.get())
|
||||
}
|
||||
/* $NIX_PATH overriding regular settings is implemented as a hack in `initGC()` */
|
||||
for (auto & i : settings.nixPath.get()) {
|
||||
lookupPath.elements.emplace_back(LookupPath::Elem::parse(i));
|
||||
}
|
||||
if (!settings.restrictEval) {
|
||||
for (auto & i : EvalSettings::getDefaultNixPath()) {
|
||||
lookupPath.elements.emplace_back(LookupPath::Elem::parse(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Allow access to all paths in the search path. */
|
||||
|
@ -771,7 +780,7 @@ void EvalState::runDebugRepl(const Error * error, const Env & env, const Expr &
|
|||
case ReplExitStatus::Continue:
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
unreachable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1140,7 +1149,7 @@ inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v, const PosIdx po
|
|||
|
||||
void Expr::eval(EvalState & state, Env & env, Value & v)
|
||||
{
|
||||
abort();
|
||||
unreachable();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1573,7 +1582,7 @@ void EvalState::callFunction(Value & fun, size_t nrArgs, Value * * args, Value &
|
|||
.withFrame(*fun.payload.lambda.env, lambda)
|
||||
.debugThrow();
|
||||
}
|
||||
abort(); // can't happen
|
||||
unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1970,7 +1979,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
|||
NixStringContext context;
|
||||
std::vector<BackedStringView> s;
|
||||
size_t sSize = 0;
|
||||
NixInt n = 0;
|
||||
NixInt n{0};
|
||||
NixFloat nf = 0;
|
||||
|
||||
bool first = !forceString;
|
||||
|
@ -2014,17 +2023,22 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
|
|||
|
||||
if (firstType == nInt) {
|
||||
if (vTmp.type() == nInt) {
|
||||
n += vTmp.integer();
|
||||
auto newN = n + vTmp.integer();
|
||||
if (auto checked = newN.valueChecked(); checked.has_value()) {
|
||||
n = NixInt(*checked);
|
||||
} else {
|
||||
state.error<EvalError>("integer overflow in adding %1% + %2%", n, vTmp.integer()).atPos(i_pos).debugThrow();
|
||||
}
|
||||
} else if (vTmp.type() == nFloat) {
|
||||
// Upgrade the type from int to float;
|
||||
firstType = nFloat;
|
||||
nf = n;
|
||||
nf = n.value;
|
||||
nf += vTmp.fpoint();
|
||||
} else
|
||||
state.error<EvalError>("cannot add %1% to an integer", showType(vTmp)).atPos(i_pos).withFrame(env, *this).debugThrow();
|
||||
} else if (firstType == nFloat) {
|
||||
if (vTmp.type() == nInt) {
|
||||
nf += vTmp.integer();
|
||||
nf += vTmp.integer().value;
|
||||
} else if (vTmp.type() == nFloat) {
|
||||
nf += vTmp.fpoint();
|
||||
} else
|
||||
|
@ -2149,7 +2163,7 @@ NixFloat EvalState::forceFloat(Value & v, const PosIdx pos, std::string_view err
|
|||
try {
|
||||
forceValue(v, pos);
|
||||
if (v.type() == nInt)
|
||||
return v.integer();
|
||||
return v.integer().value;
|
||||
else if (v.type() != nFloat)
|
||||
error<TypeError>(
|
||||
"expected a float but found %1%: %2%",
|
||||
|
@ -2336,7 +2350,7 @@ BackedStringView EvalState::coerceToString(
|
|||
shell scripting convenience, just like `null'. */
|
||||
if (v.type() == nBool && v.boolean()) return "1";
|
||||
if (v.type() == nBool && !v.boolean()) return "";
|
||||
if (v.type() == nInt) return std::to_string(v.integer());
|
||||
if (v.type() == nInt) return std::to_string(v.integer().value);
|
||||
if (v.type() == nFloat) return std::to_string(v.fpoint());
|
||||
if (v.type() == nNull) return "";
|
||||
|
||||
|
@ -2719,9 +2733,9 @@ bool EvalState::eqValues(Value & v1, Value & v2, const PosIdx pos, std::string_v
|
|||
|
||||
// Special case type-compatibility between float and int
|
||||
if (v1.type() == nInt && v2.type() == nFloat)
|
||||
return v1.integer() == v2.fpoint();
|
||||
return v1.integer().value == v2.fpoint();
|
||||
if (v1.type() == nFloat && v2.type() == nInt)
|
||||
return v1.fpoint() == v2.integer();
|
||||
return v1.fpoint() == v2.integer().value;
|
||||
|
||||
// All other types are not compatible with each other.
|
||||
if (v1.type() != v2.type()) return false;
|
||||
|
@ -2851,8 +2865,10 @@ void EvalState::printStatistics()
|
|||
topObj["cpuTime"] = cpuTime;
|
||||
#endif
|
||||
topObj["time"] = {
|
||||
#ifndef _WIN32 // TODO implement
|
||||
{"cpu", cpuTime},
|
||||
#ifdef HAVE_BOEHMGC
|
||||
#endif
|
||||
#if HAVE_BOEHMGC
|
||||
{GC_is_incremental_mode() ? "gcNonIncremental" : "gc", gcFullOnlyTime},
|
||||
{GC_is_incremental_mode() ? "gcNonIncrementalFraction" : "gcFraction", gcFullOnlyTime / cpuTime},
|
||||
#endif
|
||||
|
@ -3072,7 +3088,9 @@ std::optional<std::string> EvalState::resolveLookupPathPath(const LookupPath::Pa
|
|||
if (EvalSettings::isPseudoUrl(value)) {
|
||||
try {
|
||||
auto accessor = fetchers::downloadTarball(
|
||||
EvalSettings::resolvePseudoUrl(value)).accessor;
|
||||
store,
|
||||
fetchSettings,
|
||||
EvalSettings::resolvePseudoUrl(value));
|
||||
auto storePath = fetchToStore(*store, SourcePath(accessor), FetchMode::Copy);
|
||||
return finish(store->toRealPath(storePath));
|
||||
} catch (Error & e) {
|
||||
|
|
|
@ -246,8 +246,8 @@ NixInt PackageInfo::queryMetaInt(const std::string & name, NixInt def)
|
|||
if (v->type() == nString) {
|
||||
/* Backwards compatibility with before we had support for
|
||||
integer meta fields. */
|
||||
if (auto n = string2Int<NixInt>(v->c_str()))
|
||||
return *n;
|
||||
if (auto n = string2Int<NixInt::Inner>(v->c_str()))
|
||||
return NixInt{*n};
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "value.hh"
|
||||
#include "eval.hh"
|
||||
|
||||
#include <limits>
|
||||
#include <variant>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
|
@ -42,7 +43,7 @@ class JSONSax : nlohmann::json_sax<json> {
|
|||
auto attrs2 = state.buildBindings(attrs.size());
|
||||
for (auto & i : attrs)
|
||||
attrs2.insert(i.first, i.second);
|
||||
parent->value(state).mkAttrs(attrs2.alreadySorted());
|
||||
parent->value(state).mkAttrs(attrs2);
|
||||
return std::move(parent);
|
||||
}
|
||||
void add() override { v = nullptr; }
|
||||
|
@ -80,42 +81,46 @@ class JSONSax : nlohmann::json_sax<json> {
|
|||
public:
|
||||
JSONSax(EvalState & state, Value & v) : state(state), rs(new JSONState(&v)) {};
|
||||
|
||||
bool null()
|
||||
bool null() override
|
||||
{
|
||||
rs->value(state).mkNull();
|
||||
rs->add();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool boolean(bool val)
|
||||
bool boolean(bool val) override
|
||||
{
|
||||
rs->value(state).mkBool(val);
|
||||
rs->add();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_integer(number_integer_t val)
|
||||
bool number_integer(number_integer_t val) override
|
||||
{
|
||||
rs->value(state).mkInt(val);
|
||||
rs->add();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_unsigned(number_unsigned_t val)
|
||||
bool number_unsigned(number_unsigned_t val_) override
|
||||
{
|
||||
if (val_ > std::numeric_limits<NixInt::Inner>::max()) {
|
||||
throw Error("unsigned json number %1% outside of Nix integer range", val_);
|
||||
}
|
||||
NixInt::Inner val = val_;
|
||||
rs->value(state).mkInt(val);
|
||||
rs->add();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool number_float(number_float_t val, const string_t & s)
|
||||
bool number_float(number_float_t val, const string_t & s) override
|
||||
{
|
||||
rs->value(state).mkFloat(val);
|
||||
rs->add();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool string(string_t & val)
|
||||
bool string(string_t & val) override
|
||||
{
|
||||
rs->value(state).mkString(val);
|
||||
rs->add();
|
||||
|
@ -123,7 +128,7 @@ public:
|
|||
}
|
||||
|
||||
#if NLOHMANN_JSON_VERSION_MAJOR >= 3 && NLOHMANN_JSON_VERSION_MINOR >= 8
|
||||
bool binary(binary_t&)
|
||||
bool binary(binary_t&) override
|
||||
{
|
||||
// This function ought to be unreachable
|
||||
assert(false);
|
||||
|
@ -131,35 +136,35 @@ public:
|
|||
}
|
||||
#endif
|
||||
|
||||
bool start_object(std::size_t len)
|
||||
bool start_object(std::size_t len) override
|
||||
{
|
||||
rs = std::make_unique<JSONObjectState>(std::move(rs));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool key(string_t & name)
|
||||
bool key(string_t & name) override
|
||||
{
|
||||
dynamic_cast<JSONObjectState*>(rs.get())->key(name, state);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool end_object() {
|
||||
bool end_object() override {
|
||||
rs = rs->resolve(state);
|
||||
rs->add();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool end_array() {
|
||||
bool end_array() override {
|
||||
return end_object();
|
||||
}
|
||||
|
||||
bool start_array(size_t len) {
|
||||
bool start_array(size_t len) override {
|
||||
rs = std::make_unique<JSONListState>(std::move(rs),
|
||||
len != std::numeric_limits<size_t>::max() ? len : 128);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool parse_error(std::size_t, const std::string&, const nlohmann::detail::exception& ex) {
|
||||
bool parse_error(std::size_t, const std::string&, const nlohmann::detail::exception& ex) override {
|
||||
throw JSONParseError("%s", ex.what());
|
||||
}
|
||||
};
|
||||
|
|
|
@ -67,6 +67,14 @@ static StringToken unescapeStr(SymbolTable & symbols, char * s, size_t length)
|
|||
return {result, size_t(t - result)};
|
||||
}
|
||||
|
||||
static void requireExperimentalFeature(const ExperimentalFeature & feature, const Pos & pos)
|
||||
{
|
||||
if (!experimentalFeatureSettings.isEnabled(feature))
|
||||
throw ParseError(ErrorInfo{
|
||||
.msg = HintFmt("experimental Nix feature '%1%' is disabled; add '--extra-experimental-features %1%' to enable it", showExperimentalFeature(feature)),
|
||||
.pos = pos,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -119,12 +127,18 @@ or { return OR_KW; }
|
|||
\-\> { return IMPL; }
|
||||
\/\/ { return UPDATE; }
|
||||
\+\+ { return CONCAT; }
|
||||
\<\| { requireExperimentalFeature(Xp::PipeOperators, state->positions[CUR_POS]);
|
||||
return PIPE_FROM;
|
||||
}
|
||||
\|\> { requireExperimentalFeature(Xp::PipeOperators, state->positions[CUR_POS]);
|
||||
return PIPE_INTO;
|
||||
}
|
||||
|
||||
{ID} { yylval->id = {yytext, (size_t) yyleng}; return ID; }
|
||||
{INT} { errno = 0;
|
||||
std::optional<int64_t> numMay = string2Int<int64_t>(yytext);
|
||||
if (numMay.has_value()) {
|
||||
yylval->n = *numMay;
|
||||
yylval->n = NixInt{*numMay};
|
||||
} else {
|
||||
throw ParseError(ErrorInfo{
|
||||
.msg = HintFmt("invalid integer '%1%'", yytext),
|
||||
|
|
|
@ -32,6 +32,7 @@ subdir('build-utils-meson/threads')
|
|||
boost = dependency(
|
||||
'boost',
|
||||
modules : ['container', 'context'],
|
||||
include_type: 'system',
|
||||
)
|
||||
# boost is a public dependency, but not a pkg-config dependency unfortunately, so we
|
||||
# put in `deps_other`.
|
||||
|
@ -55,7 +56,12 @@ if bdw_gc.found()
|
|||
endif
|
||||
configdata.set('HAVE_BOEHMGC', bdw_gc.found().to_int())
|
||||
|
||||
toml11 = dependency('toml11', version : '>=3.7.0', method : 'cmake')
|
||||
toml11 = dependency(
|
||||
'toml11',
|
||||
version : '>=3.7.0',
|
||||
method : 'cmake',
|
||||
include_type: 'system',
|
||||
)
|
||||
deps_other += toml11
|
||||
|
||||
config_h = configure_file(
|
||||
|
|
|
@ -25,7 +25,7 @@ std::ostream & operator <<(std::ostream & str, const SymbolStr & symbol)
|
|||
|
||||
void Expr::show(const SymbolTable & symbols, std::ostream & str) const
|
||||
{
|
||||
abort();
|
||||
unreachable();
|
||||
}
|
||||
|
||||
void ExprInt::show(const SymbolTable & symbols, std::ostream & str) const
|
||||
|
@ -271,7 +271,7 @@ std::string showAttrPath(const SymbolTable & symbols, const AttrPath & attrPath)
|
|||
|
||||
void Expr::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
|
||||
{
|
||||
abort();
|
||||
unreachable();
|
||||
}
|
||||
|
||||
void ExprInt::bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env)
|
||||
|
|
|
@ -107,6 +107,7 @@ struct ExprInt : Expr
|
|||
{
|
||||
Value v;
|
||||
ExprInt(NixInt n) { v.mkInt(n); };
|
||||
ExprInt(NixInt::Inner n) { v.mkInt(n); };
|
||||
Value * maybeThunk(EvalState & state, Env & env) override;
|
||||
COMMON_METHODS
|
||||
};
|
||||
|
@ -186,7 +187,7 @@ struct ExprInheritFrom : ExprVar
|
|||
this->fromWith = nullptr;
|
||||
}
|
||||
|
||||
void bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env);
|
||||
void bindVars(EvalState & es, const std::shared_ptr<const StaticEnv> & env) override;
|
||||
};
|
||||
|
||||
struct ExprSelect : Expr
|
||||
|
@ -203,7 +204,7 @@ struct ExprSelect : Expr
|
|||
*
|
||||
* @param[out] v The attribute set that should contain the last attribute name (if it exists).
|
||||
* @return The last attribute name in `attrPath`
|
||||
*
|
||||
*
|
||||
* @note This does *not* evaluate the final attribute, and does not fail if that's the only attribute that does not exist.
|
||||
*/
|
||||
Symbol evalExceptFinalSelect(EvalState & state, Env & env, Value & attrs);
|
||||
|
|
|
@ -102,12 +102,8 @@ mkMesonDerivation (finalAttrs: {
|
|||
LDFLAGS = "-fuse-ld=gold";
|
||||
};
|
||||
|
||||
enableParallelBuilding = true;
|
||||
|
||||
separateDebugInfo = !stdenv.hostPlatform.isStatic;
|
||||
|
||||
strictDeps = true;
|
||||
|
||||
hardeningDisable = lib.optional stdenv.hostPlatform.isStatic "pie";
|
||||
|
||||
meta = {
|
||||
|
|
|
@ -20,6 +20,7 @@ struct StringToken
|
|||
operator std::string_view() const { return {p, l}; }
|
||||
};
|
||||
|
||||
// This type must be trivially copyable; see YYLTYPE_IS_TRIVIAL in parser.y.
|
||||
struct ParserLocation
|
||||
{
|
||||
int beginOffset;
|
||||
|
@ -86,7 +87,7 @@ struct ParserState
|
|||
|
||||
void dupAttr(const AttrPath & attrPath, const PosIdx pos, const PosIdx prevPos);
|
||||
void dupAttr(Symbol attr, const PosIdx pos, const PosIdx prevPos);
|
||||
void addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr * e, const PosIdx pos);
|
||||
void addAttr(ExprAttrs * attrs, AttrPath && attrPath, const ParserLocation & loc, Expr * e, const ParserLocation & exprLoc);
|
||||
Formals * validateFormals(Formals * formals, PosIdx pos = noPos, Symbol arg = {});
|
||||
Expr * stripIndentation(const PosIdx pos,
|
||||
std::vector<std::pair<PosIdx, std::variant<Expr *, StringToken>>> && es);
|
||||
|
@ -110,11 +111,12 @@ inline void ParserState::dupAttr(Symbol attr, const PosIdx pos, const PosIdx pre
|
|||
});
|
||||
}
|
||||
|
||||
inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr * e, const PosIdx pos)
|
||||
inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, const ParserLocation & loc, Expr * e, const ParserLocation & exprLoc)
|
||||
{
|
||||
AttrPath::iterator i;
|
||||
// All attrpaths have at least one attr
|
||||
assert(!attrPath.empty());
|
||||
auto pos = at(loc);
|
||||
// Checking attrPath validity.
|
||||
// ===========================
|
||||
for (i = attrPath.begin(); i + 1 < attrPath.end(); i++) {
|
||||
|
@ -179,6 +181,12 @@ inline void ParserState::addAttr(ExprAttrs * attrs, AttrPath && attrPath, Expr *
|
|||
} else {
|
||||
attrs->dynamicAttrs.push_back(ExprAttrs::DynamicAttrDef(i->expr, e, pos));
|
||||
}
|
||||
|
||||
auto it = lexerState.positionToDocComment.find(pos);
|
||||
if (it != lexerState.positionToDocComment.end()) {
|
||||
e->setDocComment(it->second);
|
||||
lexerState.positionToDocComment.emplace(at(exprLoc), it->second);
|
||||
}
|
||||
}
|
||||
|
||||
inline Formals * ParserState::validateFormals(Formals * formals, PosIdx pos, Symbol arg)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
%glr-parser
|
||||
%define api.location.type { ::nix::ParserLocation }
|
||||
%define api.pure
|
||||
%locations
|
||||
%define parse.error verbose
|
||||
|
@ -8,8 +8,7 @@
|
|||
%parse-param { nix::ParserState * state }
|
||||
%lex-param { void * scanner }
|
||||
%lex-param { nix::ParserState * state }
|
||||
%expect 1
|
||||
%expect-rr 1
|
||||
%expect 0
|
||||
|
||||
%code requires {
|
||||
|
||||
|
@ -27,7 +26,17 @@
|
|||
#include "eval-settings.hh"
|
||||
#include "parser-state.hh"
|
||||
|
||||
#define YYLTYPE ::nix::ParserLocation
|
||||
// Bison seems to have difficulty growing the parser stack when using C++ with
|
||||
// a custom location type. This undocumented macro tells Bison that our
|
||||
// location type is "trivially copyable" in C++-ese, so it is safe to use the
|
||||
// same memcpy macro it uses to grow the stack that it uses with its own
|
||||
// default location type. Without this, we get "error: memory exhausted" when
|
||||
// parsing some large Nix files. Our other options are to increase the initial
|
||||
// stack size (200 by default) to be as large as we ever want to support (so
|
||||
// that growing the stack is unnecessary), or redefine the stack-relocation
|
||||
// macro ourselves (which is also undocumented).
|
||||
#define YYLTYPE_IS_TRIVIAL 1
|
||||
|
||||
#define YY_DECL int yylex \
|
||||
(YYSTYPE * yylval_param, YYLTYPE * yylloc_param, yyscan_t yyscanner, nix::ParserState * state)
|
||||
|
||||
|
@ -77,7 +86,7 @@ YY_DECL;
|
|||
|
||||
using namespace nix;
|
||||
|
||||
#define CUR_POS state->at(*yylocp)
|
||||
#define CUR_POS state->at(yyloc)
|
||||
|
||||
|
||||
void yyerror(YYLTYPE * loc, yyscan_t scanner, ParserState * state, const char * error)
|
||||
|
@ -99,6 +108,14 @@ static void setDocPosition(const LexerState & lexerState, ExprLambda * lambda, P
|
|||
}
|
||||
}
|
||||
|
||||
static Expr * makeCall(PosIdx pos, Expr * fn, Expr * arg) {
|
||||
if (auto e2 = dynamic_cast<ExprCall *>(fn)) {
|
||||
e2->args.push_back(arg);
|
||||
return fn;
|
||||
}
|
||||
return new ExprCall(pos, fn, {arg});
|
||||
}
|
||||
|
||||
|
||||
%}
|
||||
|
||||
|
@ -123,9 +140,10 @@ static void setDocPosition(const LexerState & lexerState, ExprLambda * lambda, P
|
|||
|
||||
%type <e> start expr expr_function expr_if expr_op
|
||||
%type <e> expr_select expr_simple expr_app
|
||||
%type <e> expr_pipe_from expr_pipe_into
|
||||
%type <list> expr_list
|
||||
%type <attrs> binds
|
||||
%type <formals> formals
|
||||
%type <attrs> binds binds1
|
||||
%type <formals> formals formal_set
|
||||
%type <formal> formal
|
||||
%type <attrNames> attrpath
|
||||
%type <inheritAttrs> attrs
|
||||
|
@ -140,6 +158,7 @@ static void setDocPosition(const LexerState & lexerState, ExprLambda * lambda, P
|
|||
%token <path> PATH HPATH SPATH PATH_END
|
||||
%token <uri> URI
|
||||
%token IF THEN ELSE ASSERT WITH LET IN_KW REC INHERIT EQ NEQ AND OR IMPL OR_KW
|
||||
%token PIPE_FROM PIPE_INTO /* <| and |> */
|
||||
%token DOLLAR_CURLY /* == ${ */
|
||||
%token IND_STRING_OPEN IND_STRING_CLOSE
|
||||
%token ELLIPSIS
|
||||
|
@ -170,22 +189,22 @@ expr_function
|
|||
$$ = me;
|
||||
SET_DOC_POS(me, @1);
|
||||
}
|
||||
| '{' formals '}' ':' expr_function
|
||||
{ auto me = new ExprLambda(CUR_POS, state->validateFormals($2), $5);
|
||||
| formal_set ':' expr_function[body]
|
||||
{ auto me = new ExprLambda(CUR_POS, state->validateFormals($formal_set), $body);
|
||||
$$ = me;
|
||||
SET_DOC_POS(me, @1);
|
||||
}
|
||||
| '{' formals '}' '@' ID ':' expr_function
|
||||
| formal_set '@' ID ':' expr_function[body]
|
||||
{
|
||||
auto arg = state->symbols.create($5);
|
||||
auto me = new ExprLambda(CUR_POS, arg, state->validateFormals($2, CUR_POS, arg), $7);
|
||||
auto arg = state->symbols.create($ID);
|
||||
auto me = new ExprLambda(CUR_POS, arg, state->validateFormals($formal_set, CUR_POS, arg), $body);
|
||||
$$ = me;
|
||||
SET_DOC_POS(me, @1);
|
||||
}
|
||||
| ID '@' '{' formals '}' ':' expr_function
|
||||
| ID '@' formal_set ':' expr_function[body]
|
||||
{
|
||||
auto arg = state->symbols.create($1);
|
||||
auto me = new ExprLambda(CUR_POS, arg, state->validateFormals($4, CUR_POS, arg), $7);
|
||||
auto arg = state->symbols.create($ID);
|
||||
auto me = new ExprLambda(CUR_POS, arg, state->validateFormals($formal_set, CUR_POS, arg), $body);
|
||||
$$ = me;
|
||||
SET_DOC_POS(me, @1);
|
||||
}
|
||||
|
@ -206,9 +225,21 @@ expr_function
|
|||
|
||||
expr_if
|
||||
: IF expr THEN expr ELSE expr { $$ = new ExprIf(CUR_POS, $2, $4, $6); }
|
||||
| expr_pipe_from
|
||||
| expr_pipe_into
|
||||
| expr_op
|
||||
;
|
||||
|
||||
expr_pipe_from
|
||||
: expr_op PIPE_FROM expr_pipe_from { $$ = makeCall(state->at(@2), $1, $3); }
|
||||
| expr_op PIPE_FROM expr_op { $$ = makeCall(state->at(@2), $1, $3); }
|
||||
;
|
||||
|
||||
expr_pipe_into
|
||||
: expr_pipe_into PIPE_INTO expr_op { $$ = makeCall(state->at(@2), $3, $1); }
|
||||
| expr_op PIPE_INTO expr_op { $$ = makeCall(state->at(@2), $3, $1); }
|
||||
;
|
||||
|
||||
expr_op
|
||||
: '!' expr_op %prec NOT { $$ = new ExprOpNot($2); }
|
||||
| '-' expr_op %prec NEGATE { $$ = new ExprCall(CUR_POS, new ExprVar(state->s.sub), {new ExprInt(0), $2}); }
|
||||
|
@ -233,13 +264,7 @@ expr_op
|
|||
;
|
||||
|
||||
expr_app
|
||||
: expr_app expr_select {
|
||||
if (auto e2 = dynamic_cast<ExprCall *>($1)) {
|
||||
e2->args.push_back($2);
|
||||
$$ = $1;
|
||||
} else
|
||||
$$ = new ExprCall(CUR_POS, $1, {$2});
|
||||
}
|
||||
: expr_app expr_select { $$ = makeCall(CUR_POS, $1, $2); }
|
||||
| expr_select
|
||||
;
|
||||
|
||||
|
@ -295,11 +320,13 @@ expr_simple
|
|||
/* Let expressions `let {..., body = ...}' are just desugared
|
||||
into `(rec {..., body = ...}).body'. */
|
||||
| LET '{' binds '}'
|
||||
{ $3->recursive = true; $$ = new ExprSelect(noPos, $3, state->s.body); }
|
||||
{ $3->recursive = true; $3->pos = CUR_POS; $$ = new ExprSelect(noPos, $3, state->s.body); }
|
||||
| REC '{' binds '}'
|
||||
{ $3->recursive = true; $$ = $3; }
|
||||
| '{' binds '}'
|
||||
{ $$ = $2; }
|
||||
{ $3->recursive = true; $3->pos = CUR_POS; $$ = $3; }
|
||||
| '{' binds1 '}'
|
||||
{ $2->pos = CUR_POS; $$ = $2; }
|
||||
| '{' '}'
|
||||
{ $$ = new ExprAttrs(CUR_POS); }
|
||||
| '[' expr_list ']' { $$ = $2; }
|
||||
;
|
||||
|
||||
|
@ -348,52 +375,50 @@ ind_string_parts
|
|||
;
|
||||
|
||||
binds
|
||||
: binds attrpath '=' expr ';' {
|
||||
$$ = $1;
|
||||
: binds1
|
||||
| { $$ = new ExprAttrs; }
|
||||
;
|
||||
|
||||
auto pos = state->at(@2);
|
||||
auto exprPos = state->at(@4);
|
||||
{
|
||||
auto it = state->lexerState.positionToDocComment.find(pos);
|
||||
if (it != state->lexerState.positionToDocComment.end()) {
|
||||
$4->setDocComment(it->second);
|
||||
state->lexerState.positionToDocComment.emplace(exprPos, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
state->addAttr($$, std::move(*$2), $4, pos);
|
||||
delete $2;
|
||||
binds1
|
||||
: binds1[accum] attrpath '=' expr ';'
|
||||
{ $$ = $accum;
|
||||
state->addAttr($$, std::move(*$attrpath), @attrpath, $expr, @expr);
|
||||
delete $attrpath;
|
||||
}
|
||||
| binds INHERIT attrs ';'
|
||||
{ $$ = $1;
|
||||
for (auto & [i, iPos] : *$3) {
|
||||
if ($$->attrs.find(i.symbol) != $$->attrs.end())
|
||||
state->dupAttr(i.symbol, iPos, $$->attrs[i.symbol].pos);
|
||||
$$->attrs.emplace(
|
||||
| binds[accum] INHERIT attrs ';'
|
||||
{ $$ = $accum;
|
||||
for (auto & [i, iPos] : *$attrs) {
|
||||
if ($accum->attrs.find(i.symbol) != $accum->attrs.end())
|
||||
state->dupAttr(i.symbol, iPos, $accum->attrs[i.symbol].pos);
|
||||
$accum->attrs.emplace(
|
||||
i.symbol,
|
||||
ExprAttrs::AttrDef(new ExprVar(iPos, i.symbol), iPos, ExprAttrs::AttrDef::Kind::Inherited));
|
||||
}
|
||||
delete $3;
|
||||
delete $attrs;
|
||||
}
|
||||
| binds INHERIT '(' expr ')' attrs ';'
|
||||
{ $$ = $1;
|
||||
if (!$$->inheritFromExprs)
|
||||
$$->inheritFromExprs = std::make_unique<std::vector<Expr *>>();
|
||||
$$->inheritFromExprs->push_back($4);
|
||||
auto from = new nix::ExprInheritFrom(state->at(@4), $$->inheritFromExprs->size() - 1);
|
||||
for (auto & [i, iPos] : *$6) {
|
||||
if ($$->attrs.find(i.symbol) != $$->attrs.end())
|
||||
state->dupAttr(i.symbol, iPos, $$->attrs[i.symbol].pos);
|
||||
$$->attrs.emplace(
|
||||
| binds[accum] INHERIT '(' expr ')' attrs ';'
|
||||
{ $$ = $accum;
|
||||
if (!$accum->inheritFromExprs)
|
||||
$accum->inheritFromExprs = std::make_unique<std::vector<Expr *>>();
|
||||
$accum->inheritFromExprs->push_back($expr);
|
||||
auto from = new nix::ExprInheritFrom(state->at(@expr), $accum->inheritFromExprs->size() - 1);
|
||||
for (auto & [i, iPos] : *$attrs) {
|
||||
if ($accum->attrs.find(i.symbol) != $accum->attrs.end())
|
||||
state->dupAttr(i.symbol, iPos, $accum->attrs[i.symbol].pos);
|
||||
$accum->attrs.emplace(
|
||||
i.symbol,
|
||||
ExprAttrs::AttrDef(
|
||||
new ExprSelect(iPos, from, i.symbol),
|
||||
iPos,
|
||||
ExprAttrs::AttrDef::Kind::InheritedFrom));
|
||||
}
|
||||
delete $6;
|
||||
delete $attrs;
|
||||
}
|
||||
| attrpath '=' expr ';'
|
||||
{ $$ = new ExprAttrs;
|
||||
state->addAttr($$, std::move(*$attrpath), @attrpath, $expr, @expr);
|
||||
delete $attrpath;
|
||||
}
|
||||
| { $$ = new ExprAttrs(state->at(@0)); }
|
||||
;
|
||||
|
||||
attrs
|
||||
|
@ -451,15 +476,19 @@ expr_list
|
|||
| { $$ = new ExprList; }
|
||||
;
|
||||
|
||||
formal_set
|
||||
: '{' formals ',' ELLIPSIS '}' { $$ = $formals; $$->ellipsis = true; }
|
||||
| '{' ELLIPSIS '}' { $$ = new Formals; $$->ellipsis = true; }
|
||||
| '{' formals ',' '}' { $$ = $formals; $$->ellipsis = false; }
|
||||
| '{' formals '}' { $$ = $formals; $$->ellipsis = false; }
|
||||
| '{' '}' { $$ = new Formals; $$->ellipsis = false; }
|
||||
;
|
||||
|
||||
formals
|
||||
: formal ',' formals
|
||||
{ $$ = $3; $$->formals.emplace_back(*$1); delete $1; }
|
||||
: formals[accum] ',' formal
|
||||
{ $$ = $accum; $$->formals.emplace_back(*$formal); delete $formal; }
|
||||
| formal
|
||||
{ $$ = new Formals; $$->formals.emplace_back(*$1); $$->ellipsis = false; delete $1; }
|
||||
|
|
||||
{ $$ = new Formals; $$->ellipsis = false; }
|
||||
| ELLIPSIS
|
||||
{ $$ = new Formals; $$->ellipsis = true; }
|
||||
{ $$ = new Formals; $$->formals.emplace_back(*$formal); delete $formal; }
|
||||
;
|
||||
|
||||
formal
|
||||
|
|
|
@ -426,7 +426,7 @@ static void prim_typeOf(EvalState & state, const PosIdx pos, Value * * args, Val
|
|||
t = args[0]->external()->typeOf();
|
||||
break;
|
||||
case nFloat: t = "float"; break;
|
||||
case nThunk: abort();
|
||||
case nThunk: unreachable();
|
||||
}
|
||||
v.mkString(t);
|
||||
}
|
||||
|
@ -587,9 +587,9 @@ struct CompareValues
|
|||
{
|
||||
try {
|
||||
if (v1->type() == nFloat && v2->type() == nInt)
|
||||
return v1->fpoint() < v2->integer();
|
||||
return v1->fpoint() < v2->integer().value;
|
||||
if (v1->type() == nInt && v2->type() == nFloat)
|
||||
return v1->integer() < v2->fpoint();
|
||||
return v1->integer().value < v2->fpoint();
|
||||
if (v1->type() != v2->type())
|
||||
state.error<EvalError>("cannot compare %s with %s", showType(*v1), showType(*v2)).debugThrow();
|
||||
// Allow selecting a subset of enum values
|
||||
|
@ -1843,34 +1843,6 @@ static RegisterPrimOp primop_findFile(PrimOp {
|
|||
.doc = R"(
|
||||
Find *lookup-path* in *search-path*.
|
||||
|
||||
A search path is represented list of [attribute sets](./types.md#attribute-set) with two attributes:
|
||||
- `prefix` is a relative path.
|
||||
- `path` denotes a file system location
|
||||
The exact syntax depends on the command line interface.
|
||||
|
||||
Examples of search path attribute sets:
|
||||
|
||||
- ```
|
||||
{
|
||||
prefix = "nixos-config";
|
||||
path = "/etc/nixos/configuration.nix";
|
||||
}
|
||||
```
|
||||
|
||||
- ```
|
||||
{
|
||||
prefix = "";
|
||||
path = "/nix/var/nix/profiles/per-user/root/channels";
|
||||
}
|
||||
```
|
||||
|
||||
The lookup algorithm checks each entry until a match is found, returning a [path value](@docroot@/language/types.md#type-path) of the match:
|
||||
|
||||
- If *lookup-path* matches `prefix`, then the remainder of *lookup-path* (the "suffix") is searched for within the directory denoted by `path`.
|
||||
Note that the `path` may need to be downloaded at this point to look inside.
|
||||
- If the suffix is found inside that directory, then the entry is a match.
|
||||
The combined absolute path of the directory (now downloaded if need be) and the suffix is returned.
|
||||
|
||||
[Lookup path](@docroot@/language/constructs/lookup-path.md) expressions are [desugared](https://en.wikipedia.org/wiki/Syntactic_sugar) using this and [`builtins.nixPath`](#builtins-nixPath):
|
||||
|
||||
```nix
|
||||
|
@ -1882,6 +1854,119 @@ static RegisterPrimOp primop_findFile(PrimOp {
|
|||
```nix
|
||||
builtins.findFile builtins.nixPath "nixpkgs"
|
||||
```
|
||||
|
||||
A search path is represented as a list of [attribute sets](./types.md#attribute-set) with two attributes:
|
||||
- `prefix` is a relative path.
|
||||
- `path` denotes a file system location
|
||||
|
||||
Examples of search path attribute sets:
|
||||
|
||||
- ```
|
||||
{
|
||||
prefix = "";
|
||||
path = "/nix/var/nix/profiles/per-user/root/channels";
|
||||
}
|
||||
```
|
||||
- ```
|
||||
{
|
||||
prefix = "nixos-config";
|
||||
path = "/etc/nixos/configuration.nix";
|
||||
}
|
||||
```
|
||||
- ```
|
||||
{
|
||||
prefix = "nixpkgs";
|
||||
path = "https://github.com/NixOS/nixpkgs/tarballs/master";
|
||||
}
|
||||
```
|
||||
- ```
|
||||
{
|
||||
prefix = "nixpkgs";
|
||||
path = "channel:nixpkgs-unstable";
|
||||
}
|
||||
```
|
||||
- ```
|
||||
{
|
||||
prefix = "flake-compat";
|
||||
path = "flake:github:edolstra/flake-compat";
|
||||
}
|
||||
```
|
||||
|
||||
The lookup algorithm checks each entry until a match is found, returning a [path value](@docroot@/language/types.md#type-path) of the match:
|
||||
|
||||
- If a prefix of `lookup-path` matches `prefix`, then the remainder of *lookup-path* (the "suffix") is searched for within the directory denoted by `path`.
|
||||
The contents of `path` may need to be downloaded at this point to look inside.
|
||||
|
||||
- If the suffix is found inside that directory, then the entry is a match.
|
||||
The combined absolute path of the directory (now downloaded if need be) and the suffix is returned.
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> A *search-path* value
|
||||
>
|
||||
> ```
|
||||
> [
|
||||
> {
|
||||
> prefix = "";
|
||||
> path = "/home/eelco/Dev";
|
||||
> }
|
||||
> {
|
||||
> prefix = "nixos-config";
|
||||
> path = "/etc/nixos";
|
||||
> }
|
||||
> ]
|
||||
> ```
|
||||
>
|
||||
> and a *lookup-path* value `"nixos-config"` will cause Nix to try `/home/eelco/Dev/nixos-config` and `/etc/nixos` in that order and return the first path that exists.
|
||||
|
||||
If `path` starts with `http://` or `https://`, it is interpreted as the URL of a tarball that will be downloaded and unpacked to a temporary location.
|
||||
The tarball must consist of a single top-level directory.
|
||||
|
||||
The URLs of the tarballs from the official `nixos.org` channels can be abbreviated as `channel:<channel-name>`.
|
||||
See [documentation on `nix-channel`](@docroot@/command-ref/nix-channel.md) for details about channels.
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> These two search path entries are equivalent:
|
||||
>
|
||||
> - ```
|
||||
> {
|
||||
> prefix = "nixpkgs";
|
||||
> path = "channel:nixpkgs-unstable";
|
||||
> }
|
||||
> ```
|
||||
> - ```
|
||||
> {
|
||||
> prefix = "nixpkgs";
|
||||
> path = "https://nixos.org/channels/nixos-unstable/nixexprs.tar.xz";
|
||||
> }
|
||||
> ```
|
||||
|
||||
Search paths can also point to source trees using [flake URLs](@docroot@/command-ref/new-cli/nix3-flake.md#url-like-syntax).
|
||||
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> The search path entry
|
||||
>
|
||||
> ```
|
||||
> {
|
||||
> prefix = "nixpkgs";
|
||||
> path = "flake:nixpkgs";
|
||||
> }
|
||||
> ```
|
||||
> specifies that the prefix `nixpkgs` shall refer to the source tree downloaded from the `nixpkgs` entry in the flake registry.
|
||||
>
|
||||
> Similarly
|
||||
>
|
||||
> ```
|
||||
> {
|
||||
> prefix = "nixpkgs";
|
||||
> path = "flake:github:nixos/nixpkgs/nixos-22.05";
|
||||
> }
|
||||
> ```
|
||||
>
|
||||
> makes `<nixpkgs>` refer to a particular branch of the `NixOS/nixpkgs` repository on GitHub.
|
||||
)",
|
||||
.fun = prim_findFile,
|
||||
});
|
||||
|
@ -2677,13 +2762,13 @@ static struct LazyPosAcessors {
|
|||
PrimOp primop_lineOfPos{
|
||||
.arity = 1,
|
||||
.fun = [] (EvalState & state, PosIdx pos, Value * * args, Value & v) {
|
||||
v.mkInt(state.positions[PosIdx(args[0]->integer())].line);
|
||||
v.mkInt(state.positions[PosIdx(args[0]->integer().value)].line);
|
||||
}
|
||||
};
|
||||
PrimOp primop_columnOfPos{
|
||||
.arity = 1,
|
||||
.fun = [] (EvalState & state, PosIdx pos, Value * * args, Value & v) {
|
||||
v.mkInt(state.positions[PosIdx(args[0]->integer())].column);
|
||||
v.mkInt(state.positions[PosIdx(args[0]->integer().value)].column);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3159,7 +3244,8 @@ static void elemAt(EvalState & state, const PosIdx pos, Value & list, int n, Val
|
|||
/* Return the n-1'th element of a list. */
|
||||
static void prim_elemAt(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
elemAt(state, pos, *args[0], state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.elemAt"), v);
|
||||
NixInt::Inner elem = state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.elemAt").value;
|
||||
elemAt(state, pos, *args[0], elem, v);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_elemAt({
|
||||
|
@ -3453,10 +3539,12 @@ static RegisterPrimOp primop_all({
|
|||
|
||||
static void prim_genList(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
auto len = state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.genList");
|
||||
auto len_ = state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.genList").value;
|
||||
|
||||
if (len < 0)
|
||||
state.error<EvalError>("cannot create list of size %1%", len).atPos(pos).debugThrow();
|
||||
if (len_ < 0)
|
||||
state.error<EvalError>("cannot create list of size %1%", len_).atPos(pos).debugThrow();
|
||||
|
||||
size_t len = size_t(len_);
|
||||
|
||||
// More strict than striclty (!) necessary, but acceptable
|
||||
// as evaluating map without accessing any values makes little sense.
|
||||
|
@ -3713,9 +3801,17 @@ static void prim_add(EvalState & state, const PosIdx pos, Value * * args, Value
|
|||
if (args[0]->type() == nFloat || args[1]->type() == nFloat)
|
||||
v.mkFloat(state.forceFloat(*args[0], pos, "while evaluating the first argument of the addition")
|
||||
+ state.forceFloat(*args[1], pos, "while evaluating the second argument of the addition"));
|
||||
else
|
||||
v.mkInt( state.forceInt(*args[0], pos, "while evaluating the first argument of the addition")
|
||||
+ state.forceInt(*args[1], pos, "while evaluating the second argument of the addition"));
|
||||
else {
|
||||
auto i1 = state.forceInt(*args[0], pos, "while evaluating the first argument of the addition");
|
||||
auto i2 = state.forceInt(*args[1], pos, "while evaluating the second argument of the addition");
|
||||
|
||||
auto result_ = i1 + i2;
|
||||
if (auto result = result_.valueChecked(); result.has_value()) {
|
||||
v.mkInt(*result);
|
||||
} else {
|
||||
state.error<EvalError>("integer overflow in adding %1% + %2%", i1, i2).atPos(pos).debugThrow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_add({
|
||||
|
@ -3734,9 +3830,18 @@ static void prim_sub(EvalState & state, const PosIdx pos, Value * * args, Value
|
|||
if (args[0]->type() == nFloat || args[1]->type() == nFloat)
|
||||
v.mkFloat(state.forceFloat(*args[0], pos, "while evaluating the first argument of the subtraction")
|
||||
- state.forceFloat(*args[1], pos, "while evaluating the second argument of the subtraction"));
|
||||
else
|
||||
v.mkInt( state.forceInt(*args[0], pos, "while evaluating the first argument of the subtraction")
|
||||
- state.forceInt(*args[1], pos, "while evaluating the second argument of the subtraction"));
|
||||
else {
|
||||
auto i1 = state.forceInt(*args[0], pos, "while evaluating the first argument of the subtraction");
|
||||
auto i2 = state.forceInt(*args[1], pos, "while evaluating the second argument of the subtraction");
|
||||
|
||||
auto result_ = i1 - i2;
|
||||
|
||||
if (auto result = result_.valueChecked(); result.has_value()) {
|
||||
v.mkInt(*result);
|
||||
} else {
|
||||
state.error<EvalError>("integer overflow in subtracting %1% - %2%", i1, i2).atPos(pos).debugThrow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_sub({
|
||||
|
@ -3755,9 +3860,18 @@ static void prim_mul(EvalState & state, const PosIdx pos, Value * * args, Value
|
|||
if (args[0]->type() == nFloat || args[1]->type() == nFloat)
|
||||
v.mkFloat(state.forceFloat(*args[0], pos, "while evaluating the first of the multiplication")
|
||||
* state.forceFloat(*args[1], pos, "while evaluating the second argument of the multiplication"));
|
||||
else
|
||||
v.mkInt( state.forceInt(*args[0], pos, "while evaluating the first argument of the multiplication")
|
||||
* state.forceInt(*args[1], pos, "while evaluating the second argument of the multiplication"));
|
||||
else {
|
||||
auto i1 = state.forceInt(*args[0], pos, "while evaluating the first argument of the multiplication");
|
||||
auto i2 = state.forceInt(*args[1], pos, "while evaluating the second argument of the multiplication");
|
||||
|
||||
auto result_ = i1 * i2;
|
||||
|
||||
if (auto result = result_.valueChecked(); result.has_value()) {
|
||||
v.mkInt(*result);
|
||||
} else {
|
||||
state.error<EvalError>("integer overflow in multiplying %1% * %2%", i1, i2).atPos(pos).debugThrow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_mul({
|
||||
|
@ -3784,10 +3898,12 @@ static void prim_div(EvalState & state, const PosIdx pos, Value * * args, Value
|
|||
NixInt i1 = state.forceInt(*args[0], pos, "while evaluating the first operand of the division");
|
||||
NixInt i2 = state.forceInt(*args[1], pos, "while evaluating the second operand of the division");
|
||||
/* Avoid division overflow as it might raise SIGFPE. */
|
||||
if (i1 == std::numeric_limits<NixInt>::min() && i2 == -1)
|
||||
state.error<EvalError>("overflow in integer division").atPos(pos).debugThrow();
|
||||
|
||||
v.mkInt(i1 / i2);
|
||||
auto result_ = i1 / i2;
|
||||
if (auto result = result_.valueChecked(); result.has_value()) {
|
||||
v.mkInt(*result);
|
||||
} else {
|
||||
state.error<EvalError>("integer overflow in dividing %1% / %2%", i1, i2).atPos(pos).debugThrow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3802,8 +3918,9 @@ static RegisterPrimOp primop_div({
|
|||
|
||||
static void prim_bitAnd(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
v.mkInt(state.forceInt(*args[0], pos, "while evaluating the first argument passed to builtins.bitAnd")
|
||||
& state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.bitAnd"));
|
||||
auto i1 = state.forceInt(*args[0], pos, "while evaluating the first argument passed to builtins.bitAnd");
|
||||
auto i2 = state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.bitAnd");
|
||||
v.mkInt(i1.value & i2.value);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_bitAnd({
|
||||
|
@ -3817,8 +3934,10 @@ static RegisterPrimOp primop_bitAnd({
|
|||
|
||||
static void prim_bitOr(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
v.mkInt(state.forceInt(*args[0], pos, "while evaluating the first argument passed to builtins.bitOr")
|
||||
| state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.bitOr"));
|
||||
auto i1 = state.forceInt(*args[0], pos, "while evaluating the first argument passed to builtins.bitOr");
|
||||
auto i2 = state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.bitOr");
|
||||
|
||||
v.mkInt(i1.value | i2.value);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_bitOr({
|
||||
|
@ -3832,8 +3951,10 @@ static RegisterPrimOp primop_bitOr({
|
|||
|
||||
static void prim_bitXor(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
v.mkInt(state.forceInt(*args[0], pos, "while evaluating the first argument passed to builtins.bitXor")
|
||||
^ state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.bitXor"));
|
||||
auto i1 = state.forceInt(*args[0], pos, "while evaluating the first argument passed to builtins.bitXor");
|
||||
auto i2 = state.forceInt(*args[1], pos, "while evaluating the second argument passed to builtins.bitXor");
|
||||
|
||||
v.mkInt(i1.value ^ i2.value);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_bitXor({
|
||||
|
@ -3913,13 +4034,19 @@ static RegisterPrimOp primop_toString({
|
|||
non-negative. */
|
||||
static void prim_substring(EvalState & state, const PosIdx pos, Value * * args, Value & v)
|
||||
{
|
||||
int start = state.forceInt(*args[0], pos, "while evaluating the first argument (the start offset) passed to builtins.substring");
|
||||
NixInt::Inner start = state.forceInt(*args[0], pos, "while evaluating the first argument (the start offset) passed to builtins.substring").value;
|
||||
|
||||
if (start < 0)
|
||||
state.error<EvalError>("negative start position in 'substring'").atPos(pos).debugThrow();
|
||||
|
||||
|
||||
int len = state.forceInt(*args[1], pos, "while evaluating the second argument (the substring length) passed to builtins.substring");
|
||||
NixInt::Inner len = state.forceInt(*args[1], pos, "while evaluating the second argument (the substring length) passed to builtins.substring").value;
|
||||
|
||||
// Negative length may be idiomatically passed to builtins.substring to get
|
||||
// the tail of the string.
|
||||
if (len < 0) {
|
||||
len = std::numeric_limits<NixInt::Inner>::max();
|
||||
}
|
||||
|
||||
// Special-case on empty substring to avoid O(n) strlen
|
||||
// This allows for the use of empty substrings to efficently capture string context
|
||||
|
@ -3962,7 +4089,7 @@ static void prim_stringLength(EvalState & state, const PosIdx pos, Value * * arg
|
|||
{
|
||||
NixStringContext context;
|
||||
auto s = state.coerceToString(pos, *args[0], context, "while evaluating the argument passed to builtins.stringLength");
|
||||
v.mkInt(s->size());
|
||||
v.mkInt(NixInt::Inner(s->size()));
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_stringLength({
|
||||
|
@ -4446,7 +4573,8 @@ static void prim_compareVersions(EvalState & state, const PosIdx pos, Value * *
|
|||
{
|
||||
auto version1 = state.forceStringNoCtx(*args[0], pos, "while evaluating the first argument passed to builtins.compareVersions");
|
||||
auto version2 = state.forceStringNoCtx(*args[1], pos, "while evaluating the second argument passed to builtins.compareVersions");
|
||||
v.mkInt(compareVersions(version1, version2));
|
||||
auto result = compareVersions(version1, version2);
|
||||
v.mkInt(result < 0 ? -1 : result > 0 ? 1 : 0);
|
||||
}
|
||||
|
||||
static RegisterPrimOp primop_compareVersions({
|
||||
|
@ -4729,7 +4857,17 @@ void EvalState::createBaseEnv()
|
|||
addConstant("__nixPath", v, {
|
||||
.type = nList,
|
||||
.doc = R"(
|
||||
The value of the [`nix-path` configuration setting](@docroot@/command-ref/conf-file.md#conf-nix-path): a list of search path entries used to resolve [lookup paths](@docroot@/language/constructs/lookup-path.md).
|
||||
A list of search path entries used to resolve [lookup paths](@docroot@/language/constructs/lookup-path.md).
|
||||
Its value is primarily determined by the [`nix-path` configuration setting](@docroot@/command-ref/conf-file.md#conf-nix-path), which are
|
||||
- Overridden by the [`NIX_PATH`](@docroot@/command-ref/env-common.md#env-NIX_PATH) environment variable or the `--nix-path` option
|
||||
- Extended by the [`-I` option](@docroot@/command-ref/opt-common.md#opt-I) or `--extra-nix-path`
|
||||
|
||||
> **Example**
|
||||
>
|
||||
> ```bash
|
||||
> $ NIX_PATH= nix-instantiate --eval --expr "builtins.nixPath" -I foo=bar --no-pure-eval
|
||||
> [ { path = "bar"; prefix = "foo"; } ]
|
||||
> ```
|
||||
|
||||
Lookup path expressions are [desugared](https://en.wikipedia.org/wiki/Syntactic_sugar) using this and
|
||||
[`builtins.findFile`](./builtins.html#builtins-findFile):
|
||||
|
|
|
@ -1,6 +1,31 @@
|
|||
/* This is the implementation of the ‘derivation’ builtin function.
|
||||
It's actually a wrapper around the ‘derivationStrict’ primop. */
|
||||
# This is the implementation of the ‘derivation’ builtin function.
|
||||
# It's actually a wrapper around the ‘derivationStrict’ primop.
|
||||
# Note that the following comment will be shown in :doc in the repl, but not in the manual.
|
||||
|
||||
/**
|
||||
Create a derivation.
|
||||
|
||||
# Inputs
|
||||
|
||||
The single argument is an attribute set that describes what to build and how to build it.
|
||||
See https://nix.dev/manual/nix/2.23/language/derivations
|
||||
|
||||
# Output
|
||||
|
||||
The result is an attribute set that describes the derivation.
|
||||
Notably it contains the outputs, which in the context of the Nix language are special strings that refer to the output paths, which may not yet exist.
|
||||
The realisation of these outputs only occurs when needed; for example
|
||||
|
||||
* When `nix-build` or a similar command is run, it realises the outputs that were requested on its command line.
|
||||
See https://nix.dev/manual/nix/2.23/command-ref/nix-build
|
||||
|
||||
* When `import`, `readFile`, `readDir` or some other functions are called, they have to realise the outputs they depend on.
|
||||
This is referred to as "import from derivation".
|
||||
See https://nix.dev/manual/nix/2.23/language/import-from-derivation
|
||||
|
||||
Note that `derivation` is very bare-bones, and provides almost no commands during the build.
|
||||
Most likely, you'll want to use functions like `stdenv.mkDerivation` in Nixpkgs to set up a basic environment.
|
||||
*/
|
||||
drvAttrs @ { outputs ? [ "out" ], ... }:
|
||||
|
||||
let
|
||||
|
|
|
@ -122,9 +122,15 @@ static void fetchTree(
|
|||
}
|
||||
else if (attr.value->type() == nBool)
|
||||
attrs.emplace(state.symbols[attr.name], Explicit<bool>{attr.value->boolean()});
|
||||
else if (attr.value->type() == nInt)
|
||||
attrs.emplace(state.symbols[attr.name], uint64_t(attr.value->integer()));
|
||||
else if (state.symbols[attr.name] == "publicKeys") {
|
||||
else if (attr.value->type() == nInt) {
|
||||
auto intValue = attr.value->integer().value;
|
||||
|
||||
if (intValue < 0) {
|
||||
state.error<EvalError>("negative value given for fetchTree attr %1%: %2%", state.symbols[attr.name], intValue).atPos(pos).debugThrow();
|
||||
}
|
||||
|
||||
attrs.emplace(state.symbols[attr.name], uint64_t(intValue));
|
||||
} else if (state.symbols[attr.name] == "publicKeys") {
|
||||
experimentalFeatureSettings.require(Xp::VerifiedFetches);
|
||||
attrs.emplace(state.symbols[attr.name], printValueAsJSON(state, true, *attr.value, pos, context).dump());
|
||||
}
|
||||
|
@ -383,7 +389,7 @@ static RegisterPrimOp primop_fetchTree({
|
|||
- `"mercurial"`
|
||||
|
||||
*input* can also be a [URL-like reference](@docroot@/command-ref/new-cli/nix3-flake.md#flake-references).
|
||||
The additional input types and the URL-like syntax requires the [`flakes` experimental feature](@docroot@/contributing/experimental-features.md#xp-feature-flakes) to be enabled.
|
||||
The additional input types and the URL-like syntax requires the [`flakes` experimental feature](@docroot@/development/experimental-features.md#xp-feature-flakes) to be enabled.
|
||||
|
||||
> **Example**
|
||||
>
|
||||
|
@ -501,7 +507,11 @@ static void fetch(EvalState & state, const PosIdx pos, Value * * args, Value & v
|
|||
// https://github.com/NixOS/nix/issues/4313
|
||||
auto storePath =
|
||||
unpack
|
||||
? fetchToStore(*state.store, fetchers::downloadTarball(*url).accessor, FetchMode::Copy, name)
|
||||
? fetchToStore(
|
||||
*state.store,
|
||||
fetchers::downloadTarball(state.store, state.fetchSettings, *url),
|
||||
FetchMode::Copy,
|
||||
name)
|
||||
: fetchers::downloadFile(state.store, *url, name).storePath;
|
||||
|
||||
if (expectedHash) {
|
||||
|
@ -559,11 +569,11 @@ static RegisterPrimOp primop_fetchTarball({
|
|||
.doc = R"(
|
||||
Download the specified URL, unpack it and return the path of the
|
||||
unpacked tree. The file must be a tape archive (`.tar`) compressed
|
||||
with `gzip`, `bzip2` or `xz`. The top-level path component of the
|
||||
files in the tarball is removed, so it is best if the tarball
|
||||
contains a single directory at top level. The typical use of the
|
||||
function is to obtain external Nix expression dependencies, such as
|
||||
a particular version of Nixpkgs, e.g.
|
||||
with `gzip`, `bzip2` or `xz`. If the tarball consists of a
|
||||
single directory, then the top-level path component of the files
|
||||
in the tarball is removed. The typical use of the function is to
|
||||
obtain external Nix expression dependencies, such as a
|
||||
particular version of Nixpkgs, e.g.
|
||||
|
||||
```nix
|
||||
with import (fetchTarball https://github.com/NixOS/nixpkgs/archive/nixos-14.12.tar.gz) {};
|
||||
|
@ -670,12 +680,12 @@ static RegisterPrimOp primop_fetchGit({
|
|||
|
||||
Whether to check `rev` for a signature matching `publicKey` or `publicKeys`.
|
||||
If `verifyCommit` is enabled, then `fetchGit` cannot use a local repository with uncommitted changes.
|
||||
Requires the [`verified-fetches` experimental feature](@docroot@/contributing/experimental-features.md#xp-feature-verified-fetches).
|
||||
Requires the [`verified-fetches` experimental feature](@docroot@/development/experimental-features.md#xp-feature-verified-fetches).
|
||||
|
||||
- `publicKey`
|
||||
|
||||
The public key against which `rev` is verified if `verifyCommit` is enabled.
|
||||
Requires the [`verified-fetches` experimental feature](@docroot@/contributing/experimental-features.md#xp-feature-verified-fetches).
|
||||
Requires the [`verified-fetches` experimental feature](@docroot@/development/experimental-features.md#xp-feature-verified-fetches).
|
||||
|
||||
- `keytype` (default: `"ssh-ed25519"`)
|
||||
|
||||
|
@ -687,7 +697,7 @@ static RegisterPrimOp primop_fetchGit({
|
|||
- `"ssh-ed25519"`
|
||||
- `"ssh-ed25519-sk"`
|
||||
- `"ssh-rsa"`
|
||||
Requires the [`verified-fetches` experimental feature](@docroot@/contributing/experimental-features.md#xp-feature-verified-fetches).
|
||||
Requires the [`verified-fetches` experimental feature](@docroot@/development/experimental-features.md#xp-feature-verified-fetches).
|
||||
|
||||
- `publicKeys`
|
||||
|
||||
|
@ -701,7 +711,7 @@ static RegisterPrimOp primop_fetchGit({
|
|||
}
|
||||
```
|
||||
|
||||
Requires the [`verified-fetches` experimental feature](@docroot@/contributing/experimental-features.md#xp-feature-verified-fetches).
|
||||
Requires the [`verified-fetches` experimental feature](@docroot@/development/experimental-features.md#xp-feature-verified-fetches).
|
||||
|
||||
|
||||
Here are some examples of how to use `fetchGit`.
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "eval-inline.hh"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <toml.hpp>
|
||||
|
||||
namespace nix {
|
||||
|
|
|
@ -94,7 +94,7 @@ void printAmbiguous(
|
|||
break;
|
||||
default:
|
||||
printError("Nix evaluator internal error: printAmbiguous: invalid value type");
|
||||
abort();
|
||||
unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -475,7 +475,7 @@ private:
|
|||
else
|
||||
output << "primop";
|
||||
} else {
|
||||
abort();
|
||||
unreachable();
|
||||
}
|
||||
|
||||
output << "»";
|
||||
|
@ -504,7 +504,7 @@ private:
|
|||
if (options.ansiColors)
|
||||
output << ANSI_NORMAL;
|
||||
} else {
|
||||
abort();
|
||||
unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "types.hh"
|
||||
#include "chunked-vector.hh"
|
||||
#include "error.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
@ -69,6 +70,8 @@ public:
|
|||
|
||||
auto operator<=>(const Symbol other) const { return id <=> other.id; }
|
||||
bool operator==(const Symbol other) const { return id == other.id; }
|
||||
|
||||
friend class std::hash<Symbol>;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -113,7 +116,7 @@ public:
|
|||
SymbolStr operator[](Symbol s) const
|
||||
{
|
||||
if (s.id == 0 || s.id > store.size())
|
||||
abort();
|
||||
unreachable();
|
||||
return SymbolStr(store[s.id - 1]);
|
||||
}
|
||||
|
||||
|
@ -132,3 +135,12 @@ public:
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
struct std::hash<nix::Symbol>
|
||||
{
|
||||
std::size_t operator()(const nix::Symbol & s) const noexcept
|
||||
{
|
||||
return std::hash<decltype(s.id)>{}(s.id);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -22,7 +22,7 @@ json printValueAsJSON(EvalState & state, bool strict,
|
|||
switch (v.type()) {
|
||||
|
||||
case nInt:
|
||||
out = v.integer();
|
||||
out = v.integer().value;
|
||||
break;
|
||||
|
||||
case nBool:
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "value/context.hh"
|
||||
#include "source-path.hh"
|
||||
#include "print-options.hh"
|
||||
#include "checked-arithmetic.hh"
|
||||
|
||||
#if HAVE_BOEHMGC
|
||||
#include <gc/gc_allocator.h>
|
||||
|
@ -73,8 +74,8 @@ class EvalState;
|
|||
class XMLWriter;
|
||||
class Printer;
|
||||
|
||||
typedef int64_t NixInt;
|
||||
typedef double NixFloat;
|
||||
using NixInt = checked::Checked<int64_t>;
|
||||
using NixFloat = double;
|
||||
|
||||
/**
|
||||
* External values must descend from ExternalValueBase, so that
|
||||
|
@ -285,7 +286,7 @@ public:
|
|||
if (invalidIsThunk)
|
||||
return nThunk;
|
||||
else
|
||||
abort();
|
||||
unreachable();
|
||||
}
|
||||
|
||||
inline void finishValue(InternalType newType, Payload newPayload)
|
||||
|
@ -304,6 +305,11 @@ public:
|
|||
return internalType != tUninitialized;
|
||||
}
|
||||
|
||||
inline void mkInt(NixInt::Inner n)
|
||||
{
|
||||
mkInt(NixInt{n});
|
||||
}
|
||||
|
||||
inline void mkInt(NixInt n)
|
||||
{
|
||||
finishValue(tInt, { .integer = n });
|
||||
|
@ -325,9 +331,9 @@ public:
|
|||
|
||||
void mkStringMove(const char * s, const NixStringContext & context);
|
||||
|
||||
inline void mkString(const Symbol & s)
|
||||
inline void mkString(const SymbolStr & s)
|
||||
{
|
||||
mkString(((const std::string &) s).c_str());
|
||||
mkString(s.c_str());
|
||||
}
|
||||
|
||||
void mkPath(const SourcePath & path);
|
||||
|
@ -494,11 +500,11 @@ void Value::mkBlackhole()
|
|||
|
||||
#if HAVE_BOEHMGC
|
||||
typedef std::vector<Value *, traceable_allocator<Value *>> ValueVector;
|
||||
typedef std::map<Symbol, Value *, std::less<Symbol>, traceable_allocator<std::pair<const Symbol, Value *>>> ValueMap;
|
||||
typedef std::unordered_map<Symbol, Value *, std::hash<Symbol>, std::equal_to<Symbol>, traceable_allocator<std::pair<const Symbol, Value *>>> ValueMap;
|
||||
typedef std::map<Symbol, ValueVector, std::less<Symbol>, traceable_allocator<std::pair<const Symbol, ValueVector>>> ValueVectorMap;
|
||||
#else
|
||||
typedef std::vector<Value *> ValueVector;
|
||||
typedef std::map<Symbol, Value *> ValueMap;
|
||||
typedef std::unordered_map<Symbol, Value *> ValueMap;
|
||||
typedef std::map<Symbol, ValueVector> ValueVectorMap;
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue