1mod util;
2
3use proc_macro::TokenStream;
4use darling::ast::NestedMeta;
5use darling::{Error, FromMeta};
6use proc_macro2::Span;
7use quote::{quote, quote_spanned};
8use syn::LitStr;
9use syn::parse::Parser;
10
11#[derive(Debug, FromMeta)]
12enum TypeConstraintMacroArgs {
13 #[darling(rename = "allowed")]
14 Allowed(Vec<LitStr>),
15
16 #[darling(rename = "not_allowed")]
17 NotAllowed(Vec<LitStr>),
18}
19
20#[derive(Debug, Default, FromMeta)]
21enum ParameterTypeMacroArgs {
22 #[default]
23 Normal,
24
25 #[darling(rename = "number")]
26 Number,
27
28 #[darling(rename = "callable")]
29 Callable,
30
31 #[darling(rename = "boolean")]
32 Boolean,
33
34 #[darling(rename = "call_by_pointer")]
35 CallByPointer,
36
37 #[darling(rename = "var_args")]
38 VarArgs,
39
40 #[darling(rename = "raw_var_args")]
41 RawVarArgs,
42}
43
44impl ParameterTypeMacroArgs {
45 fn type_name(&self) -> &'static str {
46 match self {
47 ParameterTypeMacroArgs::Normal => "Normal",
48 ParameterTypeMacroArgs::Number => "Number",
49 ParameterTypeMacroArgs::Callable => "Callable",
50 ParameterTypeMacroArgs::Boolean => "Boolean",
51 ParameterTypeMacroArgs::CallByPointer => "CallByPointer",
52 ParameterTypeMacroArgs::VarArgs => "VarArgs",
53 ParameterTypeMacroArgs::RawVarArgs => "RawVarArgs",
54 }
55 }
56}
57
58#[derive(Debug, FromMeta)]
59struct ParameterMacroArgs {
60 name: String,
61
62 #[darling(default)]
63 info: Option<String>,
64
65 #[darling(default)]
66 parameter_type: ParameterTypeMacroArgs,
67
68 #[darling(default)]
69 type_constraint: Option<TypeConstraintMacroArgs>,
70}
71
72#[derive(Debug, FromMeta)]
73struct DeprecationInfo {
74 #[darling(default)]
75 remove_version: Option<String>,
76
77 #[darling(default)]
78 replacement_function: Option<String>,
79}
80
81#[derive(Debug, FromMeta)]
82struct LangFuncMetadata {
83 name: String,
84
85 #[darling(default)]
86 info: Option<String>,
87
88 #[darling(multiple, rename="parameter")]
89 parameters: Vec<ParameterMacroArgs>,
90
91 #[darling(default)]
92 has_info: bool,
93
94 #[darling(default)]
95 combinator_function: bool,
96
97 #[darling(default)]
98 linker_function: bool,
99
100 #[darling(default)]
101 deprecated: Option<DeprecationInfo>,
102
103 #[darling(default)]
104 return_type_constraint: Option<TypeConstraintMacroArgs>,
105}
106
107#[proc_macro]
108pub fn lang_func_id(
109 args: TokenStream
110) -> TokenStream {
111 let func_id_ident = syn::parse_macro_input!(args as syn::Ident);
112
113 let native_func_id_path: proc_macro2::TokenStream = "::lang_interpreter::interpreter::data::function::native::NativeFuncId".parse().unwrap();
114 let gen_next_native_func_id_path: proc_macro2::TokenStream = "::lang_interpreter::interpreter::data::function::native::gen_next_native_func_id".parse().unwrap();
115 let lazy_lock_path: proc_macro2::TokenStream = "::std::sync::LazyLock".parse().unwrap();
116
117 TokenStream::from(quote! {
118 static #func_id_ident: #lazy_lock_path<#native_func_id_path, fn() -> #native_func_id_path> = #lazy_lock_path::new(#gen_next_native_func_id_path);
119
120 let _ = *#func_id_ident;
122 })
123}
124
125#[proc_macro]
126pub fn lang_func_metadata(
127 args: TokenStream,
128) -> TokenStream {
129 let attr_args = match NestedMeta::parse_meta_list(args.into()) {
130 Ok(v) => v,
131 Err(e) => {
132 return TokenStream::from(Error::from(e).write_errors());
133 }
134 };
135
136 let args = match LangFuncMetadata::from_list(&attr_args) {
137 Ok(v) => v,
138 Err(e) => {
139 return TokenStream::from(e.write_errors());
140 }
141 };
142
143 let func_name = util::option_string_to_token_stream(&Some(args.name));
144 let func_info = util::option_string_to_token_stream(&args.info);
145
146 let has_info: proc_macro2::TokenStream = args.has_info.to_string().parse().unwrap();
147
148 let combinator_function: proc_macro2::TokenStream = args.combinator_function.to_string().parse().unwrap();
149
150 let linker_function: proc_macro2::TokenStream = args.linker_function.to_string().parse().unwrap();
151
152 let deprecation_info = util::option_deprecation_info_to_token_stream(&args.deprecated);
153
154 let vec_macro_path: proc_macro2::TokenStream = "::std::vec!".parse().unwrap();
155 let parameter_metadata_path: proc_macro2::TokenStream = "::lang_interpreter::interpreter::data::function::ParameterMetadata".parse().unwrap();
156 let parameter_type_path: proc_macro2::TokenStream = "::lang_interpreter::interpreter::data::function::ParameterType".parse().unwrap();
157
158 let mut parameters = Vec::new();
159 for parameter in &args.parameters {
160 let parameter_name = proc_macro2::Literal::string(¶meter.name);
161
162 let parameter_info = util::option_string_to_token_stream(¶meter.info);
163
164 let parameter_data_type_constraint = util::option_type_constraint_macro_args_to_token_stream(¶meter.type_constraint);
165
166 let parameter_type = proc_macro2::Ident::new(
167 parameter.parameter_type.type_name(),
168 Span::mixed_site(),
169 );
170
171 parameters.push(quote! {
172 #parameter_metadata_path::new(
173 #parameter_name,
174 #parameter_info,
175 #parameter_data_type_constraint,
176 #parameter_type_path::#parameter_type,
177 )
178 });
179 }
180
181 let return_value_type_constraint = util::option_type_constraint_macro_args_to_token_stream(&args.return_type_constraint);
182
183 let function_metadata_path: proc_macro2::TokenStream = "::lang_interpreter::interpreter::data::function::FunctionMetadata".parse().unwrap();
184
185 TokenStream::from(quote!{
186 #function_metadata_path::new(
187 #func_name,
188 #func_info,
189
190 #has_info,
191
192 #combinator_function,
193
194 #linker_function,
195 #deprecation_info,
196
197 #vec_macro_path[
198 #(#parameters,)*
199 ],
200
201 #return_value_type_constraint,
202 )
203 })
204}
205
206#[proc_macro]
207pub fn lang_func_adapter(
208 args: TokenStream,
209) -> TokenStream {
210 let data = syn::punctuated::Punctuated::<syn::Expr, syn::Token![,]>::parse_terminated.parse(args);
211 let data = match data {
212 Ok(v) => v,
213 Err(e) => {
214 return TokenStream::from(Error::from(e).write_errors());
215 }
216 };
217
218 if data.len() != 2 {
219 return TokenStream::from(quote!{
220 compile_error!("Expected two arguments: function identifier, metadata")
221 });
222 }
223
224 let func_ident = &data[0];
225 let metadata = &data[1];
226
227 let box_path: proc_macro2::TokenStream = "::std::boxed::Box".parse().unwrap();
228
229 let lang_func_id_macro_path: proc_macro2::TokenStream = "::lang_interpreter::lang_func_id!".parse().unwrap();
230 let func_trait_path: proc_macro2::TokenStream =
231 "::lang_interpreter::interpreter::data::function::native::ConvertToFuncTrait::func_trait".parse().unwrap();
232 let native_function_adapter_path: proc_macro2::TokenStream =
233 "::lang_interpreter::interpreter::data::function::native::NativeFunctionAdapter".parse().unwrap();
234
235 let span = Span::mixed_site();
236
237 quote_spanned!(span => {
238 #lang_func_id_macro_path(FUNC_ID);
239
240 (
241 #metadata,
242 #box_path::new(#func_trait_path(#func_ident)) as #box_path<dyn #native_function_adapter_path + 'static>,
243 *FUNC_ID,
244 )
245 }).into()
246}
247
248#[doc(hidden)]
249#[proc_macro]
250pub fn internal_tuple_from_lang_args_impl(
251 args: TokenStream,
252) -> TokenStream {
253 let count = syn::parse_macro_input!(args as syn::LitInt).base10_parse::<usize>();
254 let count = match count {
255 Ok(v) => v,
256 Err(e) => {
257 return TokenStream::from(e.into_compile_error());
258 }
259 };
260
261 let data_object_ref_ident = proc_macro2::Ident::new(
262 "DataObjectRef",
263 Span::mixed_site(),
264 );
265
266 let args_tokens = vec![data_object_ref_ident; count];
267
268 let count_lit = proc_macro2::Literal::usize_unsuffixed(count);
269 let count_plus_1_lit = proc_macro2::Literal::usize_unsuffixed(count + 1);
270
271 let next_ident = proc_macro2::Ident::new(
272 "next",
273 Span::mixed_site(),
274 );
275 let next_tokens = vec![next_ident; count];
276
277 TokenStream::from(quote! {
280 impl FromLangArgs for (#(#args_tokens,)*) {
282 fn from_lang_args(
283 this_object: OptionLangObjectRef,
284 args: Vec<DataObjectRef>,
285 ) -> Result<Self> {
286 if args.len() != #count_lit {
287 return Err(NativeError::new("Invalid argument count for native function", None));
288 }
289
290 if this_object.is_some() {
291 return Err(NativeError::new("This object may not be set for native function without a this parameter", None));
292 }
293
294 let mut args = args;
295 let mut args = args.drain(..);
296
297 Ok((#(args.#next_tokens().unwrap(),)*))
298 }
299
300 fn lang_parameter_count() -> usize {
301 #count_lit
302 }
303
304 fn is_method() -> bool {
305 false
306 }
307 }
308
309 impl FromLangArgs for (Vec<DataObjectRef>, #(#args_tokens,)*) {
311 fn from_lang_args(
312 this_object: OptionLangObjectRef,
313 args: Vec<DataObjectRef>,
314 ) -> Result<Self> {
315 if args.len() < #count_lit {
316 return Err(NativeError::new("Not enough arguments for native function", None));
317 }
318
319 if this_object.is_some() {
320 return Err(NativeError::new("This object may not be set for native function without a this parameter", None));
321 }
322
323 let var_args_count = args.len() - #count_lit;
324
325 let mut args = args;
326 let mut var_args = args.split_off(var_args_count);
327 mem::swap(&mut args, &mut var_args);
328
329 let mut args = args.drain(..);
330
331 Ok((var_args, #(args.#next_tokens().unwrap(),)*))
332 }
333
334 fn lang_parameter_count() -> usize {
335 #count_plus_1_lit
336 }
337
338 fn is_method() -> bool {
339 false
340 }
341 }
342
343 impl FromLangArgs for (#(#args_tokens,)* Vec<DataObjectRef>,) {
345 fn from_lang_args(
346 this_object: OptionLangObjectRef,
347 args: Vec<DataObjectRef>,
348 ) -> Result<Self> {
349 if args.len() < #count_lit {
350 return Err(NativeError::new("Not enough arguments for native function", None));
351 }
352
353 if this_object.is_some() {
354 return Err(NativeError::new("This object may not be set for native function without a this parameter", None));
355 }
356
357 let mut args = args;
358 let var_args = args.split_off(#count_lit);
359
360 let mut args = args.drain(..);
361
362 Ok((#(args.#next_tokens().unwrap(),)* var_args,))
363 }
364
365 fn lang_parameter_count() -> usize {
366 #count_plus_1_lit
367 }
368
369 fn is_method() -> bool {
370 false
371 }
372 }
373
374 impl FromLangArgs for (LangObjectRef, #(#args_tokens,)*) {
376 fn from_lang_args(
377 this_object: OptionLangObjectRef,
378 args: Vec<DataObjectRef>,
379 ) -> Result<Self> {
380 if args.len() != #count_lit {
381 return Err(NativeError::new("Invalid argument count for native function", None));
382 }
383
384 let Some(this_object) = this_object.as_ref() else {
385 return Err(NativeError::new("This object must be set for native function with a this parameter", None));
386 };
387
388 let mut args = args;
389 let mut args = args.drain(..);
390
391 Ok((this_object.clone(), #(args.#next_tokens().unwrap(),)*))
392 }
393
394 fn lang_parameter_count() -> usize {
395 #count_lit
396 }
397
398 fn is_method() -> bool {
399 true
400 }
401 }
402
403 impl FromLangArgs for (LangObjectRef, Vec<DataObjectRef>, #(#args_tokens,)*) {
405 fn from_lang_args(
406 this_object: OptionLangObjectRef,
407 args: Vec<DataObjectRef>,
408 ) -> Result<Self> {
409 if args.len() < #count_lit {
410 return Err(NativeError::new("Not enough arguments for native function", None));
411 }
412
413 let Some(this_object) = this_object.as_ref() else {
414 return Err(NativeError::new("This object must be set for native function with a this parameter", None));
415 };
416
417 let var_args_count = args.len() - #count_lit;
418
419 let mut args = args;
420 let mut var_args = args.split_off(var_args_count);
421 mem::swap(&mut args, &mut var_args);
422
423 let mut args = args.drain(..);
424
425 Ok((this_object.clone(), var_args, #(args.#next_tokens().unwrap(),)*))
426 }
427
428 fn lang_parameter_count() -> usize {
429 #count_plus_1_lit
430 }
431
432 fn is_method() -> bool {
433 true
434 }
435 }
436
437 impl FromLangArgs for (LangObjectRef, #(#args_tokens,)* Vec<DataObjectRef>,) {
439 fn from_lang_args(
440 this_object: OptionLangObjectRef,
441 args: Vec<DataObjectRef>,
442 ) -> Result<Self> {
443 if args.len() < #count_lit {
444 return Err(NativeError::new("Not enough arguments for native function", None));
445 }
446
447 let Some(this_object) = this_object.as_ref() else {
448 return Err(NativeError::new("This object must be set for native function with a this parameter", None));
449 };
450
451 let mut args = args;
452 let var_args = args.split_off(#count_lit);
453
454 let mut args = args.drain(..);
455
456 Ok((this_object.clone(), #(args.#next_tokens().unwrap(),)* var_args,))
457 }
458
459 fn lang_parameter_count() -> usize {
460 #count_plus_1_lit
461 }
462
463 fn is_method() -> bool {
464 true
465 }
466 }
467 })
468}
469
470#[doc(hidden)]
471#[proc_macro]
472pub fn internal_native_function_adapter_impl(
473 args: TokenStream,
474) -> TokenStream {
475 let count = syn::parse_macro_input!(args as syn::LitInt).base10_parse::<usize>();
476 let count = match count {
477 Ok(v) => v,
478 Err(e) => {
479 return TokenStream::from(e.into_compile_error());
480 }
481 };
482
483 let index_literal_tokens = (0..count).
484 map(proc_macro2::Literal::usize_unsuffixed).
485 collect::<Vec<_>>();
486
487 let generic_type_tokens = (0..count).
488 map(|i| proc_macro2::Ident::new(
489 &format!("T{}", i + 1),
490 Span::mixed_site(),
491 )).
492 collect::<Vec<_>>();
493
494 TokenStream::from(quote! {
495 impl<
496 #(#generic_type_tokens,)*
497 Ret: ReturnType,
498 F: Fn(&mut Interpreter, #(#generic_type_tokens,)*) -> Ret + 'static,
499 > ConvertToFuncTrait<Box<dyn Fn(&mut Interpreter, #(#generic_type_tokens,)*) -> Ret + 'static>> for F {
500 #[inline(always)]
501 fn func_trait(self) -> Box<dyn Fn(&mut Interpreter, #(#generic_type_tokens,)*) -> Ret + 'static> {
502 Box::new(self)
503 }
504 }
505
506 impl<
507 #(#generic_type_tokens,)*
508 Ret: ReturnType,
509 > NativeFunctionAdapter for Box<dyn Fn(&mut Interpreter, #(#generic_type_tokens,)*) -> Ret> where
510 (#(#generic_type_tokens,)*): FromLangArgs,
511 {
512 fn lang_call(
513 &self,
514 interpreter: &mut Interpreter,
515 this_object: OptionLangObjectRef,
516 args: Vec<DataObjectRef>,
517 ) -> Result<OptionDataObjectRef> {
518 let args = <(#(#generic_type_tokens,)*)>::from_lang_args(this_object, args)?;
519
520 self(interpreter, #(args.#index_literal_tokens,)*).into()
521 }
522
523 fn lang_parameter_count(&self) -> usize {
524 <(#(#generic_type_tokens,)*)>::lang_parameter_count()
525 }
526
527 fn is_method(&self) -> bool {
528 <(#(#generic_type_tokens,)*)>::is_method()
529 }
530 }
531
532 impl<
533 #(#generic_type_tokens,)*
534 Ret: ReturnType,
535 > private::Sealed for Box<dyn Fn(&mut Interpreter, #(#generic_type_tokens,)*) -> Ret> where
536 (#(#generic_type_tokens,)*): FromLangArgs,
537 {}
538 })
539}