/// <summary> /// Adds an implementation of the INotifyPropertyChanged interface to the given type. /// </summary> /// <param name="type">The type declaration</param> /// <returns>Type with INotifyPropertyChanged implemented.</returns> protected CodeTypeDeclaration ImplementINotifyPropertyChanged(CodeTypeDeclaration type) { //// This method will implement the INotifyPropertyChanged interface //// Here's an example : //// public class Customer :INotifyPropertyChanged { //// public PropertyChangedEventHandler PropertyChanged; //// public void RaisePropertyChanged(string propertyName) { //// if( this.PropertyChanged !=null ) { //// this.PropertyChanged (this, new PropertyChangedEventArgs( propertyName ) ); //// } //// } //// } CodeThisReferenceExpression thisReference = new CodeThisReferenceExpression(); CodeTypeReference notifyPropertyChanged = Code.TypeRef(typeof(INotifyPropertyChanged)); // Add the implements INotifyPropertyChanged statement // public class Customer :INotifyPropertyChanged { type.BaseTypes.Add(notifyPropertyChanged); // Add the PropertyChanged event as a field to the type // public PropertyChangedEventHandler PropertyChanged; CodeMemberEvent propertyChangedEvent = type.AddEvent(Code.TypeRef(typeof(PropertyChangedEventHandler)), "PropertyChanged"); propertyChangedEvent.ImplementationTypes.Add(notifyPropertyChanged); // this.PropertyChanged CodeEventReferenceExpression eventFieldReference = new CodeEventReferenceExpression(thisReference, "PropertyChanged"); // Add the RaisePropertyChanged Method which will invoke the PropertyChanged handler whenever a property value changes // if( this.PropertyChanged !=null ) CodeConditionStatement invokeEventHandlersIfAny = new CodeConditionStatement(new CodeBinaryOperatorExpression(eventFieldReference, CodeBinaryOperatorType.IdentityInequality, new CodePrimitiveExpression(null))); // this.PropertyChanged (this, new PropertyChangedEventArgs( propertyName ) ); invokeEventHandlersIfAny.TrueStatements.Add( new CodeDelegateInvokeExpression(eventFieldReference, new CodeExpression[] { thisReference, new CodeObjectCreateExpression("PropertyChangedEventArgs", new CodeArgumentReferenceExpression("propertyName")) })); // public void RaisePropertyChanged CodeMemberMethod method = type.AddMethod("RaisePropertyChanged", MemberAttributes.Public); method.Parameters.Add(new CodeParameterDeclarationExpression("System.String", "propertyName")); //// public void RaisePropertyChanged(string propertyName) { //// if( this.PropertyChanged !=null ) { //// this.PropertyChanged (this, new PropertyChangedEventArgs( propertyName ) ); //// } //// } method.Statements.Add(invokeEventHandlersIfAny); return type; }
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; }
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 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 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 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; }