public void Test(string input, bool isValid)
        {
            var temp1 = Path.GetTempFileName();

            var fn1 = Path.ChangeExtension(temp1, ".fsx");


            File.WriteAllText(fn1, input);
            var           fn2     = Path.ChangeExtension(temp1, ".dll");
            FSharpChecker checker = FSharpChecker.Create(FSharpOption <int> .None,
                                                         FSharpOption <bool> .None,
                                                         FSharpOption <bool> .None,
                                                         FSharpOption <ReferenceResolver.Resolver> .None,
                                                         FSharpOption <FSharpFunc <Tuple <string, DateTime>,
                                                                                   FSharpOption <Tuple <object, IntPtr, int> > > > .None,
                                                         FSharpOption <bool> .None);
            var result = checker.CompileToDynamicAssembly(new[] { "-o", fn2, "-a", fn1 },
                                                          FSharpOption <Tuple <TextWriter, TextWriter> > .None, FSharpOption <string> .None);
            var t = Microsoft.FSharp.Control.FSharpAsync.RunSynchronously(result, FSharpOption <int> .None,
                                                                          FSharpOption <CancellationToken> .None);

            if (isValid)
            {
                t.Item1.Should().BeNullOrEmpty();
            }
            else
            {
                t.Item1.Should().NotBeNullOrEmpty();
            }
        }
예제 #2
0
        public FSharpSession(string text, MirrorSharpFSharpOptions options)
        {
            _text = text;

            Checker = FSharpChecker.Create(
                null,
                keepAssemblyContents: true,
                keepAllBackgroundResolutions: true,
                legacyReferenceResolver: null
                );
            AssemblyReferencePaths             = options.AssemblyReferencePaths;
            AssemblyReferencePathsAsFSharpList = ToFSharpList(options.AssemblyReferencePaths);
            ProjectOptions = new FSharpProjectOptions(
                "_",
                sourceFiles: new[] { "_.fs" },
                otherOptions: ConvertToOtherOptions(options),
                referencedProjects: Array.Empty <Tuple <string, FSharpProjectOptions> >(),
                isIncompleteTypeCheckEnvironment: true,
                useScriptResolutionRules: false,
                loadTime: DateTime.Now,
                unresolvedReferences: null,
                originalLoadReferences: FSharpList <Tuple <Range.range, string> > .Empty,
                extraProjectInfo: null,
                stamp: null
                );
        }
예제 #3
0
        private FsharpFolderComposite FindProjectFilesUsingBuildalyzer(IAnalyzerResult analyzerResult)
        {
            var inputFiles          = new FsharpFolderComposite();
            var projectUnderTestDir = Path.GetDirectoryName(analyzerResult.ProjectFilePath);
            var projectRoot         = Path.GetDirectoryName(projectUnderTestDir);
            var rootFolderComposite = new FsharpFolderComposite()
            {
                FullPath     = projectRoot,
                RelativePath = string.Empty
            };
            var cache = new Dictionary <string, FsharpFolderComposite> {
                [string.Empty] = rootFolderComposite
            };

            // Save cache in a singleton so we can use it in other parts of the project
            FolderCompositeCache <FsharpFolderComposite> .Instance.Cache = cache;

            inputFiles.Add(rootFolderComposite);

            var fSharpChecker = FSharpChecker.Create(projectCacheSize: null, keepAssemblyContents: null, keepAllBackgroundResolutions: null, legacyReferenceResolver: null, tryGetMetadataSnapshot: null, suggestNamesForErrors: null, keepAllBackgroundSymbolUses: null, enableBackgroundItemKeyStoreAndSemanticClassification: null);

            foreach (var sourceFile in analyzerResult.SourceFiles)
            {
                // Skip xamarin UI generated files
                if (sourceFile.EndsWith(".xaml.cs"))
                {
                    continue;
                }

                var relativePath    = Path.GetRelativePath(projectUnderTestDir, sourceFile);
                var folderComposite = GetOrBuildFolderComposite(cache, Path.GetDirectoryName(relativePath), projectUnderTestDir, projectRoot, inputFiles);
                var fileName        = Path.GetFileName(sourceFile);

                var file = new FsharpFileLeaf()
                {
                    SourceCode   = FileSystem.File.ReadAllText(sourceFile),
                    RelativePath = FileSystem.Path.Combine(folderComposite.RelativePath, fileName),
                    FullPath     = sourceFile
                };

                // Get the syntax tree for the source file
                Tuple <FSharpProjectOptions, FSharpList <FSharpErrorInfo> > fSharpOptions = FSharpAsync.RunSynchronously(fSharpChecker.GetProjectOptionsFromScript(filename: file.FullPath, sourceText: SourceText.ofString(file.SourceCode), previewEnabled: null, loadedTimeStamp: null, otherFlags: null, useFsiAuxLib: null, useSdkRefs: null, assumeDotNetFramework: null, extraProjectInfo: null, optionsStamp: null, userOpName: null), timeout: null, cancellationToken: null);
                FSharpParseFileResults result = FSharpAsync.RunSynchronously(fSharpChecker.ParseFile(fileName, SourceText.ofString(file.SourceCode), fSharpChecker.GetParsingOptionsFromProjectOptions(fSharpOptions.Item1).Item1, userOpName: null), timeout: null, cancellationToken: null);

                if (result.ParseTree.Value.IsImplFile)
                {
                    var syntaxTree = (ImplFile)result.ParseTree.Value;

                    file.SyntaxTree = syntaxTree;
                    folderComposite.Add(file);
                }
                else
                {
                    var message = $"Cannot make Fsharp SyntaxTree from .fsi filetype (SyntaxTree.ParsedImplFileInput class wanted)";
                    throw new InputException(message);
                }
            }
            return(inputFiles);
        }
