Skip to content

Commit 3d6c1d9

Browse files
Simplify code
1 parent 28d56ac commit 3d6c1d9

File tree

4 files changed

+173
-274
lines changed

4 files changed

+173
-274
lines changed

src/Fable.Transforms/Dart/DartPrinter.fs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ module PrinterExtensions =
258258
member printer.IsComplex(expr: Expression) =
259259
match expr with
260260
| CommentedExpression(_, e) -> printer.IsComplex(e)
261-
261+
262262
| ThisExpression _
263263
| SuperExpression _
264264
| InterpolationString _
@@ -282,7 +282,7 @@ module PrinterExtensions =
282282
| AnonymousFunction _
283283
| AssignmentExpression _
284284
| EmitExpression _ -> true
285-
285+
286286
member printer.PrintWithParensIfComplex(expr: Expression) =
287287
if printer.IsComplex(expr) then
288288
printer.PrintWithParens(expr)
@@ -389,7 +389,7 @@ module PrinterExtensions =
389389
printer.Print("// " + comment)
390390
printer.PrintNewLine()
391391
printer.Print(statement)
392-
392+
393393
| IfStatement(test, consequent, alternate) ->
394394
printer.PrintIfStatment(test, consequent, alternate)
395395

@@ -470,7 +470,13 @@ module PrinterExtensions =
470470
printer.Print(e)
471471

472472
| LocalVariableDeclaration(ident, kind, value) ->
473-
printer.PrintVariableDeclaration(ident, kind, ?value=value)
473+
match kind, value with
474+
| Final, Some(AnonymousFunction(args, body, genParams, returnType)) ->
475+
let args = args |> List.map FunctionArg
476+
let genParams = genParams |> List.map (fun g -> { Name = g; Extends = None })
477+
printer.PrintFunctionDeclaration(returnType, ident.Name, genParams, args, body)
478+
| _ ->
479+
printer.PrintVariableDeclaration(ident, kind, ?value=value)
474480

475481
| SwitchStatement(discriminant, cases, defaultCase) ->
476482
printer.Print("switch (")
@@ -503,7 +509,7 @@ module PrinterExtensions =
503509
| Some(ContinueStatement _)
504510
| Some(BreakStatement _)
505511
| Some(ReturnStatement _) -> false
506-
| Some(IfStatement(_, consequent, alternate)) -> needsBreak consequent || needsBreak alternate
512+
| Some(IfStatement(_, consequent, alternate)) -> needsBreak consequent || needsBreak alternate
507513
| _ -> true
508514

509515
if needsBreak c.Body then
@@ -528,7 +534,7 @@ module PrinterExtensions =
528534
| CommentedExpression(comment, expr) ->
529535
printer.Print("/* " + comment + " */ ")
530536
printer.Print(expr)
531-
537+
532538
| EmitExpression(value, args, _) ->
533539
printer.PrintEmitExpression(value, args)
534540

@@ -795,7 +801,7 @@ module PrinterExtensions =
795801
if arg.IsConsThisArg then
796802
printer.Print("this." + arg.Ident.Name)
797803
else
798-
printer.PrintIdent(arg.Ident, printType=true)
804+
printer.PrintIdent(arg.Ident, printType=true)
799805

800806
match pos with
801807
| IsSingle | IsLast ->
@@ -809,7 +815,7 @@ module PrinterExtensions =
809815

810816
prevArg <- Some arg
811817
)
812-
818+
813819
member printer.PrintFunctionDeclaration(returnType: Type, name: string, genParams: GenericParam list, args: FunctionArg list, ?body: Statement list, ?isModuleOrClassMember) =
814820
printer.PrintType(returnType)
815821
printer.Print(" ")

src/Fable.Transforms/Dart/Fable2Dart.fs

Lines changed: 49 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -191,90 +191,6 @@ module Util =
191191
| None -> failwithf $"Cannot find DecisionTree target %i{targetIndex}"
192192
| Some(idents, target) -> idents, target
193193

194-
let isConditionalStament ctx guard thenExpr elseExpr =
195-
isStatement ctx guard
196-
|| isStatement ctx thenExpr
197-
|| isStatement ctx elseExpr
198-
199-
let isStatement ctx (e: Fable.Expr) =
200-
match e with
201-
| Fable.Unresolved _
202-
| Fable.Import _ | Fable.IdentExpr _ -> false
203-
204-
| Fable.Test(e,_,_) | Fable.TypeCast(e,_) -> isStatement ctx e
205-
| Fable.Get(e, kind, _, _) ->
206-
match kind with
207-
| Fable.ListHead | Fable.ListTail | Fable.OptionValue | Fable.TupleIndex _ | Fable.UnionTag
208-
| Fable.UnionField _ | Fable.FieldGet _ -> isStatement ctx e
209-
| Fable.ExprGet e2 -> isStatement ctx e || isStatement ctx e2
210-
211-
// Closures cannot be statements because they create their own scope
212-
| Fable.Lambda _ | Fable.Delegate _ | Fable.ObjectExpr _ -> false
213-
214-
| Fable.Value(v,_) ->
215-
match v with
216-
| Fable.UnitConstant _ -> true
217-
| Fable.ThisValue _ | Fable.BaseValue _
218-
| Fable.TypeInfo _ | Fable.Null _
219-
| Fable.BoolConstant _ | Fable.CharConstant _ | Fable.StringConstant _
220-
| Fable.NumberConstant _ | Fable.RegexConstant _ -> false
221-
222-
| Fable.NewRecord(e,_,_)
223-
| Fable.NewAnonymousRecord(e,_,_)
224-
| Fable.NewUnion(e,_,_,_)
225-
| Fable.StringTemplate(_,_,e)
226-
| Fable.NewTuple(e,_) -> List.exists (isStatement ctx) e
227-
| Fable.NewArray(kind,_,_) ->
228-
match kind with
229-
| Fable.ArrayValues e -> List.exists (isStatement ctx) e
230-
| Fable.ArrayAlloc e
231-
| Fable.ArrayFrom e -> isStatement ctx e
232-
| Fable.NewOption(Some e,_,_) -> isStatement ctx e
233-
| Fable.NewOption(None,_,_) -> false
234-
| Fable.NewList(Some(e1,e2),_) -> isStatement ctx e1 || isStatement ctx e2
235-
| Fable.NewList(None,_) -> false
236-
237-
| Fable.CurriedApply(callee, args, _, _) -> callee::(discardSingleUnitArg args) |> List.exists (isStatement ctx)
238-
| Fable.Call(e1, info, _, _) -> e1 :: (Option.toList info.ThisArg) @ (discardSingleUnitArg info.Args) |> List.exists (isStatement ctx)
239-
| Fable.Operation(kind, _, _) ->
240-
match kind with
241-
| Fable.Unary(_, operand) -> isStatement ctx operand
242-
| Fable.Binary(_, left, right) -> isStatement ctx left || isStatement ctx right
243-
| Fable.Logical(_, left, right) -> isStatement ctx left || isStatement ctx right
244-
245-
| Fable.Emit(i,_,_) ->
246-
i.IsStatement
247-
|| (Option.toList i.CallInfo.ThisArg) @ (discardSingleUnitArg i.CallInfo.Args) |> List.exists (isStatement ctx)
248-
249-
| Fable.Set _
250-
| Fable.Let _
251-
| Fable.LetRec _
252-
| Fable.Sequential _
253-
| Fable.TryCatch _
254-
| Fable.ForLoop _
255-
| Fable.WhileLoop _ -> true
256-
257-
| Fable.Extended(kind, _) ->
258-
match kind with
259-
| Fable.RegionStart _ -> true
260-
| Fable.Throw(Some e, _) -> isStatement ctx e
261-
| Fable.Throw(None, _)
262-
| Fable.Debugger _
263-
| Fable.Curry _ -> false
264-
265-
| Fable.DecisionTree(e, targets) ->
266-
// We should also check if one target is duplicated
267-
List.length targets > 2
268-
|| isStatement { ctx with DecisionTargets = targets } e
269-
|| List.exists (snd >> (isStatement ctx)) targets
270-
271-
| Fable.DecisionTreeSuccess(targetIndex,_, _) ->
272-
getDecisionTarget ctx targetIndex
273-
|> snd |> isStatement ctx
274-
275-
| Fable.IfThenElse(guard,thenExpr,elseExpr,_) ->
276-
elseExpr.Type = Fable.Unit || isConditionalStament ctx guard thenExpr elseExpr
277-
278194
let isInt64OrLess = function
279195
| Fable.Number(DartInt, _) -> true
280196
| _ -> false
@@ -441,7 +357,7 @@ module Util =
441357
statements, expr
442358
else
443359
let ident = getUniqueNameInDeclarationScope ctx "tmp" |> makeImmutableIdent expr.Type
444-
let varDecl = localVarDecl ident Final expr
360+
let varDecl = Statement.variableDeclaration(ident, Final, expr)
445361
statements @ [varDecl], ident.Expr
446362
| _ -> statements, ignoreExpr com ctx None
447363

