From fa307875e961a616a049206645a651a76a050a79 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Fri, 11 Dec 2020 23:32:45 +0100 Subject: [PATCH 1/8] Introduce NormalType for the normal type of a Value This will be useful to abstract over the ValueType implementation details Make use of it already to replace the showType(ValueType) function --- src/libexpr/eval-cache.cc | 4 ++-- src/libexpr/eval.cc | 34 ++++++++++++++++------------------ src/libexpr/eval.hh | 2 +- src/libexpr/flake/flake.cc | 26 +++++++++++++------------- src/libexpr/value.hh | 36 ++++++++++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 34 deletions(-) diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index 7b025be23..a11327f77 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -513,7 +513,7 @@ std::string AttrCursor::getString() auto & v = forceValue(); if (v.type != tString && v.type != tPath) - throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type)); + throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.normalType())); return v.type == tString ? v.string.s : v.path; } @@ -548,7 +548,7 @@ string_t AttrCursor::getStringWithContext() else if (v.type == tPath) return {v.path, {}}; else - throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type)); + throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.normalType())); } bool AttrCursor::getBool() diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index c6f4d1716..48fe0bbda 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -165,25 +165,20 @@ const Value *getPrimOp(const Value &v) { return primOp; } - -string showType(ValueType type) +string showType(NormalType type) { switch (type) { - case tInt: return "an integer"; - case tBool: return "a Boolean"; - case tString: return "a string"; - case tPath: return "a path"; - case tNull: return "null"; - case tAttrs: return "a set"; - case tList1: case tList2: case tListN: return "a list"; - case tThunk: return "a thunk"; - case tApp: return "a function application"; - case tLambda: return "a function"; - case tBlackhole: return "a black hole"; - case tPrimOp: return "a built-in function"; - case tPrimOpApp: return "a partially applied built-in function"; - case tExternal: return "an external value"; - case tFloat: return "a float"; + case nInt: return "an integer"; + case nBool: return "a Boolean"; + case nString: return "a string"; + case nPath: return "a path"; + case nNull: return "null"; + case nAttrs: return "a set"; + case nList: return "a list"; + case nFunction: return "a function"; + case nExternal: return "an external value"; + case nFloat: return "a float"; + case nThunk: return "a thunk"; } abort(); } @@ -198,8 +193,11 @@ string showType(const Value & v) case tPrimOpApp: return fmt("the partially applied built-in function '%s'", string(getPrimOp(v)->primOp->name)); case tExternal: return v.external->showType(); + case tThunk: return "a thunk"; + case tApp: return "a function application"; + case tBlackhole: return "a black hole"; default: - return showType(v.type); + return showType(v.normalType()); } } diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 0e1f61baa..211529954 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -346,7 +346,7 @@ private: /* Return a string representing the type of the value `v'. */ -string showType(ValueType type); +string showType(NormalType type); string showType(const Value & v); /* Decode a context string ‘!!’ into a pair parseFlakeInputs( @@ -93,7 +93,7 @@ static std::map parseFlakeInputs( static FlakeInput parseFlakeInput(EvalState & state, const std::string & inputName, Value * value, const Pos & pos) { - expectType(state, tAttrs, *value, pos); + expectType(state, nAttrs, *value, pos); FlakeInput input; @@ -108,16 +108,16 @@ static FlakeInput parseFlakeInput(EvalState & state, for (nix::Attr attr : *(value->attrs)) { try { if (attr.name == sUrl) { - expectType(state, tString, *attr.value, *attr.pos); + expectType(state, nString, *attr.value, *attr.pos); url = attr.value->string.s; attrs.emplace("url", *url); } else if (attr.name == sFlake) { - expectType(state, tBool, *attr.value, *attr.pos); + expectType(state, nBool, *attr.value, *attr.pos); input.isFlake = attr.value->boolean; } else if (attr.name == sInputs) { input.overrides = parseFlakeInputs(state, attr.value, *attr.pos); } else if (attr.name == sFollows) { - expectType(state, tString, *attr.value, *attr.pos); + expectType(state, nString, *attr.value, *attr.pos); input.follows = parseInputPath(attr.value->string.s); } else { if (attr.value->type == tString) @@ -158,7 +158,7 @@ static std::map parseFlakeInputs( { std::map inputs; - expectType(state, tAttrs, *value, pos); + expectType(state, nAttrs, *value, pos); for (nix::Attr & inputAttr : *(*value).attrs) { inputs.emplace(inputAttr.name, @@ -199,10 +199,10 @@ static Flake getFlake( Value vInfo; state.evalFile(flakeFile, vInfo, true); // FIXME: symlink attack - expectType(state, tAttrs, vInfo, Pos(foFile, state.symbols.create(flakeFile), 0, 0)); + expectType(state, nAttrs, vInfo, Pos(foFile, state.symbols.create(flakeFile), 0, 0)); if (auto description = vInfo.attrs->get(state.sDescription)) { - expectType(state, tString, *description->value, *description->pos); + expectType(state, nString, *description->value, *description->pos); flake.description = description->value->string.s; } @@ -214,9 +214,9 @@ static Flake getFlake( auto sOutputs = state.symbols.create("outputs"); if (auto outputs = vInfo.attrs->get(sOutputs)) { - expectType(state, tLambda, *outputs->value, *outputs->pos); + expectType(state, nFunction, *outputs->value, *outputs->pos); - if (outputs->value->lambda.fun->matchAttrs) { + if (outputs->value->type == tLambda && outputs->value->lambda.fun->matchAttrs) { for (auto & formal : outputs->value->lambda.fun->formals->formals) { if (formal.name != state.sSelf) flake.inputs.emplace(formal.name, FlakeInput { @@ -231,7 +231,7 @@ static Flake getFlake( auto sNixConfig = state.symbols.create("nixConfig"); if (auto nixConfig = vInfo.attrs->get(sNixConfig)) { - expectType(state, tAttrs, *nixConfig->value, *nixConfig->pos); + expectType(state, nAttrs, *nixConfig->value, *nixConfig->pos); for (auto & setting : *nixConfig->value->attrs) { forceTrivialValue(state, *setting.value, *setting.pos); diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index fe11bb2ed..833af0f3d 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -29,6 +29,22 @@ typedef enum { tFloat } ValueType; +// This type abstracts over all actual value types in the language, +// grouping together implementation details like tList*, different function +// types, and types in non-normal form (so thunks and co.) +typedef enum { + nThunk, + nInt, + nFloat, + nBool, + nString, + nPath, + nNull, + nAttrs, + nList, + nFunction, + nExternal +} NormalType; class Bindings; struct Env; @@ -147,6 +163,26 @@ struct Value NixFloat fpoint; }; + // Returns the normal type of a Value. This only returns nThunk if the + // Value hasn't been forceValue'd + inline NormalType normalType() const + { + switch (type) { + case tInt: return nInt; + case tBool: return nBool; + case tString: return nString; + case tPath: return nPath; + case tNull: return nNull; + case tAttrs: return nAttrs; + case tList1: case tList2: case tListN: return nList; + case tLambda: case tPrimOp: case tPrimOpApp: return nFunction; + case tExternal: return nExternal; + case tFloat: return nFloat; + case tThunk: case tApp: case tBlackhole: return nThunk; + } + abort(); + } + bool isList() const { return type == tList1 || type == tList2 || type == tListN; From 9f056f7afdb85b8c3bd59638197e356f269129b2 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Sat, 12 Dec 2020 00:19:05 +0100 Subject: [PATCH 2/8] Introduce Value type setters and make use of them --- src/libexpr/attr-set.cc | 2 +- src/libexpr/eval-inline.hh | 4 ++-- src/libexpr/eval.cc | 24 ++++++++++++------------ src/libexpr/value.hh | 35 +++++++++++++++++++++++++++-------- src/nix/repl.cc | 2 +- 5 files changed, 43 insertions(+), 24 deletions(-) diff --git a/src/libexpr/attr-set.cc b/src/libexpr/attr-set.cc index b1d61a285..17886a426 100644 --- a/src/libexpr/attr-set.cc +++ b/src/libexpr/attr-set.cc @@ -25,7 +25,7 @@ void EvalState::mkAttrs(Value & v, size_t capacity) return; } clearValue(v); - v.type = tAttrs; + v.setAttrs(); v.attrs = allocBindings(capacity); nrAttrsets++; nrAttrsInAttrsets += capacity; diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index 30f6ec7db..a0fd9b569 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -36,11 +36,11 @@ void EvalState::forceValue(Value & v, const Pos & pos) Env * env = v.thunk.env; Expr * expr = v.thunk.expr; try { - v.type = tBlackhole; + v.setBlackhole(); //checkInterrupt(); expr->eval(*this, *env, v); } catch (...) { - v.type = tThunk; + v.setThunk(); v.thunk.env = env; v.thunk.expr = expr; throw; diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 48fe0bbda..f68828944 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -431,7 +431,7 @@ EvalState::EvalState(const Strings & _searchPath, ref store) } clearValue(vEmptySet); - vEmptySet.type = tAttrs; + vEmptySet.setAttrs(); vEmptySet.attrs = allocBindings(0); createBaseEnv(); @@ -548,7 +548,7 @@ Value * EvalState::addPrimOp(const string & name, the primop to a dummy value. */ if (arity == 0) { auto vPrimOp = allocValue(); - vPrimOp->type = tPrimOp; + vPrimOp->setPrimOp(); vPrimOp->primOp = new PrimOp { .fun = primOp, .arity = 1, .name = sym }; Value v; mkApp(v, *vPrimOp, *vPrimOp); @@ -556,7 +556,7 @@ Value * EvalState::addPrimOp(const string & name, } Value * v = allocValue(); - v->type = tPrimOp; + v->setPrimOp(); v->primOp = new PrimOp { .fun = primOp, .arity = arity, .name = sym }; staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl; baseEnv.values[baseEnvDispl++] = v; @@ -572,7 +572,7 @@ Value * EvalState::addPrimOp(PrimOp && primOp) if (primOp.arity == 0) { primOp.arity = 1; auto vPrimOp = allocValue(); - vPrimOp->type = tPrimOp; + vPrimOp->setPrimOp(); vPrimOp->primOp = new PrimOp(std::move(primOp)); Value v; mkApp(v, *vPrimOp, *vPrimOp); @@ -584,7 +584,7 @@ Value * EvalState::addPrimOp(PrimOp && primOp) primOp.name = symbols.create(std::string(primOp.name, 2)); Value * v = allocValue(); - v->type = tPrimOp; + v->setPrimOp(); v->primOp = new PrimOp(std::move(primOp)); staticBaseEnv.vars[envName] = baseEnvDispl; baseEnv.values[baseEnvDispl++] = v; @@ -714,7 +714,7 @@ void mkString(Value & v, const char * s) Value & mkString(Value & v, std::string_view s, const PathSet & context) { - v.type = tString; + v.setString(); v.string.s = dupStringWithLen(s.data(), s.size()); v.string.context = 0; if (!context.empty()) { @@ -794,11 +794,11 @@ void EvalState::mkList(Value & v, size_t size) { clearValue(v); if (size == 1) - v.type = tList1; + v.setList1(); else if (size == 2) - v.type = tList2; + v.setList2(); else { - v.type = tListN; + v.setListN(); v.bigList.size = size; v.bigList.elems = size ? (Value * *) allocBytes(size * sizeof(Value *)) : 0; } @@ -810,7 +810,7 @@ unsigned long nrThunks = 0; static inline void mkThunk(Value & v, Env & env, Expr * expr) { - v.type = tThunk; + v.setThunk(); v.thunk.env = &env; v.thunk.expr = expr; nrThunks++; @@ -1207,7 +1207,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v) void ExprLambda::eval(EvalState & state, Env & env, Value & v) { - v.type = tLambda; + v.setLambda(); v.lambda.env = &env; v.lambda.fun = this; } @@ -1252,7 +1252,7 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos) } else { Value * fun2 = allocValue(); *fun2 = fun; - v.type = tPrimOpApp; + v.setPrimOpApp(); v.primOpApp.left = fun2; v.primOpApp.right = &arg; } diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index 833af0f3d..0995dcd7b 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -107,6 +107,25 @@ std::ostream & operator << (std::ostream & str, const ExternalValueBase & v); struct Value { ValueType type; + + inline void setInt() { type = tInt; }; + inline void setBool() { type = tBool; }; + inline void setString() { type = tString; }; + inline void setPath() { type = tPath; }; + inline void setNull() { type = tNull; }; + inline void setAttrs() { type = tAttrs; }; + inline void setList1() { type = tList1; }; + inline void setList2() { type = tList2; }; + inline void setListN() { type = tListN; }; + inline void setThunk() { type = tThunk; }; + inline void setApp() { type = tApp; }; + inline void setLambda() { type = tLambda; }; + inline void setBlackhole() { type = tBlackhole; }; + inline void setPrimOp() { type = tPrimOp; }; + inline void setPrimOpApp() { type = tPrimOpApp; }; + inline void setExternal() { type = tExternal; }; + inline void setFloat() { type = tFloat; }; + union { NixInt integer; @@ -223,7 +242,7 @@ static inline void clearValue(Value & v) static inline void mkInt(Value & v, NixInt n) { clearValue(v); - v.type = tInt; + v.setInt(); v.integer = n; } @@ -231,7 +250,7 @@ static inline void mkInt(Value & v, NixInt n) static inline void mkFloat(Value & v, NixFloat n) { clearValue(v); - v.type = tFloat; + v.setFloat(); v.fpoint = n; } @@ -239,7 +258,7 @@ static inline void mkFloat(Value & v, NixFloat n) static inline void mkBool(Value & v, bool b) { clearValue(v); - v.type = tBool; + v.setBool(); v.boolean = b; } @@ -247,13 +266,13 @@ static inline void mkBool(Value & v, bool b) static inline void mkNull(Value & v) { clearValue(v); - v.type = tNull; + v.setNull(); } static inline void mkApp(Value & v, Value & left, Value & right) { - v.type = tApp; + v.setApp(); v.app.left = &left; v.app.right = &right; } @@ -261,7 +280,7 @@ static inline void mkApp(Value & v, Value & left, Value & right) static inline void mkPrimOpApp(Value & v, Value & left, Value & right) { - v.type = tPrimOpApp; + v.setPrimOpApp(); v.app.left = &left; v.app.right = &right; } @@ -269,7 +288,7 @@ static inline void mkPrimOpApp(Value & v, Value & left, Value & right) static inline void mkStringNoCopy(Value & v, const char * s) { - v.type = tString; + v.setString(); v.string.s = s; v.string.context = 0; } @@ -287,7 +306,7 @@ void mkString(Value & v, const char * s); static inline void mkPathNoCopy(Value & v, const char * s) { clearValue(v); - v.type = tPath; + v.setPath(); v.path = s; } diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 71794a309..3cee81b49 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -551,7 +551,7 @@ bool NixRepl::processLine(string line) { Expr * e = parseString(string(line, p + 1)); Value & v(*state->allocValue()); - v.type = tThunk; + v.setThunk(); v.thunk.env = env; v.thunk.expr = e; addVarToScope(state->symbols.create(name), v); From 22ead43a0b8f94f5a4fb64cff14bf6a2a35d671c Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Sat, 12 Dec 2020 02:09:10 +0100 Subject: [PATCH 3/8] Use Value::normalType on all forced values instead of Value::type --- src/libexpr/attr-path.cc | 2 +- src/libexpr/eval-cache.cc | 22 ++--- src/libexpr/eval-inline.hh | 4 +- src/libexpr/eval.cc | 112 +++++++++++++------------- src/libexpr/flake/flake.cc | 12 +-- src/libexpr/get-drvs.cc | 30 +++---- src/libexpr/primops.cc | 89 +++++++++----------- src/libexpr/primops/fetchMercurial.cc | 2 +- src/libexpr/primops/fetchTree.cc | 12 +-- src/libexpr/value-to-json.cc | 25 +++--- src/libexpr/value-to-xml.cc | 33 ++++---- src/nix-env/nix-env.cc | 16 ++-- src/nix/eval.cc | 4 +- src/nix/flake.cc | 2 +- src/nix/repl.cc | 47 +++++------ 15 files changed, 199 insertions(+), 213 deletions(-) diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index 83854df49..54e13e6a2 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -67,7 +67,7 @@ std::pair findAlongAttrPath(EvalState & state, const string & attr if (apType == apAttr) { - if (v->type != tAttrs) + if (v->normalType() != nAttrs) throw TypeError( "the expression selected by the selection path '%1%' should be a set but is %2%", attrPath, diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index a11327f77..3c97f1201 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -390,14 +390,14 @@ Value & AttrCursor::forceValue() } if (root->db && (!cachedValue || std::get_if(&cachedValue->second))) { - if (v.type == tString) + if (v.normalType() == nString) cachedValue = {root->db->setString(getKey(), v.string.s, v.string.context), string_t{v.string.s, {}}}; - else if (v.type == tPath) + else if (v.normalType() == nPath) cachedValue = {root->db->setString(getKey(), v.path), v.path}; - else if (v.type == tBool) + else if (v.normalType() == nBool) cachedValue = {root->db->setBool(getKey(), v.boolean), v.boolean}; - else if (v.type == tAttrs) + else if (v.normalType() == nAttrs) ; // FIXME: do something? else cachedValue = {root->db->setMisc(getKey()), misc_t()}; @@ -442,7 +442,7 @@ std::shared_ptr AttrCursor::maybeGetAttr(Symbol name, bool forceErro auto & v = forceValue(); - if (v.type != tAttrs) + if (v.normalType() != nAttrs) return nullptr; //throw TypeError("'%s' is not an attribute set", getAttrPathStr()); @@ -512,10 +512,10 @@ std::string AttrCursor::getString() auto & v = forceValue(); - if (v.type != tString && v.type != tPath) + if (v.normalType() != nString && v.normalType() != nPath) throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.normalType())); - return v.type == tString ? v.string.s : v.path; + return v.normalType() == nString ? v.string.s : v.path; } string_t AttrCursor::getStringWithContext() @@ -543,9 +543,9 @@ string_t AttrCursor::getStringWithContext() auto & v = forceValue(); - if (v.type == tString) + if (v.normalType() == nString) return {v.string.s, v.getContext()}; - else if (v.type == tPath) + else if (v.normalType() == nPath) return {v.path, {}}; else throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.normalType())); @@ -567,7 +567,7 @@ bool AttrCursor::getBool() auto & v = forceValue(); - if (v.type != tBool) + if (v.normalType() != nBool) throw TypeError("'%s' is not a Boolean", getAttrPathStr()); return v.boolean; @@ -589,7 +589,7 @@ std::vector AttrCursor::getAttrs() auto & v = forceValue(); - if (v.type != tAttrs) + if (v.normalType() != nAttrs) throw TypeError("'%s' is not an attribute set", getAttrPathStr()); std::vector attrs; diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index a0fd9b569..9b644d5cb 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -56,7 +56,7 @@ void EvalState::forceValue(Value & v, const Pos & pos) inline void EvalState::forceAttrs(Value & v) { forceValue(v); - if (v.type != tAttrs) + if (v.normalType() != nAttrs) throwTypeError("value is %1% while a set was expected", v); } @@ -64,7 +64,7 @@ inline void EvalState::forceAttrs(Value & v) inline void EvalState::forceAttrs(Value & v, const Pos & pos) { forceValue(v, pos); - if (v.type != tAttrs) + if (v.normalType() != nAttrs) throwTypeError(pos, "value is %1% while a set was expected", v); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index f68828944..f33426b59 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -947,7 +947,7 @@ inline bool EvalState::evalBool(Env & env, Expr * e) { Value v; e->eval(*this, env, v); - if (v.type != tBool) + if (v.normalType() != nBool) throwTypeError("value is %1% while a Boolean was expected", v); return v.boolean; } @@ -957,7 +957,7 @@ inline bool EvalState::evalBool(Env & env, Expr * e, const Pos & pos) { Value v; e->eval(*this, env, v); - if (v.type != tBool) + if (v.normalType() != nBool) throwTypeError(pos, "value is %1% while a Boolean was expected", v); return v.boolean; } @@ -966,7 +966,7 @@ inline bool EvalState::evalBool(Env & env, Expr * e, const Pos & pos) inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v) { e->eval(*this, env, v); - if (v.type != tAttrs) + if (v.normalType() != nAttrs) throwTypeError("value is %1% while a set was expected", v); } @@ -1066,7 +1066,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) Value nameVal; i.nameExpr->eval(state, *dynamicEnv, nameVal); state.forceValue(nameVal, i.pos); - if (nameVal.type == tNull) + if (nameVal.normalType() == nNull) continue; state.forceStringNoCtx(nameVal); Symbol nameSym = state.symbols.create(nameVal.string.s); @@ -1151,7 +1151,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) Symbol name = getName(i, state, env); if (def) { state.forceValue(*vAttrs, pos); - if (vAttrs->type != tAttrs || + if (vAttrs->normalType() != nAttrs || (j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) { def->eval(state, env, v); @@ -1191,7 +1191,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v) state.forceValue(*vAttrs); Bindings::iterator j; Symbol name = getName(i, state, env); - if (vAttrs->type != tAttrs || + if (vAttrs->normalType() != nAttrs || (j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) { mkBool(v, false); @@ -1269,7 +1269,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po return; } - if (fun.type == tAttrs) { + if (fun.normalType() == nAttrs) { auto found = fun.attrs->find(sFunctor); if (found != fun.attrs->end()) { /* fun may be allocated on the stack of the calling function, @@ -1368,7 +1368,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) { forceValue(fun); - if (fun.type == tAttrs) { + if (fun.normalType() == nAttrs) { auto found = fun.attrs->find(sFunctor); if (found != fun.attrs->end()) { Value * v = allocValue(); @@ -1562,7 +1562,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) NixFloat nf = 0; bool first = !forceString; - ValueType firstType = tString; + NormalType firstType = nString; for (auto & i : *es) { Value vTmp; @@ -1573,36 +1573,36 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) since paths are copied when they are used in a derivation), and none of the strings are allowed to have contexts. */ if (first) { - firstType = vTmp.type; + firstType = vTmp.normalType(); first = false; } - if (firstType == tInt) { - if (vTmp.type == tInt) { + if (firstType == nInt) { + if (vTmp.normalType() == nInt) { n += vTmp.integer; - } else if (vTmp.type == tFloat) { + } else if (vTmp.normalType() == nFloat) { // Upgrade the type from int to float; - firstType = tFloat; + firstType = nFloat; nf = n; nf += vTmp.fpoint; } else throwEvalError(pos, "cannot add %1% to an integer", showType(vTmp)); - } else if (firstType == tFloat) { - if (vTmp.type == tInt) { + } else if (firstType == nFloat) { + if (vTmp.normalType() == nInt) { nf += vTmp.integer; - } else if (vTmp.type == tFloat) { + } else if (vTmp.normalType() == nFloat) { nf += vTmp.fpoint; } else throwEvalError(pos, "cannot add %1% to a float", showType(vTmp)); } else - s << state.coerceToString(pos, vTmp, context, false, firstType == tString); + s << state.coerceToString(pos, vTmp, context, false, firstType == nString); } - if (firstType == tInt) + if (firstType == nInt) mkInt(v, n); - else if (firstType == tFloat) + else if (firstType == nFloat) mkFloat(v, nf); - else if (firstType == tPath) { + else if (firstType == nPath) { if (!context.empty()) throwEvalError(pos, "a string that refers to a store path cannot be appended to a path"); auto path = canonPath(s.str()); @@ -1629,7 +1629,7 @@ void EvalState::forceValueDeep(Value & v) forceValue(v); - if (v.type == tAttrs) { + if (v.normalType() == nAttrs) { for (auto & i : *v.attrs) try { recurse(*i.value); @@ -1652,7 +1652,7 @@ void EvalState::forceValueDeep(Value & v) NixInt EvalState::forceInt(Value & v, const Pos & pos) { forceValue(v, pos); - if (v.type != tInt) + if (v.normalType() != nInt) throwTypeError(pos, "value is %1% while an integer was expected", v); return v.integer; } @@ -1661,9 +1661,9 @@ NixInt EvalState::forceInt(Value & v, const Pos & pos) NixFloat EvalState::forceFloat(Value & v, const Pos & pos) { forceValue(v, pos); - if (v.type == tInt) + if (v.normalType() == nInt) return v.integer; - else if (v.type != tFloat) + else if (v.normalType() != nFloat) throwTypeError(pos, "value is %1% while a float was expected", v); return v.fpoint; } @@ -1672,7 +1672,7 @@ NixFloat EvalState::forceFloat(Value & v, const Pos & pos) bool EvalState::forceBool(Value & v, const Pos & pos) { forceValue(v, pos); - if (v.type != tBool) + if (v.normalType() != nBool) throwTypeError(pos, "value is %1% while a Boolean was expected", v); return v.boolean; } @@ -1680,14 +1680,14 @@ bool EvalState::forceBool(Value & v, const Pos & pos) bool EvalState::isFunctor(Value & fun) { - return fun.type == tAttrs && fun.attrs->find(sFunctor) != fun.attrs->end(); + return fun.normalType() == nAttrs && fun.attrs->find(sFunctor) != fun.attrs->end(); } void EvalState::forceFunction(Value & v, const Pos & pos) { forceValue(v, pos); - if (v.type != tLambda && v.type != tPrimOp && v.type != tPrimOpApp && !isFunctor(v)) + if (v.normalType() != nFunction && !isFunctor(v)) throwTypeError(pos, "value is %1% while a function was expected", v); } @@ -1695,7 +1695,7 @@ void EvalState::forceFunction(Value & v, const Pos & pos) string EvalState::forceString(Value & v, const Pos & pos) { forceValue(v, pos); - if (v.type != tString) { + if (v.normalType() != nString) { if (pos) throwTypeError(pos, "value is %1% while a string was expected", v); else @@ -1761,11 +1761,11 @@ string EvalState::forceStringNoCtx(Value & v, const Pos & pos) bool EvalState::isDerivation(Value & v) { - if (v.type != tAttrs) return false; + if (v.normalType() != nAttrs) return false; Bindings::iterator i = v.attrs->find(sType); if (i == v.attrs->end()) return false; forceValue(*i->value); - if (i->value->type != tString) return false; + if (i->value->normalType() != nString) return false; return strcmp(i->value->string.s, "derivation") == 0; } @@ -1790,17 +1790,17 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, string s; - if (v.type == tString) { + if (v.normalType() == nString) { copyContext(v, context); return v.string.s; } - if (v.type == tPath) { + if (v.normalType() == nPath) { Path path(canonPath(v.path)); return copyToStore ? copyPathToStore(context, path) : path; } - if (v.type == tAttrs) { + if (v.normalType() == nAttrs) { auto maybeString = tryAttrsToString(pos, v, context, coerceMore, copyToStore); if (maybeString) { return *maybeString; @@ -1810,18 +1810,18 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, return coerceToString(pos, *i->value, context, coerceMore, copyToStore); } - if (v.type == tExternal) + if (v.normalType() == nExternal) return v.external->coerceToString(pos, context, coerceMore, copyToStore); if (coerceMore) { /* Note that `false' is represented as an empty string for shell scripting convenience, just like `null'. */ - if (v.type == tBool && v.boolean) return "1"; - if (v.type == tBool && !v.boolean) return ""; - if (v.type == tInt) return std::to_string(v.integer); - if (v.type == tFloat) return std::to_string(v.fpoint); - if (v.type == tNull) return ""; + if (v.normalType() == nBool && v.boolean) return "1"; + if (v.normalType() == nBool && !v.boolean) return ""; + if (v.normalType() == nInt) return std::to_string(v.integer); + if (v.normalType() == nFloat) return std::to_string(v.fpoint); + if (v.normalType() == nNull) return ""; if (v.isList()) { string result; @@ -1884,40 +1884,38 @@ bool EvalState::eqValues(Value & v1, Value & v2) if (&v1 == &v2) return true; // Special case type-compatibility between float and int - if (v1.type == tInt && v2.type == tFloat) + if (v1.normalType() == nInt && v2.normalType() == nFloat) return v1.integer == v2.fpoint; - if (v1.type == tFloat && v2.type == tInt) + if (v1.normalType() == nFloat && v2.normalType() == nInt) return v1.fpoint == v2.integer; // All other types are not compatible with each other. - if (v1.type != v2.type) return false; + if (v1.normalType() != v2.normalType()) return false; - switch (v1.type) { + switch (v1.normalType()) { - case tInt: + case nInt: return v1.integer == v2.integer; - case tBool: + case nBool: return v1.boolean == v2.boolean; - case tString: + case nString: return strcmp(v1.string.s, v2.string.s) == 0; - case tPath: + case nPath: return strcmp(v1.path, v2.path) == 0; - case tNull: + case nNull: return true; - case tList1: - case tList2: - case tListN: + case nList: if (v1.listSize() != v2.listSize()) return false; for (size_t n = 0; n < v1.listSize(); ++n) if (!eqValues(*v1.listElems()[n], *v2.listElems()[n])) return false; return true; - case tAttrs: { + case nAttrs: { /* If both sets denote a derivation (type = "derivation"), then compare their outPaths. */ if (isDerivation(v1) && isDerivation(v2)) { @@ -1939,15 +1937,13 @@ bool EvalState::eqValues(Value & v1, Value & v2) } /* Functions are incomparable. */ - case tLambda: - case tPrimOp: - case tPrimOpApp: + case nFunction: return false; - case tExternal: + case nExternal: return *v1.external == *v2.external; - case tFloat: + case nFloat: return v1.fpoint == v2.fpoint; default: diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 881b1b4e5..c126b2c40 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -120,7 +120,7 @@ static FlakeInput parseFlakeInput(EvalState & state, expectType(state, nString, *attr.value, *attr.pos); input.follows = parseInputPath(attr.value->string.s); } else { - if (attr.value->type == tString) + if (attr.value->normalType() == nString) attrs.emplace(attr.name, attr.value->string.s); else throw TypeError("flake input attribute '%s' is %s while a string is expected", @@ -235,17 +235,17 @@ static Flake getFlake( for (auto & setting : *nixConfig->value->attrs) { forceTrivialValue(state, *setting.value, *setting.pos); - if (setting.value->type == tString) + if (setting.value->normalType() == nString) flake.config.settings.insert({setting.name, state.forceStringNoCtx(*setting.value, *setting.pos)}); - else if (setting.value->type == tInt) + else if (setting.value->normalType() == nInt) flake.config.settings.insert({setting.name, state.forceInt(*setting.value, *setting.pos)}); - else if (setting.value->type == tBool) + else if (setting.value->normalType() == nBool) flake.config.settings.insert({setting.name, state.forceBool(*setting.value, *setting.pos)}); - else if (setting.value->isList()) { + else if (setting.value->normalType() == nList) { std::vector ss; for (unsigned int n = 0; n < setting.value->listSize(); ++n) { auto elem = setting.value->listElems()[n]; - if (elem->type != tString) + if (elem->normalType() != nString) throw TypeError("list element in flake configuration setting '%s' is %s while a string is expected", setting.name, showType(*setting.value)); ss.push_back(state.forceStringNoCtx(*elem, *setting.pos)); diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 91916e8bf..93788273f 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -128,7 +128,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall) if (!outTI->isList()) throw errMsg; Outputs result; for (auto i = outTI->listElems(); i != outTI->listElems() + outTI->listSize(); ++i) { - if ((*i)->type != tString) throw errMsg; + if ((*i)->normalType() != nString) throw errMsg; auto out = outputs.find((*i)->string.s); if (out == outputs.end()) throw errMsg; result.insert(*out); @@ -172,20 +172,20 @@ StringSet DrvInfo::queryMetaNames() bool DrvInfo::checkMeta(Value & v) { state->forceValue(v); - if (v.isList()) { + if (v.normalType() == nList) { for (unsigned int n = 0; n < v.listSize(); ++n) if (!checkMeta(*v.listElems()[n])) return false; return true; } - else if (v.type == tAttrs) { + else if (v.normalType() == nAttrs) { Bindings::iterator i = v.attrs->find(state->sOutPath); if (i != v.attrs->end()) return false; for (auto & i : *v.attrs) if (!checkMeta(*i.value)) return false; return true; } - else return v.type == tInt || v.type == tBool || v.type == tString || - v.type == tFloat; + else return v.normalType() == nInt || v.normalType() == nBool || v.normalType() == nString || + v.normalType() == nFloat; } @@ -201,7 +201,7 @@ Value * DrvInfo::queryMeta(const string & name) string DrvInfo::queryMetaString(const string & name) { Value * v = queryMeta(name); - if (!v || v->type != tString) return ""; + if (!v || v->normalType() != nString) return ""; return v->string.s; } @@ -210,8 +210,8 @@ NixInt DrvInfo::queryMetaInt(const string & name, NixInt def) { Value * v = queryMeta(name); if (!v) return def; - if (v->type == tInt) return v->integer; - if (v->type == tString) { + if (v->normalType() == nInt) return v->integer; + if (v->normalType() == nString) { /* Backwards compatibility with before we had support for integer meta fields. */ NixInt n; @@ -224,8 +224,8 @@ NixFloat DrvInfo::queryMetaFloat(const string & name, NixFloat def) { Value * v = queryMeta(name); if (!v) return def; - if (v->type == tFloat) return v->fpoint; - if (v->type == tString) { + if (v->normalType() == nFloat) return v->fpoint; + if (v->normalType() == nString) { /* Backwards compatibility with before we had support for float meta fields. */ NixFloat n; @@ -239,8 +239,8 @@ bool DrvInfo::queryMetaBool(const string & name, bool def) { Value * v = queryMeta(name); if (!v) return def; - if (v->type == tBool) return v->boolean; - if (v->type == tString) { + if (v->normalType() == nBool) return v->boolean; + if (v->normalType() == nString) { /* Backwards compatibility with before we had support for Boolean meta fields. */ if (strcmp(v->string.s, "true") == 0) return true; @@ -331,7 +331,7 @@ static void getDerivations(EvalState & state, Value & vIn, /* Process the expression. */ if (!getDerivation(state, v, pathPrefix, drvs, done, ignoreAssertionFailures)) ; - else if (v.type == tAttrs) { + else if (v.normalType() == nAttrs) { /* !!! undocumented hackery to support combining channels in nix-env.cc. */ @@ -353,7 +353,7 @@ static void getDerivations(EvalState & state, Value & vIn, /* If the value of this attribute is itself a set, should we recurse into it? => Only if it has a `recurseForDerivations = true' attribute. */ - if (i->value->type == tAttrs) { + if (i->value->normalType() == nAttrs) { Bindings::iterator j = i->value->attrs->find(state.sRecurseForDerivations); if (j != i->value->attrs->end() && state.forceBool(*j->value, *j->pos)) getDerivations(state, *i->value, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures); @@ -362,7 +362,7 @@ static void getDerivations(EvalState & state, Value & vIn, } } - else if (v.isList()) { + else if (v.normalType() == nList) { for (unsigned int n = 0; n < v.listSize(); ++n) { string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str()); if (getDerivation(state, *v.listElems()[n], pathPrefix2, drvs, done, ignoreAssertionFailures)) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 41f06c219..d501f7482 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -356,24 +356,20 @@ static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Valu { state.forceValue(*args[0], pos); string t; - switch (args[0]->type) { - case tInt: t = "int"; break; - case tBool: t = "bool"; break; - case tString: t = "string"; break; - case tPath: t = "path"; break; - case tNull: t = "null"; break; - case tAttrs: t = "set"; break; - case tList1: case tList2: case tListN: t = "list"; break; - case tLambda: - case tPrimOp: - case tPrimOpApp: - t = "lambda"; - break; - case tExternal: + switch (args[0]->normalType()) { + case nInt: t = "int"; break; + case nBool: t = "bool"; break; + case nString: t = "string"; break; + case nPath: t = "path"; break; + case nNull: t = "null"; break; + case nAttrs: t = "set"; break; + case nList: t = "list"; break; + case nFunction: t = "lambda"; break; + case nExternal: t = args[0]->external->typeOf(); break; - case tFloat: t = "float"; break; - default: abort(); + case nFloat: t = "float"; break; + case nThunk: abort(); } mkString(v, state.symbols.create(t)); } @@ -393,7 +389,7 @@ static RegisterPrimOp primop_typeOf({ static void prim_isNull(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->type == tNull); + mkBool(v, args[0]->normalType() == nNull); } static RegisterPrimOp primop_isNull({ @@ -413,18 +409,7 @@ static RegisterPrimOp primop_isNull({ static void prim_isFunction(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - bool res; - switch (args[0]->type) { - case tLambda: - case tPrimOp: - case tPrimOpApp: - res = true; - break; - default: - res = false; - break; - } - mkBool(v, res); + mkBool(v, args[0]->normalType() == nFunction); } static RegisterPrimOp primop_isFunction({ @@ -440,7 +425,7 @@ static RegisterPrimOp primop_isFunction({ static void prim_isInt(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->type == tInt); + mkBool(v, args[0]->normalType() == nInt); } static RegisterPrimOp primop_isInt({ @@ -456,7 +441,7 @@ static RegisterPrimOp primop_isInt({ static void prim_isFloat(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->type == tFloat); + mkBool(v, args[0]->normalType() == nFloat); } static RegisterPrimOp primop_isFloat({ @@ -472,7 +457,7 @@ static RegisterPrimOp primop_isFloat({ static void prim_isString(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->type == tString); + mkBool(v, args[0]->normalType() == nString); } static RegisterPrimOp primop_isString({ @@ -488,7 +473,7 @@ static RegisterPrimOp primop_isString({ static void prim_isBool(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->type == tBool); + mkBool(v, args[0]->normalType() == nBool); } static RegisterPrimOp primop_isBool({ @@ -504,7 +489,7 @@ static RegisterPrimOp primop_isBool({ static void prim_isPath(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->type == tPath); + mkBool(v, args[0]->normalType() == nPath); } static RegisterPrimOp primop_isPath({ @@ -520,20 +505,20 @@ struct CompareValues { bool operator () (const Value * v1, const Value * v2) const { - if (v1->type == tFloat && v2->type == tInt) + if (v1->normalType() == nFloat && v2->normalType() == nInt) return v1->fpoint < v2->integer; - if (v1->type == tInt && v2->type == tFloat) + if (v1->normalType() == nInt && v2->normalType() == nFloat) return v1->integer < v2->fpoint; - if (v1->type != v2->type) + if (v1->normalType() != v2->normalType()) throw EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2)); - switch (v1->type) { - case tInt: + switch (v1->normalType()) { + case nInt: return v1->integer < v2->integer; - case tFloat: + case nFloat: return v1->fpoint < v2->fpoint; - case tString: + case nString: return strcmp(v1->string.s, v2->string.s) < 0; - case tPath: + case nPath: return strcmp(v1->path, v2->path) < 0; default: throw EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2)); @@ -777,7 +762,7 @@ static RegisterPrimOp primop_deepSeq({ static void prim_trace(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - if (args[0]->type == tString) + if (args[0]->normalType() == nString) printError("trace: %1%", args[0]->string.s); else printError("trace: %1%", *args[0]); @@ -902,7 +887,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * if (ignoreNulls) { state.forceValue(*i->value, pos); - if (i->value->type == tNull) continue; + if (i->value->normalType() == nNull) continue; } if (i->name == state.sContentAddressed) { @@ -1308,7 +1293,7 @@ static void prim_dirOf(EvalState & state, const Pos & pos, Value * * args, Value { PathSet context; Path dir = dirOf(state.coerceToString(pos, *args[0], context, false, false)); - if (args[0]->type == tPath) mkPath(v, dir.c_str()); else mkString(v, dir, context); + if (args[0]->normalType() == nPath) mkPath(v, dir.c_str()); else mkString(v, dir, context); } static RegisterPrimOp primop_dirOf({ @@ -1808,7 +1793,7 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args }); state.forceValue(*args[0], pos); - if (args[0]->type != tLambda) + if (args[0]->normalType() != nFunction) throw TypeError({ .hint = hintfmt( "first argument in call to 'filterSource' is not a function but %1%", @@ -2074,7 +2059,7 @@ static RegisterPrimOp primop_hasAttr({ static void prim_isAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->type == tAttrs); + mkBool(v, args[0]->normalType() == nAttrs); } static RegisterPrimOp primop_isAttrs({ @@ -2337,7 +2322,7 @@ static RegisterPrimOp primop_mapAttrs({ static void prim_isList(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->isList()); + mkBool(v, args[0]->normalType() == nList); } static RegisterPrimOp primop_isList({ @@ -2831,7 +2816,7 @@ static void prim_add(EvalState & state, const Pos & pos, Value * * args, Value & { state.forceValue(*args[0], pos); state.forceValue(*args[1], pos); - if (args[0]->type == tFloat || args[1]->type == tFloat) + if (args[0]->normalType() == nFloat || args[1]->normalType() == nFloat) mkFloat(v, state.forceFloat(*args[0], pos) + state.forceFloat(*args[1], pos)); else mkInt(v, state.forceInt(*args[0], pos) + state.forceInt(*args[1], pos)); @@ -2850,7 +2835,7 @@ static void prim_sub(EvalState & state, const Pos & pos, Value * * args, Value & { state.forceValue(*args[0], pos); state.forceValue(*args[1], pos); - if (args[0]->type == tFloat || args[1]->type == tFloat) + if (args[0]->normalType() == nFloat || args[1]->normalType() == nFloat) mkFloat(v, state.forceFloat(*args[0], pos) - state.forceFloat(*args[1], pos)); else mkInt(v, state.forceInt(*args[0], pos) - state.forceInt(*args[1], pos)); @@ -2869,7 +2854,7 @@ static void prim_mul(EvalState & state, const Pos & pos, Value * * args, Value & { state.forceValue(*args[0], pos); state.forceValue(*args[1], pos); - if (args[0]->type == tFloat || args[1]->type == tFloat) + if (args[0]->normalType() == nFloat || args[1]->normalType() == nFloat) mkFloat(v, state.forceFloat(*args[0], pos) * state.forceFloat(*args[1], pos)); else mkInt(v, state.forceInt(*args[0], pos) * state.forceInt(*args[1], pos)); @@ -2896,7 +2881,7 @@ static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value & .errPos = pos }); - if (args[0]->type == tFloat || args[1]->type == tFloat) { + if (args[0]->normalType() == nFloat || args[1]->normalType() == nFloat) { mkFloat(v, state.forceFloat(*args[0], pos) / state.forceFloat(*args[1], pos)); } else { NixInt i1 = state.forceInt(*args[0], pos); diff --git a/src/libexpr/primops/fetchMercurial.cc b/src/libexpr/primops/fetchMercurial.cc index a77035c16..2461ebc99 100644 --- a/src/libexpr/primops/fetchMercurial.cc +++ b/src/libexpr/primops/fetchMercurial.cc @@ -17,7 +17,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar state.forceValue(*args[0]); - if (args[0]->type == tAttrs) { + if (args[0]->normalType() == nAttrs) { state.forceAttrs(*args[0], pos); diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index d094edf92..6d93e1dc2 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -85,25 +85,25 @@ static void fetchTree( state.forceValue(*args[0]); - if (args[0]->type == tAttrs) { + if (args[0]->normalType() == nAttrs) { state.forceAttrs(*args[0], pos); fetchers::Attrs attrs; for (auto & attr : *args[0]->attrs) { state.forceValue(*attr.value); - if (attr.value->type == tPath || attr.value->type == tString) + if (attr.value->normalType() == nPath || attr.value->normalType() == nString) addURI( state, attrs, attr.name, state.coerceToString(*attr.pos, *attr.value, context, false, false) ); - else if (attr.value->type == tString) + else if (attr.value->normalType() == nString) addURI(state, attrs, attr.name, attr.value->string.s); - else if (attr.value->type == tBool) + else if (attr.value->normalType() == nBool) attrs.emplace(attr.name, Explicit{attr.value->boolean}); - else if (attr.value->type == tInt) + else if (attr.value->normalType() == nInt) attrs.emplace(attr.name, attr.value->integer); else throw TypeError("fetchTree argument '%s' is %s while a string, Boolean or integer is expected", @@ -163,7 +163,7 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, state.forceValue(*args[0]); - if (args[0]->type == tAttrs) { + if (args[0]->normalType() == nAttrs) { state.forceAttrs(*args[0], pos); diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc index 6ec8315ba..b5f4c8654 100644 --- a/src/libexpr/value-to-json.cc +++ b/src/libexpr/value-to-json.cc @@ -16,30 +16,30 @@ void printValueAsJSON(EvalState & state, bool strict, if (strict) state.forceValue(v); - switch (v.type) { + switch (v.normalType()) { - case tInt: + case nInt: out.write(v.integer); break; - case tBool: + case nBool: out.write(v.boolean); break; - case tString: + case nString: copyContext(v, context); out.write(v.string.s); break; - case tPath: + case nPath: out.write(state.copyPathToStore(context, v.path)); break; - case tNull: + case nNull: out.write(nullptr); break; - case tAttrs: { + case nAttrs: { auto maybeString = state.tryAttrsToString(noPos, v, context, false, false); if (maybeString) { out.write(*maybeString); @@ -61,7 +61,7 @@ void printValueAsJSON(EvalState & state, bool strict, break; } - case tList1: case tList2: case tListN: { + case nList: { auto list(out.list()); for (unsigned int n = 0; n < v.listSize(); ++n) { auto placeholder(list.placeholder()); @@ -70,15 +70,18 @@ void printValueAsJSON(EvalState & state, bool strict, break; } - case tExternal: + case nExternal: v.external->printValueAsJSON(state, strict, out, context); break; - case tFloat: + case nFloat: out.write(v.fpoint); break; - default: + case nThunk: + throw TypeError("cannot convert %1% to JSON", showType(v)); + + case nFunction: throw TypeError("cannot convert %1% to JSON", showType(v)); } } diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc index 1f0b1541d..26be07cff 100644 --- a/src/libexpr/value-to-xml.cc +++ b/src/libexpr/value-to-xml.cc @@ -58,31 +58,31 @@ static void printValueAsXML(EvalState & state, bool strict, bool location, if (strict) state.forceValue(v); - switch (v.type) { + switch (v.normalType()) { - case tInt: + case nInt: doc.writeEmptyElement("int", singletonAttrs("value", (format("%1%") % v.integer).str())); break; - case tBool: + case nBool: doc.writeEmptyElement("bool", singletonAttrs("value", v.boolean ? "true" : "false")); break; - case tString: + case nString: /* !!! show the context? */ copyContext(v, context); doc.writeEmptyElement("string", singletonAttrs("value", v.string.s)); break; - case tPath: + case nPath: doc.writeEmptyElement("path", singletonAttrs("value", v.path)); break; - case tNull: + case nNull: doc.writeEmptyElement("null"); break; - case tAttrs: + case nAttrs: if (state.isDerivation(v)) { XMLAttrs xmlAttrs; @@ -92,14 +92,14 @@ static void printValueAsXML(EvalState & state, bool strict, bool location, a = v.attrs->find(state.sDrvPath); if (a != v.attrs->end()) { if (strict) state.forceValue(*a->value); - if (a->value->type == tString) + if (a->value->normalType() == nString) xmlAttrs["drvPath"] = drvPath = a->value->string.s; } a = v.attrs->find(state.sOutPath); if (a != v.attrs->end()) { if (strict) state.forceValue(*a->value); - if (a->value->type == tString) + if (a->value->normalType() == nString) xmlAttrs["outPath"] = a->value->string.s; } @@ -118,14 +118,19 @@ static void printValueAsXML(EvalState & state, bool strict, bool location, break; - case tList1: case tList2: case tListN: { + case nList: { XMLOpenElement _(doc, "list"); for (unsigned int n = 0; n < v.listSize(); ++n) printValueAsXML(state, strict, location, *v.listElems()[n], doc, context, drvsSeen); break; } - case tLambda: { + case nFunction: { + if (!v.isLambda()) { + // FIXME: Serialize primops and primopapps + doc.writeEmptyElement("unevaluated"); + break; + } XMLAttrs xmlAttrs; if (location) posToXML(xmlAttrs, v.lambda.fun->pos); XMLOpenElement _(doc, "function", xmlAttrs); @@ -143,15 +148,15 @@ static void printValueAsXML(EvalState & state, bool strict, bool location, break; } - case tExternal: + case nExternal: v.external->printValueAsXML(state, strict, location, doc, context, drvsSeen); break; - case tFloat: + case nFloat: doc.writeEmptyElement("float", singletonAttrs("value", (format("%1%") % v.fpoint).str())); break; - default: + case nThunk: doc.writeEmptyElement("unevaluated"); } } diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index a4b5c9e2c..404fd5111 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -1138,38 +1138,38 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) i.queryName(), j) }); else { - if (v->type == tString) { + if (v->normalType() == nString) { attrs2["type"] = "string"; attrs2["value"] = v->string.s; xml.writeEmptyElement("meta", attrs2); - } else if (v->type == tInt) { + } else if (v->normalType() == nInt) { attrs2["type"] = "int"; attrs2["value"] = (format("%1%") % v->integer).str(); xml.writeEmptyElement("meta", attrs2); - } else if (v->type == tFloat) { + } else if (v->normalType() == nFloat) { attrs2["type"] = "float"; attrs2["value"] = (format("%1%") % v->fpoint).str(); xml.writeEmptyElement("meta", attrs2); - } else if (v->type == tBool) { + } else if (v->normalType() == nBool) { attrs2["type"] = "bool"; attrs2["value"] = v->boolean ? "true" : "false"; xml.writeEmptyElement("meta", attrs2); - } else if (v->isList()) { + } else if (v->normalType() == nList) { attrs2["type"] = "strings"; XMLOpenElement m(xml, "meta", attrs2); for (unsigned int j = 0; j < v->listSize(); ++j) { - if (v->listElems()[j]->type != tString) continue; + if (v->listElems()[j]->normalType() != nString) continue; XMLAttrs attrs3; attrs3["value"] = v->listElems()[j]->string.s; xml.writeEmptyElement("string", attrs3); } - } else if (v->type == tAttrs) { + } else if (v->normalType() == nAttrs) { attrs2["type"] = "strings"; XMLOpenElement m(xml, "meta", attrs2); Bindings & attrs = *v->attrs; for (auto &i : attrs) { Attr & a(*attrs.find(i.name)); - if(a.value->type != tString) continue; + if(a.value->normalType() != nString) continue; XMLAttrs attrs3; attrs3["type"] = i.name; attrs3["value"] = a.value->string.s; diff --git a/src/nix/eval.cc b/src/nix/eval.cc index 0f02919de..bba3b1bc6 100644 --- a/src/nix/eval.cc +++ b/src/nix/eval.cc @@ -97,10 +97,10 @@ struct CmdEval : MixJSON, InstallableCommand recurse = [&](Value & v, const Pos & pos, const Path & path) { state->forceValue(v); - if (v.type == tString) + if (v.normalType() == nString) // FIXME: disallow strings with contexts? writeFile(path, v.string.s); - else if (v.type == tAttrs) { + else if (v.normalType() == nAttrs) { if (mkdir(path.c_str(), 0777) == -1) throw SysError("creating directory '%s'", path); for (auto & attr : *v.attrs) diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 7a7c71676..80b050091 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -279,7 +279,7 @@ struct CmdFlakeCheck : FlakeCommand if (v.type == tLambda) { if (!v.lambda.fun->matchAttrs || !v.lambda.fun->formals->ellipsis) throw Error("module must match an open attribute set ('{ config, ... }')"); - } else if (v.type == tAttrs) { + } else if (v.normalType() == nAttrs) { for (auto & attr : *v.attrs) try { state->forceValue(*attr.value, *attr.pos); diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 3cee81b49..56184efb9 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -446,7 +446,7 @@ bool NixRepl::processLine(string line) Pos pos; - if (v.type == tPath || v.type == tString) { + if (v.normalType() == nPath || v.normalType() == nString) { PathSet context; auto filename = state->coerceToString(noPos, v, context); pos.file = state->symbols.create(filename); @@ -669,31 +669,31 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m state->forceValue(v); - switch (v.type) { + switch (v.normalType()) { - case tInt: + case nInt: str << ANSI_CYAN << v.integer << ANSI_NORMAL; break; - case tBool: + case nBool: str << ANSI_CYAN << (v.boolean ? "true" : "false") << ANSI_NORMAL; break; - case tString: + case nString: str << ANSI_YELLOW; printStringValue(str, v.string.s); str << ANSI_NORMAL; break; - case tPath: + case nPath: str << ANSI_GREEN << v.path << ANSI_NORMAL; // !!! escaping? break; - case tNull: + case nNull: str << ANSI_CYAN "null" ANSI_NORMAL; break; - case tAttrs: { + case nAttrs: { seen.insert(&v); bool isDrv = state->isDerivation(v); @@ -738,9 +738,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m break; } - case tList1: - case tList2: - case tListN: + case nList: seen.insert(&v); str << "[ "; @@ -761,22 +759,21 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m str << "]"; break; - case tLambda: { - std::ostringstream s; - s << v.lambda.fun->pos; - str << ANSI_BLUE "«lambda @ " << filterANSIEscapes(s.str()) << "»" ANSI_NORMAL; - break; - } - - case tPrimOp: - str << ANSI_MAGENTA "«primop»" ANSI_NORMAL; + case nFunction: + if (v.type == tLambda) { + std::ostringstream s; + s << v.lambda.fun->pos; + str << ANSI_BLUE "«lambda @ " << filterANSIEscapes(s.str()) << "»" ANSI_NORMAL; + } else if (v.type == tPrimOp) { + str << ANSI_MAGENTA "«primop»" ANSI_NORMAL; + } else if (v.type == tPrimOpApp) { + str << ANSI_BLUE "«primop-app»" ANSI_NORMAL; + } else { + abort(); + } break; - case tPrimOpApp: - str << ANSI_BLUE "«primop-app»" ANSI_NORMAL; - break; - - case tFloat: + case nFloat: str << v.fpoint; break; From bf9890396731a2bbe4f04a49684dee463d818906 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Sat, 12 Dec 2020 02:15:11 +0100 Subject: [PATCH 4/8] Add ValueType checking functions for types that have the same NormalType --- src/libexpr/eval-inline.hh | 6 +++--- src/libexpr/eval.cc | 20 ++++++++++---------- src/libexpr/flake/flake.cc | 4 ++-- src/libexpr/primops.cc | 6 +++--- src/libexpr/value.hh | 14 ++++++++++++++ src/nix/flake.cc | 6 +++--- src/nix/main.cc | 2 +- src/nix/repl.cc | 8 ++++---- 8 files changed, 40 insertions(+), 26 deletions(-) diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index 9b644d5cb..8c40c2565 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -32,7 +32,7 @@ LocalNoInlineNoReturn(void throwTypeError(const Pos & pos, const char * s, const void EvalState::forceValue(Value & v, const Pos & pos) { - if (v.type == tThunk) { + if (v.isThunk()) { Env * env = v.thunk.env; Expr * expr = v.thunk.expr; try { @@ -46,9 +46,9 @@ void EvalState::forceValue(Value & v, const Pos & pos) throw; } } - else if (v.type == tApp) + else if (v.isApp()) callFunction(*v.app.left, *v.app.right, v, noPos); - else if (v.type == tBlackhole) + else if (v.isBlackhole()) throwEvalError(pos, "infinite recursion encountered"); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index f33426b59..5f9d19b8d 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -158,10 +158,10 @@ std::ostream & operator << (std::ostream & str, const Value & v) const Value *getPrimOp(const Value &v) { const Value * primOp = &v; - while (primOp->type == tPrimOpApp) { + while (primOp->isPrimOpApp()) { primOp = primOp->primOpApp.left; } - assert(primOp->type == tPrimOp); + assert(primOp->isPrimOp()); return primOp; } @@ -601,9 +601,9 @@ Value & EvalState::getBuiltin(const string & name) std::optional EvalState::getDoc(Value & v) { - if (v.type == tPrimOp || v.type == tPrimOpApp) { + if (v.isPrimOp() || v.isPrimOpApp()) { auto v2 = &v; - while (v2->type == tPrimOpApp) + while (v2->isPrimOpApp()) v2 = v2->primOpApp.left; if (v2->primOp->doc) return Doc { @@ -1227,11 +1227,11 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos) /* Figure out the number of arguments still needed. */ size_t argsDone = 0; Value * primOp = &fun; - while (primOp->type == tPrimOpApp) { + while (primOp->isPrimOpApp()) { argsDone++; primOp = primOp->primOpApp.left; } - assert(primOp->type == tPrimOp); + assert(primOp->isPrimOp()); auto arity = primOp->primOp->arity; auto argsLeft = arity - argsDone; @@ -1242,7 +1242,7 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos) Value * vArgs[arity]; auto n = arity - 1; vArgs[n--] = &arg; - for (Value * arg = &fun; arg->type == tPrimOpApp; arg = arg->primOpApp.left) + for (Value * arg = &fun; arg->isPrimOpApp(); arg = arg->primOpApp.left) vArgs[n--] = arg->primOpApp.right; /* And call the primop. */ @@ -1264,7 +1264,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po forceValue(fun, pos); - if (fun.type == tPrimOp || fun.type == tPrimOpApp) { + if (fun.isPrimOp() || fun.isPrimOpApp()) { callPrimOp(fun, arg, v, pos); return; } @@ -1285,7 +1285,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po } } - if (fun.type != tLambda) + if (!fun.isLambda()) throwTypeError(pos, "attempt to call something which is not a function but %1%", fun); ExprLambda & lambda(*fun.lambda.fun); @@ -1378,7 +1378,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) } } - if (fun.type != tLambda || !fun.lambda.fun->matchAttrs) { + if (!fun.isLambda() || !fun.lambda.fun->matchAttrs) { res = fun; return; } diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index c126b2c40..2f9658ab8 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -73,7 +73,7 @@ static std::tuple fetchOrSubstituteTree( static void forceTrivialValue(EvalState & state, Value & value, const Pos & pos) { - if (value.type == tThunk && value.isTrivial()) + if (value.isThunk() && value.isTrivial()) state.forceValue(value, pos); } @@ -216,7 +216,7 @@ static Flake getFlake( if (auto outputs = vInfo.attrs->get(sOutputs)) { expectType(state, nFunction, *outputs->value, *outputs->pos); - if (outputs->value->type == tLambda && outputs->value->lambda.fun->matchAttrs) { + if (outputs->value->isLambda() && outputs->value->lambda.fun->matchAttrs) { for (auto & formal : outputs->value->lambda.fun->formals->formals) { if (formal.name != state.sSelf) flake.inputs.emplace(formal.name, FlakeInput { diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index d501f7482..f6ca612f4 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -2239,11 +2239,11 @@ static RegisterPrimOp primop_catAttrs({ static void prim_functionArgs(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - if (args[0]->type == tPrimOpApp || args[0]->type == tPrimOp) { + if (args[0]->isPrimOpApp() || args[0]->isPrimOp()) { state.mkAttrs(v, 0); return; } - if (args[0]->type != tLambda) + if (!args[0]->isLambda()) throw TypeError({ .hint = hintfmt("'functionArgs' requires a function"), .errPos = pos @@ -2674,7 +2674,7 @@ static void prim_sort(EvalState & state, const Pos & pos, Value * * args, Value auto comparator = [&](Value * a, Value * b) { /* Optimization: if the comparator is lessThan, bypass callFunction. */ - if (args[0]->type == tPrimOp && args[0]->primOp->fun == prim_lessThan) + if (args[0]->isPrimOp() && args[0]->primOp->fun == prim_lessThan) return CompareValues()(a, b); Value vTmp1, vTmp2; diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index 0995dcd7b..e743da9c3 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -126,6 +126,20 @@ struct Value inline void setExternal() { type = tExternal; }; inline void setFloat() { type = tFloat; }; + // Functions needed to distinguish the type + // These should be removed eventually, by putting the functionality that's + // needed by callers into methods of this type + + // normalType() == nThunk + inline bool isThunk() const { return type == tThunk; }; + inline bool isApp() const { return type == tApp; }; + inline bool isBlackhole() const { return type == tBlackhole; }; + + // normalType() == nFunction + inline bool isLambda() const { return type == tLambda; }; + inline bool isPrimOp() const { return type == tPrimOp; }; + inline bool isPrimOpApp() const { return type == tPrimOpApp; }; + union { NixInt integer; diff --git a/src/nix/flake.cc b/src/nix/flake.cc index 80b050091..e4da0348c 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -260,7 +260,7 @@ struct CmdFlakeCheck : FlakeCommand auto checkOverlay = [&](const std::string & attrPath, Value & v, const Pos & pos) { try { state->forceValue(v, pos); - if (v.type != tLambda || v.lambda.fun->matchAttrs || std::string(v.lambda.fun->arg) != "final") + if (!v.isLambda() || v.lambda.fun->matchAttrs || std::string(v.lambda.fun->arg) != "final") throw Error("overlay does not take an argument named 'final'"); auto body = dynamic_cast(v.lambda.fun->body); if (!body || body->matchAttrs || std::string(body->arg) != "prev") @@ -276,7 +276,7 @@ struct CmdFlakeCheck : FlakeCommand auto checkModule = [&](const std::string & attrPath, Value & v, const Pos & pos) { try { state->forceValue(v, pos); - if (v.type == tLambda) { + if (v.isLambda()) { if (!v.lambda.fun->matchAttrs || !v.lambda.fun->formals->ellipsis) throw Error("module must match an open attribute set ('{ config, ... }')"); } else if (v.normalType() == nAttrs) { @@ -371,7 +371,7 @@ struct CmdFlakeCheck : FlakeCommand auto checkBundler = [&](const std::string & attrPath, Value & v, const Pos & pos) { try { state->forceValue(v, pos); - if (v.type != tLambda) + if (!v.isLambda()) throw Error("bundler must be a function"); if (!v.lambda.fun->formals || v.lambda.fun->formals->argNames.find(state->symbols.create("program")) == v.lambda.fun->formals->argNames.end() || diff --git a/src/nix/main.cc b/src/nix/main.cc index 27b1d7257..e7a15dec9 100644 --- a/src/nix/main.cc +++ b/src/nix/main.cc @@ -272,7 +272,7 @@ void mainWrapped(int argc, char * * argv) auto builtins = state.baseEnv.values[0]->attrs; for (auto & builtin : *builtins) { auto b = nlohmann::json::object(); - if (builtin.value->type != tPrimOp) continue; + if (!builtin.value->isPrimOp()) continue; auto primOp = builtin.value->primOp; if (!primOp->doc) continue; b["arity"] = primOp->arity; diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 56184efb9..047e2dc59 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -450,7 +450,7 @@ bool NixRepl::processLine(string line) PathSet context; auto filename = state->coerceToString(noPos, v, context); pos.file = state->symbols.create(filename); - } else if (v.type == tLambda) { + } else if (v.isLambda()) { pos = v.lambda.fun->pos; } else { // assume it's a derivation @@ -760,13 +760,13 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m break; case nFunction: - if (v.type == tLambda) { + if (v.isLambda()) { std::ostringstream s; s << v.lambda.fun->pos; str << ANSI_BLUE "«lambda @ " << filterANSIEscapes(s.str()) << "»" ANSI_NORMAL; - } else if (v.type == tPrimOp) { + } else if (v.isPrimOp()) { str << ANSI_MAGENTA "«primop»" ANSI_NORMAL; - } else if (v.type == tPrimOpApp) { + } else if (v.isPrimOpApp()) { str << ANSI_BLUE "«primop-app»" ANSI_NORMAL; } else { abort(); From 730b152b190135adef2f53c7a80cfd1111d37ead Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Sat, 12 Dec 2020 02:22:58 +0100 Subject: [PATCH 5/8] Make Value::type private This is an implementation detail and shouldn't be used. Use normalType() and the various is functions instead --- src/libexpr/eval.cc | 2 +- src/libexpr/value.hh | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 5f9d19b8d..1d11039ad 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -68,7 +68,7 @@ RootValue allocRootValue(Value * v) } -static void printValue(std::ostream & str, std::set & active, const Value & v) +void printValue(std::ostream & str, std::set & active, const Value & v) { checkInterrupt(); diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index e743da9c3..4050d7e4b 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -106,8 +106,14 @@ std::ostream & operator << (std::ostream & str, const ExternalValueBase & v); struct Value { +private: ValueType type; +friend std::string showType(const Value & v); +friend void printValue(std::ostream & str, std::set & active, const Value & v); + +public: + inline void setInt() { type = tInt; }; inline void setBool() { type = tBool; }; inline void setString() { type = tString; }; From d67e02919c7f941615407dfd14cfdab6a28c4c26 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Thu, 17 Dec 2020 14:42:52 +0100 Subject: [PATCH 6/8] Rename ValueType -> InternalType, NormalType -> ValueType And Value::type to Value::internalType, such that type() can be used in the next commit to get the new ValueType --- src/libexpr/eval.cc | 16 +++++----- src/libexpr/eval.hh | 2 +- src/libexpr/flake/flake.cc | 2 +- src/libexpr/value.hh | 64 +++++++++++++++++++------------------- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 1d11039ad..e14eb01c7 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -77,7 +77,7 @@ void printValue(std::ostream & str, std::set & active, const Valu return; } - switch (v.type) { + switch (v.internalType) { case tInt: str << v.integer; break; @@ -165,7 +165,7 @@ const Value *getPrimOp(const Value &v) { return primOp; } -string showType(NormalType type) +string showType(ValueType type) { switch (type) { case nInt: return "an integer"; @@ -186,7 +186,7 @@ string showType(NormalType type) string showType(const Value & v) { - switch (v.type) { + switch (v.internalType) { case tString: return v.string.context ? "a string with context" : "a string"; case tPrimOp: return fmt("the built-in function '%s'", string(v.primOp->name)); @@ -205,9 +205,9 @@ string showType(const Value & v) bool Value::isTrivial() const { return - type != tApp - && type != tPrimOpApp - && (type != tThunk + internalType != tApp + && internalType != tPrimOpApp + && (internalType != tThunk || (dynamic_cast(thunk.expr) && ((ExprAttrs *) thunk.expr)->dynamicAttrs.empty()) || dynamic_cast(thunk.expr) @@ -1562,7 +1562,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) NixFloat nf = 0; bool first = !forceString; - NormalType firstType = nString; + ValueType firstType = nString; for (auto & i : *es) { Value vTmp; @@ -1728,7 +1728,7 @@ void copyContext(const Value & v, PathSet & context) std::vector> Value::getContext() { std::vector> res; - assert(type == tString); + assert(internalType == tString); if (string.context) for (const char * * p = string.context; *p; ++p) res.push_back(decodeContext(*p)); diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh index 211529954..0e1f61baa 100644 --- a/src/libexpr/eval.hh +++ b/src/libexpr/eval.hh @@ -346,7 +346,7 @@ private: /* Return a string representing the type of the value `v'. */ -string showType(NormalType type); +string showType(ValueType type); string showType(const Value & v); /* Decode a context string ‘!!’ into a pair & active, const Value & v); public: - inline void setInt() { type = tInt; }; - inline void setBool() { type = tBool; }; - inline void setString() { type = tString; }; - inline void setPath() { type = tPath; }; - inline void setNull() { type = tNull; }; - inline void setAttrs() { type = tAttrs; }; - inline void setList1() { type = tList1; }; - inline void setList2() { type = tList2; }; - inline void setListN() { type = tListN; }; - inline void setThunk() { type = tThunk; }; - inline void setApp() { type = tApp; }; - inline void setLambda() { type = tLambda; }; - inline void setBlackhole() { type = tBlackhole; }; - inline void setPrimOp() { type = tPrimOp; }; - inline void setPrimOpApp() { type = tPrimOpApp; }; - inline void setExternal() { type = tExternal; }; - inline void setFloat() { type = tFloat; }; + inline void setInt() { internalType = tInt; }; + inline void setBool() { internalType = tBool; }; + inline void setString() { internalType = tString; }; + inline void setPath() { internalType = tPath; }; + inline void setNull() { internalType = tNull; }; + inline void setAttrs() { internalType = tAttrs; }; + inline void setList1() { internalType = tList1; }; + inline void setList2() { internalType = tList2; }; + inline void setListN() { internalType = tListN; }; + inline void setThunk() { internalType = tThunk; }; + inline void setApp() { internalType = tApp; }; + inline void setLambda() { internalType = tLambda; }; + inline void setBlackhole() { internalType = tBlackhole; }; + inline void setPrimOp() { internalType = tPrimOp; }; + inline void setPrimOpApp() { internalType = tPrimOpApp; }; + inline void setExternal() { internalType = tExternal; }; + inline void setFloat() { internalType = tFloat; }; // Functions needed to distinguish the type // These should be removed eventually, by putting the functionality that's // needed by callers into methods of this type // normalType() == nThunk - inline bool isThunk() const { return type == tThunk; }; - inline bool isApp() const { return type == tApp; }; - inline bool isBlackhole() const { return type == tBlackhole; }; + inline bool isThunk() const { return internalType == tThunk; }; + inline bool isApp() const { return internalType == tApp; }; + inline bool isBlackhole() const { return internalType == tBlackhole; }; // normalType() == nFunction - inline bool isLambda() const { return type == tLambda; }; - inline bool isPrimOp() const { return type == tPrimOp; }; - inline bool isPrimOpApp() const { return type == tPrimOpApp; }; + inline bool isLambda() const { return internalType == tLambda; }; + inline bool isPrimOp() const { return internalType == tPrimOp; }; + inline bool isPrimOpApp() const { return internalType == tPrimOpApp; }; union { @@ -204,9 +204,9 @@ public: // Returns the normal type of a Value. This only returns nThunk if the // Value hasn't been forceValue'd - inline NormalType normalType() const + inline ValueType normalType() const { - switch (type) { + switch (internalType) { case tInt: return nInt; case tBool: return nBool; case tString: return nString; @@ -224,22 +224,22 @@ public: bool isList() const { - return type == tList1 || type == tList2 || type == tListN; + return internalType == tList1 || internalType == tList2 || internalType == tListN; } Value * * listElems() { - return type == tList1 || type == tList2 ? smallList : bigList.elems; + return internalType == tList1 || internalType == tList2 ? smallList : bigList.elems; } const Value * const * listElems() const { - return type == tList1 || type == tList2 ? smallList : bigList.elems; + return internalType == tList1 || internalType == tList2 ? smallList : bigList.elems; } size_t listSize() const { - return type == tList1 ? 1 : type == tList2 ? 2 : bigList.size; + return internalType == tList1 ? 1 : internalType == tList2 ? 2 : bigList.size; } /* Check whether forcing this value requires a trivial amount of From 12e65078ef5c511196c9e48f7fdf71f6c0e5c89f Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Thu, 17 Dec 2020 14:45:45 +0100 Subject: [PATCH 7/8] Rename Value::normalType() -> Value::type() --- src/libexpr/attr-path.cc | 2 +- src/libexpr/eval-cache.cc | 26 +++++----- src/libexpr/eval-inline.hh | 4 +- src/libexpr/eval.cc | 74 +++++++++++++-------------- src/libexpr/flake/flake.cc | 16 +++--- src/libexpr/get-drvs.cc | 30 +++++------ src/libexpr/primops.cc | 44 ++++++++-------- src/libexpr/primops/fetchMercurial.cc | 2 +- src/libexpr/primops/fetchTree.cc | 12 ++--- src/libexpr/value-to-json.cc | 2 +- src/libexpr/value-to-xml.cc | 6 +-- src/libexpr/value.hh | 6 +-- src/nix-env/nix-env.cc | 16 +++--- src/nix/eval.cc | 4 +- src/nix/flake.cc | 2 +- src/nix/repl.cc | 4 +- 16 files changed, 125 insertions(+), 125 deletions(-) diff --git a/src/libexpr/attr-path.cc b/src/libexpr/attr-path.cc index 54e13e6a2..2d37dcb7e 100644 --- a/src/libexpr/attr-path.cc +++ b/src/libexpr/attr-path.cc @@ -67,7 +67,7 @@ std::pair findAlongAttrPath(EvalState & state, const string & attr if (apType == apAttr) { - if (v->normalType() != nAttrs) + if (v->type() != nAttrs) throw TypeError( "the expression selected by the selection path '%1%' should be a set but is %2%", attrPath, diff --git a/src/libexpr/eval-cache.cc b/src/libexpr/eval-cache.cc index 3c97f1201..75e9af787 100644 --- a/src/libexpr/eval-cache.cc +++ b/src/libexpr/eval-cache.cc @@ -390,14 +390,14 @@ Value & AttrCursor::forceValue() } if (root->db && (!cachedValue || std::get_if(&cachedValue->second))) { - if (v.normalType() == nString) + if (v.type() == nString) cachedValue = {root->db->setString(getKey(), v.string.s, v.string.context), string_t{v.string.s, {}}}; - else if (v.normalType() == nPath) + else if (v.type() == nPath) cachedValue = {root->db->setString(getKey(), v.path), v.path}; - else if (v.normalType() == nBool) + else if (v.type() == nBool) cachedValue = {root->db->setBool(getKey(), v.boolean), v.boolean}; - else if (v.normalType() == nAttrs) + else if (v.type() == nAttrs) ; // FIXME: do something? else cachedValue = {root->db->setMisc(getKey()), misc_t()}; @@ -442,7 +442,7 @@ std::shared_ptr AttrCursor::maybeGetAttr(Symbol name, bool forceErro auto & v = forceValue(); - if (v.normalType() != nAttrs) + if (v.type() != nAttrs) return nullptr; //throw TypeError("'%s' is not an attribute set", getAttrPathStr()); @@ -512,10 +512,10 @@ std::string AttrCursor::getString() auto & v = forceValue(); - if (v.normalType() != nString && v.normalType() != nPath) - throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.normalType())); + if (v.type() != nString && v.type() != nPath) + throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type())); - return v.normalType() == nString ? v.string.s : v.path; + return v.type() == nString ? v.string.s : v.path; } string_t AttrCursor::getStringWithContext() @@ -543,12 +543,12 @@ string_t AttrCursor::getStringWithContext() auto & v = forceValue(); - if (v.normalType() == nString) + if (v.type() == nString) return {v.string.s, v.getContext()}; - else if (v.normalType() == nPath) + else if (v.type() == nPath) return {v.path, {}}; else - throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.normalType())); + throw TypeError("'%s' is not a string but %s", getAttrPathStr(), showType(v.type())); } bool AttrCursor::getBool() @@ -567,7 +567,7 @@ bool AttrCursor::getBool() auto & v = forceValue(); - if (v.normalType() != nBool) + if (v.type() != nBool) throw TypeError("'%s' is not a Boolean", getAttrPathStr()); return v.boolean; @@ -589,7 +589,7 @@ std::vector AttrCursor::getAttrs() auto & v = forceValue(); - if (v.normalType() != nAttrs) + if (v.type() != nAttrs) throw TypeError("'%s' is not an attribute set", getAttrPathStr()); std::vector attrs; diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index 8c40c2565..e56ce261c 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -56,7 +56,7 @@ void EvalState::forceValue(Value & v, const Pos & pos) inline void EvalState::forceAttrs(Value & v) { forceValue(v); - if (v.normalType() != nAttrs) + if (v.type() != nAttrs) throwTypeError("value is %1% while a set was expected", v); } @@ -64,7 +64,7 @@ inline void EvalState::forceAttrs(Value & v) inline void EvalState::forceAttrs(Value & v, const Pos & pos) { forceValue(v, pos); - if (v.normalType() != nAttrs) + if (v.type() != nAttrs) throwTypeError(pos, "value is %1% while a set was expected", v); } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index e14eb01c7..2f8d6d259 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -197,7 +197,7 @@ string showType(const Value & v) case tApp: return "a function application"; case tBlackhole: return "a black hole"; default: - return showType(v.normalType()); + return showType(v.type()); } } @@ -947,7 +947,7 @@ inline bool EvalState::evalBool(Env & env, Expr * e) { Value v; e->eval(*this, env, v); - if (v.normalType() != nBool) + if (v.type() != nBool) throwTypeError("value is %1% while a Boolean was expected", v); return v.boolean; } @@ -957,7 +957,7 @@ inline bool EvalState::evalBool(Env & env, Expr * e, const Pos & pos) { Value v; e->eval(*this, env, v); - if (v.normalType() != nBool) + if (v.type() != nBool) throwTypeError(pos, "value is %1% while a Boolean was expected", v); return v.boolean; } @@ -966,7 +966,7 @@ inline bool EvalState::evalBool(Env & env, Expr * e, const Pos & pos) inline void EvalState::evalAttrs(Env & env, Expr * e, Value & v) { e->eval(*this, env, v); - if (v.normalType() != nAttrs) + if (v.type() != nAttrs) throwTypeError("value is %1% while a set was expected", v); } @@ -1066,7 +1066,7 @@ void ExprAttrs::eval(EvalState & state, Env & env, Value & v) Value nameVal; i.nameExpr->eval(state, *dynamicEnv, nameVal); state.forceValue(nameVal, i.pos); - if (nameVal.normalType() == nNull) + if (nameVal.type() == nNull) continue; state.forceStringNoCtx(nameVal); Symbol nameSym = state.symbols.create(nameVal.string.s); @@ -1151,7 +1151,7 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v) Symbol name = getName(i, state, env); if (def) { state.forceValue(*vAttrs, pos); - if (vAttrs->normalType() != nAttrs || + if (vAttrs->type() != nAttrs || (j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) { def->eval(state, env, v); @@ -1191,7 +1191,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v) state.forceValue(*vAttrs); Bindings::iterator j; Symbol name = getName(i, state, env); - if (vAttrs->normalType() != nAttrs || + if (vAttrs->type() != nAttrs || (j = vAttrs->attrs->find(name)) == vAttrs->attrs->end()) { mkBool(v, false); @@ -1269,7 +1269,7 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po return; } - if (fun.normalType() == nAttrs) { + if (fun.type() == nAttrs) { auto found = fun.attrs->find(sFunctor); if (found != fun.attrs->end()) { /* fun may be allocated on the stack of the calling function, @@ -1368,7 +1368,7 @@ void EvalState::autoCallFunction(Bindings & args, Value & fun, Value & res) { forceValue(fun); - if (fun.normalType() == nAttrs) { + if (fun.type() == nAttrs) { auto found = fun.attrs->find(sFunctor); if (found != fun.attrs->end()) { Value * v = allocValue(); @@ -1573,14 +1573,14 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) since paths are copied when they are used in a derivation), and none of the strings are allowed to have contexts. */ if (first) { - firstType = vTmp.normalType(); + firstType = vTmp.type(); first = false; } if (firstType == nInt) { - if (vTmp.normalType() == nInt) { + if (vTmp.type() == nInt) { n += vTmp.integer; - } else if (vTmp.normalType() == nFloat) { + } else if (vTmp.type() == nFloat) { // Upgrade the type from int to float; firstType = nFloat; nf = n; @@ -1588,9 +1588,9 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v) } else throwEvalError(pos, "cannot add %1% to an integer", showType(vTmp)); } else if (firstType == nFloat) { - if (vTmp.normalType() == nInt) { + if (vTmp.type() == nInt) { nf += vTmp.integer; - } else if (vTmp.normalType() == nFloat) { + } else if (vTmp.type() == nFloat) { nf += vTmp.fpoint; } else throwEvalError(pos, "cannot add %1% to a float", showType(vTmp)); @@ -1629,7 +1629,7 @@ void EvalState::forceValueDeep(Value & v) forceValue(v); - if (v.normalType() == nAttrs) { + if (v.type() == nAttrs) { for (auto & i : *v.attrs) try { recurse(*i.value); @@ -1652,7 +1652,7 @@ void EvalState::forceValueDeep(Value & v) NixInt EvalState::forceInt(Value & v, const Pos & pos) { forceValue(v, pos); - if (v.normalType() != nInt) + if (v.type() != nInt) throwTypeError(pos, "value is %1% while an integer was expected", v); return v.integer; } @@ -1661,9 +1661,9 @@ NixInt EvalState::forceInt(Value & v, const Pos & pos) NixFloat EvalState::forceFloat(Value & v, const Pos & pos) { forceValue(v, pos); - if (v.normalType() == nInt) + if (v.type() == nInt) return v.integer; - else if (v.normalType() != nFloat) + else if (v.type() != nFloat) throwTypeError(pos, "value is %1% while a float was expected", v); return v.fpoint; } @@ -1672,7 +1672,7 @@ NixFloat EvalState::forceFloat(Value & v, const Pos & pos) bool EvalState::forceBool(Value & v, const Pos & pos) { forceValue(v, pos); - if (v.normalType() != nBool) + if (v.type() != nBool) throwTypeError(pos, "value is %1% while a Boolean was expected", v); return v.boolean; } @@ -1680,14 +1680,14 @@ bool EvalState::forceBool(Value & v, const Pos & pos) bool EvalState::isFunctor(Value & fun) { - return fun.normalType() == nAttrs && fun.attrs->find(sFunctor) != fun.attrs->end(); + return fun.type() == nAttrs && fun.attrs->find(sFunctor) != fun.attrs->end(); } void EvalState::forceFunction(Value & v, const Pos & pos) { forceValue(v, pos); - if (v.normalType() != nFunction && !isFunctor(v)) + if (v.type() != nFunction && !isFunctor(v)) throwTypeError(pos, "value is %1% while a function was expected", v); } @@ -1695,7 +1695,7 @@ void EvalState::forceFunction(Value & v, const Pos & pos) string EvalState::forceString(Value & v, const Pos & pos) { forceValue(v, pos); - if (v.normalType() != nString) { + if (v.type() != nString) { if (pos) throwTypeError(pos, "value is %1% while a string was expected", v); else @@ -1761,11 +1761,11 @@ string EvalState::forceStringNoCtx(Value & v, const Pos & pos) bool EvalState::isDerivation(Value & v) { - if (v.normalType() != nAttrs) return false; + if (v.type() != nAttrs) return false; Bindings::iterator i = v.attrs->find(sType); if (i == v.attrs->end()) return false; forceValue(*i->value); - if (i->value->normalType() != nString) return false; + if (i->value->type() != nString) return false; return strcmp(i->value->string.s, "derivation") == 0; } @@ -1790,17 +1790,17 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, string s; - if (v.normalType() == nString) { + if (v.type() == nString) { copyContext(v, context); return v.string.s; } - if (v.normalType() == nPath) { + if (v.type() == nPath) { Path path(canonPath(v.path)); return copyToStore ? copyPathToStore(context, path) : path; } - if (v.normalType() == nAttrs) { + if (v.type() == nAttrs) { auto maybeString = tryAttrsToString(pos, v, context, coerceMore, copyToStore); if (maybeString) { return *maybeString; @@ -1810,18 +1810,18 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, return coerceToString(pos, *i->value, context, coerceMore, copyToStore); } - if (v.normalType() == nExternal) + if (v.type() == nExternal) return v.external->coerceToString(pos, context, coerceMore, copyToStore); if (coerceMore) { /* Note that `false' is represented as an empty string for shell scripting convenience, just like `null'. */ - if (v.normalType() == nBool && v.boolean) return "1"; - if (v.normalType() == nBool && !v.boolean) return ""; - if (v.normalType() == nInt) return std::to_string(v.integer); - if (v.normalType() == nFloat) return std::to_string(v.fpoint); - if (v.normalType() == nNull) return ""; + 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() == nFloat) return std::to_string(v.fpoint); + if (v.type() == nNull) return ""; if (v.isList()) { string result; @@ -1884,15 +1884,15 @@ bool EvalState::eqValues(Value & v1, Value & v2) if (&v1 == &v2) return true; // Special case type-compatibility between float and int - if (v1.normalType() == nInt && v2.normalType() == nFloat) + if (v1.type() == nInt && v2.type() == nFloat) return v1.integer == v2.fpoint; - if (v1.normalType() == nFloat && v2.normalType() == nInt) + if (v1.type() == nFloat && v2.type() == nInt) return v1.fpoint == v2.integer; // All other types are not compatible with each other. - if (v1.normalType() != v2.normalType()) return false; + if (v1.type() != v2.type()) return false; - switch (v1.normalType()) { + switch (v1.type()) { case nInt: return v1.integer == v2.integer; diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc index 987e7e24b..4f021570c 100644 --- a/src/libexpr/flake/flake.cc +++ b/src/libexpr/flake/flake.cc @@ -82,9 +82,9 @@ static void expectType(EvalState & state, ValueType type, Value & value, const Pos & pos) { forceTrivialValue(state, value, pos); - if (value.normalType() != type) + if (value.type() != type) throw Error("expected %s but got %s at %s", - showType(type), showType(value.normalType()), pos); + showType(type), showType(value.type()), pos); } static std::map parseFlakeInputs( @@ -120,7 +120,7 @@ static FlakeInput parseFlakeInput(EvalState & state, expectType(state, nString, *attr.value, *attr.pos); input.follows = parseInputPath(attr.value->string.s); } else { - if (attr.value->normalType() == nString) + if (attr.value->type() == nString) attrs.emplace(attr.name, attr.value->string.s); else throw TypeError("flake input attribute '%s' is %s while a string is expected", @@ -235,17 +235,17 @@ static Flake getFlake( for (auto & setting : *nixConfig->value->attrs) { forceTrivialValue(state, *setting.value, *setting.pos); - if (setting.value->normalType() == nString) + if (setting.value->type() == nString) flake.config.settings.insert({setting.name, state.forceStringNoCtx(*setting.value, *setting.pos)}); - else if (setting.value->normalType() == nInt) + else if (setting.value->type() == nInt) flake.config.settings.insert({setting.name, state.forceInt(*setting.value, *setting.pos)}); - else if (setting.value->normalType() == nBool) + else if (setting.value->type() == nBool) flake.config.settings.insert({setting.name, state.forceBool(*setting.value, *setting.pos)}); - else if (setting.value->normalType() == nList) { + else if (setting.value->type() == nList) { std::vector ss; for (unsigned int n = 0; n < setting.value->listSize(); ++n) { auto elem = setting.value->listElems()[n]; - if (elem->normalType() != nString) + if (elem->type() != nString) throw TypeError("list element in flake configuration setting '%s' is %s while a string is expected", setting.name, showType(*setting.value)); ss.push_back(state.forceStringNoCtx(*elem, *setting.pos)); diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index 93788273f..32c115c12 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -128,7 +128,7 @@ DrvInfo::Outputs DrvInfo::queryOutputs(bool onlyOutputsToInstall) if (!outTI->isList()) throw errMsg; Outputs result; for (auto i = outTI->listElems(); i != outTI->listElems() + outTI->listSize(); ++i) { - if ((*i)->normalType() != nString) throw errMsg; + if ((*i)->type() != nString) throw errMsg; auto out = outputs.find((*i)->string.s); if (out == outputs.end()) throw errMsg; result.insert(*out); @@ -172,20 +172,20 @@ StringSet DrvInfo::queryMetaNames() bool DrvInfo::checkMeta(Value & v) { state->forceValue(v); - if (v.normalType() == nList) { + if (v.type() == nList) { for (unsigned int n = 0; n < v.listSize(); ++n) if (!checkMeta(*v.listElems()[n])) return false; return true; } - else if (v.normalType() == nAttrs) { + else if (v.type() == nAttrs) { Bindings::iterator i = v.attrs->find(state->sOutPath); if (i != v.attrs->end()) return false; for (auto & i : *v.attrs) if (!checkMeta(*i.value)) return false; return true; } - else return v.normalType() == nInt || v.normalType() == nBool || v.normalType() == nString || - v.normalType() == nFloat; + else return v.type() == nInt || v.type() == nBool || v.type() == nString || + v.type() == nFloat; } @@ -201,7 +201,7 @@ Value * DrvInfo::queryMeta(const string & name) string DrvInfo::queryMetaString(const string & name) { Value * v = queryMeta(name); - if (!v || v->normalType() != nString) return ""; + if (!v || v->type() != nString) return ""; return v->string.s; } @@ -210,8 +210,8 @@ NixInt DrvInfo::queryMetaInt(const string & name, NixInt def) { Value * v = queryMeta(name); if (!v) return def; - if (v->normalType() == nInt) return v->integer; - if (v->normalType() == nString) { + if (v->type() == nInt) return v->integer; + if (v->type() == nString) { /* Backwards compatibility with before we had support for integer meta fields. */ NixInt n; @@ -224,8 +224,8 @@ NixFloat DrvInfo::queryMetaFloat(const string & name, NixFloat def) { Value * v = queryMeta(name); if (!v) return def; - if (v->normalType() == nFloat) return v->fpoint; - if (v->normalType() == nString) { + if (v->type() == nFloat) return v->fpoint; + if (v->type() == nString) { /* Backwards compatibility with before we had support for float meta fields. */ NixFloat n; @@ -239,8 +239,8 @@ bool DrvInfo::queryMetaBool(const string & name, bool def) { Value * v = queryMeta(name); if (!v) return def; - if (v->normalType() == nBool) return v->boolean; - if (v->normalType() == nString) { + if (v->type() == nBool) return v->boolean; + if (v->type() == nString) { /* Backwards compatibility with before we had support for Boolean meta fields. */ if (strcmp(v->string.s, "true") == 0) return true; @@ -331,7 +331,7 @@ static void getDerivations(EvalState & state, Value & vIn, /* Process the expression. */ if (!getDerivation(state, v, pathPrefix, drvs, done, ignoreAssertionFailures)) ; - else if (v.normalType() == nAttrs) { + else if (v.type() == nAttrs) { /* !!! undocumented hackery to support combining channels in nix-env.cc. */ @@ -353,7 +353,7 @@ static void getDerivations(EvalState & state, Value & vIn, /* If the value of this attribute is itself a set, should we recurse into it? => Only if it has a `recurseForDerivations = true' attribute. */ - if (i->value->normalType() == nAttrs) { + if (i->value->type() == nAttrs) { Bindings::iterator j = i->value->attrs->find(state.sRecurseForDerivations); if (j != i->value->attrs->end() && state.forceBool(*j->value, *j->pos)) getDerivations(state, *i->value, pathPrefix2, autoArgs, drvs, done, ignoreAssertionFailures); @@ -362,7 +362,7 @@ static void getDerivations(EvalState & state, Value & vIn, } } - else if (v.normalType() == nList) { + else if (v.type() == nList) { for (unsigned int n = 0; n < v.listSize(); ++n) { string pathPrefix2 = addToPath(pathPrefix, (format("%1%") % n).str()); if (getDerivation(state, *v.listElems()[n], pathPrefix2, drvs, done, ignoreAssertionFailures)) diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index f6ca612f4..4106f1ec8 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -356,7 +356,7 @@ static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Valu { state.forceValue(*args[0], pos); string t; - switch (args[0]->normalType()) { + switch (args[0]->type()) { case nInt: t = "int"; break; case nBool: t = "bool"; break; case nString: t = "string"; break; @@ -389,7 +389,7 @@ static RegisterPrimOp primop_typeOf({ static void prim_isNull(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->normalType() == nNull); + mkBool(v, args[0]->type() == nNull); } static RegisterPrimOp primop_isNull({ @@ -409,7 +409,7 @@ static RegisterPrimOp primop_isNull({ static void prim_isFunction(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->normalType() == nFunction); + mkBool(v, args[0]->type() == nFunction); } static RegisterPrimOp primop_isFunction({ @@ -425,7 +425,7 @@ static RegisterPrimOp primop_isFunction({ static void prim_isInt(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->normalType() == nInt); + mkBool(v, args[0]->type() == nInt); } static RegisterPrimOp primop_isInt({ @@ -441,7 +441,7 @@ static RegisterPrimOp primop_isInt({ static void prim_isFloat(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->normalType() == nFloat); + mkBool(v, args[0]->type() == nFloat); } static RegisterPrimOp primop_isFloat({ @@ -457,7 +457,7 @@ static RegisterPrimOp primop_isFloat({ static void prim_isString(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->normalType() == nString); + mkBool(v, args[0]->type() == nString); } static RegisterPrimOp primop_isString({ @@ -473,7 +473,7 @@ static RegisterPrimOp primop_isString({ static void prim_isBool(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->normalType() == nBool); + mkBool(v, args[0]->type() == nBool); } static RegisterPrimOp primop_isBool({ @@ -489,7 +489,7 @@ static RegisterPrimOp primop_isBool({ static void prim_isPath(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->normalType() == nPath); + mkBool(v, args[0]->type() == nPath); } static RegisterPrimOp primop_isPath({ @@ -505,13 +505,13 @@ struct CompareValues { bool operator () (const Value * v1, const Value * v2) const { - if (v1->normalType() == nFloat && v2->normalType() == nInt) + if (v1->type() == nFloat && v2->type() == nInt) return v1->fpoint < v2->integer; - if (v1->normalType() == nInt && v2->normalType() == nFloat) + if (v1->type() == nInt && v2->type() == nFloat) return v1->integer < v2->fpoint; - if (v1->normalType() != v2->normalType()) + if (v1->type() != v2->type()) throw EvalError("cannot compare %1% with %2%", showType(*v1), showType(*v2)); - switch (v1->normalType()) { + switch (v1->type()) { case nInt: return v1->integer < v2->integer; case nFloat: @@ -762,7 +762,7 @@ static RegisterPrimOp primop_deepSeq({ static void prim_trace(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - if (args[0]->normalType() == nString) + if (args[0]->type() == nString) printError("trace: %1%", args[0]->string.s); else printError("trace: %1%", *args[0]); @@ -887,7 +887,7 @@ static void prim_derivationStrict(EvalState & state, const Pos & pos, Value * * if (ignoreNulls) { state.forceValue(*i->value, pos); - if (i->value->normalType() == nNull) continue; + if (i->value->type() == nNull) continue; } if (i->name == state.sContentAddressed) { @@ -1293,7 +1293,7 @@ static void prim_dirOf(EvalState & state, const Pos & pos, Value * * args, Value { PathSet context; Path dir = dirOf(state.coerceToString(pos, *args[0], context, false, false)); - if (args[0]->normalType() == nPath) mkPath(v, dir.c_str()); else mkString(v, dir, context); + if (args[0]->type() == nPath) mkPath(v, dir.c_str()); else mkString(v, dir, context); } static RegisterPrimOp primop_dirOf({ @@ -1793,7 +1793,7 @@ static void prim_filterSource(EvalState & state, const Pos & pos, Value * * args }); state.forceValue(*args[0], pos); - if (args[0]->normalType() != nFunction) + if (args[0]->type() != nFunction) throw TypeError({ .hint = hintfmt( "first argument in call to 'filterSource' is not a function but %1%", @@ -2059,7 +2059,7 @@ static RegisterPrimOp primop_hasAttr({ static void prim_isAttrs(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->normalType() == nAttrs); + mkBool(v, args[0]->type() == nAttrs); } static RegisterPrimOp primop_isAttrs({ @@ -2322,7 +2322,7 @@ static RegisterPrimOp primop_mapAttrs({ static void prim_isList(EvalState & state, const Pos & pos, Value * * args, Value & v) { state.forceValue(*args[0], pos); - mkBool(v, args[0]->normalType() == nList); + mkBool(v, args[0]->type() == nList); } static RegisterPrimOp primop_isList({ @@ -2816,7 +2816,7 @@ static void prim_add(EvalState & state, const Pos & pos, Value * * args, Value & { state.forceValue(*args[0], pos); state.forceValue(*args[1], pos); - if (args[0]->normalType() == nFloat || args[1]->normalType() == nFloat) + if (args[0]->type() == nFloat || args[1]->type() == nFloat) mkFloat(v, state.forceFloat(*args[0], pos) + state.forceFloat(*args[1], pos)); else mkInt(v, state.forceInt(*args[0], pos) + state.forceInt(*args[1], pos)); @@ -2835,7 +2835,7 @@ static void prim_sub(EvalState & state, const Pos & pos, Value * * args, Value & { state.forceValue(*args[0], pos); state.forceValue(*args[1], pos); - if (args[0]->normalType() == nFloat || args[1]->normalType() == nFloat) + if (args[0]->type() == nFloat || args[1]->type() == nFloat) mkFloat(v, state.forceFloat(*args[0], pos) - state.forceFloat(*args[1], pos)); else mkInt(v, state.forceInt(*args[0], pos) - state.forceInt(*args[1], pos)); @@ -2854,7 +2854,7 @@ static void prim_mul(EvalState & state, const Pos & pos, Value * * args, Value & { state.forceValue(*args[0], pos); state.forceValue(*args[1], pos); - if (args[0]->normalType() == nFloat || args[1]->normalType() == nFloat) + if (args[0]->type() == nFloat || args[1]->type() == nFloat) mkFloat(v, state.forceFloat(*args[0], pos) * state.forceFloat(*args[1], pos)); else mkInt(v, state.forceInt(*args[0], pos) * state.forceInt(*args[1], pos)); @@ -2881,7 +2881,7 @@ static void prim_div(EvalState & state, const Pos & pos, Value * * args, Value & .errPos = pos }); - if (args[0]->normalType() == nFloat || args[1]->normalType() == nFloat) { + if (args[0]->type() == nFloat || args[1]->type() == nFloat) { mkFloat(v, state.forceFloat(*args[0], pos) / state.forceFloat(*args[1], pos)); } else { NixInt i1 = state.forceInt(*args[0], pos); diff --git a/src/libexpr/primops/fetchMercurial.cc b/src/libexpr/primops/fetchMercurial.cc index 2461ebc99..845a1ed1b 100644 --- a/src/libexpr/primops/fetchMercurial.cc +++ b/src/libexpr/primops/fetchMercurial.cc @@ -17,7 +17,7 @@ static void prim_fetchMercurial(EvalState & state, const Pos & pos, Value * * ar state.forceValue(*args[0]); - if (args[0]->normalType() == nAttrs) { + if (args[0]->type() == nAttrs) { state.forceAttrs(*args[0], pos); diff --git a/src/libexpr/primops/fetchTree.cc b/src/libexpr/primops/fetchTree.cc index 6d93e1dc2..6e7ddde8e 100644 --- a/src/libexpr/primops/fetchTree.cc +++ b/src/libexpr/primops/fetchTree.cc @@ -85,25 +85,25 @@ static void fetchTree( state.forceValue(*args[0]); - if (args[0]->normalType() == nAttrs) { + if (args[0]->type() == nAttrs) { state.forceAttrs(*args[0], pos); fetchers::Attrs attrs; for (auto & attr : *args[0]->attrs) { state.forceValue(*attr.value); - if (attr.value->normalType() == nPath || attr.value->normalType() == nString) + if (attr.value->type() == nPath || attr.value->type() == nString) addURI( state, attrs, attr.name, state.coerceToString(*attr.pos, *attr.value, context, false, false) ); - else if (attr.value->normalType() == nString) + else if (attr.value->type() == nString) addURI(state, attrs, attr.name, attr.value->string.s); - else if (attr.value->normalType() == nBool) + else if (attr.value->type() == nBool) attrs.emplace(attr.name, Explicit{attr.value->boolean}); - else if (attr.value->normalType() == nInt) + else if (attr.value->type() == nInt) attrs.emplace(attr.name, attr.value->integer); else throw TypeError("fetchTree argument '%s' is %s while a string, Boolean or integer is expected", @@ -163,7 +163,7 @@ static void fetch(EvalState & state, const Pos & pos, Value * * args, Value & v, state.forceValue(*args[0]); - if (args[0]->normalType() == nAttrs) { + if (args[0]->type() == nAttrs) { state.forceAttrs(*args[0], pos); diff --git a/src/libexpr/value-to-json.cc b/src/libexpr/value-to-json.cc index b5f4c8654..bfea24d40 100644 --- a/src/libexpr/value-to-json.cc +++ b/src/libexpr/value-to-json.cc @@ -16,7 +16,7 @@ void printValueAsJSON(EvalState & state, bool strict, if (strict) state.forceValue(v); - switch (v.normalType()) { + switch (v.type()) { case nInt: out.write(v.integer); diff --git a/src/libexpr/value-to-xml.cc b/src/libexpr/value-to-xml.cc index 26be07cff..7464455d8 100644 --- a/src/libexpr/value-to-xml.cc +++ b/src/libexpr/value-to-xml.cc @@ -58,7 +58,7 @@ static void printValueAsXML(EvalState & state, bool strict, bool location, if (strict) state.forceValue(v); - switch (v.normalType()) { + switch (v.type()) { case nInt: doc.writeEmptyElement("int", singletonAttrs("value", (format("%1%") % v.integer).str())); @@ -92,14 +92,14 @@ static void printValueAsXML(EvalState & state, bool strict, bool location, a = v.attrs->find(state.sDrvPath); if (a != v.attrs->end()) { if (strict) state.forceValue(*a->value); - if (a->value->normalType() == nString) + if (a->value->type() == nString) xmlAttrs["drvPath"] = drvPath = a->value->string.s; } a = v.attrs->find(state.sOutPath); if (a != v.attrs->end()) { if (strict) state.forceValue(*a->value); - if (a->value->normalType() == nString) + if (a->value->type() == nString) xmlAttrs["outPath"] = a->value->string.s; } diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index 8b312bf03..61ea1d64b 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -136,12 +136,12 @@ public: // These should be removed eventually, by putting the functionality that's // needed by callers into methods of this type - // normalType() == nThunk + // type() == nThunk inline bool isThunk() const { return internalType == tThunk; }; inline bool isApp() const { return internalType == tApp; }; inline bool isBlackhole() const { return internalType == tBlackhole; }; - // normalType() == nFunction + // type() == nFunction inline bool isLambda() const { return internalType == tLambda; }; inline bool isPrimOp() const { return internalType == tPrimOp; }; inline bool isPrimOpApp() const { return internalType == tPrimOpApp; }; @@ -204,7 +204,7 @@ public: // Returns the normal type of a Value. This only returns nThunk if the // Value hasn't been forceValue'd - inline ValueType normalType() const + inline ValueType type() const { switch (internalType) { case tInt: return nInt; diff --git a/src/nix-env/nix-env.cc b/src/nix-env/nix-env.cc index 404fd5111..6c2e075ed 100644 --- a/src/nix-env/nix-env.cc +++ b/src/nix-env/nix-env.cc @@ -1138,38 +1138,38 @@ static void opQuery(Globals & globals, Strings opFlags, Strings opArgs) i.queryName(), j) }); else { - if (v->normalType() == nString) { + if (v->type() == nString) { attrs2["type"] = "string"; attrs2["value"] = v->string.s; xml.writeEmptyElement("meta", attrs2); - } else if (v->normalType() == nInt) { + } else if (v->type() == nInt) { attrs2["type"] = "int"; attrs2["value"] = (format("%1%") % v->integer).str(); xml.writeEmptyElement("meta", attrs2); - } else if (v->normalType() == nFloat) { + } else if (v->type() == nFloat) { attrs2["type"] = "float"; attrs2["value"] = (format("%1%") % v->fpoint).str(); xml.writeEmptyElement("meta", attrs2); - } else if (v->normalType() == nBool) { + } else if (v->type() == nBool) { attrs2["type"] = "bool"; attrs2["value"] = v->boolean ? "true" : "false"; xml.writeEmptyElement("meta", attrs2); - } else if (v->normalType() == nList) { + } else if (v->type() == nList) { attrs2["type"] = "strings"; XMLOpenElement m(xml, "meta", attrs2); for (unsigned int j = 0; j < v->listSize(); ++j) { - if (v->listElems()[j]->normalType() != nString) continue; + if (v->listElems()[j]->type() != nString) continue; XMLAttrs attrs3; attrs3["value"] = v->listElems()[j]->string.s; xml.writeEmptyElement("string", attrs3); } - } else if (v->normalType() == nAttrs) { + } else if (v->type() == nAttrs) { attrs2["type"] = "strings"; XMLOpenElement m(xml, "meta", attrs2); Bindings & attrs = *v->attrs; for (auto &i : attrs) { Attr & a(*attrs.find(i.name)); - if(a.value->normalType() != nString) continue; + if(a.value->type() != nString) continue; XMLAttrs attrs3; attrs3["type"] = i.name; attrs3["value"] = a.value->string.s; diff --git a/src/nix/eval.cc b/src/nix/eval.cc index bba3b1bc6..ea82e5300 100644 --- a/src/nix/eval.cc +++ b/src/nix/eval.cc @@ -97,10 +97,10 @@ struct CmdEval : MixJSON, InstallableCommand recurse = [&](Value & v, const Pos & pos, const Path & path) { state->forceValue(v); - if (v.normalType() == nString) + if (v.type() == nString) // FIXME: disallow strings with contexts? writeFile(path, v.string.s); - else if (v.normalType() == nAttrs) { + else if (v.type() == nAttrs) { if (mkdir(path.c_str(), 0777) == -1) throw SysError("creating directory '%s'", path); for (auto & attr : *v.attrs) diff --git a/src/nix/flake.cc b/src/nix/flake.cc index e4da0348c..066430c5d 100644 --- a/src/nix/flake.cc +++ b/src/nix/flake.cc @@ -279,7 +279,7 @@ struct CmdFlakeCheck : FlakeCommand if (v.isLambda()) { if (!v.lambda.fun->matchAttrs || !v.lambda.fun->formals->ellipsis) throw Error("module must match an open attribute set ('{ config, ... }')"); - } else if (v.normalType() == nAttrs) { + } else if (v.type() == nAttrs) { for (auto & attr : *v.attrs) try { state->forceValue(*attr.value, *attr.pos); diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 047e2dc59..673155078 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -446,7 +446,7 @@ bool NixRepl::processLine(string line) Pos pos; - if (v.normalType() == nPath || v.normalType() == nString) { + if (v.type() == nPath || v.type() == nString) { PathSet context; auto filename = state->coerceToString(noPos, v, context); pos.file = state->symbols.create(filename); @@ -669,7 +669,7 @@ std::ostream & NixRepl::printValue(std::ostream & str, Value & v, unsigned int m state->forceValue(v); - switch (v.normalType()) { + switch (v.type()) { case nInt: str << ANSI_CYAN << v.integer << ANSI_NORMAL; From b70d22baca3e8826392b61aa53955c6da74b8724 Mon Sep 17 00:00:00 2001 From: Silvan Mosberger Date: Fri, 18 Dec 2020 14:38:49 +0100 Subject: [PATCH 8/8] Replace Value type setters with mk* functions Move clearValue inside Value mkInt instead of setInt mkBool instead of setBool mkString instead of setString mkPath instead of setPath mkNull instead of setNull mkAttrs instead of setAttrs mkList instead of setList* mkThunk instead of setThunk mkApp instead of setApp mkLambda instead of setLambda mkBlackhole instead of setBlackhole mkPrimOp instead of setPrimOp mkPrimOpApp instead of setPrimOpApp mkExternal instead of setExternal mkFloat instead of setFloat Add note that the static mk* function should be removed eventually --- src/libexpr/attr-set.cc | 4 +- src/libexpr/eval-inline.hh | 6 +- src/libexpr/eval.cc | 49 +++------- src/libexpr/nixexpr.hh | 2 +- src/libexpr/primops.cc | 2 +- src/libexpr/value.hh | 193 ++++++++++++++++++++++++------------- src/nix/repl.cc | 4 +- 7 files changed, 144 insertions(+), 116 deletions(-) diff --git a/src/libexpr/attr-set.cc b/src/libexpr/attr-set.cc index 17886a426..b6091c955 100644 --- a/src/libexpr/attr-set.cc +++ b/src/libexpr/attr-set.cc @@ -24,9 +24,7 @@ void EvalState::mkAttrs(Value & v, size_t capacity) v = vEmptySet; return; } - clearValue(v); - v.setAttrs(); - v.attrs = allocBindings(capacity); + v.mkAttrs(allocBindings(capacity)); nrAttrsets++; nrAttrsInAttrsets += capacity; } diff --git a/src/libexpr/eval-inline.hh b/src/libexpr/eval-inline.hh index e56ce261c..f6dead6b0 100644 --- a/src/libexpr/eval-inline.hh +++ b/src/libexpr/eval-inline.hh @@ -36,13 +36,11 @@ void EvalState::forceValue(Value & v, const Pos & pos) Env * env = v.thunk.env; Expr * expr = v.thunk.expr; try { - v.setBlackhole(); + v.mkBlackhole(); //checkInterrupt(); expr->eval(*this, *env, v); } catch (...) { - v.setThunk(); - v.thunk.env = env; - v.thunk.expr = expr; + v.mkThunk(env, expr); throw; } } diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 2f8d6d259..5a641d02c 100644 --- a/src/libexpr/eval.cc +++ b/src/libexpr/eval.cc @@ -430,9 +430,7 @@ EvalState::EvalState(const Strings & _searchPath, ref store) } } - clearValue(vEmptySet); - vEmptySet.setAttrs(); - vEmptySet.attrs = allocBindings(0); + vEmptySet.mkAttrs(allocBindings(0)); createBaseEnv(); } @@ -548,16 +546,14 @@ Value * EvalState::addPrimOp(const string & name, the primop to a dummy value. */ if (arity == 0) { auto vPrimOp = allocValue(); - vPrimOp->setPrimOp(); - vPrimOp->primOp = new PrimOp { .fun = primOp, .arity = 1, .name = sym }; + vPrimOp->mkPrimOp(new PrimOp { .fun = primOp, .arity = 1, .name = sym }); Value v; mkApp(v, *vPrimOp, *vPrimOp); return addConstant(name, v); } Value * v = allocValue(); - v->setPrimOp(); - v->primOp = new PrimOp { .fun = primOp, .arity = arity, .name = sym }; + v->mkPrimOp(new PrimOp { .fun = primOp, .arity = arity, .name = sym }); staticBaseEnv.vars[symbols.create(name)] = baseEnvDispl; baseEnv.values[baseEnvDispl++] = v; baseEnv.values[0]->attrs->push_back(Attr(sym, v)); @@ -572,8 +568,7 @@ Value * EvalState::addPrimOp(PrimOp && primOp) if (primOp.arity == 0) { primOp.arity = 1; auto vPrimOp = allocValue(); - vPrimOp->setPrimOp(); - vPrimOp->primOp = new PrimOp(std::move(primOp)); + vPrimOp->mkPrimOp(new PrimOp(std::move(primOp))); Value v; mkApp(v, *vPrimOp, *vPrimOp); return addConstant(primOp.name, v); @@ -584,8 +579,7 @@ Value * EvalState::addPrimOp(PrimOp && primOp) primOp.name = symbols.create(std::string(primOp.name, 2)); Value * v = allocValue(); - v->setPrimOp(); - v->primOp = new PrimOp(std::move(primOp)); + v->mkPrimOp(new PrimOp(std::move(primOp))); staticBaseEnv.vars[envName] = baseEnvDispl; baseEnv.values[baseEnvDispl++] = v; baseEnv.values[0]->attrs->push_back(Attr(primOp.name, v)); @@ -708,15 +702,13 @@ LocalNoInline(void addErrorTrace(Error & e, const Pos & pos, const char * s, con void mkString(Value & v, const char * s) { - mkStringNoCopy(v, dupString(s)); + v.mkString(dupString(s)); } Value & mkString(Value & v, std::string_view s, const PathSet & context) { - v.setString(); - v.string.s = dupStringWithLen(s.data(), s.size()); - v.string.context = 0; + v.mkString(dupStringWithLen(s.data(), s.size())); if (!context.empty()) { size_t n = 0; v.string.context = (const char * *) @@ -731,7 +723,7 @@ Value & mkString(Value & v, std::string_view s, const PathSet & context) void mkPath(Value & v, const char * s) { - mkPathNoCopy(v, dupString(s)); + v.mkPath(dupString(s)); } @@ -792,16 +784,9 @@ Env & EvalState::allocEnv(size_t size) void EvalState::mkList(Value & v, size_t size) { - clearValue(v); - if (size == 1) - v.setList1(); - else if (size == 2) - v.setList2(); - else { - v.setListN(); - v.bigList.size = size; - v.bigList.elems = size ? (Value * *) allocBytes(size * sizeof(Value *)) : 0; - } + v.mkList(size); + if (size > 2) + v.bigList.elems = (Value * *) allocBytes(size * sizeof(Value *)); nrListElems += size; } @@ -810,9 +795,7 @@ unsigned long nrThunks = 0; static inline void mkThunk(Value & v, Env & env, Expr * expr) { - v.setThunk(); - v.thunk.env = &env; - v.thunk.expr = expr; + v.mkThunk(&env, expr); nrThunks++; } @@ -1207,9 +1190,7 @@ void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v) void ExprLambda::eval(EvalState & state, Env & env, Value & v) { - v.setLambda(); - v.lambda.env = &env; - v.lambda.fun = this; + v.mkLambda(&env, this); } @@ -1252,9 +1233,7 @@ void EvalState::callPrimOp(Value & fun, Value & arg, Value & v, const Pos & pos) } else { Value * fun2 = allocValue(); *fun2 = fun; - v.setPrimOpApp(); - v.primOpApp.left = fun2; - v.primOpApp.right = &arg; + v.mkPrimOpApp(fun2, &arg); } } diff --git a/src/libexpr/nixexpr.hh b/src/libexpr/nixexpr.hh index e4cbc660f..b80a7de4e 100644 --- a/src/libexpr/nixexpr.hh +++ b/src/libexpr/nixexpr.hh @@ -129,7 +129,7 @@ struct ExprPath : Expr { string s; Value v; - ExprPath(const string & s) : s(s) { mkPathNoCopy(v, this->s.c_str()); }; + ExprPath(const string & s) : s(s) { v.mkPath(this->s.c_str()); }; COMMON_METHODS Value * maybeThunk(EvalState & state, Env & env); }; diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc index 4106f1ec8..45066e9cf 100644 --- a/src/libexpr/primops.cc +++ b/src/libexpr/primops.cc @@ -1434,7 +1434,7 @@ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Val Value * ent_val = state.allocAttr(v, state.symbols.create(ent.name)); if (ent.type == DT_UNKNOWN) ent.type = getFileType(path + "/" + ent.name); - mkStringNoCopy(*ent_val, + ent_val->mkString( ent.type == DT_REG ? "regular" : ent.type == DT_DIR ? "directory" : ent.type == DT_LNK ? "symlink" : diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh index 61ea1d64b..b317c1898 100644 --- a/src/libexpr/value.hh +++ b/src/libexpr/value.hh @@ -114,24 +114,6 @@ friend void printValue(std::ostream & str, std::set & active, con public: - inline void setInt() { internalType = tInt; }; - inline void setBool() { internalType = tBool; }; - inline void setString() { internalType = tString; }; - inline void setPath() { internalType = tPath; }; - inline void setNull() { internalType = tNull; }; - inline void setAttrs() { internalType = tAttrs; }; - inline void setList1() { internalType = tList1; }; - inline void setList2() { internalType = tList2; }; - inline void setListN() { internalType = tListN; }; - inline void setThunk() { internalType = tThunk; }; - inline void setApp() { internalType = tApp; }; - inline void setLambda() { internalType = tLambda; }; - inline void setBlackhole() { internalType = tBlackhole; }; - inline void setPrimOp() { internalType = tPrimOp; }; - inline void setPrimOpApp() { internalType = tPrimOpApp; }; - inline void setExternal() { internalType = tExternal; }; - inline void setFloat() { internalType = tFloat; }; - // Functions needed to distinguish the type // These should be removed eventually, by putting the functionality that's // needed by callers into methods of this type @@ -222,6 +204,123 @@ public: abort(); } + /* After overwriting an app node, be sure to clear pointers in the + Value to ensure that the target isn't kept alive unnecessarily. */ + inline void clearValue() + { + app.left = app.right = 0; + } + + inline void mkInt(NixInt n) + { + clearValue(); + internalType = tInt; + integer = n; + } + + inline void mkBool(bool b) + { + clearValue(); + internalType = tBool; + boolean = b; + } + + inline void mkString(const char * s, const char * * context = 0) + { + internalType = tString; + string.s = s; + string.context = context; + } + + inline void mkPath(const char * s) + { + clearValue(); + internalType = tPath; + path = s; + } + + inline void mkNull() + { + clearValue(); + internalType = tNull; + } + + inline void mkAttrs(Bindings * a) + { + clearValue(); + internalType = tAttrs; + attrs = a; + } + + inline void mkList(size_t size) + { + clearValue(); + if (size == 1) + internalType = tList1; + else if (size == 2) + internalType = tList2; + else { + internalType = tListN; + bigList.size = size; + } + } + + inline void mkThunk(Env * e, Expr * ex) + { + internalType = tThunk; + thunk.env = e; + thunk.expr = ex; + } + + inline void mkApp(Value * l, Value * r) + { + internalType = tApp; + app.left = l; + app.right = r; + } + + inline void mkLambda(Env * e, ExprLambda * f) + { + internalType = tLambda; + lambda.env = e; + lambda.fun = f; + } + + inline void mkBlackhole() + { + internalType = tBlackhole; + // Value will be overridden anyways + } + + inline void mkPrimOp(PrimOp * p) + { + clearValue(); + internalType = tPrimOp; + primOp = p; + } + + + inline void mkPrimOpApp(Value * l, Value * r) + { + internalType = tPrimOpApp; + app.left = l; + app.right = r; + } + + inline void mkExternal(ExternalValueBase * e) + { + clearValue(); + internalType = tExternal; + external = e; + } + + inline void mkFloat(NixFloat n) + { + clearValue(); + internalType = tFloat; + fpoint = n; + } + bool isList() const { return internalType == tList1 || internalType == tList2 || internalType == tListN; @@ -251,86 +350,42 @@ public: }; -/* After overwriting an app node, be sure to clear pointers in the - Value to ensure that the target isn't kept alive unnecessarily. */ -static inline void clearValue(Value & v) -{ - v.app.left = v.app.right = 0; -} - +// TODO: Remove these static functions, replace call sites with v.mk* instead static inline void mkInt(Value & v, NixInt n) { - clearValue(v); - v.setInt(); - v.integer = n; + v.mkInt(n); } - static inline void mkFloat(Value & v, NixFloat n) { - clearValue(v); - v.setFloat(); - v.fpoint = n; + v.mkFloat(n); } - static inline void mkBool(Value & v, bool b) { - clearValue(v); - v.setBool(); - v.boolean = b; + v.mkBool(b); } - static inline void mkNull(Value & v) { - clearValue(v); - v.setNull(); + v.mkNull(); } - static inline void mkApp(Value & v, Value & left, Value & right) { - v.setApp(); - v.app.left = &left; - v.app.right = &right; + v.mkApp(&left, &right); } - -static inline void mkPrimOpApp(Value & v, Value & left, Value & right) -{ - v.setPrimOpApp(); - v.app.left = &left; - v.app.right = &right; -} - - -static inline void mkStringNoCopy(Value & v, const char * s) -{ - v.setString(); - v.string.s = s; - v.string.context = 0; -} - - static inline void mkString(Value & v, const Symbol & s) { - mkStringNoCopy(v, ((const string &) s).c_str()); + v.mkString(((const string &) s).c_str()); } void mkString(Value & v, const char * s); -static inline void mkPathNoCopy(Value & v, const char * s) -{ - clearValue(v); - v.setPath(); - v.path = s; -} - - void mkPath(Value & v, const char * s); diff --git a/src/nix/repl.cc b/src/nix/repl.cc index 673155078..a992d8732 100644 --- a/src/nix/repl.cc +++ b/src/nix/repl.cc @@ -551,9 +551,7 @@ bool NixRepl::processLine(string line) { Expr * e = parseString(string(line, p + 1)); Value & v(*state->allocValue()); - v.setThunk(); - v.thunk.env = env; - v.thunk.expr = e; + v.mkThunk(env, e); addVarToScope(state->symbols.create(name), v); } else { Value v;