* Another experimental feature: a way to truly override attributes in
a rec. This will be very useful to allow end-user customisation of all-packages.nix, for instance globally overriding GCC or some other dependency. The // operator doesn't cut it: you could replace the "gcc" attribute, but all other attributes would continue to reference the original value due to the substitution semantics of rec. The syntax is a bit hacky but this is to allow backwards compatibility.
This commit is contained in:
		
							parent
							
								
									9279174dde
								
							
						
					
					
						commit
						ca07f3e370
					
				
					 2 changed files with 25 additions and 2 deletions
				
			
		|  | @ -170,16 +170,18 @@ static Expr substArgs(EvalState & state, | ||||||
|    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;}'. */ | ||||||
| LocalNoInline(ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds)) | LocalNoInline(ATerm expandRec(EvalState & state, ATerm e, ATermList rbnds, ATermList nrbnds)) | ||||||
| { | { | ||||||
|     ATerm name; |     ATerm name; | ||||||
|     Expr e2; |     Expr e2; | ||||||
|     Pos pos; |     Pos pos; | ||||||
|  |     Expr eOverrides = 0; | ||||||
| 
 | 
 | ||||||
|     /* Create the substitution list. */ |     /* Create the substitution list. */ | ||||||
|     ATermMap subs(ATgetLength(rbnds) + ATgetLength(nrbnds)); |     ATermMap subs(ATgetLength(rbnds) + ATgetLength(nrbnds)); | ||||||
|     for (ATermIterator i(rbnds); i; ++i) { |     for (ATermIterator i(rbnds); i; ++i) { | ||||||
|         if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ |         if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ | ||||||
|  |         if (name == sOverrides) eOverrides = e2; | ||||||
|         subs.set(name, makeSelect(e, name)); |         subs.set(name, makeSelect(e, name)); | ||||||
|     } |     } | ||||||
|     for (ATermIterator i(nrbnds); i; ++i) { |     for (ATermIterator i(nrbnds); i; ++i) { | ||||||
|  | @ -187,6 +189,22 @@ LocalNoInline(ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds)) | ||||||
|         subs.set(name, e2); |         subs.set(name, e2); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /* If the rec contains an attribute called `__overrides', then
 | ||||||
|  |        evaluate it, and add the attributes in that set to the rec. | ||||||
|  |        This allows overriding of recursive attributes, which is | ||||||
|  |        otherwise not possible.  (You can use the // operator to
 | ||||||
|  |        replace an attribute, but other attributes in the rec will | ||||||
|  |        still reference the original value, because that value has been | ||||||
|  |        substituted into the bodies of the other attributes.  Hence we | ||||||
|  |        need __overrides.) */ | ||||||
|  |     ATermMap overrides; | ||||||
|  |     if (eOverrides) { | ||||||
|  |         eOverrides = evalExpr(state, eOverrides); | ||||||
|  |         queryAllAttrs(overrides, overrides, false); | ||||||
|  |         foreach (ATermMap::const_iterator, i, overrides) | ||||||
|  |             subs.set(i->key, i->value); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     Substitution subs_(0, &subs); |     Substitution subs_(0, &subs); | ||||||
| 
 | 
 | ||||||
|     /* Create the non-recursive set. */ |     /* Create the non-recursive set. */ | ||||||
|  | @ -196,6 +214,10 @@ LocalNoInline(ATerm expandRec(ATerm e, ATermList rbnds, ATermList nrbnds)) | ||||||
|         as.set(name, makeAttrRHS(substitute(subs_, e2), pos)); |         as.set(name, makeAttrRHS(substitute(subs_, e2), pos)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     if (eOverrides) | ||||||
|  |         foreach (ATermMap::const_iterator, i, overrides) | ||||||
|  |             as.set(i->key, makeAttrRHS(i->value, makeNoPos())); | ||||||
|  | 
 | ||||||
|     /* Copy the non-recursive bindings.  !!! inefficient */ |     /* Copy the non-recursive bindings.  !!! inefficient */ | ||||||
|     for (ATermIterator i(nrbnds); i; ++i) { |     for (ATermIterator i(nrbnds); i; ++i) { | ||||||
|         if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ |         if (!matchBind(*i, name, e2, pos)) abort(); /* can't happen */ | ||||||
|  | @ -667,7 +689,7 @@ Expr evalExpr2(EvalState & state, Expr e) | ||||||
|     /* Mutually recursive sets. */ |     /* Mutually recursive sets. */ | ||||||
|     ATermList rbnds, nrbnds; |     ATermList rbnds, nrbnds; | ||||||
|     if (matchRec(e, rbnds, nrbnds)) |     if (matchRec(e, rbnds, nrbnds)) | ||||||
|         return expandRec(e, rbnds, nrbnds); |         return expandRec(state, e, rbnds, nrbnds); | ||||||
| 
 | 
 | ||||||
|     /* Conditionals. */ |     /* Conditionals. */ | ||||||
|     if (matchIf(e, e1, e2, e3)) |     if (matchIf(e, e1, e2, e3)) | ||||||
|  |  | ||||||
|  | @ -93,3 +93,4 @@ AttrRHS | Expr Pos | ATerm | | ||||||
| 
 | 
 | ||||||
| eTrue = makeBool(makeTrue()) | eTrue = makeBool(makeTrue()) | ||||||
| eFalse = makeBool(makeFalse()) | eFalse = makeBool(makeFalse()) | ||||||
|  | sOverrides = toATerm("__overrides") | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue