Author: eelco
Date: Wed Jul 13 12:19:57 2011
New Revision: 27756
URL: https://svn.nixos.org/websvn/nix/?rev=27756&sc=1

Log:
* Allow a default value in attribute selection by writing

    x.y.z or default

  (as originally proposed in
  https://mail.cs.uu.nl/pipermail/nix-dev/2009-September/002989.html).

  For instance, an expression like

    stdenv.lib.attrByPath ["features" "ckSched"] false args

  can now be written as

    args.features.ckSched or false

Added:
   nix/trunk/tests/lang/eval-okay-attrs5.exp
   nix/trunk/tests/lang/eval-okay-attrs5.nix
Modified:
   nix/trunk/doc/manual/release-notes.xml
   nix/trunk/misc/emacs/nix-mode.el
   nix/trunk/src/libexpr/eval.cc
   nix/trunk/src/libexpr/lexer.l
   nix/trunk/src/libexpr/nixexpr.cc
   nix/trunk/src/libexpr/nixexpr.hh
   nix/trunk/src/libexpr/parser.y

Modified: nix/trunk/doc/manual/release-notes.xml
==============================================================================
--- nix/trunk/doc/manual/release-notes.xml      Wed Jul 13 12:18:25 2011        
(r27755)
+++ nix/trunk/doc/manual/release-notes.xml      Wed Jul 13 12:19:57 2011        
(r27756)
@@ -32,6 +32,10 @@
     <literal>--max-silent-time</literal> is ineffective.</para>
   </listitem>
 
+  <listitem>
+    <para>TODO: “or” keyword.</para>
+  </listitem>
+
 </itemizedlist>
 
 </section>

Modified: nix/trunk/misc/emacs/nix-mode.el
==============================================================================
--- nix/trunk/misc/emacs/nix-mode.el    Wed Jul 13 12:18:25 2011        (r27755)
+++ nix/trunk/misc/emacs/nix-mode.el    Wed Jul 13 12:19:57 2011        (r27756)
@@ -67,7 +67,7 @@
 
 (defvar nix-keywords
   '("\\<if\\>" "\\<then\\>" "\\<else\\>" "\\<assert\\>" "\\<with\\>"
-    "\\<let\\>" "\\<in\\>" "\\<rec\\>" "\\<inherit\\>"
+    "\\<let\\>" "\\<in\\>" "\\<rec\\>" "\\<inherit\\>" "\\<or\\>"
     ("\\<true\\>" . font-lock-builtin-face)
     ("\\<false\\>" . font-lock-builtin-face)
     ("\\<null\\>" . font-lock-builtin-face)

Modified: nix/trunk/src/libexpr/eval.cc
==============================================================================
--- nix/trunk/src/libexpr/eval.cc       Wed Jul 13 12:18:25 2011        (r27755)
+++ nix/trunk/src/libexpr/eval.cc       Wed Jul 13 12:19:57 2011        (r27756)
@@ -632,7 +632,6 @@
 
 
 unsigned long nrLookups = 0;
-unsigned long nrLookupSize = 0;
 
 void ExprSelect::eval(EvalState & state, Env & env, Value & v)
 {
@@ -646,11 +645,20 @@
         
         foreach (AttrPath::const_iterator, i, attrPath) {
             nrLookups++;
-            state.forceAttrs(*vAttrs);
-            nrLookupSize += vAttrs->attrs->size();
             Bindings::iterator j;
-            if ((j = vAttrs->attrs->find(*i)) == vAttrs->attrs->end())
-                throwEvalError("attribute `%1%' missing", 
showAttrPath(attrPath));
+            if (def) {
+                state.forceValue(*vAttrs);
+                if (vAttrs->type != tAttrs ||
+                    (j = vAttrs->attrs->find(*i)) == vAttrs->attrs->end())
+                {
+                    state.eval(env, def, v);
+                    return;
+                }
+            } else {
+                state.forceAttrs(*vAttrs);
+                if ((j = vAttrs->attrs->find(*i)) == vAttrs->attrs->end())
+                    throwEvalError("attribute `%1%' missing", 
showAttrPath(attrPath));
+            }
             vAttrs = j->value;
             pos = j->pos;
         }
@@ -1270,7 +1278,6 @@
     printMsg(v, format("  number of thunks: %1%") % nrThunks);
     printMsg(v, format("  number of thunks avoided: %1%") % nrAvoided);
     printMsg(v, format("  number of attr lookups: %1%") % nrLookups);
-    printMsg(v, format("  attr lookup size: %1%") % nrLookupSize);
 }
 
 

Modified: nix/trunk/src/libexpr/lexer.l
==============================================================================
--- nix/trunk/src/libexpr/lexer.l       Wed Jul 13 12:18:25 2011        (r27755)
+++ nix/trunk/src/libexpr/lexer.l       Wed Jul 13 12:19:57 2011        (r27756)
@@ -96,6 +96,7 @@
 in          { return IN; }
 rec         { return REC; }
 inherit     { return INHERIT; }
+or          { return OR_KW; }
 \.\.\.      { return ELLIPSIS; }
 
 \=\=        { return EQ; }

Modified: nix/trunk/src/libexpr/nixexpr.cc
==============================================================================
--- nix/trunk/src/libexpr/nixexpr.cc    Wed Jul 13 12:18:25 2011        (r27755)
+++ nix/trunk/src/libexpr/nixexpr.cc    Wed Jul 13 12:19:57 2011        (r27756)
@@ -44,6 +44,7 @@
 void ExprSelect::show(std::ostream & str)
 {
     str << "(" << *e << ")." << showAttrPath(attrPath);
+    if (def) str << " or " << *def;
 }
 
 void ExprOpHasAttr::show(std::ostream & str)
@@ -211,6 +212,7 @@
 void ExprSelect::bindVars(const StaticEnv & env)
 {
     e->bindVars(env);
+    if (def) def->bindVars(env);
 }
 
 void ExprOpHasAttr::bindVars(const StaticEnv & env)

Modified: nix/trunk/src/libexpr/nixexpr.hh
==============================================================================
--- nix/trunk/src/libexpr/nixexpr.hh    Wed Jul 13 12:18:25 2011        (r27755)
+++ nix/trunk/src/libexpr/nixexpr.hh    Wed Jul 13 12:19:57 2011        (r27756)
@@ -121,10 +121,10 @@
 
 struct ExprSelect : Expr
 {
-    Expr * e;
+    Expr * e, * def;
     AttrPath attrPath;
-    ExprSelect(Expr * e, const AttrPath & attrPath) : e(e), attrPath(attrPath) 
{ };
-    ExprSelect(Expr * e, const Symbol & name) : e(e) { 
attrPath.push_back(name); };
+    ExprSelect(Expr * e, const AttrPath & attrPath, Expr * def) : e(e), 
def(def), attrPath(attrPath) { };
+    ExprSelect(Expr * e, const Symbol & name) : e(e), def(0) { 
attrPath.push_back(name); };
     COMMON_METHODS
 };
 

Modified: nix/trunk/src/libexpr/parser.y
==============================================================================
--- nix/trunk/src/libexpr/parser.y      Wed Jul 13 12:18:25 2011        (r27755)
+++ nix/trunk/src/libexpr/parser.y      Wed Jul 13 12:19:57 2011        (r27756)
@@ -237,7 +237,7 @@
   char * id; // !!! -> Symbol
   char * path;
   char * uri;
-  std::vector<nix::Symbol> * ids;
+  std::vector<nix::Symbol> * attrNames;
   std::vector<nix::Expr *> * string_parts;
 }
 
@@ -247,14 +247,15 @@
 %type <attrs> binds
 %type <formals> formals
 %type <formal> formal
-%type <ids> ids attrpath
+%type <attrNames> attrs attrpath
 %type <string_parts> string_parts ind_string_parts
+%type <id> attr
 %token <id> ID ATTRPATH
 %token <e> STR IND_STR
 %token <n> INT
 %token <path> PATH
 %token <uri> URI
-%token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL
+%token IF THEN ELSE ASSERT WITH LET IN REC INHERIT EQ NEQ AND OR IMPL OR_KW
 %token DOLLAR_CURLY /* == ${ */
 %token IND_STRING_OPEN IND_STRING_CLOSE
 %token ELLIPSIS
@@ -326,7 +327,13 @@
 
 expr_select
   : expr_simple '.' attrpath
-    { $$ = new ExprSelect($1, *$3); }
+    { $$ = new ExprSelect($1, *$3, 0); }
+  | expr_simple '.' attrpath OR_KW expr_select
+    { $$ = new ExprSelect($1, *$3, $5); }
+  | /* Backwards compatibility: because Nixpkgs has a rarely used
+       function named ‘or’, allow stuff like ‘map or [...]’. */
+    expr_simple OR_KW
+    { $$ = new ExprApp($1, new ExprVar(data->symbols.create("or"))); }
   | expr_simple { $$ = $1; }
   ;
 
@@ -370,7 +377,7 @@
 
 binds
   : binds attrpath '=' expr ';' { $$ = $1; addAttr($$, *$2, $4, makeCurPos(@2, 
data)); }
-  | binds INHERIT ids ';'
+  | binds INHERIT attrs ';'
     { $$ = $1;
       foreach (AttrPath::iterator, i, *$3) {
           if ($$->attrs.find(*i) != $$->attrs.end())
@@ -379,26 +386,31 @@
           $$->attrs[*i] = ExprAttrs::AttrDef(*i, pos);
       }
     }
-  | binds INHERIT '(' expr ')' ids ';'
+  | binds INHERIT '(' expr ')' attrs ';'
     { $$ = $1;
       /* !!! Should ensure sharing of the expression in $4. */
       foreach (vector<Symbol>::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));
-      }}
-
+      }
+    }
   | { $$ = new ExprAttrs; }
   ;
 
