protected MemberDeclarationSyntax CreateReplaceChildMethod() { var irecursiveParentType = SyntaxFactory.QualifiedName( SyntaxFactory.IdentifierName(nameof(ImmutableObjectGraph)), SyntaxFactory.GenericName(nameof(IRecursiveParent <IRecursiveType>)) .AddTypeArgumentListArguments(this.applyTo.RecursiveType.TypeSyntax)); var oldSpineParameter = SyntaxFactory.IdentifierName("oldSpine"); var newSpineParameter = SyntaxFactory.IdentifierName("newSpine"); var newChildrenVar = SyntaxFactory.IdentifierName("newChildren"); var newSelfVar = SyntaxFactory.IdentifierName("newSelf"); var lookupTableLazySentinelVar = SyntaxFactory.IdentifierName("lookupTableLazySentinel"); Func <ExpressionSyntax, InvocationExpressionSyntax> callPeek = receiver => SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, receiver, SyntaxFactory.IdentifierName(nameof(ImmutableStack <int> .Peek))), SyntaxFactory.ArgumentList()); Func <ExpressionSyntax, InvocationExpressionSyntax> createDeque = stack => SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.QualifiedName( SyntaxFactory.IdentifierName(nameof(ImmutableObjectGraph)), SyntaxFactory.IdentifierName(nameof(ImmutableObjectGraph.ImmutableDeque))), SyntaxFactory.IdentifierName(nameof(ImmutableDeque.Create))), SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(stack)))); return(SyntaxFactory.MethodDeclaration( irecursiveParentType, nameof(IRecursiveParentWithChildReplacement <IRecursiveType> .ReplaceChild)) .WithExplicitInterfaceSpecifier(SyntaxFactory.ExplicitInterfaceSpecifier(IRecursiveParentWithChildReplacementType)) .AddParameterListParameters( SyntaxFactory.Parameter(oldSpineParameter.Identifier).WithType(Syntax.ImmutableStackOf(this.applyTo.RecursiveType.TypeSyntax)), SyntaxFactory.Parameter(newSpineParameter.Identifier).WithType(Syntax.ImmutableStackOf(this.applyTo.RecursiveType.TypeSyntax))) .WithBody(SyntaxFactory.Block( // var newChildren = this.Children.Replace(oldSpine.Peek(), newSpine.Peek()); SyntaxFactory.LocalDeclarationStatement( SyntaxFactory.VariableDeclaration(varType) .AddVariables(SyntaxFactory.VariableDeclarator(newChildrenVar.Identifier).WithInitializer(SyntaxFactory.EqualsValueClause( SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression( SyntaxKind.SimpleMemberAccessExpression, Syntax.ThisDot(this.applyTo.RecursiveField.NameAsProperty), SyntaxFactory.IdentifierName(nameof(CollectionExtensions.Replace)))) .AddArgumentListArguments( SyntaxFactory.Argument(callPeek(oldSpineParameter)), // oldSpine.Peek() SyntaxFactory.Argument(callPeek(newSpineParameter)) // newSpine.Peek() ))))), // var newSelf = this.With(children: newChildren); SyntaxFactory.LocalDeclarationStatement( SyntaxFactory.VariableDeclaration(varType) .AddVariables(SyntaxFactory.VariableDeclarator(newSelfVar.Identifier).WithInitializer(SyntaxFactory.EqualsValueClause( SyntaxFactory.InvocationExpression(Syntax.ThisDot(WithMethodName)) .AddArgumentListArguments( SyntaxFactory.Argument(SyntaxFactory.NameColon(this.applyTo.RecursiveField.NameAsField), NoneToken, newChildrenVar)))))), // var lookupTableLazySentinel = RecursiveTypeExtensions.LookupTable<TRecursiveType, TRecursiveParent>.LazySentinel; SyntaxFactory.LocalDeclarationStatement( SyntaxFactory.VariableDeclaration(varType) .AddVariables(SyntaxFactory.VariableDeclarator(lookupTableLazySentinelVar.Identifier).WithInitializer(SyntaxFactory.EqualsValueClause( GetLookupTableHelperMember(nameof(LookupTableHelper.LazySentinel)))))), // if (newSelf.lookupTable == lookupTableLazySentinel && this.lookupTable != null && this.lookupTable != lookupTableLazySentinel) { SyntaxFactory.IfStatement( new ExpressionSyntax[] { // newSelf.lookupTable == lookupTableLazySentinel SyntaxFactory.BinaryExpression( SyntaxKind.EqualsExpression, SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, newSelfVar, LookupTableFieldName), lookupTableLazySentinelVar), // this.lookupTable != null SyntaxFactory.BinaryExpression( SyntaxKind.NotEqualsExpression, Syntax.ThisDot(LookupTableFieldName), SyntaxFactory.LiteralExpression(SyntaxKind.NullLiteralExpression)), // this.lookupTable != lookupTableLazySentinel SyntaxFactory.BinaryExpression( SyntaxKind.NotEqualsExpression, Syntax.ThisDot(LookupTableFieldName), lookupTableLazySentinelVar) }.ChainBinaryExpressions(SyntaxKind.LogicalAndExpression), SyntaxFactory.Block( // // Our newly mutated self wants a lookup table. If we already have one we can use it, // // but it needs to be fixed up given the newly rewritten spine through our descendents. // newSelf.lookupTable = RecursiveTypeExtensions.LookupTable<TRecursiveType, TRecursiveParent>.Fixup(this, ImmutableDeque.Create(newSpine), ImmutableDeque.Create(oldSpine)); SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, newSelfVar, LookupTableFieldName), SyntaxFactory.InvocationExpression( GetLookupTableHelperMember(nameof(LookupTableHelper.Fixup))) .AddArgumentListArguments( SyntaxFactory.Argument(SyntaxFactory.ThisExpression()), SyntaxFactory.Argument(createDeque(newSpineParameter)), SyntaxFactory.Argument(createDeque(oldSpineParameter))))), // RecursiveTypeExtensions.LookupTable<TRecursiveType, TRecursiveParent>.ValidateInternalIntegrityDebugOnly(newSelf); SyntaxFactory.ExpressionStatement(SyntaxFactory.InvocationExpression( GetLookupTableHelperMember(nameof(LookupTableHelper.ValidateInternalIntegrityDebugOnly))) .AddArgumentListArguments(SyntaxFactory.Argument(newSelfVar))))), // return newSelf; SyntaxFactory.ReturnStatement(newSelfVar)))); }
protected override void GenerateCore() { if (this.applyTo.IsRecursiveParent) { this.baseTypes.Add(SyntaxFactory.SimpleBaseType(this.IRecursiveParentWithChildReplacementType)); this.innerMembers.Add(this.CreateReplaceChildMethod()); // private readonly uint inefficiencyLoad; var inefficiencyLoadType = SyntaxFactory.PredefinedType(SyntaxFactory.Token(SyntaxKind.UIntKeyword)); this.innerMembers.Add(SyntaxFactory.FieldDeclaration( SyntaxFactory.VariableDeclaration(inefficiencyLoadType) .AddVariables(SyntaxFactory.VariableDeclarator(InefficiencyLoadFieldName.Identifier))) .AddModifiers( SyntaxFactory.Token(SyntaxKind.PrivateKeyword), SyntaxFactory.Token(SyntaxKind.ReadOnlyKeyword))); var interfaceType = SyntaxFactory.QualifiedName( SyntaxFactory.IdentifierName(nameof(ImmutableObjectGraph)), SyntaxFactory.GenericName( SyntaxFactory.Identifier(nameof(IRecursiveParentWithLookupTable <IRecursiveType>)), SyntaxFactory.TypeArgumentList(SyntaxFactory.SingletonSeparatedList <TypeSyntax>(this.applyTo.RecursiveType.TypeSyntax)))); this.baseTypes.Add(SyntaxFactory.SimpleBaseType(interfaceType)); var explicitImplementation = SyntaxFactory.ExplicitInterfaceSpecifier(interfaceType); // uint IRecursiveParentWithLookupTable<TRecursiveType>.InefficiencyLoad { get; } this.innerMembers.Add( SyntaxFactory.PropertyDeclaration(inefficiencyLoadType, nameof(IRecursiveParentWithLookupTable <IRecursiveType> .InefficiencyLoad)) .WithExplicitInterfaceSpecifier(explicitImplementation) .AddAccessorListAccessors(SyntaxFactory.AccessorDeclaration( SyntaxKind.GetAccessorDeclaration, SyntaxFactory.Block(SyntaxFactory.ReturnStatement(Syntax.ThisDot(InefficiencyLoadFieldName)))))); // IReadOnlyCollection<TRecursiveType> IRecursiveParentWithLookupTable<TRecursiveType>.Children { get; } this.innerMembers.Add( SyntaxFactory.PropertyDeclaration( Syntax.IReadOnlyCollectionOf(this.applyTo.RecursiveType.TypeSyntax), nameof(IRecursiveParentWithLookupTable <IRecursiveType> .Children)) .WithExplicitInterfaceSpecifier(explicitImplementation) .AddAccessorListAccessors(SyntaxFactory.AccessorDeclaration( SyntaxKind.GetAccessorDeclaration, SyntaxFactory.Block(SyntaxFactory.ReturnStatement(Syntax.ThisDot(this.applyTo.RecursiveField.NameAsProperty)))))); // ImmutableDictionary<IdentityFieldType, KeyValuePair<TRecursiveType, IdentityFieldType>> IRecursiveParentWithLookupTable<TRecursiveType>.LookupTable { get; } this.innerMembers.Add( SyntaxFactory.PropertyDeclaration( this.lookupTableType, nameof(IRecursiveParentWithLookupTable <IRecursiveType> .LookupTable)) .WithExplicitInterfaceSpecifier(explicitImplementation) .AddAccessorListAccessors(SyntaxFactory.AccessorDeclaration( SyntaxKind.GetAccessorDeclaration, SyntaxFactory.Block(SyntaxFactory.ReturnStatement(Syntax.ThisDot(LookupTablePropertyName)))))); } if (this.applyTo.IsRecursive) { var lookupInitResultVarName = SyntaxFactory.IdentifierName("lookupInitResult"); this.additionalCtorStatements.AddRange(new StatementSyntax[] { // var lookupInitResult = ImmutableObjectGraph.RecursiveTypeExtensions.LookupTable<TRecursiveType, TRecursiveParent>.Initialize(this, lookupTable); SyntaxFactory.LocalDeclarationStatement(SyntaxFactory.VariableDeclaration( varType, SyntaxFactory.SingletonSeparatedList(SyntaxFactory.VariableDeclarator(lookupInitResultVarName.Identifier) .WithInitializer(SyntaxFactory.EqualsValueClause( SyntaxFactory.InvocationExpression( GetLookupTableHelperMember(nameof(LookupTableHelper.Initialize)), SyntaxFactory.ArgumentList(Syntax.JoinSyntaxNodes( SyntaxKind.CommaToken, SyntaxFactory.Argument(SyntaxFactory.ThisExpression()), SyntaxFactory.Argument(LookupTableFieldName))))))))), // this.inefficiencyLoad = lookupInitResult.InefficiencyLoad; SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, Syntax.ThisDot(InefficiencyLoadFieldName), SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, lookupInitResultVarName, SyntaxFactory.IdentifierName(nameof(LookupTableHelper.InitializeLookupResult.InefficiencyLoad))))), // this.lookupTable = lookupInitResult.LookupTable; SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, Syntax.ThisDot(LookupTableFieldName), SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, lookupInitResultVarName, SyntaxFactory.IdentifierName(nameof(LookupTableHelper.InitializeLookupResult.LookupTable))))) }); this.innerMembers.Add(SyntaxFactory.PropertyDeclaration( this.lookupTableType, LookupTablePropertyName.Identifier) .AddModifiers(SyntaxFactory.Token(SyntaxKind.PrivateKeyword)) .AddAccessorListAccessors(SyntaxFactory.AccessorDeclaration( SyntaxKind.GetAccessorDeclaration, SyntaxFactory.Block( SyntaxFactory.IfStatement( SyntaxFactory.BinaryExpression( SyntaxKind.EqualsExpression, Syntax.ThisDot(LookupTableFieldName), GetLookupTableHelperMember(nameof(LookupTableHelper.LazySentinel))), SyntaxFactory.Block( SyntaxFactory.ExpressionStatement( SyntaxFactory.AssignmentExpression( SyntaxKind.SimpleAssignmentExpression, Syntax.ThisDot(LookupTableFieldName), SyntaxFactory.InvocationExpression( GetLookupTableHelperMember(nameof(LookupTableHelper.CreateLookupTable)), SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList( SyntaxFactory.Argument(SyntaxFactory.ThisExpression())))))))), SyntaxFactory.ReturnStatement(Syntax.ThisDot(LookupTableFieldName)))))); // protected System.Collections.Immutable.ImmutableDictionary<System.UInt32, KeyValuePair<FileSystemEntry, System.UInt32>> lookupTable; this.innerMembers.Add(SyntaxFactory.FieldDeclaration( SyntaxFactory.VariableDeclaration(this.lookupTableType) .AddVariables(SyntaxFactory.VariableDeclarator(LookupTableFieldName.Identifier))) .AddModifiers( SyntaxFactory.Token(SyntaxKind.ProtectedKeyword))); // public System.Collections.Immutable.ImmutableStack<TRecursiveType> GetSpine(TRecursiveType descendent) { // return this.GetSpine<TRecursiveParent, TRecursiveType>(descendent); // } var descendentParameter = SyntaxFactory.IdentifierName("descendent"); this.innerMembers.Add( SyntaxFactory.MethodDeclaration(Syntax.ImmutableStackOf(this.applyTo.RecursiveType.TypeSyntax), GetSpineMethodName.Identifier) .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters(SyntaxFactory.Parameter(descendentParameter.Identifier).WithType(this.applyTo.RecursiveType.TypeSyntax)) .WithBody(SyntaxFactory.Block( SyntaxFactory.ReturnStatement( SyntaxFactory.InvocationExpression( Syntax.ThisDot( SyntaxFactory.GenericName(nameof(RecursiveTypeExtensions.GetSpine)) .AddTypeArgumentListArguments(this.applyTo.RecursiveParent.TypeSyntax, this.applyTo.RecursiveType.TypeSyntax)), SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(descendentParameter)))))))); // public System.Collections.Immutable.ImmutableStack<TRecursiveType> GetSpine(uint identity) { // return this.GetSpine<TRecursiveParent, TRecursiveType>(identity); // } var identityParameter = SyntaxFactory.IdentifierName("identity"); this.innerMembers.Add( SyntaxFactory.MethodDeclaration(Syntax.ImmutableStackOf(this.applyTo.RecursiveType.TypeSyntax), GetSpineMethodName.Identifier) .AddModifiers(SyntaxFactory.Token(SyntaxKind.PublicKeyword)) .AddParameterListParameters(SyntaxFactory.Parameter(identityParameter.Identifier).WithType(IdentityFieldTypeSyntax)) .WithBody(SyntaxFactory.Block( SyntaxFactory.ReturnStatement( SyntaxFactory.InvocationExpression( Syntax.ThisDot( SyntaxFactory.GenericName(nameof(RecursiveTypeExtensions.GetSpine)) .AddTypeArgumentListArguments(this.applyTo.RecursiveParent.TypeSyntax, this.applyTo.RecursiveType.TypeSyntax)), SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(identityParameter)))))))); this.innerMembers.Add(this.CreateFindMethod()); } }