Author: eelco
Date: Wed Jul  6 10:58:17 2011
New Revision: 27614
URL: https://svn.nixos.org/websvn/nix/?rev=27614&sc=1

Log:
* 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.

Modified:
   nix/trunk/src/libexpr/eval.cc
   nix/trunk/src/libexpr/nixexpr.cc
   nix/trunk/src/libexpr/nixexpr.hh
   nix/trunk/src/libexpr/parser.y

Modified: nix/trunk/src/libexpr/eval.cc
==============================================================================
--- nix/trunk/src/libexpr/eval.cc       Tue Jul  5 15:14:44 2011        (r27613)
+++ nix/trunk/src/libexpr/eval.cc       Wed Jul  6 10:58:17 2011        (r27614)
@@ -656,9 +656,25 @@
 
 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);
 }
 
 

Modified: nix/trunk/src/libexpr/nixexpr.cc
==============================================================================
--- nix/trunk/src/libexpr/nixexpr.cc    Tue Jul  5 15:14:44 2011        (r27613)
+++ nix/trunk/src/libexpr/nixexpr.cc    Wed Jul  6 10:58:17 2011        (r27614)
@@ -48,7 +48,7 @@
 
 void ExprOpHasAttr::show(std::ostream & str)
 {
-    str << "(" << *e << ") ? " << name;
+    str << "(" << *e << ") ? " << showAttrPath(attrPath);
 }
 
 void ExprAttrs::show(std::ostream & str)
@@ -140,6 +140,17 @@
 }
 
 
+string showAttrPath(const AttrPath & attrPath)
+{
+    string s;
+    foreach (AttrPath::const_iterator, i, attrPath) {
+        if (!s.empty()) s += '.';
+        s += *i;
+    }
+    return s;
+}
+
+
 Pos noPos;
 
 

Modified: nix/trunk/src/libexpr/nixexpr.hh
==============================================================================
--- nix/trunk/src/libexpr/nixexpr.hh    Tue Jul  5 15:14:44 2011        (r27613)
+++ nix/trunk/src/libexpr/nixexpr.hh    Wed Jul  6 10:58:17 2011        (r27614)
@@ -40,6 +40,12 @@
 struct StaticEnv;
 
 
+/* An attribute path is a sequence of attribute names. */
+typedef vector<Symbol> AttrPath;
+
+string showAttrPath(const AttrPath & attrPath);
+
+
 /* Abstract syntax of Nix expressions. */
 
 struct Expr
@@ -124,8 +130,8 @@
 struct ExprOpHasAttr : Expr
 {
     Expr * e;
-    Symbol name;
-    ExprOpHasAttr(Expr * e, const Symbol & name) : e(e), name(name) { };
+    AttrPath attrPath;
+    ExprOpHasAttr(Expr * e, const AttrPath & attrPath) : e(e), 
attrPath(attrPath) { };
     COMMON_METHODS
 };
 

Modified: nix/trunk/src/libexpr/parser.y
==============================================================================
--- nix/trunk/src/libexpr/parser.y      Tue Jul  5 15:14:44 2011        (r27613)
+++ nix/trunk/src/libexpr/parser.y      Wed Jul  6 10:58:17 2011        (r27614)
@@ -61,18 +61,7 @@
 namespace nix {
     
 
-static string showAttrPath(const vector<Symbol> & attrPath)
-{
-    string s;
-    foreach (vector<Symbol>::const_iterator, i, attrPath) {
-        if (!s.empty()) s += '.';
-        s += *i;
-    }
-    return s;
-}
-
-
-static void dupAttr(const vector<Symbol> & attrPath, const Pos & pos, const 
Pos & prevPos)
+static void dupAttr(const AttrPath & attrPath, const Pos & pos, const Pos & 
prevPos)
 {
     throw ParseError(format("attribute `%1%' at %2% already defined at %3%")
         % showAttrPath(attrPath) % pos % prevPos);
@@ -81,17 +70,17 @@
 
 static void dupAttr(Symbol attr, const Pos & pos, const Pos & prevPos)
 {
-    vector<Symbol> attrPath; attrPath.push_back(attr);
+    AttrPath attrPath; attrPath.push_back(attr);
     throw ParseError(format("attribute `%1%' at %2% already defined at %3%")
         % showAttrPath(attrPath) % pos % prevPos);
 }
  
 
-static void addAttr(ExprAttrs * attrs, const vector<Symbol> & attrPath,
+static void addAttr(ExprAttrs * attrs, AttrPath & attrPath,
     Expr * e, const Pos & pos)
 {
     unsigned int n = 0;
-    foreach (vector<Symbol>::const_iterator, i, attrPath) {
+    foreach (AttrPath::const_iterator, i, attrPath) {
         n++;
         ExprAttrs::AttrDefs::iterator j = attrs->attrs.find(*i);
         if (j != attrs->attrs.end()) {
@@ -238,6 +227,7 @@
 %}
 
 %union {
+  // !!! We're probably leaking stuff here.  
   nix::Expr * e;
   nix::ExprList * list;
   nix::ExprAttrs * attrs;
@@ -317,7 +307,7 @@
   | expr_op OR expr_op { $$ = new ExprOpOr($1, $3); }
   | expr_op IMPL expr_op { $$ = new ExprOpImpl($1, $3); }
   | expr_op UPDATE expr_op { $$ = new ExprOpUpdate($1, $3); }
-  | expr_op '?' ID { $$ = new ExprOpHasAttr($1, data->symbols.create($3)); }
+  | expr_op '?' attrpath { $$ = new ExprOpHasAttr($1, *$3); }
   | expr_op '+' expr_op
     { vector<Expr *> * l = new vector<Expr *>;
       l->push_back($1);
@@ -382,7 +372,7 @@
   : binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, makeCurPos(@2, 
data)); }
   | binds INHERIT ids ';'
     { $$ = $1;
-      foreach (vector<Symbol>::iterator, i, *$3) {
+      foreach (AttrPath::iterator, i, *$3) {
           if ($$->attrs.find(*i) != $$->attrs.end())
               dupAttr(*i, makeCurPos(@3, data), $$->attrs[*i].pos);
           Pos pos = makeCurPos(@3, data);
@@ -392,7 +382,7 @@
   | binds INHERIT '(' expr ')' ids ';'
     { $$ = $1;
       /* !!! Should ensure sharing of the expression in $4. */
-      foreach (vector<Symbol>::iterator, i, *$6) {
+      foreach (AttrPath::iterator, i, *$6) {
           if ($$->attrs.find(*i) != $$->attrs.end())
               dupAttr(*i, makeCurPos(@6, data), $$->attrs[*i].pos);
           $$->attrs[*i] = ExprAttrs::AttrDef(new ExprSelect($4, *i), 
makeCurPos(@6, data));
_______________________________________________
nix-commits mailing list
[email protected]
http://mail.cs.uu.nl/mailman/listinfo/nix-commits

Reply via email to