Skip to content

Commit

Permalink
Removed circular dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
ncave committed Feb 28, 2021
1 parent c60ccdc commit a3802e0
Show file tree
Hide file tree
Showing 15 changed files with 297 additions and 504 deletions.
2 changes: 1 addition & 1 deletion src/Fable.Transforms/Fable2Babel.fs
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ module Reflection =
| Fable.Array _ | Fable.Tuple _ ->
libCall com ctx None "Util" "isArrayLike" [|com.TransformAsExpr(ctx, expr)|]
| Fable.List _ ->
jsInstanceof (libValue com ctx "List" "LinkedList$1") expr
jsInstanceof (libValue com ctx "List" "FSharpList") expr
| Fable.AnonymousRecordType _ ->
warnAndEvalToFalse "anonymous records"
| Fable.MetaType ->
Expand Down
61 changes: 11 additions & 50 deletions src/Fable.Transforms/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1661,50 +1661,12 @@ let stringModule (com: ICompiler) (ctx: Context) r t (i: CallInfo) (_: Expr opti
Helper.LibCall(com, "String", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some

let seqModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
let sort r returnType descending projection args genArg =
let compareFn =
let identExpr ident =
match projection with
| Some projection ->
let info = makeCallInfo None [IdentExpr ident] []
Call(projection, info, genArg, None)
| None -> IdentExpr ident
let x = makeUniqueIdent ctx genArg "x"
let y = makeUniqueIdent ctx genArg "y"
let comparison =
let comparison = compare com ctx None (identExpr x) (identExpr y)
if descending
then makeUnOp None (Number Int32) comparison UnaryMinus
else comparison
Delegate([x; y], comparison, None)
Helper.LibCall(com, "Seq", "sortWith", returnType, compareFn::args, ?loc=r) |> Some

match i.CompiledName, args with
| "Cast", [arg] -> Some arg // Erase
| ("Cache" | "ToArray"), [arg] -> toArray r t arg |> Some
| "OfList", [arg] -> toSeq t arg |> Some
| "ToList", _ -> Helper.LibCall(com, "List", "ofSeq", t, args, i.SignatureArgTypes, ?loc=r) |> Some
| ("ChunkBySize" | "Permute" | "SplitInto") as meth, [arg1; arg2] ->
let arg2 = toArray r (Array Any) arg2
let result = Helper.LibCall(com, "Array", Naming.lowerFirst meth, Any, [arg1; arg2])
Helper.LibCall(com, "Seq", "ofArray", t, [result]) |> Some
// For Using we need to cast the argument to IDisposable
| "EnumerateUsing", [arg; f] ->
Helper.LibCall(com, "Seq", "enumerateUsing", t, [arg; f], i.SignatureArgTypes, ?loc=r) |> Some
| ("Sort" | "SortDescending" as meth), args ->
(genArg com ctx r 0 i.GenericArgs) |> sort r t (meth = "SortDescending") None args
| ("SortBy" | "SortByDescending" as meth), projection::args ->
(genArg com ctx r 1 i.GenericArgs) |> sort r t (meth = "SortByDescending") (Some projection) args
| ("GroupBy" | "CountBy" as meth), args ->
let meth = Naming.lowerFirst meth
let args = injectArg com ctx r "Map" meth i.GenericArgs args
Helper.LibCall(com, "Map", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some
| ("Distinct" | "DistinctBy" as meth), args ->
| ("Distinct" | "DistinctBy" | "Except" | "GroupBy" | "CountBy" as meth), args ->
let meth = Naming.lowerFirst meth
let args = injectArg com ctx r "Set" meth i.GenericArgs args
Helper.LibCall(com, "Set", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some
| "TryExactlyOne", args ->
tryCoreOp com r t "Seq" "exactlyOne" args |> Some
let args = injectArg com ctx r "Seq2" meth i.GenericArgs args
Helper.LibCall(com, "Seq2", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some
| meth, _ ->
let meth = Naming.lowerFirst meth
let args = injectArg com ctx r "Seq" meth i.GenericArgs args
Expand Down Expand Up @@ -1860,19 +1822,16 @@ let arrayModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Ex
newArray (makeIntConst 0) t |> Some
| "IsEmpty", [ar] ->
eq (get r (Number Int32) ar "length") (makeIntConst 0) |> Some
| "TryExactlyOne", args ->
tryCoreOp com r t "Array" "exactlyOne" args |> Some
// | "SortInPlace", args ->
// let _, thisArg = List.splitLast args
// let argTypes = List.take (List.length args) i.SignatureArgTypes
// let compareFn = (genArg com ctx r 0 i.GenericArgs) |> makeComparerFunction com ctx
// Helper.InstanceCall(thisArg, "sort", t, [compareFn], argTypes, ?loc=r) |> Some
| "CopyTo", args ->
copyToArray com r t i args
| Patterns.DicContains nativeArrayFunctions meth, _ ->
let args, thisArg = List.splitLast args
let argTypes = List.take (List.length args) i.SignatureArgTypes
Helper.InstanceCall(thisArg, meth, t, args, argTypes, ?loc=r) |> Some
| ("Distinct" | "DistinctBy" | "Except" | "GroupBy" | "CountBy" as meth), args ->
let meth = Naming.lowerFirst meth
let args = injectArg com ctx r "Seq2" meth i.GenericArgs args
Helper.LibCall(com, "Seq2", "Array_" + meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some
| meth, _ ->
let meth = Naming.lowerFirst meth
let args = injectArg com ctx r "Array" meth i.GenericArgs args
Expand Down Expand Up @@ -1905,8 +1864,10 @@ let listModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Exp
// Use a cast to give it better chances of optimization (e.g. converting list
// literals to arrays) after the beta reduction pass
| "ToSeq", [x] -> toSeq t x |> Some
| "TryExactlyOne", args ->
tryCoreOp com r t "List" "exactlyOne" args |> Some
| ("Distinct" | "DistinctBy" | "Except" | "GroupBy" | "CountBy" as meth), args ->
let meth = Naming.lowerFirst meth
let args = injectArg com ctx r "Seq2" meth i.GenericArgs args
Helper.LibCall(com, "Seq2", "List_" + meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some
| meth, _ ->
let meth = Naming.lowerFirst meth
let args = injectArg com ctx r "List" meth i.GenericArgs args
Expand Down
36 changes: 7 additions & 29 deletions src/Fable.Transforms/ReplacementsInject.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,6 @@ module Fable.Transforms.ReplacementsInject

let fableReplacementsModules =
Map [
"Seq", Map [
"maxBy", (Types.comparer, 1)
"max", (Types.comparer, 0)
"minBy", (Types.comparer, 1)
"min", (Types.comparer, 0)
"sumBy", (Types.adder, 1)
"sum", (Types.adder, 0)
"averageBy", (Types.averager, 1)
"average", (Types.averager, 0)
]
"Array", Map [
"append", (Types.arrayCons, 0)
"mapIndexed", (Types.arrayCons, 1)
Expand All @@ -25,12 +15,7 @@ let fableReplacementsModules =
"mapFoldBack", (Types.arrayCons, 2)
"concat", (Types.arrayCons, 0)
"collect", (Types.arrayCons, 1)
"countBy", (Types.equalityComparer, 1)
"distinctBy", (Types.equalityComparer, 1)
"distinct", (Types.equalityComparer, 0)
"contains", (Types.equalityComparer, 0)
"except", (Types.equalityComparer, 0)
"groupBy", (Types.equalityComparer, 1)
"singleton", (Types.arrayCons, 0)
"initialize", (Types.arrayCons, 0)
"replicate", (Types.arrayCons, 0)
Expand Down Expand Up @@ -60,7 +45,6 @@ let fableReplacementsModules =
]
"List", Map [
"contains", (Types.equalityComparer, 0)
"except", (Types.equalityComparer, 0)
"sort", (Types.comparer, 0)
"sortBy", (Types.comparer, 1)
"sortDescending", (Types.comparer, 0)
Expand All @@ -73,14 +57,9 @@ let fableReplacementsModules =
"min", (Types.comparer, 0)
"average", ("Fable.Core.IGenericAverager`1", 0)
"averageBy", ("Fable.Core.IGenericAverager`1", 1)
"distinctBy", (Types.equalityComparer, 1)
"distinct", (Types.equalityComparer, 0)
"groupBy", (Types.equalityComparer, 1)
"countBy", (Types.equalityComparer, 1)
]
"Seq", Map [
"contains", (Types.equalityComparer, 0)
"except", (Types.equalityComparer, 0)
"sort", (Types.comparer, 0)
"sortBy", (Types.comparer, 1)
"sortDescending", (Types.comparer, 0)
Expand All @@ -94,6 +73,13 @@ let fableReplacementsModules =
"average", ("Fable.Core.IGenericAverager`1", 0)
"averageBy", ("Fable.Core.IGenericAverager`1", 1)
]
"Seq2", Map [
"distinct", (Types.equalityComparer, 0)
"distinctBy", (Types.equalityComparer, 1)
"except", (Types.equalityComparer, 0)
"countBy", (Types.equalityComparer, 1)
"groupBy", (Types.equalityComparer, 1)
]
"Set", Map [
"FSharpSet__Map", (Types.comparer, 1)
"singleton", (Types.comparer, 0)
Expand All @@ -103,19 +89,11 @@ let fableReplacementsModules =
"ofList", (Types.comparer, 0)
"ofArray", (Types.comparer, 0)
"ofSeq", (Types.comparer, 0)
"createMutable", (Types.equalityComparer, 0)
"distinct", (Types.equalityComparer, 0)
"distinctBy", (Types.equalityComparer, 1)
"intersectWith", (Types.comparer, 0)
"isSubsetOf", (Types.comparer, 0)
"isSupersetOf", (Types.comparer, 0)
"isProperSubsetOf", (Types.comparer, 0)
"isProperSupersetOf", (Types.comparer, 0)
]
"Map", Map [
"createMutable", (Types.equalityComparer, 0)
"groupBy", (Types.equalityComparer, 1)
"countBy", (Types.equalityComparer, 1)
]
]

52 changes: 7 additions & 45 deletions src/fable-library/Array.fs
Original file line number Diff line number Diff line change
Expand Up @@ -254,28 +254,6 @@ let collect (mapping: 'T -> 'U[]) (array: 'T[]) ([<Inject>] cons: Cons<'U>): 'U[
concat mapped cons
// collectImpl mapping array // flatMap not widely available yet

let countBy (projection: 'T -> 'Key) (array: 'T[]) ([<Inject>] eq: IEqualityComparer<'Key>): ('Key * int)[] =
let dict = Dictionary<'Key, int>(eq)
let keys: 'Key[] = [||]
for value in array do
let key = projection value
match dict.TryGetValue(key) with
| true, prev ->
dict.[key] <- prev + 1
| false, _ ->
dict.[key] <- 1
pushImpl keys key |> ignore
let result =
map (fun key -> key, dict.[key]) keys Unchecked.defaultof<_>
result

let distinctBy (projection: 'T -> 'Key) (array: 'T[]) ([<Inject>] eq: IEqualityComparer<'Key>) =
let hashSet = HashSet<'Key>(eq)
array |> filter (projection >> hashSet.Add)

let distinct (array: 'T[]) ([<Inject>] eq: IEqualityComparer<'T>) =
distinctBy id array eq

let where predicate (array: _[]) = filterImpl predicate array

let contains<'T> (value: 'T) (array: 'T[]) ([<Inject>] eq: IEqualityComparer<'T>) =
Expand All @@ -287,28 +265,6 @@ let contains<'T> (value: 'T) (array: 'T[]) ([<Inject>] eq: IEqualityComparer<'T>
else loop (i + 1)
loop 0

let except (itemsToExclude: seq<'T>) (array: 'T[]) ([<Inject>] eq: IEqualityComparer<'T>): 'T[] =
if array.Length = 0 then
array
else
let cached = HashSet(itemsToExclude, eq)
array |> filterImpl cached.Add

let groupBy (projection: 'T -> 'Key) (array: 'T[]) ([<Inject>] eq: IEqualityComparer<'Key>): ('Key * 'T[])[] =
let dict = Dictionary<'Key, ResizeArray<'T>>(eq)
let keys: 'Key[] = [||]
for v in array do
let key = projection v
match dict.TryGetValue(key) with
| true, prev ->
prev.Add(v)
| false, _ ->
dict.Add(key, ResizeArray [|v|])
pushImpl keys key |> ignore
let result =
map (fun key -> key, arrayFrom dict.[key]) keys Unchecked.defaultof<_>
result

let empty cons = allocateArrayFromCons cons 0

let singleton value ([<Inject>] cons: Cons<'T>) =
Expand Down Expand Up @@ -414,7 +370,8 @@ let addInPlace (x: 'T) (array: 'T[]) =

let addRangeInPlace (range: seq<'T>) (array: 'T[]) =
// if isTypedArrayImpl array then invalidArg "array" "Typed arrays not supported"
Seq.iter (fun x -> pushImpl array x |> ignore) range
for x in range do
addInPlace x array

let removeInPlace (item: 'T) (array: 'T[]) =
// if isTypedArrayImpl array then invalidArg "array" "Typed arrays not supported"
Expand Down Expand Up @@ -778,6 +735,11 @@ let exactlyOne (array: 'T[]) =
elif array.Length = 0 then invalidArg "array" LanguagePrimitives.ErrorStrings.InputSequenceEmptyString
else invalidArg "array" "Input array too long"

let tryExactlyOne (array: 'T[]) =
if array.Length = 1
then Some (array.[0])
else None

let head (array: 'T[]) =
if array.Length = 0 then invalidArg "array" LanguagePrimitives.ErrorStrings.InputArrayEmptyString
else array.[0]
Expand Down
4 changes: 2 additions & 2 deletions src/fable-library/BigInt.fs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ let private flipTwosComplement currByte lowBitFound =
| 0uy, false -> 0uy, false // Haven't found first bit yet and no chance to do so with zero byte
| _, false ->
// Found first byte containing a 1, flip higher bits and all future bytes
let firstBitIndex = [0..7] |> List.find (fun i -> currByte &&& (1uy <<< i) > 0uy)
let firstBitIndex = [|0;1;2;3;4;5;6;7|] |> Array.find (fun i -> currByte &&& (1uy <<< i) > 0uy)
(currByte ^^^ (0b11111110uy <<< firstBitIndex)) &&& 255uy, true

// Spec:
Expand Down Expand Up @@ -148,7 +148,7 @@ let fromByteArray (bytes:byte array) =
|> fun value -> if isPositive then value else bigint(-1) * value
else
let bytesToProcess = min bytesRemaining 4
for i in 0 .. bytesToProcess - 1 do buffer.[i] <- bytes.[currIndex + i] // fill buffer with up to 4 bytes
for i = 0 to bytesToProcess - 1 do buffer.[i] <- bytes.[currIndex + i] // fill buffer with up to 4 bytes
if isPositive then
Array.fill buffer bytesToProcess (4 - bytesToProcess) 0uy // clear any unfilled bytes in buffer
let value =
Expand Down
1 change: 1 addition & 0 deletions src/fable-library/Fable.Library.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
<Compile Include="Array.fs" />
<Compile Include="List.fs" />
<Compile Include="Seq.fs" />
<Compile Include="Seq2.fs" />
<Compile Include="Range.fs" />
<Compile Include="Set.fs" />
<Compile Include="Map.fs" />
Expand Down
53 changes: 8 additions & 45 deletions src/fable-library/List.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ module SR =
let notEnoughElements = "The input sequence has an insufficient number of elements."

[<CustomEquality; CustomComparison>]
// [<CompiledName("FSharpList`1")>]
[<CompiledName("FSharpList")>]
type LinkedList<'T when 'T: comparison> =
{ head: 'T; mutable tail: LinkedList<'T> option }

Expand Down Expand Up @@ -471,12 +471,6 @@ let contains (value: 'T) (xs: 'T list) ([<Inject>] eq: System.Collections.Generi
tryFindIndex (fun v -> eq.Equals (value, v)) xs
|> Option.isSome

let except (itemsToExclude: seq<'T>) (xs: 'T list) ([<Inject>] eq: System.Collections.Generic.IEqualityComparer<'T>) =
if xs.IsEmpty then xs
else
let cached = System.Collections.Generic.HashSet(itemsToExclude, eq)
xs |> filter cached.Add

let initialize n (f: int -> 'T) =
let root = List.Empty
let mutable node = root
Expand Down Expand Up @@ -525,7 +519,7 @@ let zip3 xs ys zs =

let sortWith (comparer: 'T -> 'T -> int) (xs: 'T list) =
let arr = toArray xs
Array.sortInPlaceWith comparer arr // TODO: use stable sort
Array.sortInPlaceWith comparer arr // Note: In JS this sort is stable
arr |> ofArray

let sort (xs: 'T list) ([<Inject>] comparer: System.Collections.Generic.IComparer<'T>) =
Expand Down Expand Up @@ -646,49 +640,17 @@ let splitAt index (xs: 'T list) =
if index > xs.Length then invalidArg "index" SR.notEnoughElements
take index xs, skip index xs

let distinctBy (projection: 'T -> 'Key) (xs: 'T list) ([<Inject>] eq: System.Collections.Generic.IEqualityComparer<'Key>) =
let hashSet = System.Collections.Generic.HashSet<'Key>(eq)
xs |> filter (projection >> hashSet.Add)

let distinct (xs: 'T list) ([<Inject>] eq: System.Collections.Generic.IEqualityComparer<'T>) =
distinctBy id xs eq

let exactlyOne (xs: 'T list) =
if xs.IsEmpty
then invalidArg "list" SR.inputSequenceEmpty
else
if xs.Tail.IsEmpty then xs.Head
else invalidArg "list" SR.inputSequenceTooLong

let groupBy (projection: 'T -> 'Key) (xs: 'T list) ([<Inject>] eq: System.Collections.Generic.IEqualityComparer<'Key>): ('Key * 'T list) list =
let dict = System.Collections.Generic.Dictionary<'Key, 'T list>(eq)
let mutable keys = List.Empty
xs |> iterate (fun v ->
let key = projection v
match dict.TryGetValue(key) with
| true, prev ->
dict.[key] <- List.Cons(v, prev)
| false, _ ->
dict.Add(key, List.Cons(v, List.Empty))
keys <- List.Cons(key, keys) )
let mutable result = List.Empty
keys |> iterate (fun key -> result <- List.Cons((key, reverse dict.[key]), result))
result

let countBy (projection: 'T -> 'Key) (xs: 'T list) ([<Inject>] eq: System.Collections.Generic.IEqualityComparer<'Key>) =
let dict = System.Collections.Generic.Dictionary<'Key, int>(eq)
let mutable keys = List.Empty
xs |> iterate (fun v ->
let key = projection v
match dict.TryGetValue(key) with
| true, prev ->
dict.[key] <- prev + 1
| false, _ ->
dict.[key] <- 1
keys <- List.Cons(key, keys) )
let mutable result = List.Empty
keys |> iterate (fun key -> result <- List.Cons((key, dict.[key]), result))
result
let tryExactlyOne (xs: 'T list) =
if not (xs.IsEmpty) && xs.Tail.IsEmpty
then Some (xs.Head)
else None

let where predicate (xs: 'T list) =
filter predicate xs
Expand All @@ -712,7 +674,8 @@ let splitInto (chunks: int) (xs: 'T list): 'T list list =

let transpose (lists: seq<'T list>): 'T list list =
lists
|> Seq.map toArray
|> Array.ofSeq
|> Array.map toArray
|> Array.transpose
|> Array.map ofArray
|> ofArray
Expand Down
Loading

0 comments on commit a3802e0

Please sign in to comment.