コード例 #1
0
ファイル: Program.cs プロジェクト: mattschwartz/docrider-app
        private static void CompileFile(string filename)
        {
            string      fileText = File.ReadAllText(filename);
            var         parser   = new Parser();
            var         compiler = new Compiler(parser);
            CompilerLog log      = compiler.Compile(fileText);

            PrettyPrintCompilerLog(log);

            Console.WriteLine($"Parser: {log.ParseTime}ms");
            Console.WriteLine($"Compiler: {log.CompileTime}ms");
        }
コード例 #2
0
ファイル: Compiler.cs プロジェクト: mattschwartz/docrider-app
        /// <summary>
        /// Definitions can be declared anywhere in the doc and aren't related to each other
        /// except that duplicate definitions are invalid.
        /// </summary>
        /// <param name="stack"></param>
        /// <param name="tokenizedLine"></param>
        private void CompileDefinition(
            CompilerLog log,
            StackObject stack,
            TokenizedLine tokenizedLine)
        {
            SyntaxTree tree = tokenizedLine.SyntaxTree;

            switch (tree.DeclaredType)
            {
            case DeclaredType.Narrative:
                if (stack.Narrative != null)
                {
                    log.Error(tokenizedLine, $"Cannot define additional narrative \"{tree.AssignedValue}\". Narrative \"{stack.Narrative.Name}\" already defined.");
                }
                else
                {
                    stack.Narrative = new Narrative(tree.AssignedValue.ToString());
                }
                break;

            case DeclaredType.Character:
                var characterName  = tree.AssignedValue.ToString();
                var characterToAdd = new Character(characterName);

                if (stack.Characters.Contains(characterToAdd))
                {
                    log.Error(tokenizedLine, $"Duplicate Character definition for \"{characterName}\".");
                }
                else
                {
                    stack.Characters.Add(characterToAdd);
                }
                break;

            case DeclaredType.Setting:
                var settingName = tree.AssignedValue.ToString();
                var setting     = new Setting(settingName);

                if (stack.Settings.Contains(setting))
                {
                    log.Error(tokenizedLine, $"Duplicate Setting definition for \"{setting.Name}\".");
                }
                else
                {
                    stack.Settings.Add(setting);
                }
                break;

            default:
                log.Error(tokenizedLine, $"Cannot define declared type {tree.DeclaredType}");
                break;
            }
        }
コード例 #3
0
        private bool CompileAssembly(IReadOnlyCollection <SyntaxTree> syntaxTrees,
                                     IReadOnlyCollection <string> externalAssemblyLocations,
                                     string outputBinaryFolder,
                                     string outputAssemblyName,
                                     string assemblyNamespace,
                                     CompilerOptions compilerOptions,
                                     bool isFSharpProject)
        {
            IReadOnlyCollection <string> locations = GetReferenceLocations(externalAssemblyLocations, compilerOptions, isFSharpProject);
            const string manifestResourcePrefix    = "FunctionMonkey.Compiler.references.netstandard2._0.";
            // For each assembly we've found we need to check and see if it is already included in the output binary folder
            // If it is then its referenced already by the function host and so we add a reference to that version.
            List <string> resolvedLocations = ResolveLocationsWithExistingReferences(outputBinaryFolder, locations);

            string[] manifestResoureNames = GetType().Assembly.GetManifestResourceNames()
                                            .Where(x => x.StartsWith(manifestResourcePrefix))
                                            .Select(x => x.Substring(manifestResourcePrefix.Length))
                                            .ToArray();

            List <PortableExecutableReference> references = BuildReferenceSet(resolvedLocations);

            CSharpCompilation compilation = CSharpCompilation.Create(assemblyNamespace) //(outputAssemblyName)
                                            .WithOptions(new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary))
                                            .AddReferences(references)
                                            .AddSyntaxTrees(syntaxTrees)
            ;

            List <ResourceDescription> resources = CreateResources(assemblyNamespace);

            string     outputFilename    = Path.Combine(outputBinaryFolder, outputAssemblyName);
            EmitResult compilationResult = compilation.Emit(outputFilename, manifestResources: resources);

            if (!compilationResult.Success)
            {
                IEnumerable <Diagnostic> failures = compilationResult.Diagnostics.Where(diagnostic =>
                                                                                        diagnostic.IsWarningAsError ||
                                                                                        diagnostic.Severity == DiagnosticSeverity.Error);

                foreach (Diagnostic diagnostic in failures)
                {
                    CompilerLog.Error($"Error compiling function: {diagnostic.ToString()}");
                }
            }

            return(compilationResult.Success);
        }
