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 }