static CodeTypeDeclaration CreateAstVisitorInterface(List <Type> nodeTypes) { EasyTypeDeclaration td = new EasyTypeDeclaration("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 CreateNodeTrackingAstVisitorClass(List <Type> nodeTypes) { EasyTypeDeclaration td = new EasyTypeDeclaration("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.Statements.Add(new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), "BeginVisit"), new CodeExpression[] { var })); // m.Statements.Add(new CodeVariableDeclarationStatement(new CodeTypeReference(typeof(object)), "result", new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), "TrackedVisit"), new CodeExpression[] { var, new CodeVariableReferenceExpression("data") }))); // m.Statements.Add(new CodeMethodInvokeExpression(new CodeMethodReferenceExpression(new CodeThisReferenceExpression(), "EndVisit"), new CodeExpression[] { var })); // m.Statements.Add(new CodeMethodReturnStatement(new CodeVariableReferenceExpression("result"))); m.Body.InvokeMethod(Easy.This, "BeginVisit", var); m.Body.DeclareVariable(typeof(object), "result").InitExpression = Easy.This.InvokeMethod("TrackedVisit", 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"); 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 void ProcessType(Type type, EasyTypeDeclaration 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) && typeof(INullable).IsAssignableFrom(field.FieldType)) { p.SetStatements.Add(new CodeSnippetStatement("\t\t\t\tif (!" + field.Name + ".IsNull) " + field.Name + ".Parent = this;")); } } foreach (ConstructorInfo ctor in type.GetConstructors()) { 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))); } } }
public static void Main(string[] args) { string directory = "../../../Project/Src/Ast/"; string visitorsDir = "../../../Project/Src/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)); }); EasyCompileUnit ccu = new EasyCompileUnit(); EasyNamespace cns = ccu.AddNamespace("ICSharpCode.NRefactory.Ast"); cns.AddImport("System"); cns.AddImport("System.Collections.Generic"); foreach (Type type in nodeTypes) { if (type.GetCustomAttributes(typeof(CustomImplementationAttribute), false).Length == 0) { EasyTypeDeclaration 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", writer.ToString()); } ccu = new EasyCompileUnit(); cns = ccu.AddNamespace("ICSharpCode.NRefactory"); cns.AddImport("System"); cns.AddImport("ICSharpCode.NRefactory.Ast"); cns.Types.Add(CreateAstVisitorInterface(nodeTypes)); using (StringWriter writer = new StringWriter()) { new Microsoft.CSharp.CSharpCodeProvider().GenerateCodeFromCompileUnit(ccu, writer, settings); File.WriteAllText(visitorsDir + "../IAstVisitor.cs", writer.ToString()); } ccu = new EasyCompileUnit(); cns = ccu.AddNamespace("ICSharpCode.NRefactory.Visitors"); cns.AddImport("System"); cns.AddImport("System.Collections.Generic"); cns.AddImport("System.Diagnostics"); cns.AddImport("ICSharpCode.NRefactory.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", writer.ToString()); } ccu = new EasyCompileUnit(); cns = ccu.AddNamespace("ICSharpCode.NRefactory.Visitors"); cns.AddImport("System"); cns.AddImport("System.Collections.Generic"); cns.AddImport("System.Diagnostics"); cns.AddImport("ICSharpCode.NRefactory.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", writer.ToString()); } ccu = new EasyCompileUnit(); cns = ccu.AddNamespace("ICSharpCode.NRefactory.Visitors"); cns.AddImport("System"); cns.AddImport("ICSharpCode.NRefactory.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", writer.ToString().Replace("public override object", "public sealed override object")); } }
static CodeTypeDeclaration CreateAstVisitorClass(List <Type> nodeTypes, bool transformer) { EasyTypeDeclaration td = new EasyTypeDeclaration(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); EasyField 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); EasyExpression 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); }