public override void EnterTypeCaseClause(GoParser.TypeCaseClauseContext context)
        {
            // typeCaseClause
            //     : typeSwitchCase ':' statementList

            // typeSwitchCase
            //     : 'case' typeList | 'default'

            // typeList
            //     : type ( ',' type )*

            if (context.typeSwitchCase().typeList() is null)
            {
                GoParser.TypeSwitchStmtContext parent = context.Parent as GoParser.TypeSwitchStmtContext;
                string identifier = parent == null ? "" : SanitizedIdentifier(parent.typeSwitchGuard().IDENTIFIER().GetText());

                m_typeSwitchDefaultCase.Peek().Append($"{Environment.NewLine}{Spacing()}default:{Environment.NewLine}{Spacing()}{{{Environment.NewLine}");

                if (!string.IsNullOrEmpty(identifier))
                {
                    m_typeSwitchDefaultCase.Peek().Append($"{Spacing(1)}var {identifier} = {string.Format(TypeSwitchExpressionMarker, m_typeSwitchExpressionLevel)};{Environment.NewLine}");
                }
            }
            else
            {
                m_targetFile.Append($"{Environment.NewLine}{Spacing()}case {string.Format(TypeSwitchCaseTypeMarker, m_typeSwitchExpressionLevel)}{Environment.NewLine}");
            }

            IndentLevel++;

            PushBlock();
        }
        public override void EnterTypeSwitchStmt(GoParser.TypeSwitchStmtContext context)
        {
            // typeSwitchStmt
            //     : 'switch' (simpleStmt ';') ? typeSwitchGuard '{' typeCaseClause * '}'

            // typeSwitchGuard
            //     : ( IDENTIFIER ':=' )? primaryExpr '.' '(' 'type' ')'

            m_typeSwitchExpressionLevel++;

            if (!(context.simpleStmt() is null) && context.simpleStmt().emptyStmt() is null)
            {
                if (!(context.simpleStmt().shortVarDecl() is null))
                {
                    // Any declared variable will be scoped to switch statement, so create a sub-block for it
                    m_targetFile.AppendLine($"{Spacing()}{{");
                    IndentLevel++;

                    // Handle storing of current values of any redeclared variables
                    m_targetFile.Append(OpenRedeclaredVariableBlock(context.simpleStmt().shortVarDecl().identifierList(), m_typeSwitchExpressionLevel));
                }

                m_targetFile.Append(string.Format(TypeSwitchStatementMarker, m_typeSwitchExpressionLevel));
            }

            m_targetFile.Append($"{Spacing()}switch ({string.Format(TypeSwitchExpressionMarker, m_typeSwitchExpressionLevel)}){Environment.NewLine}{Spacing()}{{");
            IndentLevel++;

            m_typeSwitchDefaultCase.Push(new StringBuilder());
        }
        public override void ExitTypeSwitchStmt(GoParser.TypeSwitchStmtContext context)
        {
            // typeSwitchStmt
            //     : 'switch'(simpleStmt ';') ? typeSwitchGuard '{' typeCaseClause * '}'

            // typeSwitchGuard
            //     : ( IDENTIFIER ':=' )? primaryExpr '.' '(' 'type' ')'

            // Default case always needs to be last case clause in SwitchExpression - Go allows its declaration anywhere
            m_targetFile.Append($"{m_typeSwitchDefaultCase.Pop()}{CheckForCommentsRight(context)}");

            if (PrimaryExpressions.TryGetValue(context.typeSwitchGuard().primaryExpr(), out ExpressionInfo expression))
            {
                // Replace type switch expression marker
                m_targetFile.Replace(string.Format(TypeSwitchExpressionMarker, m_typeSwitchExpressionLevel), $"{expression.Text}.type()");
            }
            else
            {
                AddWarning(context, $"Failed to find primary expression for type switch statement: {context.typeSwitchGuard().GetText()}");
            }

            if (!(context.simpleStmt() is null) && context.simpleStmt().emptyStmt() is null)
            {
                if (m_simpleStatements.TryGetValue(context.simpleStmt(), out string statement))
                {
                    m_targetFile.Replace(string.Format(TypeSwitchStatementMarker, m_typeSwitchExpressionLevel), $"{statement}{Environment.NewLine}");
                }
                else
                {
                    AddWarning(context, $"Failed to find simple statement for type switch statement: {context.simpleStmt().GetText()}");
                }

                // Close any locally scoped declared variable sub-block
                if (!(context.simpleStmt().shortVarDecl() is null))
                {
                    // Handle restoration of previous values of any redeclared variables
                    m_targetFile.Append(CloseRedeclaredVariableBlock(context.simpleStmt().shortVarDecl().identifierList(), m_typeSwitchExpressionLevel));

                    IndentLevel--;
                    m_targetFile.AppendLine();
                    m_targetFile.Append($"{Spacing()}}}");
                }
            }

            IndentLevel--;
            m_targetFile.Append($"{Spacing()}}}{CheckForCommentsRight(context)}");
            m_typeSwitchExpressionLevel--;
        }
        public override void ExitTypeCaseClause(GoParser.TypeCaseClauseContext context)
        {
            // typeCaseClause
            //     : typeSwitchCase ':' statementList

            // typeSwitchCase
            //     : 'case' typeList | 'default'

            // typeList
            //     : type ( ',' type )*

            IndentLevel--;

            if (context.typeSwitchCase().typeList() is null)
            {
                m_typeSwitchDefaultCase.Peek().Append($"{PopBlock(false)}{Spacing(1)}break;{Environment.NewLine}{Spacing()}}}");
            }
            else
            {
                string caseBlock = $"{PopBlock(false)}{Spacing(1)}break;";
                m_targetFile.Append(caseBlock);

                GoParser.TypeSwitchStmtContext parent = context.Parent as GoParser.TypeSwitchStmtContext;
                string identifier = parent == null ? "_" : SanitizedIdentifier(parent.typeSwitchGuard().IDENTIFIER().GetText());

                GoParser.TypeListContext typeList            = context.typeSwitchCase().typeList();
                StringBuilder            caseTypeExpressions = new StringBuilder();
                HashSet <string>         typeNames           = new HashSet <string>();

                for (int i = 0; i < typeList.type_().Length; i++)
                {
                    if (Types.TryGetValue(typeList.type_(i), out TypeInfo typeInfo))
                    {
                        string typeName = typeInfo.TypeName;

                        if (typeNames.Add(typeName))
                        {
                            string caseExpression = i > 0 ? $"{Environment.NewLine}{caseBlock}{Environment.NewLine}{Spacing()}case " : "";

                            if (typeName.Equals("nil", StringComparison.Ordinal))
                            {
                                caseTypeExpressions.Append($"{caseExpression}null:");
                            }
                            else
                            {
                                caseTypeExpressions.Append($"{caseExpression}{typeName} {identifier}:");
                            }
                        }
                        else
                        {
                            AddWarning(typeList, $"Skipped duplicate type info (from C# perspective) for type switch case statement: {typeList.GetText()}");
                        }
                    }
                    else
                    {
                        AddWarning(typeList, $"Failed to find type info for type switch case statement: {typeList.GetText()}");
                    }
                }

                // Replace type switch case type marker
                m_targetFile.Replace(string.Format(TypeSwitchCaseTypeMarker, m_typeSwitchExpressionLevel), caseTypeExpressions.ToString());
            }
        }