aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libexpr/eval.cc19
-rw-r--r--src/libexpr/eval.hh1
-rw-r--r--src/libexpr/primops.cc16
-rw-r--r--src/libexpr/value.hh7
-rw-r--r--tests/lang/eval-okay-getattrpos.exp1
-rw-r--r--tests/lang/eval-okay-getattrpos.nix6
6 files changed, 44 insertions, 6 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 7fb38c0fd..c2db006c1 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -410,6 +410,19 @@ void EvalState::mkThunk_(Value & v, Expr * expr)
}
+void EvalState::mkPos(Value & v, Pos * pos)
+{
+ if (pos) {
+ mkAttrs(v, 3);
+ mkString(*allocAttr(v, sFile), pos->file);
+ mkInt(*allocAttr(v, sLine), pos->line);
+ mkInt(*allocAttr(v, sColumn), pos->column);
+ v.attrs->sort();
+ } else
+ mkNull(v);
+}
+
+
/* Create a thunk for the delayed computation of the given expression
in the given environment. But if the expression is a variable,
then look it up right away. This significantly reduces the number
@@ -1044,11 +1057,7 @@ void ExprConcatStrings::eval(EvalState & state, Env & env, Value & v)
void ExprPos::eval(EvalState & state, Env & env, Value & v)
{
- state.mkAttrs(v, 3);
- mkString(*state.allocAttr(v, state.sFile), pos.file);
- mkInt(*state.allocAttr(v, state.sLine), pos.line);
- mkInt(*state.allocAttr(v, state.sColumn), pos.column);
- v.attrs->sort();
+ state.mkPos(v, &pos);
}
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index bcc029f5b..af408cd0b 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -243,6 +243,7 @@ public:
void mkList(Value & v, unsigned int length);
void mkAttrs(Value & v, unsigned int expected);
void mkThunk_(Value & v, Expr * expr);
+ void mkPos(Value & v, Pos * pos);
void concatLists(Value & v, unsigned int nrLists, Value * * lists);
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index 180a24dff..5f2a58454 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -776,6 +776,19 @@ void prim_getAttr(EvalState & state, Value * * args, Value & v)
}
+/* Return position information of the specified attribute. */
+void prim_unsafeGetAttrPos(EvalState & state, Value * * args, Value & v)
+{
+ string attr = state.forceStringNoCtx(*args[0]);
+ state.forceAttrs(*args[1]);
+ Bindings::iterator i = args[1]->attrs->find(state.symbols.create(attr));
+ if (i == args[1]->attrs->end())
+ mkNull(v);
+ else
+ state.mkPos(v, i->pos);
+}
+
+
/* Dynamic version of the `?' operator. */
static void prim_hasAttr(EvalState & state, Value * * args, Value & v)
{
@@ -1201,7 +1214,7 @@ void EvalState::createBaseEnv()
mkBool(v, false);
addConstant("false", v);
- v.type = tNull;
+ mkNull(v);
addConstant("null", v);
mkInt(v, time(0));
@@ -1252,6 +1265,7 @@ void EvalState::createBaseEnv()
// Sets
addPrimOp("__attrNames", 1, prim_attrNames);
addPrimOp("__getAttr", 2, prim_getAttr);
+ addPrimOp("__unsafeGetAttrPos", 2, prim_unsafeGetAttrPos);
addPrimOp("__hasAttr", 2, prim_hasAttr);
addPrimOp("__isAttrs", 1, prim_isAttrs);
addPrimOp("removeAttrs", 2, prim_removeAttrs);
diff --git a/src/libexpr/value.hh b/src/libexpr/value.hh
index ee5c7397b..982582793 100644
--- a/src/libexpr/value.hh
+++ b/src/libexpr/value.hh
@@ -116,6 +116,13 @@ static inline void mkBool(Value & v, bool b)
}
+static inline void mkNull(Value & v)
+{
+ v.type = tNull;
+ v.app.left = v.app.right = 00; // scrub
+}
+
+
static inline void mkApp(Value & v, Value & left, Value & right)
{
v.type = tApp;
diff --git a/tests/lang/eval-okay-getattrpos.exp b/tests/lang/eval-okay-getattrpos.exp
new file mode 100644
index 000000000..469249bbc
--- /dev/null
+++ b/tests/lang/eval-okay-getattrpos.exp
@@ -0,0 +1 @@
+{ column = 5; file = "eval-okay-getattrpos.nix"; line = 3; }
diff --git a/tests/lang/eval-okay-getattrpos.nix b/tests/lang/eval-okay-getattrpos.nix
new file mode 100644
index 000000000..ca6b07961
--- /dev/null
+++ b/tests/lang/eval-okay-getattrpos.nix
@@ -0,0 +1,6 @@
+let
+ as = {
+ foo = "bar";
+ };
+ pos = builtins.unsafeGetAttrPos "foo" as;
+in { inherit (pos) column line; file = baseNameOf pos.file; }