cpclib_asm/parser/
source.rs

1use std::fmt::Display;
2use std::ops::{Deref, DerefMut};
3
4use cpclib_common::smol_str::SmolStr;
5use cpclib_common::winnow::stream::{AsBStr, LocatingSlice, Offset};
6use cpclib_common::winnow::{BStr, Stateful};
7use cpclib_tokens::symbols::{Source, Symbol};
8use line_span::LineSpanExt;
9
10use super::ParsingState;
11use super::context::ParserContext;
12
13// This type is only handled by the parser
14pub type InnerZ80Span = Stateful<
15    LocatingSlice<
16        // the type of data, owned by the base listing of interest
17        &'static BStr
18    >,
19    // The parsing context
20    // TODO remove it an pass it over the parse arguments
21    &'static ParserContext
22>;
23
24#[derive(Clone, PartialEq, Eq)]
25pub struct Z80Span(pub(crate) InnerZ80Span);
26
27impl From<InnerZ80Span> for Z80Span {
28    fn from(value: InnerZ80Span) -> Self {
29        Self(value)
30    }
31}
32
33impl From<Z80Span> for InnerZ80Span {
34    fn from(val: Z80Span) -> Self {
35        val.0
36    }
37}
38
39impl AsRef<str> for Z80Span {
40    #[inline]
41    fn as_ref(&self) -> &str {
42        unsafe { std::str::from_utf8_unchecked(self.0.as_bstr()) }
43    }
44}
45
46impl<'a> From<&'a Z80Span> for &'a str {
47    fn from(val: &'a Z80Span) -> Self {
48        AsRef::as_ref(val)
49    }
50}
51
52pub trait SourceString: Display {
53    fn as_str(&self) -> &str;
54}
55
56impl From<&dyn SourceString> for Symbol {
57    fn from(val: &dyn SourceString) -> Self {
58        val.as_str().into()
59    }
60}
61
62impl From<&Z80Span> for Symbol {
63    fn from(val: &Z80Span) -> Self {
64        val.as_str().into()
65    }
66}
67
68impl SourceString for &Z80Span {
69    fn as_str(&self) -> &str {
70        self.as_ref()
71    }
72}
73
74impl SourceString for Z80Span {
75    fn as_str(&self) -> &str {
76        self.as_ref()
77    }
78}
79
80impl SourceString for &String {
81    fn as_str(&self) -> &str {
82        self.as_ref()
83    }
84}
85
86impl SourceString for &SmolStr {
87    fn as_str(&self) -> &str {
88        self.as_ref()
89    }
90}
91
92impl SourceString for SmolStr {
93    fn as_str(&self) -> &str {
94        self.as_ref()
95    }
96}
97
98impl Z80Span {
99    #[inline]
100    pub fn complete_source(&self) -> &str {
101        self.0.state.complete_source()
102    }
103
104    /// Get the offset from the start of the string (when considered to be a array of bytes)
105    #[inline]
106    pub fn offset_from_start(&self) -> usize {
107        let src = self.complete_source();
108        let src = src.as_bstr();
109        self.as_bstr().offset_from(&src)
110    }
111
112    /// Get the line and column relatively to the source start
113    #[inline]
114    pub fn relative_line_and_column(&self) -> (usize, usize) {
115        let offset = self.offset_from_start();
116        self.context().relative_line_and_column(offset)
117    }
118
119    #[inline]
120    pub fn location_line(&self) -> u32 {
121        self.relative_line_and_column().0 as _
122    }
123
124    /// Get the full line from the whole source code that contains the following span
125    #[inline]
126    pub fn complete_line(&self) -> &str {
127        let offset = self.offset_from_start();
128        let range = self.complete_source().find_line_range(offset);
129        let line = &self.complete_source().as_bytes()[range.start..range.end];
130        unsafe { std::str::from_utf8_unchecked(line) }
131    }
132
133    #[inline]
134    pub fn get_line_beginning(&self) -> &str {
135        self.complete_line()
136    }
137
138    #[inline]
139    pub fn filename(&self) -> &str {
140        self.state
141            .filename()
142            .as_ref()
143            .map(|p| p.as_os_str().to_str().unwrap_or("[Invalid file name]"))
144            .unwrap_or_else(|| {
145                self.state
146                    .context_name
147                    .as_ref()
148                    .map(|s| s.as_ref())
149                    .unwrap_or_else(|| "no file specified")
150            })
151    }
152}
153
154impl std::fmt::Display for Z80Span {
155    // This trait requires `fmt` with this exact signature.
156    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
157        // Write strictly the first element into the supplied output
158        // stream: `f`. Returns `fmt::Result` which indicates whether the
159        // operation succeeded or failed. Note that `write!` uses syntax which
160        // is very similar to `println!`.
161        write!(f, "{}", self.as_str())
162    }
163}
164
165impl std::fmt::Debug for Z80Span {
166    #[inline]
167    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
168        let (line, column) = self.relative_line_and_column();
169        write!(
170            f,
171            "{}:{}:{} <{}>",
172            self.context()
173                .current_filename
174                .as_ref()
175                .map(|p| p.as_str())
176                .unwrap_or("<unknown filename>"),
177            line,
178            column,
179            self.as_str()
180        )
181    }
182}
183
184impl From<&Z80Span> for SmolStr {
185    fn from(val: &Z80Span) -> Self {
186        SmolStr::from(val.as_str())
187    }
188}
189
190impl From<&Z80Span> for Source {
191    #[inline]
192    fn from(val: &Z80Span) -> Self {
193        let (line, column) = val.relative_line_and_column();
194
195        Source::new(
196            val.context()
197                .current_filename
198                .as_ref()
199                .map(|fname| fname.as_str().to_owned())
200                .unwrap_or_else(|| "<INLINE>".into()),
201            line as _,
202            column
203        )
204    }
205}
206
207// Impossible as the string MUST exist more than the span
208// impl From<String> for Z80Span {
209// fn from(s: String) -> Self {
210// let src = Arc::new(s);
211// let ctx = Arc::default();
212//
213// Self(LocatingSliceSpan::new_extra(
214// The string is safe on the heap
215// unsafe { &*(src.as_str() as *const str) as &'static str },
216// (src, ctx)
217// ))
218// }
219// }
220
221// check if still needed
222// impl Z80Span {
223// pub fn from_standard_span(
224// span: LocatingSliceSpan<&'static str, ()>,
225// extra: (Arc<String>, Arc<ParserContext>)
226// ) -> Self {
227// {
228// let _span_addr = span.fragment().as_ptr();
229// let _extra_addr = extra.as_ptr();
230// TODO; no idea why it fails :()
231//   assert!(std::ptr::eq(span_addr, extra_addr));
232// }
233//
234// Self(unsafe {
235// LocatingSliceSpan::new_from_raw_offset(
236// span.location_offset(),
237// span.location_line(),
238// span.fragment(),
239// extra
240// )
241// })
242// }
243// }
244
245impl Deref for Z80Span {
246    type Target = InnerZ80Span;
247
248    #[inline]
249    fn deref(&self) -> &Self::Target {
250        &self.0
251    }
252}
253impl DerefMut for Z80Span {
254    #[inline]
255    fn deref_mut(&mut self) -> &mut Self::Target {
256        &mut self.0
257    }
258}
259impl AsRef<InnerZ80Span> for Z80Span {
260    #[inline]
261    fn as_ref(&self) -> &InnerZ80Span {
262        self.deref()
263    }
264}
265
266impl Z80Span {
267    pub fn new_extra<S: ?Sized + AsRef<[u8]>>(src: &S, ctx: &ParserContext) -> Self {
268        let src = unsafe { std::mem::transmute(BStr::new(src)) };
269        let ctx = unsafe { &*(ctx as *const ParserContext) as &'static ParserContext };
270
271        Self(Stateful {
272            input: LocatingSlice::new(src),
273            state: ctx
274        })
275    }
276
277    pub fn context(&self) -> &ParserContext {
278        self.state
279    }
280}
281
282impl Z80Span {
283    // Used when the state is changing (it controls the parsing)
284    // pub fn clone_with_state(&self, state: ParsingState) -> Self {
285    // eprintln!("Z80Span::clone_with_state used. Need to check if it could be done differently as the state is supposed to be hold by the listing");
286    // let ctx = self.context().clone_with_state(state);
287    // let mut clone = self.clone();
288    // clone.extra =  w(ctx);
289    // clone
290    // }
291    pub fn state(&self) -> &ParsingState {
292        self.context().state()
293    }
294}