1 /**
2 Copyright: Copyright (c) 2015-2017, Joakim Brännström. All rights reserved.
3 License: MPL-2
4 Author: Joakim Brännström (joakim.brannstrom@gmx.com)
5 
6 This Source Code Form is subject to the terms of the Mozilla Public License,
7 v.2.0. If a copy of the MPL was not distributed with this file, You can obtain
8 one at http://mozilla.org/MPL/2.0/.
9 */
10 module cpptooling.generator.classes;
11 
12 import std.typecons : Yes, No, Flag;
13 
14 import my.sumtype;
15 
16 import dsrcgen.cpp : CppModule;
17 
18 import cpptooling.data : CppClass, LocationTag;
19 import cpptooling.data.symbol : USRType;
20 
21 @safe:
22 
23 // for now this function is only used at one place but genCtor, genDtor and
24 // genOp is expected to use it in the future.
25 private string genLocationComment(LookupT)(USRType usr, LookupT lookup) {
26     import std.algorithm : map, joiner;
27 
28     foreach (loc; lookup(usr).map!(a => a.any).joiner) {
29         return "Origin " ~ loc.toString;
30     }
31 
32     return "Unknown origin for USR " ~ cast(string) usr;
33 }
34 
35 /** Generate code for a C++ class from a CppClass specification.
36  *
37  * Params:
38  *  lookup = expecting same signature and behavior as Container.find!LocationTag
39  */
40 void generateHdr(LookupT)(CppClass in_c, CppModule hdr, Flag!"locationAsComment" loc_as_comment,
41         LookupT lookup, Flag!"inlineDtor" inline_dtor = No.inlineDtor) @trusted {
42     import std.array : array;
43     import std.algorithm : each, map, joiner;
44     import std.variant : visit;
45     import std.utf : byChar;
46     import cpptooling.data.representation;
47     import cpptooling.utility.sort : indexSort;
48 
49     static void genCtor(ref CppCtor m, CppModule hdr) {
50         string params = m.paramRange().joinParams();
51         hdr.ctor(m.name.get, params);
52     }
53 
54     static void genDtor(ref CppDtor m, CppModule hdr, Flag!"inlineDtor" inline_dtor) {
55         if (inline_dtor) {
56             hdr.dtor(m.isVirtual() ? Yes.isVirtual : No.isVirtual, m.name)[$.end = " {}"];
57         } else {
58             hdr.dtor(m.isVirtual() ? Yes.isVirtual : No.isVirtual, m.name);
59         }
60     }
61 
62     static void genMethod(ref CppMethod m, CppModule hdr,
63             Flag!"locationAsComment" loc_as_comment, LookupT lookup) {
64         import cpptooling.data;
65 
66         if (loc_as_comment) {
67             hdr.comment(genLocationComment(m.usr.get, lookup))[$.begin = "/// "];
68         }
69 
70         foreach (comment; m.comments) {
71             hdr.comment(comment)[$.begin = "/// "];
72         }
73 
74         string params = m.paramRange().joinParams();
75         auto o = hdr.method(cast(Flag!"isVirtual") m.isVirtual(),
76                 m.returnType.toStringDecl, m.name, cast(Flag!"isConst") m.isConst, params);
77         if (m.isPure) {
78             o[$.end = " = 0;"];
79         }
80     }
81 
82     //TODO not implemented
83     static void genOp(ref CppMethodOp m, CppModule hdr) {
84     }
85 
86     in_c.commentRange().each!(a => hdr.comment(a)[$.begin = "/// "]);
87     auto c = hdr.class_(in_c.name, in_c.inherits.map!(a => a.toString)
88             .joiner(", ").byChar.array().idup);
89     auto pub = c.public_();
90 
91     // dfmt off
92     foreach (m; in_c.methodPublicRange
93              .array
94              .indexSort!((ref a, ref b) => getName(a) < getName(b))
95              ) {
96         m.match!(
97             (CppMethod m) => genMethod(m, pub, loc_as_comment, lookup),
98             (CppMethodOp m) => genOp(m, pub),
99             (CppCtor m) => genCtor(m, pub),
100             (CppDtor m) => genDtor(m, pub, inline_dtor));
101     }
102     // dfmt on
103     hdr.sep(2);
104 }