1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
//! Compiler for inkle's ink narrative scripting language.
//!
//! Orchestrates the full compilation pipeline: file discovery, parsing
//! (`brink-syntax`), HIR lowering (`brink-ir`), semantic analysis
//! (`brink-analyzer`), and codegen into the `brink-format` binary
//! representation consumed by `brink-runtime`.
//!
//! ## The `test-util`-gated entry points (issue #2168)
//!
//! `brink_environment::compile(&Environment)` (#1306) is the ruled
//! determinism boundary and the **sole production road** into compilation —
//! `brink-cli` and `brink-web` both go through it. This crate's `compile`,
//! `compile_path`, `compile_with_options`, and `compile_path_with_options`
//! take a `read_file` closure (or read straight off disk) and bypass
//! `Environment` entirely, so once stdlib source is mounted into the
//! `Environment` manifest (#2080), anything reached through them will not
//! see the stdlib — the story compiles and conventions silently do not
//! classify.
//!
//! Every call site of these four functions is test/bench/example code
//! compiling an inline or fixture ink source with no need for a real
//! `Environment`. They stay available for exactly that under the
//! `test-util` feature (off by default). `#[cfg(test)]` cannot do this job —
//! the callers span separate integration-test crates that cannot see this
//! crate's own `#[cfg(test)]`. A test/bench/example target that needs them
//! opts in with a `dev-dependencies` edge enabling the feature, e.g.:
//!
//! The guarantee this actually gives: an external crates.io consumer, or
//! any isolated `cargo check -p <crate>` build that does not resolve
//! `brink-test-harness`, cannot reach these functions without opting in.
//! It is **not** a guarantee inside a `--workspace` build of this repo —
//! `brink-test-harness` takes `brink-compiler` with `features =
//! ["test-util"]` as a **normal** (non-dev) dependency, because its own
//! `[[bin]]` targets and `src/corpus.rs` call these functions
//! unconditionally, not just under a test cfg. Cargo's feature unification
//! then enables `test-util` for every crate sharing that `brink-compiler`
//! instance across the whole workspace resolve, so a production fn added to
//! e.g. `brink-cli` would still compile under `cargo check --workspace`.
//! The CI job's isolated `-p brink-cli -p brink-web -p brink-lsp -p
//! bevy-brink -p brink-environment` check (added alongside this note) is
//! what actually proves the fence for those crates, since it never resolves
//! `brink-test-harness`.
//!
//! ```toml
//! [dev-dependencies]
//! brink-compiler = { workspace = true, features = ["test-util"] }
//! ```
pub use ;
pub use ;
use StoryData;
use io;
use Path;
/// A diagnostic resolved for consumption outside the compiler.
///
/// The internal [`Diagnostic`] keys a file by [`FileId`] — an interning index
/// that is only meaningful inside the compiler instance that produced it and
/// is not stable across recompiles. A consumer (an editor, a host integration,
/// an LSP) cannot map that id back to a file on its own. `ResolvedDiagnostic`
/// carries the file's `path` — byte-identical to the string the host used as
/// the entry point / answered the `read_file` callback with — so a diagnostic
/// can always be located. `file` is retained for in-result correlation only.
///
/// `range` is left as byte offsets into the file's source. Line/column
/// resolution is deliberately not baked in: column units are consumer-specific
/// (LSP uses UTF-16 code units, a terminal uses bytes or chars), and the
/// consumer already holds the source text to resolve them in the unit it needs.
/// Successful compilation output, including any non-fatal warnings.
/// Compile an ink story from an entry-point file path.
///
/// Reads files from disk, follows INCLUDEs, and runs the full compilation
/// pipeline. Returns the compiled story data or a list of diagnostics.
///
/// **Test/bench/example use only** — gated behind the `test-util` feature;
/// see the module docs. Bypasses `Environment` entirely, so a real consumer
/// should use `brink_environment::compile(&Environment)` instead.
/// Compile an ink story from an entry-point file path with explicit analysis
/// options — e.g. the T1b `--dialect` flag (`AnalysisOptions::dialect`).
///
/// **Test/bench/example use only** — gated behind the `test-util` feature;
/// see the module docs. Bypasses `Environment` entirely, so a real consumer
/// should use `brink_environment::compile(&Environment)` instead.
/// Compile an ink story with caller-provided file reading.
///
/// The `read_file` callback is called for the entry point and each
/// `INCLUDE`d file discovered during parsing. This enables compilation in
/// WASM, tests, and editor contexts where files are not on disk.
///
/// **Test/bench/example use only** — gated behind the `test-util` feature;
/// see the module docs. Bypasses `Environment` entirely, so a real consumer
/// should use `brink_environment::compile(&Environment)` instead.
/// Compile with explicit analysis options — e.g. a registered host-capability
/// manifest and external-check severity (the "compiler flag, error by
/// default"). Manifest-driven diagnostics are surfaced as compile warnings or
/// errors per the severity policy.
///
/// **Test/bench/example use only** — gated behind the `test-util` feature;
/// see the module docs. Bypasses `Environment` entirely, so a real consumer
/// should use `brink_environment::compile(&Environment)` instead.
/// Errors that can occur during compilation.