* 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 =~ /\/log$/) | ||||
|         { | ||||
|             # Do noting. | ||||
|             # Do nothing. | ||||
| 	} | ||||
| 
 | ||||
|         elsif (-d $srcFile) { | ||||
|  |  | |||
|  | @ -17,18 +17,12 @@ available for installation.</para> | |||
| <para>In Nix, different users can have different <quote>views</quote> | ||||
| on the set of installed applications.  That is, there might be lots of | ||||
| applications present on the system (possibly in many different | ||||
| versions), but users can have a specific selection of those | ||||
| active — where <quote>active</quote> just means that it appears | ||||
| in a directory in the user's <envar>PATH</envar>.</para> | ||||
| 
 | ||||
| <para>Such a view on the set of installed applications is called a | ||||
| <emphasis>user environment</emphasis>, which is just a directory tree | ||||
| 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> | ||||
| versions), but users can have a specific selection of those active — | ||||
| where <quote>active</quote> just means that it appears in a directory | ||||
| in the user's <envar>PATH</envar>.  Such a view on the set of | ||||
| installed applications is called a <emphasis>user | ||||
| environment</emphasis>, which is just a directory tree consisting of | ||||
| symlinks to the files of the active applications.  </para> | ||||
| 
 | ||||
| <para>Components are installed from a set of <emphasis>Nix | ||||
| expressions</emphasis> that tell Nix how to build those components, | ||||
|  | @ -168,7 +162,21 @@ set.</para></footnote></para> | |||
| 
 | ||||
| <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> | ||||
| 
 | ||||
|  |  | |||
|  | @ -230,7 +230,7 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
|             try { | ||||
|                 return evalExpr(state, substArgs(e4, formals, e2)); | ||||
|             } 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()); | ||||
|             } | ||||
|         } | ||||
|  | @ -241,7 +241,7 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
|                 subs.set(name, e2); | ||||
|                 return evalExpr(state, substitute(subs, e4)); | ||||
|             } 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()); | ||||
|             } | ||||
|         } | ||||
|  | @ -258,7 +258,7 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
|         try { | ||||
|             return evalExpr(state, a); | ||||
|         } 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()); | ||||
|         } | ||||
|     } | ||||
|  | @ -283,6 +283,26 @@ Expr evalExpr2(EvalState & state, Expr e) | |||
|         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. */ | ||||
|     if (atMatch(m, e) >> "OpEq" >> e1 >> e2) | ||||
|         return makeBool(evalExpr(state, e1) == evalExpr(state, e2)); | ||||
|  | @ -357,7 +377,7 @@ Expr evalFile(EvalState & state, const Path & path) | |||
|     try { | ||||
|         return evalExpr(state, 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()); | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -48,6 +48,7 @@ if          { return IF; } | |||
| then        { return THEN; } | ||||
| else        { return ELSE; } | ||||
| assert      { return ASSERT; } | ||||
| with        { return WITH; } | ||||
| let         { return LET; } | ||||
| rec         { return REC; } | ||||
| inherit     { return INHERIT; } | ||||
|  |  | |||
|  | @ -296,7 +296,7 @@ void checkVarDefs(const ATermMap & defs, Expr e) | |||
|     ATMatcher m; | ||||
|     ATerm name; | ||||
|     ATermList formals; | ||||
|     ATerm body; | ||||
|     ATerm with, body; | ||||
|     ATermList rbnds, nrbnds; | ||||
| 
 | ||||
|     if (atMatch(m, e) >> "Var" >> name) { | ||||
|  | @ -341,6 +341,13 @@ void checkVarDefs(const ATermMap & defs, Expr e) | |||
|         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) { | ||||
|         int arity = ATgetArity(ATgetAFun(e)); | ||||
|         for (int i = 0; i < arity; ++i) | ||||
|  |  | |||
|  | @ -41,11 +41,11 @@ ATerm makePos(YYLTYPE * loc, void * data) | |||
|   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 <ts> binds ids expr_list formals | ||||
| %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 | ||||
| %left OR | ||||
|  | @ -67,12 +67,10 @@ expr_function | |||
|     { $$ = ATmake("Function(<term>, <term>, <term>)", $2, $5, CUR_POS); } | ||||
|   | ID ':' expr_function | ||||
|     { $$ = ATmake("Function1(<term>, <term>, <term>)", $1, $3, CUR_POS); } | ||||
|   | expr_assert | ||||
|   ; | ||||
| 
 | ||||
| expr_assert | ||||
|   : ASSERT expr ';' expr_assert | ||||
|   | ASSERT expr ';' expr_function | ||||
|     { $$ = ATmake("Assert(<term>, <term>, <term>)", $2, $4, CUR_POS); } | ||||
|   | WITH expr ';' expr_function | ||||
|     { $$ = ATmake("With(<term>, <term>, <term>)", $2, $4, CUR_POS); } | ||||
|   | expr_if | ||||
|   ; | ||||
| 
 | ||||
|  |  | |||
|  | @ -205,7 +205,7 @@ static Expr primDerivation(EvalState & state, const ATermVector & _args) | |||
|         try { | ||||
|             processBinding(state, value, ne, ss); | ||||
|         } 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()); | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue