Skip to content

Commit

Permalink
Create procedural macro interface library (#1139)
Browse files Browse the repository at this point in the history
commit-id:32dd0ae0

---

**Stack**:
- #1100
- #1110
- #1093
- #1091
- #1060
- #1139⚠️ *Part of a stack created by [spr](https://github.com/ejoffe/spr). Do
not merge manually using the UI - doing so may have unexpected results.*
  • Loading branch information
maciektr authored Feb 12, 2024
1 parent 3c1cc39 commit a8f392b
Show file tree
Hide file tree
Showing 10 changed files with 207 additions and 1 deletion.
20 changes: 20 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ members = [
"extensions/scarb-cairo-run",
"extensions/scarb-cairo-test",
"extensions/scarb-snforge-test-collector",
"plugins/scarb-macro-attributes",
"plugins/scarb-macro-interface",
"utils/create-output-dir",
"utils/scarb-build-metadata",
"utils/scarb-test-support",
Expand Down
21 changes: 21 additions & 0 deletions plugins/scarb-macro-attributes/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "scarb-macro-attributes"
version = "0.0.1"
edition.workspace = true

authors.workspace = true
categories = ["development-tools"]
description = "Cairo procedural macro interface primitives."
homepage.workspace = true
keywords = ["scarb"]
license.workspace = true
readme = "README.md"
repository.workspace = true

[lib]
proc-macro = true

[dependencies]
camino.workspace = true
quote.workspace = true
syn = { workspace = true, features = ["full", "extra-traits"] }
3 changes: 3 additions & 0 deletions plugins/scarb-macro-attributes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# scarb-macro-interface

Shared interface for Scarb procedural macros.
26 changes: 26 additions & 0 deletions plugins/scarb-macro-attributes/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemFn};

/// Inline macro helper.
///
/// This macro hides the conversion to stable ABI structs from the user.
///
/// # Safety
/// Note that token stream deserialization may fail.
#[proc_macro_attribute]
pub fn attribute_macro(_args: TokenStream, input: TokenStream) -> TokenStream {
let item: ItemFn = parse_macro_input!(input as ItemFn);
let item_name = &item.sig.ident;
let expanded = quote! {
#item

#[no_mangle]
pub unsafe extern "C" fn expand(token_stream: scarb_macro_interface::stable_abi::StableTokenStream) -> scarb_macro_interface::stable_abi::StableProcMacroResult {
let token_stream = token_stream.into_token_stream();
let result = #item_name(token_stream);
scarb_macro_interface::stable_abi::StableProcMacroResult::from_proc_macro_result(result)
}
};
TokenStream::from(expanded)
}
19 changes: 19 additions & 0 deletions plugins/scarb-macro-interface/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "scarb-macro-interface"
version = "0.0.1"
edition.workspace = true

authors.workspace = true
categories = ["development-tools"]
description = "Cairo procedural macro interface primitives."
homepage.workspace = true
keywords = ["scarb"]
license.workspace = true
readme = "README.md"
repository.workspace = true

[dependencies]
anyhow.workspace = true
serde.workspace = true
serde_json.workspace = true
libc.workspace = true
3 changes: 3 additions & 0 deletions plugins/scarb-macro-interface/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# scarb-macro-interface

Shared interface for Scarb procedural macros.
30 changes: 30 additions & 0 deletions plugins/scarb-macro-interface/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use std::fmt::Display;

#[doc(hidden)]
pub mod stable_abi;

#[derive(Debug)]
pub enum ProcMacroResult {
/// Plugin has not taken any action.
Leave,
/// Plugin generated [`TokenStream`] replacement.
Replace(TokenStream),
/// Plugin ordered item removal.
Remove,
}

#[derive(Debug, Default, Clone)]
pub struct TokenStream(String);

impl TokenStream {
#[doc(hidden)]
pub fn new(s: String) -> Self {
Self(s)
}
}

impl Display for TokenStream {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
81 changes: 81 additions & 0 deletions plugins/scarb-macro-interface/src/stable_abi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
use crate::{ProcMacroResult, TokenStream};
use std::ffi::CString;
use std::os::raw::c_char;

/// Token stream.
///
/// This struct implements FFI-safe stable ABI.
#[repr(C)]
#[derive(Debug)]
pub struct StableTokenStream(pub *mut c_char);

/// Procedural macro result.
///
/// This struct implements FFI-safe stable ABI.
#[repr(C)]
#[derive(Debug)]
pub enum StableProcMacroResult {
/// Plugin has not taken any action.
Leave,
/// Plugin generated [`TokenStream`] replacement.
Replace(StableTokenStream),
/// Plugin ordered item removal.
Remove,
}

impl StableTokenStream {
/// Convert to String.
///
/// # Safety
pub unsafe fn to_string(&self) -> String {
if self.0.is_null() {
String::default()
} else {
let cstr = CString::from_raw(self.0);
cstr.to_string_lossy().to_string()
}
}

/// Convert to native Rust representation.
///
/// # Safety
pub unsafe fn into_token_stream(self) -> TokenStream {
TokenStream::new(self.to_string())
}

/// Convert to FFI-safe representation.
///
/// # Safety
pub unsafe fn from_token_stream(token_stream: TokenStream) -> Self {
let cstr = CString::new(token_stream.0).unwrap();
StableTokenStream(cstr.into_raw())
}
}

impl StableProcMacroResult {
/// Convert to native Rust representation.
///
/// # Safety
pub unsafe fn into_proc_macro_result(self) -> ProcMacroResult {
match self {
Self::Leave => ProcMacroResult::Leave,
Self::Remove => ProcMacroResult::Remove,
Self::Replace(token_stream) => {
ProcMacroResult::Replace(token_stream.into_token_stream())
}
}
}

/// Convert to FFI-safe representation.
///
/// # Safety
pub unsafe fn from_proc_macro_result(result: ProcMacroResult) -> Self {
match result {
ProcMacroResult::Leave => StableProcMacroResult::Leave,
ProcMacroResult::Remove => StableProcMacroResult::Remove,
ProcMacroResult::Replace(token_stream) => {
StableProcMacroResult::Replace(StableTokenStream::from_token_stream(token_stream))
}
}
}
}
3 changes: 2 additions & 1 deletion scarb/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ cairo-lang-formatter.workspace = true
cairo-lang-semantic.workspace = true
cairo-lang-sierra-to-casm.workspace = true
cairo-lang-sierra.workspace = true
cairo-lang-starknet.workspace = true
cairo-lang-starknet-classes.workspace = true
cairo-lang-starknet.workspace = true
cairo-lang-test-plugin.workspace = true
cairo-lang-utils.workspace = true
camino.workspace = true
Expand All @@ -51,6 +51,7 @@ petgraph.workspace = true
redb.workspace = true
reqwest.workspace = true
scarb-build-metadata = { path = "../utils/scarb-build-metadata" }
scarb-macro-interface = { path = "../plugins/scarb-macro-interface" }
scarb-metadata = { path = "../scarb-metadata", default-features = false, features = ["builder"] }
scarb-ui = { path = "../utils/scarb-ui" }
semver.workspace = true
Expand Down

0 comments on commit a8f392b

Please sign in to comment.