コード例 #4
0
ファイル: Parser.cs プロジェクト: mattschwartz/docrider-app
        public List <TokenizedLine> TokenizeFile(CompilerLog log, string filetext)
        {
            filetext = filetext.Replace('\r', '\n');
            string[] lines = filetext.Split('\n');

            var sw = new Stopwatch();

            sw.Start();

            var result = new List <TokenizedLine>();

            for (int lineNumber = 0; lineNumber < lines.Length; ++lineNumber)
            {
                string line = lines[lineNumber];

                if (string.IsNullOrWhiteSpace(line) || line.TrimStart().StartsWith("#"))
                {
                    continue;
                }

                try
                {
                    SyntaxTree tree = Tokenize(line);

                    result.Add(new TokenizedLine
                    {
                        Line       = line,
                        LineNumber = lineNumber,
                        SyntaxTree = tree
                    });

                    log.Debug(line, lineNumber, 0, $"Success => {tree}");
                }
                catch (SyntaxParseException ex)
                {
                    log.Error(line, lineNumber, ex.Position, ex.Message);
                }
            }

            sw.Stop();
            log.ParseTime = sw.ElapsedMilliseconds;

            return(result);
        }
コード例 #5
0
ファイル: Program.cs プロジェクト: mattschwartz/docrider-app
        private static void PrettyPrintCompilerLog(CompilerLog log)
        {
            var lastBgColor = Console.BackgroundColor;
            var lastFgColor = Console.ForegroundColor;

            foreach (var message in log.GetMessages())
            {
                switch (message.Level)
                {
                case CompilerLevel.Debug:
                    Console.ForegroundColor = ConsoleColor.DarkGray;

                    Console.WriteLine($"DBG [L#{message.LineNumber,3}] {message.Message}");
                    break;

                case CompilerLevel.Info:
                    Console.ForegroundColor = ConsoleColor.Gray;

                    Console.WriteLine($"INF [L#{message.LineNumber,3}] {message.Message}");
                    break;

                case CompilerLevel.Warning:
                    Console.ForegroundColor = ConsoleColor.DarkYellow;

                    Console.WriteLine($"WRN [L#{message.LineNumber,3}] {message.Message}");
                    break;

                case CompilerLevel.Error:
                    PrettyPrintSyntaxError(
                        message.Line,
                        message.LineNumber,
                        message.ColumnNumber,
                        message.Message);
                    break;
                }

                Console.BackgroundColor = lastBgColor;
                Console.ForegroundColor = lastFgColor;
            }
        }
コード例 #6
0
ファイル: Compiler.cs プロジェクト: mattschwartz/docrider-app
        public CompilerLog Compile(string text)
        {
            var log = new CompilerLog();
            List <TokenizedLine> tokenizedLines = _parser.TokenizeFile(log, text);

            var sw = new Stopwatch();

            sw.Start();

            var objectDefinitions = new StackObject();
            var currentFrame      = new Compilation.StackFrame();

            foreach (var tokenizedLine in tokenizedLines)
            {
                switch (tokenizedLine.SyntaxTree.Directive)
                {
                case Directive.Define:
                    CompileDefinition(log, objectDefinitions, tokenizedLine);
                    break;

                case Directive.Enter:
                    CompileEntrance(objectDefinitions, log, currentFrame, tokenizedLine);
                    break;

                case Directive.Exit:
                    CompileExit(log, currentFrame, tokenizedLine);
                    break;

                default:
                    log.Warning(tokenizedLine, $"Could not operate on unknown directive {tokenizedLine.SyntaxTree.Directive}.");
                    break;
                }
            }

            sw.Stop();
            log.CompileTime = sw.ElapsedMilliseconds;

            return(log);
        }
