Example #1
0
        public VMModule?CompileAndLink(
            string source,
            string filename,
            InteropResolver resolver,
            List <ParseError> parseErrors,
            List <LinkError> linkErrors
            )
        {
            Linker      linker       = new Linker(linkErrors);
            ParseModule parsedModule = CreateInputParseModuleFromInteropResolver(resolver);

            SetupLinkerWithInteropResolver(linker, resolver);

            ILModule?compiledModule = Compile(source, filename, parseErrors, parsedModule);

            if (compiledModule == null)
            {
                return(null);
            }

            linker.AddModule(compiledModule, export: true);

            VMModule linkedModule = linker.Link();

            if (linkErrors.Count > 0)
            {
                return(null);
            }

            return(linkedModule);
        }
Example #2
0
 private void SetupLinkerWithInteropResolver(Linker linker, InteropResolver resolver)
 {
     foreach (Binding binding in resolver.Bindings)
     {
         linker.AddFunctionBinding(binding.Prototype.Name, binding.Implementation, export: false);
     }
 }
Example #3
0
        private ParseModule CreateInputParseModuleFromInteropResolver(InteropResolver resolver)
        {
            ParseModule module = new ParseModule();

            module.Functions.AddRange(resolver.Bindings.Select(b => b.Prototype));
            module.Enums.AddRange(resolver.Enums);
            return(module);
        }
Example #4
0
        public ParseModule ParseAndAnalyze(
            string source,
            string filename,
            List <ParseError> errors,
            InteropResolver resolver
            )
        {
            ParseModule module = CreateInputParseModuleFromInteropResolver(resolver);

            return(ParseAndAnalyze(source, filename, errors, module));
        }
Example #5
0
        private void ResolveInteropLibs()
        {
            InteropResolver = new InteropResolver();

            foreach (string libraryName in _libraryNames)
            {
                Assembly lib = LoadAssembly(libraryName);
                InteropResolver.ImportAssembly(lib,
                                               BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static);
            }

            _semanticAnalyzer.Register(InteropResolver.CreateHeaderModule());
        }
Example #6
0
        public VMModule?CompileAndLink(
            ParseModule parsedModule,
            InteropResolver resolver,
            List <LinkError> linkErrors
            )
        {
            Linker linker = new Linker(linkErrors);

            SetupLinkerWithInteropResolver(linker, resolver);
            ILModule compiledModule = Compile(parsedModule);

            linker.AddModule(compiledModule, export: true);

            VMModule linkedModule = linker.Link();

            if (linkErrors.Count > 0)
            {
                return(null);
            }

            return(linkedModule);
        }
