macroonz_compiler/token/capture/types.rs
1//! The capture home's declarations: what one captured declaration is and how a producer's span table answers.
2//!
3//! Declarations only.
4//! Every road that reaches a private field lives in `type_guard.rs`, this file's own child, which is where all four magnitudes below are settled.
5
6use crate::bounded::Bounded;
7
8#[path = "type_guard.rs"]
9mod guard;
10
11/// Steps one token path may carry, and so how deeply a declared input may nest.
12///
13/// A width bound alone bounds each level and says nothing about the depth, so an input nested a million groups deep would satisfy it at every level while the walk reading it did not terminate.
14pub const TOKEN_PATH_DEPTH_LIMIT: usize = 32;
15
16/// Token trees one captured input may carry at any one nesting level.
17pub const CAPTURED_TOKEN_LIMIT: usize = 4096;
18
19/// Tokens one captured input may retain across the whole tree, and positions one span table may hold.
20///
21/// The capture-work budget owns the denominator.
22/// One complete nesting level remains available for examined material that does not become a retained token.
23pub const CAPTURED_TREE_TOKEN_LIMIT: usize = CAPTURE_WORK_LIMIT - CAPTURED_TOKEN_LIMIT;
24
25/// Units of capture work one walk may spend, one unit per examined token.
26///
27/// Deliberately wider than the whole-tree magnitude, because a walk may look at more than it keeps, and a budget at the tree magnitude exactly would refuse a lawful input the moment its producer looked twice at anything.
28pub const CAPTURE_WORK_LIMIT: usize = 65_536;
29
30/// An opaque index into the producer's span table.
31///
32/// It carries no position, no file, and no length: the producer built the table while capturing, and only the producer can turn one back into a compiler span.
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
34pub struct SpanHandle(u32);
35
36/// The coordinate system one source position is counted in.
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38pub enum CoordinateRole {
39 /// A zero-based byte offset in the captured text.
40 Byte,
41 /// A zero-based ordinal retained by the source producer.
42 SemanticOrigin,
43}
44
45/// One compiler-local source position with its coordinate system stated.
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
47pub struct SourceCoordinate {
48 /// The coordinate system in which the position is counted.
49 pub role: CoordinateRole,
50 /// The zero-based position in that coordinate system.
51 pub position: u64,
52}
53
54/// The delimiter one captured group is written with.
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
56pub enum CapturedDelimiter {
57 /// `( … )`.
58 Parenthesis,
59 /// `{ … }`.
60 Brace,
61 /// `[ … ]`.
62 Bracket,
63 /// A group with no delimiter written — the invisible grouping a compiler inserts around a captured fragment.
64 ///
65 /// It is a real group and is never flattened away, and a reader of text can never write one, because text that carries no delimiter carries no group.
66 Bare,
67}
68
69crate::roster! {
70 /// Which declared magnitude one capture ran past.
71 ///
72 /// Every row refuses before any partial tree exists: a truncated capture is a different declaration, and capturing one would put everything downstream to work on material nobody wrote.
73 #[must_use = "a bound refusal names which declared magnitude the capture would have passed"]
74 pub enum CaptureBound {
75 /// The declared input nests deeper than the declared magnitude.
76 Depth = "depth",
77 /// One nesting level carries more token trees than the declared magnitude.
78 Level = "level",
79 /// The whole tree carries more tokens than the declared magnitude.
80 Tree = "tree",
81 /// The walk spent the declared capture-work budget.
82 Work = "work",
83 }
84}
85
86/// Where one captured token sits, as the index route from the root of the declared input.
87///
88/// The route is unique by construction: `[3, 0, 5]` is the sixth token of the first token of the fourth top-level token, and nothing else in the tree spells that.
89/// It is stable under everything a span is not stable under — which producer read the input, where the file moved, how the source was formatted — so two captures of one declaration agree on every route.
90#[derive(Debug, Clone, PartialEq, Eq, Hash)]
91pub struct TokenPath {
92 steps: Bounded<u32, TOKEN_PATH_DEPTH_LIMIT>,
93}
94
95/// The running state of one capture walk: what the walk has spent, and how much of the whole-tree magnitude it has taken.
96///
97/// The two are charged separately, because a producer that reads material it discards — a frontend skipping trivia, a reader backtracking over an alternative — spends work the result never shows, and the budget is the only magnitude that can see it.
98#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
99pub struct CaptureWalk {
100 remaining: usize,
101 taken: usize,
102}
103
104/// One non-group value a capture producer offers to the checked builder.
105///
106/// Groups have their own builder operation so no caller can smuggle child trees carrying foreign paths or handles through an atom seat.
107#[derive(Debug, Clone, PartialEq, Eq, Hash)]
108pub enum CapturedAtom {
109 /// An ordinary identifier-shaped word or keyword.
110 Word(String),
111 /// One punctuation character that stands alone.
112 Punct(char),
113 /// A text literal's text.
114 Text(String),
115 /// A numeric literal, exactly as written.
116 Number(String),
117 /// A byte-string literal's material.
118 ByteText(Vec<u8>),
119 /// One character literal's character.
120 Character(char),
121 /// One byte literal's byte.
122 Byte(u8),
123 /// A C string literal's material without its terminating NUL.
124 NulTerminatedText(Vec<u8>),
125 /// A raw identifier's name without its `r#` spelling marker.
126 RawIdentifier(String),
127 /// One punctuation character joined to the token after it.
128 JointPunct(char),
129}
130
131/// What one captured token carries.
132///
133/// An arm carries a literal's value and never the characters it was spelled with, so `"x"` and `r"x"` are one text and which prefix a producer read is not a fact the tree keeps.
134///
135/// # Ordering
136///
137/// The roster grows at its end and nowhere else: each arm's slot is a byte of the canonical bytes a captured declaration's identity is derived over.
138#[derive(Debug, Clone, PartialEq, Eq, Hash)]
139pub enum CapturedPayload {
140 /// An ordinary identifier-shaped word or keyword.
141 Word(String),
142 /// One punctuation character that stands alone.
143 Punct(char),
144 /// A text literal's text: `"…"` and `r"…"` alike, escapes read and quotes removed.
145 Text(String),
146 /// A numeric literal, exactly as written: the base, the digit separators, and the suffix that types it are all part of what the declaration says.
147 Number(String),
148 /// A delimited group and the tokens inside it.
149 Group {
150 /// The delimiter written around the group.
151 delimiter: CapturedDelimiter,
152 /// The tokens inside, in the order they were written.
153 trees: Bounded<CapturedTokenTree, CAPTURED_TOKEN_LIMIT>,
154 },
155 /// A byte-string literal's material: `b"…"` and `br"…"`, kept as bytes because material that is not text crosses without a lossy road existing for it to take.
156 ByteText(Vec<u8>),
157 /// One character literal's character: `'…'`.
158 Character(char),
159 /// One byte literal's byte: `b'…'`.
160 Byte(u8),
161 /// A C string literal's material: `c"…"` and `cr"…"`, without the terminating NUL, which is the literal form's and never the value's.
162 NulTerminatedText(Vec<u8>),
163 /// A raw identifier's name without its `r#` spelling marker.
164 RawIdentifier(String),
165 /// One punctuation character joined to the token after it.
166 JointPunct(char),
167}
168
169crate::roster! {
170 /// Why one literal spelling could not be read into the value it names.
171 ///
172 /// Neither row is the caller's mistake: every spelling that reaches this road was already lexed by a compiler, so a refusal is this crate saying it does not read what the compiler admitted.
173 #[must_use = "a literal refusal names why the spelling could not be read into a value"]
174 pub enum LiteralReadCause {
175 /// The spelling opens with no literal form this grammar has a row for.
176 NotAKnownForm = "not-a-known-form",
177 /// The form is one this grammar reads, and its body carries material this grammar could not read the value of.
178 NotReadable = "not-readable",
179 }
180}
181
182/// One captured token: what it carries, where it sits, and how to reach the compiler span it came from.
183#[derive(Debug, Clone, PartialEq, Eq, Hash)]
184pub struct CapturedTokenTree {
185 payload: CapturedPayload,
186 path: TokenPath,
187 span: SpanHandle,
188}
189
190/// One captured declared input: the top-level token trees, and how many span handles the producer issued.
191#[derive(Debug, Clone, PartialEq, Eq, Hash)]
192pub struct CapturedInput {
193 trees: Bounded<CapturedTokenTree, CAPTURED_TOKEN_LIMIT>,
194 issued: usize,
195}
196
197/// One borrowed run of captured tokens under its original source boundary.
198///
199/// A fragment is a view into one [`CapturedInput`] or one captured group, never a second token tree.
200/// Its producer spans remain on the tokens it borrows, while its canonical bytes exclude those producer-local coordinates on the same terms as the complete capture.
201#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
202pub struct CapturedFragment<'tokens> {
203 pub(super) tokens: &'tokens [CapturedTokenTree],
204 pub(super) end: Option<SpanHandle>,
205}
206
207#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
208enum CaptureBuilderStanding {
209 Ready,
210 Refused { retained_before_capture: usize },
211}
212
213#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
214enum CaptureLevelStanding {
215 Open,
216 Finished,
217}
218
219/// The only state that issues capture handles and retains the producer's matching source positions.
220#[derive(Debug, Clone, PartialEq, Eq, Hash)]
221pub struct CaptureBuilder<Position> {
222 positions: Vec<Position>,
223 walk: CaptureWalk,
224 standing: CaptureBuilderStanding,
225}
226
227/// One nesting level borrowed from a [`CaptureBuilder`].
228///
229/// A producer can append atoms or groups and cannot state a path, a handle, or a denominator.
230/// Every operation consumes the level, and only a successful operation returns it, so a refused partial level cannot be finished.
231pub struct CaptureLevel<'capture, Position> {
232 positions: &'capture mut Vec<Position>,
233 walk: &'capture mut CaptureWalk,
234 builder_standing: &'capture mut CaptureBuilderStanding,
235 retained_before_capture: usize,
236 path: TokenPath,
237 trees: Bounded<CapturedTokenTree, CAPTURED_TOKEN_LIMIT>,
238 standing: CaptureLevelStanding,
239}
240
241/// Why a checked capture was not completed.
242#[must_use = "a capture refusal names whether a declared bound or the producer's own reading stopped construction"]
243#[derive(Debug, Clone, PartialEq, Eq, Hash)]
244pub enum CaptureBuildRefusal<Position, ProducerRefusal> {
245 /// One declared capture magnitude was exceeded at this producer position.
246 Unbounded {
247 /// The magnitude exceeded.
248 bound: CaptureBound,
249 /// The producer's own position for the token that reached it.
250 at: Position,
251 },
252 /// The producer could not read one token after the builder issued its declaration path and producer handle.
253 ProducerRefused {
254 /// The producer's typed reason.
255 cause: ProducerRefusal,
256 /// The declaration-local route to the token the producer could not read.
257 path: TokenPath,
258 /// The handle already bound to the token's retained source position.
259 at: SpanHandle,
260 },
261}
262
263/// Why one span table could not say where a handle sits.
264///
265/// A caller holding the handle and the table's reach can tell a handle issued by another producer from a handle issued past the end of a truncated table, which is the whole of what is knowable from this side.
266#[must_use = "a resolution refusal carries the handle and how far the table reaches"]
267#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
268pub struct SpanResolutionRefusal {
269 /// The handle the table was asked to resolve.
270 pub handle: SpanHandle,
271 /// How many positions the table carries; a handle at or past this index names no position in it.
272 pub reaches: usize,
273}
274
275/// How a producer answers "where is the token this handle names?".
276///
277/// Not an option and not a default: nothing here invents a position for a handle it cannot resolve, and a diagnostic coordinate reading `byte 0` under a producer-held table would be a fiction.
278#[derive(Debug, Clone, PartialEq, Eq, Hash)]
279pub enum SpanTable {
280 /// Byte offsets into the declared input, one per issued handle.
281 ByteOffsets(Bounded<u64, CAPTURED_TREE_TOKEN_LIMIT>),
282 /// The producer holds the compiler's spans and resolves handles itself.
283 ProducerHeld,
284}