Ejemplo n.º 1
0
        public async Task <Tuple <string, Project> > CompileProject(string projectFile)
        {
            var projectFileInfo = new FileInfo(projectFile);
            var projectFolder   = projectFileInfo.Directory.FullName;

            // These two lines are just a weird hack because you get no files back from compilation.SyntaxTrees
            // if the user file isn't modified.  Not sure why that's happening.
//            var projectUserFile = projectFolder + "\\" + projectFileInfo.Name + ".user";
//            if (File.Exists(projectUserFile))
//                File.SetLastWriteTime(projectUserFile, DateTime.Now);

            var jsCompilationUnit = new JsCompilationUnit {
                UseStrict = true
            };
            var workspace = MSBuildWorkspace.Create();
            var project   = await Profiler.Time("Loading Project", async() =>
            {
                string mscorlib = this.mscorlib;
                if (mscorlib == null)
                {
                    mscorlib = FileUtils.GetWootzJsTargetFile(projectFile);
                }
                Project result;
                if (mscorlib != null)
                {
                    var mscorlibProject = await workspace.OpenProjectAsync(mscorlib);
                    result = await workspace.OpenProjectAsync(projectFile);
                    result = result.AddProjectReference(new ProjectReference(mscorlibProject.Id));
                    result = result.RemoveMetadataReference(result.MetadataReferences.Single(x => x.Display.Contains("mscorlib.dll")));
                }
                else
                {
                    result = await workspace.OpenProjectAsync(projectFile);
                }

                return(result);
            });

            var projectCompiler = new ProjectCompiler(project, jsCompilationUnit, defines);
            await projectCompiler.Compile();

            // Write out the compiled Javascript file to the target location.
            var renderer = new JsRenderer();

//            renderer.Builder.IsCompacting = true;
            Profiler.Time("Rendering javascript", () => jsCompilationUnit.Accept(renderer));

            return(Tuple.Create(renderer.Output, project));
        }
