This commit rewrites Thunk::force() so that it is not (directly)
self-recursive. It maintains a Vec of all the
previously-encountered thunks which point to the one it is currently
forcing, rather than recursively calling itself.
Benefits:
- Short term:
This commit saves the cost of a round-trip through the generator
machinery for the generators::request_force() which is removed by
this commit.
- Medium term:
Once a similar transformation has been applied to nix_cmp(),
nix_add(), nix_eq(), and coerce_to_string(), those four functions,
along with Thunk::force(), will make non-tail calls only to each
other. They can then be merged into a single tail-recursive
function which does not use the generator machinery at all:
enum Task { Cmp, Add, Eq, CoerceToString, Force};
fn Value::walk(task:Task, v1:Value, v2:Value) {
// ...
- Long term:
The long-term goal here is to use generators **only for builtins**
and [Marionette]-style remote control of the VM. In other words:
use `async` for things that actually involve concurrency. Calls
from the VM to builtins can then be blocking calls, because even
cppnix will overflow the stack if you make a MAX_STACK_DEPTH-deep
recursive call which passes through a builtin at every stack frame
(e.g. `{ func = builtins.sort (a: b: ... func ...) ...}`).
This way the inner "tight loop" of the interpreter doesn't pay the
costs of `async` and generators. These costs manifest in terms
of: performance, complex nonlocal control flow, and language
impediments (async Rust is a restricted subset of real Rust, and
is missing things like traits).
[Marionette]: https://firefox-source-docs.mozilla.org/testing/marionette/Intro.html
Change-Id: I6179b8abb2ea0492180fcb347f37595a14665777
Reviewed-on: https://cl.tvl.fyi/c/depot/+/10039
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
|
||
|---|---|---|
| .. | ||
| benches | ||
| builtin-macros | ||
| docs | ||
| proptest-regressions/value | ||
| src | ||
| tests | ||
| .skip-subtree | ||
| build.rs | ||
| Cargo.toml | ||
| default.nix | ||
| README.md | ||
Tvix Evaluator
This project implements an interpreter for the Nix programming language. You can experiment with an online version of the evaluator: tvixbolt.
The interpreter aims to be compatible with nixpkgs, on the
foundation of Nix 2.3.
Important note: The evaluator is not yet feature-complete, and while the core mechanisms (compiler, runtime, ...) have stabilised somewhat, a lot of components are still changing rapidly.
Please contact TVL with any questions you might have.
Building tvix-eval
Please check the README.md one level up for instructions on how to build this.
The evaluator itself can also be built with standard Rust tooling (i.e. cargo build).
If you would like to clone only the evaluator and build it directly with Rust tooling, you can do:
git clone https://code.tvl.fyi/depot.git:/tvix/eval.git tvix-eval
cd tvix-eval && cargo build
Tests
Tvix currently has three language test suites for tvix-eval:
-
nix_testsandtvix_testsare based on the same mechanism borrowed from the C++ Nix implementation. They consist of Nix files as well as expected output (if applicable). The test cases are split into four categories:eval-okay(evaluates successfully with the expected output),eval-fail(fails to evaluate, no expected output),parse-okay(expression parses successfully, no expected output) andparse-fail(expression fails to parse, no expected output). Tvix currently ignores the last two types of test cases, since it doesn't implement its own parser.Both test suites have a
notyetpassingdirectory. All test cases in here test behavior that is not yet supported by Tvix. They are considered to be expected failures, so you can't forget to move them into the test suite proper when fixing the incompatibility.Additionally, separate targets in the depot pipeline, under
//tvix/verify-lang-tests, check both test suites (includingnotyetpassingdirectories) against C++ Nix 2.3 and the default C++ Nix version in nixpkgs. This way we can prevent accidentally introducing test cases for behavior that C++ Nix doesn't exhibit.-
nix_testshas the test cases from C++ Nix's language test suite and is sporadically updated by manually syncing the directories. Thenotyetpassingdirectory shows how far it is until we pass it completely. -
tvix_testscontains test cases written by the Tvix contributors. Some more or less duplicate test cases contained innix_tests, but many cover relevant behavior that isn't bynix_tests. Consequently, it'd be nice to eventually merge the two test suites into a jointly maintained, common Nix language test suite.It also has a
notyetpassingdirectory for missing behavior that is discovered while working on Tvix and isn't covered by thenix_testssuite.
-
-
nix_oraclecan evaluate Nix expressions in Tvix and compare the result against C++ Nix (2.3) directly. Eventually it should gain the ability to property test generated Nix expressions. An additional feature is that it can evaluate expressions without--strict, so thunking behavior can be verified more easily.
rnix-parser
Tvix is written in memory of jD91mZM2, the author of rnix-parser who sadly passed away.
Tvix makes heavy use of rnix-parser in its bytecode compiler. The parser is now maintained by Nix community members.