1 /*
2  * This file is part of gir-to-d.
3  *
4  * gir-to-d is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation, either version 3
7  * of the License, or (at your option) any later version.
8  *
9  * gir-to-d is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with gir-to-d.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 module gtd.GirConstant;
19 
20 import std.algorithm : among, canFind;
21 import std.array : replace;
22 import std..string : splitLines, strip;
23 
24 import gtd.GirPackage;
25 import gtd.GirType;
26 import gtd.GirWrapper;
27 import gtd.Log;
28 import gtd.XMLReader;
29 
30 final class GirConstant
31 {
32 	string name;
33 	string cType;
34 	string value;
35 	string doc;
36 
37 	GirType type;
38 	GirPackage pack;
39 	GirWrapper wrapper;
40 
41 	this(GirWrapper wrapper, GirPackage pack)
42 	{
43 		this.wrapper = wrapper;
44 		this.pack = pack;
45 	}
46 
47 	void parse(T)(XMLReader!T reader)
48 	{
49 		name = reader.front.attributes["name"];
50 		value = reader.front.attributes["value"];
51 		if ( "c:type" in reader.front.attributes )
52 			cType = reader.front.attributes["c:type"];
53 		else
54 			cType = reader.front.attributes["c:identifier"];
55 
56 		reader.popFront();
57 
58 		while( !reader.empty && !reader.endTag("constant") )
59 		{
60 			switch(reader.front.value)
61 			{
62 				case "type":
63 				case "array":
64 					type = new GirType(wrapper);
65 					type.parse(reader);
66 					break;
67 				case "doc":
68 					reader.popFront();
69 					doc ~= reader.front.value;
70 					reader.popFront();
71 					break;
72 				case "doc-deprecated":
73 					reader.popFront();
74 					doc ~= "\n\nDeprecated: "~ reader.front.value;
75 					reader.popFront();
76 					break;
77 				case "source-position":
78 					reader.skipTag();
79 					break;
80 				default:
81 					warning("Unexpected tag: ", reader.front.value, " in GirConstant: ", name, reader);
82 			}
83 			reader.popFront();
84 		}
85 
86 		if ( value.canFind("\\") )
87 			value = value.replace("\\", "\\\\");
88 
89 		if ( type.cType.among("gint64", "guint64") )
90 			// See dmd issue 8929 for why we use UL for signed longs. https://issues.dlang.org/show_bug.cgi?id=8929#c7
91 			value ~= "UL";
92 	}
93 
94 	string[] getConstantDeclaration()
95 	{
96 		string[] buff;
97 		if ( doc !is null && wrapper.includeComments )
98 		{
99 			buff ~= "/**";
100 			foreach ( line; doc.splitLines() )
101 				buff ~= " * "~ line.strip();
102 			buff ~= " */";
103 		}
104 
105 		if ( type.name in pack.collectedAliases && pack.collectedAliases[type.name].baseType.cType.among("gint64", "guint64") )
106 			value ~= "UL";
107 
108 		if ( type.isString() )
109 			buff ~= "enum "~ name ~" = \""~ value ~"\";";
110 		else
111 			buff ~= "enum "~ name ~" = "~ value ~";";
112 
113 		buff ~= "alias "~ cType ~" = "~ name ~";";
114 
115 		return buff;
116 	}
117 }