// Example to rewrite incompatible statements ( VBA.g4 Line 296)
        public override void EnterEraseStmt(BosParser.EraseStmtContext context)
        {
            string arrayName      = context.valueStmt()[0].GetText();
            var    translatedStmt = $"Array.Clear({arrayName} , 0, {arrayName}.Length)";

            StreamRewriter.Replace(context.Start, context.Stop, translatedStmt);
            // In the first processing we record the kind of array declared in any declaration
            // and in the second pass we wold transpile the erase statements
        }
        // Our listener inherits from the base listener that is generated by
        // ANTLR. Inheriting from this listener allows us to implement only the
        // methods we need. The rest remain the default empty one, like the
        // following example.
        // public virtual void ExitStartRule([NotNull] BosParser.StartRuleContext ruleContext) { }

        public override void EnterAttributeStmt([NotNull] BosParser.AttributeStmtContext context)
        {
            // AttributeStmt Rule is in vba.g4 line 166 / bos.g4 line 134

            // Initial state = Attribute VB_NAME = "ThisWorkbook"
            if (context.implicitCallStmt_InStmt().GetText() == "VB_Name")
            {
                // Attribute VB_NAME = ThisWorkbook (Remove "s)
                // It will only do it with the first apparearing literal in the rule
                FileName = context.literal()[0].GetText().Trim('"');
            }
            // Remove attributes, from initial to end IToken (We will delete all of them though)
            StreamRewriter.Replace(context.Start, context.Stop, "");
        }
        private void RewriteComment(IToken tk)
        {
            // Channel 2 -> Comments channel in grammar
            List <IToken> cmtChannel = TokenStream.GetHiddenTokensToRight(tk.TokenIndex, 2)?.ToList();

            if (cmtChannel != null)
            {
                IToken cmt = cmtChannel[0];
                if (cmt != null)
                {
                    string pattern     = @"//\s*";
                    string replacement = "' ";
                    string newCmt      = Regex.Replace(cmt.Text, pattern, replacement);
                    // string newCmt = cmt.Text.Replace("//", "' ");
                    StreamRewriter.Replace(cmt, newCmt);
                }
            }
        }
        //transform a Type in a Structure
        // typeStmt rule (VBA.g4 Line 502)
        public override void EnterTypeStmt([NotNull] BosParser.TypeStmtContext context)
        {
            // Find the type name or in the grammar the identifier
            var typeName = context.ambiguousIdentifier().GetText();

            TypesStack.Push(typeName);  // Store it in the stack, helpful when recreating the type
            // Used to create the new type
            InitStructures.Add(typeName, new StructureInitializer(typeName));
            StreamRewriter.Replace(context.TYPE().Symbol, "Structure");
            StreamRewriter.Replace(context.END_TYPE().Symbol, "End Structure");

            string visibility = context.visibility().GetText();

            foreach (var st in context.typeStmt_Element())
            {
                StreamRewriter.InsertBefore(st.Start, $"{visibility} ");
            }
        }
        // Cannot initialize elements inside a Structure
        // since VBA Types are transformed in VB.NET Structures
        // Remove the initialization of array
        public override void ExitTypeStmt_Element([NotNull] BosParser.TypeStmt_ElementContext context)
        {
            // Peek: See the next element, without removing it from stack
            var currentType = TypesStack.Peek();

            // subscripts are the (1 TO 10) part of the arrays
            if (context.subscripts() != null && context.subscripts().IsEmpty)
            {
                string nameArray       = context.ambiguousIdentifier().GetText();
                string subscriptsArray = context.subscripts().GetText();
                InitStructures[currentType].Add(
                    $"ReDim {nameArray} ({subscriptsArray})");

                StringBuilder commas = new StringBuilder();
                Enumerable.Range(0, context.subscripts().subscript().Length - 1)
                .ToList()
                .ForEach(x => commas.Append(","));
                StreamRewriter.Replace(context.subscripts().Start, context.subscripts().Stop,
                                       $"{ commas.ToString() }");
            }
        }
        public override void EnterSubStmt([NotNull] BosParser.SubStmtContext context)
        {
            if (context.ambiguousIdentifier().GetText().Trim() == "Main_Run" ||
                context.ambiguousIdentifier().GetText().Trim() == "Main_Sub" ||
                context.ambiguousIdentifier().GetText().Trim() == "Main")
            {
                IsMainFile = true;
                StreamRewriter.Replace(context.ambiguousIdentifier().Start, "Main");

                if (context.block() == null)
                {
                    return; // Empty Main Statement
                }
                // Some function of VB.Net are culture-aware,
                // this means, for instance, that when parsing a double from a
                // string it searches for the proper-culture decimal separator
                // (e.g, ',' or '.'). So, we set a culture that ensure
                // that VB.Net uses a decimal separator '.'
                string startWatchStr       = $"{ Environment.NewLine} Dim sw As System.Diagnostics.Stopwatch = System.Diagnostics.Stopwatch.StartNew(){Environment.NewLine}";
                string invariantCultureStr = $"{Environment.NewLine}System.Globalization.CultureInfo.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture{Environment.NewLine}";

                // StreamRewriter.InsertBefore(null, startWatchStr);
                StreamRewriter.InsertBefore(context.block().Start, startWatchStr);
                StreamRewriter.InsertBefore(context.block().Start, invariantCultureStr);

                // Make the program wait at the end
                var waitStr      = $"{Environment.NewLine}Console.WriteLine(\"Press any key to exit the program\"){Environment.NewLine}Console.ReadKey(){Environment.NewLine}";
                var stopWatchStr = $"{ Environment.NewLine}" +
                                   $"sw.Stop(){ Environment.NewLine}" +
                                   $"Console.WriteLine($\"Time elapsed {{sw.Elapsed}}\"){Environment.NewLine}";
                // InsertBefore reverses the position of the transpiled lines,
                // so at the end one has stopWatchStr and then waitStr
                StreamRewriter.InsertAfter(context.block()?.Stop, waitStr);
                StreamRewriter.InsertAfter(context.block()?.Stop, stopWatchStr);
            }
            //base.EnterSubStmt(context);
        }
 public override void EnterImportStmt([NotNull] BosParser.ImportStmtContext context)
 {
     // ImportStmt Rule in Bos.g4 line 157
     StreamRewriter.Replace(context.IMPORT().Symbol, "Imports");
 }