예제 #4
0
        private (bool, FSharpErrorInfo[]) TryCompilation(FSharpChecker checker, FSharpList <ParsedInput> trees, List <string> pathlist, FSharpList <string> dependencies)
        {
            Tuple <FSharpErrorInfo[], int> result = FSharpAsync.RunSynchronously(
                checker.Compile(
                    trees, AssemblyName, pathlist.First(), dependencies, pdbFile: null, executable: false, noframework: true, userOpName: null), timeout: null, cancellationToken: null);

            return(result.Item2 == 0, result.Item1);
        }
예제 #5
0
        internal FSharpAssembly(FSharpCompilerOptionsBuilder builder, FSharpChecker checker)
        {
            var args = builder.ToArray();

            var task = checker.CompileToDynamicAssembly(
                args,
                FSharpOption <Tuple <TextWriter, TextWriter> > .None,
                FSharpOption <string> .None);

            var result = FSharpAsync.RunSynchronously(task, default, default);
예제 #6
0
        public CompilingProcessResult Compile(IEnumerable <ParsedInput> syntaxTrees, bool devMode)
        {
            var analyzerResult = _input.ProjectInfo.ProjectUnderTestAnalyzerResult;

            FSharpList <ParsedInput> trees        = ListModule.OfSeq(syntaxTrees.Reverse());
            FSharpList <string>      dependencies = ListModule.OfSeq(analyzerResult.References);

            //we need a checker if we want to compile
            var checker = FSharpChecker.Create(projectCacheSize: null, keepAssemblyContents: null, keepAllBackgroundResolutions: null, legacyReferenceResolver: null, tryGetMetadataSnapshot: null, suggestNamesForErrors: null, keepAllBackgroundSymbolUses: null, enableBackgroundItemKeyStoreAndSemanticClassification: null);

            var pathlist = new List <string>();
            var pdblist  = new List <string>();

            foreach (var testProject in _input.ProjectInfo.TestProjectAnalyzerResults)
            {
                var injectionPath = _input.ProjectInfo.GetInjectionFilePath(testProject);
                if (!_fileSystem.Directory.Exists(injectionPath.Substring(0, injectionPath.LastIndexOf('\\'))))
                {
                    _fileSystem.Directory.CreateDirectory(injectionPath);
                }

                pathlist.Add(Path.Combine(injectionPath, _input.ProjectInfo.GetInjectionFilePath(testProject)));

                pdblist.Add(Path.Combine(injectionPath,
                                         _input.ProjectInfo.ProjectUnderTestAnalyzerResult.GetSymbolFileName()));

                _logger.LogDebug("Injected the mutated assembly file into {0}", injectionPath);
            }
            if (!pathlist.Any())
            {
                throw new GeneralStrykerException("Could not find project under test.");
            }

            //rollback still needs to be implemented
            RollbackProcessResult rollbackProcessResult = null;

            (var compilationSucces, FSharpErrorInfo[] errorinfo) = TryCompilation(checker, trees, pathlist, dependencies);

            if (compilationSucces)
            {
                //we return if compiled succesfully
                //it is however not used as this is the end of the current F# implementation
                return(new CompilingProcessResult()
                {
                    Success = compilationSucces,
                    RollbackResult = rollbackProcessResult
                });
            }

            // compiling failed
            _logger.LogError("Failed to restore the project to a buildable state. Please report the issue. Stryker can not proceed further");
            throw new CompilationException("Failed to restore build able state.");
        }
예제 #7
0
        /// <summary>
        /// Recursively scans the given directory for files to mutate
        /// </summary>
        private FsharpFolderComposite FindInputFiles(string path, string projectUnderTestDir, string parentFolder)
        {
            var lastPathComponent = Path.GetFileName(path);

            var folderComposite = new FsharpFolderComposite
            {
                FullPath     = Path.GetFullPath(path),
                RelativePath = Path.Combine(parentFolder, lastPathComponent),
            };

            foreach (var folder in FileSystem.Directory.EnumerateDirectories(folderComposite.FullPath).Where(x => !_foldersToExclude.Contains(Path.GetFileName(x))))
            {
                folderComposite.Add(FindInputFiles(folder, projectUnderTestDir, folderComposite.RelativePath));
            }
            var fSharpChecker = FSharpChecker.Create(projectCacheSize: null, keepAssemblyContents: null, keepAllBackgroundResolutions: null, legacyReferenceResolver: null, tryGetMetadataSnapshot: null, suggestNamesForErrors: null, keepAllBackgroundSymbolUses: null, enableBackgroundItemKeyStoreAndSemanticClassification: null);

            foreach (var file in FileSystem.Directory.GetFiles(folderComposite.FullPath, "*.fs", SearchOption.TopDirectoryOnly))
            {
                var fileName = Path.GetFileName(file);

                var fileLeaf = new FsharpFileLeaf()
                {
                    SourceCode   = FileSystem.File.ReadAllText(file),
                    RelativePath = Path.Combine(folderComposite.RelativePath, fileName),
                    FullPath     = file,
                };

                // Get the syntax tree for the source file
                Tuple <FSharpProjectOptions, FSharpList <FSharpErrorInfo> > fsharpoptions = FSharpAsync.RunSynchronously(fSharpChecker.GetProjectOptionsFromScript(fileLeaf.FullPath, SourceText.ofString(fileLeaf.SourceCode), previewEnabled: null, loadedTimeStamp: null, otherFlags: null, useFsiAuxLib: null, useSdkRefs: null, assumeDotNetFramework: null, extraProjectInfo: null, optionsStamp: null, userOpName: null), timeout: null, cancellationToken: null);
                FSharpParseFileResults result = FSharpAsync.RunSynchronously(fSharpChecker.ParseFile(fileLeaf.FullPath, SourceText.ofString(fileLeaf.SourceCode), fSharpChecker.GetParsingOptionsFromProjectOptions(fsharpoptions.Item1).Item1, userOpName: null), timeout: null, cancellationToken: null);

                if (result.ParseTree.Value.IsImplFile)
                {
                    var syntaxTree = (ImplFile)result.ParseTree.Value;

                    fileLeaf.SyntaxTree = syntaxTree;

                    folderComposite.Add(fileLeaf);
                }
                else
                {
                    var message = $"Cannot make Fsharp SyntaxTree from .fsi filetype (SyntaxTree.ParsedImplFileInput class wanted)";
                    throw new InputException(message);
                }
            }

            return(folderComposite);
        }
    protected override async Task Compile(
        string code,
        string[] references)
    {
        var sourcePath = Path.GetTempFileName() + ".fs";

        File.WriteAllText(sourcePath, code);

        var compilerArgs =
            new[] {
            "fsc",
            sourcePath,
            $"--out:{FileName}",
            $"--pdb:{PdbName}",
            $"--lib:\"{BasePath}\"",
            "--debug",
            "--target:library"
        }
        .Concat(GetStandardReferences().Concat(references).Select(r => $"--reference:{r}"))
        .ToArray();

        var checker = FSharpChecker.Create(
            FSharpOption <int> .None,
            FSharpOption <bool> .None,
            FSharpOption <bool> .None,
#pragma warning disable CS0618
            FSharpOption <LegacyReferenceResolver> .None,
#pragma warning restore CS0618
            FSharpOption <FSharpFunc <Tuple <string, DateTime>, FSharpOption <Tuple <object, IntPtr, int> > > > .None,
            FSharpOption <bool> .None,
            FSharpOption <bool> .None,
            FSharpOption <bool> .None,
            FSharpOption <bool> .None
            );

        var resultFSharpAsync = checker.Compile(compilerArgs, FSharpOption <string> .None);
        var result            = await FSharpAsync.StartAsTask(resultFSharpAsync, FSharpOption <TaskCreationOptions> .None, FSharpOption <CancellationToken> .None);

        if (result.Item2 != 0)
        {
            var errors =
                result
                .Item1
                .Select(e => $"{e.FileName}({e.StartLine},{e.StartColumn}): {(e.Severity.IsError ? "error" : "warning")} {e.ErrorNumber}: {e.Message}");

            throw new InvalidOperationException($"Compilation Failed:{Environment.NewLine}{string.Join(Environment.NewLine, errors)}");
        }
    }
예제 #9
0
        public static Assembly Compile(string source)
        {
            var fileHelpersAssembly = typeof(EngineBase).Assembly;

            var checker = FSharpChecker.Create(
                FSharpOption <int> .None,
                FSharpOption <bool> .None,
                FSharpOption <bool> .None,
                FSharpOption <LegacyReferenceResolver> .None,
                FSharpOption <FSharpFunc <Tuple <string, DateTime>, FSharpOption <Tuple <object, IntPtr, int> > > > .None,
                FSharpOption <bool> .None,
                FSharpOption <bool> .None,
                FSharpOption <bool> .None,
                FSharpOption <bool> .None);

            var file = Path.GetTempFileName();

            File.WriteAllText(file + ".fs", source);

            var action = checker.CompileToDynamicAssembly(
                new[] { "-o", file + ".dll", "-a", file + ".fs", "--reference:" + fileHelpersAssembly.Location },
                FSharpOption <Tuple <TextWriter, TextWriter> > .None,
                FSharpOption <string> .None);

            var compileResult = FSharpAsync
                                .StartAsTask(action, FSharpOption <TaskCreationOptions> .None, FSharpOption <CancellationToken> .None)
                                .Result;

            var exitCode          = compileResult.Item2;
            var compilationErrors = compileResult.Item1;

            if (compilationErrors.Any() && exitCode != 0)
            {
                var errors = new StringBuilder();

                foreach (var error in compilationErrors)
                {
                    errors.AppendLine(error.ToString());
                }

                throw new InvalidOperationException($"Cannot compile fsharp: {errors}");
            }

            return(compileResult.Item3.Value);
        }
예제 #10
0
        static void Main(string[] args)
        {
            FSharpChecker fSharpChecker = FSharpChecker.Create(null, null, null, null, null, null, null, null);

            var fullPath   = Path.GetFullPath("..\\..\\..\\..\\..\\boolMutateTestApp\\boolMutateTestApp\\Program.fs");
            var sourceCode = File.ReadAllText(fullPath);

            Tuple <FSharpProjectOptions, FSharpList <FSharpErrorInfo> > fsharpoptions = FSharpAsync.RunSynchronously(fSharpChecker.GetProjectOptionsFromScript(fullPath, SourceText.ofString(sourceCode), null, null, null, null, null, null, null, null, null), null, null);
            FSharpParseFileResults result = FSharpAsync.RunSynchronously(fSharpChecker.ParseFile(fullPath, SourceText.ofString(sourceCode), fSharpChecker.GetParsingOptionsFromProjectOptions(fsharpoptions.Item1).Item1, null), null, null);
            var syntaxTree = result.ParseTree;

            if (syntaxTree.Value.IsImplFile)
            {
                var test = ((ImplFile)syntaxTree.Value).Item;
                VisitModulesAndNamespaces(test.modules);
            }
            else
            {
                Console.WriteLine("F# Interface file (*.fsi) not supported.");
            }
            //fSharpChecker.CompileToDynamicAssembly()
            //    FSharpAsync<Tuple<FSharpErrorInfo[], int>> Compile(FSharpList<SyntaxTree.ParsedInput> ast, string assemblyName, string outFile, FSharpList<string> dependencies, [OptionalArgument] FSharpOption<string> pdbFile, [OptionalArgument] FSharpOption<bool> executable, [OptionalArgument] FSharpOption<bool> noframework, [OptionalArgument] FSharpOption<string> userOpName);
        }
        public Task <IDotNetCompilation> GetFunctionCompilationAsync(FunctionMetadata functionMetadata)
        {
            // First use the C# compiler to resolve references, to get consistency with the C# Azure Functions programming model
            // Add the #r statements from the .fsx file to the resolver source
            string scriptSource          = GetFunctionSource(functionMetadata);
            var    resolverSourceBuilder = new StringBuilder();

            using (StringReader sr = new StringReader(scriptSource))
            {
                string line;

                while ((line = sr.ReadLine()) != null)
                {
                    if (_hashRRegex.IsMatch(line))
                    {
                        resolverSourceBuilder.AppendLine(line);
                    }
                }
            }

            resolverSourceBuilder.AppendLine("using System;");
            var resolverSource = resolverSourceBuilder.ToString();

            Script <object> script = CodeAnalysis.CSharp.Scripting.CSharpScript.Create(resolverSource, options: _metadataResolver.CreateScriptOptions(), assemblyLoader: AssemblyLoader.Value);

            var compiler = new SimpleSourceCodeServices(msbuildEnabled: FSharpOption <bool> .Some(false));

            FSharpErrorInfo[] errors        = null;
            byte[]            assemblyBytes = null;
            byte[]            pdbBytes      = null;

            string scriptPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

            Directory.CreateDirectory(scriptPath);

            string scriptFilePath = Path.Combine(scriptPath, Path.GetFileName(functionMetadata.ScriptFile));

            var assemblyName     = Utility.GetAssemblyNameFromMetadata(functionMetadata, Guid.NewGuid().ToString());
            var assemblyFileName = Path.Combine(scriptPath, assemblyName + ".dll");
            var pdbName          = Path.ChangeExtension(assemblyFileName, PlatformHelper.IsWindows ? "pdb" : "dll.mdb");

            try
            {
                var scriptFileBuilder = new StringBuilder();

                // Write an adjusted version of the script file, prefixing some 'open' declarations
                foreach (string import in script.Options.Imports)
                {
                    scriptFileBuilder.AppendLine("open " + import);
                }

                // Suppress undesirable warnings
                scriptFileBuilder.AppendLine("#nowarn \"988\"");

                // Set the line to match the original script
                scriptFileBuilder.AppendLine("# 0 @\"" + functionMetadata.ScriptFile + "\"");

                // Add our original script
                scriptFileBuilder.AppendLine(scriptSource);

                File.WriteAllText(scriptFilePath, scriptFileBuilder.ToString());

                var otherFlags = new List <string>();

                otherFlags.Add("fsc.exe");

                // The --noframework option is used because we will shortly add references to mscorlib and FSharp.Core
                // as dictated by the C# reference resolver, and F# doesn't like getting multiple references to those.
                otherFlags.Add("--noframework");

                var references = script.GetCompilation().References
                                 .Where(m => !(m is UnresolvedMetadataReference))
                                 .Select(m => "-r:" + m.Display)
                                 .Distinct(new FileNameEqualityComparer());

                // Add the references as reported by the metadata resolver.
                otherFlags.AddRange(references);

                if (_optimizationLevel == OptimizationLevel.Debug)
                {
                    otherFlags.Add("--optimize-");
                    otherFlags.Add("--debug+");
                    otherFlags.Add("--tailcalls-");
                }

                // TODO: FACAVAL verify if this still applies to core
                if (!PlatformHelper.IsWindows)
                {
                    var monoDir    = Path.GetDirectoryName(typeof(string).Assembly.Location);
                    var facadesDir = Path.Combine(monoDir, "Facades");
                    otherFlags.Add("--lib:" + facadesDir);
                }

                // If we have a private assembly folder, make sure the compiler uses it to resolve dependencies
                string privateAssembliesFolder = Path.Combine(Path.GetDirectoryName(functionMetadata.ScriptFile), DotNetConstants.PrivateAssembliesFolderName);
                if (Directory.Exists(privateAssembliesFolder))
                {
                    otherFlags.Add("--lib:" + Path.Combine(Path.GetDirectoryName(functionMetadata.ScriptFile), DotNetConstants.PrivateAssembliesFolderName));
                }

                otherFlags.Add("--out:" + assemblyFileName);

                // Get the #load closure
                FSharpChecker checker = FSharpChecker.Create(null, null, null, msbuildEnabled: FSharpOption <bool> .Some(false));
                var           loadFileOptionsAsync = checker.GetProjectOptionsFromScript(
                    filename: functionMetadata.ScriptFile,
                    source: scriptSource,
                    loadedTimeStamp: null,
                    otherFlags: null,
                    useFsiAuxLib: null,
                    assumeDotNetFramework: null,
                    extraProjectInfo: null);

                var loadFileOptions = FSharp.Control.FSharpAsync.RunSynchronously(loadFileOptionsAsync, null, null);
                foreach (var loadedFileName in loadFileOptions.Item1.ProjectFileNames)
                {
                    if (Path.GetFileName(loadedFileName) != Path.GetFileName(functionMetadata.ScriptFile))
                    {
                        otherFlags.Add(loadedFileName);
                    }
                }

                // Add the (adjusted) script file itself
                otherFlags.Add(scriptFilePath);

                // Compile the script to a static assembly
                var result = compiler.Compile(otherFlags.ToArray());
                errors = result.Item1;
                var code = result.Item2;

                if (code == 0)
                {
                    assemblyBytes = File.ReadAllBytes(assemblyFileName);
                    pdbBytes      = null;
                    if (File.Exists(pdbName))
                    {
                        pdbBytes = File.ReadAllBytes(pdbName);
                    }
                }
                else
                {
                    string message = $"F# compilation failed with arguments: {string.Join(" ", otherFlags)}";
                    _logger.LogDebug(message);
                }
            }
            finally
            {
                DeleteDirectoryAsync(scriptPath, recursive: true)
                .ContinueWith(
                    t => t.Exception.Handle(e =>
                {
                    string message = $"Unable to delete F# compilation file: {e.ToString()}";
                    _logger.LogWarning(message);
                    return(true);
                }), TaskContinuationOptions.OnlyOnFaulted);
            }

            return(Task.FromResult <IDotNetCompilation>(new FSharpCompilation(errors, assemblyBytes, pdbBytes)));
        }
예제 #12
0
        public ICompilation GetFunctionCompilation(FunctionMetadata functionMetadata)
        {
            // TODO: Get debug flag from context. Set to true for now.
            bool debug = true;

            // First use the C# compiler to resolve references, to get consistenct with the C# Azure Functions programming model
            Script <object> script      = CodeAnalysis.CSharp.Scripting.CSharpScript.Create("using System;", options: _metadataResolver.CreateScriptOptions(), assemblyLoader: AssemblyLoader.Value);
            Compilation     compilation = script.GetCompilation();

            var compiler = new SimpleSourceCodeServices();

            FSharpErrorInfo[]       errors         = null;
            FSharpOption <Assembly> assemblyOption = null;
            string scriptFilePath = Path.Combine(Path.GetTempPath(), Path.GetFileName(functionMetadata.ScriptFile));

            try
            {
                var scriptFileBuilder = new StringBuilder();

                // Write an adjusted version of the script file, prefixing some 'open' decarations
                foreach (string import in script.Options.Imports)
                {
                    scriptFileBuilder.AppendLine("open " + import);
                }

                // Suppress undesirable warnings
                scriptFileBuilder.AppendLine("#nowarn \"988\"");

                // Set the line to match the original script
                scriptFileBuilder.AppendLine("# 0 @\"" + functionMetadata.ScriptFile + "\"");

                // Add our original script
                string scriptSource = GetFunctionSource(functionMetadata);
                scriptFileBuilder.AppendLine(scriptSource);

                File.WriteAllText(scriptFilePath, scriptFileBuilder.ToString());

                var otherFlags = new List <string>();

                // For some reason CompileToDynamicAssembly wants "fsc.exe" as the first arg, it is ignored.
                otherFlags.Add("fsc.exe");

                // The --noframework option is used because we will shortly add references to mscorlib and FSharp.Core
                // as dictated by the C# reference resolver, and F# doesn't like getting multiple references to those.
                otherFlags.Add("--noframework");

                // Add the references as reported by the C# reference resolver.
                foreach (var mdr in compilation.References)
                {
                    if (!mdr.Display.Contains("Unresolved "))
                    {
                        otherFlags.Add("-r:" + mdr.Display);
                    }
                }

                // Above we have used the C# reference resolver to get the basic set of DLL references for the compilation.
                //
                // However F# has its own view on default options. For scripts these should include the
                // following framework facade references.

                otherFlags.Add("-r:System.Linq.dll");             // System.Linq.Expressions.Expression<T>
                otherFlags.Add("-r:System.Reflection.dll");       // System.Reflection.ParameterInfo
                otherFlags.Add("-r:System.Linq.Expressions.dll"); // System.Linq.IQueryable<T>
                otherFlags.Add("-r:System.Threading.Tasks.dll");  // valuetype [System.Threading.Tasks]System.Threading.CancellationToken
                otherFlags.Add("-r:System.IO.dll");               //  System.IO.TextWriter
                otherFlags.Add("-r:System.Net.Requests.dll");     //  System.Net.WebResponse etc.
                otherFlags.Add("-r:System.Collections.dll");      // System.Collections.Generic.List<T>
                otherFlags.Add("-r:System.Runtime.Numerics.dll"); // BigInteger
                otherFlags.Add("-r:System.Threading.dll");        // OperationCanceledException
                otherFlags.Add("-r:System.Runtime.dll");
                otherFlags.Add("-r:System.Numerics.dll");

                if (debug)
                {
                    otherFlags.Add("--optimize-");
                    otherFlags.Add("--debug+");
                    otherFlags.Add("--tailcalls-");
                }

                // This output DLL isn't actually written by FSharp.Compiler.Service when CompileToDynamicAssembly is called
                otherFlags.Add("--out:" + Path.ChangeExtension(Path.GetTempFileName(), "dll"));

                // Get the #load closure
                var loadFileOptionsAsync = FSharpChecker.Create().GetProjectOptionsFromScript(functionMetadata.ScriptFile, scriptSource, null, null, null);
                var loadFileOptions      = FSharp.Control.FSharpAsync.RunSynchronously(loadFileOptionsAsync, null, null);
                foreach (var loadedFileName in loadFileOptions.ProjectFileNames)
                {
                    if (Path.GetFileName(loadedFileName) != Path.GetFileName(functionMetadata.ScriptFile))
                    {
                        otherFlags.Add(loadedFileName);
                    }
                }

                // Add the (adjusted) script file itself
                otherFlags.Add(scriptFilePath);

                // Make the output streams (unused)
                var outStreams = FSharpOption <Tuple <TextWriter, TextWriter> > .Some(new Tuple <TextWriter, TextWriter>(Console.Out, Console.Error));

                // Compile the script to a dynamic assembly
                var result = compiler.CompileToDynamicAssembly(otherFlags: otherFlags.ToArray(), execute: outStreams);

                errors         = result.Item1;
                assemblyOption = result.Item3;
            }
            finally
            {
                File.Delete(scriptFilePath);
            }
            return(new FSharpCompilation(errors, assemblyOption));
        }
예제 #13
0
        void CompileToExe(string outputExe, string src, bool optimize = false, string target = "exe")
        {
            var checker = FSharpChecker.Create(
                FSharpOption <int> .None,
                FSharpOption <bool> .None,
                FSharpOption <bool> .None,
                FSharpOption <FSharp.Compiler.ReferenceResolver.Resolver> .None,
                FSharpOption <FSharpFunc <Tuple <string, DateTime>, FSharpOption <Tuple <object, IntPtr, int> > > > .None,
                FSharpOption <bool> .None,
                FSharpOption <bool> .None,
                FSharpOption <bool> .None);

            var tempSource = Environment.GetEnvironmentVariable("TEMP") + "/temp.fs";

            var args = new List <string>
            {
                "fsc.exe",
                "--nologo",
                "--crossoptimize" + (optimize ? "+" : "-"),
                "--optimize" + (optimize ? "+" : "-"),
                "-o", outputExe,
                "--target:" + target
            };

            if (optimize)
            {
                args.Add("--standalone");
            }

            var lines   = new List <string>();
            var loads   = new List <string>();
            var libDirs = new List <string>();

            // 提取#r、#I和#load
            using (var reader = new StringReader(src))
            {
                var references = new List <string>();

                while (reader.Peek() > 0)
                {
                    var line       = reader.ReadLine();
                    var lineTrimed = line.Trim();

                    if (lineTrimed.StartsWith("#r "))
                    {
                        references.Add(lineTrimed.Substring(2).Trim().Trim('\"').Trim());
                        lines.Add("");
                    }
                    else if (lineTrimed.StartsWith("#I "))
                    {
                        libDirs.Add("\"" + lineTrimed.Substring(2).Trim().Trim('\"').Trim() + "\"");
                        lines.Add("");
                    }
                    else if (lineTrimed.StartsWith("#load "))
                    {
                        loads.Add(lineTrimed.Substring(5).Trim().Trim('\"').Trim());
                        lines.Add("");
                    }
                    else
                    {
                        lines.Add(line);
                    }
                }

                if (libDirs.Count > 0)
                {
                    args.Add("-I:" + libDirs.Aggregate((a, b) =>
                    {
                        return(a + "," + b);
                    }));
                }

                if (references.Count > 0)
                {
                    if (!optimize)  // 因为在选定Optimized选项时已经具有了standalone选项,所以在此处需要补一个standalone选项
                    {
                        args.Add("--standalone");
                    }

                    foreach (var r in references)
                    {
                        args.Add("-r:" + r);

                        // 搜索dll并复制
                        var path = r.Trim().Trim('\"').Trim();
                        var n    = new FileInfo(path).Name;
                        if (!File.Exists(tempDir + n))
                        {
                            if (!File.Exists(path))
                            {
                                foreach (var dir in libDirs)
                                {
                                    var s = dir.Trim().Trim('\"').Trim() + "/" + path;
                                    if (File.Exists(s))
                                    {
                                        path = s;
                                        break;
                                    }
                                }
                            }

                            if (File.Exists(path))
                            {
                                File.Copy(path, tempDir + n);
                                waitForClean.Add(n);
                            }
                        }
                    }
                }
            }

            foreach (var load in loads)
            {
                var fileName = load;
                if (!File.Exists(fileName))
                {
                    foreach (var i in libDirs)
                    {
                        var s = i.Trim().Trim('\"').Trim() + "/" + fileName;
                        if (File.Exists(s))
                        {
                            fileName = s;
                            break;
                        }
                    }
                }
                var warpedFileName = "\"" + fileName + "\"";
                args.Add(warpedFileName);
            }

            File.WriteAllLines(tempSource, lines);
            args.Add("\"" + tempSource + "\"");

            var async = checker.Compile(
                args.ToArray(),
                FSharpOption <string> .None);

            var result = Microsoft.FSharp.Control.FSharpAsync.RunSynchronously(
                async,
                FSharpOption <int> .None,
                FSharpOption <System.Threading.CancellationToken> .None);

            File.Delete(tempSource);

            if (result.Item1.Length > 0)
            {
                Dispatcher.Invoke(() =>
                {
                    var sb = new StringBuilder();
                    foreach (var i in result.Item1)
                    {
                        sb
                        .Append('(')
                        .Append(i.Range.StartLine)
                        .Append(") ")
                        .Append("FS")
                        .Append(string.Format("{0:D4}", i.ErrorNumber))
                        .Append(':')
                        .AppendLine(i.Message);
                    }
                    Output.Text = sb.ToString();
                });
            }
        }
 public static async Task WarmUpAsync()
 {
     try
     {
         var fsasync = CodeFormatter.FormatDocumentAsync("tmp.fs", SourceOrigin.SourceOrigin.NewSourceString(SampleCode), FormatConfig.FormatConfig.Default, FSharpParsingOptions.Default, FSharpChecker.Create(null, null, null, null, null, null, null, null, null));
         var _       = await FSharpAsync.StartAsTask(fsasync, null, null);
     }
     catch (Exception ex)
     {
         Trace.TraceError(ex.ToString());
     }
 }
예제 #15
0
        public ICompilation GetFunctionCompilation(FunctionMetadata functionMetadata)
        {
            // First use the C# compiler to resolve references, to get consistency with the C# Azure Functions programming model
            // Add the #r statements from the .fsx file to the resolver source
            string scriptSource          = GetFunctionSource(functionMetadata);
            var    resolverSourceBuilder = new StringBuilder();

            using (StringReader sr = new StringReader(scriptSource))
            {
                string line;

                while ((line = sr.ReadLine()) != null)
                {
                    if (_hashRRegex.IsMatch(line))
                    {
                        resolverSourceBuilder.AppendLine(line);
                    }
                }
            }

            resolverSourceBuilder.AppendLine("using System;");
            var resolverSource = resolverSourceBuilder.ToString();

            Script <object> script      = CodeAnalysis.CSharp.Scripting.CSharpScript.Create(resolverSource, options: _metadataResolver.CreateScriptOptions(), assemblyLoader: AssemblyLoader.Value);
            Compilation     compilation = script.GetCompilation();

            var compiler = new SimpleSourceCodeServices(msbuildEnabled: FSharpOption <bool> .Some(false));

            FSharpErrorInfo[]       errors         = null;
            FSharpOption <Assembly> assemblyOption = null;
            string scriptFilePath = Path.Combine(Path.GetTempPath(), Path.GetFileName(functionMetadata.ScriptFile));

            var asmName = FunctionAssemblyLoader.GetAssemblyNameFromMetadata(functionMetadata, compilation.AssemblyName);
            var dllName = Path.GetTempPath() + asmName + ".dll";
            var pdbName = Path.ChangeExtension(dllName, "pdb");

            try
            {
                var scriptFileBuilder = new StringBuilder();

                // Write an adjusted version of the script file, prefixing some 'open' decarations
                foreach (string import in script.Options.Imports)
                {
                    scriptFileBuilder.AppendLine("open " + import);
                }

                // Suppress undesirable warnings
                scriptFileBuilder.AppendLine("#nowarn \"988\"");

                // Set the line to match the original script
                scriptFileBuilder.AppendLine("# 0 @\"" + functionMetadata.ScriptFile + "\"");

                // Add our original script
                scriptFileBuilder.AppendLine(scriptSource);

                File.WriteAllText(scriptFilePath, scriptFileBuilder.ToString());

                var otherFlags = new List <string>();

                // For some reason CompileToDynamicAssembly wants "fsc.exe" as the first arg, it is ignored.
                otherFlags.Add("fsc.exe");

                // The --noframework option is used because we will shortly add references to mscorlib and FSharp.Core
                // as dictated by the C# reference resolver, and F# doesn't like getting multiple references to those.
                otherFlags.Add("--noframework");

                // Add the references as reported by the C# reference resolver.
                foreach (var mdr in compilation.References)
                {
                    if (!mdr.Display.Contains("Unresolved "))
                    {
                        otherFlags.Add("-r:" + mdr.Display);
                    }
                }

                // Above we have used the C# reference resolver to get the basic set of DLL references for the compilation.
                //
                // However F# has its own view on default options. For scripts these should include the
                // following framework facade references.

                otherFlags.Add("-r:System.Linq.dll");             // System.Linq.Expressions.Expression<T>
                otherFlags.Add("-r:System.Reflection.dll");       // System.Reflection.ParameterInfo
                otherFlags.Add("-r:System.Linq.Expressions.dll"); // System.Linq.IQueryable<T>
                otherFlags.Add("-r:System.Threading.Tasks.dll");  // valuetype [System.Threading.Tasks]System.Threading.CancellationToken
                otherFlags.Add("-r:System.IO.dll");               //  System.IO.TextWriter
                otherFlags.Add("-r:System.Net.Requests.dll");     //  System.Net.WebResponse etc.
                otherFlags.Add("-r:System.Collections.dll");      // System.Collections.Generic.List<T>
                otherFlags.Add("-r:System.Runtime.Numerics.dll"); // BigInteger
                otherFlags.Add("-r:System.Threading.dll");        // OperationCanceledException
                otherFlags.Add("-r:System.Runtime.dll");
                otherFlags.Add("-r:System.Numerics.dll");

                if (_optimizationLevel == OptimizationLevel.Debug)
                {
                    otherFlags.Add("--optimize-");
                    otherFlags.Add("--debug+");
                    otherFlags.Add("--tailcalls-");
                }

                // If we have a private assembly folder, make sure the compiler uses it to resolve dependencies
                string privateAssembliesFolder = Path.Combine(Path.GetDirectoryName(functionMetadata.ScriptFile), DotNetConstants.PrivateAssembliesFolderName);
                if (Directory.Exists(privateAssembliesFolder))
                {
                    otherFlags.Add("--lib:" + Path.Combine(Path.GetDirectoryName(functionMetadata.ScriptFile), DotNetConstants.PrivateAssembliesFolderName));
                }

                otherFlags.Add("--out:" + dllName);

                // Get the #load closure
                FSharpChecker checker = FSharpChecker.Create(null, null, null, msbuildEnabled: FSharpOption <bool> .Some(false));
                var           loadFileOptionsAsync = checker.GetProjectOptionsFromScript(functionMetadata.ScriptFile, scriptSource, null, null, null);
                var           loadFileOptions      = FSharp.Control.FSharpAsync.RunSynchronously(loadFileOptionsAsync, null, null);
                foreach (var loadedFileName in loadFileOptions.ProjectFileNames)
                {
                    if (Path.GetFileName(loadedFileName) != Path.GetFileName(functionMetadata.ScriptFile))
                    {
                        otherFlags.Add(loadedFileName);
                    }
                }

                // Add the (adjusted) script file itself
                otherFlags.Add(scriptFilePath);

                // Compile the script to a static assembly
                var result = compiler.Compile(otherFlags.ToArray());
                errors = result.Item1;
                var code = result.Item2;

                if (code == 0)
                {
                    var    assemblyBytes = File.ReadAllBytes(dllName);
                    byte[] pdbBytes      = null;
                    if (File.Exists(pdbName))
                    {
                        pdbBytes = File.ReadAllBytes(pdbName);
                    }
                    var assembly = Assembly.Load(assemblyBytes, pdbBytes);
                    assemblyOption = FSharpOption <Assembly> .Some(assembly);
                }
            }
            finally
            {
                Task.WhenAll(DeleteIfExistsAsync(scriptFilePath), DeleteIfExistsAsync(dllName), DeleteIfExistsAsync(pdbName))
                .ContinueWith(t => t.Exception.Handle(e =>
                {
                    // TODO: Trace
                    return(true);
                }), TaskContinuationOptions.OnlyOnFaulted);
            }

            return(new FSharpCompilation(errors, assemblyOption));
        }