@@ -464,7 +380,7 @@ module Util =
464380
calleeStatements @ argStatements, callee
465381
else
466382
let ident = getUniqueNameInDeclarationScope ctx "tmp" |> makeImmutableIdent callee.Type
467-
let varDecl = localVarDecl ident Final callee
383+
let varDecl = Statement.variableDeclaration(ident, Final, callee)
468384
calleeStatements @ [varDecl] @ argStatements, ident.Expr
469385

470386
let transformExprsAndResolve com ctx returnStrategy exprs transformExprs =
@@ -486,13 +402,6 @@ module Util =
486402
let statements2, capturedExpr = transformExprs exprs[0] exprs[1] |> resolveExpr returnStrategy
487403
statements @ statements2, capturedExpr
488404

489-
let transformExprsAndResolve3 com ctx returnStrategy expr0 expr1 expr2 transformExprs =
490-
List.map (transform com ctx Capture) [expr0; expr1; expr2]
491-
|> combineCapturedExprs com ctx
492-
|> fun (statements, exprs) ->
493-
let statements2, capturedExpr = transformExprs exprs[0] exprs[1] exprs[2] |> resolveExpr returnStrategy
494-
statements @ statements2, capturedExpr
495-
496405
let ignoreExpr com ctx = function
497406
| None -> Expression.nullLiteral Void
498407
| Some expr -> libCall com ctx Fable.Unit "Types" "ignore" [expr]
@@ -839,7 +748,7 @@ module Util =
839748
| Fable.DeclaredType(baseEnt, _), _
840749
when typeImplementsOrExtends com baseEnt expr.Type ->
841750
com.Transform(ctx, returnStrategy, expr)
842-
751+
843752
| Fable.Any, _ -> com.Transform(ctx, returnStrategy, expr)
844753
| Fable.Unit, _ -> com.Transform(ctx, ReturnVoid, expr)
845754

@@ -851,8 +760,8 @@ module Util =
851760

852761
// TODO: Try to identify type testing in the catch clause and use Dart's `on ...` exception checking
853762
let transformTryCatch com ctx _r returnStrategy (body: Fable.Expr, catch, finalizer) =
854-
let returnStrategy, prevStmnt, captureExpr =
855-
convertCaptureStrategyIntoAssign com ctx body.Type returnStrategy
763+
let prevStmnt, returnStrategy, captureExpr =
764+
convertCaptureStrategyIntoAssign com ctx body.Type [] returnStrategy
856765
// try .. catch statements cannot be tail call optimized
857766
let ctx = { ctx with TailCallOpportunity = None }
858767
let handlers =
@@ -869,37 +778,45 @@ module Util =
869778

