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
This commit is contained in:
parent
9c143c411b
commit
fa307875e9
5 changed files with 68 additions and 34 deletions
|
@ -513,7 +513,7 @@ std::string AttrCursor::getString()
|
||||||
auto & v = forceValue();
|
auto & v = forceValue();
|
||||||
|
|
||||||
if (v.type != tString && v.type != tPath)
|
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;
|
return v.type == tString ? v.string.s : v.path;
|
||||||
}
|
}
|
||||||
|
@ -548,7 +548,7 @@ string_t AttrCursor::getStringWithContext()
|
||||||
else if (v.type == tPath)
|
else if (v.type == tPath)
|
||||||
return {v.path, {}};
|
return {v.path, {}};
|
||||||
else
|
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()
|
bool AttrCursor::getBool()
|
||||||
|
|
|
@ -165,25 +165,20 @@ const Value *getPrimOp(const Value &v) {
|
||||||
return primOp;
|
return primOp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string showType(NormalType type)
|
||||||
string showType(ValueType type)
|
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case tInt: return "an integer";
|
case nInt: return "an integer";
|
||||||
case tBool: return "a Boolean";
|
case nBool: return "a Boolean";
|
||||||
case tString: return "a string";
|
case nString: return "a string";
|
||||||
case tPath: return "a path";
|
case nPath: return "a path";
|
||||||
case tNull: return "null";
|
case nNull: return "null";
|
||||||
case tAttrs: return "a set";
|
case nAttrs: return "a set";
|
||||||
case tList1: case tList2: case tListN: return "a list";
|
case nList: return "a list";
|
||||||
case tThunk: return "a thunk";
|
case nFunction: return "a function";
|
||||||
case tApp: return "a function application";
|
case nExternal: return "an external value";
|
||||||
case tLambda: return "a function";
|
case nFloat: return "a float";
|
||||||
case tBlackhole: return "a black hole";
|
case nThunk: return "a thunk";
|
||||||
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";
|
|
||||||
}
|
}
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
@ -198,8 +193,11 @@ string showType(const Value & v)
|
||||||
case tPrimOpApp:
|
case tPrimOpApp:
|
||||||
return fmt("the partially applied built-in function '%s'", string(getPrimOp(v)->primOp->name));
|
return fmt("the partially applied built-in function '%s'", string(getPrimOp(v)->primOp->name));
|
||||||
case tExternal: return v.external->showType();
|
case tExternal: return v.external->showType();
|
||||||
|
case tThunk: return "a thunk";
|
||||||
|
case tApp: return "a function application";
|
||||||
|
case tBlackhole: return "a black hole";
|
||||||
default:
|
default:
|
||||||
return showType(v.type);
|
return showType(v.normalType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -346,7 +346,7 @@ private:
|
||||||
|
|
||||||
|
|
||||||
/* Return a string representing the type of the value `v'. */
|
/* Return a string representing the type of the value `v'. */
|
||||||
string showType(ValueType type);
|
string showType(NormalType type);
|
||||||
string showType(const Value & v);
|
string showType(const Value & v);
|
||||||
|
|
||||||
/* Decode a context string ‘!<name>!<path>’ into a pair <path,
|
/* Decode a context string ‘!<name>!<path>’ into a pair <path,
|
||||||
|
|
|
@ -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)
|
Value & value, const Pos & pos)
|
||||||
{
|
{
|
||||||
forceTrivialValue(state, value, pos);
|
forceTrivialValue(state, value, pos);
|
||||||
if (value.type != type)
|
if (value.normalType() != type)
|
||||||
throw Error("expected %s but got %s at %s",
|
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(
|
static std::map<FlakeId, FlakeInput> parseFlakeInputs(
|
||||||
|
@ -93,7 +93,7 @@ static std::map<FlakeId, FlakeInput> parseFlakeInputs(
|
||||||
static FlakeInput parseFlakeInput(EvalState & state,
|
static FlakeInput parseFlakeInput(EvalState & state,
|
||||||
const std::string & inputName, Value * value, const Pos & pos)
|
const std::string & inputName, Value * value, const Pos & pos)
|
||||||
{
|
{
|
||||||
expectType(state, tAttrs, *value, pos);
|
expectType(state, nAttrs, *value, pos);
|
||||||
|
|
||||||
FlakeInput input;
|
FlakeInput input;
|
||||||
|
|
||||||
|
@ -108,16 +108,16 @@ static FlakeInput parseFlakeInput(EvalState & state,
|
||||||
for (nix::Attr attr : *(value->attrs)) {
|
for (nix::Attr attr : *(value->attrs)) {
|
||||||
try {
|
try {
|
||||||
if (attr.name == sUrl) {
|
if (attr.name == sUrl) {
|
||||||
expectType(state, tString, *attr.value, *attr.pos);
|
expectType(state, nString, *attr.value, *attr.pos);
|
||||||
url = attr.value->string.s;
|
url = attr.value->string.s;
|
||||||
attrs.emplace("url", *url);
|
attrs.emplace("url", *url);
|
||||||
} else if (attr.name == sFlake) {
|
} else if (attr.name == sFlake) {
|
||||||
expectType(state, tBool, *attr.value, *attr.pos);
|
expectType(state, nBool, *attr.value, *attr.pos);
|
||||||
input.isFlake = attr.value->boolean;
|
input.isFlake = attr.value->boolean;
|
||||||
} else if (attr.name == sInputs) {
|
} else if (attr.name == sInputs) {
|
||||||
input.overrides = parseFlakeInputs(state, attr.value, *attr.pos);
|
input.overrides = parseFlakeInputs(state, attr.value, *attr.pos);
|
||||||
} else if (attr.name == sFollows) {
|
} 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);
|
input.follows = parseInputPath(attr.value->string.s);
|
||||||
} else {
|
} else {
|
||||||
if (attr.value->type == tString)
|
if (attr.value->type == tString)
|
||||||
|
@ -158,7 +158,7 @@ static std::map<FlakeId, FlakeInput> parseFlakeInputs(
|
||||||
{
|
{
|
||||||
std::map<FlakeId, FlakeInput> inputs;
|
std::map<FlakeId, FlakeInput> inputs;
|
||||||
|
|
||||||
expectType(state, tAttrs, *value, pos);
|
expectType(state, nAttrs, *value, pos);
|
||||||
|
|
||||||
for (nix::Attr & inputAttr : *(*value).attrs) {
|
for (nix::Attr & inputAttr : *(*value).attrs) {
|
||||||
inputs.emplace(inputAttr.name,
|
inputs.emplace(inputAttr.name,
|
||||||
|
@ -199,10 +199,10 @@ static Flake getFlake(
|
||||||
Value vInfo;
|
Value vInfo;
|
||||||
state.evalFile(flakeFile, vInfo, true); // FIXME: symlink attack
|
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)) {
|
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;
|
flake.description = description->value->string.s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,9 +214,9 @@ static Flake getFlake(
|
||||||
auto sOutputs = state.symbols.create("outputs");
|
auto sOutputs = state.symbols.create("outputs");
|
||||||
|
|
||||||
if (auto outputs = vInfo.attrs->get(sOutputs)) {
|
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) {
|
for (auto & formal : outputs->value->lambda.fun->formals->formals) {
|
||||||
if (formal.name != state.sSelf)
|
if (formal.name != state.sSelf)
|
||||||
flake.inputs.emplace(formal.name, FlakeInput {
|
flake.inputs.emplace(formal.name, FlakeInput {
|
||||||
|
@ -231,7 +231,7 @@ static Flake getFlake(
|
||||||
auto sNixConfig = state.symbols.create("nixConfig");
|
auto sNixConfig = state.symbols.create("nixConfig");
|
||||||
|
|
||||||
if (auto nixConfig = vInfo.attrs->get(sNixConfig)) {
|
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) {
|
for (auto & setting : *nixConfig->value->attrs) {
|
||||||
forceTrivialValue(state, *setting.value, *setting.pos);
|
forceTrivialValue(state, *setting.value, *setting.pos);
|
||||||
|
|
|
@ -29,6 +29,22 @@ typedef enum {
|
||||||
tFloat
|
tFloat
|
||||||
} ValueType;
|
} 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;
|
class Bindings;
|
||||||
struct Env;
|
struct Env;
|
||||||
|
@ -147,6 +163,26 @@ struct Value
|
||||||
NixFloat fpoint;
|
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
|
bool isList() const
|
||||||
{
|
{
|
||||||
return type == tList1 || type == tList2 || type == tListN;
|
return type == tList1 || type == tList2 || type == tListN;
|
||||||
|
|
Loading…
Reference in a new issue