Пример #1
0
        internal override void WriteTo(CCodeWriterBase c)
        {
            // Finish it properly

            var localImpl = new LocalImpl {
                Name = "__ConditionalAccess", Type = Type
            };
            var local = new Local {
                LocalSymbol = localImpl
            };

            var block = new Block();

            block.Statements.Add(new VariableDeclaration {
                Local = local
            });
            block.Statements.Add(
                new ExpressionStatement
            {
                Expression =
                    new AssignmentOperator
                {
                    Left  = local,
                    Right = this.Receiver
                }
            });

            // prepare access expression;
            Expression access = new Access {
                ReceiverOpt = local, Expression = this.WhenNotNull
            };
            var call = this.WhenNotNull as Call;

            if (call != null)
            {
                access           = call;
                call.ReceiverOpt = local;
            }

            var fieldAccess = this.WhenNotNull as FieldAccess;

            if (fieldAccess != null)
            {
                access = fieldAccess;
                fieldAccess.ReceiverOpt = local;
            }

            block.Statements.Add(
                new ReturnStatement
            {
                ExpressionOpt =
                    new ConditionalOperator
                {
                    Condition =
                        new BinaryOperator
                    {
                        Left = (Type.TypeKind == TypeKind.TypeParameter) ? (Expression) new Cast
                        {
                            Constrained = true,
                            Operand     = local,
                            Type        = new TypeImpl {
                                SpecialType = SpecialType.System_Object
                            }
                        } : local,
                        Right = new Literal {
                            Value = ConstantValue.Create(null)
                        },
                        OperatorKind = BinaryOperatorKind.NotEqual
                    },
                    Consequence = access,
                    Alternative = new Literal {
                        Value = ConstantValue.Create(null)
                    }
                }
            });

            new LambdaCall
            {
                Lambda = new LambdaExpression {
                    Statements = block, Type = Type
                }
            }.WriteTo(c);

            // clean up
            if (call != null)
            {
                call.ReceiverOpt = null;
            }

            if (fieldAccess != null)
            {
                fieldAccess.ReceiverOpt = null;
            }
        }
