Пример #1
0
        public static CompilationResult Compile(CompilationJob compilationJob)
        {
            var results = new List <CompilationResult>();

            // All variable declarations that we've encountered during this
            // compilation job
            var derivedVariableDeclarations = new List <Declaration>();

            // All variable declarations that we've encountered, PLUS the
            // ones we knew about before
            var knownVariableDeclarations = new List <Declaration>();

            if (compilationJob.VariableDeclarations != null)
            {
                knownVariableDeclarations.AddRange(compilationJob.VariableDeclarations);
            }

            // Get function declarations from the library, if provided
            if (compilationJob.Library != null)
            {
                knownVariableDeclarations.AddRange(GetDeclarationsFromLibrary(compilationJob.Library));
            }

            var compiledTrees = new List <(string name, IParseTree tree)>();

            // First pass: parse all files, generate their syntax trees,
            // and figure out what variables they've declared
            var stringTableManager = new StringTableManager();

            foreach (var file in compilationJob.Files)
            {
                var tree = ParseSyntaxTree(file);
                compiledTrees.Add((file.FileName, tree));

                RegisterStrings(file.FileName, stringTableManager, tree);
            }

            if (compilationJob.CompilationType == CompilationJob.Type.StringsOnly)
            {
                // Stop at this point
                return(new CompilationResult
                {
                    Declarations = null,
                    ContainsImplicitStringTags = stringTableManager.ContainsImplicitStringTags,
                    Program = null,
                    StringTable = stringTableManager.StringTable,
                });
            }

            var fileTags = new Dictionary <string, IEnumerable <string> >();

            foreach (var parsedFile in compiledTrees)
            {
                GetDeclarations(parsedFile.name, parsedFile.tree, knownVariableDeclarations, out var newDeclarations, out var newFileTags);

                derivedVariableDeclarations.AddRange(newDeclarations);
                knownVariableDeclarations.AddRange(newDeclarations);

                fileTags.Add(parsedFile.name, newFileTags);
            }

            foreach (var parsedFile in compiledTrees)
            {
                var checker = new TypeCheckVisitor(parsedFile.name, knownVariableDeclarations);

                checker.Visit(parsedFile.tree);
                derivedVariableDeclarations.AddRange(checker.NewDeclarations);
                knownVariableDeclarations.AddRange(checker.NewDeclarations);
            }

            if (compilationJob.CompilationType == CompilationJob.Type.DeclarationsOnly)
            {
                // Stop at this point
                return(new CompilationResult
                {
                    Declarations = derivedVariableDeclarations,
                    ContainsImplicitStringTags = false,
                    Program = null,
                    StringTable = null,
                    FileTags = fileTags,
                });
            }

            foreach (var parsedFile in compiledTrees)
            {
                CompilationResult compilationResult = GenerateCode(parsedFile.name, knownVariableDeclarations, compilationJob, parsedFile.tree, stringTableManager);
                results.Add(compilationResult);
            }

            var finalResult = CompilationResult.CombineCompilationResults(results, stringTableManager);

            // Last step: take every variable declaration we found in all
            // of the inputs, and create an initial value registration for
            // it.
            foreach (var declaration in knownVariableDeclarations)
            {
                // We only care about variable declarations here
                if (declaration.DeclarationType != Declaration.Type.Variable)
                {
                    continue;
                }

                Operand value;

                if (declaration.DeclarationType == Declaration.Type.Variable && declaration.defaultValue == null)
                {
                    throw new NullReferenceException($"Variable declaration {declaration.name} ({declaration.ReturnType}) has a null default value. This is not allowed.");
                }

                switch (declaration.ReturnType)
                {
                case Yarn.Type.Number:
                    value = new Operand(Convert.ToSingle(declaration.DefaultValue));
                    break;

                case Yarn.Type.String:
                    value = new Operand(Convert.ToString(declaration.DefaultValue));
                    break;

                case Yarn.Type.Bool:
                    value = new Operand(Convert.ToBoolean(declaration.DefaultValue));
                    break;

                default:
                    throw new ArgumentOutOfRangeException($"Cannot create an initial value for type {declaration.ReturnType}");
                }

                finalResult.Program.InitialValues.Add(declaration.Name, value);
            }

            finalResult.Declarations = derivedVariableDeclarations;

            finalResult.FileTags = fileTags;

            return(finalResult);
        }