1 /** 2 * Copyright: Copyright (c) 2012 Jacob Carlborg. All rights reserved. 3 * Authors: Jacob Carlborg 4 * Version: Initial created: Jan 29, 2012 5 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) 6 */ 7 module dstep.translator.Output; 8 9 static import std.array; 10 11 import tango.util.container.HashSet; 12 13 import mambo.core._; 14 15 import clang.Cursor; 16 import dstep.translator.IncludeHandler; 17 import dstep.translator.Type; 18 19 Output output; 20 21 static this () 22 { 23 output = new Output; 24 } 25 26 class Output 27 { 28 String currentContext; 29 30 alias currentContext this; 31 32 String before; 33 String after; 34 String imports; 35 string externDeclaration; 36 37 string[] typedefs; 38 string[] variables; 39 40 string[] classes; 41 string[] interfaces; 42 string[] structs; 43 string[] enums; 44 string[] unions; 45 string[] functions; 46 47 ClassData currentClass; 48 ClassData currentInterface; 49 50 this () 51 { 52 before = new String; 53 after = new String; 54 imports = new String; 55 currentContext = new String; 56 57 currentClass = new ClassData; 58 currentInterface = new ClassData; 59 } 60 61 @property string data () 62 { 63 newContext(); 64 65 this ~= before.data; 66 addDeclarations(includeHandler.toImports(), false); 67 this ~= imports.data; 68 69 if (imports.any) 70 this ~= nl; 71 72 if (externDeclaration.isPresent) 73 { 74 this ~= externDeclaration; 75 currentContext.put(nl, nl); 76 } 77 78 addDeclarations(typedefs, false); 79 addDeclarations(variables, false); 80 addDeclarations(enums); 81 addDeclarations(structs); 82 addDeclarations(unions); 83 addDeclarations(classes); 84 addDeclarations(interfaces); 85 addDeclarations(functions, false); 86 87 this ~= after.data; 88 89 return currentContext.data; 90 } 91 92 /** 93 * Creates a new context and sets it as the current context. Returns the newly created 94 * context. 95 */ 96 String newContext () 97 { 98 auto context = new String; 99 context.indentationLevel = currentContext.indentationLevel; 100 return currentContext = context; 101 } 102 103 override string toString () 104 { 105 return data.strip('\n'); 106 } 107 108 private: 109 110 void addDeclarations (string[] declarations, bool extraNewline = true) 111 { 112 auto newline = "\n"; 113 114 if (extraNewline) 115 newline ~= "\n"; 116 117 this ~= declarations.join(newline); 118 119 if (declarations.any) 120 this ~= "\n\n"; 121 } 122 } 123 124 class StructData 125 { 126 string name; 127 128 string[] instanceVariables; 129 130 bool isFwdDeclaration; 131 132 @property string data () 133 { 134 auto context = output.newContext(); 135 136 if (name.isPresent) 137 name = ' ' ~ name; 138 139 if (isFwdDeclaration) 140 { 141 context.put(type, name, ";", nl); 142 isFwdDeclaration = true; 143 } 144 else 145 { 146 context.put(type, name, nl, '{', nl); 147 148 context.indent in { 149 addDeclarations(context, instanceVariables); 150 }; 151 152 auto str = context.data.strip('\n'); 153 context = output.newContext(); 154 context ~= str; 155 context.put(nl, '}'); 156 } 157 158 return context.data; 159 } 160 161 protected: 162 163 @property string type () 164 { 165 return "struct"; 166 } 167 168 void addDeclarations (String context, string[] declarations) 169 { 170 foreach (i, e ; declarations) 171 { 172 if (i != 0) 173 context ~= nl; 174 175 context ~= e; 176 } 177 178 if (declarations.any) 179 { 180 context ~= nl; 181 context ~= nl; 182 } 183 } 184 } 185 186 class EnumData : StructData 187 { 188 @property override string type () 189 { 190 return "enum"; 191 } 192 193 protected: 194 195 override void addDeclarations (String context, string[] declarations) 196 { 197 foreach (i, e ; declarations) 198 { 199 if (i != 0) 200 { 201 context ~= ","; 202 context ~= nl; 203 } 204 205 context ~= e; 206 } 207 208 if (declarations.any) 209 { 210 context ~= nl; 211 context ~= nl; 212 } 213 } 214 } 215 216 class UnionData : StructData 217 { 218 @property override string type () 219 { 220 return "union"; 221 } 222 } 223 224 class ClassData : StructData 225 { 226 string[] instanceMethods; 227 string[] staticMethods; 228 string[] properties; 229 string[] staticProperties; 230 string[] staticVariables; 231 232 string name; 233 string superclass; 234 string[] interfaces; 235 236 HashSet!(string) propertyList; 237 238 private bool[string] mangledMethods; 239 240 this () 241 { 242 propertyList = new HashSet!(string); 243 } 244 245 string getMethodName (FunctionCursor func, string name = "", bool translateIdentifier = true) 246 { 247 auto mangledName = mangle(func, name); 248 auto selector = func.spelling; 249 250 if (!(mangledName in mangledMethods)) 251 { 252 mangledMethods[mangledName] = true; 253 name = name.isBlank ? selector : name; 254 return translateSelector(name, false, translateIdentifier); 255 } 256 257 return translateSelector(name, true, translateIdentifier); 258 } 259 260 private string mangle (FunctionCursor func, string name) 261 { 262 auto selector = func.spelling; 263 name = name.isBlank ? translateSelector(selector) : name; 264 auto mangledName = name; 265 266 foreach (param ; func.parameters) 267 mangledName ~= "_" ~ translateType(param.type); 268 269 return mangledName; 270 } 271 272 @property override string data () 273 { 274 auto cls = output.newContext(); 275 276 cls.put(type, ' ', name); 277 278 if (superclass.any) 279 cls.put(" : ", superclass); 280 281 writeInterfaces(cls); 282 cls.put(nl, '{', nl); 283 writeMembers(cls); 284 285 auto context = output.newContext(); 286 context ~= cls.data.strip('\n'); 287 context.put(nl, '}'); 288 289 return context.data; 290 } 291 292 override protected @property string type () 293 { 294 return "class"; 295 } 296 297 private: 298 299 void writeInterfaces (String cls) 300 { 301 if (interfaces.any) 302 { 303 if (superclass.isEmpty) 304 cls ~= " : "; 305 306 foreach (i, s ; interfaces) 307 { 308 if (i != 0) 309 cls ~= ", "; 310 311 cls ~= s; 312 } 313 } 314 } 315 316 void writeMembers (String cls) 317 { 318 cls.indent in { 319 addDeclarations(cls, staticVariables); 320 addDeclarations(cls, instanceVariables); 321 addDeclarations(cls, staticProperties); 322 addDeclarations(cls, properties); 323 addDeclarations(cls, staticMethods); 324 addDeclarations(cls, instanceMethods); 325 }; 326 } 327 } 328 329 class InterfaceData : ClassData 330 { 331 protected @property override string type () 332 { 333 return "interface"; 334 } 335 } 336 337 class ClassExtensionData : ClassData 338 { 339 protected @property override string type () 340 { 341 return "__classext"; 342 } 343 } 344 345 class String 346 { 347 int indentationLevel; 348 349 private 350 { 351 std.array.Appender!(string) appender; 352 int prevIndendationLevel; 353 bool shouldIndent; 354 } 355 356 String opOpAssign (string op, T) (T t) if (op == "~" && !is(T == NewLine)) 357 { 358 return put(t); 359 } 360 361 String opOpAssign (string op) (NewLine) if (op == "~") 362 { 363 return put(nl); 364 } 365 366 String put (Args...) (Args args)// if (!is(T == NewLine)) 367 { 368 foreach (arg ; args) 369 { 370 static if (is(typeof(arg) == NewLine)) 371 put(nl); 372 373 else 374 { 375 if (shouldIndent) 376 { 377 _indent(); 378 shouldIndent = false; 379 } 380 381 appender.put(arg); 382 } 383 } 384 385 return this; 386 } 387 388 String put () (NewLine) 389 { 390 appender.put('\n'); 391 shouldIndent = indentationLevel > 0; 392 393 return this; 394 } 395 396 alias put append; 397 398 String appendnl (T) (T t) 399 { 400 put(t); 401 return put(nl); 402 } 403 404 @property string data () 405 { 406 return appender.data; 407 } 408 409 @property bool isEmpty () 410 { 411 return appender.data.isEmpty; 412 } 413 414 Indendation indent () 415 { 416 return indent(indentationLevel + 1); 417 } 418 419 Indendation indent (int indentationLevel) 420 { 421 prevIndendationLevel = this.indentationLevel; 422 this.indentationLevel = indentationLevel; 423 return Indendation(this); 424 } 425 426 static struct Indendation 427 { 428 private String str; 429 430 void opIn (void delegate () dg) 431 { 432 str.shouldIndent = str.indentationLevel > 0; 433 dg(); 434 output.currentContext = str; 435 str.indentationLevel = str.prevIndendationLevel; 436 } 437 } 438 439 private: 440 441 void _indent () 442 { 443 foreach (i ; 0 .. indentationLevel) 444 appender.put(" "); 445 } 446 } 447 448 struct NewLine {} 449 NewLine nl;