~halega/+junk/sharpdevelop

« back to all changes in this revision

Viewing changes to src/Libraries/NRefactory/NRefactoryASTGenerator/Main.cs

  • Committer: sk
  • Date: 2011-09-10 05:17:57 UTC
  • Revision ID: halega@halega.com-20110910051757-qfouz1llya9m6boy
4.1.0.7915 Release Candidate 1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
 
2
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
 
3
 
 
4
using System;
 
5
using System.Collections.Generic;
 
6
using System.CodeDom;
 
7
using System.Diagnostics;
 
8
using System.Reflection;
 
9
using System.IO;
 
10
using NRefactoryASTGenerator.Ast;
 
11
using ICSharpCode.EasyCodeDom;
 
12
 
 
13
namespace NRefactoryASTGenerator
 
14
{
 
15
        class MainClass
 
16
        {
 
17
                public const string VisitPrefix = "Visit";
 
18
                
 
19
                static readonly string[] lineEndings = { "\r\n", "\r", "\n" };
 
20
                
 
21
                public static void Main(string[] args)
 
22
                {
 
23
                        string directory = "../../../Project/Src/Ast/";
 
24
                        string visitorsDir = "../../../Project/Src/Visitors/";
 
25
                        Debug.WriteLine("AST Generator running...");
 
26
                        if (!File.Exists(directory + "INode.cs")) {
 
27
                                Debug.WriteLine("did not find output directory");
 
28
                                return;
 
29
                        }
 
30
                        if (!File.Exists(visitorsDir + "AbstractAstTransformer.cs")) {
 
31
                                Debug.WriteLine("did not find visitor output directory");
 
32
                                return;
 
33
                        }
 
34
                        
 
35
                        List<Type> nodeTypes = new List<Type>();
 
36
                        foreach (Type type in typeof(MainClass).Assembly.GetTypes()) {
 
37
                                if (type.IsClass && typeof(INode).IsAssignableFrom(type)) {
 
38
                                        nodeTypes.Add(type);
 
39
                                }
 
40
                        }
 
41
                        nodeTypes.Sort(delegate(Type a, Type b) { return a.Name.CompareTo(b.Name); });
 
42
                        
 
43
                        CodeCompileUnit ccu = new CodeCompileUnit();
 
44
                        CodeNamespace cns = ccu.AddNamespace("ICSharpCode.NRefactory.Ast");
 
45
                        cns.AddImport("System");
 
46
                        cns.AddImport("System.Collections.Generic");
 
47
                        foreach (Type type in nodeTypes) {
 
48
                                if (type.GetCustomAttributes(typeof(CustomImplementationAttribute), false).Length == 0) {
 
49
                                        CodeTypeDeclaration ctd = cns.AddType(type.Name);
 
50
                                        if (type.IsAbstract) {
 
51
                                                ctd.TypeAttributes |= TypeAttributes.Abstract;
 
52
                                        }
 
53
                                        ctd.BaseTypes.Add(new CodeTypeReference(type.BaseType.Name));
 
54
                                        
 
55
                                        ProcessType(type, ctd);
 
56
                                        
 
57
                                        foreach (object o in type.GetCustomAttributes(false)) {
 
58
                                                if (o is TypeImplementationModifierAttribute) {
 
59
                                                        (o as TypeImplementationModifierAttribute).ModifyImplementation(cns, ctd, type);
 
60
                                                }
 
61
                                        }
 
62
                                        
 
63
                                        if (!type.IsAbstract) {
 
64
                                                CodeMemberMethod method = new CodeMemberMethod();
 
65
                                                method.Name = "AcceptVisitor";
 
66
                                                method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
 
67
                                                method.Parameters.Add(new CodeParameterDeclarationExpression("IAstVisitor", "visitor"));
 
68
                                                method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "data"));
 
69
                                                method.ReturnType = new CodeTypeReference(typeof(object));
 
70
                                                CodeExpression ex = new CodeVariableReferenceExpression("visitor");
 
71
                                                ex = new CodeMethodInvokeExpression(ex, VisitPrefix + ctd.Name,
 
72
                                                                                    new CodeThisReferenceExpression(),
 
73
                                                                                    new CodeVariableReferenceExpression("data"));
 
74
                                                method.Statements.Add(new CodeMethodReturnStatement(ex));
 
75
                                                ctd.Members.Add(method);
 
76
                                                
 
77
                                                method = new CodeMemberMethod();
 
78
                                                method.Name = "ToString";
 
79
                                                method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
 
80
                                                method.ReturnType = new CodeTypeReference(typeof(string));
 
81
                                                method.Statements.Add(new CodeMethodReturnStatement(CreateToString(type)));
 
82
                                                ctd.Members.Add(method);
 
83
                                        }
 
84
                                }
 
85
                        }
 
86
                        
 
87
                        System.CodeDom.Compiler.CodeGeneratorOptions settings = new System.CodeDom.Compiler.CodeGeneratorOptions();
 
88
                        settings.IndentString = "\t";
 
89
                        settings.VerbatimOrder = true;
 
90
                        
 
91
                        using (StringWriter writer = new StringWriter()) {
 
92
                                new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromCompileUnit(ccu, writer, settings);
 
93
                                File.WriteAllText(directory + "Generated.cs", NormalizeNewLines(writer));
 
94
                        }
 
95
                        
 
96
                        ccu = new CodeCompileUnit();
 
97
                        cns = ccu.AddNamespace("ICSharpCode.NRefactory");
 
98
                        cns.AddImport("System");
 
99
                        cns.AddImport("ICSharpCode.NRefactory.Ast");
 
100
                        cns.Types.Add(CreateAstVisitorInterface(nodeTypes));
 
101
                        
 
102
                        using (StringWriter writer = new StringWriter()) {
 
103
                                new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromCompileUnit(ccu, writer, settings);
 
104
                                File.WriteAllText(visitorsDir + "../IAstVisitor.cs", NormalizeNewLines(writer));
 
105
                        }
 
106
                        
 
107
                        ccu = new CodeCompileUnit();
 
108
                        cns = ccu.AddNamespace("ICSharpCode.NRefactory.Visitors");
 
109
                        cns.AddImport("System");
 
110
                        cns.AddImport("System.Collections.Generic");
 
111
                        cns.AddImport("System.Diagnostics");
 
112
                        cns.AddImport("ICSharpCode.NRefactory.Ast");
 
113
                        cns.Types.Add(CreateAstVisitorClass(nodeTypes, false));
 
114
                        
 
115
                        using (StringWriter writer = new StringWriter()) {
 
116
                                new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromCompileUnit(ccu, writer, settings);
 
117
                                File.WriteAllText(visitorsDir + "AbstractAstVisitor.cs", NormalizeNewLines(writer));
 
118
                        }
 
119
                        
 
120
                        ccu = new CodeCompileUnit();
 
121
                        cns = ccu.AddNamespace("ICSharpCode.NRefactory.Visitors");
 
122
                        cns.AddImport("System");
 
123
                        cns.AddImport("System.Collections.Generic");
 
124
                        cns.AddImport("System.Diagnostics");
 
125
                        cns.AddImport("ICSharpCode.NRefactory.Ast");
 
126
                        cns.Types.Add(CreateAstVisitorClass(nodeTypes, true));
 
127
                        
 
128
                        using (StringWriter writer = new StringWriter()) {
 
129
                                new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromCompileUnit(ccu, writer, settings);
 
130
                                File.WriteAllText(visitorsDir + "AbstractAstTransformer.cs", NormalizeNewLines(writer));
 
131
                        }
 
132
                        
 
133
                        ccu = new CodeCompileUnit();
 
134
                        cns = ccu.AddNamespace("ICSharpCode.NRefactory.Visitors");
 
135
                        cns.AddImport("System");
 
136
                        cns.AddImport("ICSharpCode.NRefactory.Ast");
 
137
                        cns.Types.Add(CreateNodeTrackingAstVisitorClass(nodeTypes));
 
138
                        
 
139
                        using (StringWriter writer = new StringWriter()) {
 
140
                                new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromCompileUnit(ccu, writer, settings);
 
141
                                // CodeDom cannot output "sealed", so we need to use this hack:
 
142
                                File.WriteAllText(visitorsDir + "NodeTrackingAstVisitor.cs",
 
143
                                                  NormalizeNewLines(writer).Replace("public override object", "public sealed override object"));
 
144
                        }
 
145
                        
 
146
                        //NotImplementedAstVisitor
 
147
                        ccu = new CodeCompileUnit();
 
148
                        cns = ccu.AddNamespace("ICSharpCode.NRefactory.Visitors");
 
149
                        cns.AddImport("System");
 
150
                        cns.AddImport("ICSharpCode.NRefactory.Ast");
 
151
                        cns.Types.Add(CreateNotImplementedAstVisitorClass(nodeTypes));
 
152
                        
 
153
                        using (StringWriter writer = new StringWriter()) {
 
154
                                new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromCompileUnit(ccu, writer, settings);
 
155
                                File.WriteAllText(visitorsDir + "NotImplementedAstVisitor.cs", NormalizeNewLines(writer));
 
156
                        }
 
157
                        Debug.WriteLine("AST Generator done!");
 
158
                        
 
159
                        Debug.WriteLine("start keyword list generation...");
 
160
                        
 
161
                        KeywordGenerator.Generate();
 
162
                        
 
163
                        Debug.WriteLine("keyword list generation done!");
 
164
                }
 
