docs: add identifiers (#11174)

* docs: add identifiers

* clarify attribute set notation and add examples

* add definition of names

Co-authored-by: Ryan Hendrickson <ryan.hendrickson@alum.mit.edu>
This commit is contained in:
Valentin Gagarin 2024-07-25 03:45:34 +02:00 committed by GitHub
parent e062021314
commit dba1142c01
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 112 additions and 28 deletions

View file

@ -28,6 +28,7 @@
- [Data Types](language/types.md) - [Data Types](language/types.md)
- [String context](language/string-context.md) - [String context](language/string-context.md)
- [Syntax and semantics](language/syntax.md) - [Syntax and semantics](language/syntax.md)
- [Identifiers](language/identifiers.md)
- [Scoping rules](language/scope.md) - [Scoping rules](language/scope.md)
- [String interpolation](language/string-interpolation.md) - [String interpolation](language/string-interpolation.md)
- [Lookup path](language/constructs/lookup-path.md) - [Lookup path](language/constructs/lookup-path.md)

View file

@ -0,0 +1,50 @@
# Identifiers
An *identifier* is an [ASCII](https://en.wikipedia.org/wiki/ASCII) character sequence that:
- Starts with a letter (`a-z`, `A-Z`) or underscore (`_`)
- Can contain any number of:
- Letters (`a-z`, `A-Z`)
- Digits (`0-9`)
- Underscores (`_`)
- Apostrophes (`'`)
- Hyphens (`-`)
- Is not one of the [keywords](#keywords)
> **Syntax**
>
> *identifier* ~ `[A-Za-z_][A-Za-z0-9_'-]*`
# Names
A name can be an [identifier](#identifier) or a [string literal](./syntax.md#string-literal).
> **Syntax**
>
> *name**identifier* | *string*
Names are used in [attribute sets](./syntax.md#attrs-literal), [`let` bindings](./syntax.md#let-expressions), and [`inherit`](./syntax.md#inheriting attributes).
# Keywords
These keywords are reserved and cannot be used as [identifiers](#identifiers):
- [`assert`](./syntax.md#assertions)
- [`else`][if]
- [`if`][if]
- [`in`][let]
- [`inherit`](./syntax.md#inheriting-attributes)
- [`let`][let]
- [`or`](./operators.md#attribute-selection) (see note)
- [`rec`](./syntax.md#recursive-sets)
- [`then`][if]
- [`with`](./syntax.md#with-expressions)
[if]: ./syntax.md#conditionals
[let]: ./syntax.md#let-expressions
> **Note**
>
> The Nix language evaluator currently allows `or` to be used as a name in some contexts, for backwards compatibility reasons.
> Users are advised not to rely on this.
>
> There are long-standing issues with how `or` is parsed as a name, which can't be resolved without making a breaking change to the language.

View file

@ -42,12 +42,6 @@
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.
An attribute path is a dot-separated list of [attribute names](./types.md#attribute-set).
> **Syntax**
>
> *attrpath* = *name* [ `.` *name* ]...
[Attribute selection]: #attribute-selection [Attribute selection]: #attribute-selection
## Has attribute ## Has attribute

View file

@ -247,37 +247,76 @@ Elements in a list can be accessed using [`builtins.elemAt`](./builtins.md#built
## Attribute Set {#attrs-literal} ## Attribute Set {#attrs-literal}
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*.
An attribute name can be an identifier or a [string](#string). Attribute sets are written enclosed in curly brackets (`{ }`).
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 (`-`). Attribute names and attribute values are separated by an equal sign (`=`).
Each value can be an arbitrary expression, terminated by a semicolon (`;`)
An attribute name is a string without context, and is denoted by a [name] (an [identifier](./identifiers.md#identifiers) or [string literal](#string-literal)).
[name]: ./identifiers.md#names
> **Syntax** > **Syntax**
> >
> *name* = *identifier* | *string* \ > *attrset*`{` { *name* `=` *expr* `;` } `}`
> *identifier* ~ `[a-zA-Z_][a-zA-Z0-9_'-]*`
Names and values are separated by an equal sign (`=`).
Each value is an arbitrary expression terminated by a semicolon (`;`).
> **Syntax**
>
> *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 in each attribute set.
Example: > **Example**
>
> This defines an attribute set with attributes named:
> - `x` with the value `123`, an integer
> - `text` with the value `"Hello"`, a string
> - `y` where the value is the result of applying the function `f` to the attribute set `{ bla = 456; }`
>
> ```nix
> {
> x = 123;
> text = "Hello";
> y = f { bla = 456; };
> }
> ```
```nix Attributes in nested attribute sets can be written using *attribute paths*.
{
x = 123;
text = "Hello";
y = f { bla = 456; };
}
```
This defines a set with attributes named `x`, `text`, `y`. > **Syntax**
>
> *attrset*`{` { *attrpath* `=` *expr* `;` } `}`
An attribute path is a dot-separated list of [names][name].
> **Syntax**
>
> *attrpath* = *name* { `.` *name* }
<!-- -->
> **Example**
>
> ```nix
> { a.b.c = 1; a.b.d = 2; }
> ```
>
> {
> a = {
> b = {
> c = 1;
> d = 2;
> };
> };
> }
Attribute names can also be set implicitly by using the [`inherit` keyword](#inheriting-attributes).
> **Example**
>
> ```nix
> { inherit (builtins) true; }
> ```
>
> { true = true; }
Attributes can be accessed with the [`.` operator](./operators.md#attribute-selection). Attributes can be accessed with the [`.` operator](./operators.md#attribute-selection).