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))); } } }
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); }