about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2004-02-02T21·39+0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2004-02-02T21·39+0000
commit1c9c0a5a46822be60c999f0196567c9e17cf5fa3 (patch)
tree6783413d7fd353fdd7562f47a2dc0aac132cd04d /src
parentd9f30fe7c74ae8518a575c0d15ee00aa46a2229a (diff)
* Added syntactic sugar to the construction of attribute sets to
  `inherit' variables from the surrounding lexical scope.

  E.g.,

    {stdenv, libfoo}: derivation {
      builder = ./bla;
      inherit stdenv libfoo;
      xyzzy = 1;
    }

  is equivalent to

    {stdenv, libfoo}: derivation {
      builder = ./bla;
      stdenv = stdenv;
      libfoo = libfoo;
      xyzzy = 1;
    }

  Note that for mutually recursive attribute set definitions (`rec
  {...}'), this also works, that is, `rec {inherit x;}' is equivalent
  to `let {fresh = x; body = rec {x = fresh;};}', *not*
  `rec {x = x}'.

Diffstat (limited to 'src')
-rw-r--r--src/libexpr/eval.cc30
-rw-r--r--src/libexpr/lexer.l1
-rw-r--r--src/libexpr/nixexpr.cc10
-rw-r--r--src/libexpr/parser.cc56
-rw-r--r--src/libexpr/parser.y20
-rw-r--r--src/libexpr/primops.cc2
6 files changed, 78 insertions, 41 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 77cab55d03..820e934a63 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -55,15 +55,15 @@ static Expr substArgs(Expr body, ATermList formals, Expr arg)
 /* Transform a mutually recursive set into a non-recursive set.  Each
    attribute is transformed into an expression that has all references
    to attributes substituted with selection expressions on the
-   original set.  E.g., e = `rec {x = f x y, y = x}' becomes `{x = f
-   (e.x) (e.y), y = e.x}'. */
-ATerm expandRec(ATerm e, ATermList bnds)
+   original set.  E.g., e = `rec {x = f x y; y = x;}' becomes `{x = f
+   (e.x) (e.y); y = e.x;}'. */
+ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds)
 {
     ATMatcher m;
 
     /* Create the substitution list. */
     ATermMap subs;
-    for (ATermIterator i(bnds); i; ++i) {
+    for (ATermIterator i(rbnds); i; ++i) {
         string s;
         Expr e2;
         if (!(atMatch(m, *i) >> "Bind" >> s >> e2))
@@ -73,7 +73,7 @@ ATerm expandRec(ATerm e, ATermList bnds)
 
     /* Create the non-recursive set. */
     ATermMap as;
-    for (ATermIterator i(bnds); i; ++i) {
+    for (ATermIterator i(rbnds); i; ++i) {
         string s;
         Expr e2;
         if (!(atMatch(m, *i) >> "Bind" >> s >> e2))
@@ -81,6 +81,15 @@ ATerm expandRec(ATerm e, ATermList bnds)
         as.set(s, substitute(subs, e2));
     }
 
+    /* Copy the non-recursive bindings.  !!! inefficient */
+    for (ATermIterator i(nrbnds); i; ++i) {
+        string s;
+        Expr e2;
+        if (!(atMatch(m, *i) >> "Bind" >> s >> e2))
+            abort(); /* can't happen */
+        as.set(s, e2);
+    }
+
     return makeAttrs(as);
 }
 
@@ -175,14 +184,9 @@ Expr evalExpr2(EvalState & state, Expr e)
     }
 
     /* Mutually recursive sets. */
-    ATermList bnds;
-    if (atMatch(m, e) >> "Rec" >> bnds)
-        return expandRec(e, bnds);
-
-    /* Let expressions `let {..., body = ...}' are just desugared
-       into `(rec {..., body = ...}).body'. */
-    if (atMatch(m, e) >> "LetRec" >> bnds)
-        return evalExpr(state, ATmake("Select(Rec(<term>), \"body\")", bnds));
+    ATermList rbnds, nrbnds;
+    if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds)
+        return expandRec(e, rbnds, nrbnds);
 
     /* Conditionals. */
     if (atMatch(m, e) >> "If" >> e1 >> e2 >> e3) {
diff --git a/src/libexpr/lexer.l b/src/libexpr/lexer.l
index 3b6e0bb657..853362cd0b 100644
--- a/src/libexpr/lexer.l
+++ b/src/libexpr/lexer.l
@@ -50,6 +50,7 @@ else        { return ELSE; }
 assert      { return ASSERT; }
 let         { return LET; }
 rec         { return REC; }
+inherit     { return INHERIT; }
 
 \=\=        { return EQ; }
 \!\=        { return NEQ; }
diff --git a/src/libexpr/nixexpr.cc b/src/libexpr/nixexpr.cc
index 7de3e823c4..b0f506e65d 100644
--- a/src/libexpr/nixexpr.cc
+++ b/src/libexpr/nixexpr.cc
@@ -181,16 +181,18 @@ Expr substitute(const ATermMap & subs, Expr e)
     }
 
     /* Idem for a mutually recursive attribute set. */
-    ATermList bindings;
-    if (atMatch(m, e) >> "Rec" >> bindings) {
+    ATermList rbnds, nrbnds;
+    if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds) {
         ATermMap subs2(subs);
-        for (ATermIterator i(bindings); i; ++i) {
+        for (ATermIterator i(rbnds); i; ++i) {
             Expr e;
             if (!(atMatch(m, *i) >> "Bind" >> s >> e))
                 abort(); /* can't happen */
             subs2.remove(s);
         }
-        return ATmake("Rec(<term>)", substitute(subs2, (ATerm) bindings));
+        return ATmake("Rec(<term>, <term>)",
+            substitute(subs2, (ATerm) rbnds),
+            substitute(subs, (ATerm) nrbnds));
     }
 
     if (ATgetType(e) == AT_APPL) {
diff --git a/src/libexpr/parser.cc b/src/libexpr/parser.cc
index 167c34bd83..2574a55bd4 100644
--- a/src/libexpr/parser.cc
+++ b/src/libexpr/parser.cc
@@ -17,32 +17,52 @@ struct ParseData
     string error;
 };
 
+
 extern "C" {
 
 #include "parser-tab.h"
 #include "lexer-tab.h"
     
-    /* Callbacks for getting from C to C++.  Due to a (small) bug in the
-       GLR code of Bison we cannot currently compile the parser as C++
-       code. */
-   
-    void setParseResult(ParseData * data, ATerm t)
-    {
-        data->result = t;
-    }
+/* Callbacks for getting from C to C++.  Due to a (small) bug in the
+   GLR code of Bison we cannot currently compile the parser as C++
+   code. */
 
-    ATerm absParsedPath(ParseData * data, ATerm t)
-    {
-        return string2ATerm(absPath(aterm2String(t), data->basePath).c_str());
-    }
+void setParseResult(ParseData * data, ATerm t)
+{
+    data->result = t;
+}
+
+ATerm absParsedPath(ParseData * data, ATerm t)
+{
+    return string2ATerm(absPath(aterm2String(t), data->basePath).c_str());
+}
     
-    void parseError(ParseData * data, char * error, int line, int column)
-    {
-        data->error = (format("%1%, at line %2%, column %3%, of %4%")
-            % error % line % column % data->location).str();
-    }
+void parseError(ParseData * data, char * error, int line, int column)
+{
+    data->error = (format("%1%, at line %2%, column %3%, of %4%")
+        % error % line % column % data->location).str();
+}
         
-    int yyparse(yyscan_t scanner, ParseData * data);
+ATerm fixAttrs(int recursive, ATermList as)
+{
+    ATMatcher m;
+    ATermList bs = ATempty, cs = ATempty;
+    ATermList * is = recursive ? &cs : &bs;
+    for (ATermIterator i(as); i; ++i) {
+        ATermList names;
+        if (atMatch(m, *i) >> "Inherit" >> names)
+            for (ATermIterator j(names); j; ++j)
+                *is = ATinsert(*is,
+                    ATmake("Bind(<term>, Var(<term>))", *j, *j));
+        else bs = ATinsert(bs, *i);
+    }
+    if (recursive)
+        return ATmake("Rec(<term>, <term>)", bs, cs);
+    else
+        return ATmake("Attrs(<term>)", bs);
+}
+
+int yyparse(yyscan_t scanner, ParseData * data);
 }
 
 
diff --git a/src/libexpr/parser.y b/src/libexpr/parser.y
index dc03117bb1..d97106fcae 100644
--- a/src/libexpr/parser.y
+++ b/src/libexpr/parser.y
@@ -18,6 +18,7 @@
 void setParseResult(void * data, ATerm t);
 void parseError(void * data, char * error, int line, int column);
 ATerm absParsedPath(void * data, ATerm t);
+ATerm fixAttrs(int recursive, ATermList as);
 
 void yyerror(YYLTYPE * loc, yyscan_t scanner, void * data, char * s)
 {
@@ -33,9 +34,9 @@ void yyerror(YYLTYPE * loc, yyscan_t scanner, void * data, char * s)
 
 %type <t> start expr expr_function expr_assert expr_op
 %type <t> expr_app expr_select expr_simple bind formal
-%type <ts> binds expr_list formals
+%type <ts> binds ids expr_list formals
 %token <t> ID INT STR PATH URI
-%token IF THEN ELSE ASSERT LET REC EQ NEQ AND OR IMPL
+%token IF THEN ELSE ASSERT LET REC INHERIT EQ NEQ AND OR IMPL
 
 %nonassoc IMPL
 %left OR
@@ -90,9 +91,14 @@ expr_simple
   | PATH { $$ = ATmake("Path(<term>)", absParsedPath(data, $1)); }
   | URI { $$ = ATmake("Uri(<term>)", $1); }
   | '(' expr ')' { $$ = $2; }
-  | LET '{' binds '}' { $$ = ATmake("LetRec(<term>)", $3); }
-  | REC '{' binds '}' { $$ = ATmake("Rec(<term>)", $3); }
-  | '{' binds '}' { $$ = ATmake("Attrs(<term>)", $2); }
+  /* Let expressions `let {..., body = ...}' are just desugared
+     into `(rec {..., body = ...}).body'. */
+  | LET '{' binds '}'
+    { $$ = ATmake("Select(<term>, \"body\")", fixAttrs(1, $3)); }
+  | REC '{' binds '}'
+    { $$ = fixAttrs(1, $3); }
+  | '{' binds '}'
+    { $$ = fixAttrs(0, $2); }
   | '[' expr_list ']' { $$ = ATmake("List(<term>)", $2); }
   | IF expr THEN expr ELSE expr
     { $$ = ATmake("If(<term>, <term>, <term>)", $2, $4, $6); }
@@ -106,8 +112,12 @@ binds
 bind
   : ID '=' expr ';'
     { $$ = ATmake("Bind(<term>, <term>)", $1, $3); }
+  | INHERIT ids ';'
+    { $$ = ATmake("Inherit(<term>)", $2); }
   ;
 
+ids: ids ID { $$ = ATinsert($1, $2); } | { $$ = ATempty; };
+
 expr_list
   : expr_select expr_list { $$ = ATinsert($2, $1); }
     /* yes, this is right-recursive, but it doesn't matter since
diff --git a/src/libexpr/primops.cc b/src/libexpr/primops.cc
index da6927d0fc..d1c398a348 100644
--- a/src/libexpr/primops.cc
+++ b/src/libexpr/primops.cc
@@ -96,7 +96,7 @@ static string processBinding(EvalState & state, Expr e, StoreExpr & ne)
         return st.str();
     }
 
-    if (atMatch(m, e) >> "Attrs" >> es) {
+    if (atMatch(m, e) >> "Attrs") {
         Expr a = queryAttr(e, "type");
         if (a && evalString(state, a) == "derivation") {
             a = queryAttr(e, "drvPath");