private IAstNode Process_ReadWriteComplex_Copying(ReadWriteComplex op)
		{
			var result = new AstComplexNode();
			LocalBuilder origTempSrc, origTempDst;
			LocalBuilder tempSrc = compilationContext.ilGenerator.DeclareLocal(op.Source.MemberType);
			LocalBuilder tempDst = compilationContext.ilGenerator.DeclareLocal(op.Destination.MemberType);
			origTempSrc = tempSrc;
			origTempDst = tempDst;

			result.nodes.Add(
				new AstWriteLocal(tempSrc, AstBuildHelper.ReadMembersChain(AstBuildHelper.ReadLocalRA(locFrom), op.Source.MembersChain)
				)
			);
			result.nodes.Add(
				new AstWriteLocal(tempDst, AstBuildHelper.ReadMembersChain(AstBuildHelper.ReadLocalRA(locTo), op.Destination.MembersChain))
			);

			var writeNullToDest =
				new List<IAstNode>
                {
                    AstBuildHelper.WriteMembersChain(
                        op.Destination.MembersChain,
                        AstBuildHelper.ReadLocalRA(locTo),
                        GetNullValue(op.NullSubstitutor)
                    )
                };

			// Target construction
			var initDest = new List<IAstNode>();
			var custCtr = op.TargetConstructor;
			if (custCtr != null)
			{
				int custCtrIdx = AddObjectToStore(custCtr);
				initDest.Add(
					new AstWriteLocal(
						tempDst,
						AstBuildHelper.CallMethod(
							custCtr.GetType().GetMethod("Invoke"),
							GetStoredObject(custCtrIdx, custCtr.GetType()),
							null
						)
					)
				);
			}
			else
			{
				initDest.Add(
					new AstWriteLocal(tempDst, new AstNewObject(op.Destination.MemberType, null))
				);
			}

			var copying = new List<IAstNode>();

			// if destination is nullable, create a temp target variable with underlying destination type
			if (ReflectionUtils.IsNullable(op.Source.MemberType))
			{
				tempSrc = compilationContext.ilGenerator.DeclareLocal(Nullable.GetUnderlyingType(op.Source.MemberType));
				copying.Add(
					new AstWriteLocal(
						tempSrc,
						AstBuildHelper.ReadPropertyRV(
							AstBuildHelper.ReadLocalRA(origTempSrc),
							op.Source.MemberType.GetProperty("Value")
						)
					)
				);
			}

			// If destination is null, initialize it.
			if (ReflectionUtils.IsNullable(op.Destination.MemberType) || !op.Destination.MemberType.IsValueType)
			{
				copying.Add(
					new AstIf()
					{
						condition = ReflectionUtils.IsNullable(op.Destination.MemberType)
							? (IAstValue)new AstExprNot((IAstValue)AstBuildHelper.ReadPropertyRV(AstBuildHelper.ReadLocalRA(origTempDst), op.Destination.MemberType.GetProperty("HasValue")))
							: new AstExprIsNull(AstBuildHelper.ReadLocalRV(origTempDst)),
						trueBranch = new AstComplexNode() { nodes = initDest }
					}
				);
				if (ReflectionUtils.IsNullable(op.Destination.MemberType))
				{
					tempDst = compilationContext.ilGenerator.DeclareLocal(Nullable.GetUnderlyingType(op.Destination.MemberType));
					copying.Add(
						new AstWriteLocal(
							tempDst,
							AstBuildHelper.ReadPropertyRV(
								AstBuildHelper.ReadLocalRA(origTempDst),
								op.Destination.MemberType.GetProperty("Value")
							)
						)
					);
				}
			}

			// Suboperations
			copying.Add(
				new AstComplexNode()
				{
					nodes = new List<IAstNode> 
					{ 
						new MappingOperationsProcessor(this) 
						{ 
							operations = op.Operations, 
							locTo = tempDst, 
							locFrom = tempSrc,
							rootOperation = mappingConfigurator.GetRootMappingOperation(op.Source.MemberType, op.Destination.MemberType)
						}.ProcessOperations() 
					}
				}
			);

			IAstRefOrValue processedValue;
			if (ReflectionUtils.IsNullable(op.Destination.MemberType))
			{
				processedValue =
					new AstNewObject(
						op.Destination.MemberType,
						new[] 
                        {
                            AstBuildHelper.ReadLocalRV(tempDst)
                        }
					);
			}
			else
			{
				processedValue = AstBuildHelper.ReadLocalRV(origTempDst);
			}

			if (op.ValuesPostProcessor != null)
			{
				int postProcessorId = AddObjectToStore(op.ValuesPostProcessor);
				processedValue =
					AstBuildHelper.CallMethod(
						op.ValuesPostProcessor.GetType().GetMethod("Invoke"),
						GetStoredObject(postProcessorId, op.ValuesPostProcessor.GetType()),
						new List<IAstStackItem>
                        {
                            processedValue,
                            AstBuildHelper.ReadLocalRV(locState)
                        }
					);
			}

			copying.Add(
				AstBuildHelper.WriteMembersChain(
					op.Destination.MembersChain,
					AstBuildHelper.ReadLocalRA(locTo),
					processedValue
				)
			);

			if (ReflectionUtils.IsNullable(op.Source.MemberType) || !op.Source.MemberType.IsValueType)
			{
				result.nodes.Add(
					new AstIf()
					{
						condition = ReflectionUtils.IsNullable(op.Source.MemberType)
							? (IAstValue)new AstExprNot((IAstValue)AstBuildHelper.ReadPropertyRV(AstBuildHelper.ReadLocalRA(origTempSrc), op.Source.MemberType.GetProperty("HasValue")))
							: new AstExprIsNull(AstBuildHelper.ReadLocalRV(origTempSrc)),
						trueBranch = new AstComplexNode() { nodes = writeNullToDest },
						falseBranch = new AstComplexNode() { nodes = copying }
					}
				);
			}
			else
			{
				result.nodes.AddRange(copying);
			}
			return result;
		}
		private IAstNode Process_ReadWriteComplex_ByConverter(ReadWriteComplex op, int operationId)
		{
			IAstNode result;
			result =
				AstBuildHelper.WriteMembersChain(
					op.Destination.MembersChain,
					AstBuildHelper.ReadLocalRA(locTo),
					AstBuildHelper.CallMethod(
						op.Converter.GetType().GetMethod("Invoke"),
						new AstCastclassRef(
							(IAstRef)AstBuildHelper.ReadMemberRV(
								 GetStoredObject(operationId, typeof(ReadWriteComplex)),
								 typeof(ReadWriteComplex).GetProperty("Converter")
							),
							op.Converter.GetType()
						),
						new List<IAstStackItem>()
						{
							AstBuildHelper.ReadMembersChain(
								AstBuildHelper.ReadLocalRA(locFrom),
								op.Source.MembersChain
							),
							AstBuildHelper.ReadLocalRV(locState),
						}
					)
				);
			return result;
		}
        private IAstNode Process_ReadWriteComplex(ReadWriteComplex op, int operationId)
        {
			IAstNode result;
			if (op.Converter != null)
			{
				result = Process_ReadWriteComplex_ByConverter(op, operationId);
			}
			else
			{
				result = Process_ReadWriteComplex_Copying(op);
			}

			if (op.SourceFilter != null)
			{
				result = Process_SourceFilter(op, operationId, result);
			}

			if (op.DestinationFilter != null)
			{
				result = Process_DestinationFilter(op, operationId, result);
			}

            return result;
        }