Ejemplo n.º 2
0
        public async Task <Tuple <string, Project> > Compile(string projectFile)
        {
            var projectFileInfo = new FileInfo(projectFile);
            var projectFolder   = projectFileInfo.Directory.FullName;

            // These two lines are just a weird hack because you get no files back from compilation.SyntaxTrees
            // if the user file isn't modified.  Not sure why that's happening.
            var projectUserFile = projectFolder + "\\" + projectFileInfo.Name + ".user";

            if (File.Exists(projectUserFile))
            {
                File.SetLastWriteTime(projectUserFile, DateTime.Now);
            }

            var project = await MSBuildWorkspace.Create().OpenProjectAsync(projectFile);

            var         projectName = project.AssemblyName;
            Compilation compilation = await project.GetCompilationAsync();

            Context.Update(project.Solution, project, compilation);

            // Check for yield
            foreach (var syntaxTree in compilation.SyntaxTrees)
            {
                var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
                var semanticModel   = compilation.GetSemanticModel(syntaxTree);
                var yieldGenerator  = new YieldGenerator(compilation, syntaxTree, semanticModel);
                compilationUnit = (CompilationUnitSyntax)compilationUnit.Accept(yieldGenerator);
                compilation     = compilation.ReplaceSyntaxTree(syntaxTree, SyntaxFactory.SyntaxTree(compilationUnit, syntaxTree.FilePath));
            }
            compilation = compilation.Clone();
            Context.Update(project.Solution, project, compilation);

            // After the basic transformation happens, we need to fix up some references afterward
            foreach (var syntaxTree in compilation.SyntaxTrees)
            {
                var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
                var semanticModel   = compilation.GetSemanticModel(syntaxTree);
                var yieldFixer      = new YieldGeneratorFixer(compilation, syntaxTree, semanticModel);
                compilationUnit = (CompilationUnitSyntax)compilationUnit.Accept(yieldFixer);
                compilation     = compilation.ReplaceSyntaxTree(syntaxTree, SyntaxFactory.SyntaxTree(compilationUnit, syntaxTree.FilePath));
            }
            Context.Update(project.Solution, project, compilation);

            // Check for async
            foreach (var syntaxTree in compilation.SyntaxTrees)
            {
                var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
                var semanticModel   = compilation.GetSemanticModel(syntaxTree);
                var asyncGenerator  = new AsyncGenerator(compilation, syntaxTree, semanticModel);
                compilationUnit = (CompilationUnitSyntax)compilationUnit.Accept(asyncGenerator);
                compilation     = compilation.ReplaceSyntaxTree(syntaxTree, SyntaxFactory.SyntaxTree(compilationUnit, syntaxTree.FilePath));
            }
            Context.Update(project.Solution, project, compilation);

            var jsCompilationUnit = new JsCompilationUnit {
                UseStrict = true
            };

            // If this is the runtime prjoect, declare the array to hold all the GetAssembly functions (this .js file
            // will be loaded first, and we only want to bother creating the array once.
            if (projectName == "mscorlib")
            {
                var assemblies = Js.Variable(SpecialNames.Assemblies, Js.Array());
                jsCompilationUnit.Body.Local(assemblies);

                // This ensures that Function.$typeName returns `Function` -- this is important when using
                // a type function as a generic argument, since otherwise when we try to assembly a
                // unique key for the permuatation of type args including a type function, we would get
                // an empty string for that arg, which would break the cache.
                jsCompilationUnit.Body.Assign(Js.Reference("Function").Member(SpecialNames.TypeName), Js.Primitive("Function"));
            }

            // Declare assembly variable
            var assemblyVariable = Js.Variable("$" + projectName.MaskSpecialCharacters() + "$Assembly", Js.Null());

            jsCompilationUnit.Body.Local(assemblyVariable);

            // Declare array to store all anonymous types
            var anonymousTypes = Js.Variable(compilation.Assembly.GetAssemblyAnonymousTypesArray(), Js.Array());

            jsCompilationUnit.Body.Local(anonymousTypes);

            // Declare array to store all the type functions in the assembly
            var assemblyTypes = Js.Variable(compilation.Assembly.GetAssemblyTypesArray(), Js.Array());

            jsCompilationUnit.Body.Local(assemblyTypes);

            // Build $GetAssemblyMethod, which lazily creates a new Assembly instance
            var globalIdioms = new Idioms(null);
            var getAssembly  = Js.Function();

            getAssembly.Body.If(
                assemblyVariable.GetReference().EqualTo(Js.Null()),
                assemblyVariable.GetReference().Assign(globalIdioms.CreateAssembly(compilation.Assembly, assemblyTypes.GetReference()))
                );
            getAssembly.Body.Return(assemblyVariable.GetReference());
            jsCompilationUnit.Body.Assign(
                Js.Reference(compilation.Assembly.GetAssemblyMethodName()),
                getAssembly);

            // Add $GetAssemblyMethod to global assemblies array
            jsCompilationUnit.Body.Express(Js.Reference("$assemblies").Member("push").Invoke(Js.Reference(compilation.Assembly.GetAssemblyMethodName())));

            // Builds out all the namespace objects.  Types live inside namepsaces, which are represented as
            // nested Javascript objects.  For example, System.Text.StringBuilder is represented (in part) as:
            //
            // System = {};
            // System.Text = {};
            // System.Text.StringBuilder = function() { ... }
            //
            // This allows access to classes using dot notation in the expected way.
            var namespaceTransformer = new NamespaceTransformer(jsCompilationUnit.Body);

            foreach (var syntaxTree in compilation.SyntaxTrees)
            {
                var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
                compilationUnit.Accept(namespaceTransformer);
            }

            var actions = new List <Tuple <INamedTypeSymbol, Action> >();

            // Scan all syntax trees for anonymous type creation expressions.  We transform them into class
            // declarations with a series of auto implemented properties.
            var anonymousTypeTransformer = new AnonymousTypeTransformer(jsCompilationUnit.Body, actions);

            foreach (var syntaxTree in compilation.SyntaxTrees)
            {
                var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
                compilationUnit.Accept(anonymousTypeTransformer);
            }

            var diagnostics = compilation.GetDiagnostics();

            foreach (var diagnostic in diagnostics)
            {
                Console.WriteLine("// " + diagnostic);
            }

            // Iterate through all the syntax trees and add entries into `actions` that correspond to type
            // declarations.
            foreach (var syntaxTree in compilation.SyntaxTrees)
            {
                var semanticModel   = compilation.GetSemanticModel(syntaxTree);
                var compilationUnit = (CompilationUnitSyntax)syntaxTree.GetRoot();
                var transformer     = new JsTransformer(syntaxTree, semanticModel);

                var typeDeclarations = GetTypeDeclarations(compilationUnit);
                foreach (var type in typeDeclarations)
                {
                    Action action = () =>
                    {
                        var statements = (JsBlockStatement)type.Accept(transformer);
                        jsCompilationUnit.Body.Aggregate(statements);
                    };
                    actions.Add(Tuple.Create((INamedTypeSymbol)ModelExtensions.GetDeclaredSymbol(semanticModel, type), action));
                }
                var delegateDeclarations = GetDelegates(compilationUnit);
                foreach (var type in delegateDeclarations)
                {
                    Action action = () =>
                    {
                        var statements = (JsBlockStatement)type.Accept(transformer);
                        jsCompilationUnit.Body.Aggregate(statements);
                    };
                    actions.Add(Tuple.Create((INamedTypeSymbol)ModelExtensions.GetDeclaredSymbol(semanticModel, type), action));
                }
            }

            // Sort all the type declarations such that base types always come before subtypes.
            SweepSort(actions);
            foreach (var item in actions)
            {
                item.Item2();
            }

            // If the project type is a console application, then invoke the Main method at the very
            // end of the file.
            var entryPoint = compilation.GetEntryPoint(CancellationToken.None);

            if (entryPoint != null)
            {
                jsCompilationUnit.Body.Express(globalIdioms.InvokeStatic(entryPoint));
            }

            // Test minification
//            var minifier = new JsMinifier();
//            jsCompilationUnit.Accept(minifier);

            // Write out the compiled Javascript file to the target location.
            var renderer = new JsRenderer();

            jsCompilationUnit.Accept(renderer);
            return(Tuple.Create(renderer.Output, project));
        }
