Skip to content

Commit

Permalink
docs: add variables and identifiers; rework scope
Browse files Browse the repository at this point in the history
  • Loading branch information
rhendric committed Jul 8, 2024
1 parent fb450de commit e9e33c7
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 9 deletions.
2 changes: 2 additions & 0 deletions doc/manual/src/SUMMARY.md.in
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
- [Data Types](language/types.md)
- [String context](language/string-context.md)
- [Syntax and semantics](language/syntax.md)
- [Expressions]()
- [Variables and Identifiers](language/identifiers.md)
- [Scoping rules](language/scope.md)
- [String interpolation](language/string-interpolation.md)
- [Lookup path](language/constructs/lookup-path.md)
Expand Down
42 changes: 42 additions & 0 deletions doc/manual/src/language/identifiers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Variables and Identifiers

> **Grammar**
>
> `word``[A-Z_a-z]['\-0-9A-Z_a-z]*`
>
> `identifier``word` (excluding keywords)
>
> `expr``identifier`
An _identifier_ is a sequence of characters starting with an ASCII letter or an underscore, followed by any number of ASCII letters, digits, underscores, apostrophes, or hyphens.

A _variable_ is an identifier used as an expression, if the identifier is not one of the following _keywords_:

- [`assert`][assert]
- [`else`][if]
- [`if`][if]
- [`in`][let]
- [`inherit`][inherit]
- [`let`][let]
- [`or`][or] _(see note)_
- [`rec`][rec]
- [`then`][if]
- [`with`][with]

[assert]: syntax.md#assertions
[if]: syntax.md#conditionals
[let]: syntax.md#let-expressions
[inherit]: syntax.md#inheriting-attributes
[or]: operators.md#attribute-selection
[rec]: syntax.md#recursive-sets
[with]: syntax.md#with-expressions

A variable must have the same name as a definition in the [scope] that encloses it.
The value of a variable is the value of the corresponding expression in the enclosing scope.

> **Note**
>
> The Nix interpreter currently allows `or` to be used as a variable in some contexts, for backwards compatibility reasons.
> Users are advised not to rely on this, as there are long-standing issues with how `or` as a variable is parsed, which can't be resolved without making a breaking change to the language.
[scope]: scope.md
38 changes: 29 additions & 9 deletions doc/manual/src/language/scope.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
# Scoping rules

Nix is [statically scoped](https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scope), but with multiple scopes and shadowing rules.
A _scope_ in the Nix language is an [identifier]-keyed dictionary, mapping each identifier to an expression and a _definition type_.
The definition type is either _explicit_ or _implicit_.
Each entry in this dictionary is a _definition_.

* primary scope: explicitly-bound variables
* [`let`](./syntax.md#let-expressions)
* [`inherit`](./syntax.md#inheriting-attributes)
* [function](./syntax.md#functions) arguments
[identifier]: identifiers.md

* secondary scope: implicitly-bound variables
* [`with`](./syntax.md#with-expressions)
Explicit definitions are created by the following expressions:
* [let-expressions](syntax.md#let-expressions)
* [recursive attribute set literals](syntax.md#recursive-sets) (`rec`)
* [function literals](syntax.md#functions)

Primary scope takes precedence over secondary scope.
See [`with`](./syntax.md#with-expressions) for a detailed example.
Implicit definitions are only created by [with-expressions].

[with-expressions]: syntax.md#with-expressions

Each of the above expressions defines which of its subexpressions are _enclosed_ by the extended scope.
The outermost expression of a Nix language file is enclosed by the [global scope], which contains only explicit definitions.
Nix is [statically scoped]; the enclosing scope of an expression is always determined only by the expressions that contain it as a subexpression, and not by the context in which it is evaluated.

[global scope]: builtins.md
[statically scoped]: https://en.wikipedia.org/wiki/Scope_(computer_science)#Lexical_scope

The above expressions _extend_ their enclosing scope by adding new definitions, or replacing existing ones with the same name.
An explicit definition can replace a definition of any type; an implicit definition can only replace another implicit definition.
See [with-expressions] for a detailed example.

> **Note**
>
> Expressions entered into the [Nix REPL] are enclosed by a scope that can be extended by command line arguments or previous REPL commands.
> These ways of extending scope are not, strictly speaking, part of the Nix language.
[Nix REPL]: @docroot@/command-ref/new-cli/nix3-repl.md

0 comments on commit e9e33c7

Please sign in to comment.