Example #7
0
        public static void Main(string[] args)
        {
            bool          isInteractive      = false;
            bool          showLex            = false;
            bool          showAst            = false;
            bool          showIl             = false;
            bool          withDebugger       = false;
            bool          forceCodegen       = false;
            bool          run                = true;
            List <string> positionals        = new List <string>();
            List <int>    argsToPass         = new List <int>();
            List <string> libraryNames       = new List <string>();
            List <string> librarySearchPaths = new List <string>();

            for (int i = 0, ilen = args.Length; i < ilen; ++i)
            {
                string arg      = args[i].Trim();
                bool   argFound = true;

                switch (arg)
                {
                case "-i":
                    isInteractive = true;
                    break;

                case "--showlex":
                    showLex = true;
                    break;

                case "--showast":
                    showAst = true;
                    break;

                case "--showil":
                    showIl = true;
                    break;

                case "-a":
                    int argToPass;
                    Int32.TryParse(args[++i], out argToPass);
                    argsToPass.Add(argToPass);
                    break;

                case "-l":
                    libraryNames.Add(args[++i]);
                    break;

                case "-L":
                    librarySearchPaths.Add(args[++i]);
                    break;

                case "--debugger":
                    withDebugger = true;
                    break;

                case "--force-codegen":
                    // Indicate that the compiler should attempt to code gen IL, even if the parse stage failed.
                    // This can be helpful to diagnose generated IL for code that doesn't compile outside of a
                    // specific project due to undefined references. The parser tries its hardest to produce a
                    // usable AST, even if there are semantic errors. Syntax errors? Not so much.
                    forceCodegen = true;
                    break;

                case "--skip-run":
                    run = false;
                    break;

                default:
                    argFound = false;
                    break;
                }

                if (!argFound)
                {
                    if (!arg.Contains("-"))
                    {
                        positionals.Add(arg);
                    }
                }
            }

            InteropResolver    interopResolver = new InteropResolver();
            const BindingFlags bindingFlags    = BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static;

            foreach (string libraryName in libraryNames)
            {
                Assembly lib = LoadAssembly(libraryName, librarySearchPaths);
                interopResolver.ImportAssembly(lib, bindingFlags);
            }

            List <ParseModule> parseModules = new List <ParseModule>(positionals.Count);
            List <ParseError>  errors       = new List <ParseError>();

            void ParseTokens(string?filename, List <Token> tokens)
            {
                Parser      parser = new Parser();
                ParseModule module = parser.Parse(filename, tokens, errors);

                parseModules.Add(module);
            }

            if (positionals.Count > 0)
            {
                // File mode - parse one or more files into ParseModules
                for (int i = 0, ilen = positionals.Count; i < ilen; ++i)
                {
                    string filename = positionals[i];

                    Lexer        lexer  = new Lexer();
                    List <Token> tokens = new List <Token>();

                    string?input;

                    filename = Path.GetFullPath(filename);
                    using StreamReader reader = new StreamReader(filename);
                    while ((input = reader.ReadLine()) != null)
                    {
                        LexLine(input, lexer, tokens, verbose: showLex);
                    }

                    lexer.FinishLex(tokens);

                    ParseTokens(filename, tokens);
                }
            }
            else
            {
                // Interactive or StdIn mode - parse exactly one ParseModule
                Lexer        lexer  = new Lexer();
                List <Token> tokens = new List <Token>();

                string?input;

                if (isInteractive)
                {
                    WritePrompt();
                    while ((input = Console.ReadLine()) != null)
                    {
                        LexLine(input, lexer, tokens, verbose: showLex);
                        WritePrompt();
                    }
                }
                else
                {
                    while ((input = Console.In.ReadLine()) != null)
                    {
                        LexLine(input, lexer, tokens, verbose: showLex);
                    }
                }

                lexer.FinishLex(tokens);

                ParseTokens(null, tokens);
            }

            List <LinkError> linkErrors = new List <LinkError>();
            Linker           linker     = new Linker(linkErrors);

            SemanticAnalyzer analyzer = new SemanticAnalyzer(errors);

            List <SemanticModule> semanticModules = new List <SemanticModule>(parseModules.Count);

            analyzer.Register(interopResolver.CreateHeaderModule());

            foreach (ParseModule module in parseModules)
            {
                analyzer.Register(module);
            }

            foreach (ParseModule module in parseModules)
            {
                semanticModules.Add(analyzer.Process(module));

                if (showAst)
                {
                    PrintTreeVisitor treeVisitor = new PrintTreeVisitor(Console.Out);
                    foreach (StructNode structNode in module.Structs)
                    {
                        structNode.AcceptTopLevelVisitor(treeVisitor);
                    }
                    foreach (FunctionDefinitionNode function in module.Functions)
                    {
                        function.AcceptTopLevelVisitor(treeVisitor);
                    }
                }
            }

            for (int i = 0, ilen = errors.Count; i < ilen; ++i)
            {
                ParseError error = errors[i];
                Console.Error.WriteLine($"{error.Start.Line + 1},{error.Start.Column + 1}: {error.Message}");
            }

            if (errors.Count > 0 && !forceCodegen)
            {
                Environment.Exit(1);
            }

            foreach (SemanticModule module in semanticModules)
            {
                CodeGenerator generator = new CodeGenerator(module, analyzer.Context);
                ILModule      ilmodule  = generator.Generate();
                if (showIl)
                {
                    ilmodule.WriteListing(Console.Out);
                }

                linker.AddModule(ilmodule, export: true);
            }

            foreach (Binding binding in interopResolver.Bindings)
            {
                linker.AddFunctionBinding(binding.Prototype.Name, binding.Implementation, export: false);
            }

            VMModule vmModule = linker.Link();

            if (linkErrors.Count > 0)
            {
                foreach (LinkError error in linkErrors)
                {
                    Console.Error.WriteLine($"Link error: {error.Message}");
                }

                Environment.Exit(1);
            }

            List <string> loadErrors = new List <string>();

            if (!interopResolver.PrepareForExecution(vmModule, loadErrors))
            {
                foreach (string error in loadErrors)
                {
                    Console.Error.WriteLine($"Load error: {error}");
                }

                Environment.Exit(1);
            }

            if (!run)
            {
                Environment.Exit(0);
                return;
            }

            using VirtualMachine vm = new VirtualMachine();

            if (withDebugger)
            {
                Debugger   debugger   = new Debugger();
                VMDebugger vmDebugger = new VMDebugger(debugger, vm);
                vmDebugger.Break += () => HandleBreak(vm, debugger, vmDebugger);
                vmDebugger.Pause();
            }

            // TODO: Args to pass is broken
            if (!vm.Call(vmModule, "main", new byte[0], success => HandleExecutionFinished(vm, success)))
            {
                Console.Error.WriteLine("Failed to call main function.");
                Environment.Exit(-1);
            }
        }