macroonz_compiler/token/capture/resolve.rs
1//! Resolving one span handle back to the position its producer holds, and stating the position a refused read already carries.
2//!
3//! Nothing here invents a position.
4//! A byte-offset table answers a handle it issued and refuses one it does not reach; a producer-held table answers in the semantic-origin role with the ordinal the handle already carries; and a read that refused before any table existed was born carrying the byte it sits at.
5//! One file composes every [`SourceCoordinate`] the seam hands out, so what a coordinate from here means is settled in one place.
6
7use super::{
8 CoordinateRole, SourceCoordinate, SpanHandle, SpanResolutionRefusal, SpanTable, TextReadRefusal,
9};
10
11impl SpanTable {
12 /// Where the token one handle names sits, in whatever coordinate role this producer speaks.
13 ///
14 /// [`SpanTable::ProducerHeld`] always answers, and answering is not inventing: the coordinate is in the semantic-origin role and its position is the handle's own ordinal in reading order, which is the fact the handle already carries.
15 /// It states no byte, no line, and no file, because this table holds none.
16 ///
17 /// # Errors
18 ///
19 /// Returns [`SpanResolutionRefusal`] where a byte-offset table does not reach the handle.
20 /// That table's whole content is one byte position per handle it issued, so answering with a semantic-origin coordinate at the handle's index would be a value indistinguishable from an honest answer under the other posture.
21 pub fn coordinate_of(
22 &self,
23 span: SpanHandle,
24 ) -> Result<SourceCoordinate, SpanResolutionRefusal> {
25 match self {
26 Self::ByteOffsets(offsets) => {
27 let unreached = SpanResolutionRefusal {
28 handle: span,
29 reaches: offsets.len(),
30 };
31 let index = usize::try_from(span.index()).map_err(|_| unreached)?;
32 offsets
33 .as_slice()
34 .get(index)
35 .map(|offset| SourceCoordinate {
36 role: CoordinateRole::Byte,
37 position: *offset,
38 })
39 .ok_or(unreached)
40 }
41 Self::ProducerHeld => Ok(SourceCoordinate {
42 role: CoordinateRole::SemanticOrigin,
43 position: u64::from(span.index()),
44 }),
45 }
46 }
47}
48
49impl TextReadRefusal {
50 /// Where this refusal sits, as a typed coordinate in the byte role.
51 ///
52 /// The text route reads bytes, so every cause it establishes has a byte position and is born carrying it.
53 /// Stating it in the shape [`SpanTable::coordinate_of`] answers in lets a caller report a read that never produced a capture — and therefore never produced a span table or a handle to look up in one.
54 ///
55 /// # Nonclaims
56 ///
57 /// No table is consulted, because at this point there is none: the position is the refusal's own, and the role says which text it counts into.
58 #[must_use]
59 pub const fn coordinate(self) -> SourceCoordinate {
60 SourceCoordinate {
61 role: CoordinateRole::Byte,
62 position: self.at,
63 }
64 }
65}