public VariableTypeBindingVisitor(
     [NotNull] OrderedSet <TypeBinding> potentialTypeBindings,
     [NotNull] OrderedSet <string> allSeenVariables,
     ICollection <TextReplacement> replacements = null)
 {
     this.potentialTypeBindings = potentialTypeBindings;
     this.allSeenVariables      = allSeenVariables;
     this.replacements          = replacements;
 }
        public UpgradeResult Upgrade(UpgradeJob upgradeJob)
        {
            var potentialTypeBindings = new OrderedSet <TypeBinding>();
            var allSeenVariables      = new OrderedSet <string>();

            foreach (var file in upgradeJob.Files)
            {
                ICharStream         input  = CharStreams.fromstring(file.Source);
                YarnSpinnerV1Lexer  lexer  = new YarnSpinnerV1Lexer(input);
                CommonTokenStream   tokens = new CommonTokenStream(lexer);
                YarnSpinnerV1Parser parser = new YarnSpinnerV1Parser(tokens);

                YarnSpinnerV1Parser.DialogueContext tree = parser.dialogue();

                var declarationVisitor = new VariableTypeBindingVisitor(potentialTypeBindings, allSeenVariables);
                declarationVisitor.Visit(tree);
            }

            // We now have information on which variables exist, and
            // potentially what type they are. We can now do a pass,
            // rewriting certain expressions.
            var outputFiles = new List <UpgradeResult.OutputFile>();

            foreach (var file in upgradeJob.Files)
            {
                ICharStream         input  = CharStreams.fromstring(file.Source);
                YarnSpinnerV1Lexer  lexer  = new YarnSpinnerV1Lexer(input);
                CommonTokenStream   tokens = new CommonTokenStream(lexer);
                YarnSpinnerV1Parser parser = new YarnSpinnerV1Parser(tokens);

                YarnSpinnerV1Parser.DialogueContext tree = parser.dialogue();

                var replacements = new List <TextReplacement>();

                var declarationVisitorWithReplacements = new VariableTypeBindingVisitor(potentialTypeBindings, allSeenVariables, replacements);
                declarationVisitorWithReplacements.Visit(tree);

                outputFiles.Add(new UpgradeResult.OutputFile(file.FileName, replacements, file.Source));
            }

            List <TypeBinding> unifiedVariableBindings = TypeBinding.UnifyBindings(potentialTypeBindings);

            // We finally have our bindings. Generate declarations for them.
            var allBindings = unifiedVariableBindings.ToDictionary(b => b.VariableName, b => b.Type);

            if (allSeenVariables.Count() > 0)
            {
                // If we're here, we've got variables, and we need to
                // generate declarations for them. We'll do this by
                // generating a node in a new file that contains them.
                var declarationsNodeStringBuilder = new System.Text.StringBuilder();

                // declarationsNodeStringBuilder.AppendLine
                var preambleLines = new[]
                {
                    "title: _AutoGeneratedVariableDeclarations",
                    "tags: generated ys-upgrade-v1-to-v2",
                    "---",
                    "// NOTE: These variable declarations were automatically generated as part",
                    "// of the upgrade process. Please check these before using them in your",
                    "// game.",
                };

                foreach (var line in preambleLines)
                {
                    declarationsNodeStringBuilder.AppendLine(line);
                }

                declarationsNodeStringBuilder.AppendLine();

                // Create a dictionary that maps a type to a string that
                // will be used in declarations. This string contains the
                // name of the type as defined in Yarn, as well as a
                // default value.
                var typesToStrings = new Dictionary <Type, string>
                {
                    { Type.Bool, "false as bool" },
                    { Type.Number, "0 as number" },
                    { Type.String, @""""" as string" },
                    { Type.Undefined, "undefined" },
                };

                foreach (var variableName in allSeenVariables)
                {
                    Type type;

                    if (allBindings.ContainsKey(variableName))
                    {
                        type = allBindings[variableName];
                    }
                    else
                    {
                        type = Type.Undefined;
                    }

                    declarationsNodeStringBuilder.Append("<<declare ");
                    declarationsNodeStringBuilder.Append(variableName);
                    declarationsNodeStringBuilder.Append(" = ");
                    declarationsNodeStringBuilder.Append(typesToStrings[type]);
                    declarationsNodeStringBuilder.Append(">>");
                    declarationsNodeStringBuilder.AppendLine();
                }

                declarationsNodeStringBuilder.AppendLine("===");

                var outputDirectory = System.IO.Path.GetDirectoryName(upgradeJob.Files.First().FileName);
                var outputFileName  = System.IO.Path.Combine(outputDirectory, "Program.yarnproject");

                var declarationsOutputFile = new UpgradeResult.OutputFile(outputFileName, declarationsNodeStringBuilder.ToString());

                outputFiles.Add(declarationsOutputFile);
            }

            return(new UpgradeResult
            {
                Files = outputFiles,
            });
        }