ts_gen/codegen/
functions.rs1use proc_macro2::TokenStream;
4use quote::quote;
5
6use crate::codegen::signatures::{
7 expand_signatures, generate_concrete_params, is_void_return, ExpandedSignature, SignatureKind,
8};
9use crate::codegen::typemap::{to_return_type, to_syn_type, CodegenContext, TypePosition};
10use crate::parse::scope::ScopeId;
11use std::collections::HashSet;
12
13use crate::ir::{FunctionDecl, ModuleContext, VariableDecl};
14
15pub fn generate_function(
19 decl: &FunctionDecl,
20 ctx: &ModuleContext,
21 cgctx: Option<&CodegenContext<'_>>,
22 doc: &Option<String>,
23 scope: ScopeId,
24) -> TokenStream {
25 let mut used_names = HashSet::new();
26 let sigs = expand_signatures(
27 &decl.js_name,
28 &[decl.params.as_slice()],
29 &decl.return_type,
30 SignatureKind::Function,
31 doc,
32 &mut used_names,
33 cgctx,
34 scope,
35 );
36
37 let items: Vec<TokenStream> = sigs
38 .iter()
39 .map(|sig| generate_expanded_free_function(sig, ctx, cgctx, None, scope))
40 .collect();
41
42 quote! { #(#items)* }
43}
44
45pub fn generate_function_with_js_namespace(
47 decl: &FunctionDecl,
48 ctx: &ModuleContext,
49 js_namespace: &str,
50 cgctx: Option<&CodegenContext<'_>>,
51 doc: &Option<String>,
52 scope: ScopeId,
53) -> TokenStream {
54 let mut used_names = HashSet::new();
55 let sigs = expand_signatures(
56 &decl.js_name,
57 &[decl.params.as_slice()],
58 &decl.return_type,
59 SignatureKind::Function,
60 doc,
61 &mut used_names,
62 cgctx,
63 scope,
64 );
65
66 let items: Vec<TokenStream> = sigs
67 .iter()
68 .map(|sig| generate_expanded_free_function(sig, ctx, cgctx, Some(js_namespace), scope))
69 .collect();
70
71 quote! { #(#items)* }
72}
73
74fn generate_expanded_free_function(
76 sig: &ExpandedSignature,
77 ctx: &ModuleContext,
78 cgctx: Option<&CodegenContext<'_>>,
79 js_namespace: Option<&str>,
80 scope: ScopeId,
81) -> TokenStream {
82 let rust_ident = super::typemap::make_ident(&sig.rust_name);
83 let params = generate_concrete_params(&sig.params, cgctx, scope);
84 let ret_ty = to_return_type(&sig.return_type, sig.catch, cgctx, scope);
85 let doc = super::doc_tokens(&sig.doc);
86 let has_variadic = sig.params.last().is_some_and(|p| p.variadic);
87
88 let mut wb_parts: Vec<TokenStream> = Vec::new();
89 if has_variadic {
90 wb_parts.push(quote! { variadic });
91 }
92 if sig.catch {
93 wb_parts.push(quote! { catch });
94 }
95 if sig.rust_name != sig.js_name {
99 let js_name = &sig.js_name;
100 wb_parts.push(quote! { js_name = #js_name });
101 }
102 if let Some(ns) = js_namespace {
103 wb_parts.push(quote! { js_namespace = #ns });
104 }
105
106 let wb_attr = if wb_parts.is_empty() {
107 quote! {}
108 } else {
109 quote! { #[wasm_bindgen(#(#wb_parts),*)] }
110 };
111
112 let ret = if is_void_return(&sig.return_type) && !sig.catch {
113 quote! {}
114 } else {
115 quote! { -> #ret_ty }
116 };
117
118 let wb_extern_attr = match ctx {
119 ModuleContext::Module(m) => quote! { #[wasm_bindgen(module = #m)] },
120 ModuleContext::Global => quote! { #[wasm_bindgen] },
121 };
122
123 quote! {
124 #wb_extern_attr
125 extern "C" {
126 #doc
127 #wb_attr
128 pub fn #rust_ident(#params) #ret;
129 }
130 }
131}
132
133pub fn generate_variable(
135 decl: &VariableDecl,
136 ctx: &ModuleContext,
137 cgctx: Option<&CodegenContext<'_>>,
138 doc: &Option<String>,
139 js_namespace: Option<&str>,
140 scope: ScopeId,
141) -> TokenStream {
142 let rust_ident = super::typemap::make_ident(&decl.name);
143 let ty = to_syn_type(&decl.type_ref, TypePosition::RETURN, cgctx, scope);
144 let doc = super::doc_tokens(doc);
145
146 let mut wb_parts: Vec<TokenStream> = vec![quote! { thread_local_v2 }];
147 if decl.js_name != decl.name {
148 let js_name = &decl.js_name;
149 wb_parts.push(quote! { js_name = #js_name });
150 }
151 if let Some(ns) = js_namespace {
152 wb_parts.push(quote! { js_namespace = #ns });
153 }
154
155 let wb_attr = quote! { #[wasm_bindgen(#(#wb_parts),*)] };
156
157 let wb_extern_attr = match ctx {
158 ModuleContext::Module(m) => quote! { #[wasm_bindgen(module = #m)] },
159 ModuleContext::Global => quote! { #[wasm_bindgen] },
160 };
161
162 quote! {
163 #wb_extern_attr
164 extern "C" {
165 #doc
166 #wb_attr
167 pub static #rust_ident: #ty;
168 }
169 }
170}