]> git.lizzy.rs Git - rust.git/blob - ARCHITECTURE.md
docs about cancelation
[rust.git] / ARCHITECTURE.md
1 # Architecture
2
3 This document describes high-level architecture of rust-analyzer.
4 If you want to familiarize yourself with the code base, you are just
5 in the right place!
6
7
8 ## Code generation
9
10 Some of the components of this repository are generated through automatic
11 processes. These are outlined below:
12
13 - `gen-syntax`: The kinds of tokens are reused in several places, so a generator
14   is used. We use tera templates to generate the files listed below, based on
15   the grammar described in [grammar.ron]:
16   - [ast/generated.rs][ast generated] in `ra_syntax` based on
17     [ast/generated.tera.rs][ast source]
18   - [syntax_kinds/generated.rs][syntax_kinds generated] in `ra_syntax` based on
19     [syntax_kinds/generated.tera.rs][syntax_kinds source]
20
21 [tera]: https://tera.netlify.com/
22 [grammar.ron]: ./crates/ra_syntax/src/grammar.ron
23 [ast generated]: ./crates/ra_syntax/src/ast/generated.rs
24 [ast source]: ./crates/ra_syntax/src/ast/generated.rs.tera
25 [syntax_kinds generated]: ./crates/ra_syntax/src/syntax_kinds/generated.rs
26 [syntax_kinds source]: ./crates/ra_syntax/src/syntax_kinds/generated.rs.tera
27
28
29 ## Code Walk-Through
30
31 ### `crates/ra_syntax`
32
33 Rust syntax tree structure and parser. See
34 [RFC](https://github.com/rust-lang/rfcs/pull/2256) for some design
35 notes.
36
37 - [rowan](https://github.com/rust-analyzer/rowan) library is used for constructing syntax trees.
38 - `grammar` module is the actual parser. It is a hand-written recursive descent parsers, which
39   produces a sequence of events like "start node X", "finish not Y". It works similarly to  [kotlin parser](https://github.com/JetBrains/kotlin/blob/4d951de616b20feca92f3e9cc9679b2de9e65195/compiler/frontend/src/org/jetbrains/kotlin/parsing/KotlinParsing.java),
40   which is a good source for inspiration for dealing with syntax errors and incomplete input. Original [libsyntax parser](https://github.com/rust-lang/rust/blob/6b99adeb11313197f409b4f7c4083c2ceca8a4fe/src/libsyntax/parse/parser.rs)
41   is what we use for the definition of the Rust language.
42 - `parser_api/parser_impl` bridges the tree-agnostic parser from `grammar` with `rowan` trees.
43   This is the thing that turns a flat list of events into a tree (see `EventProcessor`)
44 - `ast` a type safe API on top of the raw `rowan` tree.
45 - `grammar.ron` RON description of the grammar, which is used to
46   generate `syntax_kinds` and `ast` modules, using `cargo gen-syntax` command.
47 - `algo`: generic tree algorithms, including `walk` for O(1) stack
48   space tree traversal (this is cool) and `visit` for type-driven
49   visiting the nodes (this is double plus cool, if you understand how
50   `Visitor` works, you understand rust-analyzer).
51
52 Test for ra_syntax are mostly data-driven: `tests/data/parser` contains a bunch of `.rs`
53 (test vectors) and `.txt` files with corresponding syntax trees. During testing, we check
54 `.rs` against `.txt`. If the `.txt` file is missing, it is created (this is how you update
55 tests). Additionally, running `cargo gen-tests` will walk the grammar module and collect
56 all `//test test_name` comments into files inside `tests/data` directory.
57
58 See [#93](https://github.com/rust-analyzer/rust-analyzer/pull/93) for an example PR which
59 fixes a bug in the grammar.
60
61 ### `crates/ra_db`
62
63 We use [salsa][https://github.com/salsa-rs/salsa] crate for incremental and
64 on-demand computation. Roughly, you can think of salsa as a key-value store, but
65 it also can compute derived values using specified functions. The `ra_db` crate
66 provides a basic infrastructure for interracting with salsa. Crucially, it
67 defines most of the "input" queries: facts supplied by the client of the analyzer.
68
69 ### `crates/ra_hir`
70
71 HIR provides a high-level "object oriented" acess to Rust code.
72
73 The principal difference between HIR and syntax trees is that HIR is bound to a
74 particular crate instance. That is, it has cfg flags and features applied (in
75 theory, in practice this is to be implemented). So, there relation between
76 syntax and HIR is many-to-one. The `source_binder` modules is responsible for
77 guessing a hir for a particular source position.
78
79 Underneath, hir works on top of salsa, using a `HirDatabase` trait.
80
81 ### `crates/ra_analysis`
82
83 A stateful library for analyzing many Rust files as they change.
84 `AnalysisHost` is a mutable entity (clojure's atom) which holds
85 current state, incorporates changes and handles out `Analysis` --- an
86 immutable consistent snapshot of world state at a point in time, which
87 actually powers analysis.
88
89 One interesting aspect of analysis is its support for cancelation. When a change
90 is applied to `AnalysisHost`, first all currently active snapshots are
91 cancelled. Only after all snapshots are dropped the change actually affects the
92 database.
93
94 ### `crates/ra_lsp_server`
95
96 An LSP implementation which uses `ra_analysis` for managing state and
97 `ra_editor` for actually doing useful stuff.
98
99 See [#79](https://github.com/rust-analyzer/rust-analyzer/pull/79/) as an
100 example of PR which adds a new feature to `ra_editor` and exposes it
101 to `ra_lsp_server`.
102
103 ### `crates/ra_editor`
104
105 All IDE features which can be implemented if you only have access to a
106 single file. `ra_editor` could be used to enhance editing of Rust code
107 without the need to fiddle with build-systems, file
108 synchronization and such.
109
110 In a sense, `ra_editor` is just a bunch of pure functions which take a
111 syntax tree as an input.
112
113 The tests for `ra_editor` are `#[cfg(test)] mod tests` unit-tests spread
114 throughout its modules.
115
116 ### `crates/gen_lsp_server`
117
118 A language server scaffold, exposing a synchronous crossbeam-channel based API.
119 This crate handles protocol handshaking and parsing messages, while you
120 control the message dispatch loop yourself.
121
122 Run with `RUST_LOG=sync_lsp_server=debug` to see all the messages.
123
124 ### `crates/ra_cli`
125
126 A CLI interface to rust-analyzer.
127
128 ### `crate/tools`
129
130 Custom Cargo tasks used to develop rust-analyzer:
131
132 - `cargo gen-syntax` -- generate `ast` and `syntax_kinds`
133 - `cargo gen-tests` -- collect inline tests from grammar
134 - `cargo install-code` -- build and install VS Code extension and server
135
136 ### `editors/code`
137
138 VS Code plugin
139
140
141 ## Common workflows
142
143 To try out VS Code extensions, run `cargo install-code`.  This installs both the
144 `ra_lsp_server` binary and VS Code extension. To install only the binary, use
145 `cargo install --path crates/ra_lsp_server --force`
146
147 To see logs from the language server, set `RUST_LOG=info` env variable. To see
148 all communication between the server and the client, use
149 `RUST_LOG=gen_lsp_server=debug` (will print quite a bit of stuff).
150
151 To run tests, just `cargo test`.
152
153 To work on VS Code extension, launch code inside `editors/code` and use `F5` to
154 launch/debug. To automatically apply formatter and linter suggestions, use `npm
155 run fix`.
156