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.GirEnum; 19 20 import std.array : split; 21 import std.algorithm; 22 import std.range : back, empty; 23 import std..string : splitLines, strip, toUpper; 24 import std.uni : isNumber; 25 26 import gtd.GirPackage; 27 import gtd.GirWrapper; 28 import gtd.Log; 29 import gtd.XMLReader; 30 31 final class GirEnum 32 { 33 string name; 34 string cName; 35 string libVersion; 36 string doc; 37 38 GirEnumMember[] members; 39 GirWrapper wrapper; 40 GirPackage pack; 41 42 this(GirWrapper wrapper, GirPackage pack) 43 { 44 this.wrapper = wrapper; 45 this.pack = pack; 46 } 47 48 void parse(T)(XMLReader!T reader) 49 { 50 name = reader.front.attributes["name"]; 51 cName = reader.front.attributes["c:type"]; 52 53 if ( "version" in reader.front.attributes ) 54 libVersion = reader.front.attributes["version"]; 55 reader.popFront(); 56 57 while ( !reader.empty && !reader.endTag("bitfield", "enumeration") ) 58 { 59 switch (reader.front.value) 60 { 61 case "doc": 62 reader.popFront(); 63 doc ~= reader.front.value; 64 reader.popFront(); 65 break; 66 case "doc-deprecated": 67 reader.popFront(); 68 doc ~= "\n\nDeprecated: "~ reader.front.value; 69 reader.popFront(); 70 break; 71 case "member": 72 if ( reader.front.attributes["name"].startsWith("2bu", "2bi", "3bu") ) 73 { 74 reader.skipTag(); 75 break; 76 } 77 78 GirEnumMember member = GirEnumMember(wrapper); 79 member.parse(reader); 80 members ~= member; 81 break; 82 case "function": 83 //Skip these functions for now 84 //as they are also availabe as global functions. 85 //pack.parseFunction(reader); 86 reader.skipTag(); 87 break; 88 case "source-position": 89 reader.skipTag(); 90 break; 91 default: 92 warning("Unexpected tag: ", reader.front.value, " in GirEnum: ", name, reader); 93 } 94 reader.popFront(); 95 } 96 } 97 98 string[] getEnumDeclaration() 99 { 100 string[] buff; 101 if ( doc !is null && wrapper.includeComments ) 102 { 103 buff ~= "/**"; 104 foreach ( line; doc.splitLines() ) 105 buff ~= " * "~ line.strip(); 106 107 if ( libVersion ) 108 { 109 buff ~= " *"; 110 buff ~= " * Since: "~ libVersion; 111 } 112 113 buff ~= " */"; 114 } 115 116 buff ~= "public enum "~ cName ~(name.among("ParamFlags", "MessageType") ? " : uint" : ""); 117 buff ~= "{"; 118 119 foreach ( member; members ) 120 { 121 buff ~= member.getEnumMemberDeclaration(); 122 } 123 124 buff ~= "}"; 125 if ( name !is null && pack.name.among("glgdk", "glgtk") ) 126 buff ~= "alias "~ cName ~" GL"~ name ~";"; 127 else if ( name !is null && pack.name != "pango" ) 128 buff ~= "alias "~ cName ~" "~ name ~";"; 129 130 return buff; 131 } 132 } 133 134 struct GirEnumMember 135 { 136 string name; 137 string value; 138 string doc; 139 140 GirWrapper wrapper; 141 142 @disable this(); 143 144 this(GirWrapper wrapper) 145 { 146 this.wrapper = wrapper; 147 } 148 149 void parse(T)(XMLReader!T reader) 150 { 151 name = reader.front.attributes["name"]; 152 value = reader.front.attributes["value"]; 153 154 if ( name.empty ) 155 name = reader.front.attributes["c:identifier"].split("_").back; 156 157 if ( reader.front.type == XMLNodeType.EmptyTag ) 158 return; 159 160 reader.popFront(); 161 162 while ( !reader.empty && !reader.endTag("member", "constant") ) 163 { 164 switch (reader.front.value) 165 { 166 case "doc": 167 reader.popFront(); 168 doc ~= reader.front.value; 169 reader.popFront(); 170 break; 171 case "doc-deprecated": 172 reader.popFront(); 173 doc ~= "\n\nDeprecated: "~ reader.front.value; 174 reader.popFront(); 175 break; 176 case "source-position": 177 reader.skipTag(); 178 break; 179 case "type": 180 if ( reader.front.attributes["name"] == "utf8" ) 181 value = "\""~ value ~"\""; 182 break; 183 default: 184 warning("Unexpected tag: ", reader.front.value, " in GirEnumMember: ", name, reader); 185 } 186 reader.popFront(); 187 } 188 } 189 190 string[] getEnumMemberDeclaration() 191 { 192 string[] buff; 193 if ( doc !is null && wrapper.includeComments ) 194 { 195 buff ~= "/**"; 196 foreach ( line; doc.splitLines() ) 197 buff ~= " * "~ line.strip(); 198 buff ~= " */"; 199 } 200 201 if ( name[0].isNumber && name !in wrapper.aliasses ) 202 buff ~= "_"~ name.toUpper() ~" = "~ value ~","; 203 else 204 buff ~= tokenToGtkD(name.toUpper(), wrapper.aliasses, false) ~" = "~ value ~","; 205 206 return buff; 207 } 208 }