document identifier syntax for attribute sets

it's more likely for readers to find it right there.

this also slightly rewords examples to make them stand out better.
in the long run there probably needs to be a dedicated section on formal syntax, and better highlighting of examples.
This commit is contained in:
Valentin Gagarin 2023-05-11 19:23:13 +02:00
parent dfc393ffd3
commit d8bfeda164
3 changed files with 52 additions and 26 deletions

View file

@ -2,8 +2,11 @@
## Recursive sets ## Recursive sets
Recursive sets are just normal sets, but the attributes can refer to Recursive sets are like normal [attribute sets](./values.md#attribute-set), but the attributes can refer to each other.
each other. For example,
> *rec-attrset* = `rec {` [ *name* `=` *expr* `;` `]`... `}`
Example:
```nix ```nix
rec { rec {
@ -12,7 +15,9 @@ rec {
}.x }.x
``` ```
evaluates to `123`. Note that without `rec` the binding `x = y;` would This evaluates to `123`.
Note that without `rec` the binding `x = y;` would
refer to the variable `y` in the surrounding scope, if one exists, and refer to the variable `y` in the surrounding scope, if one exists, and
would be invalid if no such variable exists. That is, in a normal would be invalid if no such variable exists. That is, in a normal
(non-recursive) set, attributes are not added to the lexical scope; in a (non-recursive) set, attributes are not added to the lexical scope; in a
@ -33,7 +38,10 @@ will crash with an `infinite recursion encountered` error message.
## Let-expressions ## Let-expressions
A let-expression allows you to define local variables for an expression. A let-expression allows you to define local variables for an expression.
For instance,
> *let-in* = `let` [ *identifier* = *expr* ]... `in` *expr*
Example:
```nix ```nix
let let
@ -42,18 +50,19 @@ let
in x + y in x + y
``` ```
evaluates to `"foobar"`. This evaluates to `"foobar"`.
## Inheriting attributes ## Inheriting attributes
When defining a set or in a let-expression it is often convenient to When defining an [attribute set](./values.md#attribute-set) or in a [let-expression](#let-expressions) it is often convenient to copy variables from the surrounding lexical scope (e.g., when you want to propagate attributes).
copy variables from the surrounding lexical scope (e.g., when you want This can be shortened using the `inherit` keyword.
to propagate attributes). This can be shortened using the `inherit`
keyword. For instance, Example:
```nix ```nix
let x = 123; in let x = 123; in
{ inherit x; {
inherit x;
y = 456; y = 456;
} }
``` ```
@ -62,15 +71,23 @@ is equivalent to
```nix ```nix
let x = 123; in let x = 123; in
{ x = x; {
x = x;
y = 456; y = 456;
} }
``` ```
and both evaluate to `{ x = 123; y = 456; }`. (Note that this works and both evaluate to `{ x = 123; y = 456; }`.
because `x` is added to the lexical scope by the `let` construct.) It is
also possible to inherit attributes from another set. For instance, in > **Note**
this fragment from `all-packages.nix`, >
> This works because `x` is added to the lexical scope by the `let` construct.
It is also possible to inherit attributes from another attribute set.
Example:
In this fragment from `all-packages.nix`,
```nix ```nix
graphviz = (import ../tools/graphics/graphviz) { graphviz = (import ../tools/graphics/graphviz) {

View file

@ -35,17 +35,14 @@
## Attribute selection ## Attribute selection
> *attrset* `.` *attrpath* \[ `or` *expr* \]
Select the attribute denoted by attribute path *attrpath* from [attribute set] *attrset*. Select the attribute denoted by attribute path *attrpath* from [attribute set] *attrset*.
If the attribute doesnt exist, return the *expr* after `or` if provided, otherwise abort evaluation. If the attribute doesnt exist, return the *expr* after `or` if provided, otherwise abort evaluation.
<!-- FIXME: the following should to into its own language syntax section, but that needs more work to fit in well --> An attribute path is a dot-separated list of [attribute names](./values.md#attribute-set).
An attribute path is a dot-separated list of attribute names. > *attrpath* = *name* [ `.` *name* ]...
An attribute name can be an identifier or a string.
> *attrpath* = *name* [ `.` *name* ]... \
> *name* = *identifier* | *string* \
> *identifier* ~ `[a-zA-Z_][a-zA-Z0-9_'-]*`
[Attribute selection]: #attribute-selection [Attribute selection]: #attribute-selection

View file

@ -164,9 +164,17 @@ Note that lists are only lazy in values, and they are strict in length.
An attribute set is a collection of name-value-pairs (called *attributes*) enclosed in curly brackets (`{ }`). An attribute set is a collection of name-value-pairs (called *attributes*) enclosed in curly brackets (`{ }`).
An attribute name can be an identifier or a [string](#string).
An identifier must start with a letter (`a-z`, `A-Z`) or underscore (`_`), and can otherwise contain letters (`a-z`, `A-Z`), numbers (`0-9`), underscores (`_`), apostrophes (`'`), or dashes (`-`).
> *name* = *identifier* | *string* \
> *identifier* ~ `[a-zA-Z_][a-zA-Z0-9_'-]*`
Names and values are separated by an equal sign (`=`). Names and values are separated by an equal sign (`=`).
Each value is an arbitrary expression terminated by a semicolon (`;`). Each value is an arbitrary expression terminated by a semicolon (`;`).
> *attrset* = `{` [ *name* `=` *expr* `;` `]`... `}`
Attributes can appear in any order. Attributes can appear in any order.
An attribute name may only occur once. An attribute name may only occur once.
@ -182,15 +190,19 @@ Example:
This defines a set with attributes named `x`, `text`, `y`. This defines a set with attributes named `x`, `text`, `y`.
Attributes can be selected from a set using the `.` operator. For Attributes can be accessed with the [`.` operator](./operators.md#attribute-selection).
instance,
Example:
```nix ```nix
{ a = "Foo"; b = "Bar"; }.a { a = "Foo"; b = "Bar"; }.a
``` ```
evaluates to `"Foo"`. It is possible to provide a default value in an This evaluates to `"Foo"`.
attribute selection using the `or` keyword:
It is possible to provide a default value in an attribute selection using the `or` keyword.
Example:
```nix ```nix
{ a = "Foo"; b = "Bar"; }.c or "Xyzzy" { a = "Foo"; b = "Bar"; }.c or "Xyzzy"