cpclib_asm/parser/
source.rsuse std::fmt::Display;
use std::ops::{Deref, DerefMut};
use cpclib_common::smol_str::SmolStr;
use cpclib_common::winnow::stream::{AsBStr, Offset};
use cpclib_common::winnow::{BStr, Located, Stateful};
use cpclib_tokens::symbols::{Source, Symbol};
use line_span::LineSpanExt;
use super::context::ParserContext;
use super::ParsingState;
pub type InnerZ80Span = Stateful<
Located<
&'static BStr
>,
&'static ParserContext
>;
#[derive(Clone, PartialEq, Eq)]
pub struct Z80Span(pub(crate) InnerZ80Span);
impl From<InnerZ80Span> for Z80Span {
fn from(value: InnerZ80Span) -> Self {
Self(value)
}
}
impl From<Z80Span> for InnerZ80Span {
fn from(val: Z80Span) -> Self {
val.0
}
}
impl AsRef<str> for Z80Span {
#[inline]
fn as_ref(&self) -> &str {
unsafe { std::str::from_utf8_unchecked(self.0.as_bstr()) }
}
}
impl<'a> From<&'a Z80Span> for &'a str {
fn from(val: &'a Z80Span) -> Self {
AsRef::as_ref(val)
}
}
pub trait SourceString: Display {
fn as_str(&self) -> &str;
}
impl From<&dyn SourceString> for Symbol {
fn from(val: &dyn SourceString) -> Self {
val.as_str().into()
}
}
impl From<&Z80Span> for Symbol {
fn from(val: &Z80Span) -> Self {
val.as_str().into()
}
}
impl SourceString for &Z80Span {
fn as_str(&self) -> &str {
self.as_ref()
}
}
impl SourceString for Z80Span {
fn as_str(&self) -> &str {
self.as_ref()
}
}
impl SourceString for &String {
fn as_str(&self) -> &str {
self.as_ref()
}
}
impl SourceString for &SmolStr {
fn as_str(&self) -> &str {
self.as_ref()
}
}
impl SourceString for SmolStr {
fn as_str(&self) -> &str {
self.as_ref()
}
}
impl Z80Span {
#[inline]
pub fn complete_source(&self) -> &str {
self.0.state.complete_source()
}
#[inline]
pub fn offset_from_start(&self) -> usize {
let src = self.complete_source();
let src = src.as_bstr();
self.as_bstr().offset_from(&src)
}
#[inline]
pub fn relative_line_and_column(&self) -> (usize, usize) {
let offset = self.offset_from_start();
self.context().relative_line_and_column(offset)
}
#[inline]
pub fn location_line(&self) -> u32 {
self.relative_line_and_column().0 as _
}
#[inline]
pub fn complete_line(&self) -> &str {
let offset = self.offset_from_start();
let range = self.complete_source().find_line_range(offset);
let line = &self.complete_source().as_bytes()[range.start..range.end];
unsafe { std::str::from_utf8_unchecked(line) }
}
#[inline]
pub fn get_line_beginning(&self) -> &str {
self.complete_line()
}
#[inline]
pub fn filename(&self) -> &str {
self.state
.filename()
.as_ref()
.map(|p| p.as_os_str().to_str().unwrap_or("[Invalid file name]"))
.unwrap_or_else(|| {
self.state
.context_name
.as_ref()
.map(|s| s.as_ref())
.unwrap_or_else(|| "no file specified")
})
}
}
impl std::fmt::Display for Z80Span {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}
impl std::fmt::Debug for Z80Span {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let (line, column) = self.relative_line_and_column();
write!(
f,
"{}:{}:{} <{}>",
self.context()
.current_filename
.as_ref()
.map(|p| p.as_str())
.unwrap_or("<unknown filename>"),
line,
column,
self.as_str()
)
}
}
impl From<&Z80Span> for SmolStr {
fn from(val: &Z80Span) -> Self {
SmolStr::from(val.as_str())
}
}
impl From<&Z80Span> for Source {
#[inline]
fn from(val: &Z80Span) -> Self {
let (line, column) = val.relative_line_and_column();
Source::new(
val.context()
.current_filename
.as_ref()
.map(|fname| fname.as_str().to_owned())
.unwrap_or_else(|| "<INLINE>".into()),
line as _,
column
)
}
}
impl Deref for Z80Span {
type Target = InnerZ80Span;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Z80Span {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl AsRef<InnerZ80Span> for Z80Span {
#[inline]
fn as_ref(&self) -> &InnerZ80Span {
self.deref()
}
}
impl Z80Span {
pub fn new_extra<S: ?Sized + AsRef<[u8]>>(src: &S, ctx: &ParserContext) -> Self {
let src = unsafe { std::mem::transmute(BStr::new(src)) };
let ctx = unsafe { &*(ctx as *const ParserContext) as &'static ParserContext };
Self(Stateful {
input: Located::new(src),
state: ctx
})
}
pub fn context(&self) -> &ParserContext {
self.state
}
}
impl Z80Span {
pub fn state(&self) -> &ParsingState {
self.context().state()
}
}