Skip to content

Commit 2bf772b

Browse files
ncavealfonsogarciacaro
authored andcommitted
[WIP] Fable JS support (#657)
1 parent ec44811 commit 2bf772b

26 files changed

+1380
-179
lines changed

src/fable/Fable.Client.Node/Main.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ type FileResolver() =
300300
kv.Value |> Seq.map (fun (srcFile, trgFile) ->
301301
// Use GetFullPath to prevent things like "parentDir/./childDir"
302302
// which can cause problems when calculating relative paths
303-
srcFile, Path.GetFullPath <| Path.Combine(outDir, projDir, Path.ChangeExtension(trgFile, ".js"))))
303+
srcFile, Path.GetFullPath <| Path.Combine3(outDir, projDir, Path.ChangeExtension(trgFile, ".js"))))
304304
|> Map
305305

306306
let mergeProjectOpts (opts1: FSharpProjectOptions option, resolver: FileResolver)

src/fable/Fable.Compiler/FSharp2Fable.Util.fs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ namespace Fable.FSharp2Fable
22

33
open System
44
open System.Collections.Generic
5+
#if !FABLE_COMPILER
56
open System.Reflection
7+
#endif
68
open System.Text.RegularExpressions
79
open Microsoft.FSharp.Compiler
810
open Microsoft.FSharp.Compiler.Ast
@@ -11,7 +13,7 @@ open Fable
1113
open Fable.AST
1214
open Fable.AST.Fable.Util
1315

14-
#if DOTNETCORE
16+
#if DOTNETCORE && !FABLE_COMPILER
1517
[<AutoOpen>]
1618
module ReflectionAdapters =
1719
type System.Reflection.Assembly with
@@ -218,7 +220,7 @@ module Helpers =
218220
|> function
219221
| Some name -> name.ConstructorArguments.[0] |> snd |> string
220222
| None -> Naming.lowerFirst unionCase.DisplayName
221-
|> makeConst
223+
|> makeStrConst
222224

223225
let getArgCount (meth: FSharpMemberOrFunctionOrValue) =
224226
let args = meth.CurriedParameterGroups
@@ -527,7 +529,7 @@ module Patterns =
527529
Call(None,_op_Equality,[],[_typeInt],
528530
[ILAsm ("[I_ldlen; AI_conv DT_I4]",[],[_matchValue2])
529531
Const (length,_typeInt2)]),
530-
Const (_falseConst,_typeBool)) -> Some (matchValue, length)
532+
Const (_falseConst,_typeBool)) -> Some (matchValue, length, _typeInt2)
531533
| _ -> None
532534

533535
let (|NumberKind|_|) = function
@@ -561,10 +563,10 @@ module Patterns =
561563
| _ when typ.TypeDefinition.IsEnum -> true
562564
| _ -> false
563565
let rec makeSwitch map matchValue e =
564-
let addCase map (idx: int) (case: obj) =
565-
match Map.tryFind idx map with
566-
| Some cases -> Map.add idx (case::cases) map
567-
| None -> Map.add idx [case] map
566+
// let addCase map (idx: int) (case: obj) =
567+
// match Map.tryFind idx map with
568+
// | Some cases -> Map.add idx (case::cases) map
569+
// | None -> Map.add idx [case] map
568570
match e with
569571
| IfThenElse(Call(None,op_Equality,[],_,[Value var; Const(case,_)]),
570572
DecisionTreeSuccess(idx, []), elseExpr)
@@ -1115,6 +1117,7 @@ module Util =
11151117
|||> Seq.fold2 (fun acc genPar (ResolveGeneric ctx t) -> (genPar.Name, t)::acc)
11161118
|> List.rev
11171119

1120+
#if !FABLE_COMPILER
11181121
let getEmitter =
11191122
// Prevent ReflectionTypeLoadException
11201123
// From http://stackoverflow.com/a/7889272
@@ -1138,6 +1141,7 @@ module Util =
11381141
let typ = getTypes assembly |> Seq.find (fun x ->
11391142
x.AssemblyQualifiedName = tdef.QualifiedName)
11401143
System.Activator.CreateInstance(typ))
1144+
#endif
11411145