870779
/// Branching expressions like conditionals, decision trees or try catch cannot capture
871780
/// the resulting expression at once so declare a variable and assign the potential results to it
872-
let convertCaptureStrategyIntoAssign com ctx t returnStrategy =
781+
let convertCaptureStrategyIntoAssign com ctx t prevStatements returnStrategy =
873782
match returnStrategy with
874783
| Capture ->
875784
let t = transformType com ctx t
876785
let ident = getUniqueNameInDeclarationScope ctx "tmp" |> makeImmutableIdent t
877786
let varDecl = Statement.variableDeclaration(ident, Var)
878-
Assign ident.Expr, [varDecl], Some ident.Expr
879-
| _ -> returnStrategy, [], None
787+
varDecl::prevStatements, Assign ident.Expr, Some ident.Expr
788+
| _ -> prevStatements, returnStrategy, None
880789

881790
let transformConditional (com: IDartCompiler) ctx _r returnStrategy guardExpr thenExpr elseExpr =
882-
let asStatement =
791+
let prevStmnt, guardExpr = transformAndCaptureExpr com ctx guardExpr
792+
793+
match guardExpr with
794+
| Literal(BooleanLiteral(value=value)) ->
795+
let bodyStmnt, captureExpr = com.Transform(ctx, returnStrategy, if value then thenExpr else elseExpr)
796+
prevStmnt @ bodyStmnt, captureExpr
797+
798+
| guardExpr ->
799+
let transformAsStatement prevStmnt returnStrategy captureExpr =
800+
let thenStmnt, capturedThen = com.Transform(ctx, returnStrategy, thenExpr)
801+
let elseStmnt, capturedElse = com.Transform(ctx, returnStrategy, elseExpr)
802+
prevStmnt @ [Statement.ifStatement(guardExpr, thenStmnt, elseStmnt)], captureExpr
803+
804+
// If strategy is Capture, try to transform as conditional expression.
805+
// Note we need to transform again thenExpr/elseExpr with Assign strategy if we cannot
806+
// use conditional expression, but I cannot think of a more efficient way at the moment
883807
match returnStrategy with
884-
| ReturnVoid -> true
885-
| Target _ -> true // Compile as statement so values can be bound
886-
| Capture | Assign _ -> isConditionalStament ctx guardExpr thenExpr elseExpr
887-
| Return -> Option.isSome ctx.TailCallOpportunity || isConditionalStament ctx guardExpr thenExpr elseExpr
888-
if not asStatement then
889-
transformExprsAndResolve3 com ctx returnStrategy guardExpr thenExpr elseExpr
890-
(fun guardExpr thenExpr elseExpr -> Expression.conditionalExpression(guardExpr, thenExpr, elseExpr))
891-
else
892-
let prevStmnt, guardExpr = transformAndCaptureExpr com ctx guardExpr
893-
match guardExpr with
894-
| Literal(BooleanLiteral(value=value)) ->
895-
let bodyStmnt, captureExpr = com.Transform(ctx, returnStrategy, if value then thenExpr else elseExpr)
896-
prevStmnt @ bodyStmnt, captureExpr
897-
| guardExpr ->
898-
let returnStrategy, prevStmnt2, captureExpr =
899-
convertCaptureStrategyIntoAssign com ctx thenExpr.Type returnStrategy
900-
let thenStmnt, _ = com.Transform(ctx, returnStrategy, thenExpr)
901-
let elseStmnt, _ = com.Transform(ctx, returnStrategy, elseExpr)
902-
prevStmnt @ prevStmnt2 @ [Statement.ifStatement(guardExpr, thenStmnt, elseStmnt)], captureExpr
808+
| Capture ->
809+
match com.Transform(ctx, Capture, thenExpr) with
810+
| [], Some capturedThenExpr ->
811+
match com.Transform(ctx, Capture, elseExpr) with
812+
| [], Some capturedElseExpr ->
813+
prevStmnt, Expression.conditionalExpression(guardExpr, capturedThenExpr, capturedElseExpr) |> Some
814+
| _ ->
815+
convertCaptureStrategyIntoAssign com ctx thenExpr.Type prevStmnt returnStrategy |||> transformAsStatement
816+
| _ ->
817+
convertCaptureStrategyIntoAssign com ctx thenExpr.Type prevStmnt returnStrategy |||> transformAsStatement
818+
| _ ->
819+
transformAsStatement prevStmnt returnStrategy None
903820

