1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
extern crate proc_macro;
use proc_macro::TokenStream;
use proc_macro2::{Ident, Span};
use quote::quote;
use syn::{Item as SynItem, ItemFn};
#[proc_macro_attribute]
pub fn plugin_transform(
_args: proc_macro::TokenStream,
input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
let token = proc_macro2::TokenStream::from(input);
let parsed_results = syn::parse2::<SynItem>(token).expect("Failed to parse tokens");
match parsed_results {
SynItem::Fn(func) => handle_func(func),
_ => panic!("Please confirm if plugin macro is specified for the function"),
}
}
fn handle_func(func: ItemFn) -> TokenStream {
let ident = func.sig.ident.clone();
let process_impl_ident = Ident::new("__plugin_process_impl", Span::call_site());
let ret = quote! {
#func
#[cfg(target_arch = "wasm32")]
extern "C" {
fn __set_transform_result(bytes_ptr: i32, bytes_ptr_len: i32);
fn __free(bytes_ptr: i32, size: i32) -> i32;
}
fn set_transform_result_volatile(bytes_ptr: i32, bytes_ptr_len: i32) {
#[cfg(target_arch = "wasm32")]
unsafe {
__set_transform_result(bytes_ptr, bytes_ptr_len);
__free(bytes_ptr, bytes_ptr_len);
}
}
fn construct_error_ptr(plugin_error: swc_plugin::PluginError) -> i32 {
let ret = swc_plugin::Serialized::serialize(&plugin_error).expect("Should able to serialize PluginError");
let ret_ref = ret.as_ref();
set_transform_result_volatile(
ret_ref.as_ptr() as _,
std::convert::TryInto::try_into(ret_ref.len()).expect("Should able to convert size of PluginError")
);
1
}
#[no_mangle]
pub fn #process_impl_ident(ast_ptr: *const u8, ast_ptr_len: i32, config_str_ptr: *const u8, config_str_ptr_len: i32) -> i32 {
let ast_ptr_len_usize: Result<usize, std::num::TryFromIntError> = std::convert::TryInto::try_into(ast_ptr_len);
let config_str_ptr_len_usize: Result<usize, std::num::TryFromIntError> = std::convert::TryInto::try_into(config_str_ptr_len);
if ast_ptr_len_usize.is_err() {
let err = swc_plugin::PluginError::SizeInteropFailure("Failed to convert size of AST pointer".to_string());
return construct_error_ptr(err);
}
if config_str_ptr_len_usize.is_err() {
let err = swc_plugin::PluginError::SizeInteropFailure("Failed to convert size of plugin config string pointer".to_string());
return construct_error_ptr(err);
}
let raw_ast_serialized_bytes =
unsafe { std::slice::from_raw_parts(ast_ptr, ast_ptr_len_usize.unwrap()) };
let raw_config_serialized_bytes =
unsafe { std::slice::from_raw_parts(config_str_ptr, config_str_ptr_len_usize.unwrap()) };
let serialized_program = swc_plugin::Serialized::new_for_plugin(raw_ast_serialized_bytes, ast_ptr_len);
let serialized_config = swc_plugin::Serialized::new_for_plugin(raw_config_serialized_bytes, config_str_ptr_len);
let program = swc_plugin::Serialized::deserialize(&serialized_program);
let config = swc_plugin::Serialized::deserialize(&serialized_config);
if program.is_err() {
let err = swc_plugin::PluginError::Deserialize(
("Failed to deserialize program received from host".to_string(),
raw_ast_serialized_bytes.to_vec())
);
return construct_error_ptr(err);
}
let program: Program = program.expect("Should be a program");
if config.is_err() {
let err = swc_plugin::PluginError::Deserialize(
("Failed to deserialize config string received from host".to_string(),
raw_config_serialized_bytes.to_vec())
);
return construct_error_ptr(err);
}
let config: String = config.expect("Should be a string");
let handler = swc_plugin::errors::Handler::with_emitter(
true,
false,
Box::new(swc_plugin::environment::PluginDiagnosticsEmitter {})
);
let handler_set_result = swc_plugin::errors::HANDLER.inner.set(handler);
if handler_set_result.is_err() {
let err = swc_plugin::PluginError::Serialize(
"Failed to set handler for plugin".to_string()
);
return construct_error_ptr(err);
}
let transformed_program = #ident(program, config);
let serialized_result = swc_plugin::Serialized::serialize(&transformed_program);
if serialized_result.is_err() {
let err = swc_plugin::PluginError::Serialize("Failed to serialize transformed program".to_string());
return construct_error_ptr(err);
}
let serialized_result = serialized_result.expect("Should be a realized transformed program");
let serialized_result = serialized_result.as_ref();
let serialized_result_len: Result<i32, std::num::TryFromIntError> = std::convert::TryInto::try_into(serialized_result.len());
if serialized_result_len.is_err() {
let err = swc_plugin::PluginError::SizeInteropFailure("Failed to convert size of transformed AST pointer".to_string());
return construct_error_ptr(err);
}
set_transform_result_volatile(serialized_result.as_ptr() as _, serialized_result_len.expect("Should be an i32"));
0
}
};
ret.into()
}