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(IfNullSetFailure(prop)); string code; string propertyName = GetCode(prop); if (transformer) { code = CreateTransformerLoop(propertyName, ConvertType(elType).BaseType); } else { code = "\t\t\tif (" + propertyName + ".Count == data." + GetPropertyName(field.Name) + ".Count) {\n" + "\t\t\tfor (int i=0; i<" + propertyName + ".Count;i++) {\n" + "\t\t\t\t" + ConvertType(elType).BaseType + " o = " + propertyName + "[i];\n" + "\t\t\t\tif(o == null){return SetFailure();}\n" + "\t\t\t\tif((bool)o.AcceptVisitor(this, data." + GetPropertyName(field.Name) + "[i]) == false) return SetFailure();\n" + "\t\t\t}" + "\t\t\t}" + "\t\t\telse { return SetFailure(); }"; } m.Statements.Add(new CodeSnippetStatement(code)); return(true); } if (!typeof(INode).IsAssignableFrom(field.FieldType)) { return(false); } assertions.Add(IfNullSetFailure(prop)); if (transformer) { m.Statements.Add(nodeStack.InvokeMethod("Push", prop)); } m.Statements.Add(prop.InvokeMethod("AcceptVisitor", Easy.This, Easy.Var("data." + var.Property(GetPropertyName(field.Name)).PropertyName))); if (transformer) { m.Body.Assign(prop, nodeStack.InvokeMethod("Pop").CastTo(ConvertType(field.FieldType))); } return(true); }
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 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 CodeTypeDeclaration CreateAstComparisonVisitorClass(List <Type> nodeTypes) { CodeTypeDeclaration td = new CodeTypeDeclaration("AstComparisonVisitor"); td.TypeAttributes = TypeAttributes.Public; td.IsPartial = true; //td.BaseTypes.Add(new CodeTypeReference("IAstVisitor")); foreach (Type type in nodeTypes) { if (!type.IsAbstract) { EasyMethod m = td.AddMethod(typeof(bool), VisitPrefix + type.Name); m.Attributes = MemberAttributes.Public; m.AddParameter(ConvertType(type), GetFieldName(type.Name)); const string right_hand_side_name = "d"; m.AddParameter(typeof(object), right_hand_side_name); List <CodeStatement> assertions = new List <CodeStatement>(); string varVariableName = GetFieldName(type.Name); CodeExpression var = Easy.Var(varVariableName); assertions.Add(IfNullSetFailure(var)); if (varVariableName == "using") { varVariableName = "@using"; } CodeExpression r_var = Easy.Var(right_hand_side_name); assertions.Add(IfNullSetFailure(r_var)); // Confirm their types are the same. m.Statements.Add(new CodeSnippetStatement("\t\t\tif(" + varVariableName + ".GetType() != " + right_hand_side_name + ".GetType()) {return SetFailure();}")); // Cast the object parameter to whatever the other parameter is, and call the variable 'data'. // Like so: AddHandlerStatement data = (AddHandlerStatement) d; m.Statements.Add(new CodeSnippetStatement("\t\t\tvar data = (" + ConvertType(type).BaseType + ")d;")); m.Statements.Add(new CodeConditionStatement(new CodeSnippetExpression("!IsMatch(" + varVariableName + ", data)"), new CodeSnippetStatement("\t\t\t\treturn SetFailure();"))); AddFieldVisitCode(m, type, var, assertions, false); if (type.GetCustomAttributes(typeof(HasChildrenAttribute), true).Length > 0) { m.Body.Return(var.InvokeMethod("AcceptChildren", Easy.This, Easy.Var(right_hand_side_name))); } 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(new CodeSnippetExpression("true")); } } for (int i = 0; i < assertions.Count; i++) { m.Statements.Insert(i, assertions[i]); } } } return(td); }