165
                
 
166
                static string NormalizeNewLines(StringWriter writer)
 
167
                {
 
168
                        return string.Join(Environment.NewLine, writer.ToString().Split(lineEndings, StringSplitOptions.None));
 
169
                }
 
170
                
 
171
                static CodeTypeDeclaration CreateAstVisitorInterface(List<Type> nodeTypes)
 
172
                {
 
173
                        CodeTypeDeclaration td = new CodeTypeDeclaration("IAstVisitor");
 
174
                        td.IsInterface = true;
 
175
                        
 
176
                        foreach (Type t in nodeTypes) {
 
177
                                if (!t.IsAbstract) {
 
178
                                        EasyMethod m = td.AddMethod(typeof(object), VisitPrefix + t.Name);
 
179
                                        m.AddParameter(ConvertType(t), GetFieldName(t.Name));
 
180
                                        m.AddParameter(typeof(object), "data");
 
181
                                }
 
182
                        }
 
183
                        return td;
 
184
                }
 
185
                
 
186
                static CodeTypeDeclaration CreateAstVisitorClass(List<Type> nodeTypes, bool transformer)
 
187
                {
 
188
                        CodeTypeDeclaration td = new CodeTypeDeclaration(transformer ? "AbstractAstTransformer" : "AbstractAstVisitor");
 
189
                        td.TypeAttributes = TypeAttributes.Public | TypeAttributes.Abstract;
 
190
                        td.BaseTypes.Add(new CodeTypeReference("IAstVisitor"));
 
191
                        
 
192
                        if (transformer) {
 
193
                                string comment =
 
194
                                        "The AbstractAstTransformer will iterate through the whole AST,\n " +
 
195
                                        "just like the AbstractAstVisitor. However, the AbstractAstTransformer allows\n " +
 
196
                                        "you to modify the AST at the same time: It does not use 'foreach' internally,\n " +
 
197
                                        "so you can add members to collections of parents of the current node (but\n " +
 
198
                                        "you cannot insert or delete items as that will make the index used invalid).\n " +
 
199
                                        "You can use the methods ReplaceCurrentNode and RemoveCurrentNode to replace\n " +
 
200
                                        "or remove the current node, totally independent from the type of the parent node.";
 
201
                                Easy.AddSummary(td, comment);
 
202
                                
 
203
                                CodeMemberField field = td.AddField(Easy.TypeRef("Stack", "INode"), "nodeStack");
 
204
                                field.InitExpression = Easy.New(field.Type);
 
205
                                
 
206
                                /*
 
207
                                CodeExpression nodeStack = Easy.Var("nodeStack");
 
208
                                CodeMemberProperty p = new CodeMemberProperty();
 
209
                                p.Name = "CurrentNode";
 
210
                                p.Type = new CodeTypeReference("INode");
 
211
                                p.Attributes = MemberAttributes.Public | MemberAttributes.Final;
 
212
                                p.GetStatements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("currentNode")));
 
213
                                p.SetStatements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("currentNode"),
 
214
                                                                            new CodePropertySetValueReferenceExpression()));
 
215
                                td.Members.Add(p);
 
216
                                 */
 
217
                                
 
218
                                EasyMethod m = td.AddMethod("ReplaceCurrentNode");
 
219
                                m.AddParameter(Easy.TypeRef("INode"), "newNode");
 
220
                                m.Statements.Add(Easy.Var("nodeStack").InvokeMethod("Pop"));
 
221
                                m.Statements.Add(Easy.Var("nodeStack").InvokeMethod("Push", Easy.Var("newNode")));
 
222
                                
 
223
                                m = td.AddMethod("RemoveCurrentNode");
 
224
                                m.Statements.Add(Easy.Var("nodeStack").InvokeMethod("Pop"));
 
225
                                m.Statements.Add(Easy.Var("nodeStack").InvokeMethod("Push", Easy.Null));
 
226
                        }
 
227
                        
 
228
                        foreach (Type type in nodeTypes) {
 
229
                                if (!type.IsAbstract) {
 
230
                                        EasyMethod m = td.AddMethod(typeof(object), VisitPrefix + type.Name);
 
231
                                        m.Attributes = MemberAttributes.Public;
 
232
                                        m.AddParameter(ConvertType(type), GetFieldName(type.Name));
 
233
                                        m.AddParameter(typeof(object), "data");
 
234
                                        
 
235
                                        List<CodeStatement> assertions = new List<CodeStatement>();
 
236
                                        string varVariableName = GetFieldName(type.Name);
 
237
                                        CodeExpression var = Easy.Var(varVariableName);
 
238
                                        assertions.Add(AssertIsNotNull(var));
 
239
                                        
 
240
                                        AddFieldVisitCode(m, type, var, assertions, transformer);
 
241
                                        
 
242
                                        if (type.GetCustomAttributes(typeof(HasChildrenAttribute), true).Length > 0) {
 
243
                                                if (transformer) {
 
244
                                                        m.Statements.Add(new CodeSnippetStatement(CreateTransformerLoop(varVariableName + ".Children", "INode")));
 
245
                                                        m.Body.Return(Easy.Null);
 
246
                                                } else {
 
247
                                                        m.Body.Return(var.InvokeMethod("AcceptChildren", Easy.This, Easy.Var("data")));
 
248
                                                }
 
249
                                        } else {
 
250
                                                CodeExpressionStatement lastStatement = null;
 
251
                                                if (m.Statements.Count > 0) {
 
252
                                                        lastStatement = m.Statements[m.Statements.Count - 1] as CodeExpressionStatement;
 
253
                                                }
 
254
                                                if (lastStatement != null) {
 
255
                                                        m.Statements.RemoveAt(m.Statements.Count - 1);
 
256
                                                        m.Body.Return(lastStatement.Expression);
 
257
                                                } else {
 
258
                                                        m.Body.Return(Easy.Null);
 
259
                                                }
 
260
                                        }
 
261
                                        
 
262
                                        for (int i = 0; i < assertions.Count; i++) {
 
263
                                                m.Statements.Insert(i, assertions[i]);
 
264
                                        }
 
265
                                }
 
266
                        }
 
267
                        return td;
 
268
                }
 