Пример #2
0
        internal static Base Deserialize(BoundNode boundBody, IMethodSymbol methodSymbol = null, SpecialCases specialCase = SpecialCases.None)
        {
            // method
            var boundStatementList = boundBody as BoundStatementList;

            if (boundStatementList != null)
            {
                if (methodSymbol != null || boundStatementList.Syntax.Green is MethodDeclarationSyntax)
                {
                    var methodBody = new MethodBody(methodSymbol);
                    methodBody.Parse(boundStatementList);
                    return(methodBody);
                }

                if (boundStatementList.Syntax.Green is VariableDeclarationSyntax)
                {
                    var variableDeclaration = new VariableDeclaration();
                    variableDeclaration.Parse(boundStatementList);
                    return(variableDeclaration);
                }

                if (boundStatementList.Syntax.Green is IfStatementSyntax)
                {
                    var ifStatement = new IfStatement();
                    if (ifStatement.Parse(boundStatementList))
                    {
                        return(ifStatement);
                    }
                }

                if (boundStatementList.Syntax.Green is ForStatementSyntax)
                {
                    var forStatement = new ForStatement();
                    if (forStatement.Parse(boundStatementList))
                    {
                        return(forStatement);
                    }
                }

                if (boundStatementList.Syntax.Green is WhileStatementSyntax)
                {
                    var whileStatement = new WhileStatement();
                    if (whileStatement.Parse(boundStatementList))
                    {
                        return(whileStatement);
                    }
                }

                if (boundStatementList.Syntax.Green is DoStatementSyntax)
                {
                    var doStatement = new DoStatement();
                    if (doStatement.Parse(boundStatementList))
                    {
                        return(doStatement);
                    }
                }

                var forEachStatementSyntax = boundStatementList.Syntax.Green as ForEachStatementSyntax;
                if (forEachStatementSyntax != null)
                {
                    if (specialCase != SpecialCases.ForEachBody)
                    {
                        var forEachSimpleArrayStatement = new ForEachSimpleArrayStatement();
                        if (forEachSimpleArrayStatement.Parse(boundStatementList))
                        {
                            return(forEachSimpleArrayStatement);
                        }

                        var forEachIteratorStatement = new ForEachIteratorStatement();
                        if (forEachIteratorStatement.Parse(boundStatementList))
                        {
                            return(forEachIteratorStatement);
                        }
                    }
                }

                // try to detect 'if'
                var ifStatementNoHint = new IfStatement();
                if (ifStatementNoHint.Parse(boundStatementList))
                {
                    return(ifStatementNoHint);
                }

                var whileStatementNoHint = new WhileStatement();
                if (whileStatementNoHint.Parse(boundStatementList))
                {
                    return(whileStatementNoHint);
                }

                var block = new Block();
                block.Parse(boundStatementList, specialCase);
                return(block);
            }

            var boundConversion = boundBody as BoundConversion;

            if (boundConversion != null)
            {
                var conversion = new Conversion();
                conversion.Parse(boundConversion);
                return(conversion);
            }

            var boundTypeExpression = boundBody as BoundTypeExpression;

            if (boundTypeExpression != null)
            {
                var typeExpression = new TypeExpression();
                typeExpression.Parse(boundTypeExpression);
                return(typeExpression);
            }

            var boundThisReference = boundBody as BoundThisReference;

            if (boundThisReference != null)
            {
                var thisReference = new ThisReference();
                thisReference.Parse(boundThisReference);
                return(thisReference);
            }

            var boundBaseReference = boundBody as BoundBaseReference;

            if (boundBaseReference != null)
            {
                var baseReference = new BaseReference();
                baseReference.Parse(boundBaseReference);
                return(baseReference);
            }

            var boundFieldAccess = boundBody as BoundFieldAccess;

            if (boundFieldAccess != null)
            {
                var fieldAccess = new FieldAccess();
                fieldAccess.Parse(boundFieldAccess);
                return(fieldAccess);
            }

            var boundParameter = boundBody as BoundParameter;

            if (boundParameter != null)
            {
                var parameter = new Parameter();
                parameter.Parse(boundParameter);
                return(parameter);
            }

            var boundLocal = boundBody as BoundLocal;

            if (boundLocal != null)
            {
                var local = new Local();
                local.Parse(boundLocal);
                return(local);
            }

            var boundLiteral = boundBody as BoundLiteral;

            if (boundLiteral != null)
            {
                var literal = new Literal();
                literal.Parse(boundLiteral);
                return(literal);
            }

            var boundExpressionStatement = boundBody as BoundExpressionStatement;

            if (boundExpressionStatement != null)
            {
                var expressionStatement = new ExpressionStatement();
                expressionStatement.Parse(boundExpressionStatement);
                return(expressionStatement);
            }

            var boundSequence = boundBody as BoundSequence;

            if (boundSequence != null)
            {
                if (boundSequence.Syntax.Green is PrefixUnaryExpressionSyntax)
                {
                    var prefixUnaryExpression = new PrefixUnaryExpression();
                    if (prefixUnaryExpression.Parse(boundSequence))
                    {
                        return(prefixUnaryExpression);
                    }
                }

                if (boundSequence.Syntax.Green is PostfixUnaryExpressionSyntax)
                {
                    var postfixUnaryExpression = new PostfixUnaryExpression();
                    if (postfixUnaryExpression.Parse(boundSequence))
                    {
                        return(postfixUnaryExpression);
                    }
                }

                var sideEffectsAsLambdaCallExpression = new SideEffectsAsLambdaCallExpression();
                if (sideEffectsAsLambdaCallExpression.Parse(boundSequence))
                {
                    return(sideEffectsAsLambdaCallExpression);
                }
            }

            var boundCall = boundBody as BoundCall;

            if (boundCall != null)
            {
                var call = new Call();
                call.Parse(boundCall);
                return(call);
            }

            var boundBinaryOperator = boundBody as BoundBinaryOperator;

            if (boundBinaryOperator != null)
            {
                var binaryOperator = new BinaryOperator();
                binaryOperator.Parse(boundBinaryOperator);
                return(binaryOperator);
            }

            var boundAssignmentOperator = boundBody as BoundAssignmentOperator;

            if (boundAssignmentOperator != null)
            {
                var unaryAssignmentOperator = new UnaryAssignmentOperator();
                if (unaryAssignmentOperator.Parse(boundAssignmentOperator))
                {
                    return(unaryAssignmentOperator);
                }

                var assignmentOperator = new AssignmentOperator();
                assignmentOperator.Parse(boundAssignmentOperator);
                return(assignmentOperator);
            }

            var boundObjectCreationExpression = boundBody as BoundObjectCreationExpression;

            if (boundObjectCreationExpression != null)
            {
                var objectCreationExpression = new ObjectCreationExpression();
                objectCreationExpression.Parse(boundObjectCreationExpression);
                return(objectCreationExpression);
            }

            var boundUnaryOperator = boundBody as BoundUnaryOperator;

            if (boundUnaryOperator != null)
            {
                var unaryOperator = new UnaryOperator();
                unaryOperator.Parse(boundUnaryOperator);
                return(unaryOperator);
            }

            var boundConditionalOperator = boundBody as BoundConditionalOperator;

            if (boundConditionalOperator != null)
            {
                var conditionalOperator = new ConditionalOperator();
                conditionalOperator.Parse(boundConditionalOperator);
                return(conditionalOperator);
            }

            var boundNullCoalescingOperator = boundBody as BoundNullCoalescingOperator;

            if (boundNullCoalescingOperator != null)
            {
                var nullCoalescingOperator = new NullCoalescingOperator();
                nullCoalescingOperator.Parse(boundNullCoalescingOperator);
                return(nullCoalescingOperator);
            }

            var boundArrayCreation = boundBody as BoundArrayCreation;

            if (boundArrayCreation != null)
            {
                var arrayCreation = new ArrayCreation();
                arrayCreation.Parse(boundArrayCreation);
                return(arrayCreation);
            }

            var boundArrayInitialization = boundBody as BoundArrayInitialization;

            if (boundArrayInitialization != null)
            {
                var arrayInitialization = new ArrayInitialization();
                arrayInitialization.Parse(boundArrayInitialization);
                return(arrayInitialization);
            }

            var boundArrayAccess = boundBody as BoundArrayAccess;

            if (boundArrayAccess != null)
            {
                var arrayAccess = new ArrayAccess();
                arrayAccess.Parse(boundArrayAccess);
                return(arrayAccess);
            }

            var boundArrayLength = boundBody as BoundArrayLength;

            if (boundArrayLength != null)
            {
                var arrayLength = new ArrayLength();
                arrayLength.Parse(boundArrayLength);
                return(arrayLength);
            }

            var boundStackAllocArrayCreation = boundBody as BoundStackAllocArrayCreation;

            if (boundStackAllocArrayCreation != null)
            {
                var stackAllocArrayCreation = new StackAllocArrayCreation();
                stackAllocArrayCreation.Parse(boundStackAllocArrayCreation);
                return(stackAllocArrayCreation);
            }

            var boundDefaultOperator = boundBody as BoundDefaultOperator;

            if (boundDefaultOperator != null)
            {
                var defaultOperator = new DefaultOperator();
                defaultOperator.Parse(boundDefaultOperator);
                return(defaultOperator);
            }

            var boundReturnStatement = boundBody as BoundReturnStatement;

            if (boundReturnStatement != null)
            {
                var returnStatement = new ReturnStatement();
                returnStatement.Parse(boundReturnStatement);
                return(returnStatement);
            }

            var boundDelegateCreationExpression = boundBody as BoundDelegateCreationExpression;

            if (boundDelegateCreationExpression != null)
            {
                var delegateCreationExpression = new DelegateCreationExpression();
                delegateCreationExpression.Parse(boundDelegateCreationExpression);
                return(delegateCreationExpression);
            }

            var boundThrowStatement = boundBody as BoundThrowStatement;

            if (boundThrowStatement != null)
            {
                var throwStatement = new ThrowStatement();
                throwStatement.Parse(boundThrowStatement);
                return(throwStatement);
            }

            var boundThrowExpression = boundBody as BoundThrowExpression;

            if (boundThrowExpression != null)
            {
                var throwExpression = new ThrowExpression();
                throwExpression.Parse(boundThrowExpression);
                return(throwExpression);
            }

            var boundTryStatement = boundBody as BoundTryStatement;

            if (boundTryStatement != null)
            {
                var tryStatement = new TryStatement();
                tryStatement.Parse(boundTryStatement);
                return(tryStatement);
            }

            var boundCatchBlock = boundBody as BoundCatchBlock;

            if (boundCatchBlock != null)
            {
                var catchBlock = new CatchBlock();
                catchBlock.Parse(boundCatchBlock);
                return(catchBlock);
            }

            var boundGotoStatement = boundBody as BoundGotoStatement;

            if (boundGotoStatement != null)
            {
                if (boundGotoStatement.Syntax.Green is ContinueStatementSyntax)
                {
                    var continueStatement = new ContinueStatement();
                    continueStatement.Parse(boundGotoStatement);
                    return(continueStatement);
                }

                if (boundGotoStatement.Syntax.Green is BreakStatementSyntax)
                {
                    var breakStatement = new BreakStatement();
                    breakStatement.Parse(boundGotoStatement);
                    return(breakStatement);
                }

                ////var continueStatementNoHint = new ContinueStatement();
                ////if (continueStatementNoHint.Parse(boundGotoStatement))
                ////{
                ////    return continueStatementNoHint;
                ////}

                ////var breakStatementNoHint = new BreakStatement();
                ////if (breakStatementNoHint.Parse(boundGotoStatement))
                ////{
                ////    return breakStatementNoHint;
                ////}

                var gotoStatement = new GotoStatement();
                gotoStatement.Parse(boundGotoStatement);
                return(gotoStatement);
            }

            var boundLabelStatement = boundBody as BoundLabelStatement;

            if (boundLabelStatement != null)
            {
                var labelStatement = new LabelStatement();
                labelStatement.Parse(boundLabelStatement);
                return(labelStatement);
            }

            var boundMethodGroup = boundBody as BoundMethodGroup;

            if (boundMethodGroup != null)
            {
                var methodGroup = new MethodGroup();
                methodGroup.Parse(boundMethodGroup);
                return(methodGroup);
            }

            var boundConditionalGoto = boundBody as BoundConditionalGoto;

            if (boundConditionalGoto != null)
            {
                var conditionalGoto = new ConditionalGoto();
                conditionalGoto.Parse(boundConditionalGoto);
                return(conditionalGoto);
            }

            var boundAsOperator = boundBody as BoundAsOperator;

            if (boundAsOperator != null)
            {
                var asOperator = new AsOperator();
                asOperator.Parse(boundAsOperator);
                return(asOperator);
            }

            var boundIsOperator = boundBody as BoundIsOperator;

            if (boundIsOperator != null)
            {
                var isOperator = new IsOperator();
                isOperator.Parse(boundIsOperator);
                return(isOperator);
            }

            var boundTypeOfOperator = boundBody as BoundTypeOfOperator;

            if (boundTypeOfOperator != null)
            {
                var typeOfOperator = new TypeOfOperator();
                typeOfOperator.Parse(boundTypeOfOperator);
                return(typeOfOperator);
            }

            var boundSwitchStatement = boundBody as BoundSwitchStatement;

            if (boundSwitchStatement != null)
            {
                var switchStatement = new SwitchStatement();
                switchStatement.Parse(boundSwitchStatement);
                return(switchStatement);
            }

            var boundAddressOfOperator = boundBody as BoundAddressOfOperator;

            if (boundAddressOfOperator != null)
            {
                var addressOfOperator = new AddressOfOperator();
                addressOfOperator.Parse(boundAddressOfOperator);
                return(addressOfOperator);
            }

            var boundPointerIndirectionOperator = boundBody as BoundPointerIndirectionOperator;

            if (boundPointerIndirectionOperator != null)
            {
                if (boundPointerIndirectionOperator.Syntax.Green is ElementAccessExpressionSyntax)
                {
                    var elementAccessExpression = new ElementAccessExpression();
                    if (elementAccessExpression.Parse(boundPointerIndirectionOperator))
                    {
                        return(elementAccessExpression);
                    }
                }

                var pointerIndirectionOperator = new PointerIndirectionOperator();
                pointerIndirectionOperator.Parse(boundPointerIndirectionOperator);
                return(pointerIndirectionOperator);
            }

            var boundMakeRefOperator = boundBody as BoundMakeRefOperator;

            if (boundMakeRefOperator != null)
            {
                var makeRefOperator = new MakeRefOperator();
                makeRefOperator.Parse(boundMakeRefOperator);
                return(makeRefOperator);
            }

            var boundRefValueOperator = boundBody as BoundRefValueOperator;

            if (boundRefValueOperator != null)
            {
                var refValueOperator = new RefValueOperator();
                refValueOperator.Parse(boundRefValueOperator);
                return(refValueOperator);
            }

            var boundRefTypeOperator = boundBody as BoundRefTypeOperator;

            if (boundRefTypeOperator != null)
            {
                var refTypeOperator = new RefTypeOperator();
                refTypeOperator.Parse(boundRefTypeOperator);
                return(refTypeOperator);
            }

            var boundSizeOfOperator = boundBody as BoundSizeOfOperator;

            if (boundSizeOfOperator != null)
            {
                var sizeOfOperator = new SizeOfOperator();
                sizeOfOperator.Parse(boundSizeOfOperator);
                return(sizeOfOperator);
            }

            var boundNoOpStatement = boundBody as BoundNoOpStatement;

            if (boundNoOpStatement != null)
            {
                var noOpStatement = new NoOpStatement();
                noOpStatement.Parse(boundNoOpStatement);
                return(noOpStatement);
            }

            var boundIteratorScope = boundBody as BoundStateMachineScope;

            if (boundIteratorScope != null)
            {
                var stateMachineScope = new StateMachineScope();
                stateMachineScope.Parse(boundIteratorScope);
                return(stateMachineScope);
            }

            var boundArgList = boundBody as BoundArgList;

            if (boundArgList != null)
            {
                var argList = new ArgList();
                argList.Parse(boundArgList);
                return(argList);
            }

            var boundArgListOperator = boundBody as BoundArgListOperator;

            if (boundArgListOperator != null)
            {
                var argListOperator = new ArgListOperator();
                argListOperator.Parse(boundArgListOperator);
                return(argListOperator);
            }

            var boundLoweredConditionalAccess = boundBody as BoundLoweredConditionalAccess;

            if (boundLoweredConditionalAccess != null)
            {
                var loweredConditionalAccess = new LoweredConditionalAccess();
                loweredConditionalAccess.Parse(boundLoweredConditionalAccess);
                return(loweredConditionalAccess);
            }

            var boundConditionalReceiver = boundBody as BoundConditionalReceiver;

            if (boundConditionalReceiver != null)
            {
                var conditionalReceiver = new ConditionalReceiver();
                conditionalReceiver.Parse(boundConditionalReceiver);
                return(conditionalReceiver);
            }

            var statemnentOrExpression = Unwrap(boundBody);

            if (statemnentOrExpression == null)
            {
                throw new NotImplementedException();
            }

            return(Deserialize(statemnentOrExpression));
        }
