Skip to main content

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}