269
                
 
270
                static void AddFieldVisitCode(EasyMethod m, Type type, CodeExpression var, List<CodeStatement> assertions, bool transformer)
 
271
                {
 
272
                        if (type != null) {
 
273
                                if (type.BaseType != typeof(StatementWithEmbeddedStatement)) {
 
274
                                        AddFieldVisitCode(m, type.BaseType, var, assertions, transformer);
 
275
                                }
 
276
                                foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)) {
 
277
                                        AddVisitCode(m, field, var, assertions, transformer);
 
278
                                }
 
279
                                if (type.BaseType == typeof(StatementWithEmbeddedStatement)) {
 
280
                                        AddFieldVisitCode(m, type.BaseType, var, assertions, transformer);
 
281
                                }
 
282
                        }
 
283
                }
 
284
                
 
285
                static CodeStatement AssertIsNotNull(CodeExpression expr)
 
286
                {
 
287
                        return new CodeExpressionStatement(
 
288
                                Easy.Type("Debug").InvokeMethod("Assert",
 
289
                                                                Easy.Binary(expr,
 
290
                                                                            CodeBinaryOperatorType.IdentityInequality,
 
291
                                                                            Easy.Null))
 
292
                        );
 
293
                }
 
294
                
 
295
                static string GetCode(CodeExpression ex)
 
