ligen_core/generator/
ffi_generator.rs1use crate::prelude::*;
4
5use crate::generator::{Context, ImplementationVisitor, FunctionVisitor};
6use crate::ir::{Type, Identifier, Visibility, ImplementationItem};
7use crate::ir::processing::ReplaceIdentifier;
8
9pub trait FFIGenerator {
11 fn generate_ffi(&self, context: &Context, visitor: Option<&ImplementationVisitor>) -> TokenStream;
13}
14
15pub trait GenericFFIGenerator {
17 fn generate_parameters(_context: &Context, function: &FunctionVisitor) -> TokenStream {
19 let object_identifier = function.parent.current.self_.path().last();
20 function
21 .current
22 .inputs
23 .iter()
24 .fold(TokenStream::new(), |mut tokens, parameter| {
25 let type_ = Self::to_marshal_parameter(¶meter.type_);
26 let identifier = self_to_explicit_name(¶meter.identifier, &object_identifier);
27 tokens.append_all(quote! {#identifier: #type_,});
28 tokens
29 })
30 }
31
32 fn generate_arguments(_context: &Context, function: &FunctionVisitor) -> TokenStream {
34 let object_identifier = function.parent.current.self_.path().last();
35 function
36 .current
37 .inputs
38 .iter()
39 .fold(TokenStream::new(), |mut tokens, parameter| {
40 let identifier = self_to_explicit_name(¶meter.identifier, &object_identifier);
41 tokens.append_all(quote! {#identifier.into(),});
42 tokens
43 })
44 }
45
46 fn to_marshal_output(type_: &Type) -> TokenStream {
48 match type_ {
49 Type::Compound(path) => match path.segments.last().unwrap().name.as_str() {
50 "String" => quote! { *mut crate::ffi::RString },
51 _ => quote! { *mut #type_ },
52 },
53 _ => quote! { #type_ },
54 }
55 }
56
57 fn to_marshal_parameter(type_: &Type) -> TokenStream {
59 match type_ {
60 Type::Compound(path) => match path.segments.last().unwrap().name.as_str() {
61 "String" => quote! { crate::ffi::CChar },
62 _ => quote! { *mut #type_ },
63 },
64 _ => quote! { #type_ },
65 }
66 }
67
68 fn generate_output(_context: &Context, output: &Option<Type>) -> TokenStream {
70 match output {
71 Some(type_) => Self::to_marshal_output(type_),
72 _ => quote! {()},
73 }
74 }
75
76 fn generate_function_signature(
78 context: &Context,
79 visitor: &FunctionVisitor,
80 ) -> TokenStream {
81 let implementation = &visitor.parent.current;
82 let function = &visitor.current;
83 let parameters = Self::generate_parameters(context, visitor);
84 let output = Self::generate_output(context, &function.output);
85 let function_name = format!("{}_{}", implementation.self_.path().last().name, function.identifier.name);
86 let function_identifier = Identifier::new(&function_name);
87 quote! {
88 #[no_mangle]
89 pub extern fn #function_identifier(#parameters) -> #output
90 }
91 }
92
93 fn generate_function_block(
95 context: &Context,
96 visitor: &FunctionVisitor,
97 ) -> TokenStream {
98 let method = &visitor.current;
99 let implementation = &visitor.parent.current;
100 let arguments = Self::generate_arguments(context, visitor);
101 let self_identifier = &implementation.self_;
102 let method_identifier = &method.identifier;
103 let result = if let Some(Type::Compound(_identifier)) = method.output.as_ref() {
104 quote! {
105 Box::into_raw(Box::new(result.into()))
106 }
107 } else {
108 quote! {result}
109 };
110 quote! {
111 {
112 let result = #self_identifier::#method_identifier(#arguments);
113 #result
114 }
115 }
116 }
117
118 fn generate_function(
120 context: &Context,
121 visitor: &FunctionVisitor,
122 ) -> TokenStream {
123 if let Visibility::Public = visitor.current.visibility {
124 let function_signature = Self::generate_function_signature(context, visitor);
125 let method_block = Self::generate_function_block(context, visitor);
126 quote! { #function_signature #method_block }
127 } else {
128 quote! {}
129 }
130 }
131
132 fn generate_drop(visitor: &ImplementationVisitor) -> TokenStream {
134 let self_path = visitor.current.self_.path();
135 let object_name = self_path.last();
136 let drop_name = Identifier::new(format!("{}_drop", object_name.name).as_str());
137 quote! {
138 #[no_mangle]
139 pub unsafe extern fn #drop_name(object: *mut #object_name) {
140 Box::from_raw(object);
141 }
142 }
143 }
144
145 fn generate(context: &Context, implementation: &ImplementationVisitor) -> TokenStream {
147 let mut tokens =
148 implementation
149 .current
150 .items
151 .iter()
152 .fold(TokenStream::new(), |mut tokens, item| {
153 match item {
154 ImplementationItem::Constant(_) => unimplemented!("Constants aren't implemented yet."),
155 ImplementationItem::Method(method) => tokens.append_all(Self::generate_function(context, &implementation.child(method.clone()))),
156 }
157 tokens
158 });
159 tokens.append_all(Self::generate_drop(&implementation));
160 tokens
161 }
162}
163
164fn self_to_explicit_name(identifier: &Identifier, name_identifier: &Identifier) -> Identifier {
165 let mut identifier = identifier.clone();
166 identifier.replace_identifier(&Identifier::new("self"), &Identifier::new(name_identifier.name.to_lowercase()));
167 identifier
168}
169
170impl<T: GenericFFIGenerator> FFIGenerator for T {
171 fn generate_ffi(&self, context: &Context, implementation: Option<&ImplementationVisitor>) -> TokenStream {
172 implementation
173 .map(|implementation| Self::generate(context, implementation))
174 .unwrap_or_else(|| TokenStream::new())
175 }
176}