trans_gen/gens/dlang/
mod.rs

1use super::*;
2
3fn conv(name: &str) -> String {
4    name.replace("Int32", "Int")
5        .replace("Int64", "Long")
6        .replace("Float32", "Float")
7        .replace("Float64", "Double")
8        .replace("Params", "Parameters")
9}
10
11pub struct Generator {
12    model_init: String,
13    files: HashMap<String, String>,
14}
15
16fn type_name(schema: &Schema) -> String {
17    match schema {
18        Schema::Bool => "bool".to_owned(),
19        Schema::Int32 => "int".to_owned(),
20        Schema::Int64 => "long".to_owned(),
21        Schema::Float32 => "float".to_owned(),
22        Schema::Float64 => "double".to_owned(),
23        Schema::String => "string".to_owned(),
24        Schema::Struct(Struct { name, .. })
25        | Schema::OneOf {
26            base_name: name, ..
27        }
28        | Schema::Enum {
29            base_name: name, ..
30        } => name.camel_case(conv),
31        Schema::Option(inner) => format!("Nullable!({})", type_name(inner)),
32        Schema::Vec(inner) => format!("{}[]", type_name(inner)),
33        Schema::Map(key, value) => format!("{}[{}]", type_name(value), type_name(key),),
34    }
35}
36
37fn index_var_name(index_var: &mut usize) -> String {
38    let result = "ijk".chars().nth(*index_var).unwrap();
39    *index_var += 1;
40    result.to_string()
41}
42
43fn var_name(name: &str) -> &str {
44    match name.rfind('.') {
45        Some(index) => &name[(index + 1)..],
46        None => name,
47    }
48}
49
50fn write_struct(
51    writer: &mut Writer,
52    struc: &Struct,
53    base: Option<(&Name, usize)>,
54) -> std::fmt::Result {
55    // Class
56    if let Some((base_name, _)) = base {
57        writeln!(
58            writer,
59            "static class {} : {} {{",
60            struc.name.camel_case(conv),
61            base_name.camel_case(conv)
62        )?;
63    } else {
64        writeln!(writer, "struct {} {{", struc.name.camel_case(conv))?;
65    }
66    writer.inc_ident();
67    if let Some((_, tag)) = base {
68        writeln!(writer, "static const int TAG = {};", tag)?;
69    }
70
71    // Fields
72    for field in &struc.fields {
73        writeln!(
74            writer,
75            "{} {};",
76            type_name(&field.schema),
77            field.name.mixed_case(conv)
78        )?;
79    }
80
81    // Constructor
82    if base.is_some() {
83        writeln!(writer, "this() {{}}")?;
84    }
85    if !struc.fields.is_empty() {
86        write!(writer, "this(")?;
87        for (index, field) in struc.fields.iter().enumerate() {
88            if index > 0 {
89                write!(writer, ", ")?;
90            }
91            write!(
92                writer,
93                "{} {}",
94                type_name(&field.schema),
95                field.name.mixed_case(conv)
96            )?;
97        }
98        writeln!(writer, ") {{")?;
99        for field in &struc.fields {
100            writeln!(
101                writer,
102                "    this.{} = {};",
103                field.name.mixed_case(conv),
104                field.name.mixed_case(conv)
105            )?;
106        }
107        writeln!(writer, "}}")?;
108    }
109
110    // Reading
111    writeln!(
112        writer,
113        "static {} readFrom(Stream reader) {{",
114        struc.name.camel_case(conv)
115    )?;
116    writer.inc_ident();
117    writeln!(
118        writer,
119        "auto result = {}{}();",
120        if base.is_some() { "new " } else { "" },
121        struc.name.camel_case(conv)
122    )?;
123    for field in &struc.fields {
124        fn assign(
125            writer: &mut Writer,
126            to: &str,
127            schema: &Schema,
128            index_var: &mut usize,
129        ) -> std::fmt::Result {
130            match schema {
131                Schema::Bool => {
132                    writeln!(writer, "{} = reader.readBool();", to)?;
133                }
134                Schema::Int32 => {
135                    writeln!(writer, "{} = reader.readInt();", to)?;
136                }
137                Schema::Int64 => {
138                    writeln!(writer, "{} = reader.readLong();", to)?;
139                }
140                Schema::Float32 => {
141                    writeln!(writer, "{} = reader.readFloat();", to)?;
142                }
143                Schema::Float64 => {
144                    writeln!(writer, "{} = reader.readDouble();", to)?;
145                }
146                Schema::String => {
147                    writeln!(writer, "{} = reader.readString();", to)?;
148                }
149                Schema::Struct(Struct { name, .. })
150                | Schema::OneOf {
151                    base_name: name, ..
152                } => {
153                    writeln!(
154                        writer,
155                        "{} = {}.readFrom(reader);",
156                        to,
157                        name.camel_case(conv)
158                    )?;
159                }
160                Schema::Option(inner) => {
161                    writeln!(writer, "if (reader.readBool()) {{")?;
162                    writer.inc_ident();
163                    assign(writer, to, inner, index_var)?;
164                    writer.dec_ident();
165                    writeln!(writer, "}} else {{")?;
166                    writeln!(writer, "    {}.nullify();", to)?;
167                    writeln!(writer, "}}")?;
168                }
169                Schema::Vec(inner) => {
170                    writeln!(
171                        writer,
172                        "{} = new {}[reader.readInt()];",
173                        to,
174                        type_name(inner),
175                    )?;
176                    let index_var_name = index_var_name(index_var);
177                    writeln!(
178                        writer,
179                        "for (int {} = 0; {} < {}.length; {}++) {{",
180                        index_var_name, index_var_name, to, index_var_name
181                    )?;
182                    writer.inc_ident();
183                    assign(
184                        writer,
185                        &format!("{}[{}]", to, index_var_name),
186                        inner,
187                        index_var,
188                    )?;
189                    writer.dec_ident();
190                    writeln!(writer, "}}")?;
191                }
192                Schema::Map(key_type, value_type) => {
193                    let to_size = format!("{}Size", var_name(to));
194                    writeln!(writer, "int {} = reader.readInt();", to_size)?;
195                    writeln!(writer, "{}.clear();", to)?;
196                    let index_var_name = index_var_name(index_var);
197                    writeln!(
198                        writer,
199                        "for (int {} = 0; {} < {}; {}++) {{",
200                        index_var_name, index_var_name, to_size, index_var_name
201                    )?;
202                    writer.inc_ident();
203                    writeln!(writer, "{} {}Key;", type_name(key_type), var_name(to))?;
204                    assign(writer, &format!("{}Key", var_name(to)), key_type, index_var)?;
205                    writeln!(writer, "{} {}Value;", type_name(value_type), var_name(to))?;
206                    assign(
207                        writer,
208                        &format!("{}Value", var_name(to)),
209                        value_type,
210                        index_var,
211                    )?;
212                    writeln!(
213                        writer,
214                        "{}[{}Key] = {}Value;",
215                        to,
216                        var_name(to),
217                        var_name(to)
218                    )?;
219                    writer.dec_ident();
220                    writeln!(writer, "}}")?;
221                }
222                Schema::Enum {
223                    documentation: _,
224                    base_name,
225                    variants,
226                } => {
227                    writeln!(writer, "switch (reader.readInt()) {{")?;
228                    for (tag, variant) in variants.iter().enumerate() {
229                        writeln!(writer, "case {}:", tag)?;
230                        writeln!(
231                            writer,
232                            "    {} = {}.{};",
233                            to,
234                            base_name.camel_case(conv),
235                            variant.name.camel_case(conv)
236                        )?;
237                        writeln!(writer, "    break;")?;
238                    }
239                    writeln!(writer, "default:")?;
240                    writeln!(writer, "    throw new Exception(\"Unexpected tag value\");")?;
241                    writeln!(writer, "}}")?;
242                }
243            }
244            Ok(())
245        }
246        assign(
247            writer,
248            &format!("result.{}", field.name.mixed_case(conv)),
249            &field.schema,
250            &mut 0,
251        )?;
252    }
253    writeln!(writer, "return result;")?;
254    writer.dec_ident();
255    writeln!(writer, "}}")?;
256
257    // Writing
258    writeln!(
259        writer,
260        "{}void writeTo(Stream writer) const {{",
261        if base.is_some() { "override " } else { "" }
262    )?;
263    writer.inc_ident();
264    if base.is_some() {
265        writeln!(writer, "writer.write(TAG);")?;
266    }
267    if let Some(magic) = struc.magic {
268        writeln!(writer, "writer.write({});", magic)?;
269    }
270    for field in &struc.fields {
271        fn write(writer: &mut Writer, value: &str, schema: &Schema) -> std::fmt::Result {
272            match schema {
273                Schema::Bool => {
274                    writeln!(writer, "writer.write({});", value)?;
275                }
276                Schema::Int32 => {
277                    writeln!(writer, "writer.write({});", value)?;
278                }
279                Schema::Int64 => {
280                    writeln!(writer, "writer.write({});", value)?;
281                }
282                Schema::Float32 => {
283                    writeln!(writer, "writer.write({});", value)?;
284                }
285                Schema::Float64 => {
286                    writeln!(writer, "writer.write({});", value)?;
287                }
288                Schema::String => {
289                    writeln!(writer, "writer.write({});", value)?;
290                }
291                Schema::Struct(_) | Schema::OneOf { .. } => {
292                    writeln!(writer, "{}.writeTo(writer);", value)?;
293                }
294                Schema::Option(inner) => {
295                    writeln!(writer, "if ({}.isNull()) {{", value)?;
296                    writeln!(writer, "    writer.write(false);")?;
297                    writeln!(writer, "}} else {{")?;
298                    writer.inc_ident();
299                    writeln!(writer, "writer.write(true);")?;
300                    write(writer, &format!("{}.get", value), inner)?;
301                    writer.dec_ident();
302                    writeln!(writer, "}}")?;
303                }
304                Schema::Vec(inner) => {
305                    writeln!(writer, "writer.write(cast(int)({}.length));", value)?;
306                    writeln!(writer, "foreach ({}Element; {}) {{", var_name(value), value)?;
307                    writer.inc_ident();
308                    write(writer, &format!("{}Element", var_name(value)), inner)?;
309                    writer.dec_ident();
310                    writeln!(writer, "}}")?;
311                }
312                Schema::Map(key_type, value_type) => {
313                    writeln!(writer, "writer.write(cast(int)({}.length));", value)?;
314                    writeln!(
315                        writer,
316                        "foreach ({}Key, {}Value; {}) {{",
317                        var_name(value),
318                        var_name(value),
319                        value
320                    )?;
321                    writer.inc_ident();
322                    write(writer, &format!("{}Key", var_name(value)), key_type)?;
323                    write(writer, &format!("{}Value", var_name(value)), value_type)?;
324                    writer.dec_ident();
325                    writeln!(writer, "}}")?;
326                }
327                Schema::Enum { .. } => {
328                    writeln!(writer, "writer.write(cast(int)({}));", value)?;
329                }
330            }
331            Ok(())
332        }
333        write(writer, &field.name.mixed_case(conv), &field.schema)?;
334    }
335    writer.dec_ident();
336    writeln!(writer, "}}")?;
337
338    // ToString
339    writeln!(
340        writer,
341        "{}string toString() const {{",
342        if base.is_some() { "override " } else { "" }
343    )?;
344    writer.inc_ident();
345    writeln!(writer, "return {:?} ~ \"(\" ~", struc.name.camel_case(conv))?;
346    writer.inc_ident();
347    for field in &struc.fields {
348        writeln!(writer, "to!string({}) ~", field.name.mixed_case(conv))?;
349    }
350    writeln!(writer, "\")\";")?;
351    writer.dec_ident();
352    writer.dec_ident();
353    writeln!(writer, "}}")?;
354
355    writer.dec_ident();
356    writeln!(writer, "}}")?;
357    Ok(())
358}
359
360impl crate::Generator for Generator {
361    type Options = ();
362    fn new(_name: &str, _version: &str, _: ()) -> Self {
363        let mut files = HashMap::new();
364        files.insert("stream.d".to_owned(), include_str!("stream.d").to_owned());
365        Self {
366            model_init: String::new(),
367            files,
368        }
369    }
370    fn result(mut self) -> GenResult {
371        if !self.model_init.is_empty() {
372            self.files
373                .insert("model/package.d".to_owned(), self.model_init);
374        }
375        self.files.into()
376    }
377    fn add_only(&mut self, schema: &Schema) {
378        match schema {
379            Schema::Enum {
380                documentation: _,
381                base_name,
382                variants,
383            } => {
384                let file_name = format!("model/{}.d", base_name.snake_case(conv));
385                let mut writer = Writer::new();
386                writeln!(writer, "enum {} : int {{", base_name.camel_case(conv)).unwrap();
387                writer.inc_ident();
388                for (tag, variant) in variants.iter().enumerate() {
389                    writeln!(writer, "{} = {},", variant.name.camel_case(conv), tag,).unwrap();
390                }
391                writer.dec_ident();
392                writeln!(writer, "}}").unwrap();
393                self.files.insert(file_name, writer.get());
394                writeln!(
395                    &mut self.model_init,
396                    "public import {};",
397                    base_name.snake_case(conv),
398                )
399                .unwrap();
400            }
401            Schema::Struct(struc) => {
402                let file_name = format!("model/{}.d", struc.name.snake_case(conv));
403                let mut writer = Writer::new();
404                writeln!(writer, "import model;").unwrap();
405                writeln!(writer, "import stream;").unwrap();
406                writeln!(writer, "import std.conv;").unwrap();
407                writeln!(writer, "import std.typecons : Nullable;").unwrap();
408                writeln!(writer).unwrap();
409                write_struct(&mut writer, struc, None).unwrap();
410                self.files.insert(file_name, writer.get());
411                writeln!(
412                    &mut self.model_init,
413                    "public import {};",
414                    struc.name.snake_case(conv),
415                )
416                .unwrap();
417            }
418            Schema::OneOf {
419                documentation: _,
420                base_name,
421                variants,
422            } => {
423                let file_name = format!("model/{}.d", base_name.snake_case(conv));
424                let mut writer = Writer::new();
425                writeln!(writer, "import model;").unwrap();
426                writeln!(writer, "import stream;").unwrap();
427                writeln!(writer, "import std.conv;").unwrap();
428                writeln!(writer, "import std.typecons : Nullable;").unwrap();
429                writeln!(writer).unwrap();
430                writeln!(
431                    &mut writer,
432                    "abstract class {} {{",
433                    base_name.camel_case(conv)
434                )
435                .unwrap();
436                {
437                    writer.inc_ident();
438                    writeln!(&mut writer, "abstract void writeTo(Stream writer) const;").unwrap();
439                    writeln!(
440                        &mut writer,
441                        "static {} readFrom(Stream reader) {{",
442                        base_name.camel_case(conv)
443                    )
444                    .unwrap();
445                    {
446                        writer.inc_ident();
447                        writeln!(&mut writer, "switch (reader.readInt()) {{").unwrap();
448                        writer.inc_ident();
449                        for variant in variants {
450                            writeln!(&mut writer, "case {}.TAG:", variant.name.camel_case(conv))
451                                .unwrap();
452                            writeln!(
453                                &mut writer,
454                                "    return {}.readFrom(reader);",
455                                variant.name.camel_case(conv)
456                            )
457                            .unwrap();
458                        }
459                        writeln!(&mut writer, "default:").unwrap();
460                        writeln!(
461                            &mut writer,
462                            "    throw new Exception(\"Unexpected tag value\");"
463                        )
464                        .unwrap();
465                        writer.dec_ident();
466                        writeln!(&mut writer, "}}").unwrap();
467                        writer.dec_ident();
468                    }
469                    writeln!(&mut writer, "}}").unwrap();
470                    for (tag, variant) in variants.iter().enumerate() {
471                        writeln!(&mut writer).unwrap();
472                        write_struct(&mut writer, variant, Some((base_name, tag))).unwrap();
473                    }
474                    writer.dec_ident();
475                }
476                writeln!(&mut writer, "}}").unwrap();
477                self.files.insert(file_name, writer.get());
478                writeln!(
479                    &mut self.model_init,
480                    "public import {};",
481                    base_name.snake_case(conv),
482                )
483                .unwrap();
484            }
485            Schema::Bool
486            | Schema::Int32
487            | Schema::Int64
488            | Schema::Float32
489            | Schema::Float64
490            | Schema::String
491            | Schema::Option(_)
492            | Schema::Vec(_)
493            | Schema::Map(_, _) => {}
494        }
495    }
496}