296
                {
 
297
                        using (StringWriter writer = new StringWriter()) {
 
298
                                new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromExpression(ex, writer, null);
 
299
                                return writer.ToString();
 
300
                        }
 
301
                }
 
302
                
 
303
                static string CreateTransformerLoop(string collection, string typeName)
 
304
                {
 
305
                        return
 
306
                                "\t\t\tfor (int i = 0; i < " + collection + ".Count; i++) {\n" +
 
307
                                "\t\t\t\t" + typeName + " o = " + collection + "[i];\n" +
 
308
                                "\t\t\t\tDebug.Assert(o != null);\n" +
 
309
                                "\t\t\t\tnodeStack.Push(o);\n" +
 
310
                                "\t\t\t\to.AcceptVisitor(this, data);\n" +
 
311
                                (typeName == "INode"
 
312
                                 ? "\t\t\t\to = nodeStack.Pop();\n"
 
313
                                 : "\t\t\t\to = (" + typeName + ")nodeStack.Pop();\n") +
 
314
                                "\t\t\t\tif (o == null)\n" +
 
315
                                "\t\t\t\t\t" + collection + ".RemoveAt(i--);\n" +
 
316
                                "\t\t\t\telse\n" +
 
317
                                "\t\t\t\t\t" + collection + "[i] = o;\n" +
 
318
                                "\t\t\t}";
 
319
                }
 