-ids
-  : ids ID { $$ = $1; $1->push_back(data->symbols.create($2)); /* !!! 
dangerous */ }
+attrs
+  : attrs attr { $$ = $1; $1->push_back(data->symbols.create($2)); /* !!! 
dangerous */ }
   | { $$ = new vector<Symbol>; }
   ;
 
 attrpath
-  : attrpath '.' ID { $$ = $1; $1->push_back(data->symbols.create($3)); }
-  | ID { $$ = new vector<Symbol>; $$->push_back(data->symbols.create($1)); }
+  : attrpath '.' attr { $$ = $1; $1->push_back(data->symbols.create($3)); }
+  | attr { $$ = new vector<Symbol>; $$->push_back(data->symbols.create($1)); }
+  ;
+
+attr
+  : ID { $$ = $1; }
+  | OR_KW { $$ = "or"; }
   ;
 
 expr_list

Added: nix/trunk/tests/lang/eval-okay-attrs5.exp
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ nix/trunk/tests/lang/eval-okay-attrs5.exp   Wed Jul 13 12:19:57 2011        
(r27756)
@@ -0,0 +1 @@
+[ 123 "foo" 456 456 "foo" "xyzzy" "xyzzy" true ]

Added: nix/trunk/tests/lang/eval-okay-attrs5.nix
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ nix/trunk/tests/lang/eval-okay-attrs5.nix   Wed Jul 13 12:19:57 2011        
(r27756)
@@ -0,0 +1,21 @@
+with import ./lib.nix;
+
+let
+
+  as = { x.y.z = 123; a.b.c = 456; };
+
+  bs = { foo.bar = "foo"; };
+
+  or = x: y: x || y;
+  
+in
+  [ as.x.y.z
+    as.foo or "foo"
+    as.x.y.bla or as.a.b.c
+    as.a.b.c or as.x.y.z
+    as.x.y.bla or bs.foo.bar or "xyzzy"
+    as.x.y.bla or bs.bar.foo or "xyzzy"
+    123.bla or null.foo or "xyzzy"
+    # Backwards compatibility test.
+    (fold or [] [true false false])
+  ]
_______________________________________________
nix-commits mailing list
[email protected]
http://mail.cs.uu.nl/mailman/listinfo/nix-commits

Reply via email to