Пример #3
0
        internal override void WriteTo(CCodeWriterBase c)
        {
            Local localCase = null;

            if (this.stringEquality != null)
            {
                c.OpenBlock();

                var localImpl = new LocalImpl {
                    Name = "__SwitchExpression", Type = this.expression.Type
                };
                var local = new Local {
                    LocalSymbol = localImpl
                };

                var localImplCase = new LocalImpl {
                    Name = "__SwitchCase", Type = new TypeImpl {
                        SpecialType = SpecialType.System_Int32
                    }
                };
                localCase = new Local {
                    LocalSymbol = localImplCase
                };

                new VariableDeclaration
                {
                    Statements =
                    {
                        new ExpressionStatement
                        {
                            Expression =
                                new AssignmentOperator
                            {
                                TypeDeclaration = true,
                                Type            = new TypeImpl {
                                    SpecialType = SpecialType.System_Int32
                                },
                                Left  = localCase,
                                Right = new Literal{
                                    Value = ConstantValue.Create(0)
                                }
                            }
                        }
                    }
                }.WriteTo(c);
                new VariableDeclaration
                {
                    Statements =
                    {
                        new ExpressionStatement
                        {
                            Expression =
                                new AssignmentOperator
                            {
                                TypeDeclaration = true,
                                Type            = new TypeImpl {
                                    SpecialType = SpecialType.System_String
                                },
                                Left  = local,
                                Right = this.expression
                            }
                        }
                    }
                }.WriteTo(c);

                // first if
                IfStatement first     = null;
                IfStatement last      = null;
                var         caseIndex = 0;

                foreach (var switchSection in this.switchCases)
                {
                    foreach (var label in switchSection.Labels)
                    {
                        if (label.Value == null)
                        {
                            // default case;
                            continue;
                        }

                        caseIndex++;

                        // compare
                        var callEqual = new Call()
                        {
                            Method = this.stringEquality
                        };
                        callEqual.Arguments.Add(local);
                        callEqual.Arguments.Add(new Literal {
                            Value = label.Value
                        });

                        // set value
                        var setExpr = new ExpressionStatement
                        {
                            Expression =
                                new AssignmentOperator
                            {
                                Left  = localCase,
                                Right = new Literal {
                                    Value = ConstantValue.Create(caseIndex)
                                }
                            }
                        };

                        var ifStatement = new IfStatement
                        {
                            Condition    = callEqual,
                            IfStatements = setExpr
                        };

                        first = first ?? ifStatement;
                        if (last != null)
                        {
                            last.ElseStatementsOpt = ifStatement;
                        }

                        last = ifStatement;

                        // remap case value
                        label.Value = ConstantValue.Create(caseIndex);
                    }
                }

                if (first != null)
                {
                    first.WriteTo(c);
                }

                c.Separate();
            }

            foreach (var statement in this.statements)
            {
                statement.WriteTo(c);
            }

            c.TextSpan("switch");
            c.WhiteSpace();
            c.TextSpan("(");
            if (this.stringEquality != null)
            {
                localCase.WriteTo(c);
            }
            else
            {
                this.expression.WriteTo(c);
            }

            c.TextSpan(")");
            c.NewLine();
            c.OpenBlock();
            foreach (var switchSection in this.switchCases)
            {
                switchSection.WriteTo(c);
            }

            c.EndBlock();

            if (this.stringEquality != null)
            {
                c.EndBlock();
            }

            c.Separate();
        }
