about summary refs log tree commit diff
path: root/src/libexpr/eval.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr/eval.cc')
-rw-r--r--src/libexpr/eval.cc82
1 files changed, 48 insertions, 34 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 5b9db6eeaa6e..298f6a3a60e3 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();
 }
@@ -180,6 +184,7 @@ EvalState::EvalState(const Strings & _searchPath)
     , sFile(symbols.create("file"))
     , sLine(symbols.create("line"))
     , sColumn(symbols.create("column"))
+    , sFunctor(symbols.create("__functor"))
     , repair(false)
     , baseEnv(allocEnv(128))
     , staticBaseEnv(false, 0)
@@ -212,9 +217,9 @@ EvalState::EvalState(const Strings & _searchPath)
            allocated.  This might be a problem on systems that don't
            overcommit. */
         if (!getenv("GC_INITIAL_HEAP_SIZE")) {
-            size_t maxSize = 384 * 1024 * 1024;
             size_t size = 32 * 1024 * 1024;
 #if HAVE_SYSCONF && defined(_SC_PAGESIZE) && defined(_SC_PHYS_PAGES)
+            size_t maxSize = 384 * 1024 * 1024;
             long pageSize = sysconf(_SC_PAGESIZE);
             long pages = sysconf(_SC_PHYS_PAGES);
             if (pageSize != -1)
@@ -242,7 +247,6 @@ EvalState::EvalState(const Strings & _searchPath)
 EvalState::~EvalState()
 {
     fileEvalCache.clear();
-    printCanaries();
 }
 
 
@@ -312,11 +316,6 @@ LocalNoInlineNoReturn(void throwEvalError(const char * s, const Symbol & sym, co
     throw EvalError(format(s) % sym % p1 % p2);
 }
 
-LocalNoInlineNoReturn(void throwTypeError(const char * s))
-{
-    throw TypeError(s);
-}
-
 LocalNoInlineNoReturn(void throwTypeError(const char * s, const Pos & pos))
 {
     throw TypeError(format(s) % pos);
@@ -327,11 +326,6 @@ LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1))
     throw TypeError(format(s) % s1);
 }
 
-LocalNoInlineNoReturn(void throwTypeError(const char * s, const string & s1, const string & s2))
-{
-    throw TypeError(format(s) % s1 % s2);
-}
-
 LocalNoInlineNoReturn(void throwTypeError(const char * s, const ExprLambda & fun, const Symbol & s2, const Pos & pos))
 {
     throw TypeError(format(s) % fun.showNamePos() % s2 % pos);
@@ -895,6 +889,17 @@ void EvalState::callFunction(Value & fun, Value & arg, Value & v, const Pos & po
         return;
     }
 
+    if (fun.type == tAttrs) {
+      auto found = fun.attrs->find(sFunctor);
+      if (found != fun.attrs->end()) {
+        forceValue(*found->value);
+        Value * v2 = allocValue();
+        callFunction(*found->value, fun, *v2, pos);
+        forceValue(*v2);
+        return callFunction(*v2, arg, v, pos);
+      }
+    }
+
     if (fun.type != tLambda)
         throwTypeError("attempt to call something which is not a function but %1%, at %2%", fun, pos);
 
@@ -1255,9 +1260,9 @@ void copyContext(const Value & v, PathSet & context)
 }
 
 
-string EvalState::forceString(Value & v, PathSet & context)
+string EvalState::forceString(Value & v, PathSet & context, const Pos & pos)
 {
-    string s = forceString(v);
+    string s = forceString(v, pos);
     copyContext(v, context);
     return s;
 }
@@ -1312,6 +1317,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
@@ -1432,6 +1440,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));
     }
@@ -1502,26 +1513,6 @@ void EvalState::printStats()
 }
 
 
-void EvalState::printCanaries()
-{
-#if HAVE_BOEHMGC
-    if (!settings.get("debug-gc", false)) return;
-
-    GC_gcollect();
-
-    if (gcCanaries.empty()) {
-        printMsg(lvlError, "all canaries have been garbage-collected");
-        return;
-    }
-
-    printMsg(lvlError, "the following canaries have not been garbage-collected:");
-
-    for (auto i : gcCanaries)
-        printMsg(lvlError, format("  %1%") % i->string.s);
-#endif
-}
-
-
 size_t valueSize(Value & v)
 {
     std::set<const void *> seen;
@@ -1573,6 +1564,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:
             ;
         }
@@ -1599,4 +1595,22 @@ size_t valueSize(Value & v)
 }
 
 
+string ExternalValueBase::coerceToString(const Pos & pos, PathSet & context, bool copyMore, bool copyToStore) const
+{
+    throw TypeError(format("cannot coerce %1% to a string, at %2%") %
+        showType() % pos);
+}
+
+
+bool ExternalValueBase::operator==(const ExternalValueBase & b) const
+{
+    return false;
+}
+
+
+std::ostream & operator << (std::ostream & str, const ExternalValueBase & v) {
+    return v.print(str);
+}
+
+
 }