diff --git a/.gitignore b/.gitignore index 251a069..e7781fa 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,6 @@ target /invalid.rs /invalid .direnv/ -g \ No newline at end of file +g +perf.data* +*.svg diff --git a/Cargo.lock b/Cargo.lock index ba05446..de66117 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -113,6 +113,9 @@ dependencies = [ "tracing", "tracing-subscriber", "tracing-tree", + "tree-sitter", + "tree-sitter-edit", + "tree-sitter-rust", "walkdir", ] @@ -855,6 +858,45 @@ dependencies = [ "tracing-subscriber", ] +[[package]] +name = "tree-sitter" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e747b1f9b7b931ed39a548c1fae149101497de3c1fc8d9e18c62c1a66c683d3d" +dependencies = [ + "cc", + "regex", +] + +[[package]] +name = "tree-sitter-edit" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed3213ee656e99748eca539913b5c90df3d52618d9a1714e0935013955c8031" +dependencies = [ + "tree-sitter", + "tree-sitter-traversal", +] + +[[package]] +name = "tree-sitter-rust" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0832309b0b2b6d33760ce5c0e818cb47e1d72b468516bfe4134408926fa7594" +dependencies = [ + "cc", + "tree-sitter", +] + +[[package]] +name = "tree-sitter-traversal" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8a158225e4a4d8505f071340bba9edd109b23f01b70540dccb7c799868f307" +dependencies = [ + "tree-sitter", +] + [[package]] name = "unicode-id" version = "0.3.4" diff --git a/Cargo.toml b/Cargo.toml index 5aead06..b8d7862 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,8 +16,12 @@ license = "MIT OR Apache-2.0" [profile.release] lto = "thin" -[profile.dev] -opt-level = 1 +[profile.dev.package.proc-macro2] +opt-level = 3 +[profile.dev.package.syn] +opt-level = 3 +[profile.dev.package.genemichaels] +opt-level = 3 [dependencies] anyhow = "1.0.65" @@ -36,4 +40,7 @@ tempfile = "3.3.0" tracing = "0.1.37" tracing-subscriber = { version = "0.3.16", features = ["env-filter"] } tracing-tree = "0.2.2" +tree-sitter = "0.20.10" +tree-sitter-edit = "0.3.0" +tree-sitter-rust = "0.20.4" walkdir = "2.3.2" diff --git a/src/dylib_flag.rs b/src/dylib_flag.rs index 229ea6d..7507a49 100644 --- a/src/dylib_flag.rs +++ b/src/dylib_flag.rs @@ -32,7 +32,7 @@ impl FromStr for RustFunction { fn wrap_func_body(func: &str) -> Result { let closure = syn::parse_str::(func).context("invalid rust syntax")?; - let syn_file = syn::parse_quote! { + let file = quote::quote! { #[repr(C)] pub struct __RawOutput { out_ptr: *const u8, @@ -80,7 +80,7 @@ fn wrap_func_body(func: &str) -> Result { } }; - crate::formatting::format(syn_file) + Ok(file.to_string()) } impl RustFunction { diff --git a/src/formatting.rs b/src/formatting.rs deleted file mode 100644 index a250cd4..0000000 --- a/src/formatting.rs +++ /dev/null @@ -1,12 +0,0 @@ -use std::collections::HashMap; - -use anyhow::Context; -use genemichaels::FormatConfig; - -pub fn format(file: syn::File) -> anyhow::Result { - Ok( - genemichaels::format_ast(file, &FormatConfig::default(), HashMap::new()) - .context("formatting source file")? - .rendered, - ) -} diff --git a/src/lib.rs b/src/lib.rs index dc8dd21..7b1be42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ use std::{ mod build; mod dylib_flag; -mod formatting; +mod tree_sitter; mod passes; mod processor; diff --git a/src/processor/files.rs b/src/processor/files.rs index f906982..0eb30b1 100644 --- a/src/processor/files.rs +++ b/src/processor/files.rs @@ -19,24 +19,26 @@ mod file { pub(crate) struct SourceFile { path: PathBuf, content_str: RefCell, - content: RefCell, + content: RefCell, } impl SourceFile { pub(crate) fn open(path: PathBuf) -> Result { let string = std::fs::read_to_string(&path) .with_context(|| format!("reading file {}", path.display()))?; - let content = syn::parse_file(&string) - .with_context(|| format!("parsing file {}", path.display()))?; + + let content_ts = crate::tree_sitter::parse(&string) + .with_context(|| format!("parsing file {path:?}"))?; + Ok(SourceFile { path, content_str: RefCell::new(string), - content: RefCell::new(content), + content: RefCell::new(content_ts), }) } - pub(crate) fn write(&self, new: syn::File) -> Result<()> { - let string = crate::formatting::format(new.clone())?; + pub(crate) fn write(&self, new: tree_sitter::Tree) -> Result<()> { + let string = crate::tree_sitter::format(new, &*self.content_str.borrow())?; std::fs::write(&self.path, &string) .with_context(|| format!("writing file {}", self.path.display()))?; *self.content_str.borrow_mut() = string; @@ -96,17 +98,17 @@ pub(crate) struct FileChange<'a, 'b> { pub(crate) path: &'a Path, source_file: &'a SourceFile, before_content_str: String, - before_content: syn::File, + before_content: tree_sitter::Tree, changes: &'b mut Changes, has_written_change: bool, } impl FileChange<'_, '_> { - pub(crate) fn before_content(&self) -> (&str, &syn::File) { + pub(crate) fn before_content(&self) -> (&str, &tree_sitter::Tree) { (&self.before_content_str, &self.before_content) } - pub(crate) fn write(&mut self, new: syn::File) -> Result<()> { + pub(crate) fn write(&mut self, new: tree_sitter::Tree) -> Result<()> { self.has_written_change = true; self.source_file.write(new)?; Ok(()) diff --git a/src/processor/reaper.rs b/src/processor/reaper.rs index 5361d15..10dd969 100644 --- a/src/processor/reaper.rs +++ b/src/processor/reaper.rs @@ -82,7 +82,7 @@ impl Minimizer { let result = rustfix::apply_suggestions(change.before_content().0, &desired_suggestions)?; - let result = syn::parse_file(&result).context("parsing file after rustfix")?; + let result = crate::tree_sitter::parse(&result).context("parsing file after rustfix")?; change.write(result)?; let after = self.build.build()?; diff --git a/src/tree_sitter.rs b/src/tree_sitter.rs new file mode 100644 index 0000000..46c6d12 --- /dev/null +++ b/src/tree_sitter.rs @@ -0,0 +1,34 @@ +use anyhow::{Context, Result}; + +pub fn parse(source: &str) -> Result { + let mut parser = tree_sitter::Parser::new(); + parser + .set_language(tree_sitter_rust::language()) + .context("loading tree sitter rust grammar")?; + let content_ts = parser.parse(source, None).context("parsing file")?; + Ok(content_ts) +} + +pub fn format(file: tree_sitter::Tree, source: &str) -> anyhow::Result { + let mut s = Vec::new(); + tree_sitter_edit::render(&mut s, &file, source.as_bytes(), &Editor); + + Ok(String::from_utf8(s).unwrap()) +} + +struct Editor; + +impl tree_sitter_edit::Editor for Editor { + fn has_edit(&self, tree: &tree_sitter::Tree, node: &tree_sitter::Node<'_>) -> bool { + false + } + + fn edit( + &self, + source: &[u8], + tree: &tree_sitter::Tree, + node: &tree_sitter::Node<'_>, + ) -> Vec { + unimplemented!() + } +}