11421146
let emittedGenericArguments com (ctx: Context) r meth (typArgs, methTypArgs)
11431147
macro (args: Fable.Expr list) =
@@ -1175,6 +1179,7 @@ module Util =
11751179
let macro, args =
11761180
emittedGenericArguments com ctx r meth (typArgs, methTypArgs) macro args
11771181
Fable.Apply(Fable.Emit(macro) |> Fable.Value, args, Fable.ApplyMeth, typ, r) |> Some
1182+
#if !FABLE_COMPILER
11781183
| (:? FSharpType as emitFsType)::(:? string as emitMethName)::extraArg
11791184
when emitFsType.HasTypeDefinition ->
11801185
try
@@ -1192,6 +1197,7 @@ module Util =
11921197
sprintf "Error when invoking %s.%s"
11931198
emitFsType.TypeDefinition.DisplayName emitMethName
11941199
|> attachRange r |> fun msg -> Exception(msg + ": " + exMsg, ex) |> raise
1200+
#endif
11951201
| _ -> "EmitAttribute must receive a string or Type argument" |> attachRange r |> failwith
11961202
| _ -> None
11971203

@@ -1280,7 +1286,7 @@ module Util =
12801286
let loc = if meth.IsInstanceMember then Fable.InstanceLoc else Fable.StaticLoc
12811287
match ent.TryGetMember(methName, getMemberKind meth, loc, argTypes) with
12821288
| Some m -> m.OverloadName | None -> methName
1283-
let ext = makeGet r Fable.Any typRef (makeConst methName)
1289+
let ext = makeGet r Fable.Any typRef (makeStrConst methName)
12841290
let bind = Fable.Emit("$0.bind($1)($2...)") |> Fable.Value
12851291
Fable.Apply (bind, ext::callee::args, Fable.ApplyMeth, typ, r) |> Some
12861292
| _ -> None
@@ -1337,17 +1343,17 @@ module Util =
13371343
(** *Check if this a getter or setter *)
13381344
match getMemberKind meth with
13391345
| Fable.Getter | Fable.Field ->
1340-
makeGetFrom com ctx r typ callee (makeConst methName)
1346+
makeGetFrom com ctx r typ callee (makeStrConst methName)
13411347
| Fable.Setter ->
1342-
Fable.Set (callee, Some (makeConst methName), args.Head, r)
1348+
Fable.Set (callee, Some (makeStrConst methName), args.Head, r)
13431349
(** *Check if this is an implicit constructor *)
13441350
| Fable.Constructor ->
13451351
Fable.Apply (callee, args, Fable.ApplyCons, typ, r)
13461352
(** *If nothing of the above applies, call the method normally *)
13471353
| Fable.Method as kind ->
13481354
let applyMeth methName =
13491355
// let calleeType = Fable.Function(Some argTypes, typ)
1350-
let m = makeGet r Fable.Any callee (makeConst methName)
1356+
let m = makeGet r Fable.Any callee (makeStrConst methName)
13511357
Fable.Apply(m, args, Fable.ApplyMeth, typ, r)
13521358
if belongsToInterfaceOrImportedEntity meth
13531359
then
@@ -1406,7 +1412,7 @@ module Util =
14061412
// Cases when tryEnclosingEntity returns None are rare (see #237)
14071413
// Let's assume the value belongs to the current enclosing module
14081414
| None -> Fable.DeclaredType(ctx.enclosingEntity, []) |> makeNonGenTypeRef com
1409-
Fable.Apply (typeRef, [makeConst v.CompiledName], Fable.ApplyGet, typ, r)
1415+
Fable.Apply (typeRef, [makeStrConst v.CompiledName], Fable.ApplyGet, typ, r)
14101416

14111417
let makeDelegateFrom (com: IFableCompiler) ctx delegateType fsExpr =
14121418
let ctx = { ctx with functionBody = DelegateFunctionBody }

src/fable/Fable.Compiler/FSharp2Fable.fs

Lines changed: 31 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
module Fable.FSharp2Fable.Compiler
22

3+
#if !FABLE_COMPILER
34
open System.IO
5+
#endif
46
open System.Collections.Generic
57
open System.Text.RegularExpressions
68

