cpclib_asm/parser/
source.rs1use 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
13pub type InnerZ80Span = Stateful<
15 LocatingSlice<
16 &'static BStr
18 >,
19 &'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 #[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 #[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 #[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 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
157 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
207impl 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 pub fn state(&self) -> &ParsingState {
292 self.context().state()
293 }
294}