904821
let transformGet (com: IDartCompiler) ctx _range t returnStrategy kind fableExpr =
905822

@@ -1016,24 +933,23 @@ module Util =
1016933
let stmnts2, _ = transform com ctx (Assign toBeSet) value
1017934
stmnts1 @ stmnts2
1018935

1019-
let localVarDecl (ident: Ident) kind value =
1020-
match kind, value with
1021-
| Final, AnonymousFunction(args, body, genParams, returnType) ->
1022-
let args = args |> List.map FunctionArg
1023-
let genParams = genParams |> List.map (fun g -> { Name = g; Extends = None })
1024-
Statement.functionDeclaration(ident.Name, args, body, returnType, genParams=genParams)
1025-
| _ ->
1026-
Statement.variableDeclaration(ident, Var, value)
1027-
1028936
let transformBinding (com: IDartCompiler) ctx (var: Fable.Ident) (value: Fable.Expr) =
1029937
let ident = transformIdent com ctx var
1030-
let valueStmnts, value = transformAndCaptureExpr com ctx value
938+
let valueStmnts, value =
939+
match value with
940+
| Function(args, body) ->
941+
let genParams = args |> List.map (fun a -> a.Type) |> getLocalFunctionGenericParams com ctx
942+
// Pass the name of the bound ident to enable tail-call optimizations
943+
let args, body, returnType = transformFunction com ctx (Some var.Name) args body
944+
[], Expression.anonymousFunction(args, body, returnType, genParams)
945+
| _ -> transformAndCaptureExpr com ctx value
1031946
let kind, value = getVarKind ctx var.IsMutable value
1032947
let ctx =
1033948
match kind with
1034949
| Const -> { ctx with ConstIdents = Set.add ident.Name ctx.ConstIdents }
1035950
| Var | Final -> ctx
1036-
ctx, valueStmnts @ [localVarDecl ident kind value]
951+
// If value is an anonymous function this will be converted into function declaration in printing step
952+
ctx, valueStmnts @ [Statement.variableDeclaration(ident, kind, value)]
1037953

1038954
let transformSwitch (com: IDartCompiler) ctx returnStrategy evalExpr cases defaultCase =
1039955
let cases =
@@ -1216,7 +1132,7 @@ module Util =
12161132
let transformDecisionTree (com: IDartCompiler) (ctx: Context) returnStrategy
12171133
(targets: (Fable.Ident list * Fable.Expr) list) (treeExpr: Fable.Expr) =
12181134
let t = treeExpr.Type
1219-
let returnStrategy, prevStmnt, captureExpr = convertCaptureStrategyIntoAssign com ctx t returnStrategy
1135+
let prevStmnt, returnStrategy, captureExpr = convertCaptureStrategyIntoAssign com ctx t [] returnStrategy
12201136
let resolve stmnts = prevStmnt @ stmnts, captureExpr
12211137

12221138
// If some targets are referenced multiple times, hoist bound idents,
@@ -1571,7 +1487,7 @@ module Util =
15711487
ident, InstanceVariable(ident, kind=kind))
15721488
|> List.unzip
15731489

1574-
let consArgs = fields |> List.map (fun f -> FunctionArg(f, isConsThisArg=true))
1490+
let consArgs = fields |> List.map (fun f -> FunctionArg(f, isConsThisArg=true))
15751491
let constructor = Constructor(args=consArgs, isConst=not hasMutableFields)
15761492

15771493
// TODO: implement toString
@@ -1657,7 +1573,7 @@ module Util =
16571573

16581574
let transformAttachedMember (com: IDartCompiler) ctx (memb: Fable.MemberDecl) =
16591575
let isStatic = not memb.Info.IsInstance
1660-
let entAndMembGenParams =
1576+
let entAndMembGenParams =
16611577
match memb.DeclaringEntity with
16621578
| Some e ->
16631579
let e = com.GetEntity(e)

0 commit comments

Comments
 (0)