From 112aa2ff73bd456c32351c9eadc260a31719156b Mon Sep 17 00:00:00 2001 From: maciektr Date: Mon, 8 Apr 2024 09:42:22 +0200 Subject: [PATCH] Replace result enum with single struct commit-id:3f7d4d4c --- .../cairo-lang-macro-attributes/src/lib.rs | 54 ++---- plugins/cairo-lang-macro-stable/src/lib.rs | 21 +-- .../cairo-lang-macro/src/types/conversion.rs | 166 +++++------------- plugins/cairo-lang-macro/src/types/mod.rs | 125 ++++--------- scarb/src/compiler/plugin/proc_macro/host.rs | 136 +++++++------- scarb/tests/build_cairo_plugin.rs | 151 ++++++++++++---- 6 files changed, 271 insertions(+), 382 deletions(-) diff --git a/plugins/cairo-lang-macro-attributes/src/lib.rs b/plugins/cairo-lang-macro-attributes/src/lib.rs index ce531c3ca..236032dde 100644 --- a/plugins/cairo-lang-macro-attributes/src/lib.rs +++ b/plugins/cairo-lang-macro-attributes/src/lib.rs @@ -1,5 +1,5 @@ use proc_macro::TokenStream; -use quote::quote; +use quote::{quote, ToTokens}; use scarb_stable_hash::short_hash; use syn::spanned::Spanned; use syn::{parse_macro_input, ItemFn}; @@ -11,35 +11,20 @@ use syn::{parse_macro_input, ItemFn}; /// Note, that this macro can be used multiple times, to define multiple independent attribute macros. #[proc_macro_attribute] pub fn attribute_macro(_args: TokenStream, input: TokenStream) -> TokenStream { - let item: ItemFn = parse_macro_input!(input as ItemFn); - let original_item_name = item.sig.ident.to_string(); - let item = hide_name(item); - let item_name = &item.sig.ident; - - let callback_link = format!( - "EXPANSIONS_DESERIALIZE_{}", - item_name.to_string().to_uppercase() - ); - let callback_link = syn::Ident::new(callback_link.as_str(), item.span()); - - let expanded = quote! { - #item - - #[::cairo_lang_macro::linkme::distributed_slice(::cairo_lang_macro::MACRO_DEFINITIONS_SLICE)] - #[linkme(crate = ::cairo_lang_macro::linkme)] - static #callback_link: ::cairo_lang_macro::ExpansionDefinition = - ::cairo_lang_macro::ExpansionDefinition{ - name: #original_item_name, - kind: ::cairo_lang_macro::ExpansionKind::Attr, - fun: #item_name, - }; - }; - - TokenStream::from(expanded) + macro_helper(input, quote!(::cairo_lang_macro::ExpansionKind::Attr)) } +/// Constructs the inline macro implementation. +/// +/// This macro hides the conversion to stable ABI structs from the user. +/// +/// Note, that this macro can be used multiple times, to define multiple independent attribute macros. #[proc_macro_attribute] pub fn inline_macro(_args: TokenStream, input: TokenStream) -> TokenStream { + macro_helper(input, quote!(::cairo_lang_macro::ExpansionKind::Inline)) +} + +fn macro_helper(input: TokenStream, kind: impl ToTokens) -> TokenStream { let item: ItemFn = parse_macro_input!(input as ItemFn); let original_item_name = item.sig.ident.to_string(); let item = hide_name(item); @@ -49,32 +34,21 @@ pub fn inline_macro(_args: TokenStream, input: TokenStream) -> TokenStream { "EXPANSIONS_DESERIALIZE_{}", item_name.to_string().to_uppercase() ); - let callback_link = syn::Ident::new(callback_link.as_str(), item.span()); - // We wrap original function with `InlineProcMacroResult` to `ProcMacroResult` conversion. - // This stems from the fact, that `ProcMacroResult::Remove` does not really make sense for inline macros. - let wrapper_name = format!("{item_name}_inline_wrapper"); - let wrapper_name = syn::Ident::new(wrapper_name.as_str(), item.span()); + let callback_link = syn::Ident::new(callback_link.as_str(), item.span()); let expanded = quote! { #item - fn #wrapper_name(token_stream: ::cairo_lang_macro::TokenStream) -> ::cairo_lang_macro::ProcMacroResult { - // Assign function pointer, to validate type. - let f: fn(::cairo_lang_macro::TokenStream) -> ::cairo_lang_macro::InlineProcMacroResult = #item_name; - f(token_stream).into() - } - #[::cairo_lang_macro::linkme::distributed_slice(::cairo_lang_macro::MACRO_DEFINITIONS_SLICE)] #[linkme(crate = ::cairo_lang_macro::linkme)] static #callback_link: ::cairo_lang_macro::ExpansionDefinition = ::cairo_lang_macro::ExpansionDefinition{ name: #original_item_name, - kind: ::cairo_lang_macro::ExpansionKind::Inline, - fun: #wrapper_name, + kind: #kind, + fun: #item_name, }; }; - TokenStream::from(expanded) } diff --git a/plugins/cairo-lang-macro-stable/src/lib.rs b/plugins/cairo-lang-macro-stable/src/lib.rs index 804a719f8..654e8169d 100644 --- a/plugins/cairo-lang-macro-stable/src/lib.rs +++ b/plugins/cairo-lang-macro-stable/src/lib.rs @@ -62,22 +62,11 @@ pub type StableSeverity = NonZeroU8; /// This struct implements FFI-safe stable ABI. #[repr(C)] #[derive(Debug)] -pub enum StableProcMacroResult { - /// Plugin has not taken any action. - Leave { - diagnostics: StableSlice, - }, - /// Plugin generated [`StableTokenStream`] replacement. - Replace { - diagnostics: StableSlice, - token_stream: StableTokenStream, - aux_data: StableAuxData, - full_path_markers: StableSlice<*mut c_char>, - }, - /// Plugin ordered item removal. - Remove { - diagnostics: StableSlice, - }, +pub struct StableProcMacroResult { + pub token_stream: StableTokenStream, + pub diagnostics: StableSlice, + pub aux_data: StableAuxData, + pub full_path_markers: StableSlice<*mut c_char>, } #[repr(C)] diff --git a/plugins/cairo-lang-macro/src/types/conversion.rs b/plugins/cairo-lang-macro/src/types/conversion.rs index d069f6761..2e5516d0a 100644 --- a/plugins/cairo-lang-macro/src/types/conversion.rs +++ b/plugins/cairo-lang-macro/src/types/conversion.rs @@ -19,46 +19,21 @@ impl ProcMacroResult { /// # Safety #[doc(hidden)] pub fn into_stable(self) -> StableProcMacroResult { - match self { - ProcMacroResult::Leave { diagnostics } => { - let diagnostics = diagnostics - .into_iter() - .map(|d| d.into_stable()) - .collect::>(); - StableProcMacroResult::Leave { - diagnostics: StableSlice::new(diagnostics), - } - } - ProcMacroResult::Remove { diagnostics } => { - let diagnostics = diagnostics - .into_iter() - .map(|d| d.into_stable()) - .collect::>(); - StableProcMacroResult::Remove { - diagnostics: StableSlice::new(diagnostics), - } - } - ProcMacroResult::Replace { - token_stream, - aux_data, - diagnostics, - full_path_markers, - } => { - let diagnostics = diagnostics - .into_iter() - .map(|d| d.into_stable()) - .collect::>(); - let full_path_markers = full_path_markers - .into_iter() - .map(|m| CString::new(m).unwrap().into_raw()) - .collect::>(); - StableProcMacroResult::Replace { - token_stream: token_stream.into_stable(), - aux_data: AuxData::maybe_into_stable(aux_data), - diagnostics: StableSlice::new(diagnostics), - full_path_markers: StableSlice::new(full_path_markers), - } - } + let diagnostics = self + .diagnostics + .into_iter() + .map(|d| d.into_stable()) + .collect::>(); + let full_path_markers = self + .full_path_markers + .into_iter() + .map(|m| CString::new(m).unwrap().into_raw()) + .collect::>(); + StableProcMacroResult { + token_stream: self.token_stream.into_stable(), + aux_data: AuxData::maybe_into_stable(self.aux_data), + diagnostics: StableSlice::new(diagnostics), + full_path_markers: StableSlice::new(full_path_markers), } } @@ -69,46 +44,21 @@ impl ProcMacroResult { /// # Safety #[doc(hidden)] pub unsafe fn from_stable(result: &StableProcMacroResult) -> Self { - match result { - StableProcMacroResult::Leave { diagnostics } => { - let (ptr, n) = diagnostics.raw_parts(); - let diagnostics = slice::from_raw_parts(ptr, n) - .iter() - .map(|d| Diagnostic::from_stable(d)) - .collect::>(); - ProcMacroResult::Leave { diagnostics } - } - StableProcMacroResult::Remove { diagnostics } => { - let (ptr, n) = diagnostics.raw_parts(); - let diagnostics = slice::from_raw_parts(ptr, n) - .iter() - .map(|d| Diagnostic::from_stable(d)) - .collect::>(); - ProcMacroResult::Remove { diagnostics } - } - StableProcMacroResult::Replace { - token_stream, - aux_data, - diagnostics, - full_path_markers, - } => { - let (ptr, n) = diagnostics.raw_parts(); - let diagnostics = slice::from_raw_parts(ptr, n) - .iter() - .map(|d| Diagnostic::from_stable(d)) - .collect::>(); - let (ptr, n) = full_path_markers.raw_parts(); - let full_path_markers = slice::from_raw_parts(ptr, n) - .iter() - .map(|m| from_raw_cstr(*m)) - .collect::>(); - ProcMacroResult::Replace { - token_stream: TokenStream::from_stable(token_stream), - aux_data: AuxData::from_stable(aux_data), - diagnostics, - full_path_markers, - } - } + let (ptr, n) = result.diagnostics.raw_parts(); + let diagnostics = slice::from_raw_parts(ptr, n) + .iter() + .map(|d| Diagnostic::from_stable(d)) + .collect::>(); + let (ptr, n) = result.full_path_markers.raw_parts(); + let full_path_markers = slice::from_raw_parts(ptr, n) + .iter() + .map(|m| from_raw_cstr(*m)) + .collect::>(); + ProcMacroResult { + token_stream: TokenStream::from_stable(&result.token_stream), + diagnostics, + full_path_markers, + aux_data: AuxData::from_stable(&result.aux_data), } } @@ -120,46 +70,22 @@ impl ProcMacroResult { /// # Safety #[doc(hidden)] pub unsafe fn from_owned_stable(result: StableProcMacroResult) -> Self { - match result { - StableProcMacroResult::Leave { diagnostics } => { - let diagnostics = diagnostics.into_owned(); - let diagnostics = diagnostics - .into_iter() - .map(|d| Diagnostic::from_owned_stable(d)) - .collect::>(); - ProcMacroResult::Leave { diagnostics } - } - StableProcMacroResult::Remove { diagnostics } => { - let diagnostics = diagnostics.into_owned(); - let diagnostics = diagnostics - .into_iter() - .map(|d| Diagnostic::from_owned_stable(d)) - .collect::>(); - ProcMacroResult::Remove { diagnostics } - } - StableProcMacroResult::Replace { - token_stream, - aux_data, - diagnostics, - full_path_markers, - } => { - let diagnostics = diagnostics.into_owned(); - let diagnostics = diagnostics - .into_iter() - .map(|d| Diagnostic::from_owned_stable(d)) - .collect::>(); - let full_path_markers = full_path_markers - .into_owned() - .iter() - .map(|m| from_raw_cstring(*m)) - .collect::>(); - ProcMacroResult::Replace { - token_stream: TokenStream::from_owned_stable(token_stream), - aux_data: AuxData::from_owned_stable(aux_data), - diagnostics, - full_path_markers, - } - } + let diagnostics = result.diagnostics.into_owned(); + let diagnostics = diagnostics + .into_iter() + .map(|d| Diagnostic::from_owned_stable(d)) + .collect::>(); + let full_path_markers = result + .full_path_markers + .into_owned() + .iter() + .map(|m| from_raw_cstring(*m)) + .collect::>(); + ProcMacroResult { + token_stream: TokenStream::from_owned_stable(result.token_stream), + aux_data: AuxData::from_owned_stable(result.aux_data), + diagnostics, + full_path_markers, } } } diff --git a/plugins/cairo-lang-macro/src/types/mod.rs b/plugins/cairo-lang-macro/src/types/mod.rs index 40d5a58de..e1124cdd5 100644 --- a/plugins/cairo-lang-macro/src/types/mod.rs +++ b/plugins/cairo-lang-macro/src/types/mod.rs @@ -8,32 +8,11 @@ pub use expansions::*; /// Result of procedural macro code generation. #[derive(Debug)] -pub enum ProcMacroResult { - /// Plugin has not taken any action. - Leave { diagnostics: Vec }, - /// Plugin generated [`TokenStream`] replacement. - Replace { - token_stream: TokenStream, - aux_data: Option, - diagnostics: Vec, - full_path_markers: Vec, - }, - /// Plugin ordered item removal. - Remove { diagnostics: Vec }, -} - -/// Result of inline procedural macro code generation. -/// -/// This enum differs from `ProcMacroResult` by not having `Remove` variant. -pub enum InlineProcMacroResult { - /// Plugin has not taken any action. - Leave { diagnostics: Vec }, - /// Plugin generated [`TokenStream`] replacement. - Replace { - token_stream: TokenStream, - aux_data: Option, - diagnostics: Vec, - }, +pub struct ProcMacroResult { + pub token_stream: TokenStream, + pub aux_data: Option, + pub diagnostics: Vec, + pub full_path_markers: Vec, } /// An abstract stream of Cairo tokens. @@ -67,6 +46,11 @@ impl TokenStream { } } + #[doc(hidden)] + pub fn empty() -> Self { + Self::new("".to_string()) + } + #[doc(hidden)] pub fn with_metadata(mut self, metadata: TokenStreamMetadata) -> Self { self.metadata = metadata; @@ -79,6 +63,10 @@ impl TokenStream { pub fn metadata(&self) -> &TokenStreamMetadata { &self.metadata } + + pub fn is_empty(&self) -> bool { + self.to_string().is_empty() + } } impl Display for TokenStream { @@ -129,7 +117,7 @@ impl TokenStreamMetadata { /// let value = serde_json::to_string(&value).unwrap(); /// let value: Vec = value.into_bytes(); /// let aux_data = AuxData::new(value); -/// ProcMacroResult::replace(token_stream, Some(aux_data)) +/// ProcMacroResult::new(token_stream).with_aux_data(aux_data) /// } /// /// #[post_process] @@ -259,86 +247,35 @@ impl IntoIterator for Diagnostics { } impl ProcMacroResult { - /// Create new [`ProcMacroResult::Leave`] variant, empty diagnostics set. - pub fn leave() -> Self { - Self::Leave { - diagnostics: Vec::new(), - } - } - - /// Create new [`ProcMacroResult::Remove`] variant, empty diagnostics set. - pub fn remove() -> Self { - Self::Remove { - diagnostics: Vec::new(), - } - } - - /// Create new [`ProcMacroResult::Replace`] variant, empty diagnostics set. - pub fn replace(token_stream: TokenStream, aux_data: Option) -> Self { - Self::Replace { - aux_data, + /// Create new [`ProcMacroResult`], empty diagnostics set. + pub fn new(token_stream: TokenStream) -> Self { + Self { token_stream, - diagnostics: Vec::new(), - full_path_markers: Vec::new(), + aux_data: Default::default(), + diagnostics: Default::default(), + full_path_markers: Default::default(), } } - /// Append diagnostics to the [`ProcMacroResult`] diagnostics set. - pub fn with_diagnostics(mut self, diagnostics: Diagnostics) -> Self { - match &mut self { - Self::Leave { diagnostics: d } => d.extend(diagnostics), - Self::Remove { diagnostics: d } => d.extend(diagnostics), - Self::Replace { diagnostics: d, .. } => d.extend(diagnostics), - }; + /// Set [`AuxData`] on the [`ProcMacroResult`]. + pub fn with_aux_data(mut self, aux_data: AuxData) -> Self { + self.aux_data = Some(aux_data); self } -} -impl InlineProcMacroResult { - /// Create new [`InlineProcMacroResult::Leave`] variant, empty diagnostics set. - pub fn leave() -> Self { - Self::Leave { - diagnostics: Vec::new(), - } - } - - /// Create new [`InlineProcMacroResult::Replace`] variant, empty diagnostics set. - pub fn replace(token_stream: TokenStream, aux_data: Option) -> Self { - Self::Replace { - aux_data, - token_stream, - diagnostics: Vec::new(), - } + /// Append full path markers to the [`ProcMacroResult`]. + pub fn with_full_path_markers(mut self, full_path_markers: Vec) -> Self { + self.full_path_markers.extend(full_path_markers); + self } - /// Append diagnostics to the [`InlineProcMacroResult`] diagnostics set. + /// Append diagnostics to the [`ProcMacroResult`] diagnostics set. pub fn with_diagnostics(mut self, diagnostics: Diagnostics) -> Self { - match &mut self { - Self::Leave { diagnostics: d } => d.extend(diagnostics), - Self::Replace { diagnostics: d, .. } => d.extend(diagnostics), - }; + self.diagnostics.extend(diagnostics); self } } -impl From for ProcMacroResult { - fn from(result: InlineProcMacroResult) -> Self { - match result { - InlineProcMacroResult::Leave { diagnostics } => ProcMacroResult::Leave { diagnostics }, - InlineProcMacroResult::Replace { - token_stream, - aux_data, - diagnostics, - } => ProcMacroResult::Replace { - token_stream, - aux_data, - diagnostics, - full_path_markers: Vec::new(), - }, - } - } -} - /// Input for the post-process callback. #[derive(Clone, Debug)] pub struct PostProcessContext { @@ -365,7 +302,7 @@ mod tests { #[test] fn new_token_stream_metadata_empty() { - let token_stream = TokenStream::new("".to_string()); + let token_stream = TokenStream::empty(); assert!(token_stream.metadata.file_id.is_none()); assert!(token_stream.metadata.original_file_path.is_none()); } diff --git a/scarb/src/compiler/plugin/proc_macro/host.rs b/scarb/src/compiler/plugin/proc_macro/host.rs index c24744fd5..fa419d78d 100644 --- a/scarb/src/compiler/plugin/proc_macro/host.rs +++ b/scarb/src/compiler/plugin/proc_macro/host.rs @@ -9,8 +9,7 @@ use cairo_lang_defs::plugin::{ use cairo_lang_defs::plugin::{InlineMacroExprPlugin, InlinePluginResult, PluginDiagnostic}; use cairo_lang_diagnostics::ToOption; use cairo_lang_macro::{ - AuxData, Diagnostic, ExpansionKind, FullPathMarker, ProcMacroResult, Severity, TokenStream, - TokenStreamMetadata, + AuxData, Diagnostic, ExpansionKind, FullPathMarker, Severity, TokenStream, TokenStreamMetadata, }; use cairo_lang_semantic::db::SemanticGroup; use cairo_lang_semantic::items::attribute::SemanticQueryAttrs; @@ -353,44 +352,39 @@ impl MacroPlugin for ProcMacroHostPlugin { let mut modified = false; let mut all_diagnostics: Vec = Vec::new(); for input in expansions { - match self + let result = self .instance(input.package_id) - .generate_code(input.expansion.name.clone(), token_stream.clone()) - { - ProcMacroResult::Replace { - token_stream: new_token_stream, - aux_data: new_aux_data, - diagnostics, - full_path_markers, - } => { - token_stream = new_token_stream; - if let Some(new_aux_data) = new_aux_data { - aux_data.push(ProcMacroAuxData::new( - new_aux_data.into(), - ProcMacroId::new(input.package_id, input.expansion.clone()), - )); - } - modified = true; - all_diagnostics.extend(diagnostics); - self.full_path_markers - .write() - .unwrap() - .entry(input.package_id) - .and_modify(|markers| markers.extend(full_path_markers.clone().into_iter())) - .or_insert(full_path_markers); - } - ProcMacroResult::Remove { diagnostics } => { - all_diagnostics.extend(diagnostics); - return PluginResult { - diagnostics: into_cairo_diagnostics(all_diagnostics, stable_ptr), - code: None, - remove_original_item: true, - }; - } - ProcMacroResult::Leave { diagnostics } => { - all_diagnostics.extend(diagnostics); - } - }; + .generate_code(input.expansion.name.clone(), token_stream.clone()); + + // Handle diagnostics. + all_diagnostics.extend(result.diagnostics); + // Handle aux data. + if let Some(new_aux_data) = result.aux_data { + aux_data.push(ProcMacroAuxData::new( + new_aux_data.into(), + ProcMacroId::new(input.package_id, input.expansion.clone()), + )); + } + // Handle token stream. + let new_token_stream = result.token_stream.clone(); + if new_token_stream.is_empty() { + // Remove original code + return PluginResult { + diagnostics: into_cairo_diagnostics(all_diagnostics, stable_ptr), + code: None, + remove_original_item: true, + }; + } + // Replace original code. + modified = new_token_stream.to_string() != token_stream.to_string(); + token_stream = new_token_stream; + // Full path markers require code modification. + self.full_path_markers + .write() + .unwrap() + .entry(input.package_id) + .and_modify(|markers| markers.extend(result.full_path_markers.clone().into_iter())) + .or_insert(result.full_path_markers); } if modified { PluginResult { @@ -462,45 +456,37 @@ impl InlineMacroExprPlugin for ProcMacroInlinePlugin { let stable_ptr = syntax.clone().stable_ptr().untyped(); let token_stream = TokenStream::from_syntax_node(db, syntax.as_syntax_node()); - match self + let result = self .instance() - .generate_code(self.expansion.name.clone(), token_stream) - { - ProcMacroResult::Replace { - token_stream, - aux_data, + .generate_code(self.expansion.name.clone(), token_stream); + // Handle diagnostics. + let diagnostics = into_cairo_diagnostics(result.diagnostics, stable_ptr); + let token_stream = result.token_stream.clone(); + if token_stream.is_empty() { + // Remove original code + InlinePluginResult { + code: None, diagnostics, - // Ignore, as we know that inline macros do not generate full path markers. - full_path_markers: _, - } => { - let aux_data = aux_data.map(|aux_data| { - let aux_data = ProcMacroAuxData::new( - aux_data.into(), - ProcMacroId::new(self.instance.package_id(), self.expansion.clone()), - ); - let mut emitted = EmittedAuxData::default(); - emitted.push(aux_data); - DynGeneratedFileAuxData::new(emitted) - }); - - InlinePluginResult { - code: Some(PluginGeneratedFile { - name: "inline_proc_macro".into(), - content: token_stream.to_string(), - code_mappings: Default::default(), - aux_data, - }), - diagnostics: into_cairo_diagnostics(diagnostics, stable_ptr), - } } - ProcMacroResult::Remove { diagnostics } => InlinePluginResult { - code: None, - diagnostics: into_cairo_diagnostics(diagnostics, stable_ptr), - }, - ProcMacroResult::Leave { .. } => { - // Safe to panic, as all inline macros should originally return `InlineProcMacroResult`. - // Which is validated inside the inline macro helper attribute. - panic!("inline macro cannot return `Leave` result"); + } else { + // Replace + let aux_data = result.aux_data.map(|aux_data| { + let aux_data = ProcMacroAuxData::new( + aux_data.into(), + ProcMacroId::new(self.instance.package_id(), self.expansion.clone()), + ); + let mut emitted = EmittedAuxData::default(); + emitted.push(aux_data); + DynGeneratedFileAuxData::new(emitted) + }); + InlinePluginResult { + code: Some(PluginGeneratedFile { + name: "inline_proc_macro".into(), + content: token_stream.to_string(), + code_mappings: Default::default(), + aux_data, + }), + diagnostics, } } } diff --git a/scarb/tests/build_cairo_plugin.rs b/scarb/tests/build_cairo_plugin.rs index a07cdbc92..595c919a5 100644 --- a/scarb/tests/build_cairo_plugin.rs +++ b/scarb/tests/build_cairo_plugin.rs @@ -101,8 +101,7 @@ fn simple_project(t: &impl PathChild) { #[attribute_macro] pub fn some(token_stream: TokenStream) -> ProcMacroResult { - let _code = token_stream.to_string(); - ProcMacroResult::Leave { diagnostics: Vec::new() } + ProcMacroResult::new(token_stream) } "#}; simple_project_with_code(t, code); @@ -276,9 +275,9 @@ fn can_emit_plugin_warning() { #[attribute_macro] pub fn some(token_stream: TokenStream) -> ProcMacroResult { - let _code = token_stream.to_string(); let diag = Diagnostic::warn("Some warning from macro."); - ProcMacroResult::Leave { diagnostics: vec![diag] } + ProcMacroResult::new(token_stream) + .with_diagnostics(vec![diag].into()) } "#}, ); @@ -323,9 +322,9 @@ fn can_emit_plugin_error() { #[attribute_macro] pub fn some(token_stream: TokenStream) -> ProcMacroResult { - let _code = token_stream.to_string(); let diag = Diagnostic::error("Some error from macro."); - ProcMacroResult::Leave { diagnostics: vec![diag] } + ProcMacroResult::new(token_stream) + .with_diagnostics(vec![diag].into()) } "#}, ); @@ -370,7 +369,7 @@ fn can_remove_original_node() { #[attribute_macro] pub fn some(_: TokenStream) -> ProcMacroResult { - ProcMacroResult::Remove { diagnostics: Vec::new() } + ProcMacroResult::new(TokenStream::empty()) } "#}, ); @@ -424,12 +423,7 @@ fn can_replace_original_node() { .replace("#[some]", "") .replace("12", "34") ); - ProcMacroResult::Replace { - token_stream, - aux_data: None, - diagnostics: Vec::new(), - full_path_markers: Vec::new(), - } + ProcMacroResult::new(token_stream) } "##}, ); @@ -488,8 +482,7 @@ fn can_return_aux_data_from_plugin() { let value = serde_json::to_string(&value).unwrap(); let value: Vec = value.into_bytes(); let aux_data = AuxData::new(value); - - ProcMacroResult::replace(token_stream, Some(aux_data)) + ProcMacroResult::new(token_stream).with_aux_data(aux_data) } #[post_process] @@ -550,7 +543,7 @@ fn can_read_token_stream_metadata() { #[attribute_macro] pub fn some(token_stream: TokenStream) -> ProcMacroResult { println!("{:#?}", token_stream.metadata()); - ProcMacroResult::Leave { diagnostics: Vec::new() } + ProcMacroResult::new(token_stream) } "##}, @@ -609,7 +602,7 @@ fn can_define_multiple_macros() { .replace("12", "34") ); let aux_data = AuxData::new(Vec::new()); - ProcMacroResult::replace(token_stream, Some(aux_data)) + ProcMacroResult::new(token_stream).with_aux_data(aux_data) } #[attribute_macro] @@ -622,7 +615,7 @@ fn can_define_multiple_macros() { .replace("56", "78") ); let aux_data = AuxData::new(Vec::new()); - ProcMacroResult::replace(token_stream, Some(aux_data)) + ProcMacroResult::new(token_stream).with_aux_data(aux_data) } #[post_process] @@ -648,7 +641,7 @@ fn can_define_multiple_macros() { .replace("90", "09") ); let aux_data = AuxData::new(Vec::new()); - ProcMacroResult::replace(token_stream, Some(aux_data)) + ProcMacroResult::new(token_stream).with_aux_data(aux_data) } #[post_process] @@ -701,13 +694,13 @@ fn cannot_duplicate_macros() { use cairo_lang_macro::{ProcMacroResult, TokenStream, attribute_macro}; #[attribute_macro] - pub fn hello(_token_stream: TokenStream) -> ProcMacroResult { - ProcMacroResult::leave() + pub fn hello(token_stream: TokenStream) -> ProcMacroResult { + ProcMacroResult::new(token_stream) } #[attribute_macro] - pub fn hello(_token_stream: TokenStream) -> ProcMacroResult { - ProcMacroResult::leave() + pub fn hello(token_stream: TokenStream) -> ProcMacroResult { + ProcMacroResult::new(token_stream) } "##}, ); @@ -742,13 +735,13 @@ fn cannot_duplicate_macros_across_packages() { use cairo_lang_macro::{ProcMacroResult, TokenStream, attribute_macro}; #[attribute_macro] - pub fn hello(_token_stream: TokenStream) -> ProcMacroResult { - ProcMacroResult::leave() + pub fn hello(token_stream: TokenStream) -> ProcMacroResult { + ProcMacroResult::new(token_stream) } #[attribute_macro] - pub fn world(_token_stream: TokenStream) -> ProcMacroResult { - ProcMacroResult::leave() + pub fn world(token_stream: TokenStream) -> ProcMacroResult { + ProcMacroResult::new(token_stream) } "##}, ); @@ -760,8 +753,8 @@ fn cannot_duplicate_macros_across_packages() { use cairo_lang_macro::{ProcMacroResult, TokenStream, attribute_macro}; #[attribute_macro] - pub fn hello(_token_stream: TokenStream) -> ProcMacroResult { - ProcMacroResult::leave() + pub fn hello(token_stream: TokenStream) -> ProcMacroResult { + ProcMacroResult::new(token_stream) } "##}, "other", @@ -806,8 +799,8 @@ fn cannot_use_undefined_macro() { use cairo_lang_macro::{ProcMacroResult, TokenStream, attribute_macro}; #[attribute_macro] - pub fn hello(_token_stream: TokenStream) -> ProcMacroResult { - ProcMacroResult::leave() + pub fn hello(token_stream: TokenStream) -> ProcMacroResult { + ProcMacroResult::new(token_stream) } "##}, ); @@ -862,12 +855,8 @@ fn can_resolve_full_path_markers() { let full_path_markers = vec!["some-key".to_string()]; - ProcMacroResult::Replace { - token_stream, - full_path_markers, - aux_data: None, - diagnostics: Vec::new(), - } + ProcMacroResult::new(token_stream) + .with_full_path_markers(full_path_markers) } #[post_process] @@ -903,3 +892,91 @@ fn can_resolve_full_path_markers() { [..]Finished release target(s) in [..] "#}); } + +#[test] +fn can_implement_inline_macro() { + let temp = TempDir::new().unwrap(); + let t = temp.child("some"); + simple_project_with_code( + &t, + indoc! {r##" + use cairo_lang_macro::{ProcMacroResult, TokenStream, inline_macro}; + + #[inline_macro] + pub fn some(_token_stream: TokenStream) -> ProcMacroResult { + ProcMacroResult::new(TokenStream::new("34".to_string())) + } + "##}, + ); + let project = temp.child("hello"); + ProjectBuilder::start() + .name("hello") + .version("1.0.0") + .dep("some", &t) + .lib_cairo(indoc! {r#" + fn main() -> felt252 { some!() } + "#}) + .build(&project); + + Scarb::quick_snapbox() + .arg("cairo-run") + // Disable output from Cargo. + .env("CARGO_TERM_QUIET", "true") + .current_dir(&project) + .assert() + .success() + .stdout_matches(indoc! {r#" + [..] Compiling some v1.0.0 ([..]Scarb.toml) + [..] Compiling hello v1.0.0 ([..]Scarb.toml) + [..]Finished release target(s) in [..] + [..]Running hello + Run completed successfully, returning [34] + "#}); +} + +#[test] +fn empty_inline_macro_result() { + let temp = TempDir::new().unwrap(); + let t = temp.child("some"); + simple_project_with_code( + &t, + indoc! {r##" + use cairo_lang_macro::{ProcMacroResult, TokenStream, inline_macro}; + + #[inline_macro] + pub fn some(_token_stream: TokenStream) -> ProcMacroResult { + ProcMacroResult::new(TokenStream::empty()) + } + "##}, + ); + let project = temp.child("hello"); + ProjectBuilder::start() + .name("hello") + .version("1.0.0") + .dep("some", &t) + .lib_cairo(indoc! {r#" + fn main() -> felt252 { + let _x = some!(); + 12 + } + "#}) + .build(&project); + + Scarb::quick_snapbox() + .arg("build") + // Disable output from Cargo. + .env("CARGO_TERM_QUIET", "true") + .current_dir(&project) + .assert() + .failure() + .stdout_matches(indoc! {r#" + [..] Compiling some v1.0.0 ([..]Scarb.toml) + [..] Compiling hello v1.0.0 ([..]Scarb.toml) + error: Inline macro `some` failed. + --> [..]lib.cairo:2:14 + let _x = some!(); + ^*****^ + + error: could not compile `hello` due to previous error + "#}); +}