コード例 #7
0
ファイル: Program.cs プロジェクト: mattschwartz/docrider-app
        static void Main(string[] args)
        {
            var parser   = new Parser();
            var compiler = new Compiler(parser);

            var shellCommands = new Dictionary <string, ShellCommand>
            {
                ["Compile test file (simple)"]  = () => CompileFile("Docrider.dr"),
                ["Compile test file (complex)"] = () => CompileFile("Docrider_complex.dr"),
                ["Interactive parser"]          = () => Loopy(parser),
                ["Interactive compiler"]        = () =>
                {
                    Console.WriteLine("Enter file text (empty line to stop):");
                    string      fileText = EnterFileText();
                    CompilerLog log      = compiler.Compile(fileText);

                    PrettyPrintCompilerLog(log);
                }
            };

            while (true)
            {
                PrintOptions(shellCommands);
                string input = Console.ReadLine();
                if (int.TryParse(input, out int choice))
                {
                    int i = 0;
                    foreach (var key in shellCommands.Keys)
                    {
                        if (i++ == choice)
                        {
                            shellCommands[key]();
                        }
                    }
                }
                Console.WriteLine("\n");
            }
        }
コード例 #8
0
ファイル: Compiler.cs プロジェクト: mattschwartz/docrider-app
        private void CompileExit(
            CompilerLog log,
            Compilation.StackFrame currentFrame,
            TokenizedLine tokenizedLine)
        {
            SyntaxTree tree = tokenizedLine.SyntaxTree;

            switch (tree.DeclaredType)
            {
            case DeclaredType.Act:
                if (currentFrame.Act == null)
                {
                    log.Warning(tokenizedLine, $"Attempted to exit act but currently not in an act.");
                }
                else
                {
                    log.Debug(tokenizedLine, $"Exiting act \"{currentFrame.Act.Name}\"");
                    currentFrame.Act = null;
                }

                break;

            case DeclaredType.Scene:
                if (currentFrame.Scene == null)
                {
                    log.Warning(tokenizedLine, $"Attempted to exit scene but currently not in a scene.");
                }
                else if (currentFrame.Scene.Characters.Count != 0)
                {
                    log.Warning(tokenizedLine, "Exiting scene with characters present will exeunt all characters. Did you mean to do this?");
                    currentFrame.Scene = null;
                }
                else
                {
                    log.Debug(tokenizedLine, $"Exiting scene \"{currentFrame.Scene.Name}\"");
                    currentFrame.Scene = null;
                }
                break;

            case DeclaredType.Character:
                var characterName = tree.AssignedValue.ToString();

                if (currentFrame.Scene == null)
                {
                    log.Error(tokenizedLine, $"Cannot exit character outside of scene. Please enter a scene first.");
                }
                else
                {
                    Character characterToExit = currentFrame.Scene.Characters
                                                .SingleOrDefault(t => t.Name == characterName);

                    if (characterToExit == null)
                    {
                        log.Warning(tokenizedLine, $"Attempted to exit character \"{characterName}\" who was not present in scene.");
                    }
                    else
                    {
                        log.Debug(tokenizedLine, $"Exiting character \"{characterName}\"");
                        currentFrame.Scene.Characters.Remove(characterToExit);
                    }
                }

                break;

            case DeclaredType.Setting:
                var settingName = tree.AssignedValue.ToString();

                if (currentFrame.Setting == null)
                {
                    log.Error(tokenizedLine, $"Attempted to exit setting \"{settingName}\" which was never entered.");
                }
                else if (currentFrame.Setting.Name != settingName)
                {
                    log.Error(tokenizedLine, $"Attempted to exit setting \"{settingName}\", but expected to exit current setting with name \"{currentFrame.Setting.Name}\".");
                }
                else
                {
                    log.Debug(tokenizedLine, $"Exiting setting \"{settingName}\"");
                    currentFrame.Setting = null;
                }

                break;

            default:
                throw new InternalCompilerException($"Cannot exit declared type {tree.DeclaredType}");
            }
        }
