summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSilvan Mosberger <contact@infinisil.com>2020-12-11 23:32:45 +0100
committerSilvan Mosberger <contact@infinisil.com>2020-12-12 03:31:46 +0100
commitfa307875e961a616a049206645a651a76a050a79 (patch)
tree1af556c2f3ab0282f4ef7cf68a2be564d20dbe53
parent9c143c411b2190a05907416266b0022e5b17dd02 (diff)
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
-rw-r--r--src/libexpr/eval-cache.cc4
-rw-r--r--src/libexpr/eval.cc34
-rw-r--r--src/libexpr/eval.hh2
-rw-r--r--src/libexpr/flake/flake.cc26
-rw-r--r--src/libexpr/value.hh36
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 ‘!<name>!<path>’ into a pair <path,
diff --git a/src/libexpr/flake/flake.cc b/src/libexpr/flake/flake.cc
index 3e866e1f9..881b1b4e5 100644
--- a/src/libexpr/flake/flake.cc
+++ b/src/libexpr/flake/flake.cc
@@ -78,13 +78,13 @@ static void forceTrivialValue(EvalState & state, Value & value, const Pos & pos)
}
-static void expectType(EvalState & state, ValueType type,
+static void expectType(EvalState & state, NormalType type,
Value & value, const Pos & pos)
{
forceTrivialValue(state, value, pos);
- if (value.type != type)
+ if (value.normalType() != type)
throw Error("expected %s but got %s at %s",
- showType(type), showType(value.type), pos);
+ showType(type), showType(value.normalType()), pos);
}
static std::map<FlakeId, FlakeInput> parseFlakeInputs(
@@ -93,7 +93,7 @@ static std::map<FlakeId, FlakeInput> 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<FlakeId, FlakeInput> parseFlakeInputs(
{
std::map<FlakeId, FlakeInput> 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;