about summary refs log tree commit diff
path: root/src/libexpr/primops.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/libexpr/primops.cc')
-rw-r--r--src/libexpr/primops.cc99
1 files changed, 55 insertions, 44 deletions
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index a7884cb85521..6c30e6d549ec 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -35,7 +35,7 @@ std::pair<string, string> decodeContext(const string & s)
         size_t index = s.find("!", 1);
         return std::pair<string, string>(string(s, index + 1), string(s, 1, index - 1));
     } else
-        return std::pair<string, string>(s, "");
+        return std::pair<string, string>(s.at(0) == '/' ? s: string(s, 1), "");
 }
 
 
@@ -51,7 +51,7 @@ void realiseContext(const PathSet & context)
         assert(isStorePath(ctx));
         if (!store->isValidPath(ctx))
             throw InvalidPathError(ctx);
-        if (isDerivation(ctx))
+        if (!decoded.second.empty() && isDerivation(ctx))
             drvs.insert(decoded.first + "!" + decoded.second);
     }
     if (!drvs.empty()) {
@@ -84,16 +84,19 @@ static void prim_scopedImport(EvalState & state, const Pos & pos, Value * * args
         Derivation drv = readDerivation(path);
         Value & w = *state.allocValue();
         state.mkAttrs(w, 2 + drv.outputs.size());
-        mkString(*state.allocAttr(w, state.sDrvPath), path, singleton<PathSet>("=" + path));
-        state.mkList(*state.allocAttr(w, state.symbols.create("outputs")), drv.outputs.size());
+        Value * v2 = state.allocAttr(w, state.sDrvPath);
+        mkString(*v2, path, singleton<PathSet>("=" + path));
+        Value * outputsVal =
+            state.allocAttr(w, state.symbols.create("outputs"));
+        state.mkList(*outputsVal, drv.outputs.size());
         unsigned int outputs_index = 0;
 
-        Value * outputsVal = w.attrs->find(state.symbols.create("outputs"))->value;
-        foreach (DerivationOutputs::iterator, i, drv.outputs) {
-            mkString(*state.allocAttr(w, state.symbols.create(i->first)),
-                i->second.path, singleton<PathSet>("!" + i->first + "!" + path));
-            mkString(*(outputsVal->list.elems[outputs_index++] = state.allocValue()),
-                i->first);
+        for (const auto & o : drv.outputs) {
+            v2 = state.allocAttr(w, state.symbols.create(o.first));
+            mkString(*v2, o.second.path,
+                singleton<PathSet>("!" + o.first + "!" + path));
+            outputsVal->list.elems[outputs_index] = state.allocValue();
+            mkString(*(outputsVal->list.elems[outputs_index++]), o.first);
         }
         w.attrs->sort();
         Value fun;
@@ -184,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));
@@ -411,32 +417,6 @@ static void prim_trace(EvalState & state, const Pos & pos, Value * * args, Value
 }
 
 
-#if HAVE_BOEHMGC
-void canaryFinalizer(GC_PTR obj, GC_PTR client_data)
-{
-    Value * v = (Value *) obj;
-    EvalState & state(* (EvalState *) client_data);
-    printMsg(lvlError, format("canary ‘%1%’ garbage-collected") % v->string.s);
-    auto i = state.gcCanaries.find(v);
-    assert(i != state.gcCanaries.end());
-    state.gcCanaries.erase(i);
-}
-#endif
-
-
-void prim_gcCanary(EvalState & state, const Pos & pos, Value * * args, Value & v)
-{
-    string s = state.forceStringNoCtx(*args[0], pos);
-    state.mkList(v, 1);
-    Value * canary = v.list.elems[0] = state.allocValue();
-#if HAVE_BOEHMGC
-    state.gcCanaries.insert(canary);
-    GC_register_finalizer(canary, canaryFinalizer, &state, 0, 0);
-#endif
-    mkString(*canary, s);
-}
-
-
 void prim_valueSize(EvalState & state, const Pos & pos, Value * * args, Value & v)
 {
     /* We're not forcing the argument on purpose. */
@@ -750,8 +730,12 @@ static void prim_readFile(EvalState & state, const Pos & pos, Value * * args, Va
 {
     PathSet context;
     Path path = state.coerceToPath(pos, *args[0], context);
-    if (!context.empty())
-        throw EvalError(format("string ‘%1%’ cannot refer to other paths, at %2%") % path % pos);
+    try {
+        realiseContext(context);
+    } catch (InvalidPathError & e) {
+        throw EvalError(format("cannot read ‘%1%’, since path ‘%2%’ is not valid, at %3%")
+            % path % e.path % pos);
+    }
     mkString(v, readFile(path).c_str());
 }
 
@@ -791,7 +775,7 @@ static void prim_findFile(EvalState & state, const Pos & pos, Value * * args, Va
             % path % e.path % pos);
     }
 
-    mkPath(v, state.findFile(searchPath, path).c_str());
+    mkPath(v, state.findFile(searchPath, path, pos).c_str());
 }
 
 /* Read a directory (without . or ..) */
@@ -812,7 +796,7 @@ static void prim_readDir(EvalState & state, const Pos & pos, Value * * args, Val
     for (auto & ent : entries) {
         Value * ent_val = state.allocAttr(v, state.symbols.create(ent.name));
         if (ent.type == DT_UNKNOWN)
-            ent.type = getFileType(path);
+            ent.type = getFileType(path + "/" + ent.name);
         mkStringNoCopy(*ent_val,
             ent.type == DT_REG ? "regular" :
             ent.type == DT_DIR ? "directory" :
@@ -867,7 +851,7 @@ static void prim_toFile(EvalState & state, const Pos & pos, Value * * args, Valu
 {
     PathSet context;
     string name = state.forceStringNoCtx(*args[0], pos);
-    string contents = state.forceString(*args[1], context);
+    string contents = state.forceString(*args[1], context, pos);
 
     PathSet refs;
 
@@ -1424,10 +1408,37 @@ static void prim_hashString(EvalState & state, const Pos & pos, Value * * args,
       throw Error(format("unknown hash type ‘%1%’, at %2%") % type % pos);
 
     PathSet context; // discarded
-    string s = state.forceString(*args[1], context);
+    string s = state.forceString(*args[1], context, pos);
 
     mkString(v, printHash(hashString(ht, s)), context);
-};
+}
+
+
+/* Match a regular expression against a string and return either
+   ‘null’ or a list containing substring matches. */
+static void prim_match(EvalState & state, const Pos & pos, Value * * args, Value & v)
+{
+    Regex regex(state.forceStringNoCtx(*args[0], pos), true);
+
+    PathSet context;
+    string s = state.forceString(*args[1], context, pos);
+
+    Regex::Subs subs;
+    if (!regex.matches(s, subs)) {
+        mkNull(v);
+        return;
+    }
+
+    unsigned int len = subs.empty() ? 0 : subs.rbegin()->first + 1;
+    state.mkList(v, len);
+    for (unsigned int n = 0; n < len; ++n) {
+        auto i = subs.find(n);
+        if (i == subs.end())
+            mkNull(*(v.list.elems[n] = state.allocValue()));
+        else
+            mkString(*(v.list.elems[n] = state.allocValue()), i->second);
+    }
+}
 
 
 /*************************************************************
@@ -1523,7 +1534,6 @@ void EvalState::createBaseEnv()
 
     // Debugging
     addPrimOp("__trace", 2, prim_trace);
-    addPrimOp("__gcCanary", 1, prim_gcCanary);
     addPrimOp("__valueSize", 1, prim_valueSize);
 
     // Paths
@@ -1581,6 +1591,7 @@ void EvalState::createBaseEnv()
     addPrimOp("__unsafeDiscardStringContext", 1, prim_unsafeDiscardStringContext);
     addPrimOp("__unsafeDiscardOutputDependency", 1, prim_unsafeDiscardOutputDependency);
     addPrimOp("__hashString", 2, prim_hashString);
+    addPrimOp("__match", 2, prim_match);
 
     // Versions
     addPrimOp("__parseDrvName", 1, prim_parseDrvName);