@@ -22,10 +24,10 @@ open Util
2224
let private (|SpecialValue|_|) com ctx = function
2325
| BasicPatterns.ILFieldGet (None, typ, fieldName) as fsExpr when typ.HasTypeDefinition ->
2426
match typ.TypeDefinition.TryFullName, fieldName with
25-
| Some "System.String", "Empty" -> Some (makeConst "")
26-
| Some "System.Guid", "Empty" -> Some (makeConst "00000000-0000-0000-0000-000000000000")
27+
| Some "System.String", "Empty" -> Some (makeStrConst "")
28+
| Some "System.Guid", "Empty" -> Some (makeStrConst "00000000-0000-0000-0000-000000000000")
2729
| Some "System.TimeSpan", "Zero" ->
28-
Fable.Wrapped(makeConst 0, makeType com ctx.typeArgs fsExpr.Type) |> Some
30+
Fable.Wrapped(makeIntConst 0, makeType com ctx.typeArgs fsExpr.Type) |> Some
2931
| Some "System.DateTime", "MaxValue"
3032
| Some "System.DateTime", "MinValue" ->
3133
CoreLibCall("Date", Some (Naming.lowerFirst fieldName), false, [])
@@ -132,7 +134,7 @@ and private transformNonListNewUnionCase com ctx (fsExpr: FSharpExpr) fsType uni
132134
| KeyValueUnion ->
133135
let key, value =
134136
match argExprs with
135-
| [] -> lowerCaseName unionCase, makeConst true
137+
| [] -> lowerCaseName unionCase, makeBoolConst true
136138
| [expr] -> lowerCaseName unionCase, expr
137139
| [key; expr] when hasAtt Atts.erase unionCase.Attributes -> key, expr
138140
| _ -> FableError("KeyValue Union Cases must have one or zero fields: " + unionType.FullName, range) |> raise
@@ -144,13 +146,13 @@ and private transformNonListNewUnionCase com ctx (fsExpr: FSharpExpr) fsType uni
144146
| PojoUnion ->
145147
List.zip (Seq.toList unionCase.UnionCaseFields) argExprs
146148
|> List.map (fun (fi, e) -> fi.Name, e)
147-
|> List.append ["type", makeConst unionCase.Name]
149+
|> List.append ["type", makeStrConst unionCase.Name]
148150
|> makeJsObject (Some range)
149151
| ListUnion ->
150152
failwithf "transformNonListNewUnionCase must not be used with List %O" range
151153
| OtherType ->
152154
let argExprs = [
153-
makeConst unionCase.Name // Include Tag name in args
155+
makeStrConst unionCase.Name // Include Tag name in args
154156
Fable.Value(Fable.ArrayConst(Fable.ArrayValues argExprs, Fable.Any))
155157
]
156158
buildApplyInfo com ctx (Some range) unionType unionType (unionType.FullName)
@@ -225,14 +227,14 @@ and private transformExprWithRole (role: Role) (com: IFableCompiler) ctx fsExpr
225227

226228
| CreateEvent (callee, eventName, meth, typArgs, methTypArgs, methArgs) ->
227229
let callee, args = com.Transform ctx callee, List.map (com.Transform ctx) methArgs
228-
let callee = Fable.Apply(callee, [makeConst eventName], Fable.ApplyGet, Fable.Any, None)
230+
let callee = Fable.Apply(callee, [makeStrConst eventName], Fable.ApplyGet, Fable.Any, None)
229231
let r, typ = makeRangeFrom fsExpr, makeType com ctx.typeArgs fsExpr.Type
230232
makeCallFrom com ctx r typ meth (typArgs, methTypArgs) (Some callee) args
231233

232-
| CheckArrayLength (Transform com ctx arr, length) ->
234+
| CheckArrayLength (Transform com ctx arr, length, FableType com ctx typ) ->
233235
let r = makeRangeFrom fsExpr
234-
let lengthExpr = Fable.Apply(arr, [makeConst "length"], Fable.ApplyGet, Fable.Number Int32, r)
235-
makeEqOp r [lengthExpr; makeConst length] BinaryEqualStrict
236+
let lengthExpr = Fable.Apply(arr, [makeStrConst "length"], Fable.ApplyGet, Fable.Number Int32, r)
237+
makeEqOp r [lengthExpr; makeTypeConst typ length] BinaryEqualStrict
236238

237239
| PrintFormat (Transform com ctx expr) -> expr
238240

@@ -250,7 +252,7 @@ and private transformExprWithRole (role: Role) (com: IFableCompiler) ctx fsExpr
250252
([record], updatedFields)
251253
||> List.fold (fun acc (FieldName fieldName, e) ->
252254
let r, value = makeRangeFrom e, com.Transform ctx e
253-
let e = Fable.Set(record, Some(makeConst fieldName), value, r)
255+
let e = Fable.Set(record, Some(makeStrConst fieldName), value, r)
254256
e::acc)
255257
Fable.Sequential(assignments, r)
256258

@@ -287,20 +289,8 @@ and private transformExprWithRole (role: Role) (com: IFableCompiler) ctx fsExpr
287289
|> makeLoop (makeRangeFrom fsExpr)
288290

289291
(** Values *)
290-
// Arrays with small data (ushort, byte) won't fit the NewArray pattern
291-
// as they would require too much memory
292-
| BasicPatterns.Const(:? System.Array as arr, typ) ->
293-
let arrExprs = [
294-
for i in 0 .. (arr.GetLength(0) - 1) ->
295-
arr.GetValue(i) |> makeConst
296-
]
297-
match arr.GetType().GetElementType().FullName with
298-
| NumberKind kind -> Fable.Number kind
299-
| _ -> Fable.Any
300-
|> makeArray <| arrExprs
301-
302292
| BasicPatterns.Const(value, FableType com ctx typ) ->
303-
let e = makeConst value
293+
let e = makeTypeConst typ value
304294
if e.Type = typ then e
305295
// Enumerations are compiled as const but they have a different type
306296
else Fable.Wrapped (e, typ)
@@ -464,29 +454,29 @@ and private transformExprWithRole (role: Role) (com: IFableCompiler) ctx fsExpr
464454
| None -> makeType com ctx.typeArgs calleeType
465455
|> makeNonGenTypeRef com
466456
let r, typ = makeRangeFrom fsExpr, makeType com ctx.typeArgs fsExpr.Type
467-
makeGetFrom com ctx r typ callee (makeConst fieldName)
457+
makeGetFrom com ctx r typ callee (makeStrConst fieldName)
468458

469459
| BasicPatterns.TupleGet (_tupleType, tupleElemIndex, Transform com ctx tupleExpr) ->
470460
let r, typ = makeRangeFrom fsExpr, makeType com ctx.typeArgs fsExpr.Type
471-
makeGetFrom com ctx r typ tupleExpr (makeConst tupleElemIndex)
461+
makeGetFrom com ctx r typ tupleExpr (makeIntConst tupleElemIndex)
472462

473463
| BasicPatterns.UnionCaseGet (Transform com ctx unionExpr, fsType, unionCase, FieldName fieldName) ->
474464
let typ, range = makeType com ctx.typeArgs fsExpr.Type, makeRangeFrom fsExpr
475465
match fsType with
476466
| ErasedUnion | OptionUnion ->
477467
Fable.Wrapped(unionExpr, typ)
478468
| ListUnion ->
479-
makeGet range typ unionExpr (Naming.lowerFirst fieldName |> makeConst)
469+
makeGet range typ unionExpr (Naming.lowerFirst fieldName |> makeStrConst)
480470
| PojoUnion ->
481-
makeConst fieldName |> makeGet range typ unionExpr
471+
makeStrConst fieldName |> makeGet range typ unionExpr
482472
| KeyValueUnion ->
483473
FableError("KeyValueUnion types cannot be used in pattern matching", ?range=range) |> raise
484474
| StringEnum ->
485475
FableError("StringEnum types cannot have fields", ?range=range) |> raise
486476
| OtherType ->
487477
let i = unionCase.UnionCaseFields |> Seq.findIndex (fun x -> x.Name = fieldName)
488-
let fields = makeGet range typ unionExpr ("Fields" |> makeConst)
489-
makeGet range typ fields (i |> makeConst)
478+
let fields = makeGet range typ unionExpr ("Fields" |> makeStrConst)
479+
makeGet range typ fields (i |> makeIntConst)
490480

491481
| BasicPatterns.ILFieldSet (callee, typ, fieldName, value) ->
492482
failwithf "Unsupported ILField reference %O: %A" (makeRange fsExpr.Range) fsExpr
@@ -496,11 +486,11 @@ and private transformExprWithRole (role: Role) (com: IFableCompiler) ctx fsExpr
496486
match callee with
497487
| Some (Transform com ctx callee) -> callee
498488
| None -> makeNonGenTypeRef com calleeType
499-
Fable.Set (callee, Some (makeConst fieldName), value, makeRangeFrom fsExpr)
489+
Fable.Set (callee, Some (makeStrConst fieldName), value, makeRangeFrom fsExpr)
500490

501491
| BasicPatterns.UnionCaseTag (Transform com ctx unionExpr, _unionType) ->
502492
let r, typ = makeRangeFrom fsExpr, makeType com ctx.typeArgs fsExpr.Type
503-
makeGetFrom com ctx r typ unionExpr (makeConst "tag")
493+
makeGetFrom com ctx r typ unionExpr (makeStrConst "tag")
504494

505495
| BasicPatterns.UnionCaseSet (Transform com ctx unionExpr, _type, _case, _caseField, _valueExpr) ->
506496
makeRange fsExpr.Range |> failwithf "Unexpected UnionCaseSet %O"
@@ -647,8 +637,8 @@ and private transformExprWithRole (role: Role) (com: IFableCompiler) ctx fsExpr
647637

648638
| BasicPatterns.UnionCaseTest(Transform com ctx unionExpr, fsType, unionCase) ->
649639
let checkCase name =
650-
let left = makeGet None Fable.String unionExpr (makeConst name)
651-
let right = makeConst unionCase.Name
640+
let left = makeGet None Fable.String unionExpr (makeStrConst name)
641+
let right = makeStrConst unionCase.Name
652642
makeBinOp (makeRangeFrom fsExpr) Fable.Boolean [left; right] BinaryEqualStrict
653643
match fsType with
654644
| ErasedUnion ->
@@ -672,7 +662,7 @@ and private transformExprWithRole (role: Role) (com: IFableCompiler) ctx fsExpr
672662
makeBinOp (makeRangeFrom fsExpr) Fable.Boolean [unionExpr; Fable.Value Fable.Null] opKind
673663
| ListUnion ->
674664
let opKind = if unionCase.CompiledName = "Empty" then BinaryEqual else BinaryUnequal
675-
let expr = makeGet None Fable.Any unionExpr (makeConst "tail")
665+
let expr = makeGet None Fable.Any unionExpr (makeStrConst "tail")
676666
makeBinOp (makeRangeFrom fsExpr) Fable.Boolean [expr; Fable.Value Fable.Null] opKind
677667
| StringEnum ->
678668
makeBinOp (makeRangeFrom fsExpr) Fable.Boolean [unionExpr; lowerCaseName unionCase] BinaryEqualStrict
@@ -1177,6 +1167,9 @@ let private getProjectMaps (com: ICompiler) (parsedProj: FSharpCheckProjectResul
11771167
// This dictionary must be mutable so `dict` cannot be used
11781168
let dic = Dictionary()
11791169
dic.Add(Naming.current, Map.empty)
1170+
1171+
#if FABLE_COMPILER
1172+
#else
11801173
parsedProj.ProjectContext.GetReferencedAssemblies()
11811174
|> Seq.choose (fun assembly ->
11821175
assembly.FileName |> Option.bind (fun asmPath ->
@@ -1219,6 +1212,7 @@ let private getProjectMaps (com: ICompiler) (parsedProj: FSharpCheckProjectResul
12191212
dic.Add(asmPath, fableMap)
12201213
with _ -> ()
12211214
)
1215+
#endif
12221216
dic
12231217

12241218
let transformFiles (com: ICompiler) (parsedProj: FSharpCheckProjectResults) (projInfo: FSProjectInfo) =
@@ -1227,8 +1221,8 @@ let transformFiles (com: ICompiler) (parsedProj: FSharpCheckProjectResults) (pro
12271221
||> Map.findOrRun (fun () -> getProjectMaps com parsedProj projInfo)
12281222
// Cache for entities and inline expressions
12291223
let entitiesCache = Dictionary<string, Fable.Entity>()
1230-
let inlineExprsCache: Dictionary<string, Dictionary<FSharpMemberOrFunctionOrValue,int> * FSharpExpr> =
1231-
Map.findOrNew "inline" projInfo.Extra
1224+
let newCache = fun () -> Dictionary<string, Dictionary<FSharpMemberOrFunctionOrValue,int> * FSharpExpr>()
1225+
let inlineExprsCache = Map.findOrRun newCache "inline" projInfo.Extra
12321226
// Start transforming files
12331227
let entryFile =
12341228
parsedProj.AssemblyContents.ImplementationFiles

src/fable/Fable.Compiler/Fable.Compiler.fsproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
</ItemGroup>
4343
<ItemGroup>
4444
<Compile Include="AssemblyInfo.fs" />
45-
<Compile Include="Util.fs" />
45+
<Compile Include="Utils.fs" />
4646
<Compile Include="Replacements.fs" />
4747
<Compile Include="FSharp2Fable.Util.fs" />
4848
<Compile Include="FSharp2Fable.fs" />

0 commit comments

Comments
 (0)