320
                
 
321
                static bool AddVisitCode(EasyMethod m, FieldInfo field, CodeExpression var, List<CodeStatement> assertions, bool transformer)
 
322
                {
 
323
                        CodeExpression prop = var.Property(GetPropertyName(field.Name));
 
324
                        CodeExpression nodeStack = Easy.Var("nodeStack");
 
325
                        if (field.FieldType.FullName.StartsWith("System.Collections.Generic.List")) {
 
326
                                Type elType = field.FieldType.GetGenericArguments()[0];
 
327
                                if (!typeof(INode).IsAssignableFrom(elType))
 
328
                                        return false;
 
329
                                assertions.Add(AssertIsNotNull(prop));
 
330
                                string code;
 
331
                                if (transformer) {
 
332
                                        code = CreateTransformerLoop(GetCode(prop), ConvertType(elType).BaseType);
 
333
                                } else {
 
334
                                        code =
 
335
                                                "\t\t\tforeach (" + ConvertType(elType).BaseType + " o in " + GetCode(prop) + ") {\n" +
 
336
                                                "\t\t\t\tDebug.Assert(o != null);\n" +
 
337
                                                "\t\t\t\to.AcceptVisitor(this, data);\n" +
 
338
                                                "\t\t\t}";
 
339
                                }
 
340
                                m.Statements.Add(new CodeSnippetStatement(code));
 
341
                                return true;
 
342
                        }
 
343
                        if (!typeof(INode).IsAssignableFrom(field.FieldType))
 
344
                                return false;
 
345
                        assertions.Add(AssertIsNotNull(prop));
 
346
                        if (transformer) {
 
347
                                m.Statements.Add(nodeStack.InvokeMethod("Push", prop));
 
348
                        }
 
349
                        m.Statements.Add(prop.InvokeMethod("AcceptVisitor",
 
350
                                                           Easy.This,
 
351
                                                           Easy.Var("data")));
 
352
                        if (transformer) {
 
353
                                m.Body.Assign(prop, nodeStack.InvokeMethod("Pop").CastTo(ConvertType(field.FieldType)));
 
354
                        }
 
355
                        return true;
 
356
                }
 
357
                
 
358
                static CodeExpression CreateToString(Type type)
 
359
                {
 
360
                        CodeMethodInvokeExpression ie = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(typeof(string)),
 
361
                                                                                       "Format");
 
362
                        CodePrimitiveExpression prim = new CodePrimitiveExpression();
 
363
                        ie.Parameters.Add(prim);
 
364
                        string text = "[" + type.Name;
 
365
                        int index = 0;
 
