aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2004-02-02 21:39:33 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2004-02-02 21:39:33 +0000
commit1c9c0a5a46822be60c999f0196567c9e17cf5fa3 (patch)
tree6783413d7fd353fdd7562f47a2dc0aac132cd04d
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}'.
-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 77cab55d0..820e934a6 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 3b6e0bb65..853362cd0 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 7de3e823c..b0f506e65 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 167c34bd8..2574a55bd 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 dc03117bb..d97106fca 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 da6927d0f..d1c398a34 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");