Skip to content

Commit

Permalink
Array-based List type
Browse files Browse the repository at this point in the history
  • Loading branch information
ncave committed Oct 1, 2020
1 parent 0198451 commit bcea005
Show file tree
Hide file tree
Showing 5 changed files with 551 additions and 427 deletions.
35 changes: 18 additions & 17 deletions src/Fable.Transforms/Fable2Babel.fs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ module Annotation =
makeNativeTypeAnnotation com ctx [genArg] "Array"

let makeListTypeAnnotation com ctx genArg =
makeImportTypeAnnotation com ctx [genArg] "Types" "List"
makeImportTypeAnnotation com ctx [genArg] "List" "List"

let makeUnionTypeAnnotation com ctx genArgs =
List.map (typeAnnotation com ctx) genArgs
Expand Down Expand Up @@ -645,12 +645,6 @@ module Util =
| [] -> expr
| m::ms -> get None expr m |> getParts ms

let makeList com ctx r headAndTail =
match headAndTail with
| None -> [||]
| Some(TransformExpr com ctx head, TransformExpr com ctx tail) -> [|head; tail|]
|> libConsCall com ctx r "Types" "List"

let makeArray (com: IBabelCompiler) ctx exprs =
List.mapToArray (fun e -> com.TransformAsExpr(ctx, e)) exprs
|> ArrayExpression :> Expression
Expand Down Expand Up @@ -894,12 +888,17 @@ module Util =
| Fable.NewTuple vals -> makeArray com ctx vals
// Optimization for bundle size: compile list literals as List.ofArray
| Replacements.ListLiteral(exprs, t) ->
match exprs with
| [] -> makeList com ctx r None
| [expr] -> Some(expr, Fable.Value(Fable.NewList (None,t), None)) |> makeList com ctx r
| exprs -> [|makeArray com ctx exprs|] |> libCall com ctx r "List" "ofArray"
[|List.rev exprs |> makeArray com ctx|]
|> libCall com ctx r "List" "newList"
// match exprs with
// | [] -> libCall com ctx r "List" "empty" [||]
// | [TransformExpr com ctx expr] -> libCall com ctx r "List" "singleton" [|expr|]
// | exprs -> [|makeArray com ctx exprs|] |> libCall com ctx r "List" "ofArray"
| Fable.NewList (headAndTail, _) ->
makeList com ctx r headAndTail
match headAndTail with
| None -> libCall com ctx r "List" "empty" [||]
| Some(TransformExpr com ctx head, TransformExpr com ctx tail) ->
libCall com ctx r "List" "cons" [|head; tail|]
| Fable.NewOption (value, t) ->
match value with
| Some (TransformExpr com ctx e) ->
Expand Down Expand Up @@ -1153,10 +1152,12 @@ module Util =
| Fable.FieldKey field -> get range expr field.Name

| Fable.ListHead ->
get range (com.TransformAsExpr(ctx, fableExpr)) "head"
// get range (com.TransformAsExpr(ctx, fableExpr)) "head"
libCall com ctx range "List" "head" [|com.TransformAsExpr(ctx, fableExpr)|]

| Fable.ListTail ->
get range (com.TransformAsExpr(ctx, fableExpr)) "tail"
// get range (com.TransformAsExpr(ctx, fableExpr)) "tail"
libCall com ctx range "List" "tail" [|com.TransformAsExpr(ctx, fableExpr)|]

| Fable.TupleIndex index ->
match fableExpr with
Expand Down Expand Up @@ -1224,9 +1225,9 @@ module Util =
let op = if nonEmpty then BinaryUnequal else BinaryEqual
upcast BinaryExpression(op, com.TransformAsExpr(ctx, expr), NullLiteral(), ?loc=range)
| Fable.ListTest nonEmpty ->
let expr = com.TransformAsExpr(ctx, expr)
let op = if nonEmpty then BinaryUnequal else BinaryEqual
upcast BinaryExpression(op, get None expr "tail", NullLiteral(), ?loc=range)
// let expr = get range (com.TransformAsExpr(ctx, expr)) "IsEmpty"
let expr = libCall com ctx range "List" "isEmpty" [|com.TransformAsExpr(ctx, expr)|]
if nonEmpty then upcast UnaryExpression(UnaryNot, expr, ?loc=range) else expr
| Fable.UnionCaseTest tag ->
let expected = ofInt tag
let actual = com.TransformAsExpr(ctx, expr) |> getUnionExprTag None
Expand Down
29 changes: 13 additions & 16 deletions src/Fable.Transforms/Replacements.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1794,29 +1794,26 @@ let arrayModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Ex
Helper.LibCall(com, "Array", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some

let lists (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) =
let meth = Naming.removeGetSetPrefix i.CompiledName |> Naming.lowerFirst
match i.CompiledName, thisArg, args with
// Use methods for Head and Tail (instead of Get(ListHead) for example) to check for empty lists
| ReplaceName
[ "get_Head", "head"
"get_Tail", "tail"
"get_Item", "item"
"get_Length", "length"
"GetSlice", "slice" ] methName, Some x, _ ->
let args = match args with [ExprType Unit] -> [x] | args -> args @ [x]
Helper.LibCall(com, "List", methName, t, args, i.SignatureArgTypes, ?loc=r) |> Some
| "get_IsEmpty", Some x, _ -> Test(x, ListTest false, r) |> Some
| "get_Empty", None, _ -> NewList(None, (genArg com ctx r 0 i.GenericArgs)) |> makeValue r |> Some
| "Cons", None, [h;t] -> NewList(Some(h,t), (genArg com ctx r 0 i.GenericArgs)) |> makeValue r |> Some
| ("get_Head" | "get_Tail" | "get_IsEmpty" | "get_Length"), Some x, _ ->
Helper.LibCall(com, "List", meth, t, [x], i.SignatureArgTypes, ?loc=r) |> Some
// get r t x meth |> Some
| ("get_Item" | "GetSlice"), Some x, _ ->
Helper.LibCall(com, "List", meth, t, args @ [x], i.SignatureArgTypes, ?loc=r) |> Some
| ("get_Empty" | "Cons"), None, _ ->
Helper.LibCall(com, "List", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some
| ("GetHashCode" | "Equals" | "CompareTo"), Some callee, _ ->
Helper.InstanceCall(callee, i.CompiledName, t, args, i.SignatureArgTypes, ?loc=r) |> Some
| _ -> None

let listModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Expr option) (args: Expr list) =
match i.CompiledName, args with
| "IsEmpty", [x] -> Test(x, ListTest false, r) |> Some
| "Empty", _ -> NewList(None, (genArg com ctx r 0 i.GenericArgs)) |> makeValue r |> Some
| "Singleton", [x] ->
NewList(Some(x, Value(NewList(None, t), None)), (genArg com ctx r 0 i.GenericArgs)) |> makeValue r |> Some
// | ("Head" | "Tail" | "IsEmpty") as meth, [x] -> get r t x (Naming.lowerFirst meth) |> Some
// | "IsEmpty", [x] -> Test(x, ListTest false, r) |> Some
// | "Empty", _ -> NewList(None, (genArg com ctx r 0 i.GenericArgs)) |> makeValue r |> Some
// | "Singleton", [x] ->
// NewList(Some(x, Value(NewList(None, t), None)), (genArg com ctx r 0 i.GenericArgs)) |> makeValue r |> Some
// 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
Expand Down
Loading

0 comments on commit bcea005

Please sign in to comment.