Skip to content

Commit

Permalink
Add ProcMacroHost definition (#1060)
Browse files Browse the repository at this point in the history
commit-id:18967d01

---

**Stack**:
- #1143
- #1148
- #1100
- #1110
- #1093
- #1091
- #1060⚠️ *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 16, 2024
1 parent 8bd3d8c commit e87616a
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 11 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

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

1 change: 0 additions & 1 deletion plugins/cairo-lang-macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ repository.workspace = true

[dependencies]
anyhow.workspace = true
libc.workspace = true
cairo-lang-macro-attributes = { path = "../cairo-lang-macro-attributes" }
serde.workspace = true
serde_json.workspace = true
1 change: 1 addition & 0 deletions scarb/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ cairo-lang-sierra-to-casm.workspace = true
cairo-lang-sierra.workspace = true
cairo-lang-starknet-classes.workspace = true
cairo-lang-starknet.workspace = true
cairo-lang-syntax.workspace = true
cairo-lang-test-plugin.workspace = true
cairo-lang-utils.workspace = true
camino.workspace = true
Expand Down
32 changes: 23 additions & 9 deletions scarb/src/compiler/db.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use anyhow::{anyhow, Result};
use cairo_lang_compiler::db::RootDatabase;
use cairo_lang_compiler::db::{RootDatabase, RootDatabaseBuilder};
use cairo_lang_compiler::project::{AllCratesConfig, ProjectConfig, ProjectConfigContent};
use cairo_lang_defs::db::DefsGroup;
use cairo_lang_defs::ids::ModuleId;
Expand All @@ -11,6 +11,7 @@ use smol_str::SmolStr;
use std::sync::Arc;
use tracing::trace;

use crate::compiler::plugin::proc_macro::ProcMacroHost;
use crate::compiler::{CompilationUnit, CompilationUnitComponent};
use crate::core::Workspace;
use crate::DEFAULT_MODULE_MAIN_FILE;
Expand All @@ -23,19 +24,32 @@ pub(crate) fn build_scarb_root_database(
let mut b = RootDatabase::builder();
b.with_project_config(build_project_config(unit)?);
b.with_cfg(unit.cfg_set.clone());

for plugin_info in &unit.cairo_plugins {
let package_id = plugin_info.package.id;
let plugin = ws.config().cairo_plugins().fetch(package_id)?;
let instance = plugin.instantiate()?;
b.with_plugin_suite(instance.plugin_suite());
}

load_plugins(unit, ws, &mut b)?;
let mut db = b.build()?;
inject_virtual_wrapper_lib(&mut db, unit)?;
Ok(db)
}

fn load_plugins(
unit: &CompilationUnit,
ws: &Workspace<'_>,
builder: &mut RootDatabaseBuilder,
) -> Result<()> {
let mut proc_macros = ProcMacroHost::default();
for plugin_info in &unit.cairo_plugins {
if plugin_info.builtin {
let package_id = plugin_info.package.id;
let plugin = ws.config().cairo_plugins().fetch(package_id)?;
let instance = plugin.instantiate()?;
builder.with_plugin_suite(instance.plugin_suite());
} else {
proc_macros.register(plugin_info.package.clone())?;
}
}
builder.with_plugin_suite(proc_macros.into_plugin_suite());
Ok(())
}

/// Generates a wrapper lib file for appropriate compilation units.
///
/// This approach allows compiling crates that do not define `lib.cairo` file.
Expand Down
1 change: 1 addition & 0 deletions scarb/src/compiler/plugin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::core::PackageId;
use self::builtin::{BuiltinStarkNetPlugin, BuiltinTestPlugin};

pub mod builtin;
pub mod proc_macro;

pub trait CairoPlugin: Sync {
fn id(&self) -> PackageId;
Expand Down
25 changes: 25 additions & 0 deletions scarb/src/compiler/plugin/proc_macro/ffi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use crate::core::{Package, PackageId};
use anyhow::Result;

/// Representation of a single procedural macro.
///
/// This struct is a wrapper around a shared library containing the procedural macro implementation.
/// It is responsible for loading the shared library and providing a safe interface for code expansion.
#[derive(Debug, Clone)]
pub struct ProcMacroInstance {
package_id: PackageId,
}

impl ProcMacroInstance {
pub fn try_new(package: Package) -> Result<Self> {
// Load shared library
// TODO(maciektr): Implement
Ok(Self {
package_id: package.id,
})
}

pub fn declared_attributes(&self) -> Vec<String> {
vec![self.package_id.name.to_string()]
}
}
69 changes: 69 additions & 0 deletions scarb/src/compiler/plugin/proc_macro/host.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use crate::compiler::plugin::proc_macro::ProcMacroInstance;
use crate::core::Package;
use anyhow::Result;
use cairo_lang_defs::plugin::{MacroPlugin, MacroPluginMetadata, PluginResult};
use cairo_lang_semantic::plugin::PluginSuite;
use cairo_lang_syntax::node::ast::ModuleItem;
use cairo_lang_syntax::node::db::SyntaxGroup;
use std::sync::Arc;

/// A Cairo compiler plugin controlling the procedural macro execution.
///
/// This plugin decides which macro plugins (if any) should be applied to the processed AST item.
/// It then redirects the item to the appropriate macro plugin for code expansion.
#[derive(Debug)]
pub struct ProcMacroHostPlugin {
macros: Vec<Arc<ProcMacroInstance>>,
}

impl ProcMacroHostPlugin {
pub fn new(macros: Vec<Arc<ProcMacroInstance>>) -> Self {
Self { macros }
}
}

impl MacroPlugin for ProcMacroHostPlugin {
fn generate_code(
&self,
_db: &dyn SyntaxGroup,
_item_ast: ModuleItem,
_metadata: &MacroPluginMetadata<'_>,
) -> PluginResult {
// Apply expansion to `item_ast` where needed.
// TODO(maciektr): Implement
PluginResult::default()
}

fn declared_attributes(&self) -> Vec<String> {
self.macros
.iter()
.flat_map(|m| m.declared_attributes())
.collect()
}
}

/// A Scarb wrapper around the `ProcMacroHost` compiler plugin.
///
/// This struct represent the compiler plugin in terms of Scarb data model.
/// It also builds a plugin suite that enables the compiler plugin.
#[derive(Default)]
pub struct ProcMacroHost {
macros: Vec<Arc<ProcMacroInstance>>,
}

impl ProcMacroHost {
pub fn register(&mut self, package: Package) -> Result<()> {
// Create instance
// Register instance in hash map
let instance = ProcMacroInstance::try_new(package)?;
self.macros.push(Arc::new(instance));
Ok(())
}

pub fn into_plugin_suite(self) -> PluginSuite {
let macro_host = ProcMacroHostPlugin::new(self.macros);
let mut suite = PluginSuite::default();
suite.add_plugin_ex(Arc::new(macro_host));
suite
}
}
5 changes: 5 additions & 0 deletions scarb/src/compiler/plugin/proc_macro/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
mod ffi;
mod host;

pub use ffi::*;
pub use host::*;

0 comments on commit e87616a

Please sign in to comment.