Skip to content

Commit

Permalink
Fable support
Browse files Browse the repository at this point in the history
  • Loading branch information
ncave committed Feb 2, 2019
1 parent b284b63 commit bef8db3
Show file tree
Hide file tree
Showing 107 changed files with 7,751 additions and 3,672 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ artifacts/*.nupkg
*.orig
*.mdf
*.ldf
.paket/paket.exe
fcs/.paket/paket.exe
paket-files
docsrc/tools/FSharp.Formatting.svclog
src/fsharp/FSharp.Compiler.Service/pplex.fs
Expand All @@ -201,6 +201,7 @@ src/fsharp/FSharp.Compiler.Service/pppars.fsi
*.cto
*.vstman
project.lock.json
.vscode

src/fsharp/FSharp.Compiler.Service/FSComp.fs
src/fsharp/FSharp.Compiler.Service/FSComp.resx
Expand Down
27 changes: 27 additions & 0 deletions fcs/build.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ Target "BuildVersion" (fun _ ->
Shell.Exec("appveyor", sprintf "UpdateBuild -Version \"%s\"" buildVersion) |> ignore
)

Target "BuildTools" (fun _ ->
runDotnet __SOURCE_DIRECTORY__ "build ../src/buildtools/buildtools.proj -v n -c Proto"
)

Target "Build" (fun _ ->
runDotnet __SOURCE_DIRECTORY__ "build ../src/buildtools/buildtools.proj -v n -c Proto"
runDotnet __SOURCE_DIRECTORY__ "build FSharp.Compiler.Service.sln -v n -c release"
Expand All @@ -98,6 +102,25 @@ Target "NuGet" (fun _ ->
runDotnet __SOURCE_DIRECTORY__ "pack FSharp.Compiler.Service.sln -v n -c release"
)

Target "CodeGen.Fable" (fun _ ->
let outDir = __SOURCE_DIRECTORY__ + "/fcs-fable/codegen/"

// run FCS codegen (except that fssrgen runs without .resx output to inline it)
runDotnet outDir "run -- ../../../src/fsharp/FSComp.txt FSComp.fs"
runDotnet outDir "run -- ../../../src/fsharp/fsi/FSIstrings.txt FSIstrings.fs"

// Fable-specific (comment the #line directive as it is not supported)
["lex.fs"; "pplex.fs"; "illex.fs"; "ilpars.fs"; "pars.fs"; "pppars.fs"]
|> Seq.map (fun fileName -> outDir + fileName)
|> RegexReplaceInFilesWithEncoding @"(?<!/)# (?=\d)" "//# " Text.Encoding.UTF8

// prevent stack overflows on large files (make lexer rules inline)
let pattern = @"(?<=and )(?!inline )([a-zA-Z]+ )+ *\(lexbuf "
["lex.fs"; "pplex.fs"; "illex.fs"]
|> Seq.map (fun fileName -> outDir + fileName)
|> RegexReplaceInFilesWithEncoding pattern @"inline $0" Text.Encoding.UTF8
)

Target "GenerateDocsEn" (fun _ ->
executeFSIWithArgs "docsrc/tools" "generate.fsx" [] [] |> ignore
)
Expand Down Expand Up @@ -125,6 +148,10 @@ Target "Release" DoNothing
Target "GenerateDocs" DoNothing
Target "TestAndNuGet" DoNothing

"Clean"
==> "BuildTools"
==> "CodeGen.Fable"

"Start"
=?> ("BuildVersion", isAppVeyorBuild)
==> "Restore"
Expand Down
3 changes: 3 additions & 0 deletions fcs/fcs-fable/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Codegen
codegen/*.fs
codegen/*.fsi
155 changes: 155 additions & 0 deletions fcs/fcs-fable/adapters.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
namespace Internal.Utilities

#nowarn "1182"

//------------------------------------------------------------------------
// shims for things not yet implemented in Fable
//------------------------------------------------------------------------

module System =

module Decimal =
let GetBits(d: decimal): int[] = [| 0; 0; 0; 0 |] //TODO: proper implementation

module Diagnostics =
type Trace() =
static member TraceInformation(s) = () //TODO: proper implementation

module Reflection =
type AssemblyName(assemblyName: string) =
member x.Name = assemblyName //TODO: proper implementation

type WeakReference<'T>(v: 'T) =
member x.TryGetTarget () = (true, v)

type StringComparer(comp: System.StringComparison) =
static member Ordinal = StringComparer(System.StringComparison.Ordinal)
static member OrdinalIgnoreCase = StringComparer(System.StringComparison.OrdinalIgnoreCase)
interface System.Collections.Generic.IEqualityComparer<string> with
member x.Equals(a,b) = System.String.Compare(a, b, comp) = 0
member x.GetHashCode(a) =
match comp with
| System.StringComparison.Ordinal -> hash a
| System.StringComparison.OrdinalIgnoreCase -> hash (a.ToLowerInvariant())
| _ -> failwithf "Unsupported StringComparison: %A" comp
interface System.Collections.Generic.IComparer<string> with
member x.Compare(a,b) = System.String.Compare(a, b, comp)

module Collections =
module Concurrent =
open System.Collections.Generic

type ConcurrentDictionary<'TKey, 'TValue when 'TKey: equality>(comparer: IEqualityComparer<'TKey>) =
inherit Dictionary<'TKey, 'TValue>(comparer)
new () = ConcurrentDictionary {
new IEqualityComparer<'TKey> with
member __.GetHashCode(x) = x.GetHashCode()
member __.Equals(x, y) = x.Equals(y) }
member x.TryAdd (key:'TKey, value:'TValue) = x.[key] <- value; true
member x.GetOrAdd (key:'TKey, valueFactory: 'TKey -> 'TValue): 'TValue =
match x.TryGetValue key with
| true, v -> v
| false, _ -> let v = valueFactory(key) in x.[key] <- v; v

module IO =
module Directory =
let GetCurrentDirectory () = "." //TODO: proper xplat implementation

module Path =

let Combine (path1: string, path2: string) = //TODO: proper xplat implementation
let path1 =
if (String.length path1) = 0 then path1
else (path1.TrimEnd [|'\\';'/'|]) + "/"
path1 + (path2.TrimStart [|'\\';'/'|])

let ChangeExtension (path: string, ext: string) =
let i = path.LastIndexOf(".")
if i < 0 then path
else path.Substring(0, i) + ext

let HasExtension (path: string) =
let i = path.LastIndexOf(".")
i >= 0

let GetExtension (path: string) =
let i = path.LastIndexOf(".")
if i < 0 then ""
else path.Substring(i)

let GetInvalidPathChars () = //TODO: proper xplat implementation
Seq.toArray "<>:\"|?*\b\t"

let GetInvalidFileNameChars () = //TODO: proper xplat implementation
Seq.toArray "<>:\"|\\/?*\b\t"

let GetFullPath (path: string) = //TODO: proper xplat implementation
path

let GetFileName (path: string) =
let normPath = path.Replace("\\", "/").TrimEnd('/')
let i = normPath.LastIndexOf("/")
normPath.Substring(i + 1)

let GetFileNameWithoutExtension (path: string) =
let filename = GetFileName path
let i = filename.LastIndexOf(".")
if i < 0 then filename
else filename.Substring(0, i)

let GetDirectoryName (path: string) = //TODO: proper xplat implementation
let normPath = path.Replace("\\", "/")
let i = normPath.LastIndexOf("/")
if i <= 0 then ""
else normPath.Substring(0, i)

let IsPathRooted (path: string) = //TODO: proper xplat implementation
let normPath = path.Replace("\\", "/").TrimEnd('/')
normPath.StartsWith("/")


module Microsoft =
module FSharp =

//------------------------------------------------------------------------
// From reshapedreflection.fs
//------------------------------------------------------------------------
module Core =
module XmlAdapters =
let s_escapeChars = [| '<'; '>'; '\"'; '\''; '&' |]
let getEscapeSequence c =
match c with
| '<' -> "&lt;"
| '>' -> "&gt;"
| '\"' -> "&quot;"
| '\'' -> "&apos;"
| '&' -> "&amp;"
| _ as ch -> ch.ToString()
let escape str = String.collect getEscapeSequence str

//------------------------------------------------------------------------
// From sr.fs
//------------------------------------------------------------------------
module Compiler =
module SR =
let GetString(name: string) =
match SR.Resources.resources.TryGetValue(name) with
| true, value -> value
| _ -> "Missing FSStrings error message for: " + name

module DiagnosticMessage =
type ResourceString<'T>(sfmt: string, fmt: string) =
member x.Format =
let a = fmt.Split('%')
|> Array.filter (fun s -> String.length s > 0)
|> Array.map (fun s -> box("%" + s))
let tmp = System.String.Format(sfmt, a)
let fmt = Printf.StringFormat<'T>(tmp)
sprintf fmt

let postProcessString (s: string) =
s.Replace("\\n","\n").Replace("\\t","\t")

let DeclareResourceString (messageID: string, fmt: string) =
let messageString = SR.GetString(messageID) |> postProcessString
ResourceString<'T>(messageString, fmt)
101 changes: 101 additions & 0 deletions fcs/fcs-fable/ast_print.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

namespace Microsoft.FSharp.Compiler.SourceCodeServices

//-------------------------------------------------------------------------
// AstPrint
//-------------------------------------------------------------------------

module AstPrint =

let attribsOfSymbol (s:FSharpSymbol) =
[ match s with
| :? FSharpField as v ->
yield "field"
if v.IsCompilerGenerated then yield "compgen"
if v.IsDefaultValue then yield "default"
if v.IsMutable then yield "mutable"
if v.IsVolatile then yield "volatile"
if v.IsStatic then yield "static"
if v.IsLiteral then yield sprintf "%A" v.LiteralValue.Value

| :? FSharpEntity as v ->
v.TryFullName |> ignore // check there is no failure here
match v.BaseType with
| Some t when t.HasTypeDefinition && t.TypeDefinition.TryFullName.IsSome ->
yield sprintf "inherits %s" t.TypeDefinition.FullName
| _ -> ()
if v.IsNamespace then yield "namespace"
if v.IsFSharpModule then yield "module"
if v.IsByRef then yield "byref"
if v.IsClass then yield "class"
if v.IsDelegate then yield "delegate"
if v.IsEnum then yield "enum"
if v.IsFSharpAbbreviation then yield "abbrev"
if v.IsFSharpExceptionDeclaration then yield "exception"
if v.IsFSharpRecord then yield "record"
if v.IsFSharpUnion then yield "union"
if v.IsInterface then yield "interface"
if v.IsMeasure then yield "measure"
#if !NO_EXTENSIONTYPING
if v.IsProvided then yield "provided"
if v.IsStaticInstantiation then yield "static_inst"
if v.IsProvidedAndErased then yield "erased"
if v.IsProvidedAndGenerated then yield "generated"
#endif
if v.IsUnresolved then yield "unresolved"
if v.IsValueType then yield "valuetype"

| :? FSharpMemberOrFunctionOrValue as v ->
yield "owner: " + match v.DeclaringEntity with | Some e -> e.CompiledName | _ -> "<unknown>"
if v.IsActivePattern then yield "active_pattern"
if v.IsDispatchSlot then yield "dispatch_slot"
if v.IsModuleValueOrMember && not v.IsMember then yield "val"
if v.IsMember then yield "member"
if v.IsProperty then yield "property"
if v.IsExtensionMember then yield "extension_member"
if v.IsPropertyGetterMethod then yield "property_getter"
if v.IsPropertySetterMethod then yield "property_setter"
if v.IsEvent then yield "event"
if v.EventForFSharpProperty.IsSome then yield "property_event"
if v.IsEventAddMethod then yield "event_add"
if v.IsEventRemoveMethod then yield "event_remove"
if v.IsTypeFunction then yield "type_func"
if v.IsCompilerGenerated then yield "compiler_gen"
if v.IsImplicitConstructor then yield "implicit_ctor"
if v.IsMutable then yield "mutable"
if v.IsOverrideOrExplicitInterfaceImplementation then yield "override_impl"
if not v.IsInstanceMember then yield "static"
if v.IsInstanceMember && not v.IsInstanceMemberInCompiledCode && not v.IsExtensionMember then yield "funky"
if v.IsExplicitInterfaceImplementation then yield "interface_impl"
yield sprintf "%A" v.InlineAnnotation
// if v.IsConstructorThisValue then yield "ctorthis"
// if v.IsMemberThisValue then yield "this"
// if v.LiteralValue.IsSome then yield "literal"
| _ -> () ]

let rec printFSharpDecls prefix decls = seq {
let mutable i = 0
for decl in decls do
i <- i + 1
match decl with
| FSharpImplementationFileDeclaration.Entity (e, sub) ->
yield sprintf "%s%i) ENTITY: %s %A" prefix i e.CompiledName (attribsOfSymbol e)
if not (Seq.isEmpty e.Attributes) then
yield sprintf "%sattributes: %A" prefix (Seq.toList e.Attributes)
if not (Seq.isEmpty e.DeclaredInterfaces) then
yield sprintf "%sinterfaces: %A" prefix (Seq.toList e.DeclaredInterfaces)
yield ""
yield! printFSharpDecls (prefix + "\t") sub
| FSharpImplementationFileDeclaration.MemberOrFunctionOrValue (meth, args, body) ->
yield sprintf "%s%i) METHOD: %s %A" prefix i meth.CompiledName (attribsOfSymbol meth)
yield sprintf "%stype: %A" prefix meth.FullType
yield sprintf "%sargs: %A" prefix args
// if not meth.IsCompilerGenerated then
yield sprintf "%sbody: %A" prefix body
yield ""
| FSharpImplementationFileDeclaration.InitAction (expr) ->
yield sprintf "%s%i) ACTION" prefix i
yield sprintf "%s%A" prefix expr
yield ""
}
47 changes: 47 additions & 0 deletions fcs/fcs-fable/codegen/codegen.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<FSharpSourcesRoot>$(MSBuildProjectDirectory)\..\..\..\src</FSharpSourcesRoot>
</PropertyGroup>
<!-- <Import Project="..\..\fcs.props" /> -->
<Import Project="..\..\..\src\buildtools\buildtools.targets" />
<!-- <Import Project="fssrgen.targets" /> -->
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<!-- <FsSrGen Include="$(FSharpSourcesRoot)\fsharp\FSComp.txt">
<Link>FSComp.txt</Link>
</FsSrGen>
<FsSrGen Include="$(FSharpSourcesRoot)\fsharp\fsi\FSIstrings.txt">
<Link>FSIstrings.txt</Link>
</FsSrGen> -->
<FsYacc Include="$(FSharpSourcesRoot)\absil\ilpars.fsy">
<OtherFlags>--module Microsoft.FSharp.Compiler.AbstractIL.Internal.AsciiParser --open Microsoft.FSharp.Compiler.AbstractIL --internal --lexlib Internal.Utilities.Text.Lexing --parslib Internal.Utilities.Text.Parsing</OtherFlags>
<Link>ilpars.fsy</Link>
</FsYacc>
<FsYacc Include="$(FSharpSourcesRoot)\fsharp\pars.fsy">
<OtherFlags>--module Microsoft.FSharp.Compiler.Parser --open Microsoft.FSharp.Compiler --internal --lexlib Internal.Utilities.Text.Lexing --parslib Internal.Utilities.Text.Parsing</OtherFlags>
<Link>pars.fsy</Link>
</FsYacc>
<FsLex Include="$(FSharpSourcesRoot)\absil\illex.fsl">
<OtherFlags>--unicode --lexlib Internal.Utilities.Text.Lexing</OtherFlags>
<Link>AbsIL/illex.fsl</Link>
</FsLex>
<FsLex Include="$(FSharpSourcesRoot)\fsharp\lex.fsl">
<OtherFlags>--unicode --lexlib Internal.Utilities.Text.Lexing</OtherFlags>
<Link>ParserAndUntypedAST/lex.fsl</Link>
</FsLex>
<FsLex Include="$(FSharpSourcesRoot)\fsharp\pplex.fsl">
<OtherFlags>--unicode --lexlib Internal.Utilities.Text.Lexing</OtherFlags>
<Link>ParserAndUntypedAST/pplex.fsl</Link>
</FsLex>
<FsYacc Include="$(FSharpSourcesRoot)\fsharp\pppars.fsy">
<OtherFlags>--module Microsoft.FSharp.Compiler.PPParser --open Microsoft.FSharp.Compiler --internal --lexlib Internal.Utilities.Text.Lexing --parslib Internal.Utilities.Text.Parsing</OtherFlags>
<Link>ParserAndUntypedAST/pppars.fsy</Link>
</FsYacc>
<Compile Include="fssrgen.fsx" />
</ItemGroup>
<Target Name="GenerateCode" AfterTargets="Restore" BeforeTargets="BeforeBuild" DependsOnTargets="CallFsLex;CallFsYacc"></Target>
<!-- <Target Name="GenerateCode" AfterTargets="Restore" BeforeTargets="BeforeBuild" DependsOnTargets="CallFsLex;CallFsYacc;CallFsSrGen"></Target> -->
</Project>
Loading

0 comments on commit bef8db3

Please sign in to comment.