Compare commits
No commits in common. "c624ed31f85119fd5b93db386955f1e2dd79cb7c" and "2d2ecb5129f89d73ded31fe6ef5c0260a6f8871f" have entirely different histories.
c624ed31f8
...
2d2ecb5129
|
@ -36,13 +36,10 @@ itertools = "0.14.0"
|
||||||
mlua = { version = "0.10.2", features = ["lua54", "vendored"], optional = true }
|
mlua = { version = "0.10.2", features = ["lua54", "vendored"], optional = true }
|
||||||
path-absolutize = "3.1.1"
|
path-absolutize = "3.1.1"
|
||||||
pathdiff = "0.2.3"
|
pathdiff = "0.2.3"
|
||||||
serde = { version = "1.0.217", features = ["derive"], optional = true }
|
serde = { version = "1.0.217", features = ["derive", "rc"], optional = true }
|
||||||
shulkerbox = { version = "0.1.0", default-features = false, optional = true }
|
shulkerbox = { version = "0.1.0", default-features = false, optional = true }
|
||||||
strsim = "0.11.1"
|
strsim = "0.11.1"
|
||||||
strum = { version = "0.26.2", features = ["derive"] }
|
strum = { version = "0.26.2", features = ["derive"] }
|
||||||
strum_macros = "0.26.4"
|
strum_macros = "0.26.4"
|
||||||
thiserror = "2.0.11"
|
thiserror = "2.0.11"
|
||||||
tracing = "0.1.41"
|
tracing = "0.1.41"
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
serde_json = "1.0.138"
|
|
||||||
|
|
|
@ -146,7 +146,6 @@ impl SourceFile {
|
||||||
|
|
||||||
/// Represents a range of characters in a source file.
|
/// Represents a range of characters in a source file.
|
||||||
#[derive(Clone, Getters, CopyGetters)]
|
#[derive(Clone, Getters, CopyGetters)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
||||||
pub struct Span {
|
pub struct Span {
|
||||||
/// Get the start byte index of the span.
|
/// Get the start byte index of the span.
|
||||||
#[get_copy = "pub"]
|
#[get_copy = "pub"]
|
||||||
|
@ -158,7 +157,6 @@ pub struct Span {
|
||||||
|
|
||||||
/// Get the source file that the span is located in.
|
/// Get the source file that the span is located in.
|
||||||
#[get = "pub"]
|
#[get = "pub"]
|
||||||
#[cfg_attr(feature = "serde", serde(with = "crate::serde::source_file"))]
|
|
||||||
source_file: Arc<SourceFile>,
|
source_file: Arc<SourceFile>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ pub mod syntax;
|
||||||
pub mod transpile;
|
pub mod transpile;
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
pub(crate) mod serde;
|
mod serde;
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
#[cfg_attr(feature = "serde", doc(inline))]
|
#[cfg_attr(feature = "serde", doc(inline))]
|
||||||
pub use serde::SerdeWrapper;
|
pub use serde::SerdeWrapper;
|
||||||
|
|
225
src/serde.rs
225
src/serde.rs
|
@ -12,7 +12,7 @@ use serde::{
|
||||||
Deserialize, Serialize,
|
Deserialize, Serialize,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::base::source_file::SourceFile;
|
use crate::base::source_file::{SourceFile, Span};
|
||||||
|
|
||||||
static DEDUPLICATE_SOURCE_FILES: LazyLock<RwLock<bool>> = LazyLock::new(|| RwLock::new(false));
|
static DEDUPLICATE_SOURCE_FILES: LazyLock<RwLock<bool>> = LazyLock::new(|| RwLock::new(false));
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@ static DESERIALIZE_DATA: LazyLock<RwLock<Option<DeserializeData>>> =
|
||||||
LazyLock::new(|| RwLock::new(None));
|
LazyLock::new(|| RwLock::new(None));
|
||||||
|
|
||||||
/// Wrapper to remove duplicate source file data during (de-)serialization
|
/// Wrapper to remove duplicate source file data during (de-)serialization
|
||||||
#[expect(clippy::module_name_repetitions)]
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SerdeWrapper<T>(pub T);
|
pub struct SerdeWrapper<T>(pub T);
|
||||||
|
|
||||||
|
@ -84,7 +83,7 @@ where
|
||||||
where
|
where
|
||||||
V: de::SeqAccess<'de>,
|
V: de::SeqAccess<'de>,
|
||||||
{
|
{
|
||||||
let source_files: BTreeMap<u64, SourceFile> = seq
|
let source_files: BTreeMap<usize, SourceFile> = seq
|
||||||
.next_element()?
|
.next_element()?
|
||||||
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
|
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
|
||||||
*DESERIALIZE_DATA.write().unwrap() = Some(DeserializeData {
|
*DESERIALIZE_DATA.write().unwrap() = Some(DeserializeData {
|
||||||
|
@ -104,7 +103,7 @@ where
|
||||||
where
|
where
|
||||||
V: de::MapAccess<'de>,
|
V: de::MapAccess<'de>,
|
||||||
{
|
{
|
||||||
let mut source_files: Option<BTreeMap<u64, SourceFile>> = None;
|
let mut source_files: Option<BTreeMap<usize, SourceFile>> = None;
|
||||||
let mut data = None;
|
let mut data = None;
|
||||||
|
|
||||||
while let Some(key) = map.next_key()? {
|
while let Some(key) = map.next_key()? {
|
||||||
|
@ -141,7 +140,7 @@ where
|
||||||
let res = deserializer.deserialize_struct(
|
let res = deserializer.deserialize_struct(
|
||||||
"SerdeWrapper",
|
"SerdeWrapper",
|
||||||
&["source_files", "data"],
|
&["source_files", "data"],
|
||||||
WrapperVisitor(PhantomData::<T>),
|
WrapperVisitor(PhantomData::<T>::default()),
|
||||||
);
|
);
|
||||||
*DEDUPLICATE_SOURCE_FILES.write().unwrap() = false;
|
*DEDUPLICATE_SOURCE_FILES.write().unwrap() = false;
|
||||||
|
|
||||||
|
@ -152,9 +151,9 @@ where
|
||||||
/// Internally used for Serialization
|
/// Internally used for Serialization
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct SerializeData {
|
struct SerializeData {
|
||||||
id_counter: u64,
|
id_counter: usize,
|
||||||
ptr_to_id: BTreeMap<usize, u64>,
|
ptr_to_id: BTreeMap<usize, usize>,
|
||||||
id_to_source_file: BTreeMap<u64, SourceFile>,
|
id_to_source_file: BTreeMap<usize, SourceFile>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SerializeData {
|
impl SerializeData {
|
||||||
|
@ -165,7 +164,7 @@ impl SerializeData {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get id of already stored [`Arc`] or store it and return new id
|
/// Get id of already stored [`Arc`] or store it and return new id
|
||||||
pub fn get_id_of(&mut self, source_file: &Arc<SourceFile>) -> u64 {
|
pub fn get_id_of(&mut self, source_file: &Arc<SourceFile>) -> usize {
|
||||||
let ptr = Arc::as_ptr(source_file);
|
let ptr = Arc::as_ptr(source_file);
|
||||||
if let Some(&id) = self.ptr_to_id.get(&(ptr as usize)) {
|
if let Some(&id) = self.ptr_to_id.get(&(ptr as usize)) {
|
||||||
id
|
id
|
||||||
|
@ -182,92 +181,150 @@ impl SerializeData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
impl Serialize for Span {
|
||||||
struct DeserializeData {
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
id_to_source_file: BTreeMap<u64, Arc<SourceFile>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod source_file {
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use serde::{de, Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{base::source_file::SourceFile, serde::DESERIALIZE_DATA};
|
|
||||||
|
|
||||||
use super::{DEDUPLICATE_SOURCE_FILES, SERIALIZE_DATA};
|
|
||||||
|
|
||||||
pub fn serialize<S>(this: &Arc<SourceFile>, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde::Serializer,
|
||||||
{
|
{
|
||||||
|
let mut s = serializer.serialize_struct("Span", 3)?;
|
||||||
|
s.serialize_field("start", &self.start())?;
|
||||||
|
s.serialize_field("end", &self.end())?;
|
||||||
|
|
||||||
if *DEDUPLICATE_SOURCE_FILES.read().unwrap() {
|
if *DEDUPLICATE_SOURCE_FILES.read().unwrap() {
|
||||||
let mut data = SERIALIZE_DATA.lock().unwrap();
|
let mut data = SERIALIZE_DATA.lock().unwrap();
|
||||||
serializer.serialize_u64(data.get_id_of(this))
|
s.serialize_field("source_file", &data.get_id_of(self.source_file()))?;
|
||||||
} else {
|
} else {
|
||||||
this.as_ref().serialize(serializer)
|
s.serialize_field("source_file", self.source_file())?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deserialize<'de, D>(deserializer: D) -> Result<Arc<SourceFile>, D::Error>
|
s.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct DeserializeData {
|
||||||
|
id_to_source_file: BTreeMap<usize, Arc<SourceFile>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Span {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: serde::Deserializer<'de>,
|
D: serde::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
if *DEDUPLICATE_SOURCE_FILES.read().unwrap() {
|
#[derive(Deserialize)]
|
||||||
let id = u64::deserialize(deserializer)?;
|
#[serde(field_identifier, rename_all = "snake_case")]
|
||||||
Ok(DESERIALIZE_DATA
|
enum Field {
|
||||||
.read()
|
Start,
|
||||||
.unwrap()
|
End,
|
||||||
.as_ref()
|
SourceFile,
|
||||||
.ok_or_else(|| de::Error::custom("SourceFiles do not have been loaded yet"))?
|
|
||||||
.id_to_source_file
|
|
||||||
.get(&id)
|
|
||||||
.map(Arc::clone)
|
|
||||||
.ok_or_else(|| serde::de::Error::custom("invalid source_file id"))?)
|
|
||||||
} else {
|
|
||||||
Ok(Arc::new(SourceFile::deserialize(deserializer)?))
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
struct SpanVisitor;
|
||||||
|
|
||||||
#[cfg(all(test, feature = "shulkerbox"))]
|
impl<'de> Visitor<'de> for SpanVisitor {
|
||||||
mod tests {
|
type Value = Span;
|
||||||
use std::path::Path;
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
use shulkerbox::virtual_fs::{VFile, VFolder};
|
if *DEDUPLICATE_SOURCE_FILES.read().unwrap() {
|
||||||
|
formatter.write_str("struct Span with deduplicated SourceFiles")
|
||||||
use crate::{base::SilentHandler, syntax::syntax_tree::program::ProgramFile};
|
} else {
|
||||||
|
formatter.write_str("struct Span")
|
||||||
use super::*;
|
}
|
||||||
|
}
|
||||||
#[test]
|
|
||||||
fn test_serde_wrapper() {
|
fn visit_seq<V>(self, mut seq: V) -> Result<Self::Value, V::Error>
|
||||||
let mut vfolder = VFolder::new();
|
where
|
||||||
let vfile = VFile::Text(r#"namespace "test";"#.to_string());
|
V: serde::de::SeqAccess<'de>,
|
||||||
vfolder.add_file("main.shu", vfile);
|
{
|
||||||
|
let start = seq
|
||||||
let parsed = crate::parse(
|
.next_element()?
|
||||||
&SilentHandler::new(),
|
.ok_or_else(|| de::Error::invalid_length(0, &self))?;
|
||||||
&vfolder,
|
let end = seq
|
||||||
Path::new("main.shu"),
|
.next_element()?
|
||||||
"main".to_string(),
|
.ok_or_else(|| de::Error::invalid_length(1, &self))?;
|
||||||
)
|
let source_file = if *DEDUPLICATE_SOURCE_FILES.read().unwrap() {
|
||||||
.unwrap();
|
DESERIALIZE_DATA
|
||||||
|
.read()
|
||||||
let wrapper = SerdeWrapper(parsed);
|
.unwrap()
|
||||||
|
.as_ref()
|
||||||
let serialized = serde_json::to_string_pretty(&wrapper).unwrap();
|
.ok_or_else(|| {
|
||||||
let SerdeWrapper(deserialized) =
|
de::Error::custom("SourceFiles do not have been loaded yet")
|
||||||
serde_json::from_str::<SerdeWrapper<ProgramFile>>(&serialized).unwrap();
|
})?
|
||||||
|
.id_to_source_file
|
||||||
assert_eq!(
|
.get(
|
||||||
Arc::as_ptr(
|
&seq.next_element()?
|
||||||
deserialized
|
.ok_or_else(|| de::Error::invalid_length(2, &self))?,
|
||||||
.namespace()
|
)
|
||||||
.namespace_keyword()
|
.ok_or_else(|| de::Error::custom("invalid source_file id"))?
|
||||||
.span
|
.clone()
|
||||||
.source_file()
|
} else {
|
||||||
),
|
Arc::new(
|
||||||
Arc::as_ptr(deserialized.namespace().namespace_name().span.source_file())
|
seq.next_element()?
|
||||||
);
|
.ok_or_else(|| de::Error::invalid_length(2, &self))?,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Span::new(source_file, start, end)
|
||||||
|
.ok_or_else(|| de::Error::custom("Invalid data"))?)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
|
||||||
|
where
|
||||||
|
V: de::MapAccess<'de>,
|
||||||
|
{
|
||||||
|
let mut start = None;
|
||||||
|
let mut end = None;
|
||||||
|
let mut source_file = None;
|
||||||
|
|
||||||
|
while let Some(key) = map.next_key()? {
|
||||||
|
match key {
|
||||||
|
Field::Start => {
|
||||||
|
if start.is_some() {
|
||||||
|
return Err(de::Error::duplicate_field("start"));
|
||||||
|
}
|
||||||
|
start = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
Field::End => {
|
||||||
|
if end.is_some() {
|
||||||
|
return Err(de::Error::duplicate_field("end"));
|
||||||
|
}
|
||||||
|
end = Some(map.next_value()?);
|
||||||
|
}
|
||||||
|
Field::SourceFile => {
|
||||||
|
if source_file.is_some() {
|
||||||
|
return Err(de::Error::duplicate_field("source_file"));
|
||||||
|
}
|
||||||
|
source_file = if *DEDUPLICATE_SOURCE_FILES.read().unwrap() {
|
||||||
|
Some(
|
||||||
|
DESERIALIZE_DATA
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.as_ref()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
de::Error::custom(
|
||||||
|
"SourceFiles do not have been loaded yet",
|
||||||
|
)
|
||||||
|
})?
|
||||||
|
.id_to_source_file
|
||||||
|
.get(&map.next_value()?)
|
||||||
|
.ok_or_else(|| de::Error::custom("invalid source_file id"))?
|
||||||
|
.clone(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Some(Arc::new(map.next_value()?))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let start = start.ok_or_else(|| de::Error::missing_field("start"))?;
|
||||||
|
let end = end.ok_or_else(|| de::Error::missing_field("end"))?;
|
||||||
|
let source_file = source_file.ok_or_else(|| de::Error::missing_field("source"))?;
|
||||||
|
|
||||||
|
Ok(Span::new(source_file, start, end)
|
||||||
|
.ok_or_else(|| de::Error::custom("Invalid data"))?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_struct("Span", &["start", "end", "source_file"], SpanVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue