forked from lix-project/lix
Allow external code using libnixexpr to add types
Code that links to libnixexpr (e.g. plugins loaded with importNative, or nix-exec) may want to provide custom value types and operations on values of those types. For example, nix-exec is currently using sets where a custom IO value type would be more appropriate. This commit provides a generic hook for such types in the form of tExternal and the ExternalBase virtual class, which contains all functions necessary for libnixexpr's type-polymorphic functions (e.g. `showType`) to be implemented.
This commit is contained in:
parent
5f04da905f
commit
320659b0cd
|
@ -104,6 +104,9 @@ static void printValue(std::ostream & str, std::set<const Value *> & active, con
|
||||||
case tPrimOpApp:
|
case tPrimOpApp:
|
||||||
str << "<PRIMOP-APP>";
|
str << "<PRIMOP-APP>";
|
||||||
break;
|
break;
|
||||||
|
case tExternal:
|
||||||
|
str << *v.external;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw Error("invalid value");
|
throw Error("invalid value");
|
||||||
}
|
}
|
||||||
|
@ -136,6 +139,7 @@ string showType(const Value & v)
|
||||||
case tBlackhole: return "a black hole";
|
case tBlackhole: return "a black hole";
|
||||||
case tPrimOp: return "a built-in function";
|
case tPrimOp: return "a built-in function";
|
||||||
case tPrimOpApp: return "a partially applied built-in function";
|
case tPrimOpApp: return "a partially applied built-in function";
|
||||||
|
case tExternal: return v.external->showType();
|
||||||
}
|
}
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
@ -1314,6 +1318,9 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context,
|
||||||
return coerceToString(pos, *i->value, context, coerceMore, copyToStore);
|
return coerceToString(pos, *i->value, context, coerceMore, copyToStore);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (v.type == tExternal)
|
||||||
|
return v.external->coerceToString(pos, context, coerceMore, copyToStore);
|
||||||
|
|
||||||
if (coerceMore) {
|
if (coerceMore) {
|
||||||
|
|
||||||
/* Note that `false' is represented as an empty string for
|
/* Note that `false' is represented as an empty string for
|
||||||
|
@ -1434,6 +1441,9 @@ bool EvalState::eqValues(Value & v1, Value & v2)
|
||||||
case tPrimOpApp:
|
case tPrimOpApp:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
case tExternal:
|
||||||
|
return *v1.external == *v2.external;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throwEvalError("cannot compare %1% with %2%", showType(v1), showType(v2));
|
throwEvalError("cannot compare %1% with %2%", showType(v1), showType(v2));
|
||||||
}
|
}
|
||||||
|
@ -1575,6 +1585,11 @@ size_t valueSize(Value & v)
|
||||||
sz += doValue(*v.primOpApp.left);
|
sz += doValue(*v.primOpApp.left);
|
||||||
sz += doValue(*v.primOpApp.right);
|
sz += doValue(*v.primOpApp.right);
|
||||||
break;
|
break;
|
||||||
|
case tExternal:
|
||||||
|
if (seen.find(v.external) != seen.end()) break;
|
||||||
|
seen.insert(v.external);
|
||||||
|
sz += v.external->valueSize(seen);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
@ -1601,4 +1616,22 @@ size_t valueSize(Value & v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore)
|
||||||
|
{
|
||||||
|
throw TypeError(format("cannot coerce %1% to a string, at %2%") %
|
||||||
|
showType() % pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool ExternalValueBase::operator==(const ExternalValueBase & b)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::ostream & operator << (std::ostream & str, ExternalValueBase & v) {
|
||||||
|
return v.print(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -187,6 +187,9 @@ static void prim_typeOf(EvalState & state, const Pos & pos, Value * * args, Valu
|
||||||
case tPrimOpApp:
|
case tPrimOpApp:
|
||||||
t = "lambda";
|
t = "lambda";
|
||||||
break;
|
break;
|
||||||
|
case tExternal:
|
||||||
|
t = args[0]->external->typeOf();
|
||||||
|
break;
|
||||||
default: abort();
|
default: abort();
|
||||||
}
|
}
|
||||||
mkString(v, state.symbols.create(t));
|
mkString(v, state.symbols.create(t));
|
||||||
|
|
|
@ -80,10 +80,21 @@ void printValueAsJSON(EvalState & state, bool strict,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case tExternal:
|
||||||
|
v.external->printValueAsJSON(state, strict, str, context);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw TypeError(format("cannot convert %1% to JSON") % showType(v));
|
throw TypeError(format("cannot convert %1% to JSON") % showType(v));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExternalValueBase::printValueAsJSON(EvalState & state, bool strict,
|
||||||
|
std::ostream & str, PathSet & context)
|
||||||
|
{
|
||||||
|
throw TypeError(format("cannot convert %1% to JSON") % showType());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -144,12 +144,23 @@ static void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case tExternal:
|
||||||
|
v.external->printValueAsXML(state, strict, location, doc, context, drvsSeen);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
doc.writeEmptyElement("unevaluated");
|
doc.writeEmptyElement("unevaluated");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ExternalValueBase::printValueAsXML(EvalState & state, bool strict,
|
||||||
|
bool location, XMLWriter & doc, PathSet & context, PathSet & drvsSeen)
|
||||||
|
{
|
||||||
|
doc.writeEmptyElement("unevaluated");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void printValueAsXML(EvalState & state, bool strict, bool location,
|
void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
Value & v, std::ostream & out, PathSet & context)
|
Value & v, std::ostream & out, PathSet & context)
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,6 +19,7 @@ typedef enum {
|
||||||
tBlackhole,
|
tBlackhole,
|
||||||
tPrimOp,
|
tPrimOp,
|
||||||
tPrimOpApp,
|
tPrimOpApp,
|
||||||
|
tExternal,
|
||||||
} ValueType;
|
} ValueType;
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,10 +30,58 @@ struct ExprLambda;
|
||||||
struct PrimOp;
|
struct PrimOp;
|
||||||
struct PrimOp;
|
struct PrimOp;
|
||||||
class Symbol;
|
class Symbol;
|
||||||
|
struct Pos;
|
||||||
|
class EvalState;
|
||||||
|
class XMLWriter;
|
||||||
|
|
||||||
|
|
||||||
typedef long NixInt;
|
typedef long NixInt;
|
||||||
|
|
||||||
|
/* External values must descend from ExternalValueBase, so that
|
||||||
|
* type-agnostic nix functions (e.g. showType) can be implemented
|
||||||
|
*/
|
||||||
|
class ExternalValueBase
|
||||||
|
{
|
||||||
|
friend std::ostream & operator << (std::ostream & str, ExternalValueBase & v);
|
||||||
|
protected:
|
||||||
|
/* Print out the value */
|
||||||
|
virtual std::ostream & print(std::ostream & str) = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/* Return a simple string describing the type */
|
||||||
|
virtual string showType() = 0;
|
||||||
|
|
||||||
|
/* Return a string to be used in builtins.typeOf */
|
||||||
|
virtual string typeOf() = 0;
|
||||||
|
|
||||||
|
/* How much space does this value take up */
|
||||||
|
virtual size_t valueSize(std::set<const void *> & seen) = 0;
|
||||||
|
|
||||||
|
/* Coerce the value to a string. Defaults to uncoercable, i.e. throws an
|
||||||
|
* error
|
||||||
|
*/
|
||||||
|
virtual string coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore);
|
||||||
|
|
||||||
|
/* Compare to another value of the same type. Defaults to uncomparable,
|
||||||
|
* i.e. always false.
|
||||||
|
*/
|
||||||
|
virtual bool operator==(const ExternalValueBase & b);
|
||||||
|
|
||||||
|
/* Print the value as JSON. Defaults to unconvertable, i.e. throws an error */
|
||||||
|
virtual void printValueAsJSON(EvalState & state, bool strict,
|
||||||
|
std::ostream & str, PathSet & context);
|
||||||
|
|
||||||
|
/* Print the value as XML. Defaults to unevaluated */
|
||||||
|
virtual void printValueAsXML(EvalState & state, bool strict, bool location,
|
||||||
|
XMLWriter & doc, PathSet & context, PathSet & drvsSeen);
|
||||||
|
|
||||||
|
virtual ~ExternalValueBase()
|
||||||
|
{
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
std::ostream & operator << (std::ostream & str, ExternalValueBase & v);
|
||||||
|
|
||||||
|
|
||||||
struct Value
|
struct Value
|
||||||
{
|
{
|
||||||
|
@ -88,6 +137,7 @@ struct Value
|
||||||
struct {
|
struct {
|
||||||
Value * left, * right;
|
Value * left, * right;
|
||||||
} primOpApp;
|
} primOpApp;
|
||||||
|
ExternalValueBase * external;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue