1 // This file is part of Visual D 2 // 3 // Visual D integrates the D programming language into Visual Studio 4 // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved 5 // 6 // Distributed under the Boost Software License, Version 1.0. 7 // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt 8 9 module vdc.ast.writer; 10 11 import vdc.lexer; 12 import vdc.util; 13 import vdc.parser.expr; 14 import vdc.parser.decl; 15 import vdc.parser.stmt; 16 import vdc.parser.aggr; 17 import vdc.parser.misc; 18 import vdc.parser.mod; 19 import ast = vdc.ast.all; 20 21 import std.stdio; 22 import std.array; 23 24 //////////////////////////////////////////////////////////////// 25 void delegate(string s) getStringSink(ref string s) 26 { 27 void stringSink(string txt) 28 { 29 s ~= txt; 30 } 31 return &stringSink; 32 } 33 34 void delegate(string s) getConsoleSink() 35 { 36 void consoleSink(string txt) 37 { 38 write(txt); 39 } 40 return &consoleSink; 41 } 42 43 class CodeWriter 44 { 45 alias void delegate(string s) Sink; 46 47 Sink sink; 48 49 bool writeDeclarations = true; 50 bool writeImplementations = true; 51 bool writeClassImplementations = true; 52 bool writeReferencedOnly = false; 53 bool newline; 54 bool lastLineEmpty; 55 56 string indentation; 57 58 this(Sink snk) 59 { 60 sink = snk; 61 } 62 63 abstract void writeNode(ast.Node node); 64 65 void write(T...)(T args) 66 { 67 if(newline) 68 { 69 sink(indentation); 70 newline = false; 71 } 72 foreach(t; args) 73 static if(is(typeof(t) : ast.Node)) 74 writeNode(t); 75 else static if(is(typeof(t) : int)) 76 writeKeyword(t); 77 else 78 sink(t); 79 } 80 81 void opCall(T...)(T args) 82 { 83 write(args); 84 } 85 86 void indent(int n) 87 { 88 if(n > 0) 89 indentation ~= replicate(" ", n); 90 else 91 indentation = indentation[0..$+n*2]; 92 } 93 94 void writeArray(T)(T[] members, string sep = ", ", bool beforeFirst = false, bool afterLast = false) 95 { 96 bool writeSep = beforeFirst; 97 foreach(m; members) 98 { 99 if(writeSep) 100 write(sep); 101 writeSep = true; 102 write(m); 103 } 104 if(afterLast) 105 write(sep); 106 } 107 108 @property void nl(bool force = true) 109 { 110 if(!lastLineEmpty) 111 force = true; 112 113 if(force) 114 { 115 sink("\n"); 116 lastLineEmpty = newline; 117 newline = true; 118 } 119 } 120 121 void writeKeyword(int id) 122 { 123 write(tokenString(id)); 124 } 125 126 void writeIdentifier(string ident) 127 { 128 write(ident); 129 } 130 131 bool writeAttributes(Attribute attr, bool spaceBefore = false) 132 { 133 if(!attr) 134 return false; 135 while(attr) 136 { 137 Attribute a = attr & -attr; 138 if(spaceBefore) 139 write(" "); 140 write(attrToString(a)); 141 if(!spaceBefore) 142 write(" "); 143 attr -= a; 144 } 145 return true; 146 } 147 148 bool writeAnnotations(Annotation annot, bool spaceBefore = false) 149 { 150 if(!annot) 151 return false; 152 while(annot) 153 { 154 Annotation a = annot & -annot; 155 if(spaceBefore) 156 write(" "); 157 write(annotationToString(a)); 158 if(!spaceBefore) 159 write(" "); 160 annot -= a; 161 } 162 return true; 163 } 164 165 void writeAttributesAndAnnotations(Attribute attr, Annotation annot, bool spaceBefore = false) 166 { 167 writeAttributes(attr, spaceBefore); 168 writeAnnotations(annot, spaceBefore); 169 } 170 } 171 172 class DCodeWriter : CodeWriter 173 { 174 this(Sink snk) 175 { 176 super(snk); 177 } 178 179 override void writeNode(ast.Node node) 180 { 181 node.toD(this); 182 } 183 } 184 185 class CCodeWriter : CodeWriter 186 { 187 this(Sink snk) 188 { 189 super(snk); 190 } 191 192 override void writeNode(ast.Node node) 193 { 194 node.toC(this); 195 } 196 197 override void writeKeyword(int id) 198 { 199 // Compiler-specific 200 switch(id) 201 { 202 case TOK_long: write("__int64"); break; 203 case TOK_alias: write("typedef"); break; 204 case TOK_in: write("const"); break; 205 default: 206 write(tokenString(id)); 207 } 208 } 209 210 override void writeIdentifier(string ident) 211 { 212 // check whether it conflicts with a C++ keyword 213 // Compiler-specific 214 switch(ident) 215 { 216 case "__int64": 217 case "__int32": 218 case "__int16": 219 case "__int8": 220 case "unsigned": 221 case "signed": 222 write(ident, "__D"); 223 break; 224 default: 225 write(ident); 226 break; 227 } 228 } 229 230 override bool writeAttributes(Annotation attr, bool spaceBefore = false) 231 { 232 if(!attr) 233 return false; 234 while(attr) 235 { 236 Attribute a = attr & -attr; 237 string cs = attrToStringC(a); 238 if(cs.length > 0) 239 { 240 if(spaceBefore) 241 write(" "); 242 write(cs); 243 if(!spaceBefore) 244 write(" "); 245 } 246 attr -= a; 247 } 248 return true; 249 } 250 251 override bool writeAnnotations(Annotation annot, bool spaceBefore = false) 252 { 253 return true; 254 } 255 } 256 257 struct CodeIndenter 258 { 259 CodeWriter writer; 260 int indent; 261 262 this(CodeWriter _writer, int n = 1) 263 { 264 writer = _writer; 265 indent = n; 266 267 writer.indent(n); 268 } 269 ~this() 270 { 271 writer.indent(-indent); 272 } 273 } 274 275 string writeD(ast.Node n) 276 { 277 string txt; 278 DCodeWriter writer = new DCodeWriter(getStringSink(txt)); 279 writer.writeImplementations = false; 280 writer.writeClassImplementations = false; 281 writer(n); 282 return txt; 283 } 284 285 //////////////////////////////////////////////////////////////// 286 287 version(all) { 288 import vdc.parser.engine; 289 290 void verifyParseWrite(string filename = __FILE__, int lno = __LINE__)(string txt) 291 { 292 Parser p = new Parser; 293 p.filename = filename; 294 ast.Node n = p.parseModule(txt); 295 296 string ntxt; 297 DCodeWriter writer = new DCodeWriter(getStringSink(ntxt)); 298 writer(n); 299 300 ast.Node m = p.parseModule(ntxt); 301 bool eq = n.compare(m); 302 assert(eq); 303 } 304 305 //////////////////////////////////////////////////////////////// 306 }