366
                        do {
 
367
                                foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)) {
 
368
                                        text += " " + GetPropertyName(field.Name) + "={" + index.ToString() + "}";
 
369
                                        index++;
 
370
                                        if (typeof(System.Collections.ICollection).IsAssignableFrom(field.FieldType)) {
 
371
                                                ie.Parameters.Add(new CodeSnippetExpression("GetCollectionString(" + GetPropertyName(field.Name) + ")"));
 
372
                                        } else {
 
373
                                                ie.Parameters.Add(new CodeVariableReferenceExpression(GetPropertyName(field.Name)));
 
374
                                        }
 
375
                                }
 
376
                                type = type.BaseType;
 
377
                        } while (type != null);
 
378
                        prim.Value = text + "]";
 
379
                        if (ie.Parameters.Count == 1)
 
380
                                return prim;
 
381
                        else
 
382
                                return ie;
 
383
                        //      return String.Format("[AnonymousMethodExpression: Parameters={0} Body={1}]",
 
384
                        //                           GetCollectionString(Parameters),
 
385
                        //                           Body);
 
386
                }
 
387
                
 
388
                static void ProcessType(Type type, CodeTypeDeclaration ctd)
 
389
                {
 
390
                        foreach (FieldInfo field in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic)) {
 
391
                                ctd.AddField(ConvertType(field.FieldType), field.Name).Attributes = 0;
 
392
                        }
 
393
                        foreach (FieldInfo field in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic)) {
 
394
                                EasyProperty p = ctd.AddProperty(ConvertType(field.FieldType), GetPropertyName(field.Name));
 
395
                                p.Getter.Return(Easy.Var(field.Name));
 
396
                                CodeExpression ex;
 
397
                                if (field.FieldType.IsValueType)
 
398
                                        ex = new CodePropertySetValueReferenceExpression();
 
399
                                else
 
400
                                        ex = GetDefaultValue("value", field);
 
401
                                p.Setter.Assign(Easy.Var(field.Name), ex);
 
402
                                if (typeof(INode).IsAssignableFrom(field.FieldType)) {
 
403
                                        if (typeof(INullable).IsAssignableFrom(field.FieldType)) {
 
404
                                                p.SetStatements.Add(new CodeSnippetStatement("\t\t\t\tif (!" +field.Name+".IsNull) "+field.Name+".Parent = this;"));
 
405
                                        } else {
 
406
                                                p.SetStatements.Add(new CodeSnippetStatement("\t\t\t\t"+field.Name+".Parent = this;"));
 
407
                                        }
 
408
                                }
 
409
                        }
 
410
                        foreach (ConstructorInfo ctor in type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
 
411
                                CodeConstructor c = new CodeConstructor();
 
412
                                if (type.IsAbstract)
 
413
                                        c.Attributes = MemberAttributes.Family;
 
414
                                else
 
415
                                        c.Attributes = MemberAttributes.Public;
 
416
                                ctd.Members.Add(c);
 
417
                                ConstructorInfo baseCtor = GetBaseCtor(type);
 
418
                                foreach(ParameterInfo param in ctor.GetParameters()) {
 
419
                                        c.Parameters.Add(new CodeParameterDeclarationExpression(ConvertType(param.ParameterType),
 
420
                                                                                                param.Name));
 
421
                                        if (baseCtor != null && Array.Exists(baseCtor.GetParameters(), delegate(ParameterInfo p) { return param.Name == p.Name; }))
 
422
                                                continue;
 
423
                                        c.Statements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression(GetPropertyName(param.Name)),
 
424
                                                                                 new CodeVariableReferenceExpression(param.Name)));
 
425
                                }
 
426
                                if (baseCtor != null) {
 
427
                                        foreach(ParameterInfo param in baseCtor.GetParameters()) {
 
428
                                                c.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(param.Name));
 
429
                                        }
 
430
                                }
 
431
                                // initialize fields that were not initialized by parameter
 
432
                                foreach (FieldInfo field in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic)) {
 
433
                                        if (field.FieldType.IsValueType && field.FieldType != typeof(Location))
 
434
                                                continue;
 
435
                                        if (Array.Exists(ctor.GetParameters(), delegate(ParameterInfo p) { return field.Name == p.Name; }))
 
436
                                                continue;
 
437
                                        c.Statements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression(field.Name),
 
438
                                                                                 GetDefaultValue(null, field)));
 
439
                                }
 
440
                        }
 
441
                }
 
442
                
 
443
                internal static ConstructorInfo GetBaseCtor(Type type)
 
444
                {
 
445
                        ConstructorInfo[] list = type.BaseType.GetConstructors();
 
446
                        if (list.Length == 0)
 
447
                                return null;
 
448
                        else
 
449
                                return list[0];
 
450
                }
 
451
                
 
452
                internal static CodeExpression GetDefaultValue(string inputVariable, FieldInfo field)
 
453
                {
 
454
                        string code;
 
455
                        // get default value:
 
456
                        if (field.FieldType == typeof(string)) {
 
457
                                code = "\"\"";
 
458
                                if (field.GetCustomAttributes(typeof(QuestionMarkDefaultAttribute), false).Length > 0) {
 
459
                                        if (inputVariable == null)
 
460
                                                return new CodePrimitiveExpression("?");
 
461
                                        else
 
462
                                                return new CodeSnippetExpression("string.IsNullOrEmpty(" + inputVariable + ") ? \"?\" : " + inputVariable);
 
463
                                }
 
464
                        } else if (field.FieldType.FullName.StartsWith("System.Collections.Generic.List")) {
 
465
                                code = "new List<" + field.FieldType.GetGenericArguments()[0].Name + ">()";
 
466
                        } else if (field.FieldType == typeof(Location)) {
 
467
                                code = "Location.Empty";
 
468
                        } else {
 
469
                                code = field.FieldType.Name + ".Null";
 
470
                        }
 
471
                        if (inputVariable != null) {
 
472
                                code = inputVariable + " ?? " + code;
 
473
                        }
 
474
                        return new CodeSnippetExpression(code);
 
475
                }
 
476
                
 
477
                internal static string GetFieldName(string typeName)
 
478
                {
 
479
                        return char.ToLower(typeName[0]) + typeName.Substring(1);
 
480
                }
 
481
                
 
482
                internal static string GetPropertyName(string fieldName)
 
483
                {
 
484
                        return char.ToUpper(fieldName[0]) + fieldName.Substring(1);
 
485
                }
 
486
                
 
487
                internal static CodeTypeReference ConvertType(Type type)
 
488
                {
 
489
                        if (type.IsGenericType && !type.IsGenericTypeDefinition) {
 
490
                                CodeTypeReference tr = ConvertType(type.GetGenericTypeDefinition());
 
491
                                foreach (Type subType in type.GetGenericArguments()) {
 
492
                                        tr.TypeArguments.Add(ConvertType(subType));
 
493
                                }
 
494
                                return tr;
 
495
                        } else if (type.FullName.StartsWith("NRefactory") || type.FullName.StartsWith("System.Collections")) {
 
496
                                if (type.Name == "Attribute")
 
497
                                        return new CodeTypeReference("ICSharpCode.NRefactory.Ast.Attribute");
 
498
                                return new CodeTypeReference(type.Name);
 
499
                        } else {
 
500
                                return new CodeTypeReference(type);
 
501
                        }
 
502
                }
 
503
                
 
504
                static CodeTypeDeclaration CreateNodeTrackingAstVisitorClass(List<Type> nodeTypes)
 
505
                {
 
506
                        CodeTypeDeclaration td = new CodeTypeDeclaration("NodeTrackingAstVisitor");
 
507
                        td.TypeAttributes = TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Abstract;
 
508
                        td.BaseTypes.Add(new CodeTypeReference("AbstractAstVisitor"));
 
509
                        
 
510
                        string comment = "<summary>\n " +
 
511
                                "The NodeTrackingAstVisitor will iterate through the whole AST,\n " +
 
512
                                "just like the AbstractAstVisitor, and calls the virtual methods\n " +
 
513
                                "BeginVisit and EndVisit for each node being visited.\n " +
 
514
                                "</summary>";
 
515
                        td.Comments.Add(new CodeCommentStatement(comment, true));
 
516
                        comment = "<remarks>\n " +
 
517
                                "base.Visit(node, data) calls this.TrackedVisit(node, data), so if\n " +
 
518
                                "you want to visit child nodes using the default visiting behaviour,\n " +
 
519
                                "use base.TrackedVisit(parentNode, data).\n " +
 
520
                                "</remarks>";
 
521
                        td.Comments.Add(new CodeCommentStatement(comment, true));
 
522
                        
 
523
                        EasyMethod m = td.AddMethod("BeginVisit");
 
524
                        m.Attributes = MemberAttributes.Family;
 
525
                        m.AddParameter(Easy.TypeRef("INode"), "node");
 
526
                        
 
527
                        m = td.AddMethod("EndVisit");
 
528
                        m.Attributes = MemberAttributes.Family;
 
529
                        m.AddParameter(Easy.TypeRef("INode"), "node");
 
530
                        
 
531
                        foreach (Type type in nodeTypes) {
 
532
                                if (!type.IsAbstract) {
 
533
                                        
 
534
                                        m = td.AddMethod(typeof(object), VisitPrefix + type.Name);
 
535
                                        m.Attributes = MemberAttributes.Public | MemberAttributes.Override;
 
536
                                        m.AddParameter(ConvertType(type), GetFieldName(type.Name));
 
537
                                        m.AddParameter(new CodeTypeReference(typeof(object)), "data");
 
538
                                        
 
539
                                        CodeExpression var = Easy.Var(GetFieldName(type.Name));
 
540
                                        
 
541
                                        m.Body.InvokeMethod(Easy.This, "BeginVisit", var);
 
542
                                        m.Body.DeclareVariable(typeof(object), "result").InitExpression
 
543
                                                = Easy.This.InvokeMethod("TrackedVisit" + type.Name, var, Easy.Var("data"));
 
544
                                        m.Body.InvokeMethod(Easy.This, "EndVisit", var);
 
545
                                        m.Body.Return(Easy.Var("result"));
 
546
                                }
 
547
                        }
 
548
                        
 
549
                        foreach (Type type in nodeTypes) {
 
550
                                if (!type.IsAbstract) {
 
551
                                        
 
552
                                        m = td.AddMethod(typeof(object), "TrackedVisit" + type.Name);
 
553
                                        m.Attributes = MemberAttributes.Public;
 
554
                                        m.AddParameter(ConvertType(type), GetFieldName(type.Name));
 
555
                                        m.AddParameter(new CodeTypeReference(typeof(object)), "data");
 
556
                                        
 
557
                                        m.Body.Return(Easy.Base.InvokeMethod(VisitPrefix + type.Name, Easy.Var(GetFieldName(type.Name)), Easy.Var("data")));
 
558
                                }
 
559
                        }
 
560
                        
 
561
                        return td;
 
562
                }
 
563
                
 
564
                static CodeTypeDeclaration CreateNotImplementedAstVisitorClass(List<Type> nodeTypes)
 
565
                {
 
566
                        CodeTypeDeclaration td = new CodeTypeDeclaration("NotImplementedAstVisitor");
 
567
                        td.TypeAttributes = TypeAttributes.Public | TypeAttributes.Class;
 
568
                        td.BaseTypes.Add(new CodeTypeReference("IAstVisitor"));
 
569
                        
 
570
                        string comment = "<summary>\n " +
 
571
                                "IAstVisitor implementation that always throws NotImplementedExceptions.\n " +
 
572
                                "</summary>";
 
573
                        td.Comments.Add(new CodeCommentStatement(comment, true));
 
574
                        
 
575
                        foreach (Type type in nodeTypes) {
 
576
                                if (!type.IsAbstract) {
 
577
                                        
 
578
                                        EasyMethod m = td.AddMethod(typeof(object), VisitPrefix + type.Name);
 
579
                                        m.Attributes = MemberAttributes.Public;
 
580
                                        m.AddParameter(ConvertType(type), GetFieldName(type.Name));
 
581
                                        m.AddParameter(new CodeTypeReference(typeof(object)), "data");
 
582
                                        
 
583
                                        m.Body.Throw(Easy.New(typeof(NotImplementedException), Easy.Prim(type.Name)));
 
584
                                }
 
585
                        }
 
586
                        
 
587
                        return td;
 
588
                }
 
589
        }
 
590
}