* New language feature: with expressions.
The expression `with E1; E2' evaluates to E2 with all bindings in
  the attribute set E1 substituted.  E.g.,
    with {x = 123;}; x
  evaluates to 123.  That is, the attribute set E1 is in scope in E2.
  This is particularly useful when importing files containing lots
  definitions.  E.g., instead of
    let {
      inherit (import ./foo.nix) a b c d e f;
      body = ... a ... f ...;
    }
  we can now say
    with import ./foo.nix;
    ... a ... f ...
  I.e., we don't have to say what variables should be brought into scope.
			
			
This commit is contained in:
		
							parent
							
								
									f4d44a0026
								
							
						
					
					
						commit
						37d7abd694
					
				
					 7 changed files with 61 additions and 27 deletions
				
			
		|  | @ -27,7 +27,7 @@ sub createLinks { | ||||||
|             $srcFile =~ /\/nix-support$/ || |             $srcFile =~ /\/nix-support$/ || | ||||||
|             $srcFile =~ /\/log$/) |             $srcFile =~ /\/log$/) | ||||||
|         { |         { | ||||||
|             # Do noting. |             # Do nothing. | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|         elsif (-d $srcFile) { |         elsif (-d $srcFile) { | ||||||
|  |  | ||||||
|  | @ -17,18 +17,12 @@ available for installation.</para> | ||||||
| <para>In Nix, different users can have different <quote>views</quote> | <para>In Nix, different users can have different <quote>views</quote> | ||||||
| on the set of installed applications.  That is, there might be lots of | on the set of installed applications.  That is, there might be lots of | ||||||
| applications present on the system (possibly in many different | applications present on the system (possibly in many different | ||||||
| versions), but users can have a specific selection of those | versions), but users can have a specific selection of those active — | ||||||
| active — where <quote>active</quote> just means that it appears | where <quote>active</quote> just means that it appears in a directory | ||||||
| in a directory in the user's <envar>PATH</envar>.</para> | in the user's <envar>PATH</envar>.  Such a view on the set of | ||||||
| 
 | installed applications is called a <emphasis>user | ||||||
| <para>Such a view on the set of installed applications is called a | environment</emphasis>, which is just a directory tree consisting of | ||||||
| <emphasis>user environment</emphasis>, which is just a directory tree | symlinks to the files of the active applications.  </para> | ||||||
| consisting of symlinks to the files of the active applications.  In |  | ||||||
| Nix, operations such as upgrading or removing components never |  | ||||||
| overwrite or remove the files of those components, and they don't even |  | ||||||
| touch the user environments that point to them.  Rather, they cause a |  | ||||||
| <emphasis>new</emphasis> user environment to be constructed based on |  | ||||||
| the old one.</para> |  | ||||||
| 
 | 
 | ||||||
| <para>Components are installed from a set of <emphasis>Nix | <para>Components are installed from a set of <emphasis>Nix | ||||||
| expressions</emphasis> that tell Nix how to build those components, | expressions</emphasis> that tell Nix how to build those components, | ||||||
|  | @ -168,7 +162,21 @@ set.</para></footnote></para> | ||||||
| 
 | 
 | ||||||
| <sect1><title>Profiles</title> | <sect1><title>Profiles</title> | ||||||
| 
 | 
 | ||||||
| <para>Bla</para> | <para>In Nix, operations such as upgrading or removing components | ||||||
|  | never overwrite or remove the files of those components, and they | ||||||
|  | don't even touch the user environments that point to them.  Rather, | ||||||
|  | they cause a <emphasis>new</emphasis> user environment to be | ||||||
|  | constructed based on the old one.  This is illustrated in Figure | ||||||
|  | bla.</para> | ||||||
|  | 
 | ||||||
|  | <figure><title>User environments</title> | ||||||
|  |   <mediaobject> | ||||||
|  |     <imageobject> | ||||||
|  |       <imagedata fileref='figures/userenv-frame3.png' format='PNG' /> | ||||||
|  |     </imageobject> | ||||||
|  |   </mediaobject> | ||||||
|  | </figure> | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| </sect1> | </sect1> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -230,7 +230,7 @@ Expr evalExpr2(EvalState & state, Expr e) | ||||||
|             try { |             try { | ||||||
|                 return evalExpr(state, substArgs(e4, formals, e2)); |                 return evalExpr(state, substArgs(e4, formals, e2)); | ||||||
|             } catch (Error & e) { |             } catch (Error & e) { | ||||||
|                 throw Error(format("while evaluating function at %1%:\n%2%") |                 throw Error(format("while evaluating the function at %1%:\n%2%") | ||||||
|                     % showPos(pos) % e.msg()); |                     % showPos(pos) % e.msg()); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -241,7 +241,7 @@ Expr evalExpr2(EvalState & state, Expr e) | ||||||
|                 subs.set(name, e2); |                 subs.set(name, e2); | ||||||
|                 return evalExpr(state, substitute(subs, e4)); |                 return evalExpr(state, substitute(subs, e4)); | ||||||
|             } catch (Error & e) { |             } catch (Error & e) { | ||||||
|                 throw Error(format("while evaluating function at %1%:\n%2%") |                 throw Error(format("while evaluating the function at %1%:\n%2%") | ||||||
|                     % showPos(pos) % e.msg()); |                     % showPos(pos) % e.msg()); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  | @ -258,7 +258,7 @@ Expr evalExpr2(EvalState & state, Expr e) | ||||||
|         try { |         try { | ||||||
|             return evalExpr(state, a); |             return evalExpr(state, a); | ||||||
|         } catch (Error & e) { |         } catch (Error & e) { | ||||||
|             throw Error(format("while evaluating attribute `%1%' at %2%:\n%3%") |             throw Error(format("while evaluating the attribute `%1%' at %2%:\n%3%") | ||||||
|                 % s1 % showPos(pos) % e.msg()); |                 % s1 % showPos(pos) % e.msg()); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -283,6 +283,26 @@ Expr evalExpr2(EvalState & state, Expr e) | ||||||
|         return evalExpr(state, e2); |         return evalExpr(state, e2); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /* Withs. */ | ||||||
|  |     if (atMatch(m, e) >> "With" >> e1 >> e2 >> pos) { | ||||||
|  |         ATermMap attrs; | ||||||
|  |         try { | ||||||
|  |             e1 = evalExpr(state, e1); | ||||||
|  |             queryAllAttrs(e1, attrs); | ||||||
|  |         } catch (Error & e) { | ||||||
|  |             throw Error(format("while evaluating the `with' definitions at %1%:\n%2%") | ||||||
|  |                 % showPos(pos) % e.msg()); | ||||||
|  |         } | ||||||
|  |         try { | ||||||
|  |             e2 = substitute(attrs, e2); | ||||||
|  |             checkVarDefs(state.primOps, e2); | ||||||
|  |             return evalExpr(state, e2); | ||||||
|  |         } catch (Error & e) { | ||||||
|  |             throw Error(format("while evaluating the `with' body at %1%:\n%2%") | ||||||
|  |                 % showPos(pos) % e.msg()); | ||||||
|  |         }  | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /* Generic equality. */ |     /* Generic equality. */ | ||||||
|     if (atMatch(m, e) >> "OpEq" >> e1 >> e2) |     if (atMatch(m, e) >> "OpEq" >> e1 >> e2) | ||||||
|         return makeBool(evalExpr(state, e1) == evalExpr(state, e2)); |         return makeBool(evalExpr(state, e1) == evalExpr(state, e2)); | ||||||
|  | @ -357,7 +377,7 @@ Expr evalFile(EvalState & state, const Path & path) | ||||||
|     try { |     try { | ||||||
|         return evalExpr(state, e); |         return evalExpr(state, e); | ||||||
|     } catch (Error & e) { |     } catch (Error & e) { | ||||||
|         throw Error(format("while evaluating file `%1%':\n%2%") |         throw Error(format("while evaluating the file `%1%':\n%2%") | ||||||
|             % path % e.msg()); |             % path % e.msg()); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -48,6 +48,7 @@ if          { return IF; } | ||||||
| then        { return THEN; } | then        { return THEN; } | ||||||
| else        { return ELSE; } | else        { return ELSE; } | ||||||
| assert      { return ASSERT; } | assert      { return ASSERT; } | ||||||
|  | with        { return WITH; } | ||||||
| let         { return LET; } | let         { return LET; } | ||||||
| rec         { return REC; } | rec         { return REC; } | ||||||
| inherit     { return INHERIT; } | inherit     { return INHERIT; } | ||||||
|  |  | ||||||
|  | @ -296,7 +296,7 @@ void checkVarDefs(const ATermMap & defs, Expr e) | ||||||
|     ATMatcher m; |     ATMatcher m; | ||||||
|     ATerm name; |     ATerm name; | ||||||
|     ATermList formals; |     ATermList formals; | ||||||
|     ATerm body; |     ATerm with, body; | ||||||
|     ATermList rbnds, nrbnds; |     ATermList rbnds, nrbnds; | ||||||
| 
 | 
 | ||||||
|     if (atMatch(m, e) >> "Var" >> name) { |     if (atMatch(m, e) >> "Var" >> name) { | ||||||
|  | @ -340,6 +340,13 @@ void checkVarDefs(const ATermMap & defs, Expr e) | ||||||
|         } |         } | ||||||
|         checkVarDefs(defs2, (ATerm) rbnds); |         checkVarDefs(defs2, (ATerm) rbnds); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     else if (atMatch(m, e) >> "With" >> with >> body) { | ||||||
|  |         /* We can't check the body without evaluating the definitions
 | ||||||
|  |            (which is an arbitrary expression), so we don't do that | ||||||
|  |            here but only when actually evaluating the `with'. */ | ||||||
|  |         checkVarDefs(defs, with); | ||||||
|  |     } | ||||||
|      |      | ||||||
|     else if (ATgetType(e) == AT_APPL) { |     else if (ATgetType(e) == AT_APPL) { | ||||||
|         int arity = ATgetArity(ATgetAFun(e)); |         int arity = ATgetArity(ATgetAFun(e)); | ||||||
|  |  | ||||||
|  | @ -41,11 +41,11 @@ ATerm makePos(YYLTYPE * loc, void * data) | ||||||
|   ATermList ts; |   ATermList ts; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| %type <t> start expr expr_function expr_assert expr_if expr_op | %type <t> start expr expr_function expr_if expr_op | ||||||
| %type <t> expr_app expr_select expr_simple bind inheritsrc formal | %type <t> expr_app expr_select expr_simple bind inheritsrc formal | ||||||
| %type <ts> binds ids 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 INHERIT EQ NEQ AND OR IMPL | %token IF THEN ELSE ASSERT WITH LET REC INHERIT EQ NEQ AND OR IMPL | ||||||
| 
 | 
 | ||||||
| %nonassoc IMPL | %nonassoc IMPL | ||||||
| %left OR | %left OR | ||||||
|  | @ -67,12 +67,10 @@ expr_function | ||||||
|     { $$ = ATmake("Function(<term>, <term>, <term>)", $2, $5, CUR_POS); } |     { $$ = ATmake("Function(<term>, <term>, <term>)", $2, $5, CUR_POS); } | ||||||
|   | ID ':' expr_function |   | ID ':' expr_function | ||||||
|     { $$ = ATmake("Function1(<term>, <term>, <term>)", $1, $3, CUR_POS); } |     { $$ = ATmake("Function1(<term>, <term>, <term>)", $1, $3, CUR_POS); } | ||||||
|   | expr_assert |   | ASSERT expr ';' expr_function | ||||||
|   ; |  | ||||||
| 
 |  | ||||||
| expr_assert |  | ||||||
|   : ASSERT expr ';' expr_assert |  | ||||||
|     { $$ = ATmake("Assert(<term>, <term>, <term>)", $2, $4, CUR_POS); } |     { $$ = ATmake("Assert(<term>, <term>, <term>)", $2, $4, CUR_POS); } | ||||||
|  |   | WITH expr ';' expr_function | ||||||
|  |     { $$ = ATmake("With(<term>, <term>, <term>)", $2, $4, CUR_POS); } | ||||||
|   | expr_if |   | expr_if | ||||||
|   ; |   ; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -205,7 +205,7 @@ static Expr primDerivation(EvalState & state, const ATermVector & _args) | ||||||
|         try { |         try { | ||||||
|             processBinding(state, value, ne, ss); |             processBinding(state, value, ne, ss); | ||||||
|         } catch (Error & e) { |         } catch (Error & e) { | ||||||
|             throw Error(format("while processing derivation attribute `%1%' at %2%:\n%3%") |             throw Error(format("while processing the derivation attribute `%1%' at %2%:\n%3%") | ||||||
|                 % key % showPos(pos) % e.msg()); |                 % key % showPos(pos) % e.msg()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue