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 dsrcgen.cpp : CppModule;
15 
16 import cpptooling.data : CppClass, LocationTag;
17 import cpptooling.data.symbol : USRType;
18 
19 @safe:
20 
21 // for now this function is only used at one place but genCtor, genDtor and
22 // genOp is expected to use it in the future.
23 private string genLocationComment(LookupT)(USRType usr, LookupT lookup) {
24     import std.algorithm : map, joiner;
25 
26     foreach (loc; lookup(usr).map!(a => a.any).joiner) {
27         return "Origin " ~ loc.toString;
28     }
29 
30     return "Unknown origin for USR " ~ cast(string) usr;
31 }
32 
33 /** Generate code for a C++ class from a CppClass specification.
34  *
35  * Params:
36  *  lookup = expecting same signature and behavior as Container.find!LocationTag
37  */
38 void generateHdr(LookupT)(CppClass in_c, CppModule hdr, Flag!"locationAsComment" loc_as_comment,
39         LookupT lookup, Flag!"inlineDtor" inline_dtor = No.inlineDtor) {
40     import std.array : array;
41     import std.algorithm : each, map, joiner;
42     import std.variant : visit;
43     import std.utf : byChar;
44     import cpptooling.data.representation;
45     import cpptooling.utility.sort : indexSort;
46 
47     static void genCtor(const ref CppCtor m, CppModule hdr) {
48         string params = m.paramRange().joinParams();
49         hdr.ctor(m.name, params);
50     }
51 
52     static void genDtor(const ref CppDtor m, CppModule hdr, Flag!"inlineDtor" inline_dtor) {
53         if (inline_dtor) {
54             hdr.dtor(m.isVirtual() ? Yes.isVirtual : No.isVirtual, m.name)[$.end = " {}"];
55         } else {
56             hdr.dtor(m.isVirtual() ? Yes.isVirtual : No.isVirtual, m.name);
57         }
58     }
59 
60     static void genMethod(const ref CppMethod m, CppModule hdr,
61             Flag!"locationAsComment" loc_as_comment, LookupT lookup) {
62         import cpptooling.data;
63 
64         if (loc_as_comment) {
65             hdr.comment(genLocationComment(m.usr, lookup))[$.begin = "/// "];
66         }
67 
68         foreach (comment; m.comments) {
69             hdr.comment(comment)[$.begin = "/// "];
70         }
71 
72         string params = m.paramRange().joinParams();
73         auto o = hdr.method(cast(Flag!"isVirtual") m.isVirtual(),
74                 m.returnType.toStringDecl, m.name, cast(Flag!"isConst") m.isConst, params);
75         if (m.isPure) {
76             o[$.end = " = 0;"];
77         }
78     }
79 
80     //TODO not implemented
81     static void genOp(const ref CppMethodOp m, CppModule hdr) {
82     }
83 
84     in_c.commentRange().each!(a => hdr.comment(a)[$.begin = "/// "]);
85     auto c = hdr.class_(in_c.name, in_c.inherits.map!(a => a.toString)
86             .joiner(", ").byChar.array().idup);
87     auto pub = c.public_();
88 
89     // dfmt off
90     foreach (m; in_c.methodPublicRange
91              .array()
92              .indexSort!((ref a, ref b) => getName(a) < getName(b))
93              ) {
94         () @trusted {
95         m.visit!(
96             (const CppMethod m) => genMethod(m, pub, loc_as_comment, lookup),
97             (const CppMethodOp m) => genOp(m, pub),
98             (const CppCtor m) => genCtor(m, pub),
99             (const CppDtor m) => genDtor(m, pub, inline_dtor));
100         }();
101     }
102     // dfmt on
103     hdr.sep(2);
104 }