コード例 #9
0
ファイル: Compiler.cs プロジェクト: mattschwartz/docrider-app
        private void CompileEntrance(
            StackObject objectDefinitions,
            CompilerLog log,
            Compilation.StackFrame currentFrame,
            TokenizedLine tokenizedLine)
        {
            SyntaxTree tree = tokenizedLine.SyntaxTree;

            switch (tree.DeclaredType)
            {
            case DeclaredType.Act:
                var actName = tree.AssignedValue.ToString();
                if (currentFrame.Act != null)
                {
                    log.Error(tokenizedLine, $"Cannot enter act with name \"{actName}\" when already in act \"{currentFrame.Act.Name}\".");
                }
                else
                {
                    var actToEnter = new Act(actName);
                    if (objectDefinitions.Acts.Contains(actToEnter))
                    {
                        log.Error(tokenizedLine, $"Cannot re-enter act with name \"{actName}\".");
                    }
                    else
                    {
                        objectDefinitions.Acts.Add(actToEnter);
                        currentFrame.Act = actToEnter;
                    }
                }
                break;

            case DeclaredType.Scene:
                var sceneName = tree.AssignedValue.ToString();
                if (currentFrame.Scene != null)
                {
                    log.Error(tokenizedLine, $"Cannot enter scene with name \"{sceneName}\" when already in scene \"{currentFrame.Scene.Name}\".");
                }
                else
                {
                    var sceneToEnter = new Scene(sceneName);
                    if (objectDefinitions.Scenes.Contains(sceneToEnter))
                    {
                        log.Error(tokenizedLine, $"Cannot re-enter scene with name \"{sceneName}\".");
                    }
                    else
                    {
                        log.Debug(tokenizedLine, $"Entered scene \"{sceneName}\"");
                        objectDefinitions.Scenes.Add(sceneToEnter);
                        currentFrame.Scene = sceneToEnter;
                    }
                }
                break;

            case DeclaredType.Character:
                var characterName = tree.AssignedValue.ToString();
                var character     = objectDefinitions.Characters.SingleOrDefault(t => t.Name == characterName);

                if (character == null)
                {
                    log.Error(tokenizedLine, $"Cannot enter undefined character \"{characterName}\".");
                }
                else
                {
                    var currentScene = currentFrame.Scene;
                    if (currentScene == null)
                    {
                        log.Error(tokenizedLine, $"Cannot enter character \"{characterName}\" outside of a scene. Please enter a scene first.");
                    }
                    else
                    {
                        log.Debug(tokenizedLine, $"Entered Character \"{characterName}\"");
                        currentScene.Characters.Add(character);
                    }
                }
                break;

            case DeclaredType.Setting:
                var settingName = tree.AssignedValue.ToString();
                var setting     = objectDefinitions.Settings.SingleOrDefault(t => t.Name == settingName);

                if (setting == null)
                {
                    log.Error(tokenizedLine, $"Cannot enter undefined setting \"{settingName}\".");
                }
                else
                {
                    if (currentFrame.Setting != null)
                    {
                        log.Warning(tokenizedLine, $"Switching setting to \"{settingName}\" from current setting \"{currentFrame.Setting.Name}\".");
                    }

                    log.Debug(tokenizedLine, $"Entered setting \"{settingName}\"");
                    currentFrame.Setting = setting;
                }
                break;

            default:
                throw new InternalCompilerException($"Cannot enter declared type {tree.DeclaredType}");
            }
        }