Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding Babel types #1615

Merged
merged 8 commits into from
May 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"name": "bench-compile (Node)",
"program": "${workspaceRoot}/src/fable-standalone/test/bench-compiler/out-node/app.js",
// "args": ["${workspaceRoot}/tests/Main/Fable.Tests.fsproj", "out-tests", "--commonjs"],
"args": ["${workspaceRoot}/../fable-test/fable-test.fsproj", "out-test", "--commonjs", "--optimize-fcs"],
"args": ["${workspaceRoot}/../fable-test/fable-test.fsproj", "out-test", "--typescript"],
"cwd": "${workspaceRoot}/src/fable-standalone/test/bench-compiler"
},
{
Expand All @@ -59,7 +59,7 @@
"name": "bench-compile (.NET)",
"program": "${workspaceFolder}/src/fable-standalone/test/bench-compiler/bin/Debug/netcoreapp2.1/bench-compiler.dll",
// "args": ["${workspaceRoot}/tests/Main/Fable.Tests.fsproj", "out-tests", "--commonjs"],
"args": ["${workspaceRoot}/../fable-test/fable-test.fsproj", "out-test", "--commonjs", "--optimize-fcs"],
"args": ["${workspaceRoot}/../fable-test/fable-test.fsproj", "out-test", "--typescript"],
"cwd": "${workspaceFolder}/src/fable-standalone/test/bench-compiler"
},
{
Expand Down
1 change: 1 addition & 0 deletions src/Fable.Cli/Parser.fs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ let private parseDic (key: string) (o: JObject): IDictionary<string,string> =
let toCompilerOptions (msg: Message): CompilerOptions =
{ typedArrays = msg.typedArrays
clampByteArrays = msg.clampByteArrays
typeDecls = msg.extra.ContainsKey("typescript")
debugMode = Array.contains "DEBUG" msg.define
verbosity = GlobalParams.Singleton.Verbosity
outputPublicInlinedFunctions = Array.contains "FABLE_REPL_LIB" msg.define
Expand Down
261 changes: 195 additions & 66 deletions src/Fable.Transforms/AST/AST.Babel.fs

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions src/Fable.Transforms/FSharp2Fable.fs
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,15 @@ let private transformExpr (com: IFableCompiler) (ctx: Context) fsExpr =
| BasicPatterns.DefaultValue (FableType com ctx typ) ->
return Replacements.defaultof com ctx typ

// Capture variable generic type mapping
| BasicPatterns.Let((var, value), (BasicPatterns.Application(_body, genArgs, _args) as expr)) ->
let genArgs = Seq.map (makeType com ctx.GenericArgs) genArgs
let ctx = { ctx with GenericArgs = matchGenericParamsFrom var genArgs |> Map }
let! value = transformExpr com ctx value
let ctx, ident = putBindingInScope com ctx var value
let! body = transformExpr com ctx expr
return Fable.Let([ident, value], body)

// Assignments
| BasicPatterns.Let((var, value), body) ->
if isInline var then
Expand Down
626 changes: 496 additions & 130 deletions src/Fable.Transforms/Fable2Babel.fs

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/Fable.Transforms/Global/Compiler.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type Verbosity =
type CompilerOptions =
{ typedArrays: bool
clampByteArrays: bool
typeDecls: bool
debugMode: bool
verbosity: Verbosity
/// Meant for precompiled libraries (like the Repl Lib)
Expand Down
2 changes: 1 addition & 1 deletion src/Fable.Transforms/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2812,7 +2812,7 @@ let types (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr optio
let fsharpType methName (r: SourceLocation option) t (i: CallInfo) (args: Expr list) =
match methName with
| "MakeTupleType" ->
Helper.CoreCall("Reflection", "tuple", t, args, i.SignatureArgTypes, hasSpread=true, ?loc=r) |> Some
Helper.CoreCall("Reflection", "tuple_type", t, args, i.SignatureArgTypes, hasSpread=true, ?loc=r) |> Some
// Prevent name clash with FSharpValue.GetRecordFields
| "GetRecordFields" ->
Helper.CoreCall("Reflection", "getRecordElements", t, args, i.SignatureArgTypes, ?loc=r) |> Some
Expand Down
3 changes: 2 additions & 1 deletion src/fable-compiler-js/src/Platform.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ open Fable.Core.JsInterop
type CmdLineOptions = {
commonjs: bool
optimize: bool
watchMode: bool
sourceMaps: bool
typeDecls: bool
watchMode: bool
}

module JS =
Expand Down
12 changes: 10 additions & 2 deletions src/fable-compiler-js/src/app.fs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ let printErrors showWarnings (errors: Fable.Standalone.Error[]) =
errors |> Array.iter printError
failwith "Too many errors."

let toFableCompilerConfig (options: CmdLineOptions): Fable.Standalone.CompilerConfig =
{ typedArrays = not (options.typeDecls)
clampByteArrays = false
typeDecls = options.typeDecls
precompiledLib = None }

let parseFiles projectFileName outDir options =
// parse project
let (dllRefs, fileNames, otherOptions) = parseProject projectFileName
Expand Down Expand Up @@ -64,7 +70,8 @@ let parseFiles projectFileName outDir options =

// Fable (F# to Babel)
let fableLibraryDir = "fable-library"
let parseFable (res, fileName) = fable.CompileToBabelAst(fableLibraryDir, res, fileName)
let fableConfig = options |> toFableCompilerConfig
let parseFable (res, fileName) = fable.CompileToBabelAst(fableLibraryDir, res, fileName, fableConfig)
let trimPath (path: string) = path.Replace("../", "").Replace("./", "").Replace(":", "")
let projDir = projectFileName |> normalizeFullPath |> Path.GetDirectoryName
let libDir = getFableLibDir() |> normalizeFullPath
Expand All @@ -89,8 +96,9 @@ let run opts projectFileName outDir =
let options = {
commonjs = Option.isSome commandToRun || opts |> Array.contains "--commonjs"
optimize = opts |> Array.contains "--optimize-fcs"
watchMode = opts |> Array.contains "--watch"
sourceMaps = opts |> Array.contains "--sourceMaps"
typeDecls = opts |> Array.contains "--typescript"
watchMode = opts |> Array.contains "--watch"
}
parseFiles projectFileName outDir options
commandToRun |> Option.iter runCmdAndExitIfFails
Expand Down
2 changes: 1 addition & 1 deletion src/fable-compiler-js/src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export function transformAndSaveBabelAst(babelAst, filePath, projDir, outDir, li
// this solves a weird commonjs issue where some imports are not properly qualified
babelAst = JSON.parse(serializeToJson(babelAst)); // somehow this helps with that
const sourcePath = babelAst.fileName;
const jsPath = filePath.replace(FSHARP_EXT, ".js");
const jsPath = filePath.replace(FSHARP_EXT, options.typeDecls ? ".ts" : ".js");
let outPath = Path.resolve(outDir, jsPath);
outPath = ensureUniquePath(sourcePath, outPath);
ensureDirExists(Path.dirname(outPath));
Expand Down
2 changes: 1 addition & 1 deletion src/fable-library/FSharp.Core.fs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ module Operators =
let nullArg x = raise(System.ArgumentNullException(x))

[<CompiledName("Using")>]
let using (resource : 'T when 'T :> System.IDisposable) (action: 'T -> 'a) =
let using (resource: System.IDisposable) action =
try action(resource)
finally match (box resource) with null -> () | _ -> resource.Dispose()

Expand Down
7 changes: 0 additions & 7 deletions src/fable-library/Map.d.ts

This file was deleted.

52 changes: 26 additions & 26 deletions src/fable-library/Reflection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,25 +63,25 @@ export function compare(t1: TypeInfo, t2: TypeInfo): number {
}
}

export function type(fullname: string, generics?: TypeInfo[]): TypeInfo {
export function generic_type(fullname: string, generics?: TypeInfo[]): TypeInfo {
return new TypeInfo(fullname, generics);
}

export function record(
export function record_type(
fullname: string,
generics: TypeInfo[],
constructor: Constructor,
fields: () => FieldInfo[]): TypeInfo {
return new TypeInfo(fullname, generics, constructor, fields);
}

export function anonRecord(...fields: FieldInfo[]): TypeInfo {
export function anonRecord_type(...fields: FieldInfo[]): TypeInfo {
return new TypeInfo("", undefined, undefined, () => fields);
}

export type CaseInfoInput = string | [string, FieldInfo[]];

export function union(
export function union_type(
fullname: string,
generics: TypeInfo[],
constructor: Constructor,
Expand All @@ -93,48 +93,48 @@ export function union(
return t;
}

export function tuple(...generics: TypeInfo[]): TypeInfo {
export function tuple_type(...generics: TypeInfo[]): TypeInfo {
return new TypeInfo("System.Tuple`" + generics.length, generics);
}

export function delegate(...generics: TypeInfo[]): TypeInfo {
export function delegate_type(...generics: TypeInfo[]): TypeInfo {
return new TypeInfo("System.Func`" + generics.length, generics);
}

export function lambda(argType: TypeInfo, returnType: TypeInfo): TypeInfo {
export function lambda_type(argType: TypeInfo, returnType: TypeInfo): TypeInfo {
return new TypeInfo("Microsoft.FSharp.Core.FSharpFunc`2", [argType, returnType]);
}

export function option(generic: TypeInfo): TypeInfo {
export function option_type(generic: TypeInfo): TypeInfo {
return new TypeInfo("Microsoft.FSharp.Core.FSharpOption`1", [generic]);
}

export function list(generic: TypeInfo): TypeInfo {
export function list_type(generic: TypeInfo): TypeInfo {
return new TypeInfo("Microsoft.FSharp.Collections.FSharpList`1", [generic]);
}

export function array(generic: TypeInfo): TypeInfo {
export function array_type(generic: TypeInfo): TypeInfo {
return new TypeInfo(generic.fullname + "[]", [generic]);
}

export function enumType(fullname: string, underlyingType: TypeInfo, enumCases: EnumCase[]): TypeInfo {
export function enum_type(fullname: string, underlyingType: TypeInfo, enumCases: EnumCase[]): TypeInfo {
return new TypeInfo(fullname, [underlyingType], undefined, undefined, undefined, enumCases);
}

export const obj: TypeInfo = new TypeInfo("System.Object");
export const unit: TypeInfo = new TypeInfo("Microsoft.FSharp.Core.Unit");
export const char: TypeInfo = new TypeInfo("System.Char");
export const string: TypeInfo = new TypeInfo("System.String");
export const bool: TypeInfo = new TypeInfo("System.Boolean");
export const int8: TypeInfo = new TypeInfo("System.SByte");
export const uint8: TypeInfo = new TypeInfo("System.Byte");
export const int16: TypeInfo = new TypeInfo("System.Int16");
export const uint16: TypeInfo = new TypeInfo("System.UInt16");
export const int32: TypeInfo = new TypeInfo("System.Int32");
export const uint32: TypeInfo = new TypeInfo("System.UInt32");
export const float32: TypeInfo = new TypeInfo("System.Single");
export const float64: TypeInfo = new TypeInfo("System.Double");
export const decimal: TypeInfo = new TypeInfo("System.Decimal");
export const obj_type: TypeInfo = new TypeInfo("System.Object");
export const unit_type: TypeInfo = new TypeInfo("Microsoft.FSharp.Core.Unit");
export const char_type: TypeInfo = new TypeInfo("System.Char");
export const string_type: TypeInfo = new TypeInfo("System.String");
export const bool_type: TypeInfo = new TypeInfo("System.Boolean");
export const int8_type: TypeInfo = new TypeInfo("System.SByte");
export const uint8_type: TypeInfo = new TypeInfo("System.Byte");
export const int16_type: TypeInfo = new TypeInfo("System.Int16");
export const uint16_type: TypeInfo = new TypeInfo("System.UInt16");
export const int32_type: TypeInfo = new TypeInfo("System.Int32");
export const uint32_type: TypeInfo = new TypeInfo("System.UInt32");
export const float32_type: TypeInfo = new TypeInfo("System.Single");
export const float64_type: TypeInfo = new TypeInfo("System.Double");
export const decimal_type: TypeInfo = new TypeInfo("System.Decimal");

export function name(info: FieldInfo | CaseInfo | TypeInfo): string {
if (Array.isArray(info)) {
Expand Down Expand Up @@ -182,7 +182,7 @@ export function isEnum(t: TypeInfo) {
* but it should be enough for type comparison purposes
*/
export function getGenericTypeDefinition(t: TypeInfo) {
return t.generics == null ? t : new TypeInfo(t.fullname, t.generics.map(() => obj));
return t.generics == null ? t : new TypeInfo(t.fullname, t.generics.map(() => obj_type));
}

export function getEnumUnderlyingType(t: TypeInfo) {
Expand Down
7 changes: 0 additions & 7 deletions src/fable-library/Set.d.ts

This file was deleted.

9 changes: 8 additions & 1 deletion src/fable-standalone/src/Interfaces.fs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ type IBabelResult =
abstract BabelAst: obj
abstract FableErrors: Error[]

type CompilerConfig =
{ typedArrays: bool
clampByteArrays: bool
typeDecls: bool
precompiledLib: (string -> (string * string) option) option
}

type IFableManager =
abstract CreateChecker: references: string[] * readAllBytes: (string -> byte[]) * otherOptions: string[] -> IChecker
abstract ClearParseCaches: checker: IChecker -> unit
Expand All @@ -57,5 +64,5 @@ type IFableManager =
abstract GetDeclarationLocation: parseResults: IParseResults * line: int * col: int * lineText: string -> Async<Range option>
abstract GetToolTipText: parseResults: IParseResults * line: int * col: int * lineText: string -> Async<string[]>
abstract GetCompletionsAtLocation: parseResults: IParseResults * line: int * col: int * lineText: string -> Async<Completion[]>
abstract CompileToBabelAst: fableLibrary: string * parseResults: IParseResults * fileName: string * ?precompiledLib: (string->(string*string) option) -> IBabelResult
abstract CompileToBabelAst: fableLibrary: string * parseResults: IParseResults * fileName: string * ?config: CompilerConfig -> IBabelResult
abstract FSharpAstToString: parseResults: IParseResults * fileName: string -> string
31 changes: 19 additions & 12 deletions src/fable-standalone/src/Main.fs
Original file line number Diff line number Diff line change
Expand Up @@ -213,16 +213,22 @@ let getCompletionsAtLocation (parseResults: ParseResults) (line: int) (col: int)
return [||]
}

let makeCompiler fableLibrary fileName (project: Project) precompiledLib (otherFSharpOptions: string[]) =
let options: Fable.CompilerOptions =
{ typedArrays = true
clampByteArrays = false
debugMode = otherFSharpOptions |> Array.exists (fun x -> x = "--define:DEBUG" || x = "-d:DEBUG")
verbosity = Fable.Verbosity.Normal
outputPublicInlinedFunctions = false
precompiledLib = precompiledLib }
let com = Compiler(fileName, project, options, fableLibrary)
com
let defaultCompilerConfig: CompilerConfig =
{ typedArrays = true
clampByteArrays = false
typeDecls = false
precompiledLib = None }

let makeCompilerOptions (config: CompilerConfig option) (otherFSharpOptions: string[]): Fable.CompilerOptions =
let config = defaultArg config defaultCompilerConfig
let isDebug = otherFSharpOptions |> Array.exists (fun x -> x = "--define:DEBUG" || x = "-d:DEBUG")
{ typedArrays = config.typedArrays
clampByteArrays = config.clampByteArrays
typeDecls = config.typeDecls
debugMode = isDebug
verbosity = Fable.Verbosity.Normal
outputPublicInlinedFunctions = false
precompiledLib = config.precompiledLib }

let compileAst (com: Compiler) (project: Project) =
FSharp2Fable.Compiler.transformFile com project.ImplementationFiles
Expand Down Expand Up @@ -270,10 +276,11 @@ let init () =
let res = parseResults :?> ParseResults
getCompletionsAtLocation res line col lineText

member __.CompileToBabelAst(fableLibrary:string, parseResults:IParseResults, fileName:string, ?precompiledLib) =
member __.CompileToBabelAst(fableLibrary:string, parseResults:IParseResults, fileName:string, ?config) =
let res = parseResults :?> ParseResults
let project = res.GetProject()
let com = makeCompiler fableLibrary fileName project precompiledLib parseResults.OtherFSharpOptions
let options = makeCompilerOptions config parseResults.OtherFSharpOptions
let com = Compiler(fileName, project, options, fableLibrary)
let ast = compileAst com project
let errors =
com.GetLogs()
Expand Down
10 changes: 9 additions & 1 deletion src/fable-standalone/src/Worker/Worker.fs
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,19 @@ let rec loop (box: MailboxProcessor<WorkerRequest>) (state: State) = async {

| Some fable, CompileCode(fsharpCode, otherFSharpOptions) ->
try
// detect (and remove) a passed non-F# compiler option to avoid changing msg contract
let useTypeDeclarations = otherFSharpOptions |> Array.contains "--typescript"
let otherFSharpOptions = otherFSharpOptions |> Array.filter ((<>) "--typescript")
// Check if we need to recreate the FableState because otherFSharpOptions have changed
let! fable = makeFableState (Initialized fable) otherFSharpOptions
let (parseResults, parsingTime) = measureTime (fun () -> fable.Manager.ParseFSharpScript(fable.Checker, FILE_NAME, fsharpCode, otherFSharpOptions)) ()
let (res, fableTransformTime) = measureTime (fun () ->
fable.Manager.CompileToBabelAst("fable-library", parseResults, FILE_NAME, fun x -> resolveLibCall(fable.LibMap, x))) ()
let fableConfig =
{ typedArrays = true
clampByteArrays = false
typeDecls = useTypeDeclarations
precompiledLib = Some (fun x -> resolveLibCall(fable.LibMap, x)) }
fable.Manager.CompileToBabelAst("fable-library", parseResults, FILE_NAME, fableConfig)) ()
let (jsCode, babelTime, babelErrors) =
try
let code, t = measureTime fable.BabelAstCompiler res.BabelAst
Expand Down
8 changes: 8 additions & 0 deletions src/fable-standalone/test/bench-compiler/Platform.fs
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
module Fable.Compiler.Platform

type CmdLineOptions = {
commonjs: bool
optimize: bool
sourceMaps: bool
typeDecls: bool
watchMode: bool
}

#if DOTNET_FILE_SYSTEM && !FABLE_COMPILER

open System.IO
Expand Down
17 changes: 9 additions & 8 deletions src/fable-standalone/test/bench-compiler/app.fs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@ let printErrors showWarnings (errors: Fable.Standalone.Error[]) =
errors |> Array.iter printError
failwith "Too many errors."

type CmdLineOptions = {
commonjs: bool
optimize: bool
watchMode: bool
sourceMaps: bool
}
let toFableCompilerConfig (options: CmdLineOptions): Fable.Standalone.CompilerConfig =
{ typedArrays = not (options.typeDecls)
clampByteArrays = false
typeDecls = options.typeDecls
precompiledLib = None }

let parseFiles projectFileName outDir options =
// parse project
Expand Down Expand Up @@ -64,7 +63,8 @@ let parseFiles projectFileName outDir options =

// Fable (F# to Babel)
let fableLibraryDir = "fable-library"
let parseFable (res, fileName) = fable.CompileToBabelAst(fableLibraryDir, res, fileName)
let fableConfig = options |> toFableCompilerConfig
let parseFable (res, fileName) = fable.CompileToBabelAst(fableLibraryDir, res, fileName, fableConfig)
let trimPath (path: string) = path.Replace("../", "").Replace("./", "").Replace(":", "")
let projDir = projectFileName |> normalizeFullPath |> Path.GetDirectoryName

Expand Down Expand Up @@ -98,8 +98,9 @@ let parseArguments (argv: string[]) =
let options = {
commonjs = opts |> Array.contains "--commonjs"
optimize = opts |> Array.contains "--optimize-fcs"
watchMode = opts |> Array.contains "--watch"
sourceMaps = opts |> Array.contains "--sourceMaps"
typeDecls = opts |> Array.contains "--typescript"
watchMode = opts |> Array.contains "--watch"
}
parseFiles projectFileName outDir options
| _ -> printfn "%s" usage
Expand Down
Loading