* 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}'.
			
			
This commit is contained in:
		
							parent
							
								
									d9f30fe7c7
								
							
						
					
					
						commit
						1c9c0a5a46
					
				
					 6 changed files with 78 additions and 41 deletions
				
			
		|  | @ -55,15 +55,15 @@ static Expr substArgs(Expr body, ATermList formals, Expr arg) | ||||||
| /* Transform a mutually recursive set into a non-recursive set.  Each
 | /* Transform a mutually recursive set into a non-recursive set.  Each
 | ||||||
|    attribute is transformed into an expression that has all references |    attribute is transformed into an expression that has all references | ||||||
|    to attributes substituted with selection expressions on the |    to attributes substituted with selection expressions on the | ||||||
|    original set.  E.g., e = `rec {x = f x y, y = x}' becomes `{x = f |    original set.  E.g., e = `rec {x = f x y; y = x;}' becomes `{x = f | ||||||
|    (e.x) (e.y), y = e.x}'. */ |    (e.x) (e.y); y = e.x;}'. */ | ||||||
| ATerm expandRec(ATerm e, ATermList bnds) | ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds) | ||||||
| { | { | ||||||
|     ATMatcher m; |     ATMatcher m; | ||||||
| 
 | 
 | ||||||
|     /* Create the substitution list. */ |     /* Create the substitution list. */ | ||||||
|     ATermMap subs; |     ATermMap subs; | ||||||
|     for (ATermIterator i(bnds); i; ++i) { |     for (ATermIterator i(rbnds); i; ++i) { | ||||||
|         string s; |         string s; | ||||||
|         Expr e2; |         Expr e2; | ||||||
|         if (!(atMatch(m, *i) >> "Bind" >> s >> e2)) |         if (!(atMatch(m, *i) >> "Bind" >> s >> e2)) | ||||||
|  | @ -73,7 +73,7 @@ ATerm expandRec(ATerm e, ATermList bnds) | ||||||
| 
 | 
 | ||||||
|     /* Create the non-recursive set. */ |     /* Create the non-recursive set. */ | ||||||
|     ATermMap as; |     ATermMap as; | ||||||
|     for (ATermIterator i(bnds); i; ++i) { |     for (ATermIterator i(rbnds); i; ++i) { | ||||||
|         string s; |         string s; | ||||||
|         Expr e2; |         Expr e2; | ||||||
|         if (!(atMatch(m, *i) >> "Bind" >> s >> e2)) |         if (!(atMatch(m, *i) >> "Bind" >> s >> e2)) | ||||||
|  | @ -81,6 +81,15 @@ ATerm expandRec(ATerm e, ATermList bnds) | ||||||
|         as.set(s, substitute(subs, e2)); |         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); |     return makeAttrs(as); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -175,14 +184,9 @@ Expr evalExpr2(EvalState & state, Expr e) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Mutually recursive sets. */ |     /* Mutually recursive sets. */ | ||||||
|     ATermList bnds; |     ATermList rbnds, nrbnds; | ||||||
|     if (atMatch(m, e) >> "Rec" >> bnds) |     if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds) | ||||||
|         return expandRec(e, bnds); |         return expandRec(e, rbnds, nrbnds); | ||||||
| 
 |  | ||||||
|     /* 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)); |  | ||||||
| 
 | 
 | ||||||
|     /* Conditionals. */ |     /* Conditionals. */ | ||||||
|     if (atMatch(m, e) >> "If" >> e1 >> e2 >> e3) { |     if (atMatch(m, e) >> "If" >> e1 >> e2 >> e3) { | ||||||
|  |  | ||||||
|  | @ -50,6 +50,7 @@ else        { return ELSE; } | ||||||
| assert      { return ASSERT; } | assert      { return ASSERT; } | ||||||
| let         { return LET; } | let         { return LET; } | ||||||
| rec         { return REC; } | rec         { return REC; } | ||||||
|  | inherit     { return INHERIT; } | ||||||
| 
 | 
 | ||||||
| \=\=        { return EQ; } | \=\=        { return EQ; } | ||||||
| \!\=        { return NEQ; } | \!\=        { return NEQ; } | ||||||
|  |  | ||||||
|  | @ -181,16 +181,18 @@ Expr substitute(const ATermMap & subs, Expr e) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /* Idem for a mutually recursive attribute set. */ |     /* Idem for a mutually recursive attribute set. */ | ||||||
|     ATermList bindings; |     ATermList rbnds, nrbnds; | ||||||
|     if (atMatch(m, e) >> "Rec" >> bindings) { |     if (atMatch(m, e) >> "Rec" >> rbnds >> nrbnds) { | ||||||
|         ATermMap subs2(subs); |         ATermMap subs2(subs); | ||||||
|         for (ATermIterator i(bindings); i; ++i) { |         for (ATermIterator i(rbnds); i; ++i) { | ||||||
|             Expr e; |             Expr e; | ||||||
|             if (!(atMatch(m, *i) >> "Bind" >> s >> e)) |             if (!(atMatch(m, *i) >> "Bind" >> s >> e)) | ||||||
|                 abort(); /* can't happen */ |                 abort(); /* can't happen */ | ||||||
|             subs2.remove(s); |             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) { |     if (ATgetType(e) == AT_APPL) { | ||||||
|  |  | ||||||
|  | @ -17,32 +17,52 @@ struct ParseData | ||||||
|     string error; |     string error; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| extern "C" { | extern "C" { | ||||||
| 
 | 
 | ||||||
| #include "parser-tab.h" | #include "parser-tab.h" | ||||||
| #include "lexer-tab.h" | #include "lexer-tab.h" | ||||||
|      |      | ||||||
|     /* Callbacks for getting from C to C++.  Due to a (small) bug in the
 | /* 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++ |    GLR code of Bison we cannot currently compile the parser as C++ | ||||||
|        code. */ |    code. */ | ||||||
| 
 | 
 | ||||||
|     void setParseResult(ParseData * data, ATerm t) | void setParseResult(ParseData * data, ATerm t) | ||||||
|     { | { | ||||||
|         data->result = 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(); | ||||||
|  | } | ||||||
|  |          | ||||||
|  | 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); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|     ATerm absParsedPath(ParseData * data, ATerm t) | int yyparse(yyscan_t scanner, ParseData * data); | ||||||
|     { |  | ||||||
|         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(); |  | ||||||
|     } |  | ||||||
|          |  | ||||||
|     int yyparse(yyscan_t scanner, ParseData * data); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ | ||||||
| void setParseResult(void * data, ATerm t); | void setParseResult(void * data, ATerm t); | ||||||
| void parseError(void * data, char * error, int line, int column); | void parseError(void * data, char * error, int line, int column); | ||||||
| ATerm absParsedPath(void * data, ATerm t); | ATerm absParsedPath(void * data, ATerm t); | ||||||
|  | ATerm fixAttrs(int recursive, ATermList as); | ||||||
| 
 | 
 | ||||||
| void yyerror(YYLTYPE * loc, yyscan_t scanner, void * data, char * s) | 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> start expr expr_function expr_assert expr_op | ||||||
| %type <t> expr_app expr_select expr_simple bind formal | %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 <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 | %nonassoc IMPL | ||||||
| %left OR | %left OR | ||||||
|  | @ -90,9 +91,14 @@ expr_simple | ||||||
|   | PATH { $$ = ATmake("Path(<term>)", absParsedPath(data, $1)); } |   | PATH { $$ = ATmake("Path(<term>)", absParsedPath(data, $1)); } | ||||||
|   | URI { $$ = ATmake("Uri(<term>)", $1); } |   | URI { $$ = ATmake("Uri(<term>)", $1); } | ||||||
|   | '(' expr ')' { $$ = $2; } |   | '(' expr ')' { $$ = $2; } | ||||||
|   | LET '{' binds '}' { $$ = ATmake("LetRec(<term>)", $3); } |   /* Let expressions `let {..., body = ...}' are just desugared | ||||||
|   | REC '{' binds '}' { $$ = ATmake("Rec(<term>)", $3); } |      into `(rec {..., body = ...}).body'. */ | ||||||
|   | '{' binds '}' { $$ = ATmake("Attrs(<term>)", $2); } |   | LET '{' binds '}' | ||||||
|  |     { $$ = ATmake("Select(<term>, \"body\")", fixAttrs(1, $3)); } | ||||||
|  |   | REC '{' binds '}' | ||||||
|  |     { $$ = fixAttrs(1, $3); } | ||||||
|  |   | '{' binds '}' | ||||||
|  |     { $$ = fixAttrs(0, $2); } | ||||||
|   | '[' expr_list ']' { $$ = ATmake("List(<term>)", $2); } |   | '[' expr_list ']' { $$ = ATmake("List(<term>)", $2); } | ||||||
|   | IF expr THEN expr ELSE expr |   | IF expr THEN expr ELSE expr | ||||||
|     { $$ = ATmake("If(<term>, <term>, <term>)", $2, $4, $6); } |     { $$ = ATmake("If(<term>, <term>, <term>)", $2, $4, $6); } | ||||||
|  | @ -106,8 +112,12 @@ binds | ||||||
| bind | bind | ||||||
|   : ID '=' expr ';' |   : ID '=' expr ';' | ||||||
|     { $$ = ATmake("Bind(<term>, <term>)", $1, $3); } |     { $$ = ATmake("Bind(<term>, <term>)", $1, $3); } | ||||||
|  |   | INHERIT ids ';' | ||||||
|  |     { $$ = ATmake("Inherit(<term>)", $2); } | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
|  | ids: ids ID { $$ = ATinsert($1, $2); } | { $$ = ATempty; }; | ||||||
|  | 
 | ||||||
| expr_list | expr_list | ||||||
|   : expr_select expr_list { $$ = ATinsert($2, $1); } |   : expr_select expr_list { $$ = ATinsert($2, $1); } | ||||||
|     /* yes, this is right-recursive, but it doesn't matter since |     /* yes, this is right-recursive, but it doesn't matter since | ||||||
|  |  | ||||||
|  | @ -96,7 +96,7 @@ static string processBinding(EvalState & state, Expr e, StoreExpr & ne) | ||||||
|         return st.str(); |         return st.str(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (atMatch(m, e) >> "Attrs" >> es) { |     if (atMatch(m, e) >> "Attrs") { | ||||||
|         Expr a = queryAttr(e, "type"); |         Expr a = queryAttr(e, "type"); | ||||||
|         if (a && evalString(state, a) == "derivation") { |         if (a && evalString(state, a) == "derivation") { | ||||||
|             a = queryAttr(e, "drvPath"); |             a = queryAttr(e, "drvPath"); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue