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" + 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 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; }