Пример #4
0
        internal override void WriteTo(CCodeWriterBase c)
        {
            Local localCase = null;

            if (this.stringEquality != null)
            {
                c.OpenBlock();

                var localImpl = new LocalImpl {
                    Name = "__SwitchExpression", Type = this.expression.Type
                };
                var local = new Local
                {
                    LocalSymbol = localImpl,
                    MethodOwner = MethodOwner
                };

                var localImplCase = new LocalImpl {
                    Name = "__SwitchCase", Type = SpecialType.System_Int32.ToType()
                };
                localCase = new Local
                {
                    LocalSymbol = localImplCase,
                    MethodOwner = MethodOwner
                };

                new VariableDeclaration
                {
                    Statements =
                    {
                        new ExpressionStatement
                        {
                            Expression =
                                new AssignmentOperator
                            {
                                TypeDeclaration = true,
                                Type            = SpecialType.System_Int32.ToType(),
                                Left            = localCase,
                                Right           = new Literal {
                                    Value = ConstantValue.Create(0)
                                },
                                MethodOwner = MethodOwner
                            },
                            MethodOwner = MethodOwner
                        }
                    },
                    MethodOwner = MethodOwner
                }.WriteTo(c);
                new VariableDeclaration
                {
                    Statements =
                    {
                        new ExpressionStatement
                        {
                            Expression =
                                new AssignmentOperator
                            {
                                TypeDeclaration = true,
                                Type            = SpecialType.System_String.ToType(),
                                Left            = local,
                                Right           = this.expression,
                                MethodOwner     = MethodOwner
                            },
                            MethodOwner = MethodOwner
                        }
                    },
                    MethodOwner = MethodOwner
                }.WriteTo(c);

                // first if
                IfStatement first     = null;
                IfStatement last      = null;
                var         caseIndex = 0;

                foreach (var switchSection in this.switchCases)
                {
                    foreach (var label in switchSection.Labels)
                    {
                        if (label.Value == null)
                        {
                            // default case;
                            continue;
                        }

                        caseIndex++;

                        // compare
                        var callEqual = new Call()
                        {
                            Method = this.stringEquality
                        };
                        callEqual.Arguments.Add(local);
                        callEqual.Arguments.Add(new Literal {
                            Value = label.Value
                        });

                        // set value
                        var setExpr = new ExpressionStatement
                        {
                            Expression =
                                new AssignmentOperator
                            {
                                Left  = localCase,
                                Right = new Literal {
                                    Value = ConstantValue.Create(caseIndex)
                                }
                            }
                        };

                        var ifStatement = new IfStatement
                        {
                            Condition    = callEqual,
                            IfStatements = setExpr
                        };

                        first = first ?? ifStatement;
                        if (last != null)
                        {
                            last.ElseStatementsOpt = ifStatement;
                        }

                        last = ifStatement;

                        // remap case value
                        label.Value = ConstantValue.Create(caseIndex);
                    }
                }

                if (first != null)
                {
                    first.WriteTo(c);
                }

                c.Separate();
            }

            foreach (var statement in this.statements)
            {
                statement.WriteTo(c);
            }

            var generateDefaultLabel = this.isNullableType;

            if (this.isNullableType)
            {
                var nullCase = this.switchCases.FirstOrDefault(sc => sc.Labels.Any(l => l.Value != null && l.Value.IsNull));
                if (nullCase != null)
                {
                    generateDefaultLabel = false;
                }

                var nullCaseOrDefault = nullCase ?? this.switchCases.FirstOrDefault(sc => sc.Labels.Any(l => l.Value == null));
                if (nullCaseOrDefault != null)
                {
                    var effectiveExpression = this.expression;

                    var callExpression = this.expression as Call;
                    if (callExpression != null)
                    {
                        effectiveExpression = new UnaryOperator
                        {
                            OperatorKind = UnaryOperatorKind.LogicalNegation,
                            Operand      = new Call {
                                ReceiverOpt = callExpression.ReceiverOpt, Method = new MethodImpl {
                                    Name = "get_HasValue", Parameters = ImmutableArray <IParameterSymbol> .Empty
                                }
                            }
                        };
                    }

                    // we need to insert nullable goto;
                    var ifStatement = new IfStatement
                    {
                        Condition    = effectiveExpression,
                        IfStatements = new GotoStatement {
                            Label = nullCaseOrDefault.Labels.First(l => l.Value == null || l.Value.IsNull)
                        }
                    };

                    ifStatement.WriteTo(c);
                }
            }

            c.TextSpan("switch");
            c.WhiteSpace();
            c.TextSpan("(");
            if (this.stringEquality != null)
            {
                localCase.WriteTo(c);
            }
            else
            {
                this.expression.WriteTo(c);
            }

            c.TextSpan(")");
            c.NewLine();
            c.OpenBlock();
            foreach (var switchSection in this.switchCases)
            {
                if (!generateDefaultLabel && switchSection.Labels.Any(l => l.Value == null))
                {
                    switchSection.IsNullableType = false;
                }

                switchSection.WriteTo(c);
            }

            c.EndBlock();

            if (this.stringEquality != null)
            {
                c.EndBlock();
            }

            c.Separate();
        }