1#![deny(missing_docs)]
2#![doc = include_str!("../README.md")]
3#![no_std]
4
5extern crate alloc;
6extern crate ocaml_gen_derive;
7use alloc::collections::btree_map::Entry;
8use alloc::collections::BTreeMap;
9use alloc::format;
10use alloc::string::{String, ToString};
11use alloc::{vec, vec::Vec};
12
13pub use const_random::const_random;
14pub use ocaml_gen_derive::*;
15pub use paste::paste;
16
17pub mod conv;
18
19pub mod prelude {
30 pub use super::{decl_fake_generic, decl_func, decl_module, decl_type, decl_type_alias, Env};
31}
32
33#[derive(Debug)]
42pub struct Env {
43 locations: BTreeMap<u128, (Vec<&'static str>, &'static str)>,
45
46 current_module: Vec<&'static str>,
48
49 aliases: Vec<BTreeMap<u128, &'static str>>,
53}
54
55impl Drop for Env {
56 fn drop(&mut self) {
59 assert!(self.current_module.is_empty(), "you must call .root() on the environment to finalize the generation. You are currently still nested: {:?}", self.current_module);
60 }
61}
62
63impl Default for Env {
64 fn default() -> Self {
65 Self::new()
66 }
67}
68
69impl Env {
70 #[must_use]
72 pub fn new() -> Self {
73 Self {
74 locations: BTreeMap::new(),
75 current_module: Vec::new(),
76 aliases: vec![BTreeMap::new()],
77 }
78 }
79
80 pub fn new_type(&mut self, ty: u128, name: &'static str) {
85 match self.locations.entry(ty) {
86 Entry::Occupied(_) => panic!("ocaml-gen: cannot re-declare the same type twice"),
87 Entry::Vacant(v) => v.insert((self.current_module.clone(), name)),
88 };
89 }
90
91 #[must_use]
97 pub fn get_type(&self, ty: u128, name: &str) -> (String, bool) {
98 if let Some(alias) = self
100 .aliases
101 .last()
102 .expect("ocaml-gen bug: bad initialization of aliases")
103 .get(&ty)
104 {
105 return ((*alias).to_string(), true);
106 }
107
108 let (type_path, type_name) = self
110 .locations
111 .get(&ty)
112 .unwrap_or_else(|| panic!("ocaml-gen: the type {name} hasn't been declared"));
113
114 let mut current = self.current_module.clone();
116 current.reverse();
117 let path: Vec<&str> = type_path
118 .iter()
119 .skip_while(|&p| Some(*p) == current.pop())
120 .copied()
121 .collect();
122
123 let name = if path.is_empty() {
124 (*type_name).to_string()
125 } else {
126 format!("{}.{}", path.join("."), type_name)
127 };
128
129 (name, false)
130 }
131
132 pub fn add_alias(&mut self, ty: u128, alias: &'static str) {
137 let res = self
138 .aliases
139 .last_mut()
140 .expect("bug in ocaml-gen: the Env initializer is broken")
141 .insert(ty, alias);
142 assert!(
143 res.is_none(),
144 "ocaml-gen: cannot re-declare the same alias twice"
145 );
146 }
147
148 pub fn new_module(&mut self, mod_name: &'static str) -> String {
154 let first_letter = mod_name
155 .chars()
156 .next()
157 .expect("module name cannot be empty");
158 assert!(
159 first_letter.to_uppercase().to_string() == first_letter.to_string(),
160 "ocaml-gen: OCaml module names start with an uppercase, you provided: {mod_name}"
161 );
162
163 self.aliases.push(BTreeMap::new());
165
166 self.current_module.push(mod_name);
168
169 format!("module {mod_name} = struct ")
170 }
171
172 #[must_use]
174 pub fn nested(&self) -> usize {
175 self.current_module.len()
176 }
177
178 pub fn parent(&mut self) -> String {
180 self.aliases.pop();
182
183 self.current_module
185 .pop()
186 .expect("ocaml-gen: you are already at the root");
187 "end".to_string()
188 }
189
190 pub fn root(&mut self) -> String {
192 let mut res = String::new();
193 for _ in &self.current_module {
194 res.push_str("end\n");
195 }
196 res
197 }
198}
199
200pub trait OCamlBinding {
209 fn ocaml_binding(env: &mut Env, rename: Option<&'static str>, new_type: bool) -> String;
213}
214
215pub trait OCamlDesc {
220 fn ocaml_desc(env: &Env, generics: &[&str]) -> String;
224
225 fn unique_id() -> u128;
228}
229
230#[macro_export]
236macro_rules! decl_module {
237 ($w:expr, $env:expr, $name:expr, $b:block) => {{
238 use std::io::Write;
239 write!($w, "\n{}{}\n", format_args!("{: >1$}", "", $env.nested() * 2), $env.new_module($name)).unwrap();
240 $b
241 write!($w, "{}{}\n\n", format_args!("{: >1$}", "", $env.nested() * 2 - 2), $env.parent()).unwrap();
242 }}
243}
244
245#[macro_export]
247macro_rules! decl_func {
248 ($w:expr, $env:expr, $func:ident) => {{
249 use std::io::Write;
250 ::ocaml_gen::paste! {
251 let binding = [<$func _to_ocaml>]($env, None);
252 }
253 write!(
254 $w,
255 "{}{}\n",
256 format_args!("{: >1$}", "", $env.nested() * 2),
257 binding,
258 )
259 .unwrap();
260 }};
261 ($w:expr, $env:expr, $func:ident => $new:expr) => {{
263 use std::io::Write;
264 ::ocaml_gen::paste! {
265 let binding = [<$func _to_ocaml>]($env, Some($new));
266 }
267 write!(
268 $w,
269 "{}{}\n",
270 format_args!("{: >1$}", "", $env.nested() * 2),
271 binding,
272 )
273 .unwrap();
274 }};
275}
276
277#[macro_export]
279macro_rules! decl_type {
280 ($w:expr, $env:expr, $ty:ty) => {{
281 use std::io::Write;
282 let res = <$ty as ::ocaml_gen::OCamlBinding>::ocaml_binding($env, None, true);
283 write!(
284 $w,
285 "{}{}\n",
286 format_args!("{: >1$}", "", $env.nested() * 2),
287 res,
288 )
289 .unwrap();
290 }};
291 ($w:expr, $env:expr, $ty:ty => $new:expr) => {{
293 use std::io::Write;
294 let res = <$ty as ::ocaml_gen::OCamlBinding>::ocaml_binding($env, Some($new), true);
295 write!(
296 $w,
297 "{}{}\n",
298 format_args!("{: >1$}", "", $env.nested() * 2),
299 res,
300 )
301 .unwrap();
302 }};
303}
304
305#[macro_export]
307macro_rules! decl_type_alias {
308 ($w:expr, $env:expr, $new:expr => $ty:ty) => {{
309 use std::io::Write;
310 let res = <$ty as ::ocaml_gen::OCamlBinding>::ocaml_binding($env, Some($new), false);
311 write!(
312 $w,
313 "{}{}\n",
314 format_args!("{: >1$}", "", $env.nested() * 2),
315 res,
316 )
317 .unwrap();
318 }};
319}
320
321#[macro_export]
324macro_rules! decl_fake_generic {
325 ($name:ident, $i:expr) => {
326 pub struct $name;
327
328 impl ::ocaml_gen::OCamlDesc for $name {
329 fn ocaml_desc(_env: &::ocaml_gen::Env, generics: &[&str]) -> String {
330 format!("'{}", generics[$i])
331 }
332
333 fn unique_id() -> u128 {
334 ::ocaml_gen::const_random!(u128)
335 }
336 }
337 };
338}