1use std::collections::HashMap;
2use std::fmt::Write;
3use trans_gen_core::trans_schema::*;
4use trans_gen_core::Writer;
5
6fn conv(name: &str) -> String {
7 name.replace("Int32", "Int")
8 .replace("Int64", "Long")
9 .replace("Float32", "Single")
10 .replace("Float64", "Double")
11 .replace("Params", "Parameters")
12}
13
14pub struct Generator {
15 main_namespace: String,
16 files: HashMap<String, String>,
17}
18
19fn type_name(schema: &Schema) -> String {
20 format!("{}{}", type_name_prearray(schema), type_post_array(schema))
21}
22
23fn type_name_prearray(schema: &Schema) -> String {
24 match schema {
25 Schema::Bool => "bool".to_owned(),
26 Schema::Int32 => "int".to_owned(),
27 Schema::Int64 => "long".to_owned(),
28 Schema::Float32 => "single".to_owned(),
29 Schema::Float64 => "double".to_owned(),
30 Schema::String => "string".to_owned(),
31 Schema::Struct(Struct { name, .. })
32 | Schema::OneOf {
33 base_name: name, ..
34 }
35 | Schema::Enum {
36 base_name: name, ..
37 } => format!("{}", name.camel_case(conv)),
38 Schema::Option(inner) => format!("option<{}>", type_name(inner)),
39 Schema::Vec(inner) => type_name_prearray(inner),
40 Schema::Map(key, value) => format!("Map<{}, {}>", type_name(key), type_name(value)),
41 }
42}
43
44fn type_post_array(schema: &Schema) -> String {
45 match schema {
46 Schema::Vec(inner) => format!("[]{}", type_post_array(inner)),
47 _ => String::new(),
48 }
49}
50
51fn index_var_name(index_var: &mut usize) -> String {
52 let result = "ijk".chars().nth(*index_var).unwrap();
53 *index_var += 1;
54 result.to_string()
55}
56
57fn var_name(name: &str) -> &str {
58 match name.rfind('.') {
59 Some(index) => &name[(index + 1)..],
60 None => name,
61 }
62}
63
64fn write_struct(
65 writer: &mut Writer,
66 struc: &Struct,
67 base: Option<(&Name, usize)>,
68) -> std::fmt::Result {
69 let struc_name = if let Some((base, _)) = base {
70 format!("{}{}", base.camel_case(conv), struc.name.camel_case(conv))
71 } else {
72 struc.name.camel_case(conv)
73 };
74
75 if struc.fields.is_empty() {
76 writeln!(writer, "type {} = struct end with", struc_name)?;
77 writer.inc_ident();
78 } else {
79 writeln!(writer, "type {} = {{", struc_name)?;
80 writer.inc_ident();
81 for (index, field) in struc.fields.iter().enumerate() {
82 writeln!(
83 writer,
84 "{}: {};",
85 field.name.camel_case(conv),
86 type_name(&field.schema),
87 )?;
93 }
94 writeln!(writer, "}} with")?;
95 }
96
97 writeln!(
99 writer,
100 "member this.writeTo(writer: System.IO.BinaryWriter) ="
101 )?;
102 writer.inc_ident();
103 if let Some((_, discriminant)) = base {
104 writeln!(writer, "writer.Write {}", discriminant)?;
105 }
106 if let Some(magic) = struc.magic {
107 writeln!(writer, "writer.Write {}", magic)?;
108 }
109 for field in &struc.fields {
110 fn write(writer: &mut Writer, value: &str, schema: &Schema) -> std::fmt::Result {
111 match schema {
112 Schema::Bool => {
113 writeln!(writer, "writer.Write {}", value)?;
114 }
115 Schema::Int32 => {
116 writeln!(writer, "writer.Write {}", value)?;
117 }
118 Schema::Int64 => {
119 writeln!(writer, "writer.Write {}", value)?;
120 }
121 Schema::Float32 => {
122 writeln!(writer, "writer.Write {}", value)?;
123 }
124 Schema::Float64 => {
125 writeln!(writer, "writer.Write {}", value)?;
126 }
127 Schema::String => {
128 let data_var = format!("{}Data", var_name(value));
129 writeln!(
130 writer,
131 "let {} : byte[] = System.Text.Encoding.UTF8.GetBytes {}",
132 data_var, value
133 )?;
134 writeln!(writer, "writer.Write {}.Length", data_var)?;
135 writeln!(writer, "writer.Write {}", data_var)?;
136 }
137 Schema::Struct(_) | Schema::OneOf { .. } => {
138 writeln!(writer, "{}.writeTo writer", value)?;
139 }
140 Schema::Option(inner) => {
141 writeln!(writer, "match {} with", value)?;
142 writer.inc_ident();
143 writeln!(writer, "| Some value ->")?;
144 writer.inc_ident();
145 writeln!(writer, "writer.Write true")?;
146 write(writer, "value", inner)?;
147 writer.dec_ident();
148 writeln!(writer, "| None -> writer.Write false")?;
149 writer.dec_ident();
150 }
151 Schema::Vec(inner) => {
152 writeln!(writer, "writer.Write {}.Length", value)?;
153 writeln!(writer, "{} |> Array.iter (fun value ->", value)?;
154 writer.inc_ident();
155 write(writer, "value", inner)?;
156 writer.dec_ident();
157 writeln!(writer, ")")?;
158 }
159 Schema::Map(key_type, value_type) => {
160 writeln!(writer, "writer.Write {}.Count", value)?;
161 writeln!(writer, "{} |> Map.iter (fun key value ->", value)?;
162 writer.inc_ident();
163 write(writer, "key", key_type)?;
164 write(writer, "value", value_type)?;
165 writer.dec_ident();
166 writeln!(writer, ")")?;
167 }
168 Schema::Enum { .. } => {
169 writeln!(writer, "writer.Write (int {})", value)?;
170 }
171 }
172 Ok(())
173 }
174 write(
175 writer,
176 &format!("this.{}", field.name.camel_case(conv)),
177 &field.schema,
178 )?;
179 }
180 writer.dec_ident();
181
182 if struc.fields.is_empty() {
184 writeln!(
185 writer,
186 "static member readFrom(reader: System.IO.BinaryReader) = new {}()",
187 struc_name,
188 )?;
189 } else {
190 writeln!(
191 writer,
192 "static member readFrom(reader: System.IO.BinaryReader) = {{"
193 )?;
194 writer.inc_ident();
195 for field in &struc.fields {
196 fn read(writer: &mut Writer, schema: &Schema) -> std::fmt::Result {
197 match schema {
198 Schema::Bool => {
199 writeln!(writer, "reader.ReadBoolean()")?;
200 }
201 Schema::Int32 => {
202 writeln!(writer, "reader.ReadInt32()")?;
203 }
204 Schema::Int64 => {
205 writeln!(writer, "reader.ReadInt64()")?;
206 }
207 Schema::Float32 => {
208 writeln!(writer, "reader.ReadSingle()")?;
209 }
210 Schema::Float64 => {
211 writeln!(writer, "reader.ReadDouble()")?;
212 }
213 Schema::String => {
214 writeln!(writer, "reader.ReadInt32() |> reader.ReadBytes |> System.Text.Encoding.UTF8.GetString")?;
215 }
216 Schema::Struct(Struct { name, .. })
217 | Schema::OneOf {
218 base_name: name, ..
219 } => {
220 writeln!(writer, "{}.readFrom reader", name.camel_case(conv))?;
221 }
222 Schema::Option(inner) => {
223 writeln!(writer, "match reader.ReadBoolean() with")?;
224 writer.inc_ident();
225 writeln!(writer, "| true ->")?;
226 writer.inc_ident();
227 writeln!(writer, "Some(")?;
228 writer.inc_ident();
229 read(writer, inner)?;
230 writeln!(writer, ")")?;
231 writer.dec_ident();
232 writer.dec_ident();
233 writeln!(writer, "| false -> None")?;
234 writer.dec_ident();
235 }
236 Schema::Vec(inner) => {
237 writeln!(writer, "[|for _ in 1 .. reader.ReadInt32() do")?;
238 writer.inc_ident();
239 write!(writer, "yield ")?;
240 read(writer, inner)?;
241 writer.dec_ident();
242 writeln!(writer, "|]")?;
243 }
244 Schema::Map(key_type, value_type) => {
245 writeln!(writer, "[for _ in 1 .. reader.ReadInt32() do")?;
246 writer.inc_ident();
247 write!(writer, "let key = ")?;
248 read(writer, key_type)?;
249 write!(writer, "let value = ")?;
250 read(writer, value_type)?;
251 writeln!(writer, "yield (key, value)")?;
252 writeln!(writer, "] |> Map.ofList")?;
253 writer.dec_ident();
254 }
255 Schema::Enum { .. } => {
256 writeln!(writer, "reader.ReadInt32() |> enum")?;
257 }
258 }
259 Ok(())
260 }
261 write!(writer, "{} = ", field.name.camel_case(conv))?;
262 read(writer, &field.schema)?;
263 }
264 writer.dec_ident();
265 writeln!(writer, "}}")?;
266 }
267
268 writer.dec_ident();
269
270 Ok(())
271}
272
273impl trans_gen_core::Generator for Generator {
274 fn new(name: &str, version: &str) -> Self {
275 Self {
276 main_namespace: Name::new(name.to_owned()).camel_case(conv),
277 files: HashMap::new(),
278 }
279 }
280 fn result(self) -> HashMap<String, String> {
281 self.files
282 }
283 fn add_only(&mut self, schema: &Schema) {
284 match schema {
285 Schema::Enum {
286 base_name,
287 variants,
288 } => {
289 let file_name = format!("Model/{}.fs", base_name.camel_case(conv));
290 let mut writer = Writer::new();
291 writeln!(writer, "#nowarn \"0058\"").unwrap();
292 writeln!(writer, "namespace {}.Model", self.main_namespace).unwrap();
293 writeln!(writer, "type {} =", base_name.camel_case(conv)).unwrap();
294 writer.inc_ident();
295 for (discriminant, variant) in variants.iter().enumerate() {
296 writeln!(writer, "| {} = {}", variant.camel_case(conv), discriminant).unwrap();
297 }
298 writer.dec_ident();
299 self.files.insert(file_name, writer.get());
300 }
301 Schema::Struct(struc) => {
302 let file_name = format!("Model/{}.fs", struc.name.camel_case(conv));
303 let mut writer = Writer::new();
304 writeln!(writer, "#nowarn \"0058\"").unwrap();
305 writeln!(writer, "namespace {}.Model", self.main_namespace).unwrap();
306 write_struct(&mut writer, struc, None).unwrap();
307 self.files.insert(file_name, writer.get());
308 }
309 Schema::OneOf {
310 base_name,
311 variants,
312 } => {
313 let file_name = format!("Model/{}.fs", base_name.camel_case(conv));
314 let mut writer = Writer::new();
315 writeln!(writer, "#nowarn \"0058\"").unwrap();
316 writeln!(writer, "namespace {}.Model", self.main_namespace).unwrap();
317
318 for (discriminant, variant) in variants.iter().enumerate() {
319 writeln!(&mut writer).unwrap();
320 write_struct(&mut writer, variant, Some((base_name, discriminant))).unwrap();
321 }
322
323 writeln!(&mut writer, "type {} = ", base_name.camel_case(conv)).unwrap();
324 writer.inc_ident();
325 for (discriminant, variant) in variants.iter().enumerate() {
326 writeln!(
327 writer,
328 "| {} of {}{}",
329 variant.name.camel_case(conv),
330 base_name.camel_case(conv),
331 variant.name.camel_case(conv)
332 )
333 .unwrap();
334 }
335 writeln!(writer, "with").unwrap();
336
337 writeln!(
338 writer,
339 "member this.writeTo(writer: System.IO.BinaryWriter) ="
340 )
341 .unwrap();
342 writer.inc_ident();
343 writeln!(writer, "match this with").unwrap();
344 writer.inc_ident();
345 for (discriminant, variant) in variants.iter().enumerate() {
346 writeln!(
347 writer,
348 "| {} value -> value.writeTo writer",
349 variant.name.camel_case(conv),
350 )
351 .unwrap();
352 }
353 writer.dec_ident();
354 writer.dec_ident();
355
356 writeln!(
357 writer,
358 "static member readFrom(reader: System.IO.BinaryReader) ="
359 )
360 .unwrap();
361 writer.inc_ident();
362 writeln!(writer, "match reader.ReadInt32() with").unwrap();
363 writer.inc_ident();
364 for (discriminant, variant) in variants.iter().enumerate() {
365 writeln!(
366 writer,
367 "| {} -> {} ({}{}.readFrom reader)",
368 discriminant,
369 variant.name.camel_case(conv),
370 base_name.camel_case(conv),
371 variant.name.camel_case(conv),
372 )
373 .unwrap();
374 }
375 writeln!(
376 writer,
377 "| x -> failwith (sprintf \"Unexpected CustomDataType %d\" x)"
378 )
379 .unwrap();
380 writer.dec_ident();
381 writer.dec_ident();
382
383 writer.dec_ident();
384 self.files.insert(file_name, writer.get());
385 }
386 Schema::Bool
387 | Schema::Int32
388 | Schema::Int64
389 | Schema::Float32
390 | Schema::Float64
391 | Schema::String
392 | Schema::Option(_)
393 | Schema::Vec(_)
394 | Schema::Map(_, _) => {}
395 }
396 }
397}