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
					
				
					 5 changed files with 108 additions and 0 deletions
				
			
		|  | @ -104,6 +104,9 @@ static void printValue(std::ostream & str, std::set<const Value *> & active, con | |||
|     case tPrimOpApp: | ||||
|         str << "<PRIMOP-APP>"; | ||||
|         break; | ||||
|     case tExternal: | ||||
|         str << *v.external; | ||||
|         break; | ||||
|     default: | ||||
|         throw Error("invalid value"); | ||||
|     } | ||||
|  | @ -136,6 +139,7 @@ string showType(const Value & v) | |||
|         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 v.external->showType(); | ||||
|     } | ||||
|     abort(); | ||||
| } | ||||
|  | @ -1314,6 +1318,9 @@ string EvalState::coerceToString(const Pos & pos, Value & v, PathSet & context, | |||
|         return coerceToString(pos, *i->value, context, coerceMore, copyToStore); | ||||
|     } | ||||
| 
 | ||||
|     if (v.type == tExternal) | ||||
|         return v.external->coerceToString(pos, context, coerceMore, copyToStore); | ||||
| 
 | ||||
|     if (coerceMore) { | ||||
| 
 | ||||
|         /* Note that `false' is represented as an empty string for
 | ||||
|  | @ -1434,6 +1441,9 @@ bool EvalState::eqValues(Value & v1, Value & v2) | |||
|         case tPrimOpApp: | ||||
|             return false; | ||||
| 
 | ||||
|         case tExternal: | ||||
|             return *v1.external == *v2.external; | ||||
| 
 | ||||
|         default: | ||||
|             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.right); | ||||
|             break; | ||||
|         case tExternal: | ||||
|             if (seen.find(v.external) != seen.end()) break; | ||||
|             seen.insert(v.external); | ||||
|             sz += v.external->valueSize(seen); | ||||
|             break; | ||||
|         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: | ||||
|             t = "lambda"; | ||||
|             break; | ||||
| 	case tExternal: | ||||
|             t = args[0]->external->typeOf(); | ||||
|             break; | ||||
|         default: abort(); | ||||
|     } | ||||
|     mkString(v, state.symbols.create(t)); | ||||
|  |  | |||
|  | @ -80,10 +80,21 @@ void printValueAsJSON(EvalState & state, bool strict, | |||
|             break; | ||||
|         } | ||||
| 
 | ||||
| 	case tExternal: | ||||
|             v.external->printValueAsJSON(state, strict, str, context); | ||||
|             break; | ||||
| 
 | ||||
|         default: | ||||
|             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; | ||||
|         } | ||||
| 
 | ||||
|         case tExternal: | ||||
|             v.external->printValueAsXML(state, strict, location, doc, context, drvsSeen); | ||||
|             break; | ||||
| 
 | ||||
|         default: | ||||
|             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, | ||||
|     Value & v, std::ostream & out, PathSet & context) | ||||
| { | ||||
|  |  | |||
|  | @ -19,6 +19,7 @@ typedef enum { | |||
|     tBlackhole, | ||||
|     tPrimOp, | ||||
|     tPrimOpApp, | ||||
|     tExternal, | ||||
| } ValueType; | ||||
| 
 | ||||
| 
 | ||||
|  | @ -29,10 +30,58 @@ struct ExprLambda; | |||
| struct PrimOp; | ||||
| struct PrimOp; | ||||
| class Symbol; | ||||
| struct Pos; | ||||
| class EvalState; | ||||
| class XMLWriter; | ||||
| 
 | ||||
| 
 | ||||
| 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 | ||||
| { | ||||
|  | @ -88,6 +137,7 @@ struct Value | |||
|         struct { | ||||
|             Value * left, * right; | ||||
|         } primOpApp; | ||||
|         ExternalValueBase * external; | ||||
|     }; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue