.NET Decompiler with support for PDB generation, ReadyToRun, Metadata (&more) - cross-platform!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

591 lines
24 KiB

// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.Collections.Generic;
using System.CodeDom;
using System.Diagnostics;
using System.Reflection;
using System.IO;
using VBAstGenerator.Ast;
using ICSharpCode.EasyCodeDom;
namespace VBAstGenerator
{
class MainClass
{
public const string VisitPrefix = "Visit";
static readonly string[] lineEndings = { "\r\n", "\r", "\n" };
public static void Main(string[] args)
{
string directory = "../../../ICSharpCode.NRefactory.VB/Ast/";
string visitorsDir = "../../../ICSharpCode.NRefactory.VB/Visitors/";
Debug.WriteLine("AST Generator running...");
if (!File.Exists(directory + "INode.cs")) {
Debug.WriteLine("did not find output directory");
return;
}
if (!File.Exists(visitorsDir + "AbstractAstTransformer.cs")) {
Debug.WriteLine("did not find visitor output directory");
return;
}
List<Type> nodeTypes = new List<Type>();
foreach (Type type in typeof(MainClass).Assembly.GetTypes()) {
if (type.IsClass && typeof(INode).IsAssignableFrom(type)) {
nodeTypes.Add(type);
}
}
nodeTypes.Sort(delegate(Type a, Type b) { return a.Name.CompareTo(b.Name); });
CodeCompileUnit ccu = new CodeCompileUnit();
CodeNamespace cns = ccu.AddNamespace("ICSharpCode.NRefactory.VB.Ast");
cns.AddImport("System");
cns.AddImport("System.Collections.Generic");
foreach (Type type in nodeTypes) {
if (type.GetCustomAttributes(typeof(CustomImplementationAttribute), false).Length == 0) {
CodeTypeDeclaration ctd = cns.AddType(type.Name);
if (type.IsAbstract) {
ctd.TypeAttributes |= TypeAttributes.Abstract;
}
ctd.BaseTypes.Add(new CodeTypeReference(type.BaseType.Name));
ProcessType(type, ctd);
foreach (object o in type.GetCustomAttributes(false)) {
if (o is TypeImplementationModifierAttribute) {
(o as TypeImplementationModifierAttribute).ModifyImplementation(cns, ctd, type);
}
}
if (!type.IsAbstract) {
CodeMemberMethod method = new CodeMemberMethod();
method.Name = "AcceptVisitor";
method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
method.Parameters.Add(new CodeParameterDeclarationExpression("IAstVisitor", "visitor"));
method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(object), "data"));
method.ReturnType = new CodeTypeReference(typeof(object));
CodeExpression ex = new CodeVariableReferenceExpression("visitor");
ex = new CodeMethodInvokeExpression(ex, VisitPrefix + ctd.Name,
new CodeThisReferenceExpression(),
new CodeVariableReferenceExpression("data"));
method.Statements.Add(new CodeMethodReturnStatement(ex));
ctd.Members.Add(method);
method = new CodeMemberMethod();
method.Name = "ToString";
method.Attributes = MemberAttributes.Public | MemberAttributes.Override;
method.ReturnType = new CodeTypeReference(typeof(string));
method.Statements.Add(new CodeMethodReturnStatement(CreateToString(type)));
ctd.Members.Add(method);
}
}
}
System.CodeDom.Compiler.CodeGeneratorOptions settings = new System.CodeDom.Compiler.CodeGeneratorOptions();
settings.IndentString = "\t";
settings.VerbatimOrder = true;
using (StringWriter writer = new StringWriter()) {
new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromCompileUnit(ccu, writer, settings);
File.WriteAllText(directory + "Generated.cs", NormalizeNewLines(writer));
}
ccu = new CodeCompileUnit();
cns = ccu.AddNamespace("ICSharpCode.NRefactory.VB");
cns.AddImport("System");
cns.AddImport("ICSharpCode.NRefactory.VB.Ast");
cns.Types.Add(CreateAstVisitorInterface(nodeTypes));
using (StringWriter writer = new StringWriter()) {
new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromCompileUnit(ccu, writer, settings);
File.WriteAllText(visitorsDir + "../IAstVisitor.cs", NormalizeNewLines(writer));
}
ccu = new CodeCompileUnit();
cns = ccu.AddNamespace("ICSharpCode.NRefactory.VB.Visitors");
cns.AddImport("System");
cns.AddImport("System.Collections.Generic");
cns.AddImport("System.Diagnostics");
cns.AddImport("ICSharpCode.NRefactory.VB.Ast");
cns.Types.Add(CreateAstVisitorClass(nodeTypes, false));
using (StringWriter writer = new StringWriter()) {
new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromCompileUnit(ccu, writer, settings);
File.WriteAllText(visitorsDir + "AbstractAstVisitor.cs", NormalizeNewLines(writer));
}
ccu = new CodeCompileUnit();
cns = ccu.AddNamespace("ICSharpCode.NRefactory.VB.Visitors");
cns.AddImport("System");
cns.AddImport("System.Collections.Generic");
cns.AddImport("System.Diagnostics");
cns.AddImport("ICSharpCode.NRefactory.VB.Ast");
cns.Types.Add(CreateAstVisitorClass(nodeTypes, true));
using (StringWriter writer = new StringWriter()) {
new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromCompileUnit(ccu, writer, settings);
File.WriteAllText(visitorsDir + "AbstractAstTransformer.cs", NormalizeNewLines(writer));
}
ccu = new CodeCompileUnit();
cns = ccu.AddNamespace("ICSharpCode.NRefactory.VB.Visitors");
cns.AddImport("System");
cns.AddImport("ICSharpCode.NRefactory.VB.Ast");
cns.Types.Add(CreateNodeTrackingAstVisitorClass(nodeTypes));
using (StringWriter writer = new StringWriter()) {
new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromCompileUnit(ccu, writer, settings);
// CodeDom cannot output "sealed", so we need to use this hack:
File.WriteAllText(visitorsDir + "NodeTrackingAstVisitor.cs",
NormalizeNewLines(writer).Replace("public override object", "public sealed override object"));
}
//NotImplementedAstVisitor
ccu = new CodeCompileUnit();
cns = ccu.AddNamespace("ICSharpCode.NRefactory.VB.Visitors");
cns.AddImport("System");
cns.AddImport("ICSharpCode.NRefactory.VB.Ast");
cns.Types.Add(CreateNotImplementedAstVisitorClass(nodeTypes));
using (StringWriter writer = new StringWriter()) {
new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromCompileUnit(ccu, writer, settings);
File.WriteAllText(visitorsDir + "NotImplementedAstVisitor.cs", NormalizeNewLines(writer));
}
Debug.WriteLine("DOM Generator done!");
Debug.WriteLine("start keyword list generation...");
KeywordGenerator.Generate();
Debug.WriteLine("keyword list generation done!");
}
static string NormalizeNewLines(StringWriter writer)
{
return string.Join(Environment.NewLine, writer.ToString().Split(lineEndings, StringSplitOptions.None));
}
static CodeTypeDeclaration CreateAstVisitorInterface(List<Type> nodeTypes)
{
CodeTypeDeclaration td = new CodeTypeDeclaration("IAstVisitor");
td.IsInterface = true;
foreach (Type t in nodeTypes) {
if (!t.IsAbstract) {
EasyMethod m = td.AddMethod(typeof(object), VisitPrefix + t.Name);
m.AddParameter(ConvertType(t), GetFieldName(t.Name));
m.AddParameter(typeof(object), "data");
}
}
return td;
}
static CodeTypeDeclaration CreateAstVisitorClass(List<Type> nodeTypes, bool transformer)
{
CodeTypeDeclaration td = new CodeTypeDeclaration(transformer ? "AbstractAstTransformer" : "AbstractAstVisitor");
td.TypeAttributes = TypeAttributes.Public | TypeAttributes.Abstract;
td.BaseTypes.Add(new CodeTypeReference("IAstVisitor"));
if (transformer) {
string comment =
"The AbstractAstTransformer will iterate through the whole Ast,\n " +
"just like the AbstractAstVisitor. However, the AbstractAstTransformer allows\n " +
"you to modify the Ast at the same time: It does not use 'foreach' internally,\n " +
"so you can add members to collections of parents of the current node (but\n " +
"you cannot insert or delete items as that will make the index used invalid).\n " +
"You can use the methods ReplaceCurrentNode and RemoveCurrentNode to replace\n " +
"or remove the current node, totally independent from the type of the parent node.";
Easy.AddSummary(td, comment);
CodeMemberField field = td.AddField(Easy.TypeRef("Stack", "INode"), "nodeStack");
field.InitExpression = Easy.New(field.Type);
/*
CodeExpression nodeStack = Easy.Var("nodeStack");
CodeMemberProperty p = new CodeMemberProperty();
p.Name = "CurrentNode";
p.Type = new CodeTypeReference("INode");
p.Attributes = MemberAttributes.Public | MemberAttributes.Final;
p.GetStatements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("currentNode")));
p.SetStatements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression("currentNode"),
new CodePropertySetValueReferenceExpression()));
td.Members.Add(p);
*/
EasyMethod m = td.AddMethod("ReplaceCurrentNode");
m.AddParameter(Easy.TypeRef("INode"), "newNode");
m.Statements.Add(Easy.Var("nodeStack").InvokeMethod("Pop"));
m.Statements.Add(Easy.Var("nodeStack").InvokeMethod("Push", Easy.Var("newNode")));
m = td.AddMethod("RemoveCurrentNode");
m.Statements.Add(Easy.Var("nodeStack").InvokeMethod("Pop"));
m.Statements.Add(Easy.Var("nodeStack").InvokeMethod("Push", Easy.Null));
}
foreach (Type type in nodeTypes) {
if (!type.IsAbstract) {
EasyMethod m = td.AddMethod(typeof(object), VisitPrefix + type.Name);
m.Attributes = MemberAttributes.Public;
m.AddParameter(ConvertType(type), GetFieldName(type.Name));
m.AddParameter(typeof(object), "data");
List<CodeStatement> assertions = new List<CodeStatement>();
string varVariableName = GetFieldName(type.Name);
CodeExpression var = Easy.Var(varVariableName);
assertions.Add(AssertIsNotNull(var));
AddFieldVisitCode(m, type, var, assertions, transformer);
if (type.GetCustomAttributes(typeof(HasChildrenAttribute), true).Length > 0) {
if (transformer) {
m.Statements.Add(new CodeSnippetStatement(CreateTransformerLoop(varVariableName + ".Children", "INode")));
m.Body.Return(Easy.Null);
} else {
m.Body.Return(var.InvokeMethod("AcceptChildren", Easy.This, Easy.Var("data")));
}
} else {
CodeExpressionStatement lastStatement = null;
if (m.Statements.Count > 0) {
lastStatement = m.Statements[m.Statements.Count - 1] as CodeExpressionStatement;
}
if (lastStatement != null) {
m.Statements.RemoveAt(m.Statements.Count - 1);
m.Body.Return(lastStatement.Expression);
} else {
m.Body.Return(Easy.Null);
}
}
for (int i = 0; i < assertions.Count; i++) {
m.Statements.Insert(i, assertions[i]);
}
}
}
return td;
}
static void AddFieldVisitCode(EasyMethod m, Type type, CodeExpression var, List<CodeStatement> assertions, bool transformer)
{
if (type != null) {
if (type.BaseType != typeof(StatementWithEmbeddedStatement)) {
AddFieldVisitCode(m, type.BaseType, var, assertions, transformer);
}
foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)) {
AddVisitCode(m, field, var, assertions, transformer);
}
if (type.BaseType == typeof(StatementWithEmbeddedStatement)) {
AddFieldVisitCode(m, type.BaseType, var, assertions, transformer);
}
}
}
static CodeStatement AssertIsNotNull(CodeExpression expr)
{
return new CodeExpressionStatement(
Easy.Type("Debug").InvokeMethod("Assert",
Easy.Binary(expr,
CodeBinaryOperatorType.IdentityInequality,
Easy.Null))
);
}
static string GetCode(CodeExpression ex)
{
using (StringWriter writer = new StringWriter()) {
new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromExpression(ex, writer, null);
return writer.ToString();
}
}
static string CreateTransformerLoop(string collection, string typeName)
{
return
"\t\t\tfor (int i = 0; i < " + collection + ".Count; i++) {\n" +
"\t\t\t\t" + typeName + " o = " + collection + "[i];\n" +
"\t\t\t\tDebug.Assert(o != null);\n" +
"\t\t\t\tnodeStack.Push(o);\n" +
"\t\t\t\to.AcceptVisitor(this, data);\n" +
(typeName == "INode"
? "\t\t\t\to = nodeStack.Pop();\n"
: "\t\t\t\to = (" + typeName + ")nodeStack.Pop();\n") +
"\t\t\t\tif (o == null)\n" +
"\t\t\t\t\t" + collection + ".RemoveAt(i--);\n" +
"\t\t\t\telse\n" +
"\t\t\t\t\t" + collection + "[i] = o;\n" +
"\t\t\t}";
}
static bool AddVisitCode(EasyMethod m, FieldInfo field, CodeExpression var, List<CodeStatement> assertions, bool transformer)
{
CodeExpression prop = var.Property(GetPropertyName(field.Name));
CodeExpression nodeStack = Easy.Var("nodeStack");
if (field.FieldType.FullName.StartsWith("System.Collections.Generic.List")) {
Type elType = field.FieldType.GetGenericArguments()[0];
if (!typeof(INode).IsAssignableFrom(elType))
return false;
assertions.Add(AssertIsNotNull(prop));
string code;
if (transformer) {
code = CreateTransformerLoop(GetCode(prop), ConvertType(elType).BaseType);
} else {
code =
"\t\t\tforeach (" + ConvertType(elType).BaseType + " o in " + GetCode(prop) + ") {\n" +
"\t\t\t\tDebug.Assert(o != null);\n" +
"\t\t\t\to.AcceptVisitor(this, data);\n" +
"\t\t\t}";
}
m.Statements.Add(new CodeSnippetStatement(code));
return true;
}
if (!typeof(INode).IsAssignableFrom(field.FieldType))
return false;
assertions.Add(AssertIsNotNull(prop));
if (transformer) {
m.Statements.Add(nodeStack.InvokeMethod("Push", prop));
}
m.Statements.Add(prop.InvokeMethod("AcceptVisitor",
Easy.This,
Easy.Var("data")));
if (transformer) {
m.Body.Assign(prop, nodeStack.InvokeMethod("Pop").CastTo(ConvertType(field.FieldType)));
}
return true;
}
static CodeExpression CreateToString(Type type)
{
CodeMethodInvokeExpression ie = new CodeMethodInvokeExpression(new CodeTypeReferenceExpression(typeof(string)),
"Format");
CodePrimitiveExpression prim = new CodePrimitiveExpression();
ie.Parameters.Add(prim);
string text = "[" + type.Name;
int index = 0;
do {
foreach (FieldInfo field in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic)) {
text += " " + GetPropertyName(field.Name) + "={" + index.ToString() + "}";
index++;
if (typeof(System.Collections.ICollection).IsAssignableFrom(field.FieldType)) {
ie.Parameters.Add(new CodeSnippetExpression("GetCollectionString(" + GetPropertyName(field.Name) + ")"));
} else {
ie.Parameters.Add(new CodeVariableReferenceExpression(GetPropertyName(field.Name)));
}
}
type = type.BaseType;
} while (type != null);
prim.Value = text + "]";
if (ie.Parameters.Count == 1)
return prim;
else
return ie;
// return String.Format("[AnonymousMethodExpression: Parameters={0} Body={1}]",
// GetCollectionString(Parameters),
// Body);
}
static void ProcessType(Type type, CodeTypeDeclaration ctd)
{
foreach (FieldInfo field in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic)) {
ctd.AddField(ConvertType(field.FieldType), field.Name).Attributes = 0;
}
foreach (FieldInfo field in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic)) {
EasyProperty p = ctd.AddProperty(ConvertType(field.FieldType), GetPropertyName(field.Name));
p.Getter.Return(Easy.Var(field.Name));
CodeExpression ex;
if (field.FieldType.IsValueType)
ex = new CodePropertySetValueReferenceExpression();
else
ex = GetDefaultValue("value", field);
p.Setter.Assign(Easy.Var(field.Name), ex);
if (typeof(INode).IsAssignableFrom(field.FieldType)) {
if (typeof(INullable).IsAssignableFrom(field.FieldType)) {
p.SetStatements.Add(new CodeSnippetStatement("\t\t\t\tif (!" +field.Name+".IsNull) "+field.Name+".Parent = this;"));
} else {
p.SetStatements.Add(new CodeSnippetStatement("\t\t\t\t"+field.Name+".Parent = this;"));
}
}
}
foreach (ConstructorInfo ctor in type.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)) {
CodeConstructor c = new CodeConstructor();
if (type.IsAbstract)
c.Attributes = MemberAttributes.Family;
else
c.Attributes = MemberAttributes.Public;
ctd.Members.Add(c);
ConstructorInfo baseCtor = GetBaseCtor(type);
foreach(ParameterInfo param in ctor.GetParameters()) {
c.Parameters.Add(new CodeParameterDeclarationExpression(ConvertType(param.ParameterType),
param.Name));
if (baseCtor != null && Array.Exists(baseCtor.GetParameters(), delegate(ParameterInfo p) { return param.Name == p.Name; }))
continue;
c.Statements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression(GetPropertyName(param.Name)),
new CodeVariableReferenceExpression(param.Name)));
}
if (baseCtor != null) {
foreach(ParameterInfo param in baseCtor.GetParameters()) {
c.BaseConstructorArgs.Add(new CodeVariableReferenceExpression(param.Name));
}
}
// initialize fields that were not initialized by parameter
foreach (FieldInfo field in type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic)) {
if (field.FieldType.IsValueType && field.FieldType != typeof(Location))
continue;
if (Array.Exists(ctor.GetParameters(), delegate(ParameterInfo p) { return field.Name == p.Name; }))
continue;
c.Statements.Add(new CodeAssignStatement(new CodeVariableReferenceExpression(field.Name),
GetDefaultValue(null, field)));
}
}
}
internal static ConstructorInfo GetBaseCtor(Type type)
{
ConstructorInfo[] list = type.BaseType.GetConstructors();
if (list.Length == 0)
return null;
else
return list[0];
}
internal static CodeExpression GetDefaultValue(string inputVariable, FieldInfo field)
{
string code;
// get default value:
if (field.FieldType == typeof(string)) {
code = "\"\"";
if (field.GetCustomAttributes(typeof(QuestionMarkDefaultAttribute), false).Length > 0) {
if (inputVariable == null)
return new CodePrimitiveExpression("?");
else
return new CodeSnippetExpression("string.IsNullOrEmpty(" + inputVariable + ") ? \"?\" : " + inputVariable);
}
} else if (field.FieldType.FullName.StartsWith("System.Collections.Generic.List")) {
code = "new List<" + field.FieldType.GetGenericArguments()[0].Name + ">()";
} else if (field.FieldType == typeof(Location)) {
code = "Location.Empty";
} else {
code = field.FieldType.Name + ".Null";
}
if (inputVariable != null) {
code = inputVariable + " ?? " + code;
}
return new CodeSnippetExpression(code);
}
internal static string GetFieldName(string typeName)
{
return char.ToLower(typeName[0]) + typeName.Substring(1);
}
internal static string GetPropertyName(string fieldName)
{
return char.ToUpper(fieldName[0]) + fieldName.Substring(1);
}
internal static CodeTypeReference ConvertType(Type type)
{
if (type.IsGenericType && !type.IsGenericTypeDefinition) {
CodeTypeReference tr = ConvertType(type.GetGenericTypeDefinition());
foreach (Type subType in type.GetGenericArguments()) {
tr.TypeArguments.Add(ConvertType(subType));
}
return tr;
} else if (type.FullName.StartsWith("VBAst") || type.FullName.StartsWith("System.Collections")) {
if (type.Name == "Attribute")
return new CodeTypeReference("ICSharpCode.NRefactory.VB.Ast.Attribute");
return new CodeTypeReference(type.Name);
} else {
return new CodeTypeReference(type);
}
}
static CodeTypeDeclaration CreateNodeTrackingAstVisitorClass(List<Type> nodeTypes)
{
CodeTypeDeclaration td = new CodeTypeDeclaration("NodeTrackingAstVisitor");
td.TypeAttributes = TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Abstract;
td.BaseTypes.Add(new CodeTypeReference("AbstractAstVisitor"));
string comment = "<summary>\n " +
"The NodeTrackingAstVisitor will iterate through the whole Ast,\n " +
"just like the AbstractAstVisitor, and calls the virtual methods\n " +
"BeginVisit and EndVisit for each node being visited.\n " +
"</summary>";
td.Comments.Add(new CodeCommentStatement(comment, true));
comment = "<remarks>\n " +
"base.Visit(node, data) calls this.TrackedVisit(node, data), so if\n " +
"you want to visit child nodes using the default visiting behaviour,\n " +
"use base.TrackedVisit(parentNode, data).\n " +
"</remarks>";
td.Comments.Add(new CodeCommentStatement(comment, true));
EasyMethod m = td.AddMethod("BeginVisit");
m.Attributes = MemberAttributes.Family;
m.AddParameter(Easy.TypeRef("INode"), "node");
m = td.AddMethod("EndVisit");
m.Attributes = MemberAttributes.Family;
m.AddParameter(Easy.TypeRef("INode"), "node");
foreach (Type type in nodeTypes) {
if (!type.IsAbstract) {
m = td.AddMethod(typeof(object), VisitPrefix + type.Name);
m.Attributes = MemberAttributes.Public | MemberAttributes.Override;
m.AddParameter(ConvertType(type), GetFieldName(type.Name));
m.AddParameter(new CodeTypeReference(typeof(object)), "data");
CodeExpression var = Easy.Var(GetFieldName(type.Name));
m.Body.InvokeMethod(Easy.This, "BeginVisit", var);
m.Body.DeclareVariable(typeof(object), "result").InitExpression
= Easy.This.InvokeMethod("TrackedVisit" + type.Name, var, Easy.Var("data"));
m.Body.InvokeMethod(Easy.This, "EndVisit", var);
m.Body.Return(Easy.Var("result"));
}
}
foreach (Type type in nodeTypes) {
if (!type.IsAbstract) {
m = td.AddMethod(typeof(object), "TrackedVisit" + type.Name);
m.Attributes = MemberAttributes.Public;
m.AddParameter(ConvertType(type), GetFieldName(type.Name));
m.AddParameter(new CodeTypeReference(typeof(object)), "data");
m.Body.Return(Easy.Base.InvokeMethod(VisitPrefix + type.Name, Easy.Var(GetFieldName(type.Name)), Easy.Var("data")));
}
}
return td;
}
static CodeTypeDeclaration CreateNotImplementedAstVisitorClass(List<Type> nodeTypes)
{
CodeTypeDeclaration td = new CodeTypeDeclaration("NotImplementedAstVisitor");
td.TypeAttributes = TypeAttributes.Public | TypeAttributes.Class;
td.BaseTypes.Add(new CodeTypeReference("IAstVisitor"));
string comment = "<summary>\n " +
"IAstVisitor implementation that always throws NotImplementedExceptions.\n " +
"</summary>";
td.Comments.Add(new CodeCommentStatement(comment, true));
foreach (Type type in nodeTypes) {
if (!type.IsAbstract) {
EasyMethod m = td.AddMethod(typeof(object), VisitPrefix + type.Name);
m.Attributes = MemberAttributes.Public;
m.AddParameter(ConvertType(type), GetFieldName(type.Name));
m.AddParameter(new CodeTypeReference(typeof(object)), "data");
m.Body.Throw(Easy.New(typeof(NotImplementedException), Easy.Prim(type.Name)));
}
}
return td;
}
}
}