chore(tvix/eval): move eval docs to tvix/docs
Change-Id: I75b33c43456389de6e521b4f0ad46d68bc9e98f6 Reviewed-on: https://cl.tvl.fyi/c/depot/+/11809 Autosubmit: flokli <flokli@flokli.de> Reviewed-by: tazjin <tazjin@tvl.su> Tested-by: BuildkiteCI
This commit is contained in:
		
							parent
							
								
									6947dc4349
								
							
						
					
					
						commit
						5077ca70de
					
				
					 12 changed files with 16 additions and 0 deletions
				
			
		|  | @ -1,68 +0,0 @@ | |||
| Recursive attribute sets | ||||
| ======================== | ||||
| 
 | ||||
| The construction behaviour of recursive attribute sets is very | ||||
| specific, and a bit peculiar. | ||||
| 
 | ||||
| In essence, there are multiple "phases" of scoping that take place | ||||
| during attribute set construction: | ||||
| 
 | ||||
| 1. Every inherited value without an explicit source is inherited only | ||||
|    from the **outer** scope in which the attribute set is enclosed. | ||||
| 
 | ||||
| 2. A new scope is opened in which all recursive keys are evaluated. | ||||
|    This only considers **statically known keys**, attributes can | ||||
|    **not** recurse into dynamic keys in `self`! | ||||
| 
 | ||||
|    For example, this code is invalid in C++ Nix: | ||||
| 
 | ||||
|    ``` | ||||
|    nix-repl> rec { ${"a"+""} = 2; b = a * 10; } | ||||
|    error: undefined variable 'a' at (string):1:26 | ||||
|    ``` | ||||
| 
 | ||||
| 3. Finally, a third scope is opened in which dynamic keys are | ||||
|    evaluated. | ||||
| 
 | ||||
| This behaviour, while possibly a bit strange and unexpected, actually | ||||
| simplifies the implementation of recursive attribute sets in Tvix as | ||||
| well. | ||||
| 
 | ||||
| Essentially, a recursive attribute set like this: | ||||
| 
 | ||||
| ```nix | ||||
| rec { | ||||
|   inherit a; | ||||
|   b = a * 10; | ||||
|   ${"c" + ""} = b * 2; | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| Can be compiled like the following expression: | ||||
| 
 | ||||
| ```nix | ||||
| let | ||||
|   inherit a; | ||||
| in let | ||||
|   b = a * 10; | ||||
|   in { | ||||
|     inherit a b; | ||||
|     ${"c" + ""} = b * 2; | ||||
|   } | ||||
| ``` | ||||
| 
 | ||||
| Completely deferring the resolution of recursive identifiers to the | ||||
| existing handling of recursive scopes (i.e. deferred access) in let | ||||
| bindings. | ||||
| 
 | ||||
| In practice, we can further specialise this and compile each scope | ||||
| directly into the form expected by `OpAttrs` (that is, leaving | ||||
| attribute names on the stack) before each value's position. | ||||
| 
 | ||||
| C++ Nix's Implementation | ||||
| ------------------------ | ||||
| 
 | ||||
| * [`ExprAttrs`](https://github.com/NixOS/nix/blob/2097c30b08af19a9b42705fbc07463bea60dfb5b/src/libexpr/nixexpr.hh#L241-L268) | ||||
|   (AST representation of attribute sets) | ||||
| * [`ExprAttrs::eval`](https://github.com/NixOS/nix/blob/075bf6e5565aff9fba0ea02f3333c82adf4dccee/src/libexpr/eval.cc#L1333-L1414) | ||||
| * [`addAttr`](https://github.com/NixOS/nix/blob/master/src/libexpr/parser.y#L98-L156) (`ExprAttrs` construction in the parser) | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue