diff options
Diffstat (limited to 'tvix/eval/docs/opcodes-attrsets.md')
-rw-r--r-- | tvix/eval/docs/opcodes-attrsets.md | 122 |
1 files changed, 0 insertions, 122 deletions
diff --git a/tvix/eval/docs/opcodes-attrsets.md b/tvix/eval/docs/opcodes-attrsets.md deleted file mode 100644 index 7026f3319dda..000000000000 --- a/tvix/eval/docs/opcodes-attrsets.md +++ /dev/null @@ -1,122 +0,0 @@ -# attrset-opcodes - -The problem with attrset literals is twofold: - -1. The keys of attribute sets may be dynamically evaluated. - - Access: - - ```nix - let - k = "foo"; - attrs = { /* etc. */ }; - in attrs."${k}" - ``` - - Literal: - ```nix - let - k = "foo"; - in { - "${k}" = 42; - } - ``` - - The problem with this is that the attribute set key is not known at - compile time, and needs to be dynamically evaluated by the VM as an - expression. - - For the most part this should be pretty simple, assuming a - theoretical instruction set: - - ``` - 0000 OP_CONSTANT(0) # key "foo" - 0001 OP_CONSTANT(1) # value 42 - 0002 OP_ATTR_SET(1) # construct attrset from 2 stack values - ``` - - The operation pushing the key needs to be replaced with one that - leaves a single value (the key) on the stack, i.e. the code for the - expression, e.g.: - - ``` - 0000..000n <operations leaving a string value on the stack> - 000n+1 OP_CONSTANT(1) # value 42 - 000n+2 OP_ATTR_SET(1) # construct attrset from 2 stack values - ``` - - This is fairly easy to do by simply recursing in the compiler when - the key expression is encountered. - -2. The keys of attribute sets may be nested. - - This is the non-trivial part of dealing with attribute set - literals. Specifically, the nesting can be arbitrarily deep and the - AST does not guarantee that related set keys are located - adjacently. - - Furthermore, this frequently occurs in practice in Nix. We need a - bytecode representation that makes it possible to construct nested - attribute sets at runtime. - - Proposal: AttrPath values - - If we can leave a value representing an attribute path on the - stack, we can offload the construction of nested attribute sets to - the `OpAttrSet` operation. - - Under the hood, OpAttrSet in practice constructs a `Map<NixString, - Value>` attribute set in most cases. This means it expects to pop - the value of the key of the stack, but is otherwise free to do - whatever it wants with the underlying map. - - In a simple example, we could have code like this: - - ```nix - { - a.b = 15; - } - ``` - - This would be compiled to a new `OpAttrPath` instruction that - constructs and pushes an attribute path from a given number of - fragments (which are popped off the stack). - - For example, - - ``` - 0000 OP_CONSTANT(0) # key "a" - 0001 OP_CONSTANT(1) # key "b" - 0002 OP_ATTR_PATH(2) # construct attrpath from 2 fragments - 0003 OP_CONSTANT(2) # value 42 - 0004 OP_ATTRS(1) # construct attrset from one pair - ``` - - Right before `0004` the stack would be left like this: - - [ AttrPath[a,b], 42 ] - - Inside of the `OP_ATTRS` instruction we could then begin - construction of the map and insert the nested attribute sets as - required, as well as validate that there are no duplicate keys. - -3. Both of these cases can occur simultaneously, but this is not a - problem as the opcodes combine perfectly fine, e.g.: - - ```nix - let - k = "a"; - in { - "${k}".b = 42; - } - ``` - - results in - - ``` - 0000..000n <operations leaving a string value on the stack> - 000n+1 OP_CONSTANT(1) # key "b" - 000n+2 OP_ATTR_PATH(2) # construct attrpath from 2 fragments - 000n+3 OP_CONSTANT(2) # value 42 - 000n+4 OP_ATTR_SET(1) # construct attrset from 2 stack values - ``` |