Ejemplo n.º 3
0
        public async Task <Tuple <string, Solution> > CompileSolution(string solutionFile)
        {
//            var solution = await Profiler.Time("Loading Project", async () => await MSBuildWorkspace.Create().OpenSolutionAsync(solutionFile));
            var jsCompilationUnit = new JsCompilationUnit {
                UseStrict = true
            };

            // Since we have all the types required by the solution, we can keep track of which symbols are used and which
            // are not.  This of course means depending on reflection where you don't reference the actual symbol in code
            // will result in unexpected behavior.
            RemoveUnusedSymbols = true;

            var projectFiles = FileUtils.GetProjectFiles(solutionFile);
            var workspace    = MSBuildWorkspace.Create();
            var solution     = await Profiler.Time("Loading Solution", async() =>
            {
                string mscorlib = this.mscorlib;
                if (mscorlib == null)
                {
                    mscorlib = projectFiles.Select(x => FileUtils.GetWootzJsTargetFile(x)).First();
                }
                Solution result = workspace.CurrentSolution;
                if (mscorlib != null)
                {
                    var mscorlibProject = await workspace.OpenProjectAsync(mscorlib);
//                    result = result.AddProject(mscorlibProject.Id, mscorlibProject.Name, mscorlibProject.AssemblyName, mscorlibProject.Language);
                    foreach (var projectFile in projectFiles)
                    {
                        var project = result.Projects.SingleOrDefault(x => x.FilePath.Equals(projectFile, StringComparison.InvariantCultureIgnoreCase));
                        if (project == null)
                        {
                            project = await workspace.OpenProjectAsync(projectFile);
                        }
//                        result = result.AddProject(project.Id, project.Name, project.AssemblyName, project.Language);
//                        project = result.GetProject(project.Id);
                        project = project.AddProjectReference(new ProjectReference(mscorlibProject.Id));
                        project = project.RemoveMetadataReference(project.MetadataReferences.Single(x => x.Display.Contains("mscorlib.dll")));
                        result  = project.Solution;
                    }
                }
                else
                {
                    result = await workspace.OpenSolutionAsync(solutionFile);
                }
                return(result);
            });

            var projectCompilers = SortProjectsByDependencies(solution).Select(x => new ProjectCompiler(x, jsCompilationUnit, defines)).ToArray();

            foreach (var compiler in projectCompilers)
            {
                await compiler.Compile();
            }

            // Write out the compiled Javascript file to the target location.
            var renderer = new JsRenderer();

            Profiler.Time("Rendering javascript", () => jsCompilationUnit.Accept(renderer));

//            solution.Projects
            return(Tuple.Create(renderer.Output, solution));
        }