about summary refs log tree commit diff
path: root/src/libexpr/eval.cc
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2011-07-06T10·58+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2011-07-06T10·58+0000
commit56370378023fc84eb0153b991f4138f6acd011e3 (patch)
tree19034285effef61c373eef092e91f717c4cea020 /src/libexpr/eval.cc
parent34f4b91820796381d04c6e00ea5e805cf53d25da (diff)
* In the ‘?’ operator, allow attribute paths. For instance, you can
  write ‘attrs ? a.b’ to test whether ‘attrs’ has an attribute ‘a’
  containing an attribute ‘b’.  This is more convenient than ‘attrs ?
  a && attrs.a ? b’.

  Slight change in the semantics: it's no longer an error if the
  left-hand side of ‘?’ is not an attribute set.  In that case it just
  returns false.  So, ‘null ? foo’ no longer throws an error.

Diffstat (limited to 'src/libexpr/eval.cc')
-rw-r--r--src/libexpr/eval.cc22
1 files changed, 19 insertions, 3 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 949f45e787..c307f2a420 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -656,9 +656,25 @@ void ExprSelect::eval(EvalState & state, Env & env, Value & v)
 
 void ExprOpHasAttr::eval(EvalState & state, Env & env, Value & v)
 {
-    Value vAttrs;
-    state.evalAttrs(env, e, vAttrs);
-    mkBool(v, vAttrs.attrs->find(name) != vAttrs.attrs->end());
+    Value vTmp;
+    Value * vAttrs = &vTmp;
+
+    state.eval(env, e, vTmp);
+
+    foreach (AttrPath::const_iterator, i, attrPath) {
+        state.forceValue(*vAttrs);
+        Bindings::iterator j;
+        if (vAttrs->type != tAttrs ||
+            (j = vAttrs->attrs->find(*i)) == vAttrs->attrs->end())
+        {
+            mkBool(v, false);
+            return;
+        } else {
+            vAttrs = j->value;
+        }
+    }
+    
+    mkBool(v, true);
 }