Compiler Services: Virtualized File System
The FSharp.Compiler.Service component has a global variable
representing the file system. By setting this variable you can host the compiler in situations where a file system
is not available.
NOTE: The FSharp.Compiler.Service API is subject to change when later versions of the nuget package are published.
Setting the FileSystem
In the example below, we set the file system to an implementation which reads from disk
#r "FSharp.Compiler.Service.dll"
open System.IO
open System.Text
open FSharp.Compiler.CodeAnalysis
open FSharp.Compiler.IO
let defaultFileSystem = FileSystem
let fileName1 = @"c:\mycode\test1.fs" // note, the path doesn't exist
let fileName2 = @"c:\mycode\test2.fs" // note, the path doesn't exist
type MyFileSystem() =
let file1 =
"""
module File1
let A = 1"""
let file2 =
"""
module File2
let B = File1.A + File1.A"""
let files =
dict [ (fileName1, file1)
(fileName2, file2) ]
interface IFileSystem with
// Implement the service to open files for reading and writing
member _.OpenFileForReadShim(fileName, ?useMemoryMappedFile: bool, ?shouldShadowCopy: bool) =
match files.TryGetValue fileName with
| true, text -> new MemoryStream(Encoding.UTF8.GetBytes(text)) :> Stream
| _ ->
defaultFileSystem.OpenFileForReadShim(
fileName,
?useMemoryMappedFile = useMemoryMappedFile,
?shouldShadowCopy = shouldShadowCopy
)
member _.OpenFileForWriteShim(fileName, ?fileMode: FileMode, ?fileAccess: FileAccess, ?fileShare: FileShare) =
defaultFileSystem.OpenFileForWriteShim(
fileName,
?fileMode = fileMode,
?fileAccess = fileAccess,
?fileShare = fileShare
)
// Implement the service related to file existence and deletion
member _.FileExistsShim(fileName) =
files.ContainsKey(fileName)
|| defaultFileSystem.FileExistsShim(fileName)
// Implement the service related to temporary paths and file time stamps
member _.GetTempPathShim() = defaultFileSystem.GetTempPathShim()
member _.GetLastWriteTimeShim(fileName) =
defaultFileSystem.GetLastWriteTimeShim(fileName)
member _.GetFullPathShim(fileName) =
defaultFileSystem.GetFullPathShim(fileName)
member _.IsInvalidPathShim(fileName) =
defaultFileSystem.IsInvalidPathShim(fileName)
member _.IsPathRootedShim(fileName) =
defaultFileSystem.IsPathRootedShim(fileName)
member _.FileDeleteShim(fileName) =
defaultFileSystem.FileDeleteShim(fileName)
member _.AssemblyLoader = defaultFileSystem.AssemblyLoader
member _.GetFullFilePathInDirectoryShim dir fileName =
defaultFileSystem.GetFullFilePathInDirectoryShim dir fileName
member _.NormalizePathShim(path) =
defaultFileSystem.NormalizePathShim(path)
member _.GetDirectoryNameShim(path) =
defaultFileSystem.GetDirectoryNameShim(path)
member _.GetCreationTimeShim(path) =
defaultFileSystem.GetCreationTimeShim(path)
member _.CopyShim(src, dest, overwrite) =
defaultFileSystem.CopyShim(src, dest, overwrite)
member _.DirectoryCreateShim(path) =
defaultFileSystem.DirectoryCreateShim(path)
member _.DirectoryExistsShim(path) =
defaultFileSystem.DirectoryExistsShim(path)
member _.DirectoryDeleteShim(path) =
defaultFileSystem.DirectoryDeleteShim(path)
member _.EnumerateFilesShim(path, pattern) =
defaultFileSystem.EnumerateFilesShim(path, pattern)
member _.EnumerateDirectoriesShim(path) =
defaultFileSystem.EnumerateDirectoriesShim(path)
member _.IsStableFileHeuristic(path) =
defaultFileSystem.IsStableFileHeuristic(path)
member this.ChangeExtensionShim(path, extension) =
defaultFileSystem.ChangeExtensionShim(path, extension)
let myFileSystem = MyFileSystem()
FileSystem <- MyFileSystem()
Doing a compilation with the FileSystem
let checker = FSharpChecker.Create()
let projectOptions =
let sysLib nm =
if System.Environment.OSVersion.Platform = System.PlatformID.Win32NT then // file references only valid on Windows
System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86)
+ @"\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\"
+ nm
+ ".dll"
else
let sysDir =
System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()
let (++) a b = System.IO.Path.Combine(a, b)
sysDir ++ nm + ".dll"
let fsCore4300 () =
if System.Environment.OSVersion.Platform = System.PlatformID.Win32NT then // file references only valid on Windows
System.Environment.GetFolderPath(System.Environment.SpecialFolder.ProgramFilesX86)
+ @"\Reference Assemblies\Microsoft\FSharp\.NETFramework\v4.0\4.3.0.0\FSharp.Core.dll"
else
sysLib "FSharp.Core"
let allFlags =
[| "--simpleresolution"
"--noframework"
"--debug:full"
"--define:DEBUG"
"--optimize-"
"--doc:test.xml"
"--warn:3"
"--fullpaths"
"--flaterrors"
"--target:library"
let references =
[ sysLib "mscorlib"
sysLib "System"
sysLib "System.Core"
fsCore4300 () ]
for r in references do
"-r:" + r |]
{ ProjectFileName = @"c:\mycode\compilation.fsproj" // Make a name that is unique in this directory.
ProjectId = None
SourceFiles = [| fileName1; fileName2 |]
OriginalLoadReferences = []
Stamp = None
OtherOptions = allFlags
ReferencedProjects = [||]
IsIncompleteTypeCheckEnvironment = false
UseScriptResolutionRules = true
LoadTime = System.DateTime.Now // Note using 'Now' forces reloading
UnresolvedReferences = None }
let results =
checker.ParseAndCheckProject(projectOptions)
|> Async.RunSynchronously
results.Diagnostics
results.AssemblySignature.Entities.Count //2
results.AssemblySignature.Entities.[0]
.MembersFunctionsAndValues
.Count
results.AssemblySignature.Entities.[0]
.MembersFunctionsAndValues.[0]
.DisplayName
Summary
In this tutorial, we've seen how to globally customize the view of the file system used by the FSharp.Compiler.Service component.
At the time of writing, the following System.IO operations are not considered part of the virtualized file system API. Future iterations on the compiler service implementation may add these to the API.
- Path.Combine
- Path.DirectorySeparatorChar
- Path.GetDirectoryName
- Path.GetFileName
- Path.GetFileNameWithoutExtension
- Path.HasExtension
- Path.GetRandomFileName (used only in generation compiled win32 resources in assemblies)
NOTE: Several operations in the SourceCodeServices API accept the contents of a file to parse
or check as a parameter, in addition to a file name. In these cases, the file name is only used for
error reporting.
NOTE: Type provider components do not use the virtualized file system.
NOTE: The compiler service may use MSBuild for assembly resolutions unless --simpleresolution is
provided. When using the FileSystem API you will normally want to specify --simpleresolution as one
of your compiler flags. Also specify --noframework. You will need to supply explicit resolutions of all
referenced .NET assemblies.
namespace FSharp
--------------------
namespace Microsoft.FSharp
val mutable FileSystem: IFileSystem
type MyFileSystem =
interface IFileSystem
new: unit -> MyFileSystem
--------------------
new: unit -> MyFileSystem
type IFileSystem =
abstract ChangeExtensionShim: path: string * extension: string -> string
abstract CopyShim: src: string * dest: string * overwrite: bool -> unit
abstract DirectoryCreateShim: path: string -> string
abstract DirectoryDeleteShim: path: string -> unit
abstract DirectoryExistsShim: path: string -> bool
abstract EnumerateDirectoriesShim: path: string -> string seq
abstract EnumerateFilesShim: path: string * pattern: string -> string seq
abstract FileDeleteShim: fileName: string -> unit
abstract FileExistsShim: fileName: string -> bool
abstract GetCreationTimeShim: path: string -> DateTime
...
Creates a stream whose backing store is memory.
type MemoryStream =
inherit Stream
new: unit -> unit + 6 overloads
member BeginRead:
buffer: byte array *
offset: int *
count: int *
callback: AsyncCallback *
state: obj ->
IAsyncResult
member BeginWrite:
buffer: byte array *
offset: int *
count: int *
callback: AsyncCallback *
state: obj ->
IAsyncResult
member CopyTo: destination: Stream * bufferSize: int -> unit
member CopyToAsync:
destination: Stream *
bufferSize: int *
cancellationToken: CancellationToken ->
Task
member EndRead: asyncResult: IAsyncResult -> int
member EndWrite: asyncResult: IAsyncResult -> unit
member Flush: unit -> unit
member FlushAsync: cancellationToken: CancellationToken -> Task
...
--------------------
MemoryStream() : MemoryStream
MemoryStream(buffer: byte array) : MemoryStream
MemoryStream(capacity: int) : MemoryStream
MemoryStream(buffer: byte array, writable: bool) : MemoryStream
MemoryStream(buffer: byte array, index: int, count: int) : MemoryStream
MemoryStream(buffer: byte array, index: int, count: int, writable: bool) : MemoryStream
MemoryStream(buffer: byte array, index: int, count: int, writable: bool, publiclyVisible: bool) : MemoryStream
type Encoding =
interface ICloneable
member Clone: unit -> obj
member Equals: value: obj -> bool
member GetByteCount: chars: nativeptr<char> * count: int -> int + 5 overloads
member GetBytes: chars: nativeptr<char> * charCount: int * bytes: nativeptr<byte> * byteCount: int -> int + 7 overloads
member GetCharCount: bytes: nativeptr<byte> * count: int -> int + 3 overloads
member GetChars: bytes: nativeptr<byte> * byteCount: int * chars: nativeptr<char> * charCount: int -> int + 4 overloads
member GetDecoder: unit -> Decoder
member GetEncoder: unit -> Encoder
member GetHashCode: unit -> int
...
returns: An encoding for the UTF-8 format.
property Encoding.UTF8: Encoding with get
(+0 other overloads)
Encoding.GetBytes(s: string) : byte array
(+0 other overloads)
Encoding.GetBytes(chars: char array) : byte array
(+0 other overloads)
(extension) Encoding.GetBytes(chars: inref<System.Buffers.ReadOnlySequence<char>>, writer: System.Buffers.IBufferWriter<byte>) : int64
(+0 other overloads)
(extension) Encoding.GetBytes(chars: inref<System.Buffers.ReadOnlySequence<char>>, bytes: System.Span<byte>) : int
(+0 other overloads)
(extension) Encoding.GetBytes(chars: System.ReadOnlySpan<char>, writer: System.Buffers.IBufferWriter<byte>) : int64
(+0 other overloads)
Encoding.GetBytes(chars: System.ReadOnlySpan<char>, bytes: System.Span<byte>) : int
(+0 other overloads)
Encoding.GetBytes(s: string, index: int, count: int) : byte array
(+0 other overloads)
Encoding.GetBytes(chars: char array, index: int, count: int) : byte array
(+0 other overloads)
Encoding.GetBytes(chars: nativeptr<char>, charCount: int, bytes: nativeptr<byte>, byteCount: int) : int
(+0 other overloads)
type Stream =
inherit MarshalByRefObject
interface IAsyncDisposable
interface IDisposable
member BeginRead:
buffer: byte array *
offset: int *
count: int *
callback: AsyncCallback *
state: obj ->
IAsyncResult
member BeginWrite:
buffer: byte array *
offset: int *
count: int *
callback: AsyncCallback *
state: obj ->
IAsyncResult
member Close: unit -> unit
member CopyTo: destination: Stream -> unit + 1 overload
member CopyToAsync: destination: Stream -> Task + 3 overloads
member Dispose: unit -> unit
member DisposeAsync: unit -> ValueTask
...
filePath: string *
?useMemoryMappedFile: bool *
?shouldShadowCopy: bool ->
Stream
type FileMode =
Literal>]
| CreateNew = 1
Literal>]
| Create = 2
Literal>]
| Open = 3
Literal>]
| OpenOrCreate = 4
Literal>]
| Truncate = 5
Literal>]
| Append = 6
type FileAccess =
Literal>]
| Read = 1
Literal>]
| Write = 2
Literal>]
| ReadWrite = 3
type FileShare =
Literal>]
| None = 0
Literal>]
| Read = 1
Literal>]
| Write = 2
Literal>]
| ReadWrite = 3
Literal>]
| Delete = 4
Literal>]
| Inheritable = 16
filePath: string *
?fileMode: FileMode *
?fileAccess: FileAccess *
?fileShare: FileShare ->
Stream
dir: string ->
fileName: string ->
string
src: string *
dest: string *
overwrite: bool ->
unit
path: string *
pattern: string ->
string seq
path: string *
extension: string ->
string
type FSharpChecker =
member CheckFileInProject:
parseResults: FSharpParseFileResults *
fileName: string *
fileVersion: int *
sourceText: ISourceText *
options: FSharpProjectOptions *
?userOpName: string ->
Async<FSharpCheckFileAnswer>
member ClearCache: options: FSharpProjectOptions seq * ?userOpName: string -> unit + 1 overload
member ClearLanguageServiceRootCachesAndCollectAndFinalizeAllTransients:
unit ->
unit
member Compile:
argv: string array *
?userOpName: string ->
Async<FSharpDiagnostic array * exn option>
member FindBackgroundReferencesInFile: fileName: string * options: FSharpProjectOptions * symbol: FSharpSymbol * ?canInvalidateProject: bool * ?fastCheck: bool * ?userOpName: string -> Async<range seq> + 1 overload
member GetBackgroundCheckResultsForFileInProject:
fileName: string *
options: FSharpProjectOptions *
?userOpName: string ->
Async<FSharpParseFileResults * FSharpCheckFileResults>
member GetBackgroundParseResultsForFileInProject:
fileName: string *
options: FSharpProjectOptions *
?userOpName: string ->
Async<FSharpParseFileResults>
member GetBackgroundSemanticClassificationForFile: fileName: string * options: FSharpProjectOptions * ?userOpName: string -> Async<SemanticClassificationView option> + 1 overload
member GetParsingOptionsFromCommandLineArgs: sourceFiles: string list * argv: string list * ?isInteractive: bool * ?isEditing: bool -> FSharpParsingOptions * FSharpDiagnostic list + 1 overload
member GetParsingOptionsFromProjectOptions:
options: FSharpProjectOptions ->
FSharpParsingOptions * FSharpDiagnostic list
...
?projectCacheSize: int *
?keepAssemblyContents: bool *
?keepAllBackgroundResolutions: bool *
?legacyReferenceResolver: LegacyReferenceResolver *
?tryGetMetadataSnapshot: FSharp.Compiler.AbstractIL.ILBinaryReader.ILReaderTryGetMetadataSnapshot *
?suggestNamesForErrors: bool *
?keepAllBackgroundSymbolUses: bool *
?enableBackgroundItemKeyStoreAndSemanticClassification: bool *
?enablePartialTypeChecking: bool *
?parallelReferenceResolution: bool *
?shareImportedAssemblies: bool *
?captureIdentifiersWhenParsing: bool *
?documentSource: DocumentSource *
?useTransparentCompiler: bool *
?transparentCompilerCacheSizes: TransparentCompiler.CacheSizes ->
FSharpChecker
type Environment =
static member Exit: exitCode: int -> unit
static member ExpandEnvironmentVariables: name: string -> string
static member FailFast: message: string -> unit + 1 overload
static member GetCommandLineArgs: unit -> string array
static member GetEnvironmentVariable: variable: string -> string + 1 overload
static member GetEnvironmentVariables: unit -> IDictionary + 1 overload
static member GetFolderPath: folder: SpecialFolder -> string + 1 overload
static member GetLogicalDrives: unit -> string array
static member SetEnvironmentVariable: variable: string * value: string -> unit + 1 overload
static member CommandLine: string
...
returns: The platform identifier and version number.
property System.Environment.OSVersion: System.OperatingSystem with get
returns: One of the PlatformID values.
property System.OperatingSystem.Platform: System.PlatformID with get
type PlatformID =
Literal>]
| Win32S = 0
Literal>]
| Win32Windows = 1
Literal>]
| Win32NT = 2
Literal>]
| WinCE = 3
Literal>]
| Unix = 4
Literal>]
| Xbox = 5
Literal>]
| MacOSX = 6
Literal>]
| Other = 7
System.Environment.GetFolderPath(folder: System.Environment.SpecialFolder, option: System.Environment.SpecialFolderOption) : string
type SpecialFolder =
Literal>]
| Desktop = 0
Literal>]
| Programs = 2
Literal>]
| MyDocuments = 5
Literal>]
| Personal = 5
Literal>]
| Favorites = 6
Literal>]
| Startup = 7
Literal>]
| Recent = 8
Literal>]
| SendTo = 9
Literal>]
| StartMenu = 11
Literal>]
| MyMusic = 13
...
type RuntimeEnvironment =
static member FromGlobalAccessCache: a: Assembly -> bool
static member GetRuntimeDirectory: unit -> string
static member GetRuntimeInterfaceAsIntPtr:
clsid: Guid *
riid: Guid ->
nativeint
static member GetRuntimeInterfaceAsObject: clsid: Guid * riid: Guid -> obj
static member GetSystemVersion: unit -> string
static member SystemConfigurationFile: string
type Path =
static member ChangeExtension: path: string * extension: string -> string
static member Combine: path1: string * path2: string -> string + 4 overloads
static member EndsInDirectorySeparator: path: ReadOnlySpan<char> -> bool + 1 overload
static member Exists: path: string -> bool
static member GetDirectoryName: path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload
static member GetExtension: path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload
static member GetFileName: path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload
static member GetFileNameWithoutExtension: path: ReadOnlySpan<char> -> ReadOnlySpan<char> + 1 overload
static member GetFullPath: path: string -> string + 1 overload
static member GetInvalidFileNameChars: unit -> char array
...
Path.Combine( paths: string array) : string
Path.Combine(path1: string, path2: string) : string
Path.Combine(path1: string, path2: string, path3: string) : string
Path.Combine(path1: string, path2: string, path3: string, path4: string) : string
Represents an instant in time, typically expressed as a date and time of day.
type DateTime =
new: date: DateOnly * time: TimeOnly -> unit + 16 overloads
member Add: value: TimeSpan -> DateTime
member AddDays: value: float -> DateTime
member AddHours: value: float -> DateTime
member AddMicroseconds: value: float -> DateTime
member AddMilliseconds: value: float -> DateTime
member AddMinutes: value: float -> DateTime
member AddMonths: months: int -> DateTime
member AddSeconds: value: float -> DateTime
member AddTicks: value: int64 -> DateTime
...
--------------------
System.DateTime ()
(+0 other overloads)
System.DateTime(ticks: int64) : System.DateTime
(+0 other overloads)
System.DateTime(date: System.DateOnly, time: System.TimeOnly) : System.DateTime
(+0 other overloads)
System.DateTime(ticks: int64, kind: System.DateTimeKind) : System.DateTime
(+0 other overloads)
System.DateTime(date: System.DateOnly, time: System.TimeOnly, kind: System.DateTimeKind) : System.DateTime
(+0 other overloads)
System.DateTime(year: int, month: int, day: int) : System.DateTime
(+0 other overloads)
System.DateTime(year: int, month: int, day: int, calendar: System.Globalization.Calendar) : System.DateTime
(+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : System.DateTime
(+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: System.DateTimeKind) : System.DateTime
(+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: System.Globalization.Calendar) : System.DateTime
(+0 other overloads)
returns: An object whose value is the current local date and time.
property System.DateTime.Now: System.DateTime with get
projectSnapshot: FSharpProjectSnapshot *
?userOpName: string ->
Async<FSharpCheckProjectResults>
member FSharpChecker.ParseAndCheckProject:
options: FSharpProjectOptions *
?userOpName: string ->
Async<FSharpCheckProjectResults>
type Async =
static member AsBeginEnd:
computation: ('Arg -> Async<'T>) ->
('Arg * AsyncCallback * objnull -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent: event: IEvent<'Del,'T> * ?cancelAction: (unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate and 'Del: not null)
static member AwaitIAsyncResult:
iar: IAsyncResult *
?millisecondsTimeout: int ->
Async<bool>
static member AwaitTask: task: Task<'T> -> Async<'T> + 1 overload
static member AwaitWaitHandle:
waitHandle: WaitHandle *
?millisecondsTimeout: int ->
Async<bool>
static member CancelDefaultToken: unit -> unit
static member Catch: computation: Async<'T> -> Async<Choice<'T,exn>>
static member Choice: computations: Async<'T option> seq -> Async<'T option>
static member FromBeginEnd: beginAction: (AsyncCallback * objnull -> IAsyncResult) * endAction: (IAsyncResult -> 'T) * ?cancelAction: (unit -> unit) -> Async<'T> + 3 overloads
static member FromContinuations:
callback: (('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) ->
Async<'T>
...
--------------------
type Async<'T>
computation: Async<'T> *
?timeout: int *
?cancellationToken: System.Threading.CancellationToken ->
'T
property FSharpCheckProjectResults.Diagnostics: FSharp.Compiler.Diagnostics.FSharpDiagnostic array with get
property FSharpCheckProjectResults.AssemblySignature: FSharp.Compiler.Symbols.FSharpAssemblySignature with get
property FSharp.Compiler.Symbols.FSharpAssemblySignature.Entities: System.Collections.Generic.IList<FSharp.Compiler.Symbols.FSharpEntity> with get
returns: The number of elements contained in the ICollection`1.
property System.Collections.Generic.ICollection.Count: int with get
F# Compiler Guide