about summary refs log tree commit diff
path: root/src/libexpr/eval.cc
diff options
context:
space:
mode:
authorShea Levy <shea@shealevy.com>2014-11-30T18·16-0500
committerShea Levy <shea@shealevy.com>2014-12-02T15·27-0500
commit320659b0cd161249c95e736c3fb309b1a73ea728 (patch)
treef58c49ae4828572d4642a4d02360f8a415a9f0f9 /src/libexpr/eval.cc
parent5f04da905fcd01ea2d68cdbf7af41c836df5bb4e (diff)
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.
Diffstat (limited to 'src/libexpr/eval.cc')
-rw-r--r--src/libexpr/eval.cc33
1 files changed, 33 insertions, 0 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index ebb28021c180..b0afccdfbaaf 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -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);
+}
+
+
 }