diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc index 7fb38c0f..c2db006c 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 bcc029f5..af408cd0 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 180a24df..5f2a5845 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 ee5c7397..98258279 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 00000000..469249bb --- /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 00000000..ca6b0796 --- /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; }