From 9681897911d355319d3cd0e658013406daa1594a Mon Sep 17 00:00:00 2001 From: Dag Brattli Date: Sun, 16 Jan 2022 10:43:33 +0100 Subject: [PATCH 1/4] [Python] Use Fantomas formatting and check CI --- .config/dotnet-tools.json | 12 + .editorconfig | 9 + src/Fable.Transforms/Python/Fable2Python.fs | 3256 ++++++++----- src/Fable.Transforms/Python/Prelude.fs | 112 +- src/Fable.Transforms/Python/Python.fs | 142 +- src/Fable.Transforms/Python/PythonPrinter.fs | 127 +- src/Fable.Transforms/Python/Replacements.fs | 4429 ++++++++++++------ 7 files changed, 5176 insertions(+), 2911 deletions(-) create mode 100644 .config/dotnet-tools.json diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000000..50b7ad3532 --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,12 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "fantomas-tool": { + "version": "4.6.0", + "commands": [ + "fantomas" + ] + } + } +} \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index 21a38b33c1..7accf0334e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -7,3 +7,12 @@ indent_style = space # TS files [*.ts] indent_size = 2 + +# Fantomas (see https://github.com/fsprojects/fantomas/blob/master/docs/Documentation.md) +[*.fs] +indent_size=4 +max_line_length=140 +fsharp_space_before_uppercase_invocation=false +fsharp_space_before_member=false +fsharp_space_around_delimiter=true +fsharp_multiline_block_brackets_on_same_column=false \ No newline at end of file diff --git a/src/Fable.Transforms/Python/Fable2Python.fs b/src/Fable.Transforms/Python/Fable2Python.fs index b738dbe81d..6b7acf267f 100644 --- a/src/Fable.Transforms/Python/Fable2Python.fs +++ b/src/Fable.Transforms/Python/Fable2Python.fs @@ -1,4 +1,3 @@ - module rec Fable.Transforms.Fable2Python open System @@ -26,9 +25,9 @@ type ArgsInfo = | NoCallInfo of args: Fable.Expr list type Import = - { Module: string - LocalIdent: Identifier option - Name: string option } + { Module: string + LocalIdent: Identifier option + Name: string option } type ITailCallOpportunity = abstract Label: string @@ -36,9 +35,9 @@ type ITailCallOpportunity = abstract IsRecursiveRef: Fable.Expr -> bool type UsedNames = - { RootScope: HashSet - DeclarationScopes: HashSet - CurrentDeclarationScope: HashSet } + { RootScope: HashSet + DeclarationScopes: HashSet + CurrentDeclarationScope: HashSet } /// Python specific, used for keeping track of existing variable bindings to /// know if we need to declare an identifier as nonlocal or global. @@ -47,38 +46,42 @@ type BoundVars = EnclosingScope: HashSet LocalScope: HashSet } - member this.EnterScope () = + member this.EnterScope() = let enclosingScope = HashSet() enclosingScope.UnionWith(this.EnclosingScope) enclosingScope.UnionWith(this.LocalScope) - { this with LocalScope = HashSet (); EnclosingScope = enclosingScope } - member this.Bind(name: string) = - this.LocalScope.Add name |> ignore + { this with + LocalScope = HashSet() + EnclosingScope = enclosingScope } + + member this.Bind(name: string) = this.LocalScope.Add name |> ignore member this.Bind(ids: Identifier list) = for (Identifier name) in ids do this.LocalScope.Add name |> ignore member this.NonLocals(idents: Identifier list) = - [ - for ident in idents do - let (Identifier name) = ident - if not (this.LocalScope.Contains name) && this.EnclosingScope.Contains name then - ident - else - this.Bind(name) - ] + [ for ident in idents do + let (Identifier name) = ident + + if + not (this.LocalScope.Contains name) + && this.EnclosingScope.Contains name + then + ident + else + this.Bind(name) ] type Context = - { File: Fable.File - UsedNames: UsedNames - BoundVars: BoundVars - DecisionTargets: (Fable.Ident list * Fable.Expr) list - HoistVars: Fable.Ident list -> bool - TailCallOpportunity: ITailCallOpportunity option - OptimizeTailCall: unit -> unit - ScopedTypeParams: Set } + { File: Fable.File + UsedNames: UsedNames + BoundVars: BoundVars + DecisionTargets: (Fable.Ident list * Fable.Expr) list + HoistVars: Fable.Ident list -> bool + TailCallOpportunity: ITailCallOpportunity option + OptimizeTailCall: unit -> unit + ScopedTypeParams: Set } type IPythonCompiler = inherit Compiler @@ -90,7 +93,7 @@ type IPythonCompiler = abstract GetImportExpr: Context * moduleName: string * ?name: string * ?loc: SourceLocation -> Expression abstract TransformAsExpr: Context * Fable.Expr -> Expression * Statement list abstract TransformAsStatements: Context * ReturnStrategy option * Fable.Expr -> Statement list - abstract TransformImport: Context * selector:string * path:string -> Expression + abstract TransformImport: Context * selector: string * path: string -> Expression abstract TransformFunction: Context * string option * Fable.Ident list * Fable.Expr * Set -> Arguments * Statement list abstract WarnOnlyOnce: string * ?range: SourceLocation -> unit @@ -99,13 +102,12 @@ type IPythonCompiler = // to become independent of the specific implementation module Lib = let libCall (com: IPythonCompiler) ctx r moduleName memberName args = - Expression.call(com.TransformImport(ctx, memberName, getLibPath com moduleName), args, ?loc=r) + Expression.call (com.TransformImport(ctx, memberName, getLibPath com moduleName), args, ?loc = r) let libConsCall (com: IPythonCompiler) ctx r moduleName memberName args = - Expression.call(com.TransformImport(ctx, memberName, getLibPath com moduleName), args, ?loc=r) + Expression.call (com.TransformImport(ctx, memberName, getLibPath com moduleName), args, ?loc = r) - let libValue (com: IPythonCompiler) ctx moduleName memberName = - com.TransformImport(ctx, memberName, getLibPath com moduleName) + let libValue (com: IPythonCompiler) ctx moduleName memberName = com.TransformImport(ctx, memberName, getLibPath com moduleName) let tryPyConstructor (com: IPythonCompiler) ctx ent = match PY.Replacements.tryPyConstructor com ent with @@ -119,119 +121,169 @@ module Lib = module Reflection = open Lib - let private libReflectionCall (com: IPythonCompiler) ctx r memberName args = - libCall com ctx r "reflection" (memberName + "_type") args + let private libReflectionCall (com: IPythonCompiler) ctx r memberName args = libCall com ctx r "reflection" (memberName + "_type") args let private transformRecordReflectionInfo com ctx r (ent: Fable.Entity) generics = // TODO: Refactor these three bindings to reuse in transformUnionReflectionInfo let fullname = ent.FullName - let fullnameExpr = Expression.constant(fullname) + let fullnameExpr = Expression.constant (fullname) + let genMap = - let genParamNames = ent.GenericParameters |> List.mapToArray (fun x -> x.Name) |> Seq.toList + let genParamNames = + ent.GenericParameters + |> List.mapToArray (fun x -> x.Name) + |> Seq.toList + List.zip genParamNames generics |> Map + let fields, stmts = - ent.FSharpFields |> Seq.map (fun fi -> - let typeInfo, stmts = transformTypeInfo com ctx r genMap fi.FieldType - (Expression.list([ Expression.constant(fi.Name); typeInfo ])), stmts) + ent.FSharpFields + |> Seq.map (fun fi -> + let typeInfo, stmts = + transformTypeInfo com ctx r genMap fi.FieldType + + (Expression.list ([ Expression.constant (fi.Name); typeInfo ])), stmts) |> Seq.toList |> Helpers.unzipArgs - let fields = Expression.lambda(Arguments.arguments [], Expression.list(fields)) + + let fields = + Expression.lambda (Arguments.arguments [], Expression.list (fields)) + let py, stmts' = pyConstructor com ctx ent - [ fullnameExpr; Expression.list(generics); py; fields ] - |> libReflectionCall com ctx None "record", stmts @ stmts' + + [ fullnameExpr; Expression.list (generics); py; fields ] + |> libReflectionCall com ctx None "record", + stmts @ stmts' let private transformUnionReflectionInfo com ctx r (ent: Fable.Entity) generics = let fullname = ent.FullName - let fullnameExpr = Expression.constant(fullname) + let fullnameExpr = Expression.constant (fullname) + let genMap = - let genParamNames = ent.GenericParameters |> List.map (fun x -> x.Name) |> Seq.toList + let genParamNames = + ent.GenericParameters + |> List.map (fun x -> x.Name) + |> Seq.toList + List.zip genParamNames generics |> Map + let cases = - ent.UnionCases |> Seq.map (fun uci -> - uci.UnionCaseFields |> List.map (fun fi -> - Expression.list([ - fi.Name |> Expression.constant - let expr, stmts = transformTypeInfo com ctx r genMap fi.FieldType - expr - ])) - |> Expression.list - ) |> Seq.toList - let cases = Expression.lambda(Arguments.arguments [], Expression.list(cases)) + ent.UnionCases + |> Seq.map (fun uci -> + uci.UnionCaseFields + |> List.map (fun fi -> + Expression.list ( + [ fi.Name |> Expression.constant + let expr, stmts = + transformTypeInfo com ctx r genMap fi.FieldType + + expr ] + )) + |> Expression.list) + |> Seq.toList + + let cases = + Expression.lambda (Arguments.arguments [], Expression.list (cases)) + let py, stmts = pyConstructor com ctx ent - [ fullnameExpr; Expression.list(generics); py; cases ] - |> libReflectionCall com ctx None "union", stmts - - let transformTypeInfo (com: IPythonCompiler) ctx r (genMap: Map) t: Expression * Statement list = - let primitiveTypeInfo name = - libValue com ctx "Reflection" (name + "_type") - let numberInfo kind = - getNumberKindName kind - |> primitiveTypeInfo + + [ fullnameExpr; Expression.list (generics); py; cases ] + |> libReflectionCall com ctx None "union", + stmts + + let transformTypeInfo (com: IPythonCompiler) ctx r (genMap: Map) t : Expression * Statement list = + let primitiveTypeInfo name = libValue com ctx "Reflection" (name + "_type") + let numberInfo kind = getNumberKindName kind |> primitiveTypeInfo + let nonGenericTypeInfo fullname = - [ Expression.constant(fullname) ] + [ Expression.constant (fullname) ] |> libReflectionCall com ctx None "class" - let resolveGenerics generics: Expression list * Statement list = - generics |> Array.map (transformTypeInfo com ctx r genMap) |> List.ofArray |> Helpers.unzipArgs + + let resolveGenerics generics : Expression list * Statement list = + generics + |> Array.map (transformTypeInfo com ctx r genMap) + |> List.ofArray + |> Helpers.unzipArgs + let genericTypeInfo name genArgs = let resolved, stmts = resolveGenerics genArgs libReflectionCall com ctx None name resolved, stmts + let genericEntity (fullname: string) (generics: Expression list) = - libReflectionCall com ctx None "class" [ - Expression.constant(fullname) - if not(List.isEmpty generics) then - Expression.list(generics) - ] + libReflectionCall + com + ctx + None + "class" + [ Expression.constant (fullname) + if not (List.isEmpty generics) then + Expression.list (generics) ] + match t with | Fable.Measure _ | Fable.Any -> primitiveTypeInfo "obj", [] - | Fable.GenericParam(name,_) -> + | Fable.GenericParam (name, _) -> match Map.tryFind name genMap with | Some t -> t, [] | None -> - Replacements.genericTypeInfoError name |> addError com [] r + Replacements.genericTypeInfoError name + |> addError com [] r + Expression.none, [] - | Fable.Unit -> primitiveTypeInfo "unit", [] + | Fable.Unit -> primitiveTypeInfo "unit", [] | Fable.Boolean -> primitiveTypeInfo "bool", [] - | Fable.Char -> primitiveTypeInfo "char", [] - | Fable.String -> primitiveTypeInfo "string", [] + | Fable.Char -> primitiveTypeInfo "char", [] + | Fable.String -> primitiveTypeInfo "string", [] | Fable.Enum entRef -> let ent = com.GetEntity(entRef) let mutable numberKind = Int32 + let cases = - ent.FSharpFields |> Seq.choose (fun fi -> + ent.FSharpFields + |> Seq.choose (fun fi -> // F# seems to include a field with this name in the underlying type match fi.Name with | "value__" -> match fi.FieldType with - | Fable.Number(kind,_) -> numberKind <- kind + | Fable.Number (kind, _) -> numberKind <- kind | _ -> () + None | name -> - let value = match fi.LiteralValue with Some v -> System.Convert.ToDouble v | None -> 0. - Expression.list([ Expression.constant(name); Expression.constant(value) ]) |> Some) + let value = + match fi.LiteralValue with + | Some v -> System.Convert.ToDouble v + | None -> 0. + + Expression.list ([ Expression.constant (name); Expression.constant (value) ]) + |> Some) |> Seq.toList |> Expression.list - [ Expression.constant(entRef.FullName); numberInfo numberKind; cases ] - |> libReflectionCall com ctx None "enum", [] - | Fable.Number(kind,_) -> - numberInfo kind, [] - | Fable.LambdaType(argType, returnType) -> - genericTypeInfo "lambda" [|argType; returnType|] - | Fable.DelegateType(argTypes, returnType) -> - genericTypeInfo "delegate" ([|yield! argTypes; yield returnType|]) - | Fable.Tuple(genArgs,_) -> genericTypeInfo "tuple" (List.toArray genArgs) - | Fable.Option(genArg,_) -> genericTypeInfo "option" [|genArg|] - | Fable.Array genArg -> genericTypeInfo "array" [|genArg|] - | Fable.List genArg -> genericTypeInfo "list" [|genArg|] - | Fable.Regex -> nonGenericTypeInfo Types.regex, [] - | Fable.MetaType -> nonGenericTypeInfo Types.type_, [] - | Fable.AnonymousRecordType(fieldNames, genArgs) -> + + [ Expression.constant (entRef.FullName); numberInfo numberKind; cases ] + |> libReflectionCall com ctx None "enum", + [] + | Fable.Number (kind, _) -> numberInfo kind, [] + | Fable.LambdaType (argType, returnType) -> genericTypeInfo "lambda" [| argType; returnType |] + | Fable.DelegateType (argTypes, returnType) -> genericTypeInfo "delegate" ([| yield! argTypes; yield returnType |]) + | Fable.Tuple (genArgs, _) -> genericTypeInfo "tuple" (List.toArray genArgs) + | Fable.Option (genArg, _) -> genericTypeInfo "option" [| genArg |] + | Fable.Array genArg -> genericTypeInfo "array" [| genArg |] + | Fable.List genArg -> genericTypeInfo "list" [| genArg |] + | Fable.Regex -> nonGenericTypeInfo Types.regex, [] + | Fable.MetaType -> nonGenericTypeInfo Types.type_, [] + | Fable.AnonymousRecordType (fieldNames, genArgs) -> let genArgs, stmts = resolveGenerics (List.toArray genArgs) + List.zip (List.ofArray fieldNames) genArgs - |> List.map (fun (k, t) -> Expression.list[ Expression.constant(k); t ]) - |> libReflectionCall com ctx None "anonRecord", stmts - | Fable.DeclaredType(entRef, generics) -> + |> List.map (fun (k, t) -> + Expression.list[Expression.constant (k) + t]) + |> libReflectionCall com ctx None "anonRecord", + stmts + | Fable.DeclaredType (entRef, generics) -> let fullName = entRef.FullName + match fullName, generics with | Replacements.BuiltinEntity kind -> match kind with @@ -250,44 +302,62 @@ module Reflection = | Replacements.FSharpSet gen -> let gens, stmts = transformTypeInfo com ctx r genMap gen genericEntity fullName [ gens ], stmts - | Replacements.BclDictionary(key, value) - | Replacements.BclKeyValuePair(key, value) - | Replacements.FSharpMap(key, value) -> + | Replacements.BclDictionary (key, value) + | Replacements.BclKeyValuePair (key, value) + | Replacements.FSharpMap (key, value) -> let keys, stmts = transformTypeInfo com ctx r genMap key let values, stmts' = transformTypeInfo com ctx r genMap value - genericEntity fullName [ - keys - values - ], stmts @ stmts' - | Replacements.FSharpResult(ok, err) -> + genericEntity fullName [ keys; values ], stmts @ stmts' + | Replacements.FSharpResult (ok, err) -> let ent = com.GetEntity(entRef) let ok', stmts = transformTypeInfo com ctx r genMap ok let err', stmts' = transformTypeInfo com ctx r genMap err - let expr, stmts'' = transformUnionReflectionInfo com ctx r ent [ ok'; err' ] + + let expr, stmts'' = + transformUnionReflectionInfo com ctx r ent [ ok'; err' ] + expr, stmts @ stmts' @ stmts'' | Replacements.FSharpChoice gen -> let ent = com.GetEntity(entRef) - let gen, stmts = List.map (transformTypeInfo com ctx r genMap) gen |> Helpers.unzipArgs - let expr, stmts' = gen |> transformUnionReflectionInfo com ctx r ent + + let gen, stmts = + List.map (transformTypeInfo com ctx r genMap) gen + |> Helpers.unzipArgs + + let expr, stmts' = + gen |> transformUnionReflectionInfo com ctx r ent + expr, stmts @ stmts' | Replacements.FSharpReference gen -> let ent = com.GetEntity(entRef) let gen, stmts = transformTypeInfo com ctx r genMap gen - let expr, stmts' = [ gen ] |> transformRecordReflectionInfo com ctx r ent + + let expr, stmts' = + [ gen ] + |> transformRecordReflectionInfo com ctx r ent + expr, stmts @ stmts' | _ -> let ent = com.GetEntity(entRef) - let generics, stmts = generics |> List.map (transformTypeInfo com ctx r genMap) |> Helpers.unzipArgs + + let generics, stmts = + generics + |> List.map (transformTypeInfo com ctx r genMap) + |> Helpers.unzipArgs /// Check if the entity is actually declared in JS code if ent.IsInterface - || FSharp2Fable.Util.isErasedOrStringEnumEntity ent - || FSharp2Fable.Util.isGlobalOrImportedEntity ent - || FSharp2Fable.Util.isReplacementCandidate ent then + || FSharp2Fable.Util.isErasedOrStringEnumEntity ent + || FSharp2Fable.Util.isGlobalOrImportedEntity ent + || FSharp2Fable.Util.isReplacementCandidate ent then genericEntity ent.FullName generics, stmts else - let reflectionMethodExpr = FSharp2Fable.Util.entityRefWithSuffix com ent Naming.reflectionSuffix - let callee, stmts' = com.TransformAsExpr(ctx, reflectionMethodExpr) - Expression.call(callee, generics), stmts @ stmts' + let reflectionMethodExpr = + FSharp2Fable.Util.entityRefWithSuffix com ent Naming.reflectionSuffix + + let callee, stmts' = + com.TransformAsExpr(ctx, reflectionMethodExpr) + + Expression.call (callee, generics), stmts @ stmts' let transformReflectionInfo com ctx r (ent: Fable.Entity) generics = if ent.IsFSharpRecord then @@ -296,117 +366,135 @@ module Reflection = transformUnionReflectionInfo com ctx r ent generics else let fullname = ent.FullName + let exprs, stmts = - [ - yield Expression.constant(fullname), [] - match generics with - | [] -> yield Util.undefined None, [] - | generics -> yield Expression.list(generics), [] - match tryPyConstructor com ctx ent with - | Some (cons, stmts) -> yield cons, stmts - | None -> () - match ent.BaseType with - | Some d -> - let genMap = - Seq.zip ent.GenericParameters generics - |> Seq.map (fun (p, e) -> p.Name, e) - |> Map - yield Fable.DeclaredType(d.Entity, d.GenericArgs) - |> transformTypeInfo com ctx r genMap - | None -> () - ] + [ yield Expression.constant (fullname), [] + match generics with + | [] -> yield Util.undefined None, [] + | generics -> yield Expression.list (generics), [] + match tryPyConstructor com ctx ent with + | Some (cons, stmts) -> yield cons, stmts + | None -> () + match ent.BaseType with + | Some d -> + let genMap = + Seq.zip ent.GenericParameters generics + |> Seq.map (fun (p, e) -> p.Name, e) + |> Map + + yield + Fable.DeclaredType(d.Entity, d.GenericArgs) + |> transformTypeInfo com ctx r genMap + | None -> () ] |> Helpers.unzipArgs - exprs - |> libReflectionCall com ctx r "class", stmts - let private ofString s = Expression.constant(s) - let private ofArray babelExprs = Expression.list(babelExprs) + exprs |> libReflectionCall com ctx r "class", stmts - let transformTypeTest (com: IPythonCompiler) ctx range expr (typ: Fable.Type): Expression * Statement list = + let private ofString s = Expression.constant (s) + let private ofArray babelExprs = Expression.list (babelExprs) + + let transformTypeTest (com: IPythonCompiler) ctx range expr (typ: Fable.Type) : Expression * Statement list = let warnAndEvalToFalse msg = "Cannot type test (evals to false): " + msg |> addWarning com [] range - Expression.constant(false) - let pyTypeof (primitiveType: string) (Util.TransformExpr com ctx (expr, stmts)): Expression * Statement list = + Expression.constant (false) + + let pyTypeof (primitiveType: string) (Util.TransformExpr com ctx (expr, stmts)) : Expression * Statement list = let typeof = let func = Expression.name (Identifier("type")) let str = Expression.name (Identifier("str")) - let typ = Expression.call (func, [expr]) - Expression.call (str, [typ]) - Expression.compare(typeof, [ Eq ], [ Expression.constant(primitiveType)], ?loc=range), stmts + let typ = Expression.call (func, [ expr ]) + Expression.call (str, [ typ ]) - let jsInstanceof consExpr (Util.TransformExpr com ctx (expr, stmts)): Expression * Statement list= + Expression.compare (typeof, [ Eq ], [ Expression.constant (primitiveType) ], ?loc = range), stmts + + let jsInstanceof consExpr (Util.TransformExpr com ctx (expr, stmts)) : Expression * Statement list = let func = Expression.name (Identifier("isinstance")) let args = [ expr; consExpr ] Expression.call (func, args), stmts match typ with | Fable.Measure _ // Dummy, shouldn't be possible to test against a measure type - | Fable.Any -> Expression.constant(true), [] + | Fable.Any -> Expression.constant (true), [] | Fable.Unit -> let expr, stmts = com.TransformAsExpr(ctx, expr) - Expression.compare(expr, [ Is ], [ Util.undefined None ], ?loc=range), stmts + Expression.compare (expr, [ Is ], [ Util.undefined None ], ?loc = range), stmts | Fable.Boolean -> pyTypeof "" expr - | Fable.Char | Fable.String _ -> pyTypeof "" expr - | Fable.Number _ | Fable.Enum _ -> pyTypeof "" expr - | Fable.Regex -> jsInstanceof (Expression.identifier("RegExp")) expr - | Fable.LambdaType _ | Fable.DelegateType _ -> pyTypeof "" expr - | Fable.Array _ | Fable.Tuple _ -> + | Fable.Char + | Fable.String _ -> pyTypeof "" expr + | Fable.Number _ + | Fable.Enum _ -> pyTypeof "" expr + | Fable.Regex -> jsInstanceof (Expression.identifier ("RegExp")) expr + | Fable.LambdaType _ + | Fable.DelegateType _ -> pyTypeof "" expr + | Fable.Array _ + | Fable.Tuple _ -> let expr, stmts = com.TransformAsExpr(ctx, expr) libCall com ctx None "util" "isArrayLike" [ expr ], stmts - | Fable.List _ -> - jsInstanceof (libValue com ctx "List" "FSharpList") expr - | Fable.AnonymousRecordType _ -> - warnAndEvalToFalse "anonymous records", [] - | Fable.MetaType -> - jsInstanceof (libValue com ctx "Reflection" "TypeInfo") expr + | Fable.List _ -> jsInstanceof (libValue com ctx "List" "FSharpList") expr + | Fable.AnonymousRecordType _ -> warnAndEvalToFalse "anonymous records", [] + | Fable.MetaType -> jsInstanceof (libValue com ctx "Reflection" "TypeInfo") expr | Fable.Option _ -> warnAndEvalToFalse "options", [] // TODO | Fable.GenericParam _ -> warnAndEvalToFalse "generic parameters", [] | Fable.DeclaredType (ent, genArgs) -> match ent.FullName with | Types.idisposable -> match expr with - | MaybeCasted(ExprType(Fable.DeclaredType (ent2, _))) - when com.GetEntity(ent2) |> FSharp2Fable.Util.hasInterface Types.idisposable -> - Expression.constant(true), [] + | MaybeCasted (ExprType (Fable.DeclaredType (ent2, _))) when + com.GetEntity(ent2) + |> FSharp2Fable.Util.hasInterface Types.idisposable + -> + Expression.constant (true), [] | _ -> let expr, stmts = com.TransformAsExpr(ctx, expr) libCall com ctx None "util" "isDisposable" [ expr ], stmts | Types.ienumerable -> let expr, stmts = com.TransformAsExpr(ctx, expr) + [ expr ] - |> libCall com ctx None "util" "isIterable", stmts + |> libCall com ctx None "util" "isIterable", + stmts | Types.array -> let expr, stmts = com.TransformAsExpr(ctx, expr) + [ expr ] - |> libCall com ctx None "util" "isArrayLike", stmts + |> libCall com ctx None "util" "isArrayLike", + stmts | Types.exception_ -> let expr, stmts = com.TransformAsExpr(ctx, expr) + [ expr ] - |> libCall com ctx None "types" "isException", stmts + |> libCall com ctx None "types" "isException", + stmts | _ -> let ent = com.GetEntity(ent) + if ent.IsInterface then warnAndEvalToFalse "interfaces", [] else match tryPyConstructor com ctx ent with | Some (cons, stmts) -> - if not(List.isEmpty genArgs) then - com.WarnOnlyOnce("Generic args are ignored in type testing", ?range=range) + if not (List.isEmpty genArgs) then + com.WarnOnlyOnce("Generic args are ignored in type testing", ?range = range) + let expr, stmts' = jsInstanceof cons expr expr, stmts @ stmts' - | None -> - warnAndEvalToFalse ent.FullName, [] + | None -> warnAndEvalToFalse ent.FullName, [] module Helpers = let (|PythonModule|_|) (modulePath: string) = match modulePath with - | name when (name.Contains("/") || name.EndsWith(".fs") || name.EndsWith(".py")) -> None + | name when + (name.Contains("/") + || name.EndsWith(".fs") + || name.EndsWith(".py")) + -> + None | name -> Some(name) /// Returns true if type can be None in Python - let isOptional (fields: Fable.Ident[]) = + let isOptional (fields: Fable.Ident []) = if fields.Length < 1 then false else @@ -425,11 +513,16 @@ module Helpers = |> (fun name -> name.Replace("`", "_")) |> Helpers.clean - let getUniqueIdentifier (name: string): Identifier = + let getUniqueIdentifier (name: string) : Identifier = do index.MoveNext() |> ignore let idx = index.Current.ToString() + let deliminator = - if Char.IsLower name.[0] then "_" else "" + if Char.IsLower name.[0] then + "_" + else + "" + Identifier($"{name}{deliminator}{idx}") /// Replaces all '$' and `.`with '_' @@ -438,7 +531,8 @@ module Helpers = match name with | "Infinity" -> "float('inf')" | _ -> - (name, Naming.NoMemberPart) ||> Naming.sanitizeIdent (fun _ -> false) + (name, Naming.NoMemberPart) + ||> Naming.sanitizeIdent (fun _ -> false) /// Normalize Fable import to be relative to compiled file in outDir. /// TODO: decide if nugets referencing fable_library should be relative or absolute. Currently absolute. @@ -447,12 +541,15 @@ module Helpers = // printfn "ModulePath: %s" modulePath let fileDir = Path.GetDirectoryName modulePath let projDir = Path.GetDirectoryName(com.ProjectFile) + let modulePathname = match fileDir with - | "" | "." -> fileDir + | "" + | "." -> fileDir | _ -> IO.Path.GetFullPath(Path.Combine(Path.GetDirectoryName(com.CurrentFile), fileDir)) |> Path.normalizePath + let outDir = com.OutputDir |> Option.defaultValue projDir //printfn "modulePathname: %A" modulePathname @@ -461,12 +558,14 @@ module Helpers = // printfn $"CurrentFile: {com.CurrentFile}" // printfn $"ProjectFile: {com.ProjectFile}" - let commonPrefix = Path.getCommonBaseDir [ modulePathname; com.ProjectFile ] + let commonPrefix = + Path.getCommonBaseDir [ modulePathname; com.ProjectFile ] + let relativePath = // We know all modules will be placed somewhere in outDir or in a subdir below modulePathname - .Replace(outDir, String.Empty) // Remove outDir from module path - .Replace(projDir, String.Empty) // Remove projectDir from module path + .Replace(outDir, String.Empty) // Remove outDir from module path + .Replace(projDir, String.Empty) // Remove projectDir from module path let relativePath = if commonPrefix.Length > 0 then @@ -480,8 +579,12 @@ module Helpers = // Relative path from current file (up) to project dir let fileRelative = - let commonPrefix = Path.getCommonBaseDir [ com.CurrentFile; com.ProjectFile ] - Path.GetDirectoryName(com.CurrentFile.Replace(commonPrefix, String.Empty)).Split('/') + let commonPrefix = + Path.getCommonBaseDir [ com.CurrentFile; com.ProjectFile ] + + Path + .GetDirectoryName(com.CurrentFile.Replace(commonPrefix, String.Empty)) + .Split('/') |> Array.filter (fun x -> x.Length > 0) |> Array.map (fun _ -> "..") |> String.concat "/" @@ -512,7 +615,9 @@ module Helpers = /// - program.py /// let rewriteFablePathImport (com: IPythonCompiler) (modulePath: string) = - let commonPrefix = Path.getCommonBaseDir [ com.ProjectFile; com.CurrentFile ] + let commonPrefix = + Path.getCommonBaseDir [ com.ProjectFile; com.CurrentFile ] + let normalizedPath = normalizeModulePath com modulePath let projDir = Path.GetDirectoryName(com.ProjectFile) let fileDir = Path.GetDirectoryName(com.CurrentFile) @@ -536,7 +641,7 @@ module Helpers = // If the compiled file is not in a sub-dir underneath the project file (e.g project reference) then use // relative imports if and only if the normalizedPath exists within that referenced project. This is e.g the // case when a test project references the library it's testing and the library wants to import own files - | _, true -> true + | _, true -> true | OutputType.Exe, _ -> false | _ -> true @@ -548,17 +653,22 @@ module Helpers = let moduleName = let lower = let fileName = Path.GetFileNameWithoutExtension(modulePath) + match fileName with | "" when modulePath.StartsWith(".") -> modulePath.[1..] - | _ -> fileName |> Naming.applyCaseRule CaseRules.SnakeCase - (lower, Naming.NoMemberPart) ||> Naming.sanitizeIdent (fun _ -> false) + | _ -> + fileName + |> Naming.applyCaseRule CaseRules.SnakeCase + + (lower, Naming.NoMemberPart) + ||> Naming.sanitizeIdent (fun _ -> false) let path = match relative, normalizedPath with | _, "" -> "" | true, "." -> "." | true, path -> - path // translate path to Python relative syntax + path .Replace("../../../", "....") .Replace("../../", "...") .Replace("../", "..") @@ -568,17 +678,21 @@ module Helpers = + "." | false, "." -> "" | false, path -> - path.Replace("../", "").Replace("./", "").Replace("/", ".") + "." + path + .Replace("../", "") + .Replace("./", "") + .Replace("/", ".") + + "." $"{path}{moduleName}" let rewriteFableImport (com: IPythonCompiler) (modulePath: string) = match modulePath with - | PythonModule(name) -> name + | PythonModule (name) -> name | _ -> rewriteFablePathImport com modulePath - let unzipArgs (args: (Expression * Statement list) list): Expression list * Python.Statement list = + let unzipArgs (args: (Expression * Statement list) list) : Expression list * Python.Statement list = let stmts = args |> List.map snd |> List.collect id let args = args |> List.map fst args, stmts @@ -595,8 +709,10 @@ module Helpers = match stmt with // Remove `self = self` - | Statement.Assign { Targets = [ Name {Id=Identifier(x)}]; Value = Name {Id=Identifier(y)}} when x = y -> None - | Statement.AnnAssign { Target = Name {Id=Identifier(x)}; Value = Some (Name {Id=Identifier(y)} )} when x = y -> None + | Statement.Assign { Targets = [ Name { Id = Identifier (x) } ] + Value = Name { Id = Identifier (y) } } when x = y -> None + | Statement.AnnAssign { Target = Name { Id = Identifier (x) } + Value = Some (Name { Id = Identifier (y) }) } when x = y -> None | Expr expr -> if hasNoSideEffects expr.Value then None @@ -617,8 +733,11 @@ module Annotation = if (Set.isEmpty genParams) then [] else - com.GetImportExpr(ctx, "typing", "Generic") |> ignore - com.GetImportExpr(ctx, "typing", "TypeVar") |> ignore + com.GetImportExpr(ctx, "typing", "Generic") + |> ignore + + com.GetImportExpr(ctx, "typing", "TypeVar") + |> ignore let genParams = genParams @@ -628,38 +747,43 @@ module Annotation = com.AddTypeVar(ctx, genParam)) let generic = Expression.name "Generic" - [ Expression.subscript(generic, Expression.tuple genParams) ] + [ Expression.subscript (generic, Expression.tuple genParams) ] - let private libReflectionCall (com: IPythonCompiler) ctx r memberName args = - libCall com ctx r "reflection" (memberName + "_type") args + let private libReflectionCall (com: IPythonCompiler) ctx r memberName args = libCall com ctx r "reflection" (memberName + "_type") args let fableModuleAnnotation (com: IPythonCompiler) ctx moduleName memberName args = - let expr = com.TransformImport(ctx, memberName, getLibPath com moduleName) + let expr = + com.TransformImport(ctx, memberName, getLibPath com moduleName) + match args with | [] -> expr - | [arg] -> Expression.subscript(expr, arg) - | args -> Expression.subscript(expr, Expression.tuple(args)) + | [ arg ] -> Expression.subscript (expr, arg) + | args -> Expression.subscript (expr, Expression.tuple (args)) let stdlibModuleAnnotation (com: IPythonCompiler) ctx moduleName memberName args = let expr = com.TransformImport(ctx, memberName, moduleName) + match memberName, args with | _, [] -> expr - | _, [arg] -> Expression.subscript(expr, arg) + | _, [ arg ] -> Expression.subscript (expr, arg) | "Callable", args -> let returnType = List.last args + let args = args |> List.removeAt (args.Length - 1) |> List.choose (function - | Expression.Name({ Id=Identifier "None" }) when args.Length = 2 -> None + | Expression.Name ({ Id = Identifier "None" }) when args.Length = 2 -> None | x -> Some x) |> Expression.list - Expression.subscript(expr, Expression.tuple([args; returnType])) - | _, args -> - Expression.subscript(expr, Expression.tuple(args)) + + Expression.subscript (expr, Expression.tuple ([ args; returnType ])) + | _, args -> Expression.subscript (expr, Expression.tuple (args)) let fableModuleTypeHint com ctx moduleName memberName genArgs repeatedGenerics = - let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics + let resolved, stmts = + resolveGenerics com ctx genArgs repeatedGenerics + fableModuleAnnotation com ctx moduleName memberName resolved, stmts let stdlibModuleTypeHint com ctx moduleName memberName genArgs = @@ -669,122 +793,163 @@ module Annotation = let makeGenTypeParamInst com ctx (genArgs: Fable.Type list) (repeatedGenerics: Set option) = match genArgs with | [] -> [] - | _ -> + | _ -> genArgs |> List.map (typeAnnotation com ctx repeatedGenerics) |> List.map fst - let makeGenericTypeAnnotation (com: IPythonCompiler) ctx (id: string) (genArgs: Fable.Type list) (repeatedGenerics: Set option) = - stdlibModuleAnnotation com ctx "__future__" "annotations" [] |> ignore + let makeGenericTypeAnnotation + (com: IPythonCompiler) + ctx + (id: string) + (genArgs: Fable.Type list) + (repeatedGenerics: Set option) + = + stdlibModuleAnnotation com ctx "__future__" "annotations" [] + |> ignore + + let typeParamInst = + makeGenTypeParamInst com ctx genArgs repeatedGenerics - let typeParamInst = makeGenTypeParamInst com ctx genArgs repeatedGenerics let name = Expression.name id + if typeParamInst.IsEmpty then name else - Expression.subscript(name, Expression.tuple typeParamInst) + Expression.subscript (name, Expression.tuple typeParamInst) let makeGenericTypeAnnotation' (com: IPythonCompiler) ctx (id: string) (genArgs: string list) (repeatedGenerics: Set option) = - stdlibModuleAnnotation com ctx "__future__" "annotations" [] |> ignore + stdlibModuleAnnotation com ctx "__future__" "annotations" [] + |> ignore let name = Expression.name id + if genArgs.IsEmpty then name else let genArgs = match repeatedGenerics with | Some generics -> - let genArgs = genArgs |> Set.ofList |> Set.intersect generics |> Set.toList - if genArgs.IsEmpty then [ stdlibModuleAnnotation com ctx "typing" "Any" [] ] - else genArgs |> List.map (fun name -> com.AddTypeVar(ctx, name)) + let genArgs = + genArgs + |> Set.ofList + |> Set.intersect generics + |> Set.toList + + if genArgs.IsEmpty then + [ stdlibModuleAnnotation com ctx "typing" "Any" [] ] + else + genArgs + |> List.map (fun name -> com.AddTypeVar(ctx, name)) | _ -> - genArgs |> List.map (fun name -> com.AddTypeVar(ctx, name)) - Expression.subscript(name, Expression.tuple genArgs) + genArgs + |> List.map (fun name -> com.AddTypeVar(ctx, name)) + + Expression.subscript (name, Expression.tuple genArgs) - let resolveGenerics com ctx generics repeatedGenerics: Expression list * Statement list = - generics |> List.map (typeAnnotation com ctx repeatedGenerics) |> Helpers.unzipArgs + let resolveGenerics com ctx generics repeatedGenerics : Expression list * Statement list = + generics + |> List.map (typeAnnotation com ctx repeatedGenerics) + |> Helpers.unzipArgs let typeAnnotation (com: IPythonCompiler) ctx (repeatedGenerics: Set option) t : Expression * Statement list = let getNumberKindName kind = match kind with - | Int8 | UInt8 | Int16 | UInt16 | Int32 | UInt32 -> "int" - | Float32 | Float64 -> "float" + | Int8 + | UInt8 + | Int16 + | UInt16 + | Int32 + | UInt32 -> "int" + | Float32 + | Float64 -> "float" - let numberInfo kind = - Expression.name (getNumberKindName kind) + let numberInfo kind = Expression.name (getNumberKindName kind) // printfn "typeAnnotation: %A" t match t with | Fable.Measure _ | Fable.Any -> stdlibModuleTypeHint com ctx "typing" "Any" [] - | Fable.GenericParam(name,_) -> + | Fable.GenericParam (name, _) -> match repeatedGenerics with | Some names when names.Contains name -> - com.GetImportExpr(ctx, "typing", "TypeVar") |> ignore + com.GetImportExpr(ctx, "typing", "TypeVar") + |> ignore + let name = Helpers.clean name com.AddTypeVar(ctx, name), [] - | Some _ -> - stdlibModuleTypeHint com ctx "typing" "Any" [] + | Some _ -> stdlibModuleTypeHint com ctx "typing" "Any" [] | None -> - com.GetImportExpr(ctx, "typing", "TypeVar") |> ignore + com.GetImportExpr(ctx, "typing", "TypeVar") + |> ignore + let name = Helpers.clean name com.AddTypeVar(ctx, name), [] - | Fable.Unit -> Expression.none, [] + | Fable.Unit -> Expression.none, [] | Fable.Boolean -> Expression.name "bool", [] - | Fable.Char -> Expression.name "str", [] - | Fable.String -> Expression.name "str", [] + | Fable.Char -> Expression.name "str", [] + | Fable.String -> Expression.name "str", [] | Fable.Enum entRef -> let ent = com.GetEntity(entRef) let mutable numberKind = Int32 + let cases = - ent.FSharpFields |> Seq.choose (fun fi -> + ent.FSharpFields + |> Seq.choose (fun fi -> // F# seems to include a field with this name in the underlying type match fi.Name with | "value__" -> match fi.FieldType with - | Fable.Number(kind,_) -> numberKind <- kind + | Fable.Number (kind, _) -> numberKind <- kind | _ -> () + None | name -> - let value = match fi.LiteralValue with Some v -> System.Convert.ToDouble v | None -> 0. - Expression.list([ Expression.constant(name); Expression.constant(value) ]) |> Some) + let value = + match fi.LiteralValue with + | Some v -> System.Convert.ToDouble v + | None -> 0. + + Expression.list ([ Expression.constant (name); Expression.constant (value) ]) + |> Some) |> Seq.toList |> Expression.list - [ Expression.constant(entRef.FullName); numberInfo numberKind; cases ] - |> libReflectionCall com ctx None "enum", [] - | Fable.Number(kind,_) -> numberInfo kind, [] - | Fable.LambdaType(argType, returnType) -> + + [ Expression.constant (entRef.FullName); numberInfo numberKind; cases ] + |> libReflectionCall com ctx None "enum", + [] + | Fable.Number (kind, _) -> numberInfo kind, [] + | Fable.LambdaType (argType, returnType) -> let argTypes, returnType = Util.uncurryLambdaType t stdlibModuleTypeHint com ctx "typing" "Callable" (argTypes @ [ returnType ]) - | Fable.Option(genArg,_) -> - stdlibModuleTypeHint com ctx "typing" "Optional" [ genArg ] - | Fable.Tuple(genArgs,_) -> stdlibModuleTypeHint com ctx "typing" "Tuple" genArgs + | Fable.Option (genArg, _) -> stdlibModuleTypeHint com ctx "typing" "Optional" [ genArg ] + | Fable.Tuple (genArgs, _) -> stdlibModuleTypeHint com ctx "typing" "Tuple" genArgs | Fable.Array genArg -> match genArg with - | Fable.Type.Number(UInt8, _) -> stdlibModuleTypeHint com ctx "typing" "ByteString" [] - | Fable.Type.Number(Int8, _) - | Fable.Type.Number(Int16, _) - | Fable.Type.Number(UInt16, _) - | Fable.Type.Number(Int32, _) - | Fable.Type.Number(UInt32, _) - | Fable.Type.Number(Float32, _) - | Fable.Type.Number(Float64, _) -> stdlibModuleTypeHint com ctx "typing" "MutableSequence" [ genArg ] + | Fable.Type.Number (UInt8, _) -> stdlibModuleTypeHint com ctx "typing" "ByteString" [] + | Fable.Type.Number (Int8, _) + | Fable.Type.Number (Int16, _) + | Fable.Type.Number (UInt16, _) + | Fable.Type.Number (Int32, _) + | Fable.Type.Number (UInt32, _) + | Fable.Type.Number (Float32, _) + | Fable.Type.Number (Float64, _) -> stdlibModuleTypeHint com ctx "typing" "MutableSequence" [ genArg ] | _ -> stdlibModuleTypeHint com ctx "typing" "List" [ genArg ] | Fable.List genArg -> fableModuleTypeHint com ctx "list" "FSharpList" [ genArg ] repeatedGenerics | Replacements.Builtin kind -> makeBuiltinTypeAnnotation com ctx kind repeatedGenerics | Fable.AnonymousRecordType (_, genArgs) -> - let value = Expression.name("dict") + let value = Expression.name ("dict") let any, stmts = stdlibModuleTypeHint com ctx "typing" "Any" [] - Expression.subscript(value, Expression.tuple([ Expression.name "str"; any ])), stmts - | Fable.DeclaredType(entRef, genArgs) -> - makeEntityTypeAnnotation com ctx entRef genArgs repeatedGenerics - | _ -> - stdlibModuleTypeHint com ctx "typing" "Any" [] + Expression.subscript (value, Expression.tuple ([ Expression.name "str"; any ])), stmts + | Fable.DeclaredType (entRef, genArgs) -> makeEntityTypeAnnotation com ctx entRef genArgs repeatedGenerics + | _ -> stdlibModuleTypeHint com ctx "typing" "Any" [] let makeImportTypeId (com: IPythonCompiler) ctx moduleName typeName = - let expr = com.GetImportExpr(ctx, getLibPath com moduleName, typeName) + let expr = + com.GetImportExpr(ctx, getLibPath com moduleName, typeName) + match expr with - | Expression.Name({Id=Identifier id}) -> id + | Expression.Name ({ Id = Identifier id }) -> id | _ -> typeName let makeImportTypeAnnotation com ctx genArgs moduleName typeName = @@ -795,14 +960,15 @@ module Annotation = // printfn "DeclaredType: %A" entRef.FullName match entRef.FullName, genArgs with | Types.result, _ -> - let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics + let resolved, stmts = + resolveGenerics com ctx genArgs repeatedGenerics + fableModuleAnnotation com ctx "choice" "FSharpResult_2" resolved, stmts | Replacements.BuiltinEntity kind -> match kind with - | Replacements.BclDecimal -> - stdlibModuleTypeHint com ctx "decimal" "Decimal" [ ] + | Replacements.BclDecimal -> stdlibModuleTypeHint com ctx "decimal" "Decimal" [] | _ -> stdlibModuleTypeHint com ctx "typing" "Any" [] -(* + (* | Replacements.BclGuid | Replacements.BclTimeSpan | Replacements.BclDateTime @@ -821,55 +987,79 @@ module Annotation = makeUnionTypeAnnotation com ctx genArgs *) | Types.fsharpAsyncGeneric, _ -> - let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics - fableModuleAnnotation com ctx "async_builder" "Async" resolved, stmts - | Types.taskGeneric, _ -> - stdlibModuleTypeHint com ctx "typing" "Awaitable" genArgs + let resolved, stmts = + resolveGenerics com ctx genArgs repeatedGenerics + + fableModuleAnnotation com ctx "async_builder" "Async" resolved, stmts + | Types.taskGeneric, _ -> stdlibModuleTypeHint com ctx "typing" "Awaitable" genArgs | Types.icomparable, _ -> - let resolved, stmts = stdlibModuleTypeHint com ctx "typing" "Any" [] + let resolved, stmts = + stdlibModuleTypeHint com ctx "typing" "Any" [] + fableModuleAnnotation com ctx "util" "IComparable" [ resolved ], stmts | Types.comparer, _ -> - let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics + let resolved, stmts = + resolveGenerics com ctx genArgs repeatedGenerics + fableModuleAnnotation com ctx "util" "IComparer" resolved, stmts | Types.equalityComparer, _ -> - let resolved, stmts = stdlibModuleTypeHint com ctx "typing" "Any" [] - fableModuleAnnotation com ctx "util" "IEqualityComparer" [ resolved ], stmts + let resolved, stmts = + stdlibModuleTypeHint com ctx "typing" "Any" [] + + fableModuleAnnotation com ctx "util" "IEqualityComparer" [ resolved ], stmts | Types.ienumerator, _ -> - let resolved, stmts = stdlibModuleTypeHint com ctx "typing" "Any" [] - fableModuleAnnotation com ctx "util" "IEnumerator" [resolved], stmts + let resolved, stmts = + stdlibModuleTypeHint com ctx "typing" "Any" [] + + fableModuleAnnotation com ctx "util" "IEnumerator" [ resolved ], stmts | Types.ienumeratorGeneric, _ -> - let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics - fableModuleAnnotation com ctx "util" "IEnumerator" resolved, stmts + let resolved, stmts = + resolveGenerics com ctx genArgs repeatedGenerics + + fableModuleAnnotation com ctx "util" "IEnumerator" resolved, stmts | Types.ienumerable, _ -> - let resolved, stmts = stdlibModuleTypeHint com ctx "typing" "Any" [] - fableModuleAnnotation com ctx "util" "IEnumerable" [resolved], stmts + let resolved, stmts = + stdlibModuleTypeHint com ctx "typing" "Any" [] + + fableModuleAnnotation com ctx "util" "IEnumerable" [ resolved ], stmts | Types.ienumerableGeneric, _ -> - let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics - fableModuleAnnotation com ctx "util" "IEnumerable" resolved, stmts + let resolved, stmts = + resolveGenerics com ctx genArgs repeatedGenerics + + fableModuleAnnotation com ctx "util" "IEnumerable" resolved, stmts | Types.icollection, _ | Types.icollectionGeneric, _ -> - let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics - fableModuleAnnotation com ctx "util" "ICollection" resolved, stmts - | Types.idisposable, _ -> - libValue com ctx "util" "IDisposable", [] + let resolved, stmts = + resolveGenerics com ctx genArgs repeatedGenerics + + fableModuleAnnotation com ctx "util" "ICollection" resolved, stmts + | Types.idisposable, _ -> libValue com ctx "util" "IDisposable", [] | Types.iobserverGeneric, _ -> - let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics - fableModuleAnnotation com ctx "observable" "IObserver" resolved, stmts + let resolved, stmts = + resolveGenerics com ctx genArgs repeatedGenerics + + fableModuleAnnotation com ctx "observable" "IObserver" resolved, stmts | Types.iobservableGeneric, _ -> - let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics - fableModuleAnnotation com ctx "observable" "IObservable" resolved, stmts - | Types.cancellationToken, _ -> - libValue com ctx "async_builder" "CancellationToken", [] + let resolved, stmts = + resolveGenerics com ctx genArgs repeatedGenerics + + fableModuleAnnotation com ctx "observable" "IObservable" resolved, stmts + | Types.cancellationToken, _ -> libValue com ctx "async_builder" "CancellationToken", [] | _ -> let ent = com.GetEntity(entRef) + if ent.IsInterface then let name = Helpers.removeNamespace ent.FullName + match entRef.SourcePath with | Some path when path <> com.CurrentFile -> // this is just to import the interface - let importPath = Path.getRelativeFileOrDirPath false com.CurrentFile false path + let importPath = + Path.getRelativeFileOrDirPath false com.CurrentFile false path + com.GetImportExpr(ctx, importPath, name) |> ignore | _ -> () + makeGenericTypeAnnotation com ctx name genArgs repeatedGenerics, [] else match Lib.tryPyConstructor com ctx ent with @@ -882,16 +1072,15 @@ module Annotation = | "boolean" -> BooleanTypeAnnotation | "string" -> StringTypeAnnotation | _ -> AnyTypeAnnotation*) - | Expression.Name {Id = Identifier id } -> - makeGenericTypeAnnotation com ctx id genArgs repeatedGenerics, [] + | Expression.Name { Id = Identifier id } -> makeGenericTypeAnnotation com ctx id genArgs repeatedGenerics, [] // TODO: Resolve references to types in nested modules | _ -> stdlibModuleTypeHint com ctx "typing" "Any" [] - | None -> - stdlibModuleTypeHint com ctx "typing" "Any" [] + | None -> stdlibModuleTypeHint com ctx "typing" "Any" [] + let makeBuiltinTypeAnnotation com ctx kind repeatedGenerics = match kind with - | Replacements.BclGuid -> Expression.name("str"), [] - | Replacements.FSharpReference genArg -> makeImportTypeAnnotation com ctx [genArg] "types" "FSharpRef", [] + | Replacements.BclGuid -> Expression.name ("str"), [] + | Replacements.FSharpReference genArg -> makeImportTypeAnnotation com ctx [ genArg ] "types" "FSharpRef", [] (* | Replacements.BclTimeSpan -> NumberTypeAnnotation | Replacements.BclDateTime -> makeSimpleTypeAnnotation com ctx "Date" @@ -913,21 +1102,34 @@ module Annotation = |> makeImportTypeAnnotation com ctx genArgs "Fable.Core" *) | Replacements.FSharpResult (ok, err) -> - let resolved, stmts = resolveGenerics com ctx [ok; err] repeatedGenerics - fableModuleAnnotation com ctx "choice" "FSharpResult_2" resolved, stmts - | _ -> - stdlibModuleTypeHint com ctx "typing" "Any" [] + let resolved, stmts = + resolveGenerics com ctx [ ok; err ] repeatedGenerics + + fableModuleAnnotation com ctx "choice" "FSharpResult_2" resolved, stmts + | _ -> stdlibModuleTypeHint com ctx "typing" "Any" [] let transformFunctionWithAnnotations (com: IPythonCompiler) ctx name (args: Fable.Ident list) (body: Fable.Expr) = let argTypes = args |> List.map (fun id -> id.Type) - let genTypeParams = Util.getGenericTypeParams (argTypes @ [body.Type]) - let newTypeParams = Set.difference genTypeParams ctx.ScopedTypeParams - let ctx = { ctx with ScopedTypeParams = Set.union ctx.ScopedTypeParams newTypeParams } + + let genTypeParams = + Util.getGenericTypeParams (argTypes @ [ body.Type ]) + + let newTypeParams = + Set.difference genTypeParams ctx.ScopedTypeParams + + let ctx = + { ctx with ScopedTypeParams = Set.union ctx.ScopedTypeParams newTypeParams } // In Python a generic type arg must appear both in the argument and the return type (cannot appear only once) - let repeatedGenerics = Util.getRepeatedGenericTypeParams (argTypes @ [body.Type]) - let args', body' = com.TransformFunction(ctx, name, args, body, repeatedGenerics) - let returnType, stmts = typeAnnotation com ctx (Some repeatedGenerics) body.Type + let repeatedGenerics = + Util.getRepeatedGenericTypeParams (argTypes @ [ body.Type ]) + + let args', body' = + com.TransformFunction(ctx, name, args, body, repeatedGenerics) + + let returnType, stmts = + typeAnnotation com ctx (Some repeatedGenerics) body.Type + args', stmts @ body', returnType module Util = @@ -939,137 +1141,172 @@ module Util = let name = match name with //| "this" -> "self" - | "math" | "Math" -> + | "math" + | "Math" -> com.GetImportExpr(ctx, "math") |> ignore "math" | _ -> Helpers.clean name Identifier name - let (|TransformExpr|) (com: IPythonCompiler) ctx e : Expression * Statement list = - com.TransformAsExpr(ctx, e) + let (|TransformExpr|) (com: IPythonCompiler) ctx e : Expression * Statement list = com.TransformAsExpr(ctx, e) - let (|Function|_|) = function - | Fable.Lambda(arg, body, _) -> Some([arg], body) - | Fable.Delegate(args, body, _) -> Some(args, body) + let (|Function|_|) = + function + | Fable.Lambda (arg, body, _) -> Some([ arg ], body) + | Fable.Delegate (args, body, _) -> Some(args, body) | _ -> None let discardUnitArg (args: Fable.Ident list) = match args with | [] -> [] - | [unitArg] when unitArg.Type = Fable.Unit -> [] - | [thisArg; unitArg] when thisArg.IsThisArgument && unitArg.Type = Fable.Unit -> [thisArg] + | [ unitArg ] when unitArg.Type = Fable.Unit -> [] + | [ thisArg; unitArg ] when + thisArg.IsThisArgument + && unitArg.Type = Fable.Unit + -> + [ thisArg ] | args -> args let getUniqueNameInRootScope (ctx: Context) name = - let name = (name, Naming.NoMemberPart) ||> Naming.sanitizeIdent (fun name -> - name <> "str" // Do not rewrite `str` - && (ctx.UsedNames.RootScope.Contains(name) - || ctx.UsedNames.DeclarationScopes.Contains(name))) + let name = + (name, Naming.NoMemberPart) + ||> Naming.sanitizeIdent (fun name -> + name <> "str" // Do not rewrite `str` + && (ctx.UsedNames.RootScope.Contains(name) + || ctx.UsedNames.DeclarationScopes.Contains(name))) + ctx.UsedNames.RootScope.Add(name) |> ignore Helpers.clean name let getUniqueNameInDeclarationScope (ctx: Context) name = - let name = (name, Naming.NoMemberPart) ||> Naming.sanitizeIdent (fun name -> - ctx.UsedNames.RootScope.Contains(name) || ctx.UsedNames.CurrentDeclarationScope.Contains(name)) - ctx.UsedNames.CurrentDeclarationScope.Add(name) |> ignore + let name = + (name, Naming.NoMemberPart) + ||> Naming.sanitizeIdent (fun name -> + ctx.UsedNames.RootScope.Contains(name) + || ctx.UsedNames.CurrentDeclarationScope.Contains(name)) + + ctx.UsedNames.CurrentDeclarationScope.Add(name) + |> ignore + name - type NamedTailCallOpportunity(com: IPythonCompiler, ctx, name, args: Fable.Ident list) = + type NamedTailCallOpportunity (com: IPythonCompiler, ctx, name, args: Fable.Ident list) = // Capture the current argument values to prevent delayed references from getting corrupted, // for that we use block-scoped ES2015 variable declarations. See #681, #1859 // TODO: Local unique ident names let argIds = discardUnitArg args |> List.map (fun arg -> - let name = getUniqueNameInDeclarationScope ctx (arg.Name + "_mut") + let name = + getUniqueNameInDeclarationScope ctx (arg.Name + "_mut") + let ta, _ = typeAnnotation com ctx None arg.Type - Arg.arg(name, ta)) + Arg.arg (name, ta)) + interface ITailCallOpportunity with member _.Label = name member _.Args = argIds + member _.IsRecursiveRef(e) = - match e with Fable.IdentExpr id -> name = id.Name | _ -> false + match e with + | Fable.IdentExpr id -> name = id.Name + | _ -> false let getDecisionTarget (ctx: Context) targetIndex = match List.tryItem targetIndex ctx.DecisionTargets with | None -> failwithf "Cannot find DecisionTree target %i" targetIndex - | Some(idents, target) -> idents, target + | Some (idents, target) -> idents, target let rec isPyStatement ctx preferStatement (expr: Fable.Expr) = match expr with | Fable.Unresolved _ - | Fable.Value _ | Fable.Import _ | Fable.IdentExpr _ - | Fable.Lambda _ | Fable.Delegate _ | Fable.ObjectExpr _ - | Fable.Call _ | Fable.CurriedApply _ | Fable.Operation _ - | Fable.Get _ | Fable.Test _ | Fable.TypeCast _ -> false + | Fable.Value _ + | Fable.Import _ + | Fable.IdentExpr _ + | Fable.Lambda _ + | Fable.Delegate _ + | Fable.ObjectExpr _ + | Fable.Call _ + | Fable.CurriedApply _ + | Fable.Operation _ + | Fable.Get _ + | Fable.Test _ + | Fable.TypeCast _ -> false | Fable.TryCatch _ - | Fable.Sequential _ | Fable.Let _ | Fable.LetRec _ | Fable.Set _ - | Fable.ForLoop _ | Fable.WhileLoop _ -> true - | Fable.Extended(kind, _) -> + | Fable.Sequential _ + | Fable.Let _ + | Fable.LetRec _ + | Fable.Set _ + | Fable.ForLoop _ + | Fable.WhileLoop _ -> true + | Fable.Extended (kind, _) -> match kind with - | Fable.Throw _ | Fable.Return _ | Fable.Break _ | Fable.Debugger -> true + | Fable.Throw _ + | Fable.Return _ + | Fable.Break _ + | Fable.Debugger -> true | Fable.Curry _ -> false // TODO: If IsJsSatement is false, still try to infer it? See #2414 // /^\s*(break|continue|debugger|while|for|switch|if|try|let|const|var)\b/ - | Fable.Emit(i,_,_) -> i.IsStatement + | Fable.Emit (i, _, _) -> i.IsStatement - | Fable.DecisionTreeSuccess(targetIndex,_, _) -> + | Fable.DecisionTreeSuccess (targetIndex, _, _) -> getDecisionTarget ctx targetIndex - |> snd |> isPyStatement ctx preferStatement + |> snd + |> isPyStatement ctx preferStatement // Make it also statement if we have more than, say, 3 targets? // That would increase the chances to convert it into a switch - | Fable.DecisionTree(_,targets) -> + | Fable.DecisionTree (_, targets) -> preferStatement || List.exists (snd >> (isPyStatement ctx false)) targets - | Fable.IfThenElse(_,thenExpr,elseExpr,_) -> - preferStatement || isPyStatement ctx false thenExpr || isPyStatement ctx false elseExpr + | Fable.IfThenElse (_, thenExpr, elseExpr, _) -> + preferStatement + || isPyStatement ctx false thenExpr + || isPyStatement ctx false elseExpr let addErrorAndReturnNull (com: Compiler) (range: SourceLocation option) (error: string) = addError com [] range error Expression.none - let ident (com: IPythonCompiler) (ctx: Context) (id: Fable.Ident) = - com.GetIdentifier(ctx, id.Name) + let ident (com: IPythonCompiler) (ctx: Context) (id: Fable.Ident) = com.GetIdentifier(ctx, id.Name) - let identAsExpr (com: IPythonCompiler) (ctx: Context) (id: Fable.Ident) = - com.GetIdentifierAsExpr(ctx, id.Name) + let identAsExpr (com: IPythonCompiler) (ctx: Context) (id: Fable.Ident) = com.GetIdentifierAsExpr(ctx, id.Name) - let thisExpr = - Expression.name("self") + let thisExpr = Expression.name ("self") - let ofInt (i: int) = - Expression.constant(float i) + let ofInt (i: int) = Expression.constant (float i) - let ofString (s: string) = - Expression.constant(s) + let ofString (s: string) = Expression.constant (s) - let memberFromName (com: IPythonCompiler) (ctx: Context) (memberName: string): Expression = + let memberFromName (com: IPythonCompiler) (ctx: Context) (memberName: string) : Expression = // printfn "memberFromName: %A" memberName match memberName with - | "ToString" -> Expression.identifier("__str__") - | "Equals" -> Expression.identifier("__eq__") - | "set" -> Expression.identifier("__setitem__") - | "get" -> Expression.identifier("__getitem__") + | "ToString" -> Expression.identifier ("__str__") + | "Equals" -> Expression.identifier ("__eq__") + | "set" -> Expression.identifier ("__setitem__") + | "get" -> Expression.identifier ("__getitem__") | n when n.StartsWith("Symbol.iterator") -> let name = Identifier "__iter__" - Expression.name(name) + Expression.name (name) | n -> //when Naming.hasIdentForbiddenChars n -> let n = Naming.toSnakeCase n - (n, Naming.NoMemberPart) ||> Naming.sanitizeIdent (fun _ -> false) + + (n, Naming.NoMemberPart) + ||> Naming.sanitizeIdent (fun _ -> false) |> Expression.name -// | n -> + // | n -> // com.GetIdentifierAsExpr(ctx, n) let get (com: IPythonCompiler) ctx r left memberName subscript = // printfn "get: %A" (memberName, subscript) match subscript with | true -> - let expr = Expression.constant(memberName) + let expr = Expression.constant (memberName) Expression.subscript (value = left, slice = expr, ctx = Load) | _ -> let expr = com.GetIdentifier(ctx, memberName) @@ -1077,175 +1314,192 @@ module Util = let getExpr com ctx r (object: Expression) (expr: Expression) = match expr with - | Expression.Constant(value=name) when (name :? string) -> + | Expression.Constant (value = name) when (name :? string) -> let name = name :?> string |> Identifier Expression.attribute (value = object, attr = name, ctx = Load), [] - | e -> - Expression.subscript(value = object, slice = e, ctx = Load), [] + | e -> Expression.subscript (value = object, slice = e, ctx = Load), [] let rec getParts com ctx (parts: string list) (expr: Expression) = match parts with | [] -> expr - | m::ms -> get com ctx None expr m false |> getParts com ctx ms + | m :: ms -> + get com ctx None expr m false + |> getParts com ctx ms let makeArray (com: IPythonCompiler) ctx exprs typ = - let expr, stmts = exprs |> List.map (fun e -> com.TransformAsExpr(ctx, e)) |> Helpers.unzipArgs + let expr, stmts = + exprs + |> List.map (fun e -> com.TransformAsExpr(ctx, e)) + |> Helpers.unzipArgs let letter = match typ with - | Fable.Type.Number(UInt8, _) -> Some "B" - | Fable.Type.Number(Int8, _) -> Some "b" - | Fable.Type.Number(Int16, _) -> Some "h" - | Fable.Type.Number(UInt16, _) -> Some "H" - | Fable.Type.Number(Int32, _) -> Some "i" - | Fable.Type.Number(UInt32, _) -> Some "I" - | Fable.Type.Number(Float32, _) -> Some "f" - | Fable.Type.Number(Float64, _) -> Some "d" + | Fable.Type.Number (UInt8, _) -> Some "B" + | Fable.Type.Number (Int8, _) -> Some "b" + | Fable.Type.Number (Int16, _) -> Some "h" + | Fable.Type.Number (UInt16, _) -> Some "H" + | Fable.Type.Number (Int32, _) -> Some "i" + | Fable.Type.Number (UInt32, _) -> Some "I" + | Fable.Type.Number (Float32, _) -> Some "f" + | Fable.Type.Number (Float64, _) -> Some "d" | _ -> None match letter with | Some "B" -> let bytearray = Expression.name "bytearray" - Expression.call(bytearray, [Expression.list(expr)]), stmts + Expression.call (bytearray, [ Expression.list (expr) ]), stmts | Some l -> let array = com.GetImportExpr(ctx, "array", "array") - Expression.call(array, Expression.constant l :: [Expression.list(expr)]), stmts - | _ -> - expr |> Expression.list, stmts + + Expression.call ( + array, + Expression.constant l + :: [ Expression.list (expr) ] + ), + stmts + | _ -> expr |> Expression.list, stmts let makeList (com: IPythonCompiler) ctx exprs = - let expr, stmts = exprs |> List.map (fun e -> com.TransformAsExpr(ctx, e)) |> Helpers.unzipArgs + let expr, stmts = + exprs + |> List.map (fun e -> com.TransformAsExpr(ctx, e)) + |> Helpers.unzipArgs + expr |> Expression.list, stmts let makeTuple (com: IPythonCompiler) ctx exprs = - let expr, stmts = exprs |> List.map (fun e -> com.TransformAsExpr(ctx, e)) |> Helpers.unzipArgs + let expr, stmts = + exprs + |> List.map (fun e -> com.TransformAsExpr(ctx, e)) + |> Helpers.unzipArgs + expr |> Expression.tuple, stmts let makeStringArray strings = strings - |> List.map (fun x -> Expression.constant(x)) + |> List.map (fun x -> Expression.constant (x)) |> Expression.list let makePyObject (pairs: seq) = - pairs |> Seq.map (fun (name, value) -> - let prop = Expression.constant(name) - prop, value) + pairs + |> Seq.map (fun (name, value) -> + let prop = Expression.constant (name) + prop, value) |> Seq.toList |> List.unzip |> Expression.dict - let assign range left right = - Expression.namedExpr(left, right, ?loc=range) + let assign range left right = Expression.namedExpr (left, right, ?loc = range) /// Immediately Invoked Function Expression let iife (com: IPythonCompiler) ctx (expr: Fable.Expr) = // Use an arrow function in case we need to capture `this` let args = Arguments.arguments () + let afe, stmts = transformFunctionWithAnnotations com ctx None [] expr |||> makeArrowFunctionExpression com ctx None - Expression.call(afe, []), stmts + + Expression.call (afe, []), stmts let multiVarDeclaration (ctx: Context) (variables: (Identifier * Expression option) list) = let ids, values = variables - |> List.distinctBy (fun (Identifier(name=name), _value) -> name) + |> List.distinctBy (fun (Identifier (name = name), _value) -> name) |> List.map (function - | i, Some value -> Expression.name(i, Store), value, i - | i, _ -> Expression.name(i, Store), Expression.none, i) + | i, Some value -> Expression.name (i, Store), value, i + | i, _ -> Expression.name (i, Store), Expression.none, i) |> List.unzip3 |> fun (ids, values, ids') -> ctx.BoundVars.Bind(ids') - (Expression.tuple(ids), Expression.tuple(values)) + (Expression.tuple (ids), Expression.tuple (values)) - [ Statement.assign([ids], values) ] + [ Statement.assign ([ ids ], values) ] let varDeclaration (ctx: Context) (var: Expression) (typ: Expression option) value = // printfn "varDeclaration: %A" (var, value, typ) match var with - | Name({Id=id}) -> do ctx.BoundVars.Bind([id]) + | Name ({ Id = id }) -> do ctx.BoundVars.Bind([ id ]) | _ -> () - [ - match typ with - | Some typ -> Statement.assign(var, annotation=typ, value=value) - | _ -> Statement.assign([var], value) - ] + [ match typ with + | Some typ -> Statement.assign (var, annotation = typ, value = value) + | _ -> Statement.assign ([ var ], value) ] let restElement (var: Identifier) = - let var = Expression.name(var) - Expression.starred(var) + let var = Expression.name (var) + Expression.starred (var) let callSuper (args: Expression list) = - let super = Expression.name("super().__init__") - Expression.call(super, args) + let super = Expression.name ("super().__init__") + Expression.call (super, args) - let callSuperAsStatement (args: Expression list) = - Statement.expr(callSuper args) + let callSuperAsStatement (args: Expression list) = Statement.expr (callSuper args) let makeClassConstructor (args: Arguments) (isOptional: bool) body = // printfn "makeClassConstructor: %A" (args.Args, body) let name = Identifier("__init__") - let self = Arg.arg("self") + let self = Arg.arg ("self") + let args_ = match args.Args with | [ _unit ] when isOptional -> - { args with Args = self::args.Args; Defaults=[ Expression.none ] } - | _ -> - { args with Args = self::args.Args } + { args with + Args = self :: args.Args + Defaults = [ Expression.none ] } + | _ -> { args with Args = self :: args.Args } match args.Args, body with | [], [] | [], [ Statement.Pass ] -> [] // Remove empty `__init__` with no arguments - | _ -> [ Statement.functionDef(name, args_, body = body, returns=Expression.none) ] + | _ -> [ Statement.functionDef (name, args_, body = body, returns = Expression.none) ] - let callFunction r funcExpr (args: Expression list) (kw: Keyword list) = - Expression.call(funcExpr, args, kw=kw, ?loc=r) + let callFunction r funcExpr (args: Expression list) (kw: Keyword list) = Expression.call (funcExpr, args, kw = kw, ?loc = r) let callFunctionWithThisContext com ctx r funcExpr (args: Expression list) = - let args = thisExpr::args - Expression.call(get com ctx None funcExpr "call" false, args, ?loc=r) + let args = thisExpr :: args + Expression.call (get com ctx None funcExpr "call" false, args, ?loc = r) let emitExpression range (txt: string) args = let value = match txt with | "$0.join('')" -> "''.join($0)" | "throw $0" -> "raise $0" - | Naming.StartsWith("void ") value - | Naming.StartsWith("new ") value -> value + | Naming.StartsWith ("void ") value + | Naming.StartsWith ("new ") value -> value | _ -> txt - Expression.emit (value, args, ?loc=range) - let undefined range: Expression = - Expression.none + Expression.emit (value, args, ?loc = range) + + let undefined range : Expression = Expression.none let getGenericTypeParams (types: Fable.Type list) = - let rec getGenParams = function - | Fable.GenericParam(name,_) -> [name] + let rec getGenParams = + function + | Fable.GenericParam (name, _) -> [ name ] | t -> t.Generics |> List.collect getGenParams - types - |> List.collect getGenParams - |> Set.ofList + + types |> List.collect getGenParams |> Set.ofList // Returns type parameters that is used more than once let getRepeatedGenericTypeParams (types: Fable.Type list) = - let rec getGenParams = function - | Fable.GenericParam(name,_) -> [name] + let rec getGenParams = + function + | Fable.GenericParam (name, _) -> [ name ] | t -> t.Generics |> List.collect getGenParams + types |> List.collect getGenParams |> List.countBy id - |> List.choose (fun (param, count) -> - if count > 1 then - Some param - else None) + |> List.choose (fun (param, count) -> if count > 1 then Some param else None) |> Set.ofList let uncurryLambdaType t = - let rec uncurryLambdaArgs acc = function - | Fable.LambdaType(paramType, returnType) -> - uncurryLambdaArgs (paramType::acc) returnType + let rec uncurryLambdaArgs acc = + function + | Fable.LambdaType (paramType, returnType) -> uncurryLambdaArgs (paramType :: acc) returnType | t -> List.rev acc, t + uncurryLambdaArgs [] t type MemberKind = @@ -1257,59 +1511,86 @@ module Util = // printfn "getMemberArgsAndBody: %A" hasSpread let funcName, genTypeParams, args, body = match kind, args with - | Attached(isStatic=false), thisArg::args -> - let genTypeParams = Set.difference (getGenericTypeParams [thisArg.Type]) ctx.ScopedTypeParams + | Attached(isStatic = false), thisArg :: args -> + let genTypeParams = + Set.difference (getGenericTypeParams [ thisArg.Type ]) ctx.ScopedTypeParams + let body = // TODO: If ident is not captured maybe we can just replace it with "this" if FableTransforms.isIdentUsed thisArg.Name body then let thisKeyword = Fable.IdentExpr { thisArg with Name = "self" } Fable.Let(thisArg, thisKeyword, body) - else body + else + body + None, genTypeParams, args, body - | Attached(isStatic=true), _ + | Attached(isStatic = true), _ | ClassConstructor, _ -> None, ctx.ScopedTypeParams, args, body | NonAttached funcName, _ -> Some funcName, Set.empty, args, body | _ -> None, Set.empty, args, body - let ctx = { ctx with ScopedTypeParams = Set.union ctx.ScopedTypeParams genTypeParams } - let args, body, returnType = transformFunctionWithAnnotations com ctx funcName args body + let ctx = + { ctx with ScopedTypeParams = Set.union ctx.ScopedTypeParams genTypeParams } + + let args, body, returnType = + transformFunctionWithAnnotations com ctx funcName args body + let args = let len = args.Args.Length - if not hasSpread || len = 0 then args - else { args with VarArg = Some { args.Args.[len-1] with Annotation = None } ; Args = args.Args.[..len-2] } + + if not hasSpread || len = 0 then + args + else + { args with + VarArg = Some { args.Args.[len - 1] with Annotation = None } + Args = args.Args.[.. len - 2] } args, body, returnType let getUnionCaseName (uci: Fable.UnionCase) = - match uci.CompiledName with Some cname -> cname | None -> uci.Name + match uci.CompiledName with + | Some cname -> cname + | None -> uci.Name let getUnionExprTag (com: IPythonCompiler) ctx r (fableExpr: Fable.Expr) = let expr, stmts = com.TransformAsExpr(ctx, fableExpr) - let expr, stmts' = getExpr com ctx r expr (Expression.constant("tag")) + + let expr, stmts' = + getExpr com ctx r expr (Expression.constant ("tag")) + expr, stmts @ stmts' let wrapIntExpression typ (e: Expression) = match e, typ with | Expression.Constant _, _ -> e // TODO: Unsigned ints seem to cause problems, should we check only Int32 here? - | _, Fable.Number((Int8 | Int16 | Int32),_) - | _, Fable.Enum _ -> - Expression.boolOp(BoolOperator.Or, [e; Expression.constant(0)]) + | _, + Fable.Number ((Int8 + | Int16 + | Int32), + _) + | _, Fable.Enum _ -> Expression.boolOp (BoolOperator.Or, [ e; Expression.constant (0) ]) | _ -> e - let wrapExprInBlockWithReturn (e, stmts) = - stmts @ [ Statement.return'(e) ] + let wrapExprInBlockWithReturn (e, stmts) = stmts @ [ Statement.return' (e) ] - let makeArrowFunctionExpression com ctx (name: string option) (args: Arguments) (body: Statement list) returnType : Expression * Statement list = + let makeArrowFunctionExpression + com + ctx + (name: string option) + (args: Arguments) + (body: Statement list) + returnType + : Expression * Statement list = let args = match args.Args with | [] -> let ta = com.GetImportExpr(ctx, "typing", "Any") - Arguments.arguments(args=[ Arg.arg("__unit", annotation=ta) ], defaults=[ Expression.none ]) + Arguments.arguments (args = [ Arg.arg ("__unit", annotation = ta) ], defaults = [ Expression.none ]) | _ -> args match body with -// | [ Statement.Return({Value=Some expr}) ] -> + // | [ Statement.Return({Value=Some expr}) ] -> // let fn = Expression.name(Helpers.getUniqueIdentifier "lambda") // // Remove annotations from lambda expressions // let args' = { args with Args = args.Args |> List.map(fun arg -> { arg with Annotation = None })} @@ -1320,174 +1601,230 @@ module Util = // let ta = pythonModuleAnnotation com ctx "typing" "Callable" (taArgs @ [ returnType ]) // let stmts = [Statement.assign(fn, lambda, ta)] // fn, stmts - | _ -> - let ident = name |> Option.map Identifier |> Option.defaultWith (fun _ -> Helpers.getUniqueIdentifier "arrow") - let func = Statement.functionDef(name = ident, args = args, body = body, returns=returnType) - Expression.name ident, [ func ] + | _ -> + let ident = + name + |> Option.map Identifier + |> Option.defaultWith (fun _ -> Helpers.getUniqueIdentifier "arrow") + + let func = + Statement.functionDef (name = ident, args = args, body = body, returns = returnType) + + Expression.name ident, [ func ] let makeFunction name (args: Arguments, body: Expression, decoratorList, returnType) : Statement = // printfn "makeFunction: %A" name let body = wrapExprInBlockWithReturn (body, []) - Statement.functionDef(name = name, args = args, body = body, decoratorList=decoratorList, returns=returnType) + Statement.functionDef (name = name, args = args, body = body, decoratorList = decoratorList, returns = returnType) - let makeFunctionExpression (com: IPythonCompiler) ctx name (args, body: Expression, decoratorList, returnType: Expression) : Expression * Statement list= + let makeFunctionExpression + (com: IPythonCompiler) + ctx + name + (args, body: Expression, decoratorList, returnType: Expression) + : Expression * Statement list = let ctx = { ctx with BoundVars = ctx.BoundVars.EnterScope() } let name = - name |> Option.map (fun name -> com.GetIdentifier(ctx, name)) + name + |> Option.map (fun name -> com.GetIdentifier(ctx, name)) |> Option.defaultValue (Helpers.getUniqueIdentifier "expr") - let func = makeFunction name (args, body, decoratorList, returnType) - Expression.name(name), [ func ] + + let func = + makeFunction name (args, body, decoratorList, returnType) + + Expression.name (name), [ func ] let optimizeTailCall (com: IPythonCompiler) (ctx: Context) range (tc: ITailCallOpportunity) args = - let rec checkCrossRefs tempVars allArgs = function + let rec checkCrossRefs tempVars allArgs = + function | [] -> tempVars - | (argId, _arg)::rest -> - let found = allArgs |> List.exists (FableTransforms.deepExists (function - | Fable.IdentExpr i -> argId = i.Name - | _ -> false)) + | (argId, _arg) :: rest -> + let found = + allArgs + |> List.exists ( + FableTransforms.deepExists (function + | Fable.IdentExpr i -> argId = i.Name + | _ -> false) + ) + let tempVars = if found then - let tempVarName = getUniqueNameInDeclarationScope ctx (argId + "_tmp") + let tempVarName = + getUniqueNameInDeclarationScope ctx (argId + "_tmp") + Map.add argId tempVarName tempVars - else tempVars + else + tempVars + checkCrossRefs tempVars allArgs rest + ctx.OptimizeTailCall() - let zippedArgs = List.zip (tc.Args |> List.map(fun { Arg=Identifier id } -> id)) args + + let zippedArgs = + List.zip + (tc.Args + |> List.map (fun { Arg = Identifier id } -> id)) + args + let tempVars = checkCrossRefs Map.empty args zippedArgs - let tempVarReplacements = tempVars |> Map.map (fun _ v -> makeIdentExpr v) + + let tempVarReplacements = + tempVars |> Map.map (fun _ v -> makeIdentExpr v) + [ - // First declare temp variables - for KeyValue(argId, tempVar) in tempVars do - yield! varDeclaration ctx (com.GetIdentifierAsExpr(ctx, tempVar)) None (com.GetIdentifierAsExpr(ctx, argId)) - // Then assign argument expressions to the original argument identifiers - // See https://github.com/fable-compiler/Fable/issues/1368#issuecomment-434142713 - for argId, arg in zippedArgs do - let arg = FableTransforms.replaceValues tempVarReplacements arg - let arg, stmts = com.TransformAsExpr(ctx, arg) - yield! stmts @ (assign None (com.GetIdentifierAsExpr(ctx, argId)) arg |> exprAsStatement ctx) - yield Statement.continue'(?loc=range) - ] + // First declare temp variables + for KeyValue (argId, tempVar) in tempVars do + yield! varDeclaration ctx (com.GetIdentifierAsExpr(ctx, tempVar)) None (com.GetIdentifierAsExpr(ctx, argId)) + // Then assign argument expressions to the original argument identifiers + // See https://github.com/fable-compiler/Fable/issues/1368#issuecomment-434142713 + for argId, arg in zippedArgs do + let arg = FableTransforms.replaceValues tempVarReplacements arg + let arg, stmts = com.TransformAsExpr(ctx, arg) + + yield! + stmts + @ (assign None (com.GetIdentifierAsExpr(ctx, argId)) arg + |> exprAsStatement ctx) + yield Statement.continue' (?loc = range) ] let transformImport (com: IPythonCompiler) ctx (r: SourceLocation option) (name: string) (moduleName: string) = let name, parts = - let parts = Array.toList(name.Split('.')) + let parts = Array.toList (name.Split('.')) parts.Head, parts.Tail + com.GetImportExpr(ctx, moduleName, name) |> getParts com ctx parts - let transformCast (com: IPythonCompiler) (ctx: Context) t e: Expression * Statement list = + let transformCast (com: IPythonCompiler) (ctx: Context) t e : Expression * Statement list = match t with // Optimization for (numeric) array or list literals casted to seq // Done at the very end of the compile pipeline to get more opportunities // of matching cast and literal expressions after resolving pipes, inlining... - | Fable.DeclaredType(ent,[_]) -> + | Fable.DeclaredType (ent, [ _ ]) -> match ent.FullName, e with - | Types.ienumerableGeneric, Replacements.ArrayOrListLiteral(exprs, typ) -> - makeArray com ctx exprs typ + | Types.ienumerableGeneric, Replacements.ArrayOrListLiteral (exprs, typ) -> makeArray com ctx exprs typ | _ -> com.TransformAsExpr(ctx, e) | _ -> com.TransformAsExpr(ctx, e) - let transformCurry (com: IPythonCompiler) (ctx: Context) expr arity: Expression * Statement list = + let transformCurry (com: IPythonCompiler) (ctx: Context) expr arity : Expression * Statement list = com.TransformAsExpr(ctx, Replacements.curryExprAtRuntime com arity expr) - let transformValue (com: IPythonCompiler) (ctx: Context) r value: Expression * Statement list = + let transformValue (com: IPythonCompiler) (ctx: Context) r value : Expression * Statement list = match value with - | Fable.BaseValue(None,_) -> Expression.identifier("super().__init__"), [] - | Fable.BaseValue(Some boundIdent,_) -> identAsExpr com ctx boundIdent, [] - | Fable.ThisValue _ -> Expression.identifier("self"), [] + | Fable.BaseValue (None, _) -> Expression.identifier ("super().__init__"), [] + | Fable.BaseValue (Some boundIdent, _) -> identAsExpr com ctx boundIdent, [] + | Fable.ThisValue _ -> Expression.identifier ("self"), [] | Fable.TypeInfo t -> transformTypeInfo com ctx r Map.empty t | Fable.Null _t -> Expression.none, [] | Fable.UnitConstant -> undefined r, [] - | Fable.BoolConstant x -> Expression.constant(x, ?loc=r), [] - | Fable.CharConstant x -> Expression.constant(string x, ?loc=r), [] - | Fable.StringConstant x -> Expression.constant(x, ?loc=r), [] - | Fable.NumberConstant (x,_,_) -> + | Fable.BoolConstant x -> Expression.constant (x, ?loc = r), [] + | Fable.CharConstant x -> Expression.constant (string x, ?loc = r), [] + | Fable.StringConstant x -> Expression.constant (x, ?loc = r), [] + | Fable.NumberConstant (x, _, _) -> match x with - | x when x = infinity -> Expression.name("float('inf')"), [] - | x when x = -infinity -> Expression.name("float('-inf')"), [] - | _ -> Expression.constant(x, ?loc=r), [] + | x when x = infinity -> Expression.name ("float('inf')"), [] + | x when x = -infinity -> Expression.name ("float('-inf')"), [] + | _ -> Expression.constant (x, ?loc = r), [] //| Fable.RegexConstant (source, flags) -> Expression.regExpLiteral(source, flags, ?loc=r) - | Fable.NewArray (values, typ) -> - makeArray com ctx values typ + | Fable.NewArray (values, typ) -> makeArray com ctx values typ | Fable.NewArrayFrom (size, typ) -> // printfn "NewArrayFrom: %A" (size, size.Type, typ) let arg, stmts = com.TransformAsExpr(ctx, size) match size with - | Fable.Value(kind=Fable.ValueKind.NumberConstant(value=0.0)) -> - Expression.list [], [] + | Fable.Value(kind = Fable.ValueKind.NumberConstant(value = 0.0)) -> Expression.list [], [] | _ -> match size.Type with | Fable.Type.Number _ -> - let array = Expression.list [ Expression.constant(0) ] - Expression.binOp(array, Mult, arg), stmts + let array = Expression.list [ Expression.constant (0) ] + Expression.binOp (array, Mult, arg), stmts | _ -> - let name = Expression.name("list") - Expression.call(name, [arg]), stmts + let name = Expression.name ("list") + Expression.call (name, [ arg ]), stmts - | Fable.NewTuple(vals,_) -> makeTuple com ctx vals + | Fable.NewTuple (vals, _) -> makeTuple com ctx vals // Optimization for bundle size: compile list literals as List.ofArray | Fable.NewList (headAndTail, _) -> - let rec getItems acc = function + let rec getItems acc = + function | None -> List.rev acc, None - | Some(head, Fable.Value(Fable.NewList(tail, _),_)) -> getItems (head::acc) tail - | Some(head, tail) -> List.rev (head::acc), Some tail + | Some (head, Fable.Value (Fable.NewList (tail, _), _)) -> getItems (head :: acc) tail + | Some (head, tail) -> List.rev (head :: acc), Some tail + match getItems [] headAndTail with - | [], None -> - libCall com ctx r "list" "empty" [], [] - | [TransformExpr com ctx (expr, stmts)], None -> - libCall com ctx r "list" "singleton" [ expr ], stmts + | [], None -> libCall com ctx r "list" "empty" [], [] + | [ TransformExpr com ctx (expr, stmts) ], None -> libCall com ctx r "list" "singleton" [ expr ], stmts | exprs, None -> let expr, stmts = makeList com ctx exprs - [ expr ] - |> libCall com ctx r "list" "ofArray", stmts - | [TransformExpr com ctx (head, stmts)], Some(TransformExpr com ctx (tail, stmts')) -> - libCall com ctx r "list" "cons" [ head; tail], stmts @ stmts' - | exprs, Some(TransformExpr com ctx (tail, stmts)) -> + [ expr ] |> libCall com ctx r "list" "ofArray", stmts + | [ TransformExpr com ctx (head, stmts) ], Some (TransformExpr com ctx (tail, stmts')) -> + libCall com ctx r "list" "cons" [ head; tail ], stmts @ stmts' + | exprs, Some (TransformExpr com ctx (tail, stmts)) -> let expr, stmts' = makeList com ctx exprs + [ expr; tail ] - |> libCall com ctx r "list" "ofArrayWithTail", stmts @ stmts' + |> libCall com ctx r "list" "ofArrayWithTail", + stmts @ stmts' | Fable.NewOption (value, t, _) -> match value with | Some (TransformExpr com ctx (e, stmts)) -> - if mustWrapOption t - then libCall com ctx r "option" "some" [ e ], stmts - else e, stmts + if mustWrapOption t then + libCall com ctx r "option" "some" [ e ], stmts + else + e, stmts | None -> undefined r, [] - | Fable.EnumConstant(x,_) -> - com.TransformAsExpr(ctx, x) - | Fable.NewRecord(values, ent, genArgs) -> + | Fable.EnumConstant (x, _) -> com.TransformAsExpr(ctx, x) + | Fable.NewRecord (values, ent, genArgs) -> let ent = com.GetEntity(ent) - let values, stmts = List.map (fun x -> com.TransformAsExpr(ctx, x)) values |> Helpers.unzipArgs + + let values, stmts = + List.map (fun x -> com.TransformAsExpr(ctx, x)) values + |> Helpers.unzipArgs + let consRef, stmts' = ent |> pyConstructor com ctx - Expression.call(consRef, values, ?loc=r), stmts @ stmts' - | Fable.NewAnonymousRecord(values, fieldNames, _genArgs) -> - let values, stmts = values |> List.map (fun x -> com.TransformAsExpr(ctx, x)) |> Helpers.unzipArgs - List.zip (List.ofArray fieldNames) values |> makePyObject, stmts - | Fable.NewUnion(values, tag, ent, genArgs) -> + Expression.call (consRef, values, ?loc = r), stmts @ stmts' + | Fable.NewAnonymousRecord (values, fieldNames, _genArgs) -> + let values, stmts = + values + |> List.map (fun x -> com.TransformAsExpr(ctx, x)) + |> Helpers.unzipArgs + + List.zip (List.ofArray fieldNames) values + |> makePyObject, + stmts + | Fable.NewUnion (values, tag, ent, genArgs) -> let ent = com.GetEntity(ent) - let values, stmts = List.map (fun x -> com.TransformAsExpr(ctx, x)) values |> Helpers.unzipArgs + + let values, stmts = + List.map (fun x -> com.TransformAsExpr(ctx, x)) values + |> Helpers.unzipArgs + let consRef, stmts' = ent |> pyConstructor com ctx // let caseName = ent.UnionCases |> List.item tag |> getUnionCaseName |> ofString - let values = (ofInt tag)::values - Expression.call(consRef, values, ?loc=r), stmts @ stmts' + let values = (ofInt tag) :: values + Expression.call (consRef, values, ?loc = r), stmts @ stmts' | _ -> failwith $"transformValue: value {value} not supported!" let enumerator2iterator com ctx = - let enumerator = Expression.call(get com ctx None (Expression.identifier("self")) "GetEnumerator" false, []) - [ Statement.return'(libCall com ctx None "util" "toIterator" [ enumerator ]) ] + let enumerator = + Expression.call (get com ctx None (Expression.identifier ("self")) "GetEnumerator" false, []) + + [ Statement.return' (libCall com ctx None "util" "toIterator" [ enumerator ]) ] let extractBaseExprFromBaseCall (com: IPythonCompiler) (ctx: Context) (baseType: Fable.DeclaredType option) baseCall = // printfn "extractBaseExprFromBaseCall: %A" (baseCall, baseType) match baseCall, baseType with - | Some (Fable.Call(baseRef, info, _, _)), _ -> + | Some (Fable.Call (baseRef, info, _, _)), _ -> let baseExpr, stmts = match baseRef with | Fable.IdentExpr id -> com.GetIdentifierAsExpr(ctx, id.Name), [] | _ -> transformAsExpr com ctx baseRef - let expr, keywords, stmts' = transformCallArgs com ctx None (CallInfo info) - Some (baseExpr, (expr, keywords, stmts @ stmts')) + + let expr, keywords, stmts' = + transformCallArgs com ctx None (CallInfo info) + + Some(baseExpr, (expr, keywords, stmts @ stmts')) | Some (Fable.Value _), Some baseType -> // let baseEnt = com.GetEntity(baseType.Entity) // let entityName = FSharp2Fable.Helpers.getEntityDeclarationName com baseType.Entity @@ -1496,19 +1833,25 @@ module Util = // let baseExpr = (baseRefId |> typedIdent com ctx) :> Expression // Some (baseExpr, []) // default base constructor let range = baseCall |> Option.bind (fun x -> x.Range) - sprintf "Ignoring base call for %s" baseType.Entity.FullName |> addWarning com [] range + + sprintf "Ignoring base call for %s" baseType.Entity.FullName + |> addWarning com [] range + None | Some _, _ -> let range = baseCall |> Option.bind (fun x -> x.Range) - "Unexpected base call expression, please report" |> addError com [] range + + "Unexpected base call expression, please report" + |> addError com [] range + None | None, _ -> None - let transformObjectExpr (com: IPythonCompiler) ctx (members: Fable.MemberDecl list) typ baseCall: Expression * Statement list = + let transformObjectExpr (com: IPythonCompiler) ctx (members: Fable.MemberDecl list) typ baseCall : Expression * Statement list = // printfn "transformObjectExpr: %A" typ let makeMethod prop hasSpread args body decorators = let args, body, returnType = - getMemberArgsAndBody com ctx (Attached(isStatic=false)) hasSpread args body + getMemberArgsAndBody com ctx (Attached(isStatic = false)) hasSpread args body let name = let name = @@ -1518,13 +1861,18 @@ module Util = com.GetIdentifier(ctx, Naming.toSnakeCase name) - let self = Arg.arg("self") + let self = Arg.arg ("self") + let args = match decorators with // Remove extra parameters from getters, i.e __unit=None - | [Expression.Name({Id=Identifier("property")})] -> { args with Args = [ self ]; Defaults=[] } - | _ -> { args with Args = self::args.Args } - Statement.functionDef(name, args, body, decorators, returns=returnType) + | [ Expression.Name ({ Id = Identifier ("property") }) ] -> + { args with + Args = [ self ] + Defaults = [] } + | _ -> { args with Args = self :: args.Args } + + Statement.functionDef (name, args, body, decorators, returns = returnType) let interfaces = match typ with @@ -1532,26 +1880,31 @@ module Util = | _ -> let ta, _ = typeAnnotation com ctx None typ [ ta ] + let members = - members |> List.collect (fun memb -> + members + |> List.collect (fun memb -> let info = memb.Info + if info.IsGetter || info.IsValue then - let decorators = [ Expression.name("property") ] + let decorators = [ Expression.name ("property") ] [ makeMethod memb.Name false memb.Args memb.Body decorators ] elif info.IsSetter then let decorators = [ Expression.name $"{memb.Name}.setter" ] [ makeMethod memb.Name false memb.Args memb.Body decorators ] elif info.IsEnumerator then - let method = makeMethod memb.Name info.HasSpread memb.Args memb.Body [] + let method = + makeMethod memb.Name info.HasSpread memb.Args memb.Body [] + let iterator = let body = enumerator2iterator com ctx let name = com.GetIdentifier(ctx, "__iter__") - let args = Arguments.arguments([Arg.arg("self")]) - Statement.functionDef(name = name, args = args, body = body) - [ method; iterator] + let args = Arguments.arguments ([ Arg.arg ("self") ]) + Statement.functionDef (name = name, args = args, body = body) + + [ method; iterator ] else - [ makeMethod memb.Name info.HasSpread memb.Args memb.Body [] ] - ) + [ makeMethod memb.Name info.HasSpread memb.Args memb.Body [] ]) let baseExpr, classMembers = baseCall @@ -1560,60 +1913,71 @@ module Util = let consBody = [ callSuperAsStatement baseArgs ] let args = Arguments.empty let classCons = makeClassConstructor args false consBody - Some baseExpr, classCons @ members - ) + Some baseExpr, classCons @ members) |> Option.defaultValue (None, members) |> (fun (expr, memb) -> expr |> Option.toList, memb) let classBody = match classMembers with - | [] -> [ Pass] + | [] -> [ Pass ] | _ -> classMembers + let name = Helpers.getUniqueIdentifier "ObjectExpr" - let stmt = Statement.classDef(name, body=classBody, bases=interfaces @ [] ) - Expression.call(Expression.name name), [ stmt ] - let transformCallArgs (com: IPythonCompiler) ctx r (info: ArgsInfo): Expression list * Keyword list * Statement list = + let stmt = + Statement.classDef (name, body = classBody, bases = interfaces @ []) + + Expression.call (Expression.name name), [ stmt ] + + let transformCallArgs (com: IPythonCompiler) ctx r (info: ArgsInfo) : Expression list * Keyword list * Statement list = let tryGetParamObjInfo (memberInfo: Fable.CallMemberInfo) = let tryGetParamNames (parameters: Fable.ParamInfo list) = - (Some [], parameters) ||> List.fold (fun acc p -> + (Some [], parameters) + ||> List.fold (fun acc p -> match acc, p.Name with - | Some acc, Some name -> Some(name::acc) + | Some acc, Some name -> Some(name :: acc) | _ -> None) |> function | Some names -> List.rev names |> Some | None -> "ParamObj cannot be used with unnamed parameters" |> addWarning com [] r + None match memberInfo.CurriedParameterGroups, memberInfo.DeclaringEntity with // Check only members with multiple non-curried arguments - | [parameters], Some entRef when not (List.isEmpty parameters) -> + | [ parameters ], Some entRef when not (List.isEmpty parameters) -> com.TryGetEntity(entRef) |> Option.bind (fun ent -> - if ent.IsFSharpModule then None + if ent.IsFSharpModule then + None else ent.MembersFunctionsAndValues |> Seq.tryFind (fun m -> m.IsInstance = memberInfo.IsInstance && m.CompiledName = memberInfo.CompiledName && match m.CurriedParameterGroups with - | [parameters2] when List.sameLength parameters parameters2 -> - List.zip parameters parameters2 |> List.forall (fun (p1, p2) -> typeEquals true p1.Type p2.Type) - | _ -> false)) + | [ parameters2 ] when List.sameLength parameters parameters2 -> + List.zip parameters parameters2 + |> List.forall (fun (p1, p2) -> typeEquals true p1.Type p2.Type) + | _ -> false)) |> Option.bind (fun m -> - m.Attributes |> Seq.tryPick (fun a -> + m.Attributes + |> Seq.tryPick (fun a -> if a.Entity.FullName = Atts.paramObject then let index = match a.ConstructorArgs with - | :? int as index::_ -> index + | :? int as index :: _ -> index | _ -> 0 - tryGetParamNames parameters |> Option.map (fun paramNames -> - {| Index = index; Parameters = paramNames |}) - else None - )) - | _ -> None + + tryGetParamNames parameters + |> Option.map (fun paramNames -> + {| Index = index + Parameters = paramNames |}) + else + None)) + | _ -> None let paramObjInfo, hasSpread, args = match info with @@ -1623,6 +1987,7 @@ module Util = // ParamObject is not compatible with arg spread | Some mi when not i.HasSpread -> tryGetParamObjInfo mi | _ -> None + paramObjInfo, i.HasSpread, i.Args | NoCallInfo args -> None, false, args @@ -1634,32 +1999,48 @@ module Util = let args, objValues = List.splitAt i.Index args let _, objKeys = List.splitAt i.Index i.Parameters let objKeys = List.take (List.length objValues) objKeys + let objArg, stmts = List.zip objKeys objValues |> List.choose (function - | k, Fable.Value(Fable.NewOption(value,_, _),_) -> value |> Option.map (fun v -> k, v) + | k, Fable.Value (Fable.NewOption (value, _, _), _) -> value |> Option.map (fun v -> k, v) | k, v -> Some(k, v)) |> List.map (fun (k, v) -> k, com.TransformAsExpr(ctx, v)) |> List.map (fun (k, (v, stmts)) -> ((k, v), stmts)) |> List.unzip - |> (fun (kv, stmts) -> kv |> List.map(fun (k, v) -> Keyword.keyword(Identifier k, v)), stmts |> List.collect id) + |> (fun (kv, stmts) -> + kv + |> List.map (fun (k, v) -> Keyword.keyword (Identifier k, v)), + stmts |> List.collect id) + args, Some objArg, stmts let args, stmts' = match args with | [] - | [MaybeCasted(Fable.Value(Fable.UnitConstant,_))] -> [], [] + | [ MaybeCasted (Fable.Value (Fable.UnitConstant, _)) ] -> [], [] | args when hasSpread -> match List.rev args with | [] -> [], [] - | Replacements.ArrayOrListLiteral(spreadArgs,_)::rest -> - let rest = List.rev rest |> List.map (fun e -> com.TransformAsExpr(ctx, e)) - rest @ (List.map (fun e -> com.TransformAsExpr(ctx, e)) spreadArgs) |> Helpers.unzipArgs - | last::rest -> - let rest, stmts = List.rev rest |> List.map (fun e -> com.TransformAsExpr(ctx, e)) |> Helpers.unzipArgs + | Replacements.ArrayOrListLiteral (spreadArgs, _) :: rest -> + let rest = + List.rev rest + |> List.map (fun e -> com.TransformAsExpr(ctx, e)) + + rest + @ (List.map (fun e -> com.TransformAsExpr(ctx, e)) spreadArgs) + |> Helpers.unzipArgs + | last :: rest -> + let rest, stmts = + List.rev rest + |> List.map (fun e -> com.TransformAsExpr(ctx, e)) + |> Helpers.unzipArgs + let expr, stmts' = com.TransformAsExpr(ctx, last) - rest @ [ Expression.starred(expr) ], stmts @ stmts' - | args -> List.map (fun e -> com.TransformAsExpr(ctx, e)) args |> Helpers.unzipArgs + rest @ [ Expression.starred (expr) ], stmts @ stmts' + | args -> + List.map (fun e -> com.TransformAsExpr(ctx, e)) args + |> Helpers.unzipArgs match objArg with | None -> args, [], stmts @ stmts' @@ -1668,137 +2049,154 @@ module Util = //let kw = Statement.assign([ name], objArg) args, objArg, stmts @ stmts' - let resolveExpr (ctx: Context) t strategy pyExpr: Statement list = + let resolveExpr (ctx: Context) t strategy pyExpr : Statement list = // printfn "resolveExpr: %A" (pyExpr, strategy) match strategy with - | None | Some ReturnUnit -> exprAsStatement ctx pyExpr + | None + | Some ReturnUnit -> exprAsStatement ctx pyExpr // TODO: Where to put these int wrappings? Add them also for function arguments? | Some ResourceManager - | Some Return -> [ Statement.return'(pyExpr) ] - | Some(Assign left) -> exprAsStatement ctx (assign None left pyExpr) - | Some(Target left) -> exprAsStatement ctx (assign None (left |> Expression.identifier) pyExpr) + | Some Return -> [ Statement.return' (pyExpr) ] + | Some (Assign left) -> exprAsStatement ctx (assign None left pyExpr) + | Some (Target left) -> exprAsStatement ctx (assign None (left |> Expression.identifier) pyExpr) - let transformOperation com ctx range opKind: Expression * Statement list = + let transformOperation com ctx range opKind : Expression * Statement list = match opKind with - | Fable.Unary(UnaryVoid, TransformExpr com ctx (expr, stmts)) -> - Expression.none, stmts - | Fable.Unary(UnaryTypeof, TransformExpr com ctx (expr, stmts)) -> - let func = Expression.name("type") + | Fable.Unary (UnaryVoid, TransformExpr com ctx (expr, stmts)) -> Expression.none, stmts + | Fable.Unary (UnaryTypeof, TransformExpr com ctx (expr, stmts)) -> + let func = Expression.name ("type") let args = [ expr ] Expression.call (func, args), stmts // Transform `~(~(a/b))` to `a // b` - | Fable.Unary(UnaryOperator.UnaryNotBitwise, Fable.Operation(kind=Fable.Unary(UnaryOperator.UnaryNotBitwise, Fable.Operation(kind=Fable.Binary(BinaryOperator.BinaryDivide, TransformExpr com ctx (left, stmts), TransformExpr com ctx (right, stmts')))))) -> - Expression.binOp(left, FloorDiv, right), stmts @ stmts' - | Fable.Unary(UnaryOperator.UnaryNotBitwise, Fable.Operation(kind=Fable.Unary(UnaryOperator.UnaryNotBitwise, TransformExpr com ctx (left, stmts)))) -> - let name = Expression.name("int") - Expression.call(name, [left]), stmts - | Fable.Unary(op, TransformExpr com ctx (expr, stmts)) -> - Expression.unaryOp(op, expr, ?loc=range), stmts - - | Fable.Binary(BinaryInstanceOf, TransformExpr com ctx (left, stmts), TransformExpr com ctx (right, stmts')) -> - let func = Expression.name("isinstance") + | Fable.Unary (UnaryOperator.UnaryNotBitwise, + Fable.Operation(kind = Fable.Unary (UnaryOperator.UnaryNotBitwise, + Fable.Operation(kind = Fable.Binary (BinaryOperator.BinaryDivide, + TransformExpr com ctx (left, stmts), + TransformExpr com ctx (right, stmts')))))) -> + Expression.binOp (left, FloorDiv, right), stmts @ stmts' + | Fable.Unary (UnaryOperator.UnaryNotBitwise, + Fable.Operation(kind = Fable.Unary (UnaryOperator.UnaryNotBitwise, TransformExpr com ctx (left, stmts)))) -> + let name = Expression.name ("int") + Expression.call (name, [ left ]), stmts + | Fable.Unary (op, TransformExpr com ctx (expr, stmts)) -> Expression.unaryOp (op, expr, ?loc = range), stmts + + | Fable.Binary (BinaryInstanceOf, TransformExpr com ctx (left, stmts), TransformExpr com ctx (right, stmts')) -> + let func = Expression.name ("isinstance") let args = [ left; right ] Expression.call (func, args), stmts' @ stmts - | Fable.Binary(op, TransformExpr com ctx (left, stmts), TransformExpr com ctx (right, stmts')) -> + | Fable.Binary (op, TransformExpr com ctx (left, stmts), TransformExpr com ctx (right, stmts')) -> match op with | BinaryEqualStrict -> match left, right with - | Expression.Constant _ , _ - | _, Expression.Constant _ -> - Expression.compare(left, BinaryEqual, [right], ?loc=range), stmts @ stmts' - | _, Expression.Name _ -> - Expression.compare(left, BinaryEqualStrict, [right], ?loc=range), stmts @ stmts' + | Expression.Constant _, _ + | _, Expression.Constant _ -> Expression.compare (left, BinaryEqual, [ right ], ?loc = range), stmts @ stmts' + | _, Expression.Name _ -> Expression.compare (left, BinaryEqualStrict, [ right ], ?loc = range), stmts @ stmts' | _ -> // Use == for the rest - Expression.compare(left, BinaryEqual, [right], ?loc=range), stmts @ stmts' + Expression.compare (left, BinaryEqual, [ right ], ?loc = range), stmts @ stmts' | BinaryUnequalStrict -> match left, right with - | Expression.Constant _, _ - | _, Expression.Constant _ -> - Expression.compare(left, BinaryUnequal, [right], ?loc=range), stmts @ stmts' - | _ -> - Expression.compare(left, op, [right], ?loc=range), stmts @ stmts' + | Expression.Constant _, _ + | _, Expression.Constant _ -> Expression.compare (left, BinaryUnequal, [ right ], ?loc = range), stmts @ stmts' + | _ -> Expression.compare (left, op, [ right ], ?loc = range), stmts @ stmts' | BinaryEqual -> match left, right with - | Expression.Constant _, _ -> - Expression.compare(left, BinaryEqual, [right], ?loc=range), stmts @ stmts' - | _, Expression.Name({Id=Identifier("None")}) -> - Expression.compare(left, BinaryEqualStrict, [right], ?loc=range), stmts @ stmts' - | _ -> - Expression.compare(left, op, [right], ?loc=range), stmts @ stmts' + | Expression.Constant _, _ -> Expression.compare (left, BinaryEqual, [ right ], ?loc = range), stmts @ stmts' + | _, Expression.Name ({ Id = Identifier ("None") }) -> + Expression.compare (left, BinaryEqualStrict, [ right ], ?loc = range), stmts @ stmts' + | _ -> Expression.compare (left, op, [ right ], ?loc = range), stmts @ stmts' | BinaryUnequal -> match right with - | Expression.Name({ Id=Identifier("None")} ) -> + | Expression.Name ({ Id = Identifier ("None") }) -> let op = BinaryUnequalStrict - Expression.compare(left, op, [right], ?loc=range), stmts @ stmts' - | _ -> - Expression.compare(left, op, [right], ?loc=range), stmts @ stmts' + Expression.compare (left, op, [ right ], ?loc = range), stmts @ stmts' + | _ -> Expression.compare (left, op, [ right ], ?loc = range), stmts @ stmts' | BinaryLess | BinaryLessOrEqual | BinaryGreater - | BinaryGreaterOrEqual -> - Expression.compare(left, op, [right], ?loc=range), stmts @ stmts' - | _ -> - Expression.binOp(left, op, right, ?loc=range), stmts @ stmts' + | BinaryGreaterOrEqual -> Expression.compare (left, op, [ right ], ?loc = range), stmts @ stmts' + | _ -> Expression.binOp (left, op, right, ?loc = range), stmts @ stmts' - | Fable.Logical(op, TransformExpr com ctx (left, stmts), TransformExpr com ctx (right, stmts')) -> - Expression.boolOp(op, [left; right], ?loc=range), stmts @ stmts' + | Fable.Logical (op, TransformExpr com ctx (left, stmts), TransformExpr com ctx (right, stmts')) -> + Expression.boolOp (op, [ left; right ], ?loc = range), stmts @ stmts' let transformEmit (com: IPythonCompiler) ctx range (info: Fable.EmitInfo) = let macro = info.Macro let info = info.CallInfo - let thisArg, stmts = info.ThisArg |> Option.map (fun e -> com.TransformAsExpr(ctx, e)) |> Option.toList |> Helpers.unzipArgs - let exprs, _, stmts' = transformCallArgs com ctx range (CallInfo info) + + let thisArg, stmts = + info.ThisArg + |> Option.map (fun e -> com.TransformAsExpr(ctx, e)) + |> Option.toList + |> Helpers.unzipArgs + + let exprs, _, stmts' = + transformCallArgs com ctx range (CallInfo info) if macro.StartsWith("functools") then com.GetImportExpr(ctx, "functools") |> ignore - let args = - exprs - |> List.append thisArg + let args = exprs |> List.append thisArg emitExpression range macro args, stmts @ stmts' let transformCall (com: IPythonCompiler) ctx range callee (callInfo: Fable.CallInfo) : Expression * Statement list = // printfn "transformCall: %A" (callee, callInfo) let callee', stmts = com.TransformAsExpr(ctx, callee) - let args, kw, stmts' = transformCallArgs com ctx range (CallInfo callInfo) + + let args, kw, stmts' = + transformCallArgs com ctx range (CallInfo callInfo) match callee, callInfo.ThisArg with - | Fable.Get(expr, Fable.FieldGet(fieldName="Dispose"), _, _), _ -> + | Fable.Get (expr, Fable.FieldGet(fieldName = "Dispose"), _, _), _ -> let expr, stmts'' = com.TransformAsExpr(ctx, expr) libCall com ctx range "util" "dispose" [ expr ], stmts @ stmts' @ stmts'' - | Fable.Get(expr, Fable.FieldGet(fieldName="set"), _, _), _ -> + | Fable.Get (expr, Fable.FieldGet(fieldName = "set"), _, _), _ -> // printfn "Type: %A" expr.Type let right, stmts = com.TransformAsExpr(ctx, callInfo.Args.Head) - let arg, stmts' = com.TransformAsExpr(ctx, callInfo.Args.Tail.Head) + + let arg, stmts' = + com.TransformAsExpr(ctx, callInfo.Args.Tail.Head) + let value, stmts'' = com.TransformAsExpr(ctx, expr) - Expression.none, Statement.assign([Expression.subscript(value, right)], arg) :: stmts @ stmts' @ stmts'' - | Fable.Get(_, Fable.FieldGet(fieldName="sort"), _, _), _ -> - callFunction range callee' [] kw, stmts @ stmts' - | _, Some(TransformExpr com ctx (thisArg, stmts'')) -> callFunction range callee' (thisArg::args) kw, stmts @ stmts' @ stmts'' - | _, None when callInfo.IsConstructor -> Expression.call(callee', args, kw, ?loc=range), stmts @ stmts' + Expression.none, + Statement.assign ([ Expression.subscript (value, right) ], arg) + :: stmts + @ stmts' @ stmts'' + | Fable.Get (_, Fable.FieldGet(fieldName = "sort"), _, _), _ -> callFunction range callee' [] kw, stmts @ stmts' + + | _, Some (TransformExpr com ctx (thisArg, stmts'')) -> callFunction range callee' (thisArg :: args) kw, stmts @ stmts' @ stmts'' + | _, None when callInfo.IsConstructor -> Expression.call (callee', args, kw, ?loc = range), stmts @ stmts' | _, None -> callFunction range callee' args kw, stmts @ stmts' let transformCurriedApply com ctx range (TransformExpr com ctx (applied, stmts)) args = match transformCallArgs com ctx range (NoCallInfo args) with | [], kw, stmts' -> callFunction range applied [] kw, stmts @ stmts' - | args, kw, stmts' -> (applied, args) ||> List.fold (fun e arg -> callFunction range e [arg] kw), stmts @ stmts' + | args, kw, stmts' -> + (applied, args) + ||> List.fold (fun e arg -> callFunction range e [ arg ] kw), + stmts @ stmts' let transformCallAsStatements com ctx range t returnStrategy callee callInfo = let argsLen (i: Fable.CallInfo) = - List.length i.Args + (if Option.isSome i.ThisArg then 1 else 0) + List.length i.Args + + (if Option.isSome i.ThisArg then 1 else 0) // Warn when there's a recursive call that couldn't be optimized? match returnStrategy, ctx.TailCallOpportunity with - | Some(Return|ReturnUnit), Some tc when tc.IsRecursiveRef(callee) - && argsLen callInfo = List.length tc.Args -> + | Some (Return + | ReturnUnit), + Some tc when + tc.IsRecursiveRef(callee) + && argsLen callInfo = List.length tc.Args + -> let args = match callInfo.ThisArg with - | Some thisArg -> thisArg::callInfo.Args + | Some thisArg -> thisArg :: callInfo.Args | None -> callInfo.Args + optimizeTailCall com ctx range tc args | _ -> let expr, stmts = transformCall com ctx range callee callInfo @@ -1807,23 +2205,34 @@ module Util = let transformCurriedApplyAsStatements com ctx range t returnStrategy callee args = // Warn when there's a recursive call that couldn't be optimized? match returnStrategy, ctx.TailCallOpportunity with - | Some(Return|ReturnUnit), Some tc when tc.IsRecursiveRef(callee) - && List.sameLength args tc.Args -> + | Some (Return + | ReturnUnit), + Some tc when + tc.IsRecursiveRef(callee) + && List.sameLength args tc.Args + -> optimizeTailCall com ctx range tc args | _ -> - let expr, stmts = transformCurriedApply com ctx range callee args + let expr, stmts = + transformCurriedApply com ctx range callee args + stmts @ (expr |> resolveExpr ctx t returnStrategy) let getNonLocals (body: Statement list) = let body, nonLocals = body - |> List.partition (function | Statement.NonLocal _ -> false | _ -> true) + |> List.partition (function + | Statement.NonLocal _ -> false + | _ -> true) let nonLocal = nonLocals - |> List.collect (function | Statement.NonLocal(nl) -> nl.Names | _ -> []) + |> List.collect (function + | Statement.NonLocal (nl) -> nl.Names + | _ -> []) |> List.distinct |> Statement.nonLocal + [ nonLocal ], body let transformBody (com: IPythonCompiler) ctx ret (body: Statement list) : Statement list = @@ -1837,53 +2246,70 @@ module Util = // in a lambda to isolate its variable context let transformBlock (com: IPythonCompiler) ctx ret (expr: Fable.Expr) : Statement list = let block = - com.TransformAsStatements(ctx, ret, expr) |> List.choose Helpers.isProductiveStatement + com.TransformAsStatements(ctx, ret, expr) + |> List.choose Helpers.isProductiveStatement + match block with | [] -> [ Pass ] - | _ -> - block - |> transformBody com ctx ret + | _ -> block |> transformBody com ctx ret let transformTryCatch com (ctx: Context) r returnStrategy (body, catch: option, finalizer) = // try .. catch statements cannot be tail call optimized let ctx = { ctx with TailCallOpportunity = None } + let handlers = - catch |> Option.map (fun (param, body) -> + catch + |> Option.map (fun (param, body) -> let body = transformBlock com ctx returnStrategy body - let exn = Expression.identifier("Exception") |> Some + let exn = Expression.identifier ("Exception") |> Some let identifier = ident com ctx param [ ExceptHandler.exceptHandler (``type`` = exn, name = identifier, body = body) ]) + let finalizer, stmts = match finalizer with | Some finalizer -> - finalizer |> - transformBlock com ctx None - |> List.partition (function | Statement.NonLocal _ -> false | _ -> true ) - | None -> [], [] + finalizer + |> transformBlock com ctx None + |> List.partition (function + | Statement.NonLocal _ -> false + | _ -> true) + | None -> [], [] - stmts @ [ Statement.try'(transformBlock com ctx returnStrategy body, ?handlers=handlers, finalBody=finalizer, ?loc=r) ] + stmts + @ [ Statement.try' (transformBlock com ctx returnStrategy body, ?handlers = handlers, finalBody = finalizer, ?loc = r) ] let rec transformIfStatement (com: IPythonCompiler) ctx r ret guardExpr thenStmnt elseStmnt = // printfn "transformIfStatement" let expr, stmts = com.TransformAsExpr(ctx, guardExpr) + match expr with - | Constant(value=value) when (value :? bool) -> + | Constant (value = value) when (value :? bool) -> match value with - | :? bool as value when value -> stmts @ com.TransformAsStatements(ctx, ret, thenStmnt) - | _ -> stmts @ com.TransformAsStatements(ctx, ret, elseStmnt) + | :? bool as value when value -> + stmts + @ com.TransformAsStatements(ctx, ret, thenStmnt) + | _ -> + stmts + @ com.TransformAsStatements(ctx, ret, elseStmnt) | guardExpr -> let thenStmnt, stmts' = transformBlock com ctx ret thenStmnt - |> List.partition (function | Statement.NonLocal _ -> false | _ -> true ) + |> List.partition (function + | Statement.NonLocal _ -> false + | _ -> true) + let ifStatement, stmts'' = let block, stmts = com.TransformAsStatements(ctx, ret, elseStmnt) - |> List.partition (function | Statement.NonLocal _ -> false | _ -> true ) + |> List.partition (function + | Statement.NonLocal _ -> false + | _ -> true) match block with - | [ ] -> Statement.if'(guardExpr, thenStmnt, ?loc=r), stmts - | [ elseStmnt ] -> Statement.if'(guardExpr, thenStmnt, [ elseStmnt ], ?loc=r), stmts - | statements -> Statement.if'(guardExpr, thenStmnt, statements, ?loc=r), stmts + | [] -> Statement.if' (guardExpr, thenStmnt, ?loc = r), stmts + | [ elseStmnt ] -> Statement.if' (guardExpr, thenStmnt, [ elseStmnt ], ?loc = r), stmts + | statements -> Statement.if' (guardExpr, thenStmnt, statements, ?loc = r), stmts + stmts @ stmts' @ stmts'' @ [ ifStatement ] let transformGet (com: IPythonCompiler) ctx range typ (fableExpr: Fable.Expr) kind = @@ -1891,38 +2317,41 @@ module Util = // printfn "transformGet: %A" (fableExpr.Type) match kind with - | Fable.ExprGet(Fable.Value(kind=Fable.StringConstant("length"))) - | Fable.FieldGet(fieldName="length") -> - let func = Expression.name("len") + | Fable.ExprGet (Fable.Value(kind = Fable.StringConstant ("length"))) + | Fable.FieldGet(fieldName = "length") -> + let func = Expression.name ("len") let left, stmts = com.TransformAsExpr(ctx, fableExpr) Expression.call (func, [ left ]), stmts - | Fable.FieldGet(fieldName="message") -> - let func = Expression.name("str") + | Fable.FieldGet(fieldName = "message") -> + let func = Expression.name ("str") let left, stmts = com.TransformAsExpr(ctx, fableExpr) Expression.call (func, [ left ]), stmts - | Fable.FieldGet(fieldName="push") -> + | Fable.FieldGet(fieldName = "push") -> let attr = Identifier("append") let value, stmts = com.TransformAsExpr(ctx, fableExpr) Expression.attribute (value = value, attr = attr, ctx = Load), stmts - | Fable.ExprGet(TransformExpr com ctx (prop, stmts)) -> + | Fable.ExprGet (TransformExpr com ctx (prop, stmts)) -> let expr, stmts' = com.TransformAsExpr(ctx, fableExpr) let expr, stmts'' = getExpr com ctx range expr prop expr, stmts @ stmts' @ stmts'' - | Fable.FieldGet(fieldName,_) -> + | Fable.FieldGet (fieldName, _) -> //printfn "Fable.FieldGet: %A" (fieldName, fableExpr.Type) let fieldName = fieldName |> Naming.toSnakeCase // |> Helpers.clean + let fableExpr = match fableExpr with // If we're accessing a virtual member with default implementation (see #701) // from base class, we can use `super` in JS so we don't need the bound this arg - | Fable.Value(Fable.BaseValue(_,t), r) -> Fable.Value(Fable.BaseValue(None, t), r) + | Fable.Value (Fable.BaseValue (_, t), r) -> Fable.Value(Fable.BaseValue(None, t), r) | _ -> fableExpr + let expr, stmts = com.TransformAsExpr(ctx, fableExpr) + let subscript = match fableExpr.Type with | Fable.AnonymousRecordType _ -> true - | Fable.GenericParam (_, [Fable.Constraint.HasMember (_, false)]) -> true + | Fable.GenericParam (_, [ Fable.Constraint.HasMember (_, false) ]) -> true | _ -> false // printfn "Fable.FieldGet: %A" (fieldName, fableExpr.Type) get com ctx range expr fieldName subscript, stmts @@ -1940,50 +2369,60 @@ module Util = | Fable.TupleIndex index -> match fableExpr with // TODO: Check the erased expressions don't have side effects? - | Fable.Value(Fable.NewTuple(exprs, _), _) -> - com.TransformAsExpr(ctx, List.item index exprs) + | Fable.Value (Fable.NewTuple (exprs, _), _) -> com.TransformAsExpr(ctx, List.item index exprs) | TransformExpr com ctx (expr, stmts) -> let expr, stmts' = getExpr com ctx range expr (ofInt index) expr, stmts @ stmts' | Fable.OptionValue -> let expr, stmts = com.TransformAsExpr(ctx, fableExpr) - if mustWrapOption typ || com.Options.Language = TypeScript - then libCall com ctx None "option" "value" [ expr ], stmts - else expr, stmts + + if mustWrapOption typ + || com.Options.Language = TypeScript then + libCall com ctx None "option" "value" [ expr ], stmts + else + expr, stmts | Fable.UnionTag -> let expr, stmts = getUnionExprTag com ctx range fableExpr expr, stmts - | Fable.UnionField(_, fieldIndex) -> + | Fable.UnionField (_, fieldIndex) -> let expr, stmts = com.TransformAsExpr(ctx, fableExpr) - let expr, stmts' = getExpr com ctx None expr (Expression.constant("fields")) - let expr, stmts'' = getExpr com ctx range expr (ofInt fieldIndex) + + let expr, stmts' = + getExpr com ctx None expr (Expression.constant ("fields")) + + let expr, stmts'' = + getExpr com ctx range expr (ofInt fieldIndex) + expr, stmts @ stmts' @ stmts'' let transformSet (com: IPythonCompiler) ctx range fableExpr typ (value: Fable.Expr) kind = // printfn "transformSet: %A" (fableExpr, value) let expr, stmts = com.TransformAsExpr(ctx, fableExpr) + let value, stmts' = let value, st = com.TransformAsExpr(ctx, value) value |> wrapIntExpression typ, st + let ret, stmts'' = match kind with - | Fable.ValueSet -> - expr, [] - | Fable.ExprSet(TransformExpr com ctx (e, stmts'')) -> + | Fable.ValueSet -> expr, [] + | Fable.ExprSet (TransformExpr com ctx (e, stmts'')) -> let expr, stmts''' = getExpr com ctx None expr e expr, stmts'' @ stmts''' - | Fable.FieldSet(fieldName) -> + | Fable.FieldSet (fieldName) -> let fieldName = fieldName |> Naming.toSnakeCase |> Helpers.clean get com ctx None expr fieldName false, [] + assign range ret value, stmts @ stmts' @ stmts'' let transformBindingExprBody (com: IPythonCompiler) (ctx: Context) (var: Fable.Ident) (value: Fable.Expr) = match value with - | Function(args, body) -> + | Function (args, body) -> let name = Some var.Name + transformFunctionWithAnnotations com ctx name args body |||> makeArrowFunctionExpression com ctx name | _ -> @@ -1998,11 +2437,16 @@ module Util = let transformBindingAsStatements (com: IPythonCompiler) ctx (var: Fable.Ident) (value: Fable.Expr) = // printfn "transformBindingAsStatements: %A" (var, value) if isPyStatement ctx false value then - let varName, varExpr = Expression.name(var.Name), identAsExpr com ctx var + let varName, varExpr = + Expression.name (var.Name), identAsExpr com ctx var + ctx.BoundVars.Bind(var.Name) let ta, stmts = typeAnnotation com ctx None var.Type - let decl = Statement.assign(varName, ta) - let body = com.TransformAsStatements(ctx, Some(Assign varExpr), value) + let decl = Statement.assign (varName, ta) + + let body = + com.TransformAsStatements(ctx, Some(Assign varExpr), value) + stmts @ [ decl ] @ body else let value, stmts = transformBindingExprBody com ctx var value @@ -2011,52 +2455,71 @@ module Util = let decl = varDeclaration ctx varName (Some ta) value stmts @ stmts' @ decl - let transformTest (com: IPythonCompiler) ctx range kind expr: Expression * Statement list = + let transformTest (com: IPythonCompiler) ctx range kind expr : Expression * Statement list = match kind with - | Fable.TypeTest t -> - transformTypeTest com ctx range expr t + | Fable.TypeTest t -> transformTypeTest com ctx range expr t | Fable.OptionTest nonEmpty -> - let op = if nonEmpty then BinaryUnequalStrict else BinaryEqualStrict + let op = + if nonEmpty then + BinaryUnequalStrict + else + BinaryEqualStrict + let expr, stmts = com.TransformAsExpr(ctx, expr) - Expression.compare(expr, op, [Expression.none], ?loc=range), stmts + Expression.compare (expr, op, [ Expression.none ], ?loc = range), stmts | Fable.ListTest nonEmpty -> let expr, stmts = com.TransformAsExpr(ctx, expr) // let op = if nonEmpty then BinaryUnequal else BinaryEqual // Expression.binaryExpression(op, get None expr "tail", Expression.none, ?loc=range) let expr = let expr = libCall com ctx range "list" "isEmpty" [ expr ] - if nonEmpty then Expression.unaryOp(UnaryNot, expr, ?loc=range) else expr + + if nonEmpty then + Expression.unaryOp (UnaryNot, expr, ?loc = range) + else + expr + expr, stmts | Fable.UnionCaseTest tag -> let expected = ofInt tag let actual, stmts = getUnionExprTag com ctx None expr - Expression.compare(actual, [Eq], [ expected ], ?loc=range), stmts + Expression.compare (actual, [ Eq ], [ expected ], ?loc = range), stmts - let transformSwitch (com: IPythonCompiler) ctx useBlocks returnStrategy evalExpr cases defaultCase: Statement list = + let transformSwitch (com: IPythonCompiler) ctx useBlocks returnStrategy evalExpr cases defaultCase : Statement list = let cases = - cases |> List.collect (fun (guards, expr) -> + cases + |> List.collect (fun (guards, expr) -> // Remove empty branches match returnStrategy, expr, guards with - | None, Fable.Value(Fable.UnitConstant,_), _ + | None, Fable.Value (Fable.UnitConstant, _), _ | _, _, [] -> [] | _, _, guards -> let guards, lastGuard = List.splitLast guards - let guards = guards |> List.map (fun e -> - let expr, stmts = com.TransformAsExpr(ctx, e) - (stmts, Some expr)) - let caseBody = com.TransformAsStatements(ctx, returnStrategy, expr) + + let guards = + guards + |> List.map (fun e -> + let expr, stmts = com.TransformAsExpr(ctx, e) + (stmts, Some expr)) + + let caseBody = + com.TransformAsStatements(ctx, returnStrategy, expr) + let caseBody = match returnStrategy with | Some Return -> caseBody - | _ -> List.append caseBody [ Statement.break'() ] + | _ -> List.append caseBody [ Statement.break' () ] + let expr, stmts = com.TransformAsExpr(ctx, lastGuard) - guards @ [(stmts @ caseBody, Some expr)] - ) + guards @ [ (stmts @ caseBody, Some expr) ]) + let cases = match defaultCase with | Some expr -> - let defaultCaseBody = com.TransformAsStatements(ctx, returnStrategy, expr) - cases @ [(defaultCaseBody, None)] + let defaultCaseBody = + com.TransformAsStatements(ctx, returnStrategy, expr) + + cases @ [ (defaultCaseBody, None) ] | None -> cases let value, stmts = com.TransformAsExpr(ctx, evalExpr) @@ -2068,7 +2531,8 @@ module Util = match test with | None -> body | Some test -> - let expr = Expression.compare (left = value, ops = [ Eq ], comparators = [ test ]) + let expr = + Expression.compare (left = value, ops = [ Eq ], comparators = [ test ]) let test = match fallThrough with @@ -2082,129 +2546,184 @@ module Util = // Remove any break statements from body let body = body - |> List.filter (function | Statement.Break -> false | _ -> true) + |> List.filter (function + | Statement.Break -> false + | _ -> true) |> function // Make sure we don't have an empty body | [] -> [ Statement.Pass ] - | body -> body + | body -> body let nonLocals, body = getNonLocals body - let nonLocals, orElse = ifThenElse None cases |> List.append nonLocals |> getNonLocals - nonLocals @ [ Statement.if'(test = test, body = body, orelse = orElse) ] + + let nonLocals, orElse = + ifThenElse None cases + |> List.append nonLocals + |> getNonLocals + + nonLocals + @ [ Statement.if' (test = test, body = body, orelse = orElse) ] let result = cases |> ifThenElse None + match result with | [] -> [] | ifStmt -> stmts @ ifStmt let matchTargetIdentAndValues idents values = - if List.isEmpty idents then [] - elif List.sameLength idents values then List.zip idents values - else failwith "Target idents/values lengths differ" + if List.isEmpty idents then + [] + elif List.sameLength idents values then + List.zip idents values + else + failwith "Target idents/values lengths differ" let getDecisionTargetAndBindValues (com: IPythonCompiler) (ctx: Context) targetIndex boundValues = let idents, target = getDecisionTarget ctx targetIndex - let identsAndValues = matchTargetIdentAndValues idents boundValues + + let identsAndValues = + matchTargetIdentAndValues idents boundValues + if not com.Options.DebugMode then let bindings, replacements = (([], Map.empty), identsAndValues) ||> List.fold (fun (bindings, replacements) (ident, expr) -> if canHaveSideEffects expr then - (ident, expr)::bindings, replacements + (ident, expr) :: bindings, replacements else bindings, Map.add ident.Name expr replacements) + let target = FableTransforms.replaceValues replacements target List.rev bindings, target else identsAndValues, target let transformDecisionTreeSuccessAsExpr (com: IPythonCompiler) (ctx: Context) targetIndex boundValues = - let bindings, target = getDecisionTargetAndBindValues com ctx targetIndex boundValues + let bindings, target = + getDecisionTargetAndBindValues com ctx targetIndex boundValues + match bindings with | [] -> com.TransformAsExpr(ctx, target) | bindings -> - let target = List.rev bindings |> List.fold (fun e (i,v) -> Fable.Let(i,v,e)) target + let target = + List.rev bindings + |> List.fold (fun e (i, v) -> Fable.Let(i, v, e)) target + com.TransformAsExpr(ctx, target) let exprAsStatement (ctx: Context) (expr: Expression) : Statement list = // printfn "exprAsStatement: %A" expr match expr with // A single None will be removed (i.e transformCall may return None) - | Name({Id=Identifier "None"}) -> [] - | NamedExpr({Target=target; Value=value; Loc=_ }) -> + | Name ({ Id = Identifier "None" }) -> [] + | NamedExpr ({ Target = target + Value = value + Loc = _ }) -> let nonLocals = match target with - | Expression.Name({ Id=id }) -> [ ctx.BoundVars.NonLocals([ id ]) |> Statement.nonLocal ] + | Expression.Name ({ Id = id }) -> + [ ctx.BoundVars.NonLocals([ id ]) + |> Statement.nonLocal ] | _ -> [] // printfn "Nonlocals: %A" nonLocals - nonLocals @ [ Statement.assign([target], value) ] - | _ -> [ Statement.expr(expr) ] - - let transformDecisionTreeSuccessAsStatements (com: IPythonCompiler) (ctx: Context) returnStrategy targetIndex boundValues: Statement list = + nonLocals + @ [ Statement.assign ([ target ], value) ] + | _ -> [ Statement.expr (expr) ] + + let transformDecisionTreeSuccessAsStatements + (com: IPythonCompiler) + (ctx: Context) + returnStrategy + targetIndex + boundValues + : Statement list = match returnStrategy with - | Some(Target targetId) as target -> + | Some (Target targetId) as target -> let idents, _ = getDecisionTarget ctx targetIndex + let assignments = matchTargetIdentAndValues idents boundValues |> List.collect (fun (id, TransformExpr com ctx (value, stmts)) -> - let stmts' = assign None (identAsExpr com ctx id) value |> exprAsStatement ctx + let stmts' = + assign None (identAsExpr com ctx id) value + |> exprAsStatement ctx + stmts @ stmts') - let targetAssignment = assign None (targetId |> Expression.name) (ofInt targetIndex) |> exprAsStatement ctx + + let targetAssignment = + assign None (targetId |> Expression.name) (ofInt targetIndex) + |> exprAsStatement ctx + targetAssignment @ assignments | ret -> - let bindings, target = getDecisionTargetAndBindValues com ctx targetIndex boundValues - let bindings = bindings |> Seq.collect (fun (i, v) -> transformBindingAsStatements com ctx i v) |> Seq.toList - bindings @ (com.TransformAsStatements(ctx, ret, target)) + let bindings, target = + getDecisionTargetAndBindValues com ctx targetIndex boundValues + + let bindings = + bindings + |> Seq.collect (fun (i, v) -> transformBindingAsStatements com ctx i v) + |> Seq.toList + + bindings + @ (com.TransformAsStatements(ctx, ret, target)) let transformDecisionTreeAsSwitch expr = - let (|Equals|_|) = function - | Fable.Operation(Fable.Binary(BinaryEqualStrict, expr, right), _, _) -> - Some(expr, right) - | Fable.Test(expr, Fable.UnionCaseTest tag, _) -> - let evalExpr = Fable.Get(expr, Fable.UnionTag, Fable.Number(Int32, None), None) + let (|Equals|_|) = + function + | Fable.Operation (Fable.Binary (BinaryEqualStrict, expr, right), _, _) -> Some(expr, right) + | Fable.Test (expr, Fable.UnionCaseTest tag, _) -> + let evalExpr = + Fable.Get(expr, Fable.UnionTag, Fable.Number(Int32, None), None) + let right = makeIntConst tag Some(evalExpr, right) | _ -> None + let sameEvalExprs evalExpr1 evalExpr2 = match evalExpr1, evalExpr2 with | Fable.IdentExpr i1, Fable.IdentExpr i2 - | Fable.Get(Fable.IdentExpr i1,Fable.UnionTag,_,_), Fable.Get(Fable.IdentExpr i2,Fable.UnionTag,_,_) -> + | Fable.Get (Fable.IdentExpr i1, Fable.UnionTag, _, _), Fable.Get (Fable.IdentExpr i2, Fable.UnionTag, _, _) -> i1.Name = i2.Name | _ -> false - let rec checkInner cases evalExpr = function - | Fable.IfThenElse(Equals(evalExpr2, caseExpr), - Fable.DecisionTreeSuccess(targetIndex, boundValues, _), treeExpr, _) - when sameEvalExprs evalExpr evalExpr2 -> + + let rec checkInner cases evalExpr = + function + | Fable.IfThenElse (Equals (evalExpr2, caseExpr), Fable.DecisionTreeSuccess (targetIndex, boundValues, _), treeExpr, _) when + sameEvalExprs evalExpr evalExpr2 + -> match treeExpr with - | Fable.DecisionTreeSuccess(defaultTargetIndex, defaultBoundValues, _) -> - let cases = (caseExpr, targetIndex, boundValues)::cases |> List.rev + | Fable.DecisionTreeSuccess (defaultTargetIndex, defaultBoundValues, _) -> + let cases = + (caseExpr, targetIndex, boundValues) :: cases + |> List.rev + Some(evalExpr, cases, (defaultTargetIndex, defaultBoundValues)) - | treeExpr -> checkInner ((caseExpr, targetIndex, boundValues)::cases) evalExpr treeExpr + | treeExpr -> checkInner ((caseExpr, targetIndex, boundValues) :: cases) evalExpr treeExpr | _ -> None + match expr with - | Fable.IfThenElse(Equals(evalExpr, caseExpr), - Fable.DecisionTreeSuccess(targetIndex, boundValues, _), treeExpr, _) -> - match checkInner [caseExpr, targetIndex, boundValues] evalExpr treeExpr with - | Some(evalExpr, cases, defaultCase) -> - Some(evalExpr, cases, defaultCase) + | Fable.IfThenElse (Equals (evalExpr, caseExpr), Fable.DecisionTreeSuccess (targetIndex, boundValues, _), treeExpr, _) -> + match checkInner [ caseExpr, targetIndex, boundValues ] evalExpr treeExpr with + | Some (evalExpr, cases, defaultCase) -> Some(evalExpr, cases, defaultCase) | None -> None | _ -> None - let transformDecisionTreeAsExpr (com: IPythonCompiler) (ctx: Context) targets expr: Expression * Statement list = + let transformDecisionTreeAsExpr (com: IPythonCompiler) (ctx: Context) targets expr : Expression * Statement list = // TODO: Check if some targets are referenced multiple times let ctx = { ctx with DecisionTargets = targets } com.TransformAsExpr(ctx, expr) let groupSwitchCases t (cases: (Fable.Expr * int * Fable.Expr list) list) (defaultIndex, defaultBoundValues) = cases - |> List.groupBy (fun (_,idx,boundValues) -> + |> List.groupBy (fun (_, idx, boundValues) -> // Try to group cases with some target index and empty bound values // If bound values are non-empty use also a non-empty Guid to prevent grouping - if List.isEmpty boundValues - then idx, Guid.Empty - else idx, Guid.NewGuid()) - |> List.map (fun ((idx,_), cases) -> + if List.isEmpty boundValues then + idx, Guid.Empty + else + idx, Guid.NewGuid()) + |> List.map (fun ((idx, _), cases) -> let caseExprs = cases |> List.map Tuple3.item1 // If there are multiple cases, it means boundValues are empty // (see `groupBy` above), so it doesn't mind which one we take as reference @@ -2215,124 +2734,176 @@ module Util = // Check if the last case can also be grouped with the default branch, see #2357 | cases when List.isEmpty defaultBoundValues -> match List.splitLast cases with - | cases, (_, Fable.DecisionTreeSuccess(idx, [], _)) - when idx = defaultIndex -> cases + | cases, (_, Fable.DecisionTreeSuccess (idx, [], _)) when idx = defaultIndex -> cases | _ -> cases | cases -> cases let getTargetsWithMultipleReferences expr = - let rec findSuccess (targetRefs: Map) = function + let rec findSuccess (targetRefs: Map) = + function | [] -> targetRefs - | expr::exprs -> + | expr :: exprs -> match expr with // We shouldn't actually see this, but shortcircuit just in case - | Fable.DecisionTree _ -> - findSuccess targetRefs exprs - | Fable.DecisionTreeSuccess(idx,_,_) -> + | Fable.DecisionTree _ -> findSuccess targetRefs exprs + | Fable.DecisionTreeSuccess (idx, _, _) -> let count = Map.tryFind idx targetRefs |> Option.defaultValue 0 + let targetRefs = Map.add idx (count + 1) targetRefs findSuccess targetRefs exprs | expr -> let exprs2 = FableTransforms.getSubExpressions expr findSuccess targetRefs (exprs @ exprs2) - findSuccess Map.empty [expr] |> Seq.choose (fun kv -> - if kv.Value > 1 then Some kv.Key else None) |> Seq.toList + + findSuccess Map.empty [ expr ] + |> Seq.choose (fun kv -> + if kv.Value > 1 then + Some kv.Key + else + None) + |> Seq.toList /// When several branches share target create first a switch to get the target index and bind value /// and another to execute the actual target - let transformDecisionTreeWithTwoSwitches (com: IPythonCompiler) ctx returnStrategy - (targets: (Fable.Ident list * Fable.Expr) list) treeExpr = + let transformDecisionTreeWithTwoSwitches + (com: IPythonCompiler) + ctx + returnStrategy + (targets: (Fable.Ident list * Fable.Expr) list) + treeExpr + = // Declare target and bound idents - let targetId = getUniqueNameInDeclarationScope ctx "pattern_matching_result" |> makeIdent + let targetId = + getUniqueNameInDeclarationScope ctx "pattern_matching_result" + |> makeIdent + let multiVarDecl = let boundIdents = - targets |> List.collect (fun (idents,_) -> - idents) |> List.map (fun id -> ident com ctx id, None) - multiVarDeclaration ctx ((ident com ctx targetId,None)::boundIdents) + targets + |> List.collect (fun (idents, _) -> idents) + |> List.map (fun id -> ident com ctx id, None) + + multiVarDeclaration ctx ((ident com ctx targetId, None) :: boundIdents) // Transform targets as switch let switch2 = // TODO: Declare the last case as the default case? - let cases = targets |> List.mapi (fun i (_,target) -> [makeIntConst i], target) + let cases = + targets + |> List.mapi (fun i (_, target) -> [ makeIntConst i ], target) + transformSwitch com ctx true returnStrategy (targetId |> Fable.IdentExpr) cases None // Transform decision tree let targetAssign = Target(ident com ctx targetId) let ctx = { ctx with DecisionTargets = targets } + match transformDecisionTreeAsSwitch treeExpr with - | Some(evalExpr, cases, (defaultIndex, defaultBoundValues)) -> - let cases = groupSwitchCases (Fable.Number(Int32, None)) cases (defaultIndex, defaultBoundValues) - let defaultCase = Fable.DecisionTreeSuccess(defaultIndex, defaultBoundValues, Fable.Number(Int32, None)) - let switch1 = transformSwitch com ctx false (Some targetAssign) evalExpr cases (Some defaultCase) + | Some (evalExpr, cases, (defaultIndex, defaultBoundValues)) -> + let cases = + groupSwitchCases (Fable.Number(Int32, None)) cases (defaultIndex, defaultBoundValues) + + let defaultCase = + Fable.DecisionTreeSuccess(defaultIndex, defaultBoundValues, Fable.Number(Int32, None)) + + let switch1 = + transformSwitch com ctx false (Some targetAssign) evalExpr cases (Some defaultCase) + multiVarDecl @ switch1 @ switch2 | None -> - let decisionTree = com.TransformAsStatements(ctx, Some targetAssign, treeExpr) + let decisionTree = + com.TransformAsStatements(ctx, Some targetAssign, treeExpr) + multiVarDecl @ decisionTree @ switch2 - let transformDecisionTreeAsStatements (com: IPythonCompiler) (ctx: Context) returnStrategy - (targets: (Fable.Ident list * Fable.Expr) list) (treeExpr: Fable.Expr): Statement list = + let transformDecisionTreeAsStatements + (com: IPythonCompiler) + (ctx: Context) + returnStrategy + (targets: (Fable.Ident list * Fable.Expr) list) + (treeExpr: Fable.Expr) + : Statement list = // If some targets are referenced multiple times, hoist bound idents, // resolve the decision index and compile the targets as a switch let targetsWithMultiRefs = - if com.Options.Language = TypeScript then [] // no hoisting when compiled with types - else getTargetsWithMultipleReferences treeExpr + if com.Options.Language = TypeScript then + [] // no hoisting when compiled with types + else + getTargetsWithMultipleReferences treeExpr + match targetsWithMultiRefs with | [] -> let ctx = { ctx with DecisionTargets = targets } + match transformDecisionTreeAsSwitch treeExpr with - | Some(evalExpr, cases, (defaultIndex, defaultBoundValues)) -> + | Some (evalExpr, cases, (defaultIndex, defaultBoundValues)) -> let t = treeExpr.Type - let cases = cases |> List.map (fun (caseExpr, targetIndex, boundValues) -> - [caseExpr], Fable.DecisionTreeSuccess(targetIndex, boundValues, t)) - let defaultCase = Fable.DecisionTreeSuccess(defaultIndex, defaultBoundValues, t) + + let cases = + cases + |> List.map (fun (caseExpr, targetIndex, boundValues) -> + [ caseExpr ], Fable.DecisionTreeSuccess(targetIndex, boundValues, t)) + + let defaultCase = + Fable.DecisionTreeSuccess(defaultIndex, defaultBoundValues, t) + transformSwitch com ctx true returnStrategy evalExpr cases (Some defaultCase) - | None -> - com.TransformAsStatements(ctx, returnStrategy, treeExpr) + | None -> com.TransformAsStatements(ctx, returnStrategy, treeExpr) | targetsWithMultiRefs -> // If the bound idents are not referenced in the target, remove them let targets = - targets |> List.map (fun (idents, expr) -> + targets + |> List.map (fun (idents, expr) -> idents |> List.exists (fun i -> FableTransforms.isIdentUsed i.Name expr) |> function | true -> idents, expr | false -> [], expr) + let hasAnyTargetWithMultiRefsBoundValues = - targetsWithMultiRefs |> List.exists (fun idx -> - targets.[idx] |> fst |> List.isEmpty |> not) + targetsWithMultiRefs + |> List.exists (fun idx -> targets.[idx] |> fst |> List.isEmpty |> not) + if not hasAnyTargetWithMultiRefsBoundValues then match transformDecisionTreeAsSwitch treeExpr with - | Some(evalExpr, cases, (defaultIndex, defaultBoundValues)) -> + | Some (evalExpr, cases, (defaultIndex, defaultBoundValues)) -> let t = treeExpr.Type - let cases = groupSwitchCases t cases (defaultIndex, defaultBoundValues) + + let cases = + groupSwitchCases t cases (defaultIndex, defaultBoundValues) + let ctx = { ctx with DecisionTargets = targets } - let defaultCase = Fable.DecisionTreeSuccess(defaultIndex, defaultBoundValues, t) + + let defaultCase = + Fable.DecisionTreeSuccess(defaultIndex, defaultBoundValues, t) + transformSwitch com ctx true returnStrategy evalExpr cases (Some defaultCase) - | None -> - transformDecisionTreeWithTwoSwitches com ctx returnStrategy targets treeExpr + | None -> transformDecisionTreeWithTwoSwitches com ctx returnStrategy targets treeExpr else transformDecisionTreeWithTwoSwitches com ctx returnStrategy targets treeExpr let transformSequenceExpr (com: IPythonCompiler) ctx (exprs: Fable.Expr list) : Expression * Statement list = // printfn "transformSequenceExpr1" let ctx = { ctx with BoundVars = ctx.BoundVars.EnterScope() } + let body = exprs - |> List.collecti - (fun i e -> - let expr, stmts = com.TransformAsExpr(ctx, e) - // Return the last expression - if i = exprs.Length - 1 then - stmts @ [ Statement.return' (expr)] - else - stmts @ exprAsStatement ctx expr) - |> transformBody com ctx None + |> List.collecti (fun i e -> + let expr, stmts = com.TransformAsExpr(ctx, e) + // Return the last expression + if i = exprs.Length - 1 then + stmts @ [ Statement.return' (expr) ] + else + stmts @ exprAsStatement ctx expr) + |> transformBody com ctx None let name = Helpers.getUniqueIdentifier "expr" - let func = Statement.functionDef(name = name, args = Arguments.arguments [], body = body) - let name = Expression.name(name) - Expression.call(name), [ func ] + let func = + Statement.functionDef (name = name, args = Arguments.arguments [], body = body) + + let name = Expression.name (name) + Expression.call (name), [ func ] let transformSequenceExpr' (com: IPythonCompiler) ctx (exprs: Expression list) (stmts: Statement list) : Expression * Statement list = // printfn "transformSequenceExpr2', exprs: %A" exprs.Length @@ -2341,129 +2912,140 @@ module Util = let body = exprs - |> List.collecti - (fun i expr -> - // Return the last expression - if i = exprs.Length - 1 then - stmts @ [ Statement.return' (expr) ] - else - exprAsStatement ctx expr) + |> List.collecti (fun i expr -> + // Return the last expression + if i = exprs.Length - 1 then + stmts @ [ Statement.return' (expr) ] + else + exprAsStatement ctx expr) let name = Helpers.getUniqueIdentifier "expr" - let func = Statement.functionDef(name = name, args = Arguments.arguments [], body = body) + + let func = + Statement.functionDef (name = name, args = Arguments.arguments [], body = body) let name = Expression.name (name) Expression.call (name), [ func ] - let rec transformAsExpr (com: IPythonCompiler) ctx (expr: Fable.Expr): Expression * Statement list = + let rec transformAsExpr (com: IPythonCompiler) ctx (expr: Fable.Expr) : Expression * Statement list = // printfn "transformAsExpr: %A" expr match expr with | Fable.Unresolved e -> addErrorAndReturnNull com e.Range "Unexpected unresolved expression", [] - | Fable.TypeCast(e,t) -> transformCast com ctx t e + | Fable.TypeCast (e, t) -> transformCast com ctx t e - | Fable.Value(kind, r) -> transformValue com ctx r kind + | Fable.Value (kind, r) -> transformValue com ctx r kind | Fable.IdentExpr id -> identAsExpr com ctx id, [] - | Fable.Import({ Selector = selector; Path = path; Kind=kind }, _, r) -> + | Fable.Import ({ Selector = selector + Path = path + Kind = kind }, + _, + r) -> // printfn "Fable.Import: %A" (selector, path) transformImport com ctx r selector path, [] - | Fable.Test(expr, kind, range) -> - transformTest com ctx range kind expr + | Fable.Test (expr, kind, range) -> transformTest com ctx range kind expr - | Fable.Lambda(arg, body, name) -> - transformFunctionWithAnnotations com ctx name [arg] body + | Fable.Lambda (arg, body, name) -> + transformFunctionWithAnnotations com ctx name [ arg ] body |||> makeArrowFunctionExpression com ctx name - | Fable.Delegate(args, body, name) -> + | Fable.Delegate (args, body, name) -> transformFunctionWithAnnotations com ctx name args body |||> makeArrowFunctionExpression com ctx name - | Fable.ObjectExpr ([], _typ, None) -> - Expression.none, [] + | Fable.ObjectExpr ([], _typ, None) -> Expression.none, [] | Fable.ObjectExpr (members, typ, baseCall) -> // printfn "members: %A" (members, typ) transformObjectExpr com ctx members typ baseCall - | Fable.Call(Fable.Get(expr, Fable.FieldGet(fieldName="has"), _, _), info, _, range) -> + | Fable.Call (Fable.Get (expr, Fable.FieldGet(fieldName = "has"), _, _), info, _, range) -> let left, stmts = com.TransformAsExpr(ctx, info.Args.Head) let value, stmts' = com.TransformAsExpr(ctx, expr) - Expression.compare (left, [ComparisonOperator.In], [value]), stmts @ stmts' + Expression.compare (left, [ ComparisonOperator.In ], [ value ]), stmts @ stmts' - | Fable.Call(Fable.Get(expr, Fable.FieldGet(fieldName="slice"), _, _), info, _, range) -> + | Fable.Call (Fable.Get (expr, Fable.FieldGet(fieldName = "slice"), _, _), info, _, range) -> let left, stmts = com.TransformAsExpr(ctx, expr) - let args, stmts' = info.Args |> List.map (fun arg -> com.TransformAsExpr(ctx, arg)) |> List.unzip |> (fun (e, s) -> (e, List.collect id s)) + + let args, stmts' = + info.Args + |> List.map (fun arg -> com.TransformAsExpr(ctx, arg)) + |> List.unzip + |> (fun (e, s) -> (e, List.collect id s)) + let slice = match args with - | [] -> Expression.slice() - | [ lower ] -> Expression.slice(lower=lower) - | [ Expression.Name({Id=Identifier("None")}); upper ] -> Expression.slice(upper=upper) - | [ lower; upper ] -> Expression.slice(lower=lower, upper=upper) + | [] -> Expression.slice () + | [ lower ] -> Expression.slice (lower = lower) + | [ Expression.Name ({ Id = Identifier ("None") }); upper ] -> Expression.slice (upper = upper) + | [ lower; upper ] -> Expression.slice (lower = lower, upper = upper) | _ -> failwith $"Array slice with {args.Length} not supported" + Expression.subscript (left, slice), stmts @ stmts' - | Fable.Call(Fable.Get(expr, Fable.FieldGet(fieldName=name), _, _), _info, _, _range) when name.ToLower() = "tostring" -> - let func = Expression.name("str") + | Fable.Call (Fable.Get (expr, Fable.FieldGet (fieldName = name), _, _), _info, _, _range) when name.ToLower() = "tostring" -> + let func = Expression.name ("str") let left, stmts = com.TransformAsExpr(ctx, expr) Expression.call (func, [ left ]), stmts - | Fable.Call(Fable.Get(expr, Fable.FieldGet(fieldName="Equals"), _, _), { Args=[arg]}, _, _range) -> + | Fable.Call (Fable.Get (expr, Fable.FieldGet(fieldName = "Equals"), _, _), { Args = [ arg ] }, _, _range) -> let right, stmts = com.TransformAsExpr(ctx, arg) let left, stmts' = com.TransformAsExpr(ctx, expr) - Expression.compare (left, [Eq], [right]), stmts @ stmts' + Expression.compare (left, [ Eq ], [ right ]), stmts @ stmts' - | Fable.Call(Fable.Get(expr, Fable.FieldGet(fieldName="split"), _, _), { Args=[Fable.Value(kind=Fable.StringConstant(""))]}, _, _range) -> - let func = Expression.name("list") + | Fable.Call (Fable.Get (expr, Fable.FieldGet(fieldName = "split"), _, _), + { Args = [ Fable.Value(kind = Fable.StringConstant ("")) ] }, + _, + _range) -> + let func = Expression.name ("list") let value, stmts = com.TransformAsExpr(ctx, expr) Expression.call (func, [ value ]), stmts - | Fable.Call(Fable.Get(expr, Fable.FieldGet(fieldName="charCodeAt"), _, _), _info, _, _range) -> - let func = Expression.name("ord") + | Fable.Call (Fable.Get (expr, Fable.FieldGet(fieldName = "charCodeAt"), _, _), _info, _, _range) -> + let func = Expression.name ("ord") let value, stmts = com.TransformAsExpr(ctx, expr) Expression.call (func, [ value ]), stmts - | Fable.Call(callee, info, _, range) -> - transformCall com ctx range callee info + | Fable.Call (callee, info, _, range) -> transformCall com ctx range callee info - | Fable.CurriedApply(callee, args, _, range) -> - transformCurriedApply com ctx range callee args + | Fable.CurriedApply (callee, args, _, range) -> transformCurriedApply com ctx range callee args - | Fable.Operation(kind, _, range) -> - transformOperation com ctx range kind + | Fable.Operation (kind, _, range) -> transformOperation com ctx range kind - | Fable.Get(expr, kind, typ, range) -> - transformGet com ctx range typ expr kind + | Fable.Get (expr, kind, typ, range) -> transformGet com ctx range typ expr kind - | Fable.IfThenElse(TransformExpr com ctx (guardExpr, stmts), - TransformExpr com ctx (thenExpr, stmts'), - TransformExpr com ctx (elseExpr, stmts''), _r) -> - Expression.ifExp (guardExpr, thenExpr, elseExpr), stmts @ stmts' @ stmts'' + | Fable.IfThenElse (TransformExpr com ctx (guardExpr, stmts), + TransformExpr com ctx (thenExpr, stmts'), + TransformExpr com ctx (elseExpr, stmts''), + _r) -> Expression.ifExp (guardExpr, thenExpr, elseExpr), stmts @ stmts' @ stmts'' - | Fable.DecisionTree(expr, targets) -> - transformDecisionTreeAsExpr com ctx targets expr + | Fable.DecisionTree (expr, targets) -> transformDecisionTreeAsExpr com ctx targets expr - | Fable.DecisionTreeSuccess(idx, boundValues, _) -> - transformDecisionTreeSuccessAsExpr com ctx idx boundValues + | Fable.DecisionTreeSuccess (idx, boundValues, _) -> transformDecisionTreeSuccessAsExpr com ctx idx boundValues - | Fable.Set(expr, kind, typ, value, range) -> - let expr', stmts = transformSet com ctx range expr typ value kind + | Fable.Set (expr, kind, typ, value, range) -> + let expr', stmts = + transformSet com ctx range expr typ value kind //printfn "Fable.Set: %A" expr match expr' with - | Expression.NamedExpr({ Target = target; Value = _; Loc=_ }) -> + | Expression.NamedExpr ({ Target = target; Value = _; Loc = _ }) -> let nonLocals = match target with - | Expression.Name({Id=id}) -> [ ctx.BoundVars.NonLocals([id]) |> Statement.nonLocal ] + | Expression.Name ({ Id = id }) -> + [ ctx.BoundVars.NonLocals([ id ]) + |> Statement.nonLocal ] | _ -> [] + expr', nonLocals @ stmts | _ -> expr', stmts - | Fable.Let(ident, value, body) -> + | Fable.Let (ident, value, body) -> // printfn "Fable.Let: %A" (ident, value, body) iife com ctx expr - | Fable.LetRec(bindings, body) -> + | Fable.LetRec (bindings, body) -> if ctx.HoistVars(List.map fst bindings) then let values, stmts = bindings @@ -2472,186 +3054,267 @@ module Util = |> (fun (e, s) -> (e, List.collect id s)) let expr, stmts' = com.TransformAsExpr(ctx, body) - let expr, stmts'' = transformSequenceExpr' com ctx (values @ [expr]) [] + + let expr, stmts'' = + transformSequenceExpr' com ctx (values @ [ expr ]) [] + expr, stmts @ stmts' @ stmts'' - else iife com ctx expr + else + iife com ctx expr | Fable.Sequential exprs -> transformSequenceExpr com ctx exprs - | Fable.Emit(info, _, range) -> - if info.IsStatement then iife com ctx expr - else transformEmit com ctx range info + | Fable.Emit (info, _, range) -> + if info.IsStatement then + iife com ctx expr + else + transformEmit com ctx range info // These cannot appear in expression position in JS, must be wrapped in a lambda - | Fable.WhileLoop _ | Fable.ForLoop _ | Fable.TryCatch _ -> - iife com ctx expr - | Fable.Extended(instruction, _) -> + | Fable.WhileLoop _ + | Fable.ForLoop _ + | Fable.TryCatch _ -> iife com ctx expr + | Fable.Extended (instruction, _) -> match instruction with - | Fable.Curry(e, arity) -> transformCurry com ctx e arity - | Fable.Throw _ | Fable.Return _ | Fable.Break _ | Fable.Debugger -> iife com ctx expr + | Fable.Curry (e, arity) -> transformCurry com ctx e arity + | Fable.Throw _ + | Fable.Return _ + | Fable.Break _ + | Fable.Debugger -> iife com ctx expr - let rec transformAsStatements (com: IPythonCompiler) ctx returnStrategy - (expr: Fable.Expr): Statement list = + let rec transformAsStatements (com: IPythonCompiler) ctx returnStrategy (expr: Fable.Expr) : Statement list = match expr with | Fable.Unresolved e -> addError com [] e.Range "Unexpected unresolved expression" [] - | Fable.Extended(kind, _r) -> + | Fable.Extended (kind, _r) -> match kind with - | Fable.Curry(e, arity) -> + | Fable.Curry (e, arity) -> let expr, stmts = transformCurry com ctx e arity - stmts @ (expr |> resolveExpr ctx e.Type returnStrategy) - | Fable.Throw(TransformExpr com ctx (e, stmts), _) -> stmts @ [Statement.raise(e) ] - | Fable.Return(TransformExpr com ctx (e, stmts)) -> stmts @ [ Statement.return'(e)] + + stmts + @ (expr |> resolveExpr ctx e.Type returnStrategy) + | Fable.Throw (TransformExpr com ctx (e, stmts), _) -> stmts @ [ Statement.raise (e) ] + | Fable.Return (TransformExpr com ctx (e, stmts)) -> stmts @ [ Statement.return' (e) ] | Fable.Debugger -> [] - | Fable.Break _ -> [ Statement.break'() ] + | Fable.Break _ -> [ Statement.break' () ] - | Fable.TypeCast(e, t) -> + | Fable.TypeCast (e, t) -> let expr, stmts = transformCast com ctx t e stmts @ (expr |> resolveExpr ctx t returnStrategy) - | Fable.Value(kind, r) -> + | Fable.Value (kind, r) -> let expr, stmts = transformValue com ctx r kind - stmts @ (expr |> resolveExpr ctx kind.Type returnStrategy) - - | Fable.IdentExpr id -> - identAsExpr com ctx id |> resolveExpr ctx id.Type returnStrategy - | Fable.Import({ Selector = selector; Path = path; Kind=kind }, t, r) -> - transformImport com ctx r selector path |> resolveExpr ctx t returnStrategy + stmts + @ (expr |> resolveExpr ctx kind.Type returnStrategy) - | Fable.Test(expr, kind, range) -> + | Fable.IdentExpr id -> + identAsExpr com ctx id + |> resolveExpr ctx id.Type returnStrategy + + | Fable.Import ({ Selector = selector + Path = path + Kind = kind }, + t, + r) -> + transformImport com ctx r selector path + |> resolveExpr ctx t returnStrategy + + | Fable.Test (expr, kind, range) -> let expr, stmts = transformTest com ctx range kind expr - stmts @ (expr |> resolveExpr ctx Fable.Boolean returnStrategy) - | Fable.Lambda(arg, body, name) -> + stmts + @ (expr + |> resolveExpr ctx Fable.Boolean returnStrategy) + + | Fable.Lambda (arg, body, name) -> let expr', stmts = - transformFunctionWithAnnotations com ctx name [arg] body + transformFunctionWithAnnotations com ctx name [ arg ] body |||> makeArrowFunctionExpression com ctx name - stmts @ (expr' |> resolveExpr ctx expr.Type returnStrategy) - | Fable.Delegate(args, body, name) -> + stmts + @ (expr' |> resolveExpr ctx expr.Type returnStrategy) + + | Fable.Delegate (args, body, name) -> let expr', stmts = transformFunctionWithAnnotations com ctx name args body |||> makeArrowFunctionExpression com ctx name - stmts @ (expr' |> resolveExpr ctx expr.Type returnStrategy) + + stmts + @ (expr' |> resolveExpr ctx expr.Type returnStrategy) | Fable.ObjectExpr ([], _, None) -> [] // Remove empty object expression | Fable.ObjectExpr (members, t, baseCall) -> let expr, stmts = transformObjectExpr com ctx members t baseCall stmts @ (expr |> resolveExpr ctx t returnStrategy) - | Fable.Call(callee, info, typ, range) -> - transformCallAsStatements com ctx range typ returnStrategy callee info + | Fable.Call (callee, info, typ, range) -> transformCallAsStatements com ctx range typ returnStrategy callee info - | Fable.CurriedApply(callee, args, typ, range) -> - transformCurriedApplyAsStatements com ctx range typ returnStrategy callee args + | Fable.CurriedApply (callee, args, typ, range) -> transformCurriedApplyAsStatements com ctx range typ returnStrategy callee args - | Fable.Emit(info, t, range) -> + | Fable.Emit (info, t, range) -> let e, stmts = transformEmit com ctx range info + if info.IsStatement then - stmts @ [ Statement.expr(e) ] // Ignore the return strategy - else stmts @ resolveExpr ctx t returnStrategy e + stmts @ [ Statement.expr (e) ] // Ignore the return strategy + else + stmts @ resolveExpr ctx t returnStrategy e - | Fable.Operation(kind, t, range) -> + | Fable.Operation (kind, t, range) -> let expr, stmts = transformOperation com ctx range kind stmts @ (expr |> resolveExpr ctx t returnStrategy) - | Fable.Get(expr, kind, t, range) -> + | Fable.Get (expr, kind, t, range) -> let expr, stmts = transformGet com ctx range t expr kind stmts @ (expr |> resolveExpr ctx t returnStrategy) - | Fable.Let(ident, value, body) -> + | Fable.Let (ident, value, body) -> match ident, value, body with // Transform F# `use` i.e TryCatch as Python `with` - | {Name=valueName}, value, Fable.TryCatch(body, None, Some(Fable.IfThenElse(_, Fable.Call(Fable.Get(Fable.TypeCast(Fable.IdentExpr({Name=disposeName}), _), Fable.FieldGet("Dispose", _), t, _), _, _, _), elseExpr, _)), _) when valueName = disposeName -> + | { Name = valueName }, + value, + Fable.TryCatch (body, + None, + Some (Fable.IfThenElse (_, + Fable.Call (Fable.Get (Fable.TypeCast (Fable.IdentExpr ({ Name = disposeName }), _), + Fable.FieldGet ("Dispose", _), + t, + _), + _, + _, + _), + elseExpr, + _)), + _) when valueName = disposeName -> let id = Identifier valueName - let body = com.TransformAsStatements(ctx, Some ResourceManager, body) + + let body = + com.TransformAsStatements(ctx, Some ResourceManager, body) + let value, stmts = com.TransformAsExpr(ctx, value) - let items = [ WithItem.withItem(value, Expression.name id) ] - stmts @ [ Statement.with'(items, body) ] + let items = [ WithItem.withItem (value, Expression.name id) ] + stmts @ [ Statement.with' (items, body) ] | _ -> let binding = transformBindingAsStatements com ctx ident value List.append binding (transformAsStatements com ctx returnStrategy body) - | Fable.LetRec(bindings, body) -> - let bindings = bindings |> Seq.collect (fun (i, v) -> transformBindingAsStatements com ctx i v) |> Seq.toList + | Fable.LetRec (bindings, body) -> + let bindings = + bindings + |> Seq.collect (fun (i, v) -> transformBindingAsStatements com ctx i v) + |> Seq.toList + List.append bindings (transformAsStatements com ctx returnStrategy body) - | Fable.Set(expr, kind, typ, value, range) -> - let expr', stmts = transformSet com ctx range expr typ value kind + | Fable.Set (expr, kind, typ, value, range) -> + let expr', stmts = + transformSet com ctx range expr typ value kind // printfn "Fable.Set: %A" (expr', value) match expr' with - | Expression.NamedExpr({ Target = target; Value = value; Loc=_ }) -> + | Expression.NamedExpr ({ Target = target + Value = value + Loc = _ }) -> let nonLocals = match target with - | Expression.Name({Id=id}) -> [ ctx.BoundVars.NonLocals([id]) |> Statement.nonLocal ] + | Expression.Name ({ Id = id }) -> + [ ctx.BoundVars.NonLocals([ id ]) + |> Statement.nonLocal ] | _ -> [] - nonLocals @ stmts @ [ Statement.assign([target], value) ] - | _ -> stmts @ (expr' |> resolveExpr ctx expr.Type returnStrategy) - | Fable.IfThenElse(guardExpr, thenExpr, elseExpr, r) -> + nonLocals + @ stmts @ [ Statement.assign ([ target ], value) ] + | _ -> + stmts + @ (expr' |> resolveExpr ctx expr.Type returnStrategy) + + | Fable.IfThenElse (guardExpr, thenExpr, elseExpr, r) -> let asStatement = match returnStrategy with - | None | Some ReturnUnit -> true - | Some(Target _) -> true // Compile as statement so values can be bound - | Some(Assign _) -> (isPyStatement ctx false thenExpr) || (isPyStatement ctx false elseExpr) + | None + | Some ReturnUnit -> true + | Some (Target _) -> true // Compile as statement so values can be bound + | Some (Assign _) -> + (isPyStatement ctx false thenExpr) + || (isPyStatement ctx false elseExpr) | Some ResourceManager | Some Return -> Option.isSome ctx.TailCallOpportunity - || (isPyStatement ctx false thenExpr) || (isPyStatement ctx false elseExpr) + || (isPyStatement ctx false thenExpr) + || (isPyStatement ctx false elseExpr) + if asStatement then transformIfStatement com ctx r returnStrategy guardExpr thenExpr elseExpr else let guardExpr', stmts = transformAsExpr com ctx guardExpr let thenExpr', stmts' = transformAsExpr com ctx thenExpr let elseExpr', stmts'' = transformAsExpr com ctx elseExpr + stmts @ stmts' - @ stmts'' - @ (Expression.ifExp(guardExpr', thenExpr', elseExpr', ?loc=r) |> resolveExpr ctx thenExpr.Type returnStrategy) + @ stmts'' + @ (Expression.ifExp (guardExpr', thenExpr', elseExpr', ?loc = r) + |> resolveExpr ctx thenExpr.Type returnStrategy) | Fable.Sequential statements -> let lasti = (List.length statements) - 1 - statements |> List.mapiToArray (fun i statement -> - let ret = if i < lasti then None else returnStrategy + + statements + |> List.mapiToArray (fun i statement -> + let ret = + if i < lasti then + None + else + returnStrategy + com.TransformAsStatements(ctx, ret, statement)) |> List.concat - | Fable.TryCatch (body, catch, finalizer, r) -> - transformTryCatch com ctx r returnStrategy (body, catch, finalizer) + | Fable.TryCatch (body, catch, finalizer, r) -> transformTryCatch com ctx r returnStrategy (body, catch, finalizer) - | Fable.DecisionTree(expr, targets) -> - transformDecisionTreeAsStatements com ctx returnStrategy targets expr + | Fable.DecisionTree (expr, targets) -> transformDecisionTreeAsStatements com ctx returnStrategy targets expr - | Fable.DecisionTreeSuccess(idx, boundValues, _) -> - transformDecisionTreeSuccessAsStatements com ctx returnStrategy idx boundValues + | Fable.DecisionTreeSuccess (idx, boundValues, _) -> transformDecisionTreeSuccessAsStatements com ctx returnStrategy idx boundValues - | Fable.WhileLoop(TransformExpr com ctx (guard, stmts), body, label, range) -> - stmts @ [ Statement.while'(guard, transformBlock com ctx None body, ?loc=range) ] + | Fable.WhileLoop (TransformExpr com ctx (guard, stmts), body, label, range) -> + stmts + @ [ Statement.while' (guard, transformBlock com ctx None body, ?loc = range) ] | Fable.ForLoop (var, TransformExpr com ctx (start, stmts), TransformExpr com ctx (limit, stmts'), body, isUp, range) -> let limit, step = - if isUp - then - let limit = Expression.binOp (limit, Add, Expression.constant (1)) // Python `range` has exclusive end. - limit, 1 + if isUp then + let limit = + Expression.binOp (limit, Add, Expression.constant (1)) // Python `range` has exclusive end. + + limit, 1 else - let limit = Expression.binOp (limit, Sub, Expression.constant (1)) // Python `range` has exclusive end. + let limit = + Expression.binOp (limit, Sub, Expression.constant (1)) // Python `range` has exclusive end. + limit, -1 - let step = Expression.constant(step) - let iter = Expression.call (Expression.name (Identifier "range"), args = [ start; limit; step ]) + let step = Expression.constant (step) + + let iter = + Expression.call (Expression.name (Identifier "range"), args = [ start; limit; step ]) + let body = transformBlock com ctx None body let target = com.GetIdentifierAsExpr(ctx, var.Name) - [ Statement.for'(target = target, iter = iter, body = body) ] + [ Statement.for' (target = target, iter = iter, body = body) ] - let transformFunction com ctx name (args: Fable.Ident list) (body: Fable.Expr) (repeatedGenerics: Set): Arguments * Statement list = + let transformFunction + com + ctx + name + (args: Fable.Ident list) + (body: Fable.Expr) + (repeatedGenerics: Set) + : Arguments * Statement list = let tailcallChance = - Option.map (fun name -> - NamedTailCallOpportunity(com, ctx, name, args) :> ITailCallOpportunity) name + Option.map (fun name -> NamedTailCallOpportunity(com, ctx, name, args) :> ITailCallOpportunity) name + let args = discardUnitArg args // For Python we need to append the TC-arguments to any declared (arrow) function inside the while-loop of the @@ -2662,18 +3325,23 @@ module Util = tc.Args |> List.map (fun arg -> let (Identifier name) = arg.Arg - let name = name.Substring(0, name.Length-4) - Arg.arg(name, ?annotation=arg.Annotation), Expression.name(name)) + let name = name.Substring(0, name.Length - 4) + Arg.arg (name, ?annotation = arg.Annotation), Expression.name (name)) |> List.unzip | _ -> [], [] let declaredVars = ResizeArray() let mutable isTailCallOptimized = false + let ctx = - { ctx with TailCallOpportunity = tailcallChance - HoistVars = fun ids -> declaredVars.AddRange(ids); true - OptimizeTailCall = fun () -> isTailCallOptimized <- true - BoundVars = ctx.BoundVars.EnterScope() } + { ctx with + TailCallOpportunity = tailcallChance + HoistVars = + fun ids -> + declaredVars.AddRange(ids) + true + OptimizeTailCall = fun () -> isTailCallOptimized <- true + BoundVars = ctx.BoundVars.EnterScope() } // printfn "Args: %A" args let body = @@ -2682,12 +3350,13 @@ module Util = elif isPyStatement ctx (Option.isSome tailcallChance) body then transformBlock com ctx (Some Return) body else - transformAsExpr com ctx body |> wrapExprInBlockWithReturn + transformAsExpr com ctx body + |> wrapExprInBlockWithReturn let isUnit = List.tryLast args |> Option.map (function - | { Type=Fable.GenericParam _ } -> true + | { Type = Fable.GenericParam _ } -> true | _ -> false) |> Option.defaultValue false @@ -2697,19 +3366,26 @@ module Util = // Replace args, see NamedTailCallOpportunity constructor let args' = List.zip args tc.Args - |> List.map (fun (_id, {Arg=Identifier tcArg}) -> + |> List.map (fun (_id, { Arg = Identifier tcArg }) -> let id = com.GetIdentifier(ctx, tcArg) - let ta, _ = typeAnnotation com ctx (Some repeatedGenerics) _id.Type - Arg.arg(id, annotation=ta)) + + let ta, _ = + typeAnnotation com ctx (Some repeatedGenerics) _id.Type + + Arg.arg (id, annotation = ta)) + let varDecls = List.zip args tc.Args - |> List.map (fun (id, {Arg=Identifier tcArg}) -> ident com ctx id, Some (com.GetIdentifierAsExpr(ctx, tcArg))) + |> List.map (fun (id, { Arg = Identifier tcArg }) -> ident com ctx id, Some(com.GetIdentifierAsExpr(ctx, tcArg))) |> multiVarDeclaration ctx let body = varDecls @ body // Make sure we don't get trapped in an infinite loop, see #1624 - let body = body @ [ Statement.break'() ] - args', [], Statement.while'(Expression.constant(true), body) + let body = body @ [ Statement.break' () ] + + args', + [], + Statement.while' (Expression.constant (true), body) |> List.singleton | _ -> // Make sure all of the last optional arguments will accept None as their default value @@ -2720,20 +3396,24 @@ module Util = match arg.Type with | Fable.Option _ -> true | _ -> false) - |> List.map(fun _ -> Expression.none) + |> List.map (fun _ -> Expression.none) + let args' = args |> List.map (fun id -> - let ta, _ = typeAnnotation com ctx (Some repeatedGenerics) id.Type - Arg.arg(ident com ctx id, annotation=ta)) + let ta, _ = + typeAnnotation com ctx (Some repeatedGenerics) id.Type + + Arg.arg (ident com ctx id, annotation = ta)) + args', defaults, body let arguments = match args, isUnit with - | [], true -> Arguments.arguments(args=Arg.arg(Identifier("__unit"))::tcArgs, defaults=Expression.none::tcDefaults) + | [], true -> Arguments.arguments (args = Arg.arg (Identifier("__unit")) :: tcArgs, defaults = Expression.none :: tcDefaults) // So we can also receive unit - | _, true -> Arguments.arguments(args @ tcArgs, defaults=Expression.none::tcDefaults) - | _ -> Arguments.arguments(args @ tcArgs, defaults=defaults @ tcDefaults) + | _, true -> Arguments.arguments (args @ tcArgs, defaults = Expression.none :: tcDefaults) + | _ -> Arguments.arguments (args @ tcArgs, defaults = defaults @ tcDefaults) arguments, body @@ -2741,16 +3421,24 @@ module Util = let declareEntryPoint (com: IPythonCompiler) (ctx: Context) (funcExpr: Expression) = com.GetImportExpr(ctx, "sys") |> ignore let args = emitExpression None "sys.argv[1:]" [] - let test = Expression.compare(Expression.name("__name__"), [ ComparisonOperator.Eq ], [Expression.constant("__main__")]) - let main = Expression.call(funcExpr, [ args ]) |> Statement.expr |> List.singleton - Statement.if'(test, main) + + let test = + Expression.compare (Expression.name ("__name__"), [ ComparisonOperator.Eq ], [ Expression.constant ("__main__") ]) + + let main = + Expression.call (funcExpr, [ args ]) + |> Statement.expr + |> List.singleton + + Statement.if' (test, main) let declareModuleMember ctx isPublic (membName: Identifier) typ (expr: Expression) = - let membName = Expression.name(membName) + let membName = Expression.name (membName) varDeclaration ctx membName typ expr let makeEntityTypeParamDecl (com: IPythonCompiler) ctx (ent: Fable.Entity) = - getEntityGenParams ent |> makeTypeParamDecl com ctx + getEntityGenParams ent + |> makeTypeParamDecl com ctx let getUnionFieldsAsIdents (_com: IPythonCompiler) _ctx (_ent: Fable.Entity) = let tagId = makeTypedIdent (Fable.Number(Int32, None)) "tag" @@ -2760,9 +3448,15 @@ module Util = let getEntityFieldsAsIdents _com (ent: Fable.Entity) = ent.FSharpFields |> Seq.map (fun field -> - let name = (Naming.toSnakeCase field.Name, Naming.NoMemberPart) ||> Naming.sanitizeIdent Naming.pyBuiltins.Contains + let name = + (Naming.toSnakeCase field.Name, Naming.NoMemberPart) + ||> Naming.sanitizeIdent Naming.pyBuiltins.Contains + let typ = field.FieldType - let id: Fable.Ident = { makeTypedIdent typ name with IsMutable = field.IsMutable } + + let id: Fable.Ident = + { makeTypedIdent typ name with IsMutable = field.IsMutable } + id) |> Seq.toArray @@ -2777,19 +3471,39 @@ module Util = prop) |> Seq.toArray - let declareClassType (com: IPythonCompiler) ctx (ent: Fable.Entity) entName (consArgs: Arguments) (isOptional: bool) (consBody: Statement list) (baseExpr: Expression option) classMembers slotMembers = + let declareClassType + (com: IPythonCompiler) + ctx + (ent: Fable.Entity) + entName + (consArgs: Arguments) + (isOptional: bool) + (consBody: Statement list) + (baseExpr: Expression option) + classMembers + slotMembers + = // printfn "declareClassType: %A" consBody let generics = makeEntityTypeParamDecl com ctx ent - let classCons = makeClassConstructor consArgs isOptional consBody - let classFields = slotMembers // TODO: annotations + + let classCons = + makeClassConstructor consArgs isOptional consBody + + let classFields = slotMembers // TODO: annotations let classMembers = classCons @ classMembers //printfn "ClassMembers: %A" classMembers let classBody = let body = [ yield! classFields; yield! classMembers ] + match body with | [] -> [ Pass ] | _ -> body - let interfaces = ent.AllInterfaces |> List.ofSeq |> List.map (fun int -> int.Entity.FullName) + + let interfaces = + ent.AllInterfaces + |> List.ofSeq + |> List.map (fun int -> int.Entity.FullName) + let bases = baseExpr |> Option.toList @@ -2798,42 +3512,80 @@ module Util = // Add IDisposable as ABC. | xs when List.contains "System.IDisposable" xs -> let iDisposable = libValue com ctx "util" "IDisposable" - iDisposable::bases + iDisposable :: bases | _ -> bases) let name = com.GetIdentifier(ctx, entName) - Statement.classDef(name, body = classBody, bases = bases @ generics) + Statement.classDef (name, body = classBody, bases = bases @ generics) let createSlotsForRecordType (com: IPythonCompiler) ctx (classEnt: Fable.Entity) = - let strFromIdent (ident: Identifier ) = ident.Name + let strFromIdent (ident: Identifier) = ident.Name + if classEnt.IsValueType then let elements = getEntityFieldsAsProps com ctx classEnt - |> Array.map (nameFromKey com ctx >> strFromIdent >> Expression.string) + |> Array.map ( + nameFromKey com ctx + >> strFromIdent + >> Expression.string + ) |> Array.toList - let slots = Expression.list(elements, Load) - [ Statement.assign([Expression.name("__slots__", Store)], slots) ] - else [ ] - let declareType (com: IPythonCompiler) ctx (ent: Fable.Entity) entName (consArgs: Arguments) (isOptional: bool) (consBody: Statement list) baseExpr classMembers : Statement list = + let slots = Expression.list (elements, Load) + [ Statement.assign ([ Expression.name ("__slots__", Store) ], slots) ] + else + [] + + let declareType + (com: IPythonCompiler) + ctx + (ent: Fable.Entity) + entName + (consArgs: Arguments) + (isOptional: bool) + (consBody: Statement list) + baseExpr + classMembers + : Statement list = let slotMembers = createSlotsForRecordType com ctx ent - let typeDeclaration = declareClassType com ctx ent entName consArgs isOptional consBody baseExpr classMembers slotMembers + + let typeDeclaration = + declareClassType com ctx ent entName consArgs isOptional consBody baseExpr classMembers slotMembers + let reflectionDeclaration, stmts = - let ta = fableModuleAnnotation com ctx "Reflection" "TypeInfo" [] - let genArgs = Array.init ent.GenericParameters.Length (fun i -> "gen" + string i |> makeIdent) - let args = genArgs |> Array.mapToList (fun id -> Arg.arg(ident com ctx id, annotation=ta)) - let args = Arguments.arguments(args) + let ta = + fableModuleAnnotation com ctx "Reflection" "TypeInfo" [] + + let genArgs = + Array.init ent.GenericParameters.Length (fun i -> "gen" + string i |> makeIdent) + + let args = + genArgs + |> Array.mapToList (fun id -> Arg.arg (ident com ctx id, annotation = ta)) + + let args = Arguments.arguments (args) let generics = genArgs |> Array.mapToList (identAsExpr com ctx) - let body, stmts = transformReflectionInfo com ctx None ent generics + + let body, stmts = + transformReflectionInfo com ctx None ent generics // https://github.com/fable-compiler/Fable.Python/issues/42 - let decoratorList = [ com.GetImportExpr(ctx, "functools", "lru_cache") ] - let expr, stmts' = makeFunctionExpression com ctx None (args, body, decoratorList, ta) - let name = com.GetIdentifier(ctx, entName + Naming.reflectionSuffix) - expr |> declareModuleMember ctx ent.IsPublic name None, stmts @ stmts' + let decoratorList = + [ com.GetImportExpr(ctx, "functools", "lru_cache") ] + + let expr, stmts' = + makeFunctionExpression com ctx None (args, body, decoratorList, ta) + + let name = + com.GetIdentifier(ctx, entName + Naming.reflectionSuffix) + + expr + |> declareModuleMember ctx ent.IsPublic name None, + stmts @ stmts' - stmts @ [typeDeclaration ] @ reflectionDeclaration + stmts + @ [ typeDeclaration ] @ reflectionDeclaration let transformModuleFunction (com: IPythonCompiler) ctx (info: Fable.MemberInfo) (membName: string) args body = let args, body', returnType = @@ -2841,13 +3593,17 @@ module Util = // printfn "transformModuleFunction %A" (membName, args) let name = com.GetIdentifier(ctx, membName) - let stmt = Statement.functionDef(name = name, args = args, body = body', returns=returnType) + + let stmt = + Statement.functionDef (name = name, args = args, body = body', returns = returnType) + let expr = Expression.name name + info.Attributes |> Seq.exists (fun att -> att.Entity.FullName = Atts.entryPoint) |> function - | true -> [ stmt; declareEntryPoint com ctx expr ] - | false -> [ stmt ] //; declareModuleMember info.IsPublic membName false expr ] + | true -> [ stmt; declareEntryPoint com ctx expr ] + | false -> [ stmt ] //; declareModuleMember info.IsPublic membName false expr ] let transformAction (com: IPythonCompiler) ctx expr = let statements = transformAsStatements com ctx None expr @@ -2863,10 +3619,10 @@ module Util = let nameFromKey (com: IPythonCompiler) (ctx: Context) key = match key with - | Expression.Name({Id=ident}) -> ident - | Expression.Constant(value=value) -> + | Expression.Name ({ Id = ident }) -> ident + | Expression.Constant (value = value) -> match value with - | :? string as name -> com.GetIdentifier(ctx, name) + | :? string as name -> com.GetIdentifier(ctx, name) | _ -> failwith $"Not a valid value: {value}" | name -> failwith $"Not a valid name: {name}" @@ -2874,15 +3630,17 @@ module Util = let isStatic = not memb.Info.IsInstance let isGetter = memb.Info.IsGetter - let decorators = [ - if isStatic then - Expression.name("staticmethod") - elif isGetter then - Expression.name("property") - else - Expression.name($"{memb.Name}.setter") ] + let decorators = + [ if isStatic then + Expression.name ("staticmethod") + elif isGetter then + Expression.name ("property") + else + Expression.name ($"{memb.Name}.setter") ] + let args, body, returnType = getMemberArgsAndBody com ctx (Attached isStatic) false memb.Args memb.Body + let key = memberFromName com ctx memb.Name |> nameFromKey com ctx @@ -2891,82 +3649,97 @@ module Util = if isStatic then args else - let self = Arg.arg("self") - { args with Args = self::args.Args } + let self = Arg.arg ("self") + { args with Args = self :: args.Args } // Python do not support static getters. if isStatic && isGetter then match body with - | [Statement.Return({Value=Some x})] -> + | [ Statement.Return ({ Value = Some x }) ] -> let ta, stmts = typeAnnotation com ctx None memb.Body.Type - stmts @ [ Statement.assign(Expression.name(key), ta, x) ] + + stmts + @ [ Statement.assign (Expression.name (key), ta, x) ] | _ -> failwith "Statements not supported for static class properties" else - Statement.functionDef(key, arguments, body = body, decoratorList=decorators, returns=returnType) + Statement.functionDef (key, arguments, body = body, decoratorList = decorators, returns = returnType) |> List.singleton let transformAttachedMethod (com: IPythonCompiler) ctx (memb: Fable.MemberDecl) = // printfn "transformAttachedMethod: %A" memb let isStatic = not memb.Info.IsInstance + let decorators = if isStatic then - [Expression.name("staticmethod")] + [ Expression.name ("staticmethod") ] else [] + let makeMethod name args body decorators returnType = let key = memberFromName com ctx name |> nameFromKey com ctx - Statement.functionDef(key, args, body = body, decoratorList=decorators, returns=returnType) + Statement.functionDef (key, args, body = body, decoratorList = decorators, returns = returnType) + let args, body, returnType = getMemberArgsAndBody com ctx (Attached isStatic) memb.Info.HasSpread memb.Args memb.Body - let self = Arg.arg("self") + + let self = Arg.arg ("self") + let arguments = if isStatic then args else - { args with Args = self::args.Args } - [ - yield makeMethod memb.Name arguments body decorators returnType - if memb.Info.IsEnumerator then - yield makeMethod "__iter__" (Arguments.arguments([self])) (enumerator2iterator com ctx) decorators returnType - ] + { args with Args = self :: args.Args } + + [ yield makeMethod memb.Name arguments body decorators returnType + if memb.Info.IsEnumerator then + yield makeMethod "__iter__" (Arguments.arguments ([ self ])) (enumerator2iterator com ctx) decorators returnType ] let transformUnion (com: IPythonCompiler) ctx (ent: Fable.Entity) (entName: string) classMembers = let fieldIds = getUnionFieldsAsIdents com ctx ent + let args, isOptional = let args = fieldIds.[0] |> ident com ctx |> (fun id -> let ta, _ = typeAnnotation com ctx None fieldIds.[0].Type - Arg.arg(id, annotation=ta)) + Arg.arg (id, annotation = ta)) |> List.singleton + let varargs = fieldIds.[1] |> ident com ctx |> (fun id -> - let gen = getGenericTypeParams [fieldIds.[1].Type] |> Set.toList |> List.tryHead + let gen = + getGenericTypeParams [ fieldIds.[1].Type ] + |> Set.toList + |> List.tryHead + let ta = Expression.name (gen |> Option.defaultValue "Any") - Arg.arg(id, annotation=ta)) + Arg.arg (id, annotation = ta)) + let isOptional = Helpers.isOptional fieldIds - Arguments.arguments(args=args, vararg=varargs), isOptional + Arguments.arguments (args = args, vararg = varargs), isOptional let body = - [ - yield callSuperAsStatement [] - yield! fieldIds |> Array.map (fun id -> - let left = get com ctx None thisExpr id.Name false - let right = - match id.Type with - | Fable.Number _ -> - Expression.boolOp(BoolOperator.Or, [identAsExpr com ctx id; Expression.constant(0)]) - | Fable.Array _ -> - // Convert varArg from tuple to list. TODO: we might need to do this other places as well. - Expression.call(Expression.name("list"), [identAsExpr com ctx id]) - | _ -> identAsExpr com ctx id - let ta,_ = typeAnnotation com ctx None id.Type - Statement.assign(left, ta, right)) - ] + [ yield callSuperAsStatement [] + yield! + fieldIds + |> Array.map (fun id -> + let left = get com ctx None thisExpr id.Name false + + let right = + match id.Type with + | Fable.Number _ -> Expression.boolOp (BoolOperator.Or, [ identAsExpr com ctx id; Expression.constant (0) ]) + | Fable.Array _ -> + // Convert varArg from tuple to list. TODO: we might need to do this other places as well. + Expression.call (Expression.name ("list"), [ identAsExpr com ctx id ]) + | _ -> identAsExpr com ctx id + + let ta, _ = typeAnnotation com ctx None id.Type + Statement.assign (left, ta, right)) ] + let cases = let expr, stmts = ent.UnionCases @@ -2975,11 +3748,14 @@ module Util = |> makeList com ctx let name = Identifier("cases") - let body = stmts @ [ Statement.return'(expr) ] - let decorators = [ Expression.name("staticmethod") ] + let body = stmts @ [ Statement.return' (expr) ] + let decorators = [ Expression.name ("staticmethod") ] let value = com.GetImportExpr(ctx, "typing", "List") - let returnType = Expression.subscript(value, Expression.name("str")) - Statement.functionDef(name, Arguments.arguments(), body = body, returns=returnType, decoratorList=decorators) + + let returnType = + Expression.subscript (value, Expression.name ("str")) + + Statement.functionDef (name, Arguments.arguments (), body = body, returns = returnType, decoratorList = decorators) let baseExpr = libValue com ctx "Types" "Union" |> Some let classMembers = List.append [ cases ] classMembers @@ -2988,50 +3764,80 @@ module Util = let transformClassWithCompilerGeneratedConstructor (com: IPythonCompiler) ctx (ent: Fable.Entity) (entName: string) classMembers = // printfn "transformClassWithCompilerGeneratedConstructor" let fieldIds = getEntityFieldsAsIdents com ent - let args = fieldIds |> Array.map (fun id -> com.GetIdentifier(ctx, id.Name) |> Expression.name) - let isOptional = Helpers.isOptional fieldIds || ent.IsFSharpRecord || ent.IsValueType + + let args = + fieldIds + |> Array.map (fun id -> com.GetIdentifier(ctx, id.Name) |> Expression.name) + + let isOptional = + Helpers.isOptional fieldIds + || ent.IsFSharpRecord + || ent.IsValueType + let baseExpr = - if ent.IsFSharpExceptionDeclaration - then libValue com ctx "Types" "FSharpException" |> Some - elif ent.IsFSharpRecord || ent.IsValueType - then libValue com ctx "Types" "Record" |> Some - else None - let body = [ - if Option.isSome baseExpr then - yield callSuperAsStatement [] - - yield! (ent.FSharpFields |> List.collecti (fun i field -> - let left = get com ctx None thisExpr (Naming.toSnakeCase field.Name) false - let right = args.[i] |> wrapIntExpression field.FieldType - assign None left right |> exprAsStatement ctx)) - ] + if ent.IsFSharpExceptionDeclaration then + libValue com ctx "Types" "FSharpException" |> Some + elif ent.IsFSharpRecord || ent.IsValueType then + libValue com ctx "Types" "Record" |> Some + else + None + + let body = + [ if Option.isSome baseExpr then + yield callSuperAsStatement [] + + yield! + (ent.FSharpFields + |> List.collecti (fun i field -> + let left = + get com ctx None thisExpr (Naming.toSnakeCase field.Name) false + + let right = args.[i] |> wrapIntExpression field.FieldType + assign None left right |> exprAsStatement ctx)) ] + let args = fieldIds |> Array.mapToList (fun id -> let ta, _ = typeAnnotation com ctx None id.Type - Arg.arg(ident com ctx id, annotation=ta)) - |> (fun args -> Arguments.arguments(args=args)) + Arg.arg (ident com ctx id, annotation = ta)) + |> (fun args -> Arguments.arguments (args = args)) + declareType com ctx ent entName args isOptional body baseExpr classMembers - let transformClassWithImplicitConstructor (com: IPythonCompiler) ctx (classDecl: Fable.ClassDecl) classMembers (cons: Fable.MemberDecl) = + let transformClassWithImplicitConstructor + (com: IPythonCompiler) + ctx + (classDecl: Fable.ClassDecl) + classMembers + (cons: Fable.MemberDecl) + = // printfn "transformClassWithImplicitConstructor: %A" classDecl let classEnt = com.GetEntity(classDecl.Entity) - let classIdent = Expression.name(com.GetIdentifier(ctx, classDecl.Name)) + + let classIdent = + Expression.name (com.GetIdentifier(ctx, classDecl.Name)) + let consArgs, consBody, _returnType = getMemberArgsAndBody com ctx ClassConstructor cons.Info.HasSpread cons.Args cons.Body + let isOptional = Helpers.isOptional (cons.Args |> Array.ofList) // Change exposed constructor's return type from None to entity type. let returnType = - let availableGenerics = cons.Args |> List.map (fun arg -> arg.Type) |> getGenericTypeParams + let availableGenerics = + cons.Args + |> List.map (fun arg -> arg.Type) + |> getGenericTypeParams + let genParams = getEntityGenParams classEnt makeGenericTypeAnnotation' com ctx classDecl.Name (genParams |> List.ofSeq) (Some availableGenerics) let exposedCons = let argExprs = consArgs.Args - |> List.map (fun p -> Expression.identifier(p.Arg)) - let exposedConsBody = Expression.call(classIdent, argExprs) + |> List.map (fun p -> Expression.identifier (p.Arg)) + + let exposedConsBody = Expression.call (classIdent, argExprs) let name = com.GetIdentifier(ctx, cons.Name) makeFunction name (consArgs, exposedConsBody, [], returnType) @@ -3039,110 +3845,128 @@ module Util = classDecl.BaseCall |> extractBaseExprFromBaseCall com ctx classEnt.BaseType |> Option.orElseWith (fun () -> - if classEnt.IsValueType then Some(libValue com ctx "Types" "Record", ([], [], [])) - else None) + if classEnt.IsValueType then + Some(libValue com ctx "Types" "Record", ([], [], [])) + else + None) |> Option.map (fun (baseExpr, (baseArgs, kw, stmts)) -> let consBody = stmts @ consBody |> List.append [ callSuperAsStatement baseArgs ] + Some baseExpr, consBody) |> Option.defaultValue (None, consBody) - [ - yield! declareType com ctx classEnt classDecl.Name consArgs isOptional consBody baseExpr classMembers - exposedCons - ] + + [ yield! declareType com ctx classEnt classDecl.Name consArgs isOptional consBody baseExpr classMembers; exposedCons ] let transformInterface (com: IPythonCompiler) ctx (classEnt: Fable.Entity) (classDecl: Fable.ClassDecl) = // printfn "transformInterface" - let classIdent = com.GetIdentifier(ctx, Helpers.removeNamespace classEnt.FullName) + let classIdent = + com.GetIdentifier(ctx, Helpers.removeNamespace classEnt.FullName) + let members = classEnt.MembersFunctionsAndValues |> List.ofSeq |> List.groupBy (fun memb -> memb.DisplayName) // Remove duplicate method when we have getters and setters - |> List.collect (fun (_, gr) -> gr |> List.filter (fun memb -> gr.Length = 1 || (memb.IsGetter || memb.IsSetter))) - - let classMembers = [ - for memb in members do - let name = memb.DisplayName |> Naming.toSnakeCase |> Helpers.clean - com.GetImportExpr(ctx, "abc", "abstractmethod") |> ignore - let decorators = [ - if memb.IsValue || memb.IsGetter then - Expression.name("property") - if memb.IsSetter then - Expression.name($"{name}.setter") - - Expression.name("abstractmethod") // Must be after @property - ] - let name = com.GetIdentifier(ctx, name) - let args = - let args = [ - if memb.IsInstance then - Arg.arg("self") - for n, parameterGroup in memb.CurriedParameterGroups |> Seq.indexed do - for m, pg in parameterGroup |> Seq.indexed do - let ta, _ = typeAnnotation com ctx None pg.Type - Arg.arg(pg.Name |> Option.defaultValue $"__arg{n+m}", annotation=ta) - ] - Arguments.arguments(args) - let returnType, _ = typeAnnotation com ctx None memb.ReturnParameter.Type - let body = [ Statement.expr(Expression.name("...")) ] - Statement.functionDef(name, args, body, returns=returnType, decoratorList=decorators) - - if members.IsEmpty then - Statement.Pass - ] - - let bases = [ - let interfaces = - classEnt.AllInterfaces - |> List.ofSeq - |> List.map (fun int -> int.Entity) - |> List.filter (fun ent -> ent.FullName <> classEnt.FullName) - - for ref in interfaces do - let entity = com.GetEntity(ref) - // printfn "FullName: %A" entity.FullName - match entity.FullName with - | "System.IDisposable" -> - let iDisposable = libValue com ctx "util" "IDisposable" - iDisposable - | name -> Expression.name(Helpers.removeNamespace name) + |> List.collect (fun (_, gr) -> + gr + |> List.filter (fun memb -> gr.Length = 1 || (memb.IsGetter || memb.IsSetter))) + + let classMembers = + [ for memb in members do + let name = + memb.DisplayName + |> Naming.toSnakeCase + |> Helpers.clean + + com.GetImportExpr(ctx, "abc", "abstractmethod") + |> ignore + + let decorators = + [ if memb.IsValue || memb.IsGetter then + Expression.name ("property") + if memb.IsSetter then + Expression.name ($"{name}.setter") - // Only add Protocol base if no interfaces (since the included interfaces will be protocols themselves) - if List.isEmpty interfaces then - com.GetImportExpr(ctx, "typing", "Protocol") + Expression.name ("abstractmethod") ] // Must be after @property - for gen in classEnt.GenericParameters do - Expression.subscript(com.GetImportExpr(ctx, "typing", "Generic"), com.AddTypeVar(ctx, gen.Name)) - ] - [ Statement.classDef(classIdent, body = classMembers, bases = bases) ] + let name = com.GetIdentifier(ctx, name) + + let args = + let args = + [ if memb.IsInstance then Arg.arg ("self") + for n, parameterGroup in memb.CurriedParameterGroups |> Seq.indexed do + for m, pg in parameterGroup |> Seq.indexed do + let ta, _ = typeAnnotation com ctx None pg.Type + Arg.arg (pg.Name |> Option.defaultValue $"__arg{n + m}", annotation = ta) ] + + Arguments.arguments (args) + + let returnType, _ = + typeAnnotation com ctx None memb.ReturnParameter.Type + + let body = [ Statement.expr (Expression.name ("...")) ] + Statement.functionDef (name, args, body, returns = returnType, decoratorList = decorators) + + if members.IsEmpty then Statement.Pass ] + + let bases = + [ let interfaces = + classEnt.AllInterfaces + |> List.ofSeq + |> List.map (fun int -> int.Entity) + |> List.filter (fun ent -> ent.FullName <> classEnt.FullName) + + for ref in interfaces do + let entity = com.GetEntity(ref) + // printfn "FullName: %A" entity.FullName + match entity.FullName with + | "System.IDisposable" -> + let iDisposable = libValue com ctx "util" "IDisposable" + iDisposable + | name -> Expression.name (Helpers.removeNamespace name) + + // Only add Protocol base if no interfaces (since the included interfaces will be protocols themselves) + if List.isEmpty interfaces then + com.GetImportExpr(ctx, "typing", "Protocol") + + for gen in classEnt.GenericParameters do + Expression.subscript (com.GetImportExpr(ctx, "typing", "Generic"), com.AddTypeVar(ctx, gen.Name)) ] + + [ Statement.classDef (classIdent, body = classMembers, bases = bases) ] let rec transformDeclaration (com: IPythonCompiler) ctx decl = // printfn "transformDeclaration: %A" decl // printfn "ctx.UsedNames: %A" ctx.UsedNames let withCurrentScope (ctx: Context) (usedNames: Set) f = - let ctx = { ctx with UsedNames = { ctx.UsedNames with CurrentDeclarationScope = HashSet usedNames } } + let ctx = + { ctx with UsedNames = { ctx.UsedNames with CurrentDeclarationScope = HashSet usedNames } } + let result = f ctx ctx.UsedNames.DeclarationScopes.UnionWith(ctx.UsedNames.CurrentDeclarationScope) result match decl with | Fable.ModuleDeclaration decl -> - decl.Members |> List.collect (transformDeclaration com ctx) + decl.Members + |> List.collect (transformDeclaration com ctx) | Fable.ActionDeclaration decl -> - withCurrentScope ctx decl.UsedNames <| fun ctx -> - transformAction com ctx decl.Body + withCurrentScope ctx decl.UsedNames + <| fun ctx -> transformAction com ctx decl.Body | Fable.MemberDeclaration decl -> - withCurrentScope ctx decl.UsedNames <| fun ctx -> + withCurrentScope ctx decl.UsedNames + <| fun ctx -> let decls = if decl.Info.IsValue then let value, stmts = transformAsExpr com ctx decl.Body let name = com.GetIdentifier(ctx, decl.Name) let ta, _ = typeAnnotation com ctx None decl.Body.Type - stmts @ declareModuleMember ctx decl.Info.IsPublic name (Some ta) value + + stmts + @ declareModuleMember ctx decl.Info.IsPublic name (Some ta) value else transformModuleFunction com ctx decl.Info decl.Name decl.Args decl.Body @@ -3159,7 +3983,8 @@ module Util = let classMembers = decl.AttachedMembers |> List.collect (fun memb -> - withCurrentScope ctx memb.UsedNames <| fun ctx -> + withCurrentScope ctx memb.UsedNames + <| fun ctx -> if memb.Info.IsGetter || memb.Info.IsSetter then transformAttachedProperty com ctx memb else @@ -3169,19 +3994,17 @@ module Util = | ent, _ when ent.IsInterface -> transformInterface com ctx ent decl | ent, _ when ent.IsFSharpUnion -> transformUnion com ctx ent decl.Name classMembers | _, Some cons -> - withCurrentScope ctx cons.UsedNames <| fun ctx -> - transformClassWithImplicitConstructor com ctx decl classMembers cons + withCurrentScope ctx cons.UsedNames + <| fun ctx -> transformClassWithImplicitConstructor com ctx decl classMembers cons | _, None -> transformClassWithCompilerGeneratedConstructor com ctx ent decl.Name classMembers let transformTypeVars (com: IPythonCompiler) ctx (typeVars: HashSet) = - [ - for var in typeVars do - let targets = Expression.name(var) |> List.singleton - let value = com.GetImportExpr(ctx, "typing", "TypeVar") - let args = Expression.constant(var) |> List.singleton - let value = Expression.call(value, args) - Statement.assign(targets, value) - ] + [ for var in typeVars do + let targets = Expression.name (var) |> List.singleton + let value = com.GetImportExpr(ctx, "typing", "TypeVar") + let args = Expression.constant (var) |> List.singleton + let value = Expression.call (value, args) + Statement.assign (targets, value) ] let transformImports (com: IPythonCompiler) (imports: Import list) : Statement list = //printfn "transformImports: %A" imports @@ -3190,44 +4013,42 @@ module Util = |> List.map (fun im -> //printfn "Import: %A" im let moduleName = im.Module |> Helpers.rewriteFableImport com + match im.Name with | Some "*" | Some "default" -> let (Identifier local) = im.LocalIdent.Value + if moduleName <> local then - Some moduleName, Alias.alias(im.LocalIdent.Value) + Some moduleName, Alias.alias (im.LocalIdent.Value) else - None, Alias.alias(im.LocalIdent.Value) + None, Alias.alias (im.LocalIdent.Value) | Some name -> let name = Naming.toSnakeCase name - Some moduleName, Alias.alias(Identifier(Helpers.clean name), ?asname=im.LocalIdent) - | None -> - None, Alias.alias(Identifier(moduleName), ?asname=im.LocalIdent)) + Some moduleName, Alias.alias (Identifier(Helpers.clean name), ?asname = im.LocalIdent) + | None -> None, Alias.alias (Identifier(moduleName), ?asname = im.LocalIdent)) |> List.groupBy fst |> List.map (fun (a, b) -> a, List.map snd b) |> List.sortBy (fun name -> let name = match name with | Some moduleName, _ -> moduleName.ToLower() - | None, { Name=name }::_ -> name.Name + | None, { Name = name } :: _ -> name.Name | _ -> "" + match name with | name when name.StartsWith("__") -> "A" + name | name when name.StartsWith("fable") -> "C" + name | name when name.StartsWith(".") -> "D" + name - | _ -> "B" + name - ) + | _ -> "B" + name) - [ - for moduleName, aliases in imports do - match moduleName with - | Some name -> - Statement.importFrom (Some(Identifier(name)), aliases) - | None -> - // Do not put multiple imports on a single line. flake8(E401) - for alias in aliases do - Statement.import([alias]) - ] + [ for moduleName, aliases in imports do + match moduleName with + | Some name -> Statement.importFrom (Some(Identifier(name)), aliases) + | None -> + // Do not put multiple imports on a single line. flake8(E401) + for alias in aliases do + Statement.import ([ alias ]) ] let getIdentForImport (ctx: Context) (moduleName: string) (name: string option) = // printfn "getIdentForImport: %A" (moduleName, name) @@ -3238,7 +4059,8 @@ module Util = |> Some | Some name -> match name with - | "default" | "*" -> Path.GetFileNameWithoutExtension(moduleName) + | "default" + | "*" -> Path.GetFileNameWithoutExtension(moduleName) | _ -> name |> Naming.toSnakeCase |> getUniqueNameInRootScope ctx @@ -3252,7 +4074,7 @@ module Compiler = let onlyOnceWarnings = HashSet() let imports = Dictionary() - let typeVars : HashSet = HashSet () + let typeVars: HashSet = HashSet() interface IPythonCompiler with member _.WarnOnlyOnce(msg, ?range) = @@ -3262,10 +4084,11 @@ module Compiler = member _.GetImportExpr(ctx, moduleName, ?name, ?r) = //printfn "GetImportExpr: %A" (moduleName, name) let cachedName = moduleName + "::" + defaultArg name "module" + match imports.TryGetValue(cachedName) with | true, i -> match i.LocalIdent with - | Some localIdent -> Expression.identifier(localIdent) + | Some localIdent -> Expression.identifier (localIdent) | None -> Expression.none | false, _ -> let local_id = getIdentForImport ctx moduleName name @@ -3277,37 +4100,48 @@ module Compiler = { Name = None Module = moduleName LocalIdent = local_id } + imports.Add(cachedName, i) | Some name -> let i = - { Name = + { Name = if name = Naming.placeholder then - "`importMember` must be assigned to a variable" - |> addError com [] r; name - else name + "`importMember` must be assigned to a variable" + |> addError com [] r + + name + else + name |> Some - Module = moduleName - LocalIdent = local_id } + Module = moduleName + LocalIdent = local_id } + imports.Add(cachedName, i) match local_id with - | Some localId -> Expression.identifier(localId) + | Some localId -> Expression.identifier (localId) | None -> Expression.none member _.GetAllImports() = imports.Values :> Import seq |> List.ofSeq member _.GetAllTypeVars() = typeVars + member _.AddTypeVar(ctx, name: string) = // TypeVars should be private and uppercase. For auto-generated (inferred) generics we use a double-undercore. let name = - let name = name.ToUpperInvariant () |> Helpers.clean + let name = name.ToUpperInvariant() |> Helpers.clean + if name.EndsWith("_") then - $"__{name.TrimEnd([|'_'|])}" + $"__{name.TrimEnd([| '_' |])}" else $"_{name}" typeVars.Add name |> ignore - ctx.UsedNames.DeclarationScopes.Add(name) |> ignore - Expression.name(name) + + ctx.UsedNames.DeclarationScopes.Add(name) + |> ignore + + Expression.name (name) + member bcom.TransformAsExpr(ctx, e) = transformAsExpr bcom ctx e member bcom.TransformAsStatements(ctx, ret, e) = transformAsStatements bcom ctx ret e member bcom.TransformFunction(ctx, name, args, body, generics) = transformFunction bcom ctx name args body generics @@ -3323,41 +4157,51 @@ module Compiler = member _.OutputDir = com.OutputDir member _.OutputType = com.OutputType member _.ProjectFile = com.ProjectFile - member _.IsPrecompilingInlineFunction = com.IsPrecompilingInlineFunction + + member _.IsPrecompilingInlineFunction = + com.IsPrecompilingInlineFunction + member _.WillPrecompileInlineFunction(file) = com.WillPrecompileInlineFunction(file) member _.GetImplementationFile(fileName) = com.GetImplementationFile(fileName) member _.GetRootModule(fileName) = com.GetRootModule(fileName) member _.TryGetEntity(fullName) = com.TryGetEntity(fullName) member _.GetInlineExpr(fullName) = com.GetInlineExpr(fullName) member _.AddWatchDependency(fileName) = com.AddWatchDependency(fileName) - member _.AddLog(msg, severity, ?range, ?fileName:string, ?tag: string) = - com.AddLog(msg, severity, ?range=range, ?fileName=fileName, ?tag=tag) + + member _.AddLog(msg, severity, ?range, ?fileName: string, ?tag: string) = + com.AddLog(msg, severity, ?range = range, ?fileName = fileName, ?tag = tag) let makeCompiler com = PythonCompiler(com) let transformFile (com: Compiler) (file: Fable.File) = let com = makeCompiler com :> IPythonCompiler + let declScopes = let hs = HashSet() + for decl in file.Declarations do hs.UnionWith(decl.UsedNames) + hs let ctx = - { File = file - UsedNames = { RootScope = HashSet file.UsedNamesInRootScope - DeclarationScopes = declScopes - CurrentDeclarationScope = Unchecked.defaultof<_> } - BoundVars = { GlobalScope = HashSet () - EnclosingScope = HashSet () - LocalScope = HashSet () } - DecisionTargets = [] - HoistVars = fun _ -> false - TailCallOpportunity = None - OptimizeTailCall = fun () -> () - ScopedTypeParams = Set.empty } - - let rootDecls = List.collect (transformDeclaration com ctx) file.Declarations + { File = file + UsedNames = + { RootScope = HashSet file.UsedNamesInRootScope + DeclarationScopes = declScopes + CurrentDeclarationScope = Unchecked.defaultof<_> } + BoundVars = + { GlobalScope = HashSet() + EnclosingScope = HashSet() + LocalScope = HashSet() } + DecisionTargets = [] + HoistVars = fun _ -> false + TailCallOpportunity = None + OptimizeTailCall = fun () -> () + ScopedTypeParams = Set.empty } + + let rootDecls = + List.collect (transformDeclaration com ctx) file.Declarations let typeVars = com.GetAllTypeVars() |> transformTypeVars com ctx let importDecls = com.GetAllImports() |> transformImports com diff --git a/src/Fable.Transforms/Python/Prelude.fs b/src/Fable.Transforms/Python/Prelude.fs index 5a575a4b96..ad62310dda 100644 --- a/src/Fable.Transforms/Python/Prelude.fs +++ b/src/Fable.Transforms/Python/Prelude.fs @@ -8,15 +8,25 @@ module Naming = open System.Text.RegularExpressions let lowerFirst (s: string) = - s.Substring(0,1).ToLowerInvariant() + s.Substring(1) + s.Substring(0, 1).ToLowerInvariant() + + s.Substring(1) let upperFirst (s: string) = - s.Substring(0,1).ToUpperInvariant() + s.Substring(1) + s.Substring(0, 1).ToUpperInvariant() + + s.Substring(1) let private dashify (separator: string) (input: string) = - Regex.Replace(input, "[a-z]?[A-Z]", fun m -> - if m.Value.Length = 1 then m.Value.ToLowerInvariant() - else m.Value.Substring(0,1) + separator + m.Value.Substring(1,1).ToLowerInvariant()) + Regex.Replace( + input, + "[a-z]?[A-Z]", + fun m -> + if m.Value.Length = 1 then + m.Value.ToLowerInvariant() + else + m.Value.Substring(0, 1) + + separator + + m.Value.Substring(1, 1).ToLowerInvariant() + ) let applyCaseRule caseRule name = match caseRule with @@ -24,7 +34,8 @@ module Naming = | CaseRules.SnakeCase -> dashify "_" name | CaseRules.SnakeCaseAllCaps -> (dashify "_" name).ToUpperInvariant() | CaseRules.KebabCase -> dashify "-" name - | CaseRules.None | _ -> name + | CaseRules.None + | _ -> name let toSnakeCase (name: string) = if name.Length > 0 && Char.IsLower(name.[0]) then @@ -33,8 +44,10 @@ module Naming = name let cleanNameAsPyIdentifier (name: string) = - if name = ".ctor" then "_ctor" - else name.Replace('.','_').Replace('`','_') + if name = ".ctor" then + "_ctor" + else + name.Replace('.', '_').Replace('`', '_') let pyKeywords = // https://docs.python.org/3/reference/lexical_analysis.html#keywords @@ -103,57 +116,90 @@ module Naming = // Other names "self" ] + let reflectionSuffix = "_reflection" let preventConflicts conflicts originalName = let rec check originalName n = - let name = if n > 0 then originalName + "_" + (string n) else originalName - if not (conflicts name) then name else check originalName (n+1) + let name = + if n > 0 then + originalName + "_" + (string n) + else + originalName + + if not (conflicts name) then + name + else + check originalName (n + 1) + check originalName 0 let isIdentChar index (c: char) = let code = int c + c = '_' - || (65 <= code && code <= 90) // a-z - || (97 <= code && code <= 122) // A-Z + || (65 <= code && code <= 90) // a-z + || (97 <= code && code <= 122) // A-Z // Digits are not allowed in first position, see #1397 || (index > 0 && 48 <= code && code <= 57) // 0-9 let hasIdentForbiddenChars (ident: string) = let mutable found = false + for i = 0 to ident.Length - 1 do - found <- found || not(isIdentChar i ident.[i]) + found <- found || not (isIdentChar i ident.[i]) + found let sanitizeIdentForbiddenChars (ident: string) = if hasIdentForbiddenChars ident then - System.String.Concat(seq { - for i = 0 to (ident.Length - 1) do - let c = ident.[i] - if isIdentChar i c - then string c - elif c = '$' || c = '_' || c = ' ' || c = '*' || c = '.' - then "_" - else "_" + System.String.Format("{0:X}", int c).PadLeft(4, '0') - }) - else ident + System.String.Concat( + seq { + for i = 0 to (ident.Length - 1) do + let c = ident.[i] + + if isIdentChar i c then + string c + elif c = '$' + || c = '_' + || c = ' ' + || c = '*' + || c = '.' then + "_" + else + "_" + + System + .String + .Format("{0:X}", int c) + .PadLeft(4, '0') + } + ) + else + ident let checkPyKeywords name = - if pyKeywords.Contains name - then name + "_" - else name + if pyKeywords.Contains name then + name + "_" + else + name let private printPart sanitize separator part overloadSuffix = - (if part = "" then "" else separator + (sanitize part)) + - (if overloadSuffix = "" then "" else "_" + overloadSuffix) + (if part = "" then + "" + else + separator + (sanitize part)) + + (if overloadSuffix = "" then + "" + else + "_" + overloadSuffix) let private buildName sanitize name part = - (sanitize name) + - (match part with - | Naming.InstanceMemberPart(s, i) -> printPart sanitize "__" s i - | Naming.StaticMemberPart(s, i) -> printPart sanitize "_" s i - | Naming.NoMemberPart -> "") + (sanitize name) + + (match part with + | Naming.InstanceMemberPart (s, i) -> printPart sanitize "__" s i + | Naming.StaticMemberPart (s, i) -> printPart sanitize "_" s i + | Naming.NoMemberPart -> "") let sanitizeIdent conflicts name part = // Replace Forbidden Chars diff --git a/src/Fable.Transforms/Python/Python.fs b/src/Fable.Transforms/Python/Python.fs index 4c62766635..6f65ec00c2 100644 --- a/src/Fable.Transforms/Python/Python.fs +++ b/src/Fable.Transforms/Python/Python.fs @@ -153,15 +153,15 @@ type Try = /// A single context manager in a with block. context_expr is the context manager, often a Call node. optional_vars is a /// Name, Tuple or List for the as foo part, or None if that isn’t used. type WithItem = - { ContextExpr: Expression - OptionalVars: Expression option } + { ContextExpr: Expression + OptionalVars: Expression option } /// A with block. items is a list of withitem nodes representing the context managers, and body is the indented block /// inside the context. type With = - { Items: WithItem list - Body: Statement list - TypeComment: string option } + { Items: WithItem list + Body: Statement list + TypeComment: string option } /// A single argument in a list. arg is a raw string of the argument name, annotation is its annotation, such as a Str /// or Name node. @@ -756,20 +756,21 @@ type AST = [] module PythonExtensions = type Statement with + static member break'() : Statement = Break static member continue' ?loc : Statement = Continue static member import(names) : Statement = Import { Names = names } static member expr(value) : Statement = { Expr.Value = value } |> Expr - static member raise(value) : Statement = { Exception=value; Cause=None} |> Raise + static member raise(value) : Statement = { Exception = value; Cause = None } |> Raise static member try'(body, ?handlers, ?orElse, ?finalBody, ?loc) : Statement = Try.try' (body, ?handlers = handlers, ?orElse = orElse, ?finalBody = finalBody, ?loc = loc) |> Try static member with'(items, ?body, ?typeComment) : Statement = - { Items=items - Body=defaultArg body [] - TypeComment=typeComment } + { Items = items + Body = defaultArg body [] + TypeComment = typeComment } |> With static member classDef(name, ?bases, ?keywords, ?body, ?decoratorList, ?loc) : Statement = @@ -837,9 +838,9 @@ module PythonExtensions = Loc = loc } |> Name - static member name(name, ?ctx) : Expression = Expression.name(Identifier(name), ?ctx = ctx) - static member identifier(name, ?ctx, ?loc) : Expression = Expression.name(Identifier(name), ?ctx = ctx, ?loc = loc) - static member identifier(identifier, ?ctx, ?loc) : Expression = Expression.name(identifier, ?ctx = ctx, ?loc = loc) + static member name(name, ?ctx) : Expression = Expression.name (Identifier(name), ?ctx = ctx) + static member identifier(name, ?ctx, ?loc) : Expression = Expression.name (Identifier(name), ?ctx = ctx, ?loc = loc) + static member identifier(identifier, ?ctx, ?loc) : Expression = Expression.name (identifier, ?ctx = ctx, ?loc = loc) static member dict(keys, values) : Expression = { Keys = keys; Values = values } |> Dict static member tuple(elts, ?loc) : Expression = { Elements = elts; Loc = loc } |> Tuple @@ -876,23 +877,22 @@ module PythonExtensions = static member compare(left, op, comparators, ?loc) : Expression = let op = - match op with - | BinaryEqual -> Eq - | BinaryEqualStrict -> Is - | BinaryUnequal -> NotEq - | BinaryUnequalStrict -> IsNot - | BinaryLess -> Lt - | BinaryLessOrEqual -> LtE - | BinaryGreater -> Gt - | BinaryGreaterOrEqual -> GtE - | _ -> failwith $"compare: Operator {op} not supported" - Expression.compare(left, [op], comparators) - - static member none = - Expression.name (Identifier(name="None")) - - static member any = - Expression.name (Identifier(name="Any")) + match op with + | BinaryEqual -> Eq + | BinaryEqualStrict -> Is + | BinaryUnequal -> NotEq + | BinaryUnequalStrict -> IsNot + | BinaryLess -> Lt + | BinaryLessOrEqual -> LtE + | BinaryGreater -> Gt + | BinaryGreaterOrEqual -> GtE + | _ -> failwith $"compare: Operator {op} not supported" + + Expression.compare (left, [ op ], comparators) + + static member none = Expression.name (Identifier(name = "None")) + + static member any = Expression.name (Identifier(name = "Any")) static member attribute(value, attr, ?ctx) : Expression = { Value = value @@ -902,17 +902,17 @@ module PythonExtensions = static member unaryOp(op, operand, ?loc) : Expression = let op = - match op with - | UnaryMinus -> USub - | UnaryPlus -> UAdd - | UnaryNot -> Not - | UnaryNotBitwise -> Invert - // | UnaryTypeof -> "typeof" - // | UnaryVoid -> - // | UnaryDelete -> "delete" - | _ -> failwith $"unaryOp: Operator {op} not supported" - - Expression.unaryOp(op, operand, ?loc=loc) + match op with + | UnaryMinus -> USub + | UnaryPlus -> UAdd + | UnaryNot -> Not + | UnaryNotBitwise -> Invert + // | UnaryTypeof -> "typeof" + // | UnaryVoid -> + // | UnaryDelete -> "delete" + | _ -> failwith $"unaryOp: Operator {op} not supported" + + Expression.unaryOp (op, operand, ?loc = loc) static member unaryOp(op, operand, ?loc) : Expression = { Op = op @@ -920,7 +920,11 @@ module PythonExtensions = Loc = loc } |> UnaryOp - static member namedExpr(target, value, ?loc) = { Target = target; Value = value; Loc=loc } |> NamedExpr + static member namedExpr(target, value, ?loc) = + { Target = target + Value = value + Loc = loc } + |> NamedExpr static member subscript(value, slice, ?ctx) : Expression = { Value = value @@ -937,32 +941,38 @@ module PythonExtensions = static member binOp(left, op, right, ?loc) : Expression = let op = - match op with - | BinaryPlus -> Add - | BinaryMinus -> Sub - | BinaryMultiply -> Mult - | BinaryDivide -> Div - | BinaryModulus -> Mod - | BinaryOrBitwise -> BitOr - | BinaryAndBitwise -> BitAnd - | BinaryShiftLeft -> LShift - | BinaryShiftRightZeroFill -> RShift - | BinaryShiftRightSignPropagating -> RShift - | BinaryXorBitwise -> BitXor - | _ -> failwith $"binOp: Operator {op} not supported" - - Expression.binOp(left, op, right, ?loc=loc) - - static member boolOp(op: BoolOperator, values, ?loc) : Expression = { Values = values; Operator = op; Loc=loc } |> BoolOp + match op with + | BinaryPlus -> Add + | BinaryMinus -> Sub + | BinaryMultiply -> Mult + | BinaryDivide -> Div + | BinaryModulus -> Mod + | BinaryOrBitwise -> BitOr + | BinaryAndBitwise -> BitAnd + | BinaryShiftLeft -> LShift + | BinaryShiftRightZeroFill -> RShift + | BinaryShiftRightSignPropagating -> RShift + | BinaryXorBitwise -> BitXor + | _ -> failwith $"binOp: Operator {op} not supported" + + Expression.binOp (left, op, right, ?loc = loc) + + static member boolOp(op: BoolOperator, values, ?loc) : Expression = + { Values = values + Operator = op + Loc = loc } + |> BoolOp + static member boolOp(op: LogicalOperator, values, ?loc) : Expression = let op = match op with | LogicalAnd -> And | LogicalOr -> Or - Expression.boolOp(op, values, ?loc=loc) - static member constant(value: obj, ?loc) : Expression = Constant (value=value, loc=loc) - static member string(value: string, ?loc) : Expression = Constant (value=value, loc=loc) + Expression.boolOp (op, values, ?loc = loc) + + static member constant(value: obj, ?loc) : Expression = Constant(value = value, loc = loc) + static member string(value: string, ?loc) : Expression = Constant(value = value, loc = loc) static member starred(value: Expression, ?ctx: ExpressionContext) : Expression = Starred(value, ctx |> Option.defaultValue Load) static member list(elts: Expression list, ?ctx: ExpressionContext) : Expression = List(elts, ctx |> Option.defaultValue Load) @@ -981,9 +991,11 @@ module PythonExtensions = type Alias with static member alias(name, ?asname) = { Name = name; AsName = asname } + type WithItem with + static member withItem(contextExpr, ?optinalVars) = - { ContextExpr=contextExpr + { ContextExpr = contextExpr OptionalVars = optinalVars } type Try with @@ -1018,8 +1030,7 @@ module PythonExtensions = Annotation = annotation TypeComment = typeComment } - static member arg(arg, ?annotation, ?typeComment) = - Arg.arg(Identifier(arg), ?annotation=annotation, ?typeComment=typeComment) + static member arg(arg, ?annotation, ?typeComment) = Arg.arg (Identifier(arg), ?annotation = annotation, ?typeComment = typeComment) type Keyword with @@ -1042,7 +1053,8 @@ module PythonExtensions = KwDefaults = defaultArg kwDefaults [] KwArg = kwarg Defaults = defaultArg defaults [] } - static member empty = Arguments.arguments() + + static member empty = Arguments.arguments () type For with diff --git a/src/Fable.Transforms/Python/PythonPrinter.fs b/src/Fable.Transforms/Python/PythonPrinter.fs index e1fb7c9cc5..e708222fbd 100644 --- a/src/Fable.Transforms/Python/PythonPrinter.fs +++ b/src/Fable.Transforms/Python/PythonPrinter.fs @@ -7,13 +7,7 @@ open Fable.AST open Fable.AST.Python type SourceMapGenerator = - abstract AddMapping: - originalLine: int - * originalColumn: int - * generatedLine: int - * generatedColumn: int - * ?name: string - -> unit + abstract AddMapping: originalLine: int * originalColumn: int * generatedLine: int * generatedColumn: int * ?name: string -> unit type Writer = inherit IDisposable @@ -24,12 +18,12 @@ type Printer = abstract Column: int abstract PushIndentation: unit -> unit abstract PopIndentation: unit -> unit - abstract Print: string * ?loc:SourceLocation -> unit + abstract Print: string * ?loc: SourceLocation -> unit abstract PrintNewLine: unit -> unit abstract AddLocation: SourceLocation option -> unit abstract MakeImportPath: string -> string -type PrinterImpl(writer: Writer, map: SourceMapGenerator) = +type PrinterImpl (writer: Writer, map: SourceMapGenerator) = // TODO: We can make this configurable later let indentSpaces = " " let builder = Text.StringBuilder() @@ -41,13 +35,15 @@ type PrinterImpl(writer: Writer, map: SourceMapGenerator) = match loc with | None -> () | Some loc -> - map.AddMapping(originalLine = loc.start.line, - originalColumn = loc.start.column, - generatedLine = line, - generatedColumn = column, - ?name = loc.identifierName) + map.AddMapping( + originalLine = loc.start.line, + originalColumn = loc.start.column, + generatedLine = line, + generatedColumn = column, + ?name = loc.identifierName + ) - member _.Flush(): Async = + member _.Flush() : Async = async { do! writer.Write(builder.ToString()) builder.Clear() |> ignore @@ -65,14 +61,11 @@ type PrinterImpl(writer: Writer, map: SourceMapGenerator) = member _.Line = line member _.Column = column - member _.PushIndentation() = - indent <- indent + 1 + member _.PushIndentation() = indent <- indent + 1 - member _.PopIndentation() = - if indent > 0 then indent <- indent - 1 + member _.PopIndentation() = if indent > 0 then indent <- indent - 1 - member _.AddLocation(loc) = - addLoc loc + member _.AddLocation(loc) = addLoc loc member _.Print(str, loc) = addLoc loc @@ -85,8 +78,7 @@ type PrinterImpl(writer: Writer, map: SourceMapGenerator) = builder.Append(str) |> ignore column <- column + str.Length - member this.PrintNewLine() = - this.PrintNewLine() + member this.PrintNewLine() = this.PrintNewLine() member this.MakeImportPath(path) = path @@ -136,6 +128,7 @@ module PrinterExtensions = member printer.Print(arg: Arg) = let (Identifier name) = arg.Arg printer.Print(name) + match arg.Annotation with | Some ann -> printer.Print(": ") @@ -155,13 +148,16 @@ module PrinterExtensions = let args = arguments.Args |> List.map AST.Arg let defaults = arguments.Defaults + for i = 0 to args.Length - 1 do - printer.Print(args.[i]) - if i >= args.Length - defaults.Length then - printer.Print("=") - printer.Print(defaults.[i-(args.Length-defaults.Length)]) - if i < args.Length - 1 then - printer.Print(", ") + printer.Print(args.[i]) + + if i >= args.Length - defaults.Length then + printer.Print("=") + printer.Print(defaults.[i - (args.Length - defaults.Length)]) + + if i < args.Length - 1 then + printer.Print(", ") match arguments.Args, arguments.VarArg with | [], Some vararg -> @@ -183,6 +179,7 @@ module PrinterExtensions = member printer.Print(wi: WithItem) = printer.Print(wi.ContextExpr) + match wi.OptionalVars with | Some vars -> printer.Print(" as ") @@ -200,6 +197,7 @@ module PrinterExtensions = printer.Print(assign.Target) printer.Print(" : ") printer.Print(assign.Annotation) + match assign.Value with | Some value -> printer.Print(" = ") @@ -253,7 +251,7 @@ module PrinterExtensions = match stmts with | [] | [ Pass ] -> () - | [ If { Test=test; Body=body; Else=els } ] -> + | [ If { Test = test; Body = body; Else = els } ] -> printer.Print("elif ") printer.Print(test) printer.Print(":") @@ -302,7 +300,8 @@ module PrinterExtensions = printer.Print(")") member printer.Print(im: ImportFrom) = - let (Identifier path) = im.Module |> Option.defaultValue (Identifier ".") + let (Identifier path) = + im.Module |> Option.defaultValue (Identifier ".") printer.Print("from ") printer.Print(path) @@ -334,11 +333,11 @@ module PrinterExtensions = member printer.Print(node: Subscript) = printer.Print(node.Value) printer.Print("[") + match node.Slice with - | Tuple({Elements=elems}) -> - printer.PrintCommaSeparatedList(elems) - | _ -> - printer.Print(node.Slice) + | Tuple ({ Elements = elems }) -> printer.PrintCommaSeparatedList(elems) + | _ -> printer.Print(node.Slice) + printer.Print("]") member printer.Print(node: BinOp) = printer.PrintOperation(node.Left, node.Operator, node.Right) @@ -375,10 +374,13 @@ module PrinterExtensions = printer.ComplexExpressionWithParens(node.Func) printer.Print("(") printer.PrintCommaSeparatedList(node.Args) + if not node.Keywords.IsEmpty then if not node.Args.IsEmpty then printer.Print(", ") + printer.PrintCommaSeparatedList(node.Keywords) + printer.Print(")") member printer.Print(node: Emit) = @@ -416,18 +418,22 @@ module PrinterExtensions = |> replace @"\$(\d+)\.\.\." (fun m -> let rep = ResizeArray() let i = int m.Groups.[1].Value + for j = i to node.Args.Length - 1 do rep.Add("$" + string j) + String.concat ", " rep) |> replace @"\{\{\s*\$(\d+)\s*\?(.*?)\:(.*?)\}\}" (fun m -> let i = int m.Groups.[1].Value + match node.Args.[i] with - | Constant(value=value) when (value :?> bool) -> m.Groups.[2].Value + | Constant (value = value) when (value :?> bool) -> m.Groups.[2].Value | _ -> m.Groups.[3].Value) |> replace @"\{\{([^\}]*\$(\d+).*?)\}\}" (fun m -> let i = int m.Groups.[2].Value + match List.tryItem i node.Args with | Some _ -> m.Groups.[1].Value | None -> "") @@ -435,8 +441,9 @@ module PrinterExtensions = // If placeholder is followed by !, emit string literals as JS: "let $0! = $1" |> replace @"\$(\d+)!" (fun m -> let i = int m.Groups.[1].Value + match List.tryItem i node.Args with - | Some(Constant(value, _)) when (value :? string) -> unbox value + | Some (Constant (value, _)) when (value :? string) -> unbox value | _ -> "") let matches = @@ -544,7 +551,7 @@ module PrinterExtensions = printer.Print(node.Name) match node.AsName with - | Some (Identifier alias) when Identifier alias <> node.Name-> + | Some (Identifier alias) when Identifier alias <> node.Name -> printer.Print(" as ") printer.Print(alias) | _ -> () @@ -617,7 +624,7 @@ module PrinterExtensions = | Emit ex -> printer.Print(ex) | UnaryOp ex -> printer.Print(ex) | FormattedValue ex -> printer.Print(ex) - | Constant (value=value) -> + | Constant (value = value) -> match box value with | :? string as str -> printer.Print("\"") @@ -638,7 +645,9 @@ module PrinterExtensions = | Slice (lower, upper, step) -> if lower.IsSome then printer.Print(lower.Value) + printer.Print(":") + if upper.IsSome then printer.Print(upper.Value) | Starred (ex, ctx) -> @@ -666,13 +675,7 @@ module PrinterExtensions = | AST.Identifier id -> printer.Print(id) | AST.WithItem wi -> printer.Print(wi) - member printer.PrintBlock - ( - nodes: 'a list, - printNode: Printer -> 'a -> unit, - printSeparator: Printer -> unit, - ?skipNewLineAtEnd - ) = + member printer.PrintBlock(nodes: 'a list, printNode: Printer -> 'a -> unit, printSeparator: Printer -> unit, ?skipNewLineAtEnd) = let skipNewLineAtEnd = defaultArg skipNewLineAtEnd false printer.Print("") printer.PrintNewLine() @@ -732,8 +735,8 @@ module PrinterExtensions = | None -> () | Some node -> printer.Print(node) - member printer.PrintOptional(node: Expression option) = - printer.PrintOptional(node |> Option.map AST.Expression) + member printer.PrintOptional(node: Expression option) = printer.PrintOptional(node |> Option.map AST.Expression) + member printer.PrintOptional(node: Identifier option) = match node with | None -> () @@ -751,16 +754,12 @@ module PrinterExtensions = member printer.PrintCommaSeparatedList(nodes: Expression list) = printer.PrintList(nodes, (fun p x -> printer.Print(x)), (fun p -> p.Print(", "))) - member printer.PrintCommaSeparatedList(nodes: Arg list) = - printer.PrintCommaSeparatedList(nodes |> List.map AST.Arg) - member printer.PrintCommaSeparatedList(nodes: Keyword list) = - printer.PrintCommaSeparatedList(nodes |> List.map AST.Keyword) - member printer.PrintCommaSeparatedList(nodes: Alias list) = - printer.PrintCommaSeparatedList(nodes |> List.map AST.Alias) - member printer.PrintCommaSeparatedList(nodes: Identifier list) = - printer.PrintCommaSeparatedList(nodes |> List.map AST.Identifier) - member printer.PrintCommaSeparatedList(nodes: WithItem list) = - printer.PrintCommaSeparatedList(nodes |> List.map AST.WithItem) + + member printer.PrintCommaSeparatedList(nodes: Arg list) = printer.PrintCommaSeparatedList(nodes |> List.map AST.Arg) + member printer.PrintCommaSeparatedList(nodes: Keyword list) = printer.PrintCommaSeparatedList(nodes |> List.map AST.Keyword) + member printer.PrintCommaSeparatedList(nodes: Alias list) = printer.PrintCommaSeparatedList(nodes |> List.map AST.Alias) + member printer.PrintCommaSeparatedList(nodes: Identifier list) = printer.PrintCommaSeparatedList(nodes |> List.map AST.Identifier) + member printer.PrintCommaSeparatedList(nodes: WithItem list) = printer.PrintCommaSeparatedList(nodes |> List.map AST.WithItem) member printer.PrintFunction ( @@ -781,9 +780,11 @@ module PrinterExtensions = printer.Print("(") printer.Print(args) printer.Print(")") + if returnType.IsSome then printer.Print(" -> ") printer.PrintOptional(returnType) + printer.Print(":") printer.PrintBlock(body, skipNewLineAtEnd = true) @@ -810,21 +811,23 @@ module PrinterExtensions = printer.ComplexExpressionWithParens(right) open PrinterExtensions -let run writer map (program: Module): Async = + +let run writer map (program: Module) : Async = let printDeclWithExtraLine extraLine (printer: Printer) (decl: Statement) = printer.Print(decl) if printer.Column > 0 then printer.PrintNewLine() - if extraLine then - printer.PrintNewLine() + + if extraLine then printer.PrintNewLine() async { use printer = new PrinterImpl(writer, map) let imports, restDecls = - program.Body |> List.splitWhile (function + program.Body + |> List.splitWhile (function | Import _ | ImportFrom _ -> true | _ -> false) diff --git a/src/Fable.Transforms/Python/Replacements.fs b/src/Fable.Transforms/Python/Replacements.fs index 5ee8cd0925..49c629ce8a 100644 --- a/src/Fable.Transforms/Python/Replacements.fs +++ b/src/Fable.Transforms/Python/Replacements.fs @@ -19,33 +19,58 @@ type Helper = let info = defaultArg argTypes [] |> makeCallInfo None args Call(consExpr, { info with IsConstructor = true }, returnType, loc) - static member InstanceCall(callee: Expr, memb: string, returnType: Type, args: Expr list, - ?argTypes: Type list, ?loc: SourceLocation) = + static member InstanceCall(callee: Expr, memb: string, returnType: Type, args: Expr list, ?argTypes: Type list, ?loc: SourceLocation) = let callee = getAttachedMember callee memb let info = defaultArg argTypes [] |> makeCallInfo None args Call(callee, info, returnType, loc) - static member Application(callee: Expr, returnType: Type, args: Expr list, - ?argTypes: Type list, ?loc: SourceLocation) = + static member Application(callee: Expr, returnType: Type, args: Expr list, ?argTypes: Type list, ?loc: SourceLocation) = let info = defaultArg argTypes [] |> makeCallInfo None args Call(callee, info, returnType, loc) static member LibValue(com, coreModule: string, coreMember: string, returnType: Type) = makeImportLib com returnType coreMember coreModule - static member LibCall(com, coreModule: string, coreMember: string, returnType: Type, args: Expr list, - ?argTypes: Type list, ?thisArg: Expr, ?hasSpread: bool, ?isPyConstructor: bool, ?loc: SourceLocation) = + static member LibCall + ( + com, + coreModule: string, + coreMember: string, + returnType: Type, + args: Expr list, + ?argTypes: Type list, + ?thisArg: Expr, + ?hasSpread: bool, + ?isPyConstructor: bool, + ?loc: SourceLocation + ) = let callee = makeImportLib com Any coreMember coreModule let info = makeCallInfo thisArg args (defaultArg argTypes []) - Call(callee, { info with HasSpread = defaultArg hasSpread false - IsConstructor = defaultArg isPyConstructor false }, returnType, loc) - static member GlobalCall(ident: string, returnType: Type, args: Expr list, ?argTypes: Type list, - ?memb: string, ?isPyConstructor: bool, ?loc: SourceLocation) = + Call( + callee, + { info with + HasSpread = defaultArg hasSpread false + IsConstructor = defaultArg isPyConstructor false }, + returnType, + loc + ) + + static member GlobalCall + ( + ident: string, + returnType: Type, + args: Expr list, + ?argTypes: Type list, + ?memb: string, + ?isPyConstructor: bool, + ?loc: SourceLocation + ) = let callee = match memb with | Some memb -> getAttachedMember (makeIdentExpr ident) memb | None -> makeIdentExpr ident + let info = makeCallInfo None args (defaultArg argTypes []) Call(callee, { info with IsConstructor = defaultArg isPyConstructor false }, returnType, loc) @@ -54,8 +79,12 @@ type Helper = [] module Atts = - let [] decorator = "Fable.Core.PY.DecoratorAttribute" // typeof.FullName - let [] reflectedDecorator = "Fable.Core.PY.ReflectedDecoratorAttribute" // typeof.FullName + [] + let decorator = "Fable.Core.PY.DecoratorAttribute" // typeof.FullName + + [] + let reflectedDecorator = + "Fable.Core.PY.ReflectedDecoratorAttribute" // typeof.FullName module Helpers = let getTypedArrayName (com: Compiler) numberKind = @@ -74,55 +103,50 @@ module Helpers = let name = (name, Naming.NoMemberPart) ||> Naming.sanitizeIdent (FSharp2Fable.Helpers.isUsedName ctx) - ctx.UsedNamesInDeclarationScope.Add(name) |> ignore + + ctx.UsedNamesInDeclarationScope.Add(name) + |> ignore + name let resolveArgTypes argTypes (genArgs: (string * Type) list) = - argTypes |> List.map (function - | GenericParam(name,_) as t -> - genArgs |> List.tryPick (fun (name2, t) -> - if name = name2 then Some t else None) + argTypes + |> List.map (function + | GenericParam (name, _) as t -> + genArgs + |> List.tryPick (fun (name2, t) -> if name = name2 then Some t else None) |> Option.defaultValue t | t -> t) - let asOptimizable optimization = function - | Call(e, i, t, r) -> Call(e, { i with OptimizableInto = Some optimization }, t, r) + let asOptimizable optimization = + function + | Call (e, i, t, r) -> Call(e, { i with OptimizableInto = Some optimization }, t, r) | e -> e - let objValue (k, v): MemberDecl = - { - Name = k - FullDisplayName = k - Args = [] - Body = v - UsedNames = Set.empty - Info = FSharp2Fable.MemberInfo(isValue=true) - ExportDefault = false - } + let objValue (k, v) : MemberDecl = + { Name = k + FullDisplayName = k + Args = [] + Body = v + UsedNames = Set.empty + Info = FSharp2Fable.MemberInfo(isValue = true) + ExportDefault = false } - let typedObjExpr t kvs = - ObjectExpr(List.map objValue kvs, t, None) + let typedObjExpr t kvs = ObjectExpr(List.map objValue kvs, t, None) - let objExpr kvs = - typedObjExpr Any kvs + let objExpr kvs = typedObjExpr Any kvs - let add left right = - Operation(Binary(BinaryPlus, left, right), left.Type, None) + let add left right = Operation(Binary(BinaryPlus, left, right), left.Type, None) - let sub left right = - Operation(Binary(BinaryMinus, left, right), left.Type, None) + let sub left right = Operation(Binary(BinaryMinus, left, right), left.Type, None) - let eq left right = - Operation(Binary(BinaryEqualStrict, left, right), Boolean, None) + let eq left right = Operation(Binary(BinaryEqualStrict, left, right), Boolean, None) - let neq left right = - Operation(Binary(BinaryUnequalStrict, left, right), Boolean, None) + let neq left right = Operation(Binary(BinaryUnequalStrict, left, right), Boolean, None) - let isNull expr = - Operation(Binary(BinaryEqual, expr, Value(Null Any, None)), Boolean, None) + let isNull expr = Operation(Binary(BinaryEqual, expr, Value(Null Any, None)), Boolean, None) - let error msg = - Helper.PyConstructorCall(makeIdentExpr "Exception", Any, [msg]) + let error msg = Helper.PyConstructorCall(makeIdentExpr "Exception", Any, [ msg ]) let str txt = Value(StringConstant txt, None) @@ -130,8 +154,10 @@ module Helpers = List.tryItem i genArgs |> Option.map snd |> Option.defaultWith (fun () -> - "Couldn't find generic argument in position " + (string i) + "Couldn't find generic argument in position " + + (string i) |> addError com ctx.InlinePath r + Any) open Helpers @@ -147,15 +173,16 @@ type BuiltinType = | BclDecimal | BclBigInt | BclHashSet of Type - | BclDictionary of key:Type * value:Type - | BclKeyValuePair of key:Type * value:Type + | BclDictionary of key: Type * value: Type + | BclKeyValuePair of key: Type * value: Type | FSharpSet of Type - | FSharpMap of key:Type * value:Type + | FSharpMap of key: Type * value: Type | FSharpChoice of Type list | FSharpResult of Type * Type | FSharpReference of Type -let (|BuiltinDefinition|_|) = function +let (|BuiltinDefinition|_|) = + function | Types.guid -> Some BclGuid | Types.timespan -> Some BclTimeSpan | Types.datetime -> Some BclDateTime @@ -168,39 +195,49 @@ let (|BuiltinDefinition|_|) = function | "Microsoft.FSharp.Core.decimal`1" -> Some BclDecimal | Types.bigint -> Some BclBigInt | Types.fsharpSet -> Some(FSharpSet(Any)) - | Types.fsharpMap -> Some(FSharpMap(Any,Any)) + | Types.fsharpMap -> Some(FSharpMap(Any, Any)) | Types.hashset -> Some(BclHashSet(Any)) - | Types.dictionary -> Some(BclDictionary(Any,Any)) - | Types.keyValuePair -> Some(BclKeyValuePair(Any,Any)) - | Types.result -> Some(FSharpResult(Any,Any)) + | Types.dictionary -> Some(BclDictionary(Any, Any)) + | Types.keyValuePair -> Some(BclKeyValuePair(Any, Any)) + | Types.result -> Some(FSharpResult(Any, Any)) | Types.reference -> Some(FSharpReference(Any)) | (Naming.StartsWith Types.choiceNonGeneric genArgs) -> - List.replicate (int genArgs.[1..]) Any |> FSharpChoice |> Some + List.replicate (int genArgs.[1..]) Any + |> FSharpChoice + |> Some | _ -> None let (|BuiltinEntity|_|) (ent: string, genArgs) = match ent, genArgs with - | BuiltinDefinition(FSharpSet _), [t] -> Some(FSharpSet(t)) - | BuiltinDefinition(FSharpMap _), [k;v] -> Some(FSharpMap(k,v)) - | BuiltinDefinition(BclHashSet _), [t] -> Some(BclHashSet(t)) - | BuiltinDefinition(BclDictionary _), [k;v] -> Some(BclDictionary(k,v)) - | BuiltinDefinition(BclKeyValuePair _), [k;v] -> Some(BclKeyValuePair(k,v)) - | BuiltinDefinition(FSharpResult _), [k;v] -> Some(FSharpResult(k,v)) - | BuiltinDefinition(FSharpReference _), [v] -> Some(FSharpReference(v)) - | BuiltinDefinition(FSharpChoice _), genArgs -> Some(FSharpChoice genArgs) + | BuiltinDefinition (FSharpSet _), [ t ] -> Some(FSharpSet(t)) + | BuiltinDefinition (FSharpMap _), [ k; v ] -> Some(FSharpMap(k, v)) + | BuiltinDefinition (BclHashSet _), [ t ] -> Some(BclHashSet(t)) + | BuiltinDefinition (BclDictionary _), [ k; v ] -> Some(BclDictionary(k, v)) + | BuiltinDefinition (BclKeyValuePair _), [ k; v ] -> Some(BclKeyValuePair(k, v)) + | BuiltinDefinition (FSharpResult _), [ k; v ] -> Some(FSharpResult(k, v)) + | BuiltinDefinition (FSharpReference _), [ v ] -> Some(FSharpReference(v)) + | BuiltinDefinition (FSharpChoice _), genArgs -> Some(FSharpChoice genArgs) | BuiltinDefinition t, _ -> Some t | _ -> None -let (|Builtin|_|) = function - | DeclaredType(ent, genArgs) -> +let (|Builtin|_|) = + function + | DeclaredType (ent, genArgs) -> match ent.FullName, genArgs with | BuiltinEntity x -> Some x | _ -> None | _ -> None -let (|Integer|Float|) = function - | Int8 | UInt8 | Int16 | UInt16 | Int32 | UInt32 -> Integer - | Float32 | Float64 -> Float +let (|Integer|Float|) = + function + | Int8 + | UInt8 + | Int16 + | UInt16 + | Int32 + | UInt32 -> Integer + | Float32 + | Float64 -> Float type NumberExtKind = | JsNumber of NumberKind @@ -208,18 +245,20 @@ type NumberExtKind = | Long of unsigned: bool | BigInt -let (|NumberExtKind|_|) = function - | Patterns.DicContains FSharp2Fable.TypeHelpers.numberTypes kind -> Some (JsNumber kind) - | Types.int64 -> Some (Long false) - | Types.uint64 -> Some (Long true) +let (|NumberExtKind|_|) = + function + | Patterns.DicContains FSharp2Fable.TypeHelpers.numberTypes kind -> Some(JsNumber kind) + | Types.int64 -> Some(Long false) + | Types.uint64 -> Some(Long true) | Types.decimal -> Some Decimal | Types.bigint -> Some BigInt | _ -> None -let (|NumberExt|_|) = function - | Number(n, _) -> Some (JsNumber n) - | Builtin BclInt64 -> Some (Long false) - | Builtin BclUInt64 -> Some (Long true) +let (|NumberExt|_|) = + function + | Number (n, _) -> Some(JsNumber n) + | Builtin BclInt64 -> Some(Long false) + | Builtin BclUInt64 -> Some(Long true) | Builtin BclDecimal -> Some Decimal | Builtin BclBigInt -> Some BigInt | _ -> None @@ -231,93 +270,114 @@ let getTypeNameFromFullName (fullname: string) = let fullname = match fullname.IndexOf("[") with | -1 -> fullname - | i -> fullname.[..i - 1] + | i -> fullname.[.. i - 1] + match fullname.LastIndexOf(".") with | -1 -> fullname | i -> fullname.Substring(i + 1) let getTypeName com (ctx: Context) r t = match t with - | GenericParam(name,_) -> + | GenericParam (name, _) -> genericTypeInfoError name |> addError com ctx.InlinePath r | _ -> () + getTypeFullName false t |> getTypeNameFromFullName let rec namesof com ctx acc e = match acc, e with - | acc, Get(e, ExprGet(StringConst prop), _, _) -> namesof com ctx (prop::acc) e - | acc, Get(e, FieldGet(fieldName, _), _, _) -> namesof com ctx (fieldName::acc) e - | [], IdentExpr ident -> ident.DisplayName::acc |> Some - | [], NestedLambda(args, Call(IdentExpr ident, info, _, _), None) -> - if List.sameLength args info.Args && List.zip args info.Args |> List.forall (fun (a1, a2) -> - match a2 with IdentExpr id2 -> a1.Name = id2.Name | _ -> false) - then ident.DisplayName::acc |> Some - else None - | [], Value(TypeInfo t, r) -> (getTypeName com ctx r t)::acc |> Some + | acc, Get (e, ExprGet (StringConst prop), _, _) -> namesof com ctx (prop :: acc) e + | acc, Get (e, FieldGet (fieldName, _), _, _) -> namesof com ctx (fieldName :: acc) e + | [], IdentExpr ident -> ident.DisplayName :: acc |> Some + | [], NestedLambda (args, Call (IdentExpr ident, info, _, _), None) -> + if List.sameLength args info.Args + && List.zip args info.Args + |> List.forall (fun (a1, a2) -> + match a2 with + | IdentExpr id2 -> a1.Name = id2.Name + | _ -> false) then + ident.DisplayName :: acc |> Some + else + None + | [], Value (TypeInfo t, r) -> (getTypeName com ctx r t) :: acc |> Some | [], _ -> None | acc, _ -> Some acc let (|Namesof|_|) com ctx e = namesof com ctx [] e let (|Nameof|_|) com ctx e = namesof com ctx [] e |> Option.bind List.tryLast -let (|ReplaceName|_|) (namesAndReplacements: (string*string) list) name = - namesAndReplacements |> List.tryPick (fun (name2, replacement) -> - if name2 = name then Some replacement else None) +let (|ReplaceName|_|) (namesAndReplacements: (string * string) list) name = + namesAndReplacements + |> List.tryPick (fun (name2, replacement) -> + if name2 = name then + Some replacement + else + None) -let (|OrDefault|) (def:'T) = function +let (|OrDefault|) (def: 'T) = + function | Some v -> v | None -> def let (|EntFullName|_|) (typ: Type) = match typ with - | DeclaredType(ent, _) -> Some ent.FullName + | DeclaredType (ent, _) -> Some ent.FullName | _ -> None let (|ListLiteral|_|) e = - let rec untail t acc = function - | Value(NewList(None, _),_) -> Some(List.rev acc, t) - | Value(NewList(Some(head, tail), _),_) -> untail t (head::acc) tail + let rec untail t acc = + function + | Value (NewList (None, _), _) -> Some(List.rev acc, t) + | Value (NewList (Some (head, tail), _), _) -> untail t (head :: acc) tail | _ -> None + match e with - | NewList(None, t) -> Some([], t) - | NewList(Some(head, tail), t) -> untail t [head] tail + | NewList (None, t) -> Some([], t) + | NewList (Some (head, tail), t) -> untail t [ head ] tail | _ -> None -let (|ArrayOrListLiteral|_|) = function - | MaybeCasted(Value((NewArray(vals, t)|ListLiteral(vals, t)),_)) -> Some(vals, t) +let (|ArrayOrListLiteral|_|) = + function + | MaybeCasted (Value ((NewArray (vals, t) + | ListLiteral (vals, t)), + _)) -> Some(vals, t) | _ -> None -let (|IDictionary|IEqualityComparer|Other|) = function - | DeclaredType(ent,_) -> +let (|IDictionary|IEqualityComparer|Other|) = + function + | DeclaredType (ent, _) -> match ent.FullName with | Types.idictionary -> IDictionary | Types.equalityComparer -> IEqualityComparer | _ -> Other | _ -> Other -let (|IEnumerable|IEqualityComparer|Other|) = function - | DeclaredType(ent,_) -> +let (|IEnumerable|IEqualityComparer|Other|) = + function + | DeclaredType (ent, _) -> match ent.FullName with | Types.ienumerableGeneric -> IEnumerable | Types.equalityComparer -> IEqualityComparer | _ -> Other | _ -> Other -let (|NewAnonymousRecord|_|) = function +let (|NewAnonymousRecord|_|) = + function // The F# compiler may create some bindings of expression arguments to fix https://github.com/dotnet/fsharp/issues/6487 - | NestedRevLets(bindings, Value(NewAnonymousRecord(exprs, fieldNames, genArgs), r)) -> + | NestedRevLets (bindings, Value (NewAnonymousRecord (exprs, fieldNames, genArgs), r)) -> Some(List.rev bindings, exprs, fieldNames, genArgs, r) - | Value(NewAnonymousRecord(exprs, fieldNames, genArgs), r) -> - Some([], exprs, fieldNames, genArgs, r) + | Value (NewAnonymousRecord (exprs, fieldNames, genArgs), r) -> Some([], exprs, fieldNames, genArgs, r) | _ -> None -let coreModFor = function +let coreModFor = + function | BclGuid -> "guid" | BclDateTime -> "date" | BclDateTimeOffset -> "date_offset" | BclTimer -> "timer" - | BclInt64 | BclUInt64 -> "long" + | BclInt64 + | BclUInt64 -> "long" | BclDecimal -> "decimal" | BclBigInt -> "big_int" | BclTimeSpan -> "time_span" @@ -335,21 +395,32 @@ let makeUniqueIdent ctx t name = |> makeTypedIdent t let makeLongInt com r t signed (x: uint64) = - let lowBits = NumberConstant (float (uint32 x), Float64, None) - let highBits = NumberConstant (float (x >>> 32), Float64, None) - let unsigned = BoolConstant (not signed) - let args = [makeValue None lowBits; makeValue None highBits; makeValue None unsigned] - Helper.LibCall(com, "long", "fromBits", t, args, ?loc=r) + let lowBits = NumberConstant(float (uint32 x), Float64, None) + let highBits = NumberConstant(float (x >>> 32), Float64, None) + let unsigned = BoolConstant(not signed) + + let args = + [ makeValue None lowBits; makeValue None highBits; makeValue None unsigned ] + + Helper.LibCall(com, "long", "fromBits", t, args, ?loc = r) let makeDecimal com r t (x: decimal) = - let str = x.ToString(System.Globalization.CultureInfo.InvariantCulture) - Helper.LibCall(com, "decimal", "Decimal", t, [makeStrConst str], isPyConstructor=true, ?loc=r) + let str = + x.ToString(System.Globalization.CultureInfo.InvariantCulture) + + Helper.LibCall(com, "decimal", "Decimal", t, [ makeStrConst str ], isPyConstructor = true, ?loc = r) let makeDecimalFromExpr com r t (e: Expr) = - Helper.LibCall(com, "decimal", "Decimal", t, [e], isPyConstructor=true, ?loc=r) + Helper.LibCall(com, "decimal", "Decimal", t, [ e ], isPyConstructor = true, ?loc = r) let makeFloat32 r (x: float32) = - Helper.GlobalCall("math", Number(Float32, None), [NumberConstant (float x, Float32, None) |> makeValue r], memb="fround") + Helper.GlobalCall( + "math", + Number(Float32, None), + [ NumberConstant(float x, Float32, None) + |> makeValue r ], + memb = "fround" + ) let makeTypeConst com r (typ: Type) (value: obj) = match typ, value with @@ -362,73 +433,131 @@ let makeTypeConst com r (typ: Type) (value: obj) = | String, (:? string as x) -> StringConstant x |> makeValue r | Char, (:? char as x) -> CharConstant x |> makeValue r // Integer types - | Number(UInt8, uom), (:? byte as x) -> NumberConstant(float x, UInt8, uom) |> makeValue r - | Number(Int8, uom), (:? sbyte as x) -> NumberConstant(float x, Int8, uom) |> makeValue r - | Number(Int16, uom), (:? int16 as x) -> NumberConstant(float x, Int16, uom) |> makeValue r - | Number(UInt16, uom), (:? uint16 as x) -> NumberConstant(float x, UInt16, uom) |> makeValue r - | Number(Int32, uom), (:? int as x) -> NumberConstant(float x, Int32, uom) |> makeValue r - | Number(UInt32, uom), (:? uint32 as x) -> NumberConstant(float x, UInt32, uom) |> makeValue r + | Number (UInt8, uom), (:? byte as x) -> NumberConstant(float x, UInt8, uom) |> makeValue r + | Number (Int8, uom), (:? sbyte as x) -> NumberConstant(float x, Int8, uom) |> makeValue r + | Number (Int16, uom), (:? int16 as x) -> NumberConstant(float x, Int16, uom) |> makeValue r + | Number (UInt16, uom), (:? uint16 as x) -> + NumberConstant(float x, UInt16, uom) + |> makeValue r + | Number (Int32, uom), (:? int as x) -> NumberConstant(float x, Int32, uom) |> makeValue r + | Number (UInt32, uom), (:? uint32 as x) -> + NumberConstant(float x, UInt32, uom) + |> makeValue r // Float types - | Number(Float32, uom), (:? float32 as x) -> NumberConstant(float x, Float32, uom) |> makeValue r - | Number(Float64, uom), (:? float as x) -> NumberConstant(float x, Float64, uom) |> makeValue r + | Number (Float32, uom), (:? float32 as x) -> + NumberConstant(float x, Float32, uom) + |> makeValue r + | Number (Float64, uom), (:? float as x) -> + NumberConstant(float x, Float64, uom) + |> makeValue r // Enums | Enum _, (:? int64) | Enum _, (:? uint64) -> failwith "int64 enums are not supported" - | Enum e, (:? byte as x) -> EnumConstant(NumberConstant(float x, UInt8, None) |> makeValue None, e) |> makeValue r - | Enum e, (:? sbyte as x) -> EnumConstant(NumberConstant(float x, Int8, None) |> makeValue None, e) |> makeValue r - | Enum e, (:? int16 as x) -> EnumConstant(NumberConstant(float x, Int16, None) |> makeValue None, e) |> makeValue r - | Enum e, (:? uint16 as x) -> EnumConstant(NumberConstant(float x, UInt16, None) |> makeValue None, e) |> makeValue r - | Enum e, (:? int as x) -> EnumConstant(NumberConstant(float x, Int32, None) |> makeValue None, e) |> makeValue r - | Enum e, (:? uint32 as x) -> EnumConstant(NumberConstant(float x, UInt32, None) |> makeValue None, e) |> makeValue r + | Enum e, (:? byte as x) -> + EnumConstant( + NumberConstant(float x, UInt8, None) + |> makeValue None, + e + ) + |> makeValue r + | Enum e, (:? sbyte as x) -> + EnumConstant( + NumberConstant(float x, Int8, None) + |> makeValue None, + e + ) + |> makeValue r + | Enum e, (:? int16 as x) -> + EnumConstant( + NumberConstant(float x, Int16, None) + |> makeValue None, + e + ) + |> makeValue r + | Enum e, (:? uint16 as x) -> + EnumConstant( + NumberConstant(float x, UInt16, None) + |> makeValue None, + e + ) + |> makeValue r + | Enum e, (:? int as x) -> + EnumConstant( + NumberConstant(float x, Int32, None) + |> makeValue None, + e + ) + |> makeValue r + | Enum e, (:? uint32 as x) -> + EnumConstant( + NumberConstant(float x, UInt32, None) + |> makeValue None, + e + ) + |> makeValue r // TODO: Regex | Unit, _ -> UnitConstant |> makeValue r // Arrays with small data type (ushort, byte) are represented // in F# AST as BasicPatterns.Const - | Array (Number(kind, uom)), (:? (byte[]) as arr) -> - let values = arr |> Array.map (fun x -> NumberConstant (float x, kind, uom) |> makeValue None) |> Seq.toList - NewArray (values, Number(kind, uom)) |> makeValue r - | Array (Number(kind, uom)), (:? (uint16[]) as arr) -> - let values = arr |> Array.map (fun x -> NumberConstant (float x, kind, uom) |> makeValue None) |> Seq.toList - NewArray (values, Number(kind, uom)) |> makeValue r + | Array (Number (kind, uom)), (:? (byte []) as arr) -> + let values = + arr + |> Array.map (fun x -> + NumberConstant(float x, kind, uom) + |> makeValue None) + |> Seq.toList + + NewArray(values, Number(kind, uom)) |> makeValue r + | Array (Number (kind, uom)), (:? (uint16 []) as arr) -> + let values = + arr + |> Array.map (fun x -> + NumberConstant(float x, kind, uom) + |> makeValue None) + |> Seq.toList + + NewArray(values, Number(kind, uom)) |> makeValue r | _ -> failwithf "Unexpected type %A for literal %O (%s)" typ value (value.GetType().FullName) -let makeTypeInfo r t = - TypeInfo t |> makeValue r +let makeTypeInfo r t = TypeInfo t |> makeValue r let makeTypeDefinitionInfo r t = let t = match t with - | Option(_, isStruct) -> Option(Any, isStruct) + | Option (_, isStruct) -> Option(Any, isStruct) | Array _ -> Array Any | List _ -> List Any - | Tuple(genArgs, isStruct) -> - Tuple(genArgs |> List.map (fun _ -> Any), isStruct) - | DeclaredType(ent, genArgs) -> + | Tuple (genArgs, isStruct) -> Tuple(genArgs |> List.map (fun _ -> Any), isStruct) + | DeclaredType (ent, genArgs) -> let genArgs = genArgs |> List.map (fun _ -> Any) DeclaredType(ent, genArgs) // TODO: Do something with FunctionType and ErasedUnion? | t -> t + TypeInfo t |> makeValue r let createAtom com (value: Expr) = let typ = value.Type - Helper.LibCall(com, "util", "createAtom", typ, [value], [typ]) + Helper.LibCall(com, "util", "createAtom", typ, [ value ], [ typ ]) let makeRefFromMutableValue com ctx r t (value: Expr) = - let getter = - Delegate([], value, None) + let getter = Delegate([], value, None) + let setter = let v = makeUniqueIdent ctx t "v" - Delegate([v], Set(value, ValueSet, t, IdentExpr v, None), None) - Helper.LibCall(com, "types", "FSharpRef", t, [getter; setter], isPyConstructor=true) + Delegate([ v ], Set(value, ValueSet, t, IdentExpr v, None), None) + + Helper.LibCall(com, "types", "FSharpRef", t, [ getter; setter ], isPyConstructor = true) let makeRefFromMutableField com ctx r t callee key = let getter = Delegate([], Get(callee, FieldGet(key, true), t, r), None) + let setter = let v = makeUniqueIdent ctx t "v" - Delegate([v], Set(callee, FieldSet(key), t, IdentExpr v, r), None) - Helper.LibCall(com, "types", "FSharpRef", t, [getter; setter], isPyConstructor=true) + Delegate([ v ], Set(callee, FieldSet(key), t, IdentExpr v, r), None) + + Helper.LibCall(com, "types", "FSharpRef", t, [ getter; setter ], isPyConstructor = true) // Mutable and public module values are compiled as functions, because // values imported from ES2015 modules cannot be modified (see #986) @@ -437,13 +566,15 @@ let makeRefFromMutableFunc com ctx r t (value: Expr) = let info = makeCallInfo None [] [] let value = makeCall r t info value Delegate([], value, None) + let setter = let v = makeUniqueIdent ctx t "v" - let args = [IdentExpr v; makeBoolConst true] - let info = makeCallInfo None args [t; Boolean] + let args = [ IdentExpr v; makeBoolConst true ] + let info = makeCallInfo None args [ t; Boolean ] let value = makeCall r Unit info value - Delegate([v], value, None) - Helper.LibCall(com, "types", "FSharpRef", t, [getter; setter], isPyConstructor=true) + Delegate([ v ], value, None) + + Helper.LibCall(com, "types", "FSharpRef", t, [ getter; setter ], isPyConstructor = true) // let turnLastArgIntoRef com ctx args = // let args, defValue = List.splitLast args @@ -451,35 +582,37 @@ let makeRefFromMutableFunc com ctx r t (value: Expr) = let toChar (arg: Expr) = match arg.Type with - | Char | String -> arg - | _ -> Helper.GlobalCall("chr", Char, [arg]) + | Char + | String -> arg + | _ -> Helper.GlobalCall("chr", Char, [ arg ]) let toString com (ctx: Context) r (args: Expr list) = match args with | [] -> "toString is called with empty args" |> addErrorAndReturnNull com ctx.InlinePath r - | head::tail -> + | head :: tail -> match head.Type with - | Char | String -> head - | Builtin BclGuid when tail.IsEmpty -> - Helper.GlobalCall("str", String, [ head ], ?loc=r) - | Builtin (BclGuid|BclTimeSpan|BclDecimal as bt) -> - Helper.LibCall(com, coreModFor bt, "toString", String, args) - | Builtin (BclInt64|BclUInt64|BclBigInt) -> - Helper.LibCall(com, "util", "int64_to_string", String, args) - | Number(Int8,_) - | Number(UInt8,_) -> - Helper.LibCall(com, "util", "int8_to_string", String, args) - | Number(Int16,_) -> Helper.LibCall(com, "util", "int16_to_string", String, args) - | Number(Int32,_) -> Helper.LibCall(com, "util", "int32_to_string", String, args) - | Number _ -> Helper.LibCall(com, "types", "toString", String, [head], ?loc=r) - | Array _ | List _ -> - Helper.LibCall(com, "types", "seqToString", String, [head], ?loc=r) + | Char + | String -> head + | Builtin BclGuid when tail.IsEmpty -> Helper.GlobalCall("str", String, [ head ], ?loc = r) + | Builtin (BclGuid + | BclTimeSpan + | BclDecimal as bt) -> Helper.LibCall(com, coreModFor bt, "toString", String, args) + | Builtin (BclInt64 + | BclUInt64 + | BclBigInt) -> Helper.LibCall(com, "util", "int64_to_string", String, args) + | Number (Int8, _) + | Number (UInt8, _) -> Helper.LibCall(com, "util", "int8_to_string", String, args) + | Number (Int16, _) -> Helper.LibCall(com, "util", "int16_to_string", String, args) + | Number (Int32, _) -> Helper.LibCall(com, "util", "int32_to_string", String, args) + | Number _ -> Helper.LibCall(com, "types", "toString", String, [ head ], ?loc = r) + | Array _ + | List _ -> Helper.LibCall(com, "types", "seqToString", String, [ head ], ?loc = r) // | DeclaredType(ent, _) when ent.IsFSharpUnion || ent.IsFSharpRecord || ent.IsValueType -> // Helper.InstanceCall(head, "toString", String, [], ?loc=r) // | DeclaredType(ent, _) -> - | _ -> Helper.LibCall(com, "types", "toString", String, [head], ?loc=r) + | _ -> Helper.LibCall(com, "types", "toString", String, [ head ], ?loc = r) let getParseParams (kind: NumberExtKind) = let isFloatOrDecimal, numberModule, unsigned, bitsize = @@ -495,6 +628,7 @@ let getParseParams (kind: NumberExtKind) = | Long unsigned -> false, "Long", unsigned, 64 | Decimal -> true, "Decimal", false, 128 | x -> failwithf "Unexpected kind in getParseParams: %A" x + isFloatOrDecimal, numberModule, unsigned, bitsize let castBigIntMethod typeTo = @@ -507,37 +641,43 @@ let castBigIntMethod typeTo = | JsNumber UInt8 -> "toByte" | JsNumber UInt16 -> "toUInt16" | JsNumber UInt32 -> "toUInt32" - | Long unsigned -> if unsigned then "toUInt64" else "toInt64" + | Long unsigned -> + if unsigned then + "toUInt64" + else + "toInt64" | JsNumber Float32 -> "toSingle" | JsNumber Float64 -> "toDouble" | Decimal -> "toDecimal" | BigInt -> failwith "Unexpected bigint-bigint conversion" | _ -> failwithf "Unexpected non-number type %A" typeTo -let kindIndex t = // 0 1 2 3 4 5 6 7 8 9 10 11 - match t with // i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 dec big - | JsNumber Int8 -> 0 // 0 i8 - - - - + + + + - - - + - | JsNumber Int16 -> 1 // 1 i16 + - - - + + + + - - - + - | JsNumber Int32 -> 2 // 2 i32 + + - - + + + + - - - + - | Long false -> 3 // 3 i64 + + + - + + + + - - - + - | JsNumber UInt8 -> 4 // 4 u8 + + + + - - - - - - - + - | JsNumber UInt16 -> 5 // 5 u16 + + + + + - - - - - - + - | JsNumber UInt32 -> 6 // 6 u32 + + + + + + - - - - - + - | Long true -> 7 // 7 u64 + + + + + + + - - - - + +let kindIndex t = // 0 1 2 3 4 5 6 7 8 9 10 11 + match t with // i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 dec big + | JsNumber Int8 -> 0 // 0 i8 - - - - + + + + - - - + + | JsNumber Int16 -> 1 // 1 i16 + - - - + + + + - - - + + | JsNumber Int32 -> 2 // 2 i32 + + - - + + + + - - - + + | Long false -> 3 // 3 i64 + + + - + + + + - - - + + | JsNumber UInt8 -> 4 // 4 u8 + + + + - - - - - - - + + | JsNumber UInt16 -> 5 // 5 u16 + + + + + - - - - - - + + | JsNumber UInt32 -> 6 // 6 u32 + + + + + + - - - - - + + | Long true -> 7 // 7 u64 + + + + + + + - - - - + | JsNumber Float32 -> 8 // 8 f32 + + + + + + + + - - - + | JsNumber Float64 -> 9 // 9 f64 + + + + + + + + - - - + - | Decimal -> 10 // 10 dec + + + + + + + + - - - + - | BigInt -> 11 // 11 big + + + + + + + + + + + - + | Decimal -> 10 // 10 dec + + + + + + + + - - - + + | BigInt -> 11 // 11 big + + + + + + + + + + + - let needToCast typeFrom typeTo = let v = kindIndex typeFrom // argument type (vertical) - let h = kindIndex typeTo // return type (horizontal) - ((v > h) || (v < 4 && h > 3)) && (h < 8) || (h <> v && (h = 11 || v = 11)) + let h = kindIndex typeTo // return type (horizontal) + + ((v > h) || (v < 4 && h > 3)) && (h < 8) + || (h <> v && (h = 11 || v = 11)) /// Conversions to floating point -let toFloat com (ctx: Context) r targetType (args: Expr list): Expr = +let toFloat com (ctx: Context) r targetType (args: Expr list) : Expr = match args.Head.Type with - | Char -> Helper.InstanceCall(args.Head, "charCodeAt", Number(Int32, None), [makeIntConst 0]) + | Char -> Helper.InstanceCall(args.Head, "charCodeAt", Number(Int32, None), [ makeIntConst 0 ]) | String -> Helper.LibCall(com, "double", "parse", targetType, args) | NumberExt kind -> match kind with @@ -550,17 +690,18 @@ let toFloat com (ctx: Context) r targetType (args: Expr list): Expr = addWarning com ctx.InlinePath r "Cannot make conversion because source type is unknown" TypeCast(args.Head, targetType) -let toDecimal com (ctx: Context) r targetType (args: Expr list): Expr = +let toDecimal com (ctx: Context) r targetType (args: Expr list) : Expr = match args.Head.Type with | Char -> - Helper.InstanceCall(args.Head, "charCodeAt", Number(Int32, None), [makeIntConst 0]) + Helper.InstanceCall(args.Head, "charCodeAt", Number(Int32, None), [ makeIntConst 0 ]) |> makeDecimalFromExpr com r targetType | String -> makeDecimalFromExpr com r targetType args.Head | NumberExt kind -> match kind with | BigInt -> Helper.LibCall(com, "big_int", castBigIntMethod targetType, targetType, args) - | Long _ -> Helper.LibCall(com, "long", "toNumber", Number(Float64, None), args) - |> makeDecimalFromExpr com r targetType + | Long _ -> + Helper.LibCall(com, "long", "toNumber", Number(Float64, None), args) + |> makeDecimalFromExpr com r targetType | Decimal -> args.Head | JsNumber _ -> makeDecimalFromExpr com r targetType args.Head | Enum _ -> makeDecimalFromExpr com r targetType args.Head @@ -573,36 +714,45 @@ let fastIntFloor expr = let inner = makeUnOp None Any expr UnaryNotBitwise makeUnOp None (Number(Int32, None)) inner UnaryNotBitwise -let stringToInt com (ctx: Context) r targetType (args: Expr list): Expr = +let stringToInt com (ctx: Context) r targetType (args: Expr list) : Expr = let kind = match targetType with | NumberExt kind -> kind | x -> failwithf "Unexpected type in stringToInt: %A" x + let style = int System.Globalization.NumberStyles.Any - let _isFloatOrDecimal, numberModule, unsigned, bitsize = getParseParams kind - let parseArgs = [makeIntConst style; makeBoolConst unsigned; makeIntConst bitsize] - Helper.LibCall(com, numberModule, "parse", targetType, - [args.Head] @ parseArgs @ args.Tail, ?loc=r) -let toLong com (ctx: Context) r (unsigned: bool) targetType (args: Expr list): Expr = + let _isFloatOrDecimal, numberModule, unsigned, bitsize = + getParseParams kind + + let parseArgs = + [ makeIntConst style; makeBoolConst unsigned; makeIntConst bitsize ] + + Helper.LibCall(com, numberModule, "parse", targetType, [ args.Head ] @ parseArgs @ args.Tail, ?loc = r) + +let toLong com (ctx: Context) r (unsigned: bool) targetType (args: Expr list) : Expr = let fromInteger kind arg = let kind = makeIntConst (kindIndex (JsNumber kind)) - Helper.LibCall(com, "long", "fromInteger", targetType, [arg; makeBoolConst unsigned; kind]) + Helper.LibCall(com, "long", "fromInteger", targetType, [ arg; makeBoolConst unsigned; kind ]) + let sourceType = args.Head.Type + match sourceType with | Char -> - Helper.InstanceCall(args.Head, "charCodeAt", Number(Int32, None), [makeIntConst 0]) + Helper.InstanceCall(args.Head, "charCodeAt", Number(Int32, None), [ makeIntConst 0 ]) |> fromInteger UInt16 | String -> stringToInt com ctx r targetType args | NumberExt kind -> match kind with | BigInt -> Helper.LibCall(com, "big_int", castBigIntMethod targetType, targetType, args) - | Long _ -> Helper.LibCall(com, "long", "fromValue", targetType, args @ [makeBoolConst unsigned]) + | Long _ -> Helper.LibCall(com, "long", "fromValue", targetType, args @ [ makeBoolConst unsigned ]) | Decimal -> - let n = Helper.LibCall(com, "decimal", "toNumber", Number(Float64, None), args) - Helper.LibCall(com, "long", "fromNumber", targetType, [n; makeBoolConst unsigned]) + let n = + Helper.LibCall(com, "decimal", "toNumber", Number(Float64, None), args) + + Helper.LibCall(com, "long", "fromNumber", targetType, [ n; makeBoolConst unsigned ]) | JsNumber (Integer as kind) -> fromInteger kind args.Head - | JsNumber Float -> Helper.LibCall(com, "long", "fromNumber", targetType, args @ [makeBoolConst unsigned]) + | JsNumber Float -> Helper.LibCall(com, "long", "fromNumber", targetType, args @ [ makeBoolConst unsigned ]) | Enum _ -> fromInteger Int32 args.Head | _ -> addWarning com ctx.InlinePath r "Cannot make conversion because source type is unknown" @@ -610,30 +760,37 @@ let toLong com (ctx: Context) r (unsigned: bool) targetType (args: Expr list): E /// Conversion to integers (excluding longs and bigints) let toInt com (ctx: Context) r targetType (args: Expr list) = - let transformEnumType = function Enum _ -> Number(Int32, None) | t -> t + let transformEnumType = + function + | Enum _ -> Number(Int32, None) + | t -> t + let sourceType = transformEnumType args.Head.Type let targetType = transformEnumType targetType + let emitCast typeTo arg = match typeTo with - | JsNumber Int8 -> emitJsExpr None (Number(Int8, None)) [arg] "(int($0) + 0x80 & 0xFF) - 0x80" - | JsNumber Int16 -> emitJsExpr None (Number(Int16, None)) [arg] "(int($0) + 0x8000 & 0xFFFF) - 0x8000" + | JsNumber Int8 -> emitJsExpr None (Number(Int8, None)) [ arg ] "(int($0) + 0x80 & 0xFF) - 0x80" + | JsNumber Int16 -> emitJsExpr None (Number(Int16, None)) [ arg ] "(int($0) + 0x8000 & 0xFFFF) - 0x8000" | JsNumber Int32 -> fastIntFloor arg - | JsNumber UInt8 -> emitJsExpr None (Number(UInt8, None)) [arg] "int($0+0x100 if $0 < 0 else $0) & 0xFF" - | JsNumber UInt16 -> emitJsExpr None (Number(UInt16, None)) [arg] "int($0+0x10000 if $0 < 0 else $0) & 0xFFFF" - | JsNumber UInt32 -> emitJsExpr None (Number(UInt32, None)) [arg] "int($0+0x100000000 if $0 < 0 else $0)" + | JsNumber UInt8 -> emitJsExpr None (Number(UInt8, None)) [ arg ] "int($0+0x100 if $0 < 0 else $0) & 0xFF" + | JsNumber UInt16 -> emitJsExpr None (Number(UInt16, None)) [ arg ] "int($0+0x10000 if $0 < 0 else $0) & 0xFFFF" + | JsNumber UInt32 -> emitJsExpr None (Number(UInt32, None)) [ arg ] "int($0+0x100000000 if $0 < 0 else $0)" | _ -> failwithf "Unexpected non-integer type %A" typeTo + match sourceType, targetType with - | Char, _ -> Helper.InstanceCall(args.Head, "charCodeAt", targetType, [makeIntConst 0]) + | Char, _ -> Helper.InstanceCall(args.Head, "charCodeAt", targetType, [ makeIntConst 0 ]) | String, _ -> stringToInt com ctx r targetType args | Builtin BclBigInt, _ -> Helper.LibCall(com, "big_int", castBigIntMethod targetType, targetType, args) - | NumberExt typeFrom, NumberExt typeTo -> + | NumberExt typeFrom, NumberExt typeTo -> if needToCast typeFrom typeTo then match typeFrom with | Long _ -> Helper.LibCall(com, "Long", "to_int", targetType, args) // TODO: make no-op | Decimal -> Helper.LibCall(com, "Decimal", "to_number", targetType, args) | _ -> args.Head |> emitCast typeTo - else TypeCast(args.Head, targetType) + else + TypeCast(args.Head, targetType) | _ -> addWarning com ctx.InlinePath r "Cannot make conversion because source type is unknown" TypeCast(args.Head, targetType) @@ -641,28 +798,33 @@ let toInt com (ctx: Context) r targetType (args: Expr list) = let round com (args: Expr list) = match args.Head.Type with | Builtin BclDecimal -> - let n = Helper.LibCall(com, "decimal", "toNumber", Number(Float64, None), [args.Head]) - let rounded = Helper.LibCall(com, "util", "round", Number(Float64, None), [n]) - rounded::args.Tail - | Number(Float,_) -> - let rounded = Helper.LibCall(com, "util", "round", Number(Float64, None), [args.Head]) - rounded::args.Tail + let n = + Helper.LibCall(com, "decimal", "toNumber", Number(Float64, None), [ args.Head ]) + + let rounded = + Helper.LibCall(com, "util", "round", Number(Float64, None), [ n ]) + + rounded :: args.Tail + | Number (Float, _) -> + let rounded = + Helper.LibCall(com, "util", "round", Number(Float64, None), [ args.Head ]) + + rounded :: args.Tail | _ -> args -let toList com returnType expr = - Helper.LibCall(com, "list", "ofSeq", returnType, [expr]) +let toList com returnType expr = Helper.LibCall(com, "list", "ofSeq", returnType, [ expr ]) let toArray r t expr = let t = match t with | Array t // This is used also by Seq.cache, which returns `'T seq` instead of `'T array` - | DeclaredType(_, [t]) -> t + | DeclaredType (_, [ t ]) -> t | t -> t + Value(NewArrayFrom(expr, t), r) -let stringToCharArray t e = - Helper.InstanceCall(e, "split", t, [makeStrConst ""]) +let stringToCharArray t e = Helper.InstanceCall(e, "split", t, [ makeStrConst "" ]) let toSeq t (e: Expr) = match e.Type with @@ -670,100 +832,139 @@ let toSeq t (e: Expr) = | String -> stringToCharArray t e | _ -> TypeCast(e, t) -let (|ListSingleton|) x = [x] +let (|ListSingleton|) x = [ x ] let rec findInScope (scope: FSharp2Fable.Scope) identName = match scope with | [] -> None - | (_,ident2,expr)::prevScope -> + | (_, ident2, expr) :: prevScope -> if identName = ident2.Name then match expr with - | Some(MaybeCasted(IdentExpr ident)) when not ident.IsMutable -> findInScope prevScope ident.Name + | Some (MaybeCasted (IdentExpr ident)) when not ident.IsMutable -> findInScope prevScope ident.Name | expr -> expr - else findInScope prevScope identName + else + findInScope prevScope identName let (|CustomOp|_|) (com: ICompiler) (ctx: Context) opName argTypes sourceTypes = - sourceTypes |> List.tryPick (function - | DeclaredType(ent,_) -> + sourceTypes + |> List.tryPick (function + | DeclaredType (ent, _) -> let ent = com.GetEntity(ent) FSharp2Fable.TypeHelpers.tryFindMember com ent ctx.GenericArgs opName false argTypes | _ -> None) let applyOp (com: ICompiler) (ctx: Context) r t opName (args: Expr list) argTypes genArgs = - let unOp operator operand = - Operation(Unary(operator, operand), t, r) - let binOp op left right = - Operation(Binary(op, left, right), t, r) + let unOp operator operand = Operation(Unary(operator, operand), t, r) + let binOp op left right = Operation(Binary(op, left, right), t, r) + let truncateUnsigned operation = // see #1550 match t with - | Number(UInt32,_) -> - Operation(Binary(BinaryShiftRightZeroFill,operation,makeIntConst 0), t, r) + | Number (UInt32, _) -> Operation(Binary(BinaryShiftRightZeroFill, operation, makeIntConst 0), t, r) | _ -> operation - let logicOp op left right = - Operation(Logical(op, left, right), Boolean, r) + + let logicOp op left right = Operation(Logical(op, left, right), Boolean, r) + let nativeOp opName argTypes args = match opName, args with - | Operators.addition, [left; right] -> binOp BinaryPlus left right - | Operators.subtraction, [left; right] -> binOp BinaryMinus left right - | Operators.multiply, [left; right] -> binOp BinaryMultiply left right - | (Operators.division | Operators.divideByInt), [left; right] -> + | Operators.addition, [ left; right ] -> binOp BinaryPlus left right + | Operators.subtraction, [ left; right ] -> binOp BinaryMinus left right + | Operators.multiply, [ left; right ] -> binOp BinaryMultiply left right + | (Operators.division + | Operators.divideByInt), + [ left; right ] -> match argTypes with // Floor result of integer divisions (see #172) - | Number(Integer,_)::_ -> binOp BinaryDivide left right |> fastIntFloor + | Number (Integer, _) :: _ -> binOp BinaryDivide left right |> fastIntFloor | _ -> binOp BinaryDivide left right - | Operators.modulus, [left; right] -> binOp BinaryModulus left right - | Operators.leftShift, [left; right] -> binOp BinaryShiftLeft left right |> truncateUnsigned // See #1530 - | Operators.rightShift, [left; right] -> + | Operators.modulus, [ left; right ] -> binOp BinaryModulus left right + | Operators.leftShift, [ left; right ] -> + binOp BinaryShiftLeft left right + |> truncateUnsigned // See #1530 + | Operators.rightShift, [ left; right ] -> match argTypes with - | Number(UInt32,_)::_ -> binOp BinaryShiftRightZeroFill left right // See #646 + | Number (UInt32, _) :: _ -> binOp BinaryShiftRightZeroFill left right // See #646 | _ -> binOp BinaryShiftRightSignPropagating left right - | Operators.bitwiseAnd, [left; right] -> binOp BinaryAndBitwise left right |> truncateUnsigned - | Operators.bitwiseOr, [left; right] -> binOp BinaryOrBitwise left right |> truncateUnsigned - | Operators.exclusiveOr, [left; right] -> binOp BinaryXorBitwise left right |> truncateUnsigned - | Operators.booleanAnd, [left; right] -> logicOp LogicalAnd left right - | Operators.booleanOr, [left; right] -> logicOp LogicalOr left right - | Operators.logicalNot, [operand] -> unOp UnaryNotBitwise operand |> truncateUnsigned - | Operators.unaryNegation, [operand] -> + | Operators.bitwiseAnd, [ left; right ] -> + binOp BinaryAndBitwise left right + |> truncateUnsigned + | Operators.bitwiseOr, [ left; right ] -> + binOp BinaryOrBitwise left right + |> truncateUnsigned + | Operators.exclusiveOr, [ left; right ] -> + binOp BinaryXorBitwise left right + |> truncateUnsigned + | Operators.booleanAnd, [ left; right ] -> logicOp LogicalAnd left right + | Operators.booleanOr, [ left; right ] -> logicOp LogicalOr left right + | Operators.logicalNot, [ operand ] -> unOp UnaryNotBitwise operand |> truncateUnsigned + | Operators.unaryNegation, [ operand ] -> match argTypes with - | Number(Int8,_)::_ -> Helper.LibCall(com, "int32", "op_UnaryNegation_Int8", t, args, ?loc=r) - | Number(Int16,_)::_ -> Helper.LibCall(com, "int32", "op_UnaryNegation_Int16", t, args, ?loc=r) - | Number(Int32,_)::_ -> Helper.LibCall(com, "int32", "op_UnaryNegation_Int32", t, args, ?loc=r) + | Number (Int8, _) :: _ -> Helper.LibCall(com, "int32", "op_UnaryNegation_Int8", t, args, ?loc = r) + | Number (Int16, _) :: _ -> Helper.LibCall(com, "int32", "op_UnaryNegation_Int16", t, args, ?loc = r) + | Number (Int32, _) :: _ -> Helper.LibCall(com, "int32", "op_UnaryNegation_Int32", t, args, ?loc = r) | _ -> unOp UnaryMinus operand - | _ -> sprintf "Operator %s not found in %A" opName argTypes - |> addErrorAndReturnNull com ctx.InlinePath r + | _ -> + sprintf "Operator %s not found in %A" opName argTypes + |> addErrorAndReturnNull com ctx.InlinePath r + let argTypes = resolveArgTypes argTypes genArgs + match argTypes with - | Builtin (BclInt64|BclUInt64|BclDecimal|BclBigInt|BclDateTime|BclDateTimeOffset as bt)::_ -> + | Builtin (BclInt64 + | BclUInt64 + | BclDecimal + | BclBigInt + | BclDateTime + | BclDateTimeOffset as bt) :: _ -> let opName = match bt, opName with | BclUInt64, Operators.rightShift -> "op_RightShiftUnsigned" // See #1482 | BclDecimal, Operators.divideByInt -> Operators.division | _ -> opName - Helper.LibCall(com, coreModFor bt, opName, t, args, argTypes, ?loc=r) - | Builtin (FSharpSet _)::_ -> - let mangledName = Naming.buildNameWithoutSanitationFrom "FSharpSet" true opName "" - Helper.LibCall(com, "set", mangledName, t, args, argTypes, ?loc=r) + + Helper.LibCall(com, coreModFor bt, opName, t, args, argTypes, ?loc = r) + | Builtin (FSharpSet _) :: _ -> + let mangledName = + Naming.buildNameWithoutSanitationFrom "FSharpSet" true opName "" + + Helper.LibCall(com, "set", mangledName, t, args, argTypes, ?loc = r) // | Builtin (FSharpMap _)::_ -> // let mangledName = Naming.buildNameWithoutSanitationFrom "FSharpMap" true opName overloadSuffix.Value // Helper.LibCall(com, "Map", mangledName, t, args, argTypes, ?loc=r) - | Builtin BclTimeSpan::_ -> - nativeOp opName argTypes args + | Builtin BclTimeSpan :: _ -> nativeOp opName argTypes args | CustomOp com ctx opName argTypes m -> let genArgs = genArgs |> Seq.map snd FSharp2Fable.Util.makeCallFrom com ctx r t genArgs None args m | _ -> nativeOp opName argTypes args -let isCompatibleWithJsComparison = function - | Builtin (BclInt64|BclUInt64|BclDecimal|BclBigInt) - | Array _ | List _ | Tuple _ | Option _ | MetaType | Measure _ -> false - | Builtin (BclGuid|BclTimeSpan) -> true +let isCompatibleWithJsComparison = + function + | Builtin (BclInt64 + | BclUInt64 + | BclDecimal + | BclBigInt) + | Array _ + | List _ + | Tuple _ + | Option _ + | MetaType + | Measure _ -> false + | Builtin (BclGuid + | BclTimeSpan) -> true // TODO: Non-record/union declared types without custom equality // should be compatible with JS comparison | DeclaredType _ -> false | GenericParam _ -> false | AnonymousRecordType _ -> false - | Any | Unit | Boolean | Number _ | String | Char | Regex - | Enum _ | DelegateType _ | LambdaType _ -> true + | Any + | Unit + | Boolean + | Number _ + | String + | Char + | Regex + | Enum _ + | DelegateType _ + | LambdaType _ -> true // Overview of hash rules: // * `hash`, `Unchecked.hash` first check if GetHashCode is implemented and then default to structural hash. @@ -774,8 +975,12 @@ let identityHash com r (arg: Expr) = let methodName = match arg.Type with // These are the same for identity/structural hashing - | Char | String | Builtin BclGuid -> "stringHash" - | Number _ | Enum _ | Builtin BclTimeSpan -> "numberHash" + | Char + | String + | Builtin BclGuid -> "stringHash" + | Number _ + | Enum _ + | Builtin BclTimeSpan -> "numberHash" | List _ -> "safeHash" | Tuple _ -> "arrayHash" // F# tuples must use structural hashing // These are only used for structural hashing @@ -784,84 +989,130 @@ let identityHash com r (arg: Expr) = // | Builtin (BclInt64|BclUInt64|BclDecimal) -> "fastStructuralHash" | DeclaredType _ -> "safeHash" | _ -> "identityHash" - Helper.LibCall(com, "Util", methodName, Number(Int32, None), [arg], ?loc=r) + + Helper.LibCall(com, "Util", methodName, Number(Int32, None), [ arg ], ?loc = r) let structuralHash (com: ICompiler) r (arg: Expr) = let methodName = match arg.Type with - | Char | String | Builtin BclGuid -> "stringHash" - | Number _ | Enum _ | Builtin BclTimeSpan -> "numberHash" + | Char + | String + | Builtin BclGuid -> "stringHash" + | Number _ + | Enum _ + | Builtin BclTimeSpan -> "numberHash" | List _ -> "safeHash" // TODO: Get hash functions of the generic arguments // for better performance when using tuples as map keys | Tuple _ | Array _ -> "arrayHash" - | Builtin (BclDateTime|BclDateTimeOffset) -> "dateHash" - | Builtin (BclInt64|BclUInt64|BclDecimal) -> "fastStructuralHash" - | DeclaredType(ent, _) -> + | Builtin (BclDateTime + | BclDateTimeOffset) -> "dateHash" + | Builtin (BclInt64 + | BclUInt64 + | BclDecimal) -> "fastStructuralHash" + | DeclaredType (ent, _) -> let ent = com.GetEntity(ent) - if not ent.IsInterface then "safeHash" - else "structuralHash" + + if not ent.IsInterface then + "safeHash" + else + "structuralHash" | _ -> "structuralHash" - Helper.LibCall(com, "Util", methodName, Number(Int32, None), [arg], ?loc=r) + + Helper.LibCall(com, "Util", methodName, Number(Int32, None), [ arg ], ?loc = r) let rec equals (com: ICompiler) ctx r equal (left: Expr) (right: Expr) = let is equal expr = - if equal then expr - else makeUnOp None Boolean expr UnaryNot + if equal then + expr + else + makeUnOp None Boolean expr UnaryNot + match left.Type with - | Builtin (BclGuid|BclTimeSpan) - | Boolean | Char | String | Number _ | Enum _ -> - let op = if equal then BinaryEqual else BinaryUnequal + | Builtin (BclGuid + | BclTimeSpan) + | Boolean + | Char + | String + | Number _ + | Enum _ -> + let op = + if equal then + BinaryEqual + else + BinaryUnequal + makeBinOp r Boolean left right op - | Builtin (BclDateTime|BclDateTimeOffset) -> - Helper.LibCall(com, "date", "equals", Boolean, [left; right], ?loc=r) |> is equal - | Builtin (FSharpSet _|FSharpMap _) -> - Helper.InstanceCall(left, "Equals", Boolean, [right]) |> is equal - | Builtin (BclInt64|BclUInt64|BclDecimal|BclBigInt as bt) -> - Helper.LibCall(com, coreModFor bt, "equals", Boolean, [left; right], ?loc=r) |> is equal + | Builtin (BclDateTime + | BclDateTimeOffset) -> + Helper.LibCall(com, "date", "equals", Boolean, [ left; right ], ?loc = r) + |> is equal + | Builtin (FSharpSet _ + | FSharpMap _) -> + Helper.InstanceCall(left, "Equals", Boolean, [ right ]) + |> is equal + | Builtin (BclInt64 + | BclUInt64 + | BclDecimal + | BclBigInt as bt) -> + Helper.LibCall(com, coreModFor bt, "equals", Boolean, [ left; right ], ?loc = r) + |> is equal | DeclaredType _ -> - Helper.LibCall(com, "util", "equals", Boolean, [left; right], ?loc=r) |> is equal + Helper.LibCall(com, "util", "equals", Boolean, [ left; right ], ?loc = r) + |> is equal | Array t -> let f = makeEqualityFunction com ctx t - Helper.LibCall(com, "array", "equalsWith", Boolean, [f; left; right], ?loc=r) |> is equal + + Helper.LibCall(com, "array", "equalsWith", Boolean, [ f; left; right ], ?loc = r) + |> is equal | List _ -> - Helper.LibCall(com, "util", "equals", Boolean, [left; right], ?loc=r) |> is equal + Helper.LibCall(com, "util", "equals", Boolean, [ left; right ], ?loc = r) + |> is equal | MetaType -> - Helper.LibCall(com, "reflection", "equals", Boolean, [left; right], ?loc=r) |> is equal + Helper.LibCall(com, "reflection", "equals", Boolean, [ left; right ], ?loc = r) + |> is equal | Tuple _ -> - Helper.LibCall(com, "util", "equalArrays", Boolean, [left; right], ?loc=r) |> is equal + Helper.LibCall(com, "util", "equalArrays", Boolean, [ left; right ], ?loc = r) + |> is equal | _ -> - Helper.LibCall(com, "util", "equals", Boolean, [left; right], ?loc=r) |> is equal + Helper.LibCall(com, "util", "equals", Boolean, [ left; right ], ?loc = r) + |> is equal /// Compare function that will call Util.compare or instance `CompareTo` as appropriate and compare (com: ICompiler) ctx r (left: Expr) (right: Expr) = match left.Type with - | Builtin (BclGuid|BclTimeSpan) - | Boolean | Char | String | Number _ | Enum _ -> - Helper.LibCall(com, "util", "comparePrimitives", Number(Int32, None), [left; right], ?loc=r) - | Builtin (BclDateTime|BclDateTimeOffset) -> - Helper.LibCall(com, "date", "compare", Number(Int32, None), [left; right], ?loc=r) - | Builtin (BclInt64|BclUInt64|BclDecimal|BclBigInt as bt) -> - Helper.LibCall(com, coreModFor bt, "compare", Number(Int32, None), [left; right], ?loc=r) - | DeclaredType _ -> - Helper.LibCall(com, "util", "compare", Number(Int32, None), [left; right], ?loc=r) + | Builtin (BclGuid + | BclTimeSpan) + | Boolean + | Char + | String + | Number _ + | Enum _ -> Helper.LibCall(com, "util", "comparePrimitives", Number(Int32, None), [ left; right ], ?loc = r) + | Builtin (BclDateTime + | BclDateTimeOffset) -> Helper.LibCall(com, "date", "compare", Number(Int32, None), [ left; right ], ?loc = r) + | Builtin (BclInt64 + | BclUInt64 + | BclDecimal + | BclBigInt as bt) -> Helper.LibCall(com, coreModFor bt, "compare", Number(Int32, None), [ left; right ], ?loc = r) + | DeclaredType _ -> Helper.LibCall(com, "util", "compare", Number(Int32, None), [ left; right ], ?loc = r) | Array t -> let f = makeComparerFunction com ctx t - Helper.LibCall(com, "array", "compareWith", Number(Int32, None), [f; left; right], ?loc=r) - | List _ -> - Helper.LibCall(com, "util", "compare", Number(Int32, None), [left; right], ?loc=r) - | Tuple _ -> - Helper.LibCall(com, "util", "compareArrays", Number(Int32, None), [left; right], ?loc=r) - | _ -> - Helper.LibCall(com, "util", "compare", Number(Int32, None), [left; right], ?loc=r) + Helper.LibCall(com, "array", "compareWith", Number(Int32, None), [ f; left; right ], ?loc = r) + | List _ -> Helper.LibCall(com, "util", "compare", Number(Int32, None), [ left; right ], ?loc = r) + | Tuple _ -> Helper.LibCall(com, "util", "compareArrays", Number(Int32, None), [ left; right ], ?loc = r) + | _ -> Helper.LibCall(com, "util", "compare", Number(Int32, None), [ left; right ], ?loc = r) /// Wraps comparison with the binary operator, like `comparison < 0` and compareIf (com: ICompiler) ctx r (left: Expr) (right: Expr) op = match left.Type with - | Builtin (BclGuid|BclTimeSpan) - | Boolean | Char | String | Number _ | Enum _ -> - makeEqOp r left right op + | Builtin (BclGuid + | BclTimeSpan) + | Boolean + | Char + | String + | Number _ + | Enum _ -> makeEqOp r left right op | _ -> let comparison = compare com ctx r left right makeEqOp r comparison (makeIntConst 0) op @@ -870,134 +1121,138 @@ and makeComparerFunction (com: ICompiler) ctx typArg = let x = makeUniqueIdent ctx typArg "x" let y = makeUniqueIdent ctx typArg "y" let body = compare com ctx None (IdentExpr x) (IdentExpr y) - Delegate([x; y], body, None) + Delegate([ x; y ], body, None) + +and makeComparer (com: ICompiler) ctx typArg = objExpr [ "Compare", makeComparerFunction com ctx typArg ] -and makeComparer (com: ICompiler) ctx typArg = - objExpr ["Compare", makeComparerFunction com ctx typArg] and makeEqualityFunction (com: ICompiler) ctx typArg = let x = makeUniqueIdent ctx typArg "x" let y = makeUniqueIdent ctx typArg "y" let body = equals com ctx None true (IdentExpr x) (IdentExpr y) - Delegate([x; y], body, None) + Delegate([ x; y ], body, None) let makeEqualityComparer (com: ICompiler) ctx typArg = let x = makeUniqueIdent ctx typArg "x" let y = makeUniqueIdent ctx typArg "y" - objExpr ["Equals", Delegate([x; y], equals com ctx None true (IdentExpr x) (IdentExpr y), None) - "GetHashCode", Delegate([x], structuralHash com None (IdentExpr x), None)] + + objExpr [ + "Equals", Delegate([ x; y ], equals com ctx None true (IdentExpr x) (IdentExpr y), None) + "GetHashCode", Delegate([ x ], structuralHash com None (IdentExpr x), None) + ] // TODO: Try to detect at compile-time if the object already implements `Compare`? -let inline makeComparerFromEqualityComparer e = - e // leave it as is, if implementation supports it - // Helper.LibCall(com, "Util", "comparerFromEqualityComparer", Any, [e]) +let inline makeComparerFromEqualityComparer e = e // leave it as is, if implementation supports it +// Helper.LibCall(com, "Util", "comparerFromEqualityComparer", Any, [e]) /// Adds comparer as last argument for set creator methods let makeSet (com: ICompiler) ctx r t methName args genArg = - let args = args @ [makeComparer com ctx genArg] - Helper.LibCall(com, "set", Naming.lowerFirst methName, t, args, ?loc=r) + let args = args @ [ makeComparer com ctx genArg ] + Helper.LibCall(com, "set", Naming.lowerFirst methName, t, args, ?loc = r) /// Adds comparer as last argument for map creator methods let makeMap (com: ICompiler) ctx r t methName args genArg = - let args = args @ [makeComparer com ctx genArg] - Helper.LibCall(com, "map", Naming.lowerFirst methName, t, args, ?loc=r) + let args = args @ [ makeComparer com ctx genArg ] + Helper.LibCall(com, "map", Naming.lowerFirst methName, t, args, ?loc = r) let makeDictionaryWithComparer com r t sourceSeq comparer = - Helper.LibCall(com, "mutable_map", "Dictionary", t, [sourceSeq; comparer], isPyConstructor=true, ?loc=r) + Helper.LibCall(com, "mutable_map", "Dictionary", t, [ sourceSeq; comparer ], isPyConstructor = true, ?loc = r) let makeDictionary (com: ICompiler) ctx r t sourceSeq = match t with - | DeclaredType(_,[key;_]) when not(isCompatibleWithJsComparison key) -> + | DeclaredType (_, [ key; _ ]) when not (isCompatibleWithJsComparison key) -> // makeComparer com ctx key makeEqualityComparer com ctx key |> makeDictionaryWithComparer com r t sourceSeq - | _ -> Helper.GlobalCall("dict", t, [sourceSeq], isPyConstructor=true, ?loc=r) + | _ -> Helper.GlobalCall("dict", t, [ sourceSeq ], isPyConstructor = true, ?loc = r) let makeHashSetWithComparer com r t sourceSeq comparer = - Helper.LibCall(com, "mutable_set", "HashSet", t, [sourceSeq; comparer], isPyConstructor=true, ?loc=r) + Helper.LibCall(com, "mutable_set", "HashSet", t, [ sourceSeq; comparer ], isPyConstructor = true, ?loc = r) let makeHashSet (com: ICompiler) ctx r t sourceSeq = match t with - | DeclaredType(_,[key]) when not(isCompatibleWithJsComparison key) -> + | DeclaredType (_, [ key ]) when not (isCompatibleWithJsComparison key) -> // makeComparer com ctx key makeEqualityComparer com ctx key |> makeHashSetWithComparer com r t sourceSeq - | _ -> Helper.GlobalCall("set", t, [sourceSeq], isPyConstructor=true, ?loc=r) + | _ -> Helper.GlobalCall("set", t, [ sourceSeq ], isPyConstructor = true, ?loc = r) let rec getZero (com: ICompiler) ctx (t: Type) = match t with | Boolean -> makeBoolConst false - | Char | String -> makeStrConst "" // TODO: Use null for string? + | Char + | String -> makeStrConst "" // TODO: Use null for string? | Number _ -> makeIntConst 0 | Builtin BclTimeSpan -> Helper.LibCall(com, "time_span", "create", t, [ makeIntConst 0 ]) | Builtin BclDateTime as t -> Helper.LibCall(com, "date", "minValue", t, []) | Builtin BclDateTimeOffset as t -> Helper.LibCall(com, "DateOffset", "minValue", t, []) | Builtin (FSharpSet genArg) as t -> makeSet com ctx None t "Empty" [] genArg - | Builtin (BclInt64|BclUInt64) as t -> Helper.LibCall(com, "Long", "fromInt", t, [makeIntConst 0]) - | Builtin BclBigInt as t -> Helper.LibCall(com, "big_int", "fromInt32", t, [makeIntConst 0]) + | Builtin (BclInt64 + | BclUInt64) as t -> Helper.LibCall(com, "Long", "fromInt", t, [ makeIntConst 0 ]) + | Builtin BclBigInt as t -> Helper.LibCall(com, "big_int", "fromInt32", t, [ makeIntConst 0 ]) | Builtin BclDecimal as t -> makeIntConst 0 |> makeDecimalFromExpr com None t - | Builtin (BclKeyValuePair(k,v)) -> - makeTuple None [getZero com ctx k; getZero com ctx v] - | ListSingleton(CustomOp com ctx "get_Zero" [] m) -> - FSharp2Fable.Util.makeCallFrom com ctx None t [] None [] m + | Builtin (BclKeyValuePair (k, v)) -> makeTuple None [ getZero com ctx k; getZero com ctx v ] + | ListSingleton (CustomOp com ctx "get_Zero" [] m) -> FSharp2Fable.Util.makeCallFrom com ctx None t [] None [] m | _ -> Value(Null Any, None) // null let getOne (com: ICompiler) ctx (t: Type) = match t with - | Builtin (BclInt64|BclUInt64) as t -> Helper.LibCall(com, "long", "fromInt", t, [makeIntConst 1]) - | Builtin BclBigInt as t -> Helper.LibCall(com, "big_int", "fromInt32", t, [makeIntConst 1]) + | Builtin (BclInt64 + | BclUInt64) as t -> Helper.LibCall(com, "long", "fromInt", t, [ makeIntConst 1 ]) + | Builtin BclBigInt as t -> Helper.LibCall(com, "big_int", "fromInt32", t, [ makeIntConst 1 ]) | Builtin BclDecimal as t -> makeIntConst 1 |> makeDecimalFromExpr com None t - | ListSingleton(CustomOp com ctx "get_One" [] m) -> - FSharp2Fable.Util.makeCallFrom com ctx None t [] None [] m + | ListSingleton (CustomOp com ctx "get_One" [] m) -> FSharp2Fable.Util.makeCallFrom com ctx None t [] None [] m | _ -> makeIntConst 1 let makeAddFunction (com: ICompiler) ctx t = let x = makeUniqueIdent ctx t "x" let y = makeUniqueIdent ctx t "y" - let body = applyOp com ctx None t Operators.addition [IdentExpr x; IdentExpr y] [t; t] [] - Delegate([x; y], body, None) + + let body = + applyOp com ctx None t Operators.addition [ IdentExpr x; IdentExpr y ] [ t; t ] [] + + Delegate([ x; y ], body, None) let makeGenericAdder (com: ICompiler) ctx t = - objExpr [ - "GetZero", getZero com ctx t |> makeDelegate [] - "Add", makeAddFunction com ctx t - ] + objExpr [ "GetZero", getZero com ctx t |> makeDelegate []; "Add", makeAddFunction com ctx t ] let makeGenericAverager (com: ICompiler) ctx t = let divideFn = let x = makeUniqueIdent ctx t "x" let i = makeUniqueIdent ctx (Number(Int32, None)) "i" - let body = applyOp com ctx None t Operators.divideByInt [IdentExpr x; IdentExpr i] [t; Number(Int32, None)] [] - Delegate([x; i], body, None) - objExpr [ - "GetZero", getZero com ctx t |> makeDelegate [] - "Add", makeAddFunction com ctx t - "DivideByInt", divideFn - ] + + let body = + applyOp com ctx None t Operators.divideByInt [ IdentExpr x; IdentExpr i ] [ t; Number(Int32, None) ] [] + + Delegate([ x; i ], body, None) + + objExpr [ "GetZero", getZero com ctx t |> makeDelegate []; "Add", makeAddFunction com ctx t; "DivideByInt", divideFn ] let makePojoFromLambda com arg = - let rec flattenSequential = function - | Sequential statements -> - List.collect flattenSequential statements - | e -> [e] + let rec flattenSequential = + function + | Sequential statements -> List.collect flattenSequential statements + | e -> [ e ] + match arg with - | Lambda(_, lambdaBody, _) -> - (flattenSequential lambdaBody, Some []) ||> List.foldBack (fun statement acc -> + | Lambda (_, lambdaBody, _) -> + (flattenSequential lambdaBody, Some []) + ||> List.foldBack (fun statement acc -> match acc, statement with - | Some acc, Set(_, FieldSet(fieldName), _, value, _) -> - objValue (fieldName, value)::acc |> Some + | Some acc, Set (_, FieldSet (fieldName), _, value, _) -> objValue (fieldName, value) :: acc |> Some | _ -> None) | _ -> None |> Option.map (fun members -> ObjectExpr(members, Any, None)) - |> Option.defaultWith (fun () -> Helper.LibCall(com, "util", "jsOptions", Any, [arg])) + |> Option.defaultWith (fun () -> Helper.LibCall(com, "util", "jsOptions", Any, [ arg ])) let makePojo (com: Compiler) caseRule keyValueList = let makeObjMember caseRule name values = let value = match values with | [] -> makeBoolConst true - | [value] -> value + | [ value ] -> value | values -> Value(NewArray(values, Any), None) - objValue(Naming.applyCaseRule caseRule name, value) + + objValue (Naming.applyCaseRule caseRule name, value) // let rec findKeyValueList scope identName = // match scope with @@ -1012,61 +1267,66 @@ let makePojo (com: Compiler) caseRule keyValueList = let caseRule = match caseRule with - | Some(Value(NumberConstant(rule,_,_),_)) - | Some(Value(EnumConstant(Value(NumberConstant(rule,_,_),_),_),_)) -> Some rule + | Some (Value (NumberConstant (rule, _, _), _)) + | Some (Value (EnumConstant (Value (NumberConstant (rule, _, _), _), _), _)) -> Some rule | _ -> None - |> Option.map (fun rule -> enum(int rule)) + |> Option.map (fun rule -> enum (int rule)) |> Option.defaultValue Fable.Core.CaseRules.None match keyValueList with - | ArrayOrListLiteral(kvs,_) -> Some kvs + | ArrayOrListLiteral (kvs, _) -> Some kvs // | MaybeCasted(IdentExpr ident) -> findKeyValueList ctx.Scope ident.Name | _ -> None |> Option.bind (fun kvs -> - (kvs, Some []) ||> List.foldBack (fun m acc -> + (kvs, Some []) + ||> List.foldBack (fun m acc -> match acc, m with // Try to get the member key and value at compile time for unions and tuples - | Some acc, MaybeCasted(Value(NewUnion(values, uci, ent, _),_)) -> + | Some acc, MaybeCasted (Value (NewUnion (values, uci, ent, _), _)) -> let uci = com.GetEntity(ent).UnionCases |> List.item uci let name = defaultArg uci.CompiledName uci.Name - makeObjMember caseRule name values::acc |> Some - | Some acc, MaybeCasted(Value(NewTuple((StringConst name)::values,_),_)) -> + makeObjMember caseRule name values :: acc |> Some + | Some acc, MaybeCasted (Value (NewTuple ((StringConst name) :: values, _), _)) -> // Don't change the case for tuples in disguise - makeObjMember Core.CaseRules.None name values::acc |> Some + makeObjMember Core.CaseRules.None name values + :: acc + |> Some | _ -> None)) |> Option.map (fun members -> ObjectExpr(members, Any, None)) let injectArg (com: ICompiler) (ctx: Context) r moduleName methName (genArgs: (string * Type) list) args = let injectArgInner args (injectType, injectGenArgIndex) = let fail () = - sprintf "Cannot inject arg to %s.%s (genArgs %A - expected index %i)" - moduleName methName (List.map fst genArgs) injectGenArgIndex + sprintf + "Cannot inject arg to %s.%s (genArgs %A - expected index %i)" + moduleName + methName + (List.map fst genArgs) + injectGenArgIndex |> addError com ctx.InlinePath r + args match List.tryItem injectGenArgIndex genArgs with - | None -> fail() - | Some (_,genArg) -> + | None -> fail () + | Some (_, genArg) -> match injectType with - | Types.comparer -> - args @ [makeComparer com ctx genArg] - | Types.equalityComparer -> - args @ [makeEqualityComparer com ctx genArg] + | Types.comparer -> args @ [ makeComparer com ctx genArg ] + | Types.equalityComparer -> args @ [ makeEqualityComparer com ctx genArg ] | Types.arrayCons -> match genArg with - | Number(numberKind,_) when com.Options.TypedArrays -> + | Number (numberKind, _) when com.Options.TypedArrays -> let name = Helpers.getTypedArrayName com numberKind let cons = [ makeImportLib com Any name "types" ] args @ cons // Python will complain if we miss an argument | _ when com.Options.Language = Python -> - args @ [ Expr.Value(ValueKind.NewOption(None, genArg, false), None) ] + args + @ [ Expr.Value(ValueKind.NewOption(None, genArg, false), None) ] | _ -> args - | Types.adder -> - args @ [makeGenericAdder com ctx genArg] - | Types.averager -> - args @ [makeGenericAverager com ctx genArg] - | _ -> fail() + | Types.adder -> args @ [ makeGenericAdder com ctx genArg ] + | Types.averager -> args @ [ makeGenericAverager com ctx genArg ] + | _ -> fail () Map.tryFind moduleName ReplacementsInject.fableReplacementsModules |> Option.bind (Map.tryFind methName) @@ -1082,10 +1342,14 @@ let tryEntityRef (com: Compiler) entFullName = | BuiltinDefinition BclInt64 | BuiltinDefinition BclUInt64 -> makeImportLib com Any "default" "Long" |> Some | BuiltinDefinition BclDecimal -> makeImportLib com Any "default" "Decimal" |> Some - | BuiltinDefinition BclBigInt -> makeImportLib com Any "BigInteger" "BigInt/z" |> Some - | BuiltinDefinition(FSharpReference _) -> makeImportLib com Any "FSharpRef" "Types" |> Some - | BuiltinDefinition(FSharpResult _) -> makeImportLib com Any "FSharpResult_2" "Choice" |> Some - | BuiltinDefinition(FSharpChoice genArgs) -> + | BuiltinDefinition BclBigInt -> + makeImportLib com Any "BigInteger" "BigInt/z" + |> Some + | BuiltinDefinition (FSharpReference _) -> makeImportLib com Any "FSharpRef" "Types" |> Some + | BuiltinDefinition (FSharpResult _) -> + makeImportLib com Any "FSharpResult_2" "Choice" + |> Some + | BuiltinDefinition (FSharpChoice genArgs) -> let membName = $"FSharpChoice${List.length genArgs}" makeImportLib com Any membName "choice" |> Some // | BuiltinDefinition BclGuid -> jsTypeof "string" expr @@ -1095,14 +1359,17 @@ let tryEntityRef (com: Compiler) entFullName = // | BuiltinDefinition BclKeyValuePair _ -> fail "KeyValuePair" // TODO: // | BuiltinDefinition FSharpSet _ -> fail "Set" // TODO: // | BuiltinDefinition FSharpMap _ -> fail "Map" // TODO: - | Types.matchFail -> makeImportLib com Any "MatchFailureException" "Types" |> Some + | Types.matchFail -> + makeImportLib com Any "MatchFailureException" "Types" + |> Some | Types.exception_ -> makeIdentExpr "Exception" |> Some | _ -> None let tryPyConstructor com (ent: Entity) = - if FSharp2Fable.Util.isReplacementCandidate ent - then tryEntityRef com ent.FullName - else FSharp2Fable.Util.tryEntityRefMaybeGlobalOrImported com ent + if FSharp2Fable.Util.isReplacementCandidate ent then + tryEntityRef com ent.FullName + else + FSharp2Fable.Util.tryEntityRefMaybeGlobalOrImported com ent let pyConstructor com ent = match tryPyConstructor com ent with @@ -1112,137 +1379,185 @@ let pyConstructor com ent = |> sprintf "Cannot find %s constructor" |> addErrorAndReturnNull com [] None -let tryOp com r t op args = - Helper.LibCall(com, "option", "tryOp", t, op::args, ?loc=r) +let tryOp com r t op args = Helper.LibCall(com, "option", "tryOp", t, op :: args, ?loc = r) let tryCoreOp com r t coreModule coreMember args = let op = Helper.LibValue(com, coreModule, coreMember, Any) tryOp com r t op args -let emptyGuid () = - makeStrConst "00000000-0000-0000-0000-000000000000" +let emptyGuid () = makeStrConst "00000000-0000-0000-0000-000000000000" let rec defaultof (com: ICompiler) ctx (t: Type) = match t with | Number _ -> makeIntConst 0 | Boolean -> makeBoolConst false - | Tuple(args, true) -> NewTuple(args |> List.map (defaultof com ctx), true) |> makeValue None + | Tuple (args, true) -> + NewTuple(args |> List.map (defaultof com ctx), true) + |> makeValue None | Builtin BclTimeSpan -> getZero com ctx t | Builtin BclDateTime | Builtin BclDateTimeOffset - | Builtin (BclInt64|BclUInt64) + | Builtin (BclInt64 + | BclUInt64) | Builtin BclBigInt | Builtin BclDecimal -> getZero com ctx t - | Builtin BclGuid -> emptyGuid() - | DeclaredType(ent,_) -> + | Builtin BclGuid -> emptyGuid () + | DeclaredType (ent, _) -> let ent = com.GetEntity(ent) // TODO: For BCL types we cannot access the constructor, raise error or warning? - if ent.IsValueType - then tryPyConstructor com ent - else None + if ent.IsValueType then + tryPyConstructor com ent + else + None |> Option.map (fun e -> Helper.PyConstructorCall(e, t, [])) |> Option.defaultWith (fun () -> Null t |> makeValue None) // TODO: Fail (or raise warning) if this is an unresolved generic parameter? | _ -> Null t |> makeValue None let fableCoreLib (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = - let fixDynamicImportPath = function - | Value(StringConstant path, r) when path.EndsWith(".fs") -> + let fixDynamicImportPath = + function + | Value (StringConstant path, r) when path.EndsWith(".fs") -> // In imports *.ts extensions have to be converted to *.py extensions instead let fileExt = com.Options.FileExtension - let fileExt = if fileExt.EndsWith(".ts") then Path.replaceExtension ".py" fileExt else fileExt + + let fileExt = + if fileExt.EndsWith(".ts") then + Path.replaceExtension ".py" fileExt + else + fileExt + Value(StringConstant(Path.replaceExtension fileExt path), r) | path -> path match i.DeclaringEntityFullName, i.CompiledName with | _, "op_ErasedCast" -> List.tryHead args | _, ".ctor" -> typedObjExpr t [] |> Some - | _, ("pyNative"|"nativeOnly") -> + | _, + ("pyNative" + | "nativeOnly") -> // TODO: Fail at compile time? addWarning com ctx.InlinePath r $"{i.CompiledName} is being compiled without replacement, this will fail at runtime." + let runtimeMsg = "A function supposed to be replaced by Python native code has been called, please check." - |> StringConstant |> makeValue None + |> StringConstant + |> makeValue None + makeThrow r t (error runtimeMsg) |> Some - | _, ("nameof"|"nameof2" as meth) -> + | _, + ("nameof" + | "nameof2" as meth) -> match args with - | [Nameof com ctx name as arg] -> - if meth = "nameof2" - then makeTuple r [makeStrConst name; arg] |> Some - else makeStrConst name |> Some - | _ -> "Cannot infer name of expression" - |> addError com ctx.InlinePath r - makeStrConst Naming.unknown |> Some - | _, ("nameofLambda"|"namesofLambda" as meth) -> + | [ Nameof com ctx name as arg ] -> + if meth = "nameof2" then + makeTuple r [ makeStrConst name; arg ] |> Some + else + makeStrConst name |> Some + | _ -> + "Cannot infer name of expression" + |> addError com ctx.InlinePath r + + makeStrConst Naming.unknown |> Some + | _, + ("nameofLambda" + | "namesofLambda" as meth) -> match args with - | [Lambda(_, (Namesof com ctx names), _)] -> Some names - | [MaybeCasted(IdentExpr ident)] -> + | [ Lambda (_, (Namesof com ctx names), _) ] -> Some names + | [ MaybeCasted (IdentExpr ident) ] -> match findInScope ctx.Scope ident.Name with - | Some(Lambda(_, (Namesof com ctx names), _)) -> Some names + | Some (Lambda (_, (Namesof com ctx names), _)) -> Some names | _ -> None | _ -> None |> Option.defaultWith (fun () -> "Cannot infer name of expression" |> addError com ctx.InlinePath r - [Naming.unknown]) - |> fun names -> - if meth = "namesofLambda" then List.map makeStrConst names |> makeArray String |> Some - else List.tryHead names |> Option.map makeStrConst - | _, ("casenameWithFieldCount"|"casenameWithFieldIndex" as meth) -> - let rec inferCasename = function - | Lambda(arg, IfThenElse(Test(IdentExpr arg2, UnionCaseTest tag,_),thenExpr,_,_),_) when arg.Name = arg2.Name -> + [ Naming.unknown ]) + |> fun names -> + if meth = "namesofLambda" then + List.map makeStrConst names + |> makeArray String + |> Some + else + List.tryHead names |> Option.map makeStrConst + + | _, + ("casenameWithFieldCount" + | "casenameWithFieldIndex" as meth) -> + let rec inferCasename = + function + | Lambda (arg, IfThenElse (Test (IdentExpr arg2, UnionCaseTest tag, _), thenExpr, _, _), _) when arg.Name = arg2.Name -> match arg.Type with - | DeclaredType(e,_) -> + | DeclaredType (e, _) -> let e = com.GetEntity(e) + if e.IsFSharpUnion then let c = e.UnionCases.[tag] let caseName = defaultArg c.CompiledName c.Name + if meth = "casenameWithFieldCount" then Some(caseName, c.UnionCaseFields.Length) else match thenExpr with - | NestedRevLets(bindings, IdentExpr i) -> - bindings |> List.tryPick (fun (i2, v) -> + | NestedRevLets (bindings, IdentExpr i) -> + bindings + |> List.tryPick (fun (i2, v) -> match v with - | Get(_, UnionField(_,fieldIdx),_,_) when i.Name = i2.Name -> Some fieldIdx + | Get (_, UnionField (_, fieldIdx), _, _) when i.Name = i2.Name -> Some fieldIdx | _ -> None) |> Option.map (fun fieldIdx -> caseName, fieldIdx) | _ -> None - else None + else + None | _ -> None | _ -> None match args with - | [MaybeCasted(IdentExpr ident)] -> findInScope ctx.Scope ident.Name |> Option.bind inferCasename - | [e] -> inferCasename e + | [ MaybeCasted (IdentExpr ident) ] -> + findInScope ctx.Scope ident.Name + |> Option.bind inferCasename + | [ e ] -> inferCasename e | _ -> None |> Option.orElseWith (fun () -> "Cannot infer case name of expression" |> addError com ctx.InlinePath r + Some(Naming.unknown, -1)) - |> Option.map (fun (s, i) -> - makeTuple r [makeStrConst s; makeIntConst i]) + |> Option.map (fun (s, i) -> makeTuple r [ makeStrConst s; makeIntConst i ]) - | _, "Async.AwaitPromise.Static" -> Helper.LibCall(com, "async_", "awaitPromise", t, args, ?loc=r) |> Some - | _, "Async.StartAsPromise.Static" -> Helper.LibCall(com, "async_", "startAsPromise", t, args, ?loc=r) |> Some + | _, "Async.AwaitPromise.Static" -> + Helper.LibCall(com, "async_", "awaitPromise", t, args, ?loc = r) + |> Some + | _, "Async.StartAsPromise.Static" -> + Helper.LibCall(com, "async_", "startAsPromise", t, args, ?loc = r) + |> Some | "Fable.Core.Testing.Assert", _ -> match i.CompiledName with - | "AreEqual" -> Helper.LibCall(com, "util", "assertEqual", t, args, ?loc=r) |> Some - | "NotEqual" -> Helper.LibCall(com, "util", "assertNotEqual", t, args, ?loc=r) |> Some + | "AreEqual" -> + Helper.LibCall(com, "util", "assertEqual", t, args, ?loc = r) + |> Some + | "NotEqual" -> + Helper.LibCall(com, "util", "assertNotEqual", t, args, ?loc = r) + |> Some | _ -> None | "Fable.Core.Reflection", meth -> - Helper.LibCall(com, "reflection", meth, t, args, ?loc=r) |> Some + Helper.LibCall(com, "reflection", meth, t, args, ?loc = r) + |> Some | "Fable.Core.Compiler", meth -> match meth with | "version" -> makeStrConst Literals.VERSION |> Some | "majorMinorVersion" -> try - let m = System.Text.RegularExpressions.Regex.Match(Literals.VERSION, @"^\d+\.\d+") + let m = + System.Text.RegularExpressions.Regex.Match(Literals.VERSION, @"^\d+\.\d+") + float m.Value |> makeFloatConst |> Some - with _ -> + with + | _ -> "Cannot parse compiler version" - |> addErrorAndReturnNull com ctx.InlinePath r |> Some + |> addErrorAndReturnNull com ctx.InlinePath r + |> Some | "debugMode" -> makeBoolConst com.Options.DebugMode |> Some | "typedArrays" -> makeBoolConst com.Options.TypedArrays |> Some | "extension" -> makeStrConst com.Options.FileExtension |> Some @@ -1250,248 +1565,360 @@ let fableCoreLib (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Exp | "Fable.Core.PyInterop", _ | "Fable.Core.JsInterop", _ -> match i.CompiledName, args with - | "importDynamic", [path] -> + | "importDynamic", [ path ] -> let path = fixDynamicImportPath path - Helper.GlobalCall("import", t, [path], ?loc=r) |> Some - | "importValueDynamic", [arg] -> + + Helper.GlobalCall("import", t, [ path ], ?loc = r) + |> Some + | "importValueDynamic", [ arg ] -> let dynamicImport selector path = let path = fixDynamicImportPath path - let import = Helper.GlobalCall("import", t, [path], ?loc=r) + let import = Helper.GlobalCall("import", t, [ path ], ?loc = r) + match selector with | StringConst "*" -> import | selector -> let selector = let m = makeIdent "m" - Delegate([m], Get(IdentExpr m, ExprGet selector, Any, None), None) - Helper.InstanceCall(import, "then", t, [selector]) + Delegate([ m ], Get(IdentExpr m, ExprGet selector, Any, None), None) + + Helper.InstanceCall(import, "then", t, [ selector ]) + let arg = match arg with | IdentExpr ident -> findInScope ctx.Scope ident.Name |> Option.defaultValue arg | arg -> arg + match arg with // TODO: Check this is not a fable-library import? - | Import(info,_,_) -> - dynamicImport (makeStrConst info.Selector) (makeStrConst info.Path) |> Some - | NestedLambda(args, Call(Import(importInfo,_,_),callInfo,_,_), None) - when argEquals args callInfo.Args -> - dynamicImport (makeStrConst importInfo.Selector) (makeStrConst importInfo.Path) |> Some + | Import (info, _, _) -> + dynamicImport (makeStrConst info.Selector) (makeStrConst info.Path) + |> Some + | NestedLambda (args, Call (Import (importInfo, _, _), callInfo, _, _), None) when argEquals args callInfo.Args -> + dynamicImport (makeStrConst importInfo.Selector) (makeStrConst importInfo.Path) + |> Some | _ -> "The imported value is not coming from a different file" - |> addErrorAndReturnNull com ctx.InlinePath r |> Some + |> addErrorAndReturnNull com ctx.InlinePath r + |> Some | Naming.StartsWith "import" suffix, _ -> let (|RequireStringConst|_|) e = (match e with | StringConst s -> Some s - | MaybeCasted(IdentExpr ident) -> - match findInScope ctx.Scope ident.Name with - | Some(StringConst s) -> Some s - | _ -> None + | MaybeCasted (IdentExpr ident) -> + match findInScope ctx.Scope ident.Name with + | Some (StringConst s) -> Some s + | _ -> None | _ -> None) - |> Option.orElseWith(fun () -> - addError com ctx.InlinePath r "Import only accepts string literals"; None) + |> Option.orElseWith (fun () -> + addError com ctx.InlinePath r "Import only accepts string literals" + None) + match suffix, args with - | "Member", [RequireStringConst path] -> makeImportUserGenerated r t Naming.placeholder path |> Some - | "Default", [RequireStringConst path] -> makeImportUserGenerated r t "default" path |> Some - | "SideEffects", [RequireStringConst path] -> makeImportUserGenerated r t "" path |> Some - | "All", [RequireStringConst path] -> makeImportUserGenerated r t "*" path |> Some - | _, [RequireStringConst selector; RequireStringConst path] -> makeImportUserGenerated r t selector path |> Some + | "Member", [ RequireStringConst path ] -> + makeImportUserGenerated r t Naming.placeholder path + |> Some + | "Default", [ RequireStringConst path ] -> makeImportUserGenerated r t "default" path |> Some + | "SideEffects", [ RequireStringConst path ] -> makeImportUserGenerated r t "" path |> Some + | "All", [ RequireStringConst path ] -> makeImportUserGenerated r t "*" path |> Some + | _, [ RequireStringConst selector; RequireStringConst path ] -> makeImportUserGenerated r t selector path |> Some | _ -> None // Dynamic casting, erase - | "op_BangHat", [arg] -> Some arg - | "op_BangBang", [arg] -> + | "op_BangHat", [ arg ] -> Some arg + | "op_BangBang", [ arg ] -> match arg, i.GenericArgs with - | NewAnonymousRecord(_, exprs, fieldNames, _, _), - [_; (_,DeclaredType(ent, []))] -> + | NewAnonymousRecord (_, exprs, fieldNames, _, _), [ _; (_, DeclaredType (ent, [])) ] -> let ent = com.GetEntity(ent) + if ent.IsInterface then FSharp2Fable.TypeHelpers.fitsAnonRecordInInterface com r exprs fieldNames ent |> function - | Error errors -> + | Error errors -> errors |> List.iter (fun (range, error) -> addWarning com ctx.InlinePath range error) + Some arg - | Ok () -> - Some arg - else Some arg + | Ok () -> Some arg + else + Some arg | _ -> Some arg - | "op_Dynamic", [left; memb] -> - getExpr r t left memb |> Some - | "op_DynamicAssignment", [callee; prop; MaybeLambdaUncurriedAtCompileTime value] -> - setExpr r callee prop value |> Some - | ("op_Dollar"|"createNew" as m), callee::args -> + | "op_Dynamic", [ left; memb ] -> getExpr r t left memb |> Some + | "op_DynamicAssignment", [ callee; prop; MaybeLambdaUncurriedAtCompileTime value ] -> setExpr r callee prop value |> Some + | ("op_Dollar" + | "createNew" as m), + callee :: args -> let args = destructureTupleArgs args - if m = "createNew" then "new $0($1...)" else "$0($1...)" - |> emitJsExpr r t (callee::args) |> Some - | Naming.StartsWith "emitJs" rest, [args; macro] -> + + if m = "createNew" then + "new $0($1...)" + else + "$0($1...)" + |> emitJsExpr r t (callee :: args) + |> Some + | Naming.StartsWith "emitJs" rest, [ args; macro ] -> match macro with | StringConst macro -> - let args = destructureTupleArgs [args] + let args = destructureTupleArgs [ args ] let isStatement = rest = "Statement" emitJs r t args isStatement macro |> Some - | _ -> "emitJs only accepts string literals" |> addError com ctx.InlinePath r; None - | "op_EqualsEqualsGreater", [name; MaybeLambdaUncurriedAtCompileTime value] -> - makeTuple r [name; value] |> Some + | _ -> + "emitJs only accepts string literals" + |> addError com ctx.InlinePath r + + None + | "op_EqualsEqualsGreater", [ name; MaybeLambdaUncurriedAtCompileTime value ] -> makeTuple r [ name; value ] |> Some | "createObj", _ -> - Helper.LibCall(com, "util", "createObj", Any, args) |> asOptimizable "pojo" |> Some - | "keyValueList", [caseRule; keyValueList] -> + Helper.LibCall(com, "util", "createObj", Any, args) + |> asOptimizable "pojo" + |> Some + | "keyValueList", [ caseRule; keyValueList ] -> // makePojo com ctx caseRule keyValueList - let args = [keyValueList; caseRule] - Helper.LibCall(com, "map_util", "keyValueList", Any, args) |> asOptimizable "pojo" |> Some + let args = [ keyValueList; caseRule ] + + Helper.LibCall(com, "map_util", "keyValueList", Any, args) + |> asOptimizable "pojo" + |> Some | "toPlainJsObj", _ -> let emptyObj = ObjectExpr([], t, None) - Helper.GlobalCall("Object", Any, emptyObj::args, memb="assign", ?loc=r) |> Some - | "jsOptions", [arg] -> - makePojoFromLambda com arg |> Some - | "jsThis", _ -> - emitJsExpr r t [] "self" |> Some + + Helper.GlobalCall("Object", Any, emptyObj :: args, memb = "assign", ?loc = r) + |> Some + | "jsOptions", [ arg ] -> makePojoFromLambda com arg |> Some + | "jsThis", _ -> emitJsExpr r t [] "self" |> Some | "jsConstructor", _ -> match (genArg com ctx r 0 i.GenericArgs) with - | DeclaredType(ent, _) -> com.GetEntity(ent) |> pyConstructor com |> Some - | _ -> "Only declared types define a function constructor in JS" - |> addError com ctx.InlinePath r; None - | "createEmpty", _ -> - typedObjExpr t [] |> Some + | DeclaredType (ent, _) -> com.GetEntity(ent) |> pyConstructor com |> Some + | _ -> + "Only declared types define a function constructor in JS" + |> addError com ctx.InlinePath r + + None + | "createEmpty", _ -> typedObjExpr t [] |> Some // Deprecated methods - | "ofJson", _ -> Helper.GlobalCall("JSON", t, args, memb="parse", ?loc=r) |> Some - | "toJson", _ -> Helper.GlobalCall("JSON", t, args, memb="stringify", ?loc=r) |> Some - | ("inflate"|"deflate"), _ -> List.tryHead args + | "ofJson", _ -> + Helper.GlobalCall("JSON", t, args, memb = "parse", ?loc = r) + |> Some + | "toJson", _ -> + Helper.GlobalCall("JSON", t, args, memb = "stringify", ?loc = r) + |> Some + | ("inflate" + | "deflate"), + _ -> List.tryHead args | _ -> None | _ -> None let getReference r t expr = getAttachedMemberWith r t expr "contents" let setReference r expr value = setExpr r expr (makeStrConst "contents") value -let newReference com r t value = Helper.LibCall(com, "types", "FSharpRef", t, [value], isPyConstructor=true, ?loc=r) + +let newReference com r t value = + Helper.LibCall(com, "types", "FSharpRef", t, [ value ], isPyConstructor = true, ?loc = r) let references (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg, args with | "get_Value", Some callee, _ -> getReference r t callee |> Some - | "set_Value", Some callee, [value] -> setReference r callee value |> Some + | "set_Value", Some callee, [ value ] -> setReference r callee value |> Some | _ -> None let getMangledNames (i: CallInfo) (thisArg: Expr option) = let isStatic = Option.isNone thisArg let pos = i.DeclaringEntityFullName.LastIndexOf('.') - let moduleName = i.DeclaringEntityFullName.Substring(0, pos).Replace("Microsoft.", "") - let entityName = i.DeclaringEntityFullName.Substring(pos + 1) |> Naming.cleanNameAsPyIdentifier - let memberName = i.CompiledName |> Naming.cleanNameAsPyIdentifier - let mangledName = Naming.buildNameWithoutSanitationFrom entityName isStatic memberName i.OverloadSuffix + + let moduleName = + i + .DeclaringEntityFullName + .Substring(0, pos) + .Replace("Microsoft.", "") + + let entityName = + i.DeclaringEntityFullName.Substring(pos + 1) + |> Naming.cleanNameAsPyIdentifier + + let memberName = + i.CompiledName |> Naming.cleanNameAsPyIdentifier + + let mangledName = + Naming.buildNameWithoutSanitationFrom entityName isStatic memberName i.OverloadSuffix + moduleName, mangledName let bclType (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = let moduleName, mangledName = getMangledNames i thisArg - let args = match thisArg with Some callee -> callee::args | _ -> args - Helper.LibCall(com, moduleName, mangledName, t, args, i.SignatureArgTypes, ?loc=r) |> Some + + let args = + match thisArg with + | Some callee -> callee :: args + | _ -> args + + Helper.LibCall(com, moduleName, mangledName, t, args, i.SignatureArgTypes, ?loc = r) + |> Some let fsharpModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) = let moduleName, mangledName = getMangledNames i thisArg - Helper.LibCall(com, moduleName, mangledName, t, args, i.SignatureArgTypes, ?loc=r) |> Some + + Helper.LibCall(com, moduleName, mangledName, t, args, i.SignatureArgTypes, ?loc = r) + |> Some // TODO: This is likely broken let getPrecompiledLibMangledName entityName memberName overloadSuffix isStatic = let memberName = Naming.sanitizeIdentForbiddenChars memberName let entityName = Naming.sanitizeIdentForbiddenChars entityName + let name, memberPart = match entityName, isStatic with | "", _ -> memberName, Naming.NoMemberPart | _, true -> entityName, Naming.StaticMemberPart(memberName, overloadSuffix) | _, false -> entityName, Naming.InstanceMemberPart(memberName, overloadSuffix) - Naming.buildNameWithoutSanitation name memberPart |> Naming.checkJsKeywords + + Naming.buildNameWithoutSanitation name memberPart + |> Naming.checkJsKeywords let fsFormat (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg, args with | "get_Value", Some callee, _ -> - getAttachedMemberWith None t callee "input" |> Some + getAttachedMemberWith None t callee "input" + |> Some | "PrintFormatToStringThen", _, _ -> match args with - | [_] -> Helper.LibCall(com, "string", "toText", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | [cont; fmt] -> Helper.InstanceCall(fmt, "cont", t, [cont]) |> Some + | [ _ ] -> + Helper.LibCall(com, "string", "toText", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | [ cont; fmt ] -> + Helper.InstanceCall(fmt, "cont", t, [ cont ]) + |> Some | _ -> None | "PrintFormatToString", _, _ -> - Helper.LibCall(com, "string", "toText", t, args, i.SignatureArgTypes, ?loc=r) |> Some + Helper.LibCall(com, "string", "toText", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | "PrintFormatLine", _, _ -> - Helper.LibCall(com, "string", "toConsole", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | ("PrintFormatToError"|"PrintFormatLineToError"), _, _ -> + Helper.LibCall(com, "string", "toConsole", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | ("PrintFormatToError" + | "PrintFormatLineToError"), + _, + _ -> // addWarning com ctx.FileName r "eprintf will behave as eprintfn" - Helper.LibCall(com, "string", "toConsoleError", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | ("PrintFormatToTextWriter"|"PrintFormatLineToTextWriter"), _, _::args -> + Helper.LibCall(com, "string", "toConsoleError", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | ("PrintFormatToTextWriter" + | "PrintFormatLineToTextWriter"), + _, + _ :: args -> // addWarning com ctx.FileName r "fprintfn will behave as printfn" - Helper.LibCall(com, "string", "toConsole", t, args, i.SignatureArgTypes, ?loc=r) |> Some + Helper.LibCall(com, "string", "toConsole", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | "PrintFormat", _, _ -> // addWarning com ctx.FileName r "Printf will behave as printfn" - Helper.LibCall(com, "string", "toConsole", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | "PrintFormatThen", _, arg::callee::_ -> - Helper.InstanceCall(callee, "cont", t, [arg]) |> Some + Helper.LibCall(com, "string", "toConsole", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | "PrintFormatThen", _, arg :: callee :: _ -> + Helper.InstanceCall(callee, "cont", t, [ arg ]) + |> Some | "PrintFormatToStringThenFail", _, _ -> - Helper.LibCall(com, "string", "toFail", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | ("PrintFormatToStringBuilder" // bprintf - | "PrintFormatToStringBuilderThen" // Printf.kbprintf - ), _, _ -> fsharpModule com ctx r t i thisArg args - | ".ctor", _, str::(Value(NewArray _, _) as values)::_ -> - Helper.LibCall(com, "string", "interpolate", t, [str; values], i.SignatureArgTypes, ?loc=r) |> Some - | ".ctor", _, arg::_ -> - Helper.LibCall(com, "string", "printf", t, [arg], i.SignatureArgTypes, ?loc=r) |> Some + Helper.LibCall(com, "string", "toFail", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | ("PrintFormatToStringBuilder" // bprintf + | "PrintFormatToStringBuilderThen"), // Printf.kbprintf + _, + _ -> fsharpModule com ctx r t i thisArg args + | ".ctor", _, str :: (Value (NewArray _, _) as values) :: _ -> + Helper.LibCall(com, "string", "interpolate", t, [ str; values ], i.SignatureArgTypes, ?loc = r) + |> Some + | ".ctor", _, arg :: _ -> + Helper.LibCall(com, "string", "printf", t, [ arg ], i.SignatureArgTypes, ?loc = r) + |> Some | _ -> None let operators (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = - let curriedApply r t applied args = - CurriedApply(applied, args, t, r) + let curriedApply r t applied args = CurriedApply(applied, args, t, r) let compose (com: ICompiler) r t f1 f2 = let argType, retType = match t with - | LambdaType(argType, retType) -> argType, retType + | LambdaType (argType, retType) -> argType, retType | _ -> Any, Any + let tempVar = makeUniqueIdent ctx argType "arg" + let tempVarExpr = match argType with // Erase unit references, because the arg may be erased | Unit -> Value(UnitConstant, None) | _ -> IdentExpr tempVar + let body = - [tempVarExpr] + [ tempVarExpr ] |> curriedApply None Any f1 |> List.singleton |> curriedApply r retType f2 + Lambda(tempVar, body, None) let math r t (args: Expr list) argTypes methName = let meth = Naming.lowerFirst methName - Helper.GlobalCall("math", t, args, argTypes, meth, ?loc=r) + Helper.GlobalCall("math", t, args, argTypes, meth, ?loc = r) match i.CompiledName, args with - | ("DefaultArg" | "DefaultValueArg"), _ -> - Helper.LibCall(com, "option", "defaultArg", t, args, i.SignatureArgTypes, ?loc=r) |> Some + | ("DefaultArg" + | "DefaultValueArg"), + _ -> + Helper.LibCall(com, "option", "defaultArg", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | "DefaultAsyncBuilder", _ -> - makeImportLib com t "singleton" "async_builder" |> Some + makeImportLib com t "singleton" "async_builder" + |> Some // Erased operators. // KeyValuePair is already compiled as a tuple - | ("KeyValuePattern"|"Identity"|"Box"|"Unbox"|"ToEnum"), [arg] -> TypeCast(arg, t) |> Some + | ("KeyValuePattern" + | "Identity" + | "Box" + | "Unbox" + | "ToEnum"), + [ arg ] -> TypeCast(arg, t) |> Some // Cast to unit to make sure nothing is returned when wrapped in a lambda, see #1360 | "Ignore", _ -> //Operation(Unary(UnaryVoid, args.Head), t, r) |> Some // "void $0" |> emitJsExpr r t args |> Some - Helper.LibCall(com, "util", "ignore", t, args, i.SignatureArgTypes, ?loc=r) |> Some + Helper.LibCall(com, "util", "ignore", t, args, i.SignatureArgTypes, ?loc = r) + |> Some // Number and String conversions - | ("ToSByte"|"ToByte"|"ToInt8"|"ToUInt8"|"ToInt16"|"ToUInt16"|"ToInt"|"ToUInt"|"ToInt32"|"ToUInt32"), _ -> - toInt com ctx r t args |> Some + | ("ToSByte" + | "ToByte" + | "ToInt8" + | "ToUInt8" + | "ToInt16" + | "ToUInt16" + | "ToInt" + | "ToUInt" + | "ToInt32" + | "ToUInt32"), + _ -> toInt com ctx r t args |> Some | "ToInt64", _ -> toLong com ctx r false t args |> Some | "ToUInt64", _ -> toLong com ctx r true t args |> Some - | ("ToSingle"|"ToDouble"), _ -> toFloat com ctx r t args |> Some + | ("ToSingle" + | "ToDouble"), + _ -> toFloat com ctx r t args |> Some | "ToDecimal", _ -> toDecimal com ctx r t args |> Some | "ToChar", _ -> toChar args.Head |> Some | "ToString", _ -> toString com ctx r args |> Some - | "CreateSequence", [xs] -> toSeq t xs |> Some - | "CreateDictionary", [arg] -> makeDictionary com ctx r t arg |> Some - | "CreateSet", _ -> (genArg com ctx r 0 i.GenericArgs) |> makeSet com ctx r t "OfSeq" args |> Some + | "CreateSequence", [ xs ] -> toSeq t xs |> Some + | "CreateDictionary", [ arg ] -> makeDictionary com ctx r t arg |> Some + | "CreateSet", _ -> + (genArg com ctx r 0 i.GenericArgs) + |> makeSet com ctx r t "OfSeq" args + |> Some // Ranges - | ("op_Range"|"op_RangeStep"), _ -> + | ("op_Range" + | "op_RangeStep"), + _ -> let genArg = genArg com ctx r 0 i.GenericArgs + let addStep args = match args with - | [first; last] -> [first; getOne com ctx genArg; last] + | [ first; last ] -> [ first; getOne com ctx genArg; last ] | _ -> args + let modul, meth, args = match genArg with | Char -> "Range", "rangeChar", args @@ -1500,425 +1927,665 @@ let operators (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr o | Builtin BclDecimal -> "Range", "rangeDecimal", addStep args | Builtin BclBigInt -> "Range", "rangeBigInt", addStep args | _ -> "Range", "rangeDouble", addStep args - Helper.LibCall(com, modul, meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + + Helper.LibCall(com, modul, meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some // Pipes and composition - | "op_PipeRight", [x; f] - | "op_PipeLeft", [f; x] -> curriedApply r t f [x] |> Some - | "op_PipeRight2", [x; y; f] - | "op_PipeLeft2", [f; x; y] -> curriedApply r t f [x; y] |> Some - | "op_PipeRight3", [x; y; z; f] - | "op_PipeLeft3", [f; x; y; z] -> curriedApply r t f [x; y; z] |> Some - | "op_ComposeRight", [f1; f2] -> compose com r t f1 f2 |> Some - | "op_ComposeLeft", [f2; f1] -> compose com r t f1 f2 |> Some + | "op_PipeRight", [ x; f ] + | "op_PipeLeft", [ f; x ] -> curriedApply r t f [ x ] |> Some + | "op_PipeRight2", [ x; y; f ] + | "op_PipeLeft2", [ f; x; y ] -> curriedApply r t f [ x; y ] |> Some + | "op_PipeRight3", [ x; y; z; f ] + | "op_PipeLeft3", [ f; x; y; z ] -> curriedApply r t f [ x; y; z ] |> Some + | "op_ComposeRight", [ f1; f2 ] -> compose com r t f1 f2 |> Some + | "op_ComposeLeft", [ f2; f1 ] -> compose com r t f1 f2 |> Some // Strings - | ("PrintFormatToString" // sprintf - | "PrintFormatToStringThen" // Printf.ksprintf - | "PrintFormat" | "PrintFormatLine" // printf / printfn - | "PrintFormatToError" // eprintf - | "PrintFormatLineToError" // eprintfn - | "PrintFormatThen" // Printf.kprintf - | "PrintFormatToStringThenFail" // Printf.failwithf - | "PrintFormatToStringBuilder" // bprintf - | "PrintFormatToStringBuilderThen" // Printf.kbprintf - ), _ -> fsFormat com ctx r t i thisArg args + | ("PrintFormatToString" // sprintf + | "PrintFormatToStringThen" // Printf.ksprintf + | "PrintFormat" + | "PrintFormatLine" // printf / printfn + | "PrintFormatToError" // eprintf + | "PrintFormatLineToError" // eprintfn + | "PrintFormatThen" // Printf.kprintf + | "PrintFormatToStringThenFail" // Printf.failwithf + | "PrintFormatToStringBuilder" // bprintf + | "PrintFormatToStringBuilderThen"), // Printf.kbprintf + _ -> fsFormat com ctx r t i thisArg args | ("Failure" - | "FailurePattern" // (|Failure|_|) - | "LazyPattern" // (|Lazy|_|) - | "Lock" // lock - | "NullArg" // nullArg - | "Using" // using - ), _ -> fsharpModule com ctx r t i thisArg args + | "FailurePattern" // (|Failure|_|) + | "LazyPattern" // (|Lazy|_|) + | "Lock" // lock + | "NullArg" // nullArg + | "Using"), // using + _ -> fsharpModule com ctx r t i thisArg args // Exceptions - | "FailWith", [msg] | "InvalidOp", [msg] -> - makeThrow r t (error msg) |> Some - | "InvalidArg", [argName; msg] -> + | "FailWith", [ msg ] + | "InvalidOp", [ msg ] -> makeThrow r t (error msg) |> Some + | "InvalidArg", [ argName; msg ] -> let msg = add (add msg (str "\\nParameter name: ")) argName makeThrow r t (error msg) |> Some - | "Raise", [arg] -> makeThrow r t arg |> Some + | "Raise", [ arg ] -> makeThrow r t arg |> Some | "Reraise", _ -> match ctx.CaughtException with | Some ex -> makeThrow r t (IdentExpr ex) |> Some | None -> "`reraise` used in context where caught exception is not available, please report" |> addError com ctx.InlinePath r + makeThrow r t (error (str "")) |> Some // Math functions // TODO: optimize square pow: x * x - | "Pow", _ | "PowInteger", _ | "op_Exponentiation", _ -> + | "Pow", _ + | "PowInteger", _ + | "op_Exponentiation", _ -> match resolveArgTypes i.SignatureArgTypes i.GenericArgs with - | Builtin (BclDecimal)::_ -> - Helper.LibCall(com, "decimal", "pow", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + | Builtin (BclDecimal) :: _ -> + Helper.LibCall(com, "decimal", "pow", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some | _ -> math r t args i.SignatureArgTypes "pow" |> Some - | ("Ceiling" | "Floor" as meth), _ -> + | ("Ceiling" + | "Floor" as meth), + _ -> let meth = Naming.lowerFirst meth + match resolveArgTypes i.SignatureArgTypes i.GenericArgs with - | Builtin (BclDecimal)::_ -> - Helper.LibCall(com, "decimal", meth, t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + | Builtin (BclDecimal) :: _ -> + Helper.LibCall(com, "decimal", meth, t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some | _ -> - let meth = if meth = "ceiling" then "ceil" else meth + let meth = + if meth = "ceiling" then + "ceil" + else + meth + math r t args i.SignatureArgTypes meth |> Some - | "Log", [arg1; arg2] -> + | "Log", [ arg1; arg2 ] -> // "Math.log($0) / Math.log($1)" - let dividend = math None t [arg1] (List.take 1 i.SignatureArgTypes) "log" - let divisor = math None t [arg2] (List.skip 1 i.SignatureArgTypes) "log" - makeBinOp r t dividend divisor BinaryDivide |> Some + let dividend = + math None t [ arg1 ] (List.take 1 i.SignatureArgTypes) "log" + + let divisor = + math None t [ arg2 ] (List.skip 1 i.SignatureArgTypes) "log" + + makeBinOp r t dividend divisor BinaryDivide + |> Some | "Abs", _ -> match resolveArgTypes i.SignatureArgTypes i.GenericArgs with - | Builtin (BclInt64 | BclBigInt | BclDecimal as bt)::_ -> - Helper.LibCall(com, coreModFor bt, "abs", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some - | _ -> math r t args i.SignatureArgTypes i.CompiledName |> Some - | "Acos", _ | "Asin", _ | "Atan", _ | "Atan2", _ - | "Cos", _ | "Cosh", _ | "Exp", _ | "Log", _ | "Log10", _ - | "Sin", _ | "Sinh", _ | "Sqrt", _ | "Tan", _ | "Tanh", _ -> - math r t args i.SignatureArgTypes i.CompiledName |> Some + | Builtin (BclInt64 + | BclBigInt + | BclDecimal as bt) :: _ -> + Helper.LibCall(com, coreModFor bt, "abs", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some + | _ -> + math r t args i.SignatureArgTypes i.CompiledName + |> Some + | "Acos", _ + | "Asin", _ + | "Atan", _ + | "Atan2", _ + | "Cos", _ + | "Cosh", _ + | "Exp", _ + | "Log", _ + | "Log10", _ + | "Sin", _ + | "Sinh", _ + | "Sqrt", _ + | "Tan", _ + | "Tanh", _ -> + math r t args i.SignatureArgTypes i.CompiledName + |> Some | "Round", _ -> match resolveArgTypes i.SignatureArgTypes i.GenericArgs with - | Builtin (BclDecimal)::_ -> - Helper.LibCall(com, "decimal", "round", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some - | _ -> Helper.LibCall(com, "util", "round", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + | Builtin (BclDecimal) :: _ -> + Helper.LibCall(com, "decimal", "round", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some + | _ -> + Helper.LibCall(com, "util", "round", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some | "Truncate", _ -> match resolveArgTypes i.SignatureArgTypes i.GenericArgs with - | Builtin (BclDecimal)::_ -> - Helper.LibCall(com, "decimal", "truncate", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some - | _ -> Helper.GlobalCall("math", t, args, i.SignatureArgTypes, memb="trunc", ?loc=r) |> Some + | Builtin (BclDecimal) :: _ -> + Helper.LibCall(com, "decimal", "truncate", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some + | _ -> + Helper.GlobalCall("math", t, args, i.SignatureArgTypes, memb = "trunc", ?loc = r) + |> Some | "Sign", _ -> let args = toFloat com ctx r t args |> List.singleton - Helper.LibCall(com, "util", "sign", t, args, i.SignatureArgTypes, ?loc=r) |> Some + + Helper.LibCall(com, "util", "sign", t, args, i.SignatureArgTypes, ?loc = r) + |> Some // Numbers - | ("Infinity"|"InfinitySingle"), _ -> - Helper.GlobalIdent("Number", "POSITIVE_INFINITY", t, ?loc=r) |> Some - | ("NaN"|"NaNSingle"), _ -> - Helper.GlobalIdent("Number", "NaN", t, ?loc=r) |> Some - | "Fst", [tup] -> Get(tup, TupleIndex 0, t, r) |> Some - | "Snd", [tup] -> Get(tup, TupleIndex 1, t, r) |> Some + | ("Infinity" + | "InfinitySingle"), + _ -> + Helper.GlobalIdent("Number", "POSITIVE_INFINITY", t, ?loc = r) + |> Some + | ("NaN" + | "NaNSingle"), + _ -> + Helper.GlobalIdent("Number", "NaN", t, ?loc = r) + |> Some + | "Fst", [ tup ] -> Get(tup, TupleIndex 0, t, r) |> Some + | "Snd", [ tup ] -> Get(tup, TupleIndex 1, t, r) |> Some // Reference - | "op_Dereference", [arg] -> getReference r t arg |> Some - | "op_ColonEquals", [o; v] -> setReference r o v |> Some - | "Ref", [arg] -> newReference com r t arg |> Some - | ("Increment"|"Decrement"), _ -> - if i.CompiledName = "Increment" then "$0.contents +=1" else "$0.contents -=1" - |> emitJsExpr r t args |> Some + | "op_Dereference", [ arg ] -> getReference r t arg |> Some + | "op_ColonEquals", [ o; v ] -> setReference r o v |> Some + | "Ref", [ arg ] -> newReference com r t arg |> Some + | ("Increment" + | "Decrement"), + _ -> + if i.CompiledName = "Increment" then + "$0.contents +=1" + else + "$0.contents -=1" + |> emitJsExpr r t args + |> Some // Concatenates two lists - | "op_Append", _ -> Helper.LibCall(com, "list", "append", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some - | (Operators.inequality | "Neq"), [left; right] -> equals com ctx r false left right |> Some - | (Operators.equality | "Eq"), [left; right] -> equals com ctx r true left right |> Some - | "IsNull", [arg] -> makeEqOp r arg (Null arg.Type |> makeValue None) BinaryEqual |> Some - | "Hash", [arg] -> structuralHash com r arg |> Some + | "op_Append", _ -> + Helper.LibCall(com, "list", "append", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some + | (Operators.inequality + | "Neq"), + [ left; right ] -> equals com ctx r false left right |> Some + | (Operators.equality + | "Eq"), + [ left; right ] -> equals com ctx r true left right |> Some + | "IsNull", [ arg ] -> + makeEqOp r arg (Null arg.Type |> makeValue None) BinaryEqual + |> Some + | "Hash", [ arg ] -> structuralHash com r arg |> Some // Comparison - | "Compare", [left; right] -> compare com ctx r left right |> Some - | (Operators.lessThan | "Lt"), [left; right] -> compareIf com ctx r left right BinaryLess |> Some - | (Operators.lessThanOrEqual | "Lte"), [left; right] -> compareIf com ctx r left right BinaryLessOrEqual |> Some - | (Operators.greaterThan | "Gt"), [left; right] -> compareIf com ctx r left right BinaryGreater |> Some - | (Operators.greaterThanOrEqual | "Gte"), [left; right] -> compareIf com ctx r left right BinaryGreaterOrEqual |> Some - | ("Min"|"Max"|"Clamp" as meth), _ -> + | "Compare", [ left; right ] -> compare com ctx r left right |> Some + | (Operators.lessThan + | "Lt"), + [ left; right ] -> compareIf com ctx r left right BinaryLess |> Some + | (Operators.lessThanOrEqual + | "Lte"), + [ left; right ] -> + compareIf com ctx r left right BinaryLessOrEqual + |> Some + | (Operators.greaterThan + | "Gt"), + [ left; right ] -> + compareIf com ctx r left right BinaryGreater + |> Some + | (Operators.greaterThanOrEqual + | "Gte"), + [ left; right ] -> + compareIf com ctx r left right BinaryGreaterOrEqual + |> Some + | ("Min" + | "Max" + | "Clamp" as meth), + _ -> let f = makeComparerFunction com ctx t - Helper.LibCall(com, "util", Naming.lowerFirst meth, t, f::args, i.SignatureArgTypes, ?loc=r) |> Some - | "Not", [operand] -> // TODO: Check custom operator? + + Helper.LibCall(com, "util", Naming.lowerFirst meth, t, f :: args, i.SignatureArgTypes, ?loc = r) + |> Some + | "Not", [ operand ] -> // TODO: Check custom operator? makeUnOp r t operand UnaryNot |> Some | Patterns.SetContains Operators.standardSet, _ -> - applyOp com ctx r t i.CompiledName args i.SignatureArgTypes i.GenericArgs |> Some + applyOp com ctx r t i.CompiledName args i.SignatureArgTypes i.GenericArgs + |> Some // Type info | "TypeOf", _ -> - (genArg com ctx r 0 i.GenericArgs) |> makeTypeInfo r |> Some - | "TypeDefOf", _ -> (genArg com ctx r 0 i.GenericArgs) |> makeTypeDefinitionInfo r |> Some + (genArg com ctx r 0 i.GenericArgs) + |> makeTypeInfo r + |> Some + | "TypeDefOf", _ -> + (genArg com ctx r 0 i.GenericArgs) + |> makeTypeDefinitionInfo r + |> Some | _ -> None let chars (com: ICompiler) (ctx: Context) r t (i: CallInfo) (_: Expr option) (args: Expr list) = - let icall r t args argTypes memb = + let icall r t args argTypes memb = match args, argTypes with - | thisArg::args, _::argTypes -> + | thisArg :: args, _ :: argTypes -> let info = makeCallInfo None args argTypes - getAttachedMember thisArg memb |> makeCall r t info |> Some + + getAttachedMember thisArg memb + |> makeCall r t info + |> Some | _ -> None + match i.CompiledName with | "ToUpper" -> icall r t args i.SignatureArgTypes "upper" | "ToUpperInvariant" -> icall r t args i.SignatureArgTypes "upper" | "ToLower" -> icall r t args i.SignatureArgTypes "lower" | "ToLowerInvariant" -> icall r t args i.SignatureArgTypes "lower" | "ToString" -> toString com ctx r args |> Some - | "GetUnicodeCategory" | "IsControl" | "IsDigit" | "IsLetter" - | "IsLetterOrDigit" | "IsUpper" | "IsLower" | "IsNumber" - | "IsPunctuation" | "IsSeparator" | "IsSymbol" | "IsWhiteSpace" - | "IsHighSurrogate" | "IsLowSurrogate" | "IsSurrogate" -> + | "GetUnicodeCategory" + | "IsControl" + | "IsDigit" + | "IsLetter" + | "IsLetterOrDigit" + | "IsUpper" + | "IsLower" + | "IsNumber" + | "IsPunctuation" + | "IsSeparator" + | "IsSymbol" + | "IsWhiteSpace" + | "IsHighSurrogate" + | "IsLowSurrogate" + | "IsSurrogate" -> let methName = Naming.lowerFirst i.CompiledName - let methName = if List.length args > 1 then methName + "2" else methName - Helper.LibCall(com, "char", methName, t, args, i.SignatureArgTypes, ?loc=r) |> Some - | "IsSurrogatePair" | "Parse" -> + + let methName = + if List.length args > 1 then + methName + "2" + else + methName + + Helper.LibCall(com, "char", methName, t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | "IsSurrogatePair" + | "Parse" -> let methName = Naming.lowerFirst i.CompiledName - Helper.LibCall(com, "char", methName, t, args, i.SignatureArgTypes, ?loc=r) |> Some + + Helper.LibCall(com, "char", methName, t, args, i.SignatureArgTypes, ?loc = r) + |> Some | _ -> None let implementedStringFunctions = - set [| "Compare" - "CompareTo" - "EndsWith" - "Format" - "IndexOfAny" - "Insert" - "IsNullOrEmpty" - "IsNullOrWhiteSpace" - "PadLeft" - "PadRight" - "Remove" - "Replace" - "Substring" - |] - -let getEnumerator com r t expr = - Helper.LibCall(com, "util", "getEnumerator", t, [toSeq Any expr], ?loc=r) + set [| + "Compare" + "CompareTo" + "EndsWith" + "Format" + "IndexOfAny" + "Insert" + "IsNullOrEmpty" + "IsNullOrWhiteSpace" + "PadLeft" + "PadRight" + "Remove" + "Replace" + "Substring" + |] + +let getEnumerator com r t expr = Helper.LibCall(com, "util", "getEnumerator", t, [ toSeq Any expr ], ?loc = r) let strings (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg, args with - | ".ctor", _, fstArg::_ -> + | ".ctor", _, fstArg :: _ -> match fstArg.Type with | Char -> match args with - | [_; _] -> emitJsExpr r t args "$0 * $1" |> Some // String(char, int) - | _ -> "Unexpected arguments in System.String constructor." - |> addErrorAndReturnNull com ctx.InlinePath r |> Some + | [ _; _ ] -> emitJsExpr r t args "$0 * $1" |> Some // String(char, int) + | _ -> + "Unexpected arguments in System.String constructor." + |> addErrorAndReturnNull com ctx.InlinePath r + |> Some | Array _ -> match args with - | [_] -> emitJsExpr r t args "''.join($0)" |> Some // String(char[]) - | [_; _; _] -> emitJsExpr r t args "''.join($0)[$1:$2+1]" |> Some // String(char[], int, int) - | _ -> "Unexpected arguments in System.String constructor." - |> addErrorAndReturnNull com ctx.InlinePath r |> Some - | _ -> - fsFormat com ctx r t i thisArg args - | "get_Length", Some c, _ -> Helper.GlobalCall("len", t, [c], [t], ?loc=r) |> Some + | [ _ ] -> emitJsExpr r t args "''.join($0)" |> Some // String(char[]) + | [ _; _; _ ] -> emitJsExpr r t args "''.join($0)[$1:$2+1]" |> Some // String(char[], int, int) + | _ -> + "Unexpected arguments in System.String constructor." + |> addErrorAndReturnNull com ctx.InlinePath r + |> Some + | _ -> fsFormat com ctx r t i thisArg args + | "get_Length", Some c, _ -> + Helper.GlobalCall("len", t, [ c ], [ t ], ?loc = r) + |> Some | "get_Chars", Some c, _ -> - Helper.LibCall(com, "string", "getCharAtIndex", t, args, i.SignatureArgTypes, c, ?loc=r) |> Some - | "Equals", Some x, [y] | "Equals", None, [x; y] -> - makeEqOp r x y BinaryEqualStrict |> Some - | "Equals", Some x, [y; kind] | "Equals", None, [x; y; kind] -> - let left = Helper.LibCall(com, "string", "compare", Number(Int32, None), [x; y; kind]) - makeEqOp r left (makeIntConst 0) BinaryEqualStrict |> Some + Helper.LibCall(com, "string", "getCharAtIndex", t, args, i.SignatureArgTypes, c, ?loc = r) + |> Some + | "Equals", Some x, [ y ] + | "Equals", None, [ x; y ] -> makeEqOp r x y BinaryEqualStrict |> Some + | "Equals", Some x, [ y; kind ] + | "Equals", None, [ x; y; kind ] -> + let left = + Helper.LibCall(com, "string", "compare", Number(Int32, None), [ x; y; kind ]) + + makeEqOp r left (makeIntConst 0) BinaryEqualStrict + |> Some | "GetEnumerator", Some c, _ -> getEnumerator com r t c |> Some - | "Contains", Some c, arg::_ -> + | "Contains", Some c, arg :: _ -> if (List.length args) > 1 then addWarning com ctx.InlinePath r "String.Contains: second argument is ignored" - let left = Helper.InstanceCall(c, "find", Number(Int32, None), [arg]) - makeEqOp r left (makeIntConst 0) BinaryGreaterOrEqual |> Some - | "StartsWith", Some c, [_str] -> - let left = Helper.InstanceCall(c, "find", Number(Int32, None), args) - makeEqOp r left (makeIntConst 0) BinaryEqualStrict |> Some - | "StartsWith", Some c, [_str; _comp] -> - Helper.LibCall(com, "string", "startsWith", t, args, i.SignatureArgTypes, c, ?loc=r) |> Some - | ReplaceName [ "ToUpper", "upper" - "ToUpperInvariant", "upper" - "ToLower", "lower" - "ToLowerInvariant", "lower" ] methName, Some c, args -> - Helper.InstanceCall(c, methName, t, args, i.SignatureArgTypes, ?loc=r) |> Some + + let left = + Helper.InstanceCall(c, "find", Number(Int32, None), [ arg ]) + + makeEqOp r left (makeIntConst 0) BinaryGreaterOrEqual + |> Some + | "StartsWith", Some c, [ _str ] -> + let left = + Helper.InstanceCall(c, "find", Number(Int32, None), args) + + makeEqOp r left (makeIntConst 0) BinaryEqualStrict + |> Some + | "StartsWith", Some c, [ _str; _comp ] -> + Helper.LibCall(com, "string", "startsWith", t, args, i.SignatureArgTypes, c, ?loc = r) + |> Some + | ReplaceName [ "ToUpper", "upper"; "ToUpperInvariant", "upper"; "ToLower", "lower"; "ToLowerInvariant", "lower" ] methName, + Some c, + args -> + Helper.InstanceCall(c, methName, t, args, i.SignatureArgTypes, ?loc = r) + |> Some | "IndexOf", Some c, _ -> match args with - | [ExprType Char] - | [ExprType String] - | [ExprType Char; ExprType(Number(Int32, None))] - | [ExprType String; ExprType(Number(Int32, None))] -> - Helper.InstanceCall(c, "find", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | _ -> "The only extra argument accepted for String.IndexOf/LastIndexOf is startIndex." - |> addErrorAndReturnNull com ctx.InlinePath r |> Some + | [ ExprType Char ] + | [ ExprType String ] + | [ ExprType Char; ExprType (Number (Int32, None)) ] + | [ ExprType String; ExprType (Number (Int32, None)) ] -> + Helper.InstanceCall(c, "find", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | _ -> + "The only extra argument accepted for String.IndexOf/LastIndexOf is startIndex." + |> addErrorAndReturnNull com ctx.InlinePath r + |> Some | "LastIndexOf", Some c, _ -> match args with - | [ExprType Char] - | [ExprType String] -> - Helper.InstanceCall(c, "rfind", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | [ExprType Char as str; ExprType(Number(Int32, None)) as start] - | [ExprType String as str; ExprType(Number(Int32, None)) as start] -> - Helper.InstanceCall(c, "rfind", t, [str; Value(NumberConstant(0.0, Int32, None), None); start], i.SignatureArgTypes, ?loc=r) |> Some - | _ -> "The only extra argument accepted for String.IndexOf/LastIndexOf is startIndex." - |> addErrorAndReturnNull com ctx.InlinePath r |> Some - | ("Trim" | "TrimStart" | "TrimEnd"), Some c, _ -> + | [ ExprType Char ] + | [ ExprType String ] -> + Helper.InstanceCall(c, "rfind", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | [ ExprType Char as str; ExprType (Number (Int32, None)) as start ] + | [ ExprType String as str; ExprType (Number (Int32, None)) as start ] -> + Helper.InstanceCall(c, "rfind", t, [ str; Value(NumberConstant(0.0, Int32, None), None); start ], i.SignatureArgTypes, ?loc = r) + |> Some + | _ -> + "The only extra argument accepted for String.IndexOf/LastIndexOf is startIndex." + |> addErrorAndReturnNull com ctx.InlinePath r + |> Some + | ("Trim" + | "TrimStart" + | "TrimEnd"), + Some c, + _ -> let methName = match i.CompiledName with | "TrimStart" -> "lstrip" | "TrimEnd" -> "rstrip" | _ -> "strip" + match args with - | [] -> Helper.InstanceCall(c, methName, t, [], i.SignatureArgTypes, ?loc=r) |> Some - | head::tail -> + | [] -> + Helper.InstanceCall(c, methName, t, [], i.SignatureArgTypes, ?loc = r) + |> Some + | head :: tail -> let spread = match head.Type, tail with | Array _, [] -> true | _ -> false - Helper.LibCall(com, "string", Naming.lowerFirst i.CompiledName, t, c::args, hasSpread=spread, ?loc=r) |> Some - | "ToCharArray", Some c, _ -> - stringToCharArray t c |> Some + + Helper.LibCall(com, "string", Naming.lowerFirst i.CompiledName, t, c :: args, hasSpread = spread, ?loc = r) + |> Some + | "ToCharArray", Some c, _ -> stringToCharArray t c |> Some | "Split", Some c, _ -> match args with // Optimization - | [] -> Helper.InstanceCall(c, "split", t, [makeStrConst ""]) |> Some - | [Value(CharConstant _,_) as separator] - | [StringConst _ as separator] - | [Value(NewArray([separator],_),_)] -> - Helper.InstanceCall(c, "split", t, [separator]) |> Some - | [arg1; ExprType(Enum _) as arg2] -> + | [] -> + Helper.InstanceCall(c, "split", t, [ makeStrConst "" ]) + |> Some + | [ Value (CharConstant _, _) as separator ] + | [ StringConst _ as separator ] + | [ Value (NewArray ([ separator ], _), _) ] -> + Helper.InstanceCall(c, "split", t, [ separator ]) + |> Some + | [ arg1; ExprType (Enum _) as arg2 ] -> let arg1 = match arg1.Type with | Array _ -> arg1 - | _ -> Value(NewArray([arg1], String), None) - let args = [arg1; Value(Null Any, None); arg2] - Helper.LibCall(com, "string", "split", t, c::args, ?loc=r) |> Some + | _ -> Value(NewArray([ arg1 ], String), None) + + let args = [ arg1; Value(Null Any, None); arg2 ] + + Helper.LibCall(com, "string", "split", t, c :: args, ?loc = r) + |> Some | args -> - Helper.LibCall(com, "string", "split", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + Helper.LibCall(com, "string", "split", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some | "Join", None, _ -> let methName = match i.SignatureArgTypes with - | [_; Array _; Number _; Number _] -> "joinWithIndices" + | [ _; Array _; Number _; Number _ ] -> "joinWithIndices" | _ -> "join" - Helper.LibCall(com, "string", methName, t, args, ?loc=r) |> Some + + Helper.LibCall(com, "string", methName, t, args, ?loc = r) + |> Some | "Concat", None, _ -> match i.SignatureArgTypes with - | [Array _ | IEnumerable] -> - Helper.LibCall(com, "string", "join", t, ((makeStrConst "")::args), ?loc=r) |> Some + | [ Array _ | IEnumerable ] -> + Helper.LibCall(com, "string", "join", t, ((makeStrConst "") :: args), ?loc = r) + |> Some | _ -> - Helper.LibCall(com, "string", "concat", t, args, hasSpread=true, ?loc=r) |> Some + Helper.LibCall(com, "string", "concat", t, args, hasSpread = true, ?loc = r) + |> Some | "CompareOrdinal", None, _ -> - Helper.LibCall(com, "string", "compareOrdinal", t, args, ?loc=r) |> Some + Helper.LibCall(com, "string", "compareOrdinal", t, args, ?loc = r) + |> Some | Patterns.SetContains implementedStringFunctions, thisArg, args -> - Helper.LibCall(com, "string", Naming.lowerFirst i.CompiledName, t, args, i.SignatureArgTypes, - hasSpread=i.HasSpread, ?thisArg=thisArg, ?loc=r) |> Some + Helper.LibCall( + com, + "string", + Naming.lowerFirst i.CompiledName, + t, + args, + i.SignatureArgTypes, + hasSpread = i.HasSpread, + ?thisArg = thisArg, + ?loc = r + ) + |> Some | _ -> None let stringModule (com: ICompiler) (ctx: Context) r t (i: CallInfo) (_: Expr option) (args: Expr list) = match i.CompiledName, args with - | "Length", [arg] -> getAttachedMemberWith r t arg "length" |> Some - | ("Iterate" | "IterateIndexed" | "ForAll" | "Exists"), _ -> - // Cast the string to char[], see #1279 - let args = args |> List.replaceLast (fun e -> stringToCharArray e.Type e) - Helper.LibCall(com, "seq", Naming.lowerFirst i.CompiledName, t, args, i.SignatureArgTypes, ?loc=r) |> Some - | ("Map" | "MapIndexed" | "Collect"), _ -> + | "Length", [ arg ] -> getAttachedMemberWith r t arg "length" |> Some + | ("Iterate" + | "IterateIndexed" + | "ForAll" + | "Exists"), + _ -> // Cast the string to char[], see #1279 - let args = args |> List.replaceLast (fun e -> stringToCharArray e.Type e) + let args = + args + |> List.replaceLast (fun e -> stringToCharArray e.Type e) + + Helper.LibCall(com, "seq", Naming.lowerFirst i.CompiledName, t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | ("Map" + | "MapIndexed" + | "Collect"), + _ -> + // Cast the string to char[], see #1279 + let args = + args + |> List.replaceLast (fun e -> stringToCharArray e.Type e) + let name = Naming.lowerFirst i.CompiledName - emitJsExpr r t [Helper.LibCall(com, "seq", name, Any, args, i.SignatureArgTypes)] "''.join(list($0))" |> Some + + emitJsExpr r t [ Helper.LibCall(com, "seq", name, Any, args, i.SignatureArgTypes) ] "''.join(list($0))" + |> Some | "Concat", _ -> - Helper.LibCall(com, "string", "join", t, args, ?loc=r) |> Some + Helper.LibCall(com, "string", "join", t, args, ?loc = r) + |> Some // Rest of StringModule methods | meth, args -> - Helper.LibCall(com, "string", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + Helper.LibCall(com, "string", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some let formattableString (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg, args with - | "Create", None, [str; args] -> objExpr ["str", str; "args", args] |> Some + | "Create", None, [ str; args ] -> objExpr [ "str", str; "args", args ] |> Some | "get_Format", Some x, _ -> getAttachedMemberWith r t x "str" |> Some - | "get_ArgumentCount", Some x, _ -> getAttachedMemberWith r t (getAttachedMember x "args") "length" |> Some - | "GetArgument", Some x, [idx] -> getExpr r t (getAttachedMember x "args") idx |> Some + | "get_ArgumentCount", Some x, _ -> + getAttachedMemberWith r t (getAttachedMember x "args") "length" + |> Some + | "GetArgument", Some x, [ idx ] -> + getExpr r t (getAttachedMember x "args") idx + |> Some | "GetArguments", Some x, [] -> getAttachedMemberWith r t x "args" |> Some | _ -> None let seqModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, args with - | "Cast", [arg] -> Some arg // Erase - | "CreateEvent", [addHandler; removeHandler; createHandler] -> - Helper.LibCall(com, "event", "createEvent", t, [addHandler; removeHandler], i.SignatureArgTypes, ?loc=r) |> Some - | "Distinct" | "DistinctBy" | "Except" | "GroupBy" | "CountBy" as meth, args -> + | "Cast", [ arg ] -> Some arg // Erase + | "CreateEvent", [ addHandler; removeHandler; createHandler ] -> + Helper.LibCall(com, "event", "createEvent", t, [ addHandler; removeHandler ], i.SignatureArgTypes, ?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", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + + 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 - Helper.LibCall(com, "seq", meth, t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + + Helper.LibCall(com, "seq", meth, t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some let resizeArrays (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg, args with // Use Any to prevent creation of a typed array (not resizable) // TODO: Include a value in Fable AST to indicate the Array should always be dynamic? - | ".ctor", _, [] -> - makeArray Any [] |> Some + | ".ctor", _, [] -> makeArray Any [] |> Some // Don't pass the size to `new Array()` because that would fill the array with null values - | ".ctor", _, [ExprType(Number _)] -> - makeArray Any [] |> Some + | ".ctor", _, [ ExprType (Number _) ] -> makeArray Any [] |> Some // Optimize expressions like `ResizeArray [|1|]` or `ResizeArray [1]` - | ".ctor", _, [ArrayOrListLiteral(vals,_)] -> - makeArray Any vals |> Some + | ".ctor", _, [ ArrayOrListLiteral (vals, _) ] -> makeArray Any vals |> Some | ".ctor", _, args -> - Helper.GlobalCall("list", t, args, ?loc=r) + Helper.GlobalCall("list", t, args, ?loc = r) |> asOptimizable "array" |> Some - | "get_Item", Some ar, [idx] -> getExpr r t ar idx |> Some - | "set_Item", Some ar, [idx; value] -> setExpr r ar idx value |> Some - | "Add", Some ar, [arg] -> - "void ($0)" |> emitJsExpr r t [Helper.InstanceCall(ar, "push", t, [arg])] |> Some - | "Remove", Some ar, [arg] -> - Helper.LibCall(com, "array", "removeInPlace", t, [arg; ar], ?loc=r) |> Some - | "RemoveAll", Some ar, [arg] -> - Helper.LibCall(com, "array", "removeAllInPlace", t, [arg; ar], ?loc=r) |> Some - | "FindIndex", Some ar, [arg] -> - Helper.LibCall(com, "array", "find_index", t, [arg; ar], ?loc=r) |> Some - | "FindLastIndex", Some ar, [arg] -> - Helper.LibCall(com, "array", "findLastIndex", t, [arg; ar], ?loc=r) |> Some - | "ForEach", Some ar, [arg] -> - Helper.LibCall(com, "array", "iterate", t, [arg; ar], ?loc=r) |> Some + | "get_Item", Some ar, [ idx ] -> getExpr r t ar idx |> Some + | "set_Item", Some ar, [ idx; value ] -> setExpr r ar idx value |> Some + | "Add", Some ar, [ arg ] -> + "void ($0)" + |> emitJsExpr r t [ Helper.InstanceCall(ar, "push", t, [ arg ]) ] + |> Some + | "Remove", Some ar, [ arg ] -> + Helper.LibCall(com, "array", "removeInPlace", t, [ arg; ar ], ?loc = r) + |> Some + | "RemoveAll", Some ar, [ arg ] -> + Helper.LibCall(com, "array", "removeAllInPlace", t, [ arg; ar ], ?loc = r) + |> Some + | "FindIndex", Some ar, [ arg ] -> + Helper.LibCall(com, "array", "find_index", t, [ arg; ar ], ?loc = r) + |> Some + | "FindLastIndex", Some ar, [ arg ] -> + Helper.LibCall(com, "array", "findLastIndex", t, [ arg; ar ], ?loc = r) + |> Some + | "ForEach", Some ar, [ arg ] -> + Helper.LibCall(com, "array", "iterate", t, [ arg; ar ], ?loc = r) + |> Some | "GetEnumerator", Some ar, _ -> getEnumerator com r t ar |> Some // ICollection members, implemented in dictionaries and sets too. We need runtime checks (see #1120) - | "get_Count", Some (MaybeCasted(ar)), _ -> + | "get_Count", Some (MaybeCasted (ar)), _ -> match ar.Type with // Fable translates System.Collections.Generic.List as Array // TODO: Check also IList? - | Array _ -> getAttachedMemberWith r t ar "length" |> Some - | _ -> Helper.LibCall(com, "util", "count", t, [ar], ?loc=r) |> Some + | Array _ -> getAttachedMemberWith r t ar "length" |> Some + | _ -> + Helper.LibCall(com, "util", "count", t, [ ar ], ?loc = r) + |> Some | "Clear", Some ar, _ -> - Helper.LibCall(com, "Util", "clear", t, [ar], ?loc=r) |> Some - | "Find", Some ar, [arg] -> - let opt = Helper.LibCall(com, "array", "tryFind", t, [arg; ar], ?loc=r) - Helper.LibCall(com, "Option", "defaultArg", t, [opt; defaultof com ctx t], ?loc=r) |> Some - | "Exists", Some ar, [arg] -> - let left = Helper.InstanceCall(ar, "index", Number(Int32, None), [arg], ?loc=r) - makeEqOp r left (makeIntConst -1) BinaryGreater |> Some - | "FindLast", Some ar, [arg] -> - let opt = Helper.LibCall(com, "array", "tryFindBack", t, [arg; ar], ?loc=r) - Helper.LibCall(com, "Option", "defaultArg", t, [opt; defaultof com ctx t], ?loc=r) |> Some - | "FindAll", Some ar, [arg] -> - Helper.LibCall(com, "Array", "filter", t, [arg; ar], ?loc=r) |> Some - | "AddRange", Some ar, [arg] -> - Helper.LibCall(com, "Array", "addRangeInPlace", t, [arg; ar], ?loc=r) |> Some - | "GetRange", Some ar, [idx; cnt] -> - Helper.LibCall(com, "Array", "getSubArray", t, [ar; idx; cnt], ?loc=r) |> Some - | "Contains", Some (MaybeCasted(ar)), [arg] -> - emitJsExpr r t [ar; arg] "$1 in $0" |> Some + Helper.LibCall(com, "Util", "clear", t, [ ar ], ?loc = r) + |> Some + | "Find", Some ar, [ arg ] -> + let opt = + Helper.LibCall(com, "array", "tryFind", t, [ arg; ar ], ?loc = r) + + Helper.LibCall(com, "Option", "defaultArg", t, [ opt; defaultof com ctx t ], ?loc = r) + |> Some + | "Exists", Some ar, [ arg ] -> + let left = + Helper.InstanceCall(ar, "index", Number(Int32, None), [ arg ], ?loc = r) + + makeEqOp r left (makeIntConst -1) BinaryGreater + |> Some + | "FindLast", Some ar, [ arg ] -> + let opt = + Helper.LibCall(com, "array", "tryFindBack", t, [ arg; ar ], ?loc = r) + + Helper.LibCall(com, "Option", "defaultArg", t, [ opt; defaultof com ctx t ], ?loc = r) + |> Some + | "FindAll", Some ar, [ arg ] -> + Helper.LibCall(com, "Array", "filter", t, [ arg; ar ], ?loc = r) + |> Some + | "AddRange", Some ar, [ arg ] -> + Helper.LibCall(com, "Array", "addRangeInPlace", t, [ arg; ar ], ?loc = r) + |> Some + | "GetRange", Some ar, [ idx; cnt ] -> + Helper.LibCall(com, "Array", "getSubArray", t, [ ar; idx; cnt ], ?loc = r) + |> Some + | "Contains", Some (MaybeCasted (ar)), [ arg ] -> emitJsExpr r t [ ar; arg ] "$1 in $0" |> Some | "IndexOf", Some ar, args -> - Helper.LibCall(com, "array", "index_of", t, ar::args, ?loc=r) |> Some - | "Insert", Some ar, [idx; arg] -> - Helper.InstanceCall(ar, "insert", t, [idx; arg], ?loc=r) |> Some - | "InsertRange", Some ar, [idx; arg] -> - Helper.LibCall(com, "array", "insertRangeInPlace", t, [idx; arg; ar], ?loc=r) |> Some + Helper.LibCall(com, "array", "index_of", t, ar :: args, ?loc = r) + |> Some + | "Insert", Some ar, [ idx; arg ] -> + Helper.InstanceCall(ar, "insert", t, [ idx; arg ], ?loc = r) + |> Some + | "InsertRange", Some ar, [ idx; arg ] -> + Helper.LibCall(com, "array", "insertRangeInPlace", t, [ idx; arg; ar ], ?loc = r) + |> Some | "RemoveRange", Some ar, args -> - Helper.LibCall(com, "array", "remove_many_at", t, args @ [ar], ?loc=r) |> Some - | "RemoveAt", Some ar, [idx] -> - Helper.InstanceCall(ar, "pop", t, [idx], ?loc=r) |> Some + Helper.LibCall(com, "array", "remove_many_at", t, args @ [ ar ], ?loc = r) + |> Some + | "RemoveAt", Some ar, [ idx ] -> + Helper.InstanceCall(ar, "pop", t, [ idx ], ?loc = r) + |> Some | "Reverse", Some ar, [] -> - Helper.InstanceCall(ar, "reverse", t, args, ?loc=r) |> Some + Helper.InstanceCall(ar, "reverse", t, args, ?loc = r) + |> Some | "Sort", Some ar, [] -> - let compareFn = (genArg com ctx r 0 i.GenericArgs) |> makeComparerFunction com ctx - Helper.InstanceCall(ar, "sort", t, [compareFn], ?loc=r) |> Some - | "Sort", Some ar, [ExprType(DelegateType _)] -> - Helper.InstanceCall(ar, "sort", t, args, ?loc=r) |> Some - | "Sort", Some ar, [arg] -> - Helper.LibCall(com, "array", "sortInPlace", t, [ar; arg], i.SignatureArgTypes, ?loc=r) |> Some + let compareFn = + (genArg com ctx r 0 i.GenericArgs) + |> makeComparerFunction com ctx + + Helper.InstanceCall(ar, "sort", t, [ compareFn ], ?loc = r) + |> Some + | "Sort", Some ar, [ ExprType (DelegateType _) ] -> + Helper.InstanceCall(ar, "sort", t, args, ?loc = r) + |> Some + | "Sort", Some ar, [ arg ] -> + Helper.LibCall(com, "array", "sortInPlace", t, [ ar; arg ], i.SignatureArgTypes, ?loc = r) + |> Some | "ToArray", Some ar, [] -> - Helper.InstanceCall(ar, "slice", t, args, ?loc=r) |> Some + Helper.InstanceCall(ar, "slice", t, args, ?loc = r) + |> Some | _ -> None let nativeArrayFunctions = dict [| //"Exists", "some" - //"Filter", "filter" - //"Find", "find" - //"FindIndex", "index" - //"ForAll", "all" - //"Iterate", "forEach" - //"Reduce", "reduce" - //"ReduceBack", "reduceRight" - |] + //"Filter", "filter" + //"Find", "find" + //"FindIndex", "index" + //"ForAll", "all" + //"Iterate", "forEach" + //"Reduce", "reduce" + //"ReduceBack", "reduceRight" + |] let tuples (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) = - let changeKind isStruct = function - | Value(NewTuple(args, _), r)::_ -> Value(NewTuple(args, isStruct), r) |> Some - | ExprType(Tuple(genArgs, _)) as e::_ -> TypeCast(e, Tuple(genArgs, isStruct)) |> Some + let changeKind isStruct = + function + | Value (NewTuple (args, _), r) :: _ -> Value(NewTuple(args, isStruct), r) |> Some + | ExprType (Tuple (genArgs, _)) as e :: _ -> TypeCast(e, Tuple(genArgs, isStruct)) |> Some | _ -> None + match i.CompiledName, thisArg with - | (".ctor"|"Create"), _ -> - let isStruct = i.DeclaringEntityFullName.StartsWith("System.ValueTuple") + | (".ctor" + | "Create"), + _ -> + let isStruct = + i.DeclaringEntityFullName.StartsWith("System.ValueTuple") + Value(NewTuple(args, isStruct), r) |> Some | "get_Item1", Some x -> Get(x, TupleIndex 0, t, r) |> Some | "get_Item2", Some x -> Get(x, TupleIndex 1, t, r) |> Some @@ -1936,202 +2603,322 @@ let tuples (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: E let copyToArray (com: ICompiler) r t (i: CallInfo) args = let method = match args with - | ExprType(Array(Number _))::_ when com.Options.TypedArrays -> "copyToTypedArray" + | ExprType (Array (Number _)) :: _ when com.Options.TypedArrays -> "copyToTypedArray" | _ -> "copyTo" - Helper.LibCall(com, "array", method, t, args, i.SignatureArgTypes, ?loc=r) |> Some + + Helper.LibCall(com, "array", method, t, args, i.SignatureArgTypes, ?loc = r) + |> Some let arrays (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg, args with - | "get_Length", Some arg, _ -> Helper.GlobalCall("len", t, [arg], [t], ?loc=r) |> Some - | "get_Item", Some arg, [idx] -> getExpr r t arg idx |> Some - | "set_Item", Some arg, [idx; value] -> setExpr r arg idx value |> Some - | "Copy", None, [_source; _sourceIndex; _target; _targetIndex; _count] -> copyToArray com r t i args - | "Copy", None, [source; target; count] -> copyToArray com r t i [source; makeIntConst 0; target; makeIntConst 0; count] + | "get_Length", Some arg, _ -> + Helper.GlobalCall("len", t, [ arg ], [ t ], ?loc = r) + |> Some + | "get_Item", Some arg, [ idx ] -> getExpr r t arg idx |> Some + | "set_Item", Some arg, [ idx; value ] -> setExpr r arg idx value |> Some + | "Copy", None, [ _source; _sourceIndex; _target; _targetIndex; _count ] -> copyToArray com r t i args + | "Copy", None, [ source; target; count ] -> copyToArray com r t i [ source; makeIntConst 0; target; makeIntConst 0; count ] | "IndexOf", None, args -> - Helper.LibCall(com, "array", "index_of", t, args, i.SignatureArgTypes, ?loc=r) |> Some + Helper.LibCall(com, "array", "index_of", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | "GetEnumerator", Some arg, _ -> getEnumerator com r t arg |> Some | _ -> None let arrayModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Expr option) (args: Expr list) = - let newArray size t = - Value(NewArrayFrom(size, t), None) + let newArray size t = Value(NewArrayFrom(size, t), None) + let createArray size value = match t, value with - | Array(Number _ as t2), None when com.Options.TypedArrays -> newArray size t2 + | Array (Number _ as t2), None when com.Options.TypedArrays -> newArray size t2 | Array t2, value -> - let value = value |> Option.defaultWith (fun () -> getZero com ctx t2) + let value = + value + |> Option.defaultWith (fun () -> getZero com ctx t2) // If we don't fill the array some operations may behave unexpectedly, like Array.prototype.reduce - Helper.LibCall(com, "array", "fill", t, [newArray size t2; makeIntConst 0; size; value]) - | _ -> $"Expecting an array type but got {t}" - |> addErrorAndReturnNull com ctx.InlinePath r + Helper.LibCall(com, "array", "fill", t, [ newArray size t2; makeIntConst 0; size; value ]) + | _ -> + $"Expecting an array type but got {t}" + |> addErrorAndReturnNull com ctx.InlinePath r + match i.CompiledName, args with - | "ToSeq", [arg] -> Some arg - | "OfSeq", [arg] -> toArray r t arg |> Some - | "OfList", [arg] -> - Helper.LibCall(com, "list", "toArray", t, args, i.SignatureArgTypes, ?loc=r) |> Some + | "ToSeq", [ arg ] -> Some arg + | "OfSeq", [ arg ] -> toArray r t arg |> Some + | "OfList", [ arg ] -> + Helper.LibCall(com, "list", "toArray", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | "ToList", args -> - Helper.LibCall(com, "list", "ofArray", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | ("Length" | "Count"), [arg] -> Helper.GlobalCall("len", t, [arg], [t], ?loc=r) |> Some - | "Item", [idx; ar] -> getExpr r t ar idx |> Some - | "Get", [ar; idx] -> getExpr r t ar idx |> Some - | "Set", [ar; idx; value] -> setExpr r ar idx value |> Some - | "ZeroCreate", [count] -> createArray count None |> Some - | "Create", [count; value] -> createArray count (Some value) |> Some + Helper.LibCall(com, "list", "ofArray", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | ("Length" + | "Count"), + [ arg ] -> + Helper.GlobalCall("len", t, [ arg ], [ t ], ?loc = r) + |> Some + | "Item", [ idx; ar ] -> getExpr r t ar idx |> Some + | "Get", [ ar; idx ] -> getExpr r t ar idx |> Some + | "Set", [ ar; idx; value ] -> setExpr r ar idx value |> Some + | "ZeroCreate", [ count ] -> createArray count None |> Some + | "Create", [ count; value ] -> createArray count (Some value) |> Some | "Empty", _ -> - let t = match t with Array t -> t | _ -> Any + let t = + match t with + | Array t -> t + | _ -> Any + newArray (makeIntConst 0) t |> Some - | "IsEmpty", [ar] -> - eq (getAttachedMemberWith r (Number(Int32, None)) ar "length") (makeIntConst 0) |> Some + | "IsEmpty", [ ar ] -> + eq (getAttachedMemberWith r (Number(Int32, None)) ar "length") (makeIntConst 0) + |> Some - | "CopyTo", args -> - copyToArray com r t i args + | "CopyTo", args -> copyToArray com r t i args | "SortInPlaceWith", args -> let args, thisArg = List.splitLast args let argTypes = List.take (List.length args) i.SignatureArgTypes let meth = "sort" - Helper.InstanceCall(thisArg, meth, t, args, argTypes, ?loc=r) |> Some + + Helper.InstanceCall(thisArg, meth, t, args, argTypes, ?loc = r) + |> Some | Patterns.DicContains nativeArrayFunctions meth, _ -> let args, thisArg = List.splitLast args let argTypes = List.take (List.length args) i.SignatureArgTypes - let call = Helper.GlobalCall(meth, t, args @ [thisArg], ?loc=r) - Helper.GlobalCall("list", t, [call], ?loc=r) + + let call = + Helper.GlobalCall(meth, t, args @ [ thisArg ], ?loc = r) + + Helper.GlobalCall("list", t, [ call ], ?loc = r) |> Some - | "Distinct" | "DistinctBy" | "Except" | "GroupBy" | "CountBy" as meth, args -> + | "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 + + 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 - Helper.LibCall(com, "array", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + + 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) = 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", "getSlice" ] 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 + | ReplaceName [ "get_Head", "head"; "get_Tail", "tail"; "get_Item", "item"; "get_Length", "length"; "GetSlice", "getSlice" ] 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 - | ("GetHashCode" | "Equals" | "CompareTo"), Some callee, _ -> - Helper.InstanceCall(callee, i.CompiledName, t, args, i.SignatureArgTypes, ?loc=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 + | ("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 + | "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 - | ("Distinct" | "DistinctBy" | "Except" | "GroupBy" | "CountBy" as meth), args -> + | "ToSeq", [ x ] -> toSeq t x |> 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 + + 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 - Helper.LibCall(com, "list", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + + Helper.LibCall(com, "list", meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some let sets (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName with - | ".ctor" -> (genArg com ctx r 0 i.GenericArgs) |> makeSet com ctx r t "OfSeq" args |> Some + | ".ctor" -> + (genArg com ctx r 0 i.GenericArgs) + |> makeSet com ctx r t "OfSeq" args + |> Some | _ -> let isStatic = Option.isNone thisArg - let mangledName = Naming.buildNameWithoutSanitationFrom "FSharpSet" isStatic i.CompiledName "" - let args = injectArg com ctx r "Set" mangledName i.GenericArgs args - Helper.LibCall(com, "set", mangledName, t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + + let mangledName = + Naming.buildNameWithoutSanitationFrom "FSharpSet" isStatic i.CompiledName "" + + let args = + injectArg com ctx r "Set" mangledName i.GenericArgs args + + Helper.LibCall(com, "set", mangledName, t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some let setModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Expr option) (args: Expr list) = let meth = Naming.lowerFirst i.CompiledName let args = injectArg com ctx r "Set" meth i.GenericArgs args - Helper.LibCall(com, "set", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + + Helper.LibCall(com, "set", meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some let maps (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName with - | ".ctor" -> (genArg com ctx r 0 i.GenericArgs) |> makeMap com ctx r t "OfSeq" args |> Some + | ".ctor" -> + (genArg com ctx r 0 i.GenericArgs) + |> makeMap com ctx r t "OfSeq" args + |> Some | _ -> let isStatic = Option.isNone thisArg - let mangledName = Naming.buildNameWithoutSanitationFrom "FSharpMap" isStatic i.CompiledName "" - let args = injectArg com ctx r "Map" mangledName i.GenericArgs args - Helper.LibCall(com, "map", mangledName, t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + + let mangledName = + Naming.buildNameWithoutSanitationFrom "FSharpMap" isStatic i.CompiledName "" + + let args = + injectArg com ctx r "Map" mangledName i.GenericArgs args + + Helper.LibCall(com, "map", mangledName, t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some let mapModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Expr option) (args: Expr list) = let meth = Naming.lowerFirst i.CompiledName let args = injectArg com ctx r "Map" meth i.GenericArgs args - Helper.LibCall(com, "map", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + + Helper.LibCall(com, "map", meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some let results (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Expr option) (args: Expr list) = match i.CompiledName with - | ("Bind" | "Map" | "MapError") as meth -> - Some ("Result_" + meth) + | ("Bind" + | "Map" + | "MapError") as meth -> Some("Result_" + meth) | _ -> None - |> Option.map (fun meth -> - Helper.LibCall(com, "choice", meth, t, args, i.SignatureArgTypes, ?loc=r)) + |> Option.map (fun meth -> Helper.LibCall(com, "choice", meth, t, args, i.SignatureArgTypes, ?loc = r)) let nullables (com: ICompiler) (_: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg with | ".ctor", None -> List.tryHead args // | "get_Value", Some c -> Get(c, OptionValue, t, r) |> Some // Get(OptionValueOptionValue) doesn't do a null check - | "get_Value", Some c -> Helper.LibCall(com, "option", "value", t, [c], ?loc=r) |> Some + | "get_Value", Some c -> + Helper.LibCall(com, "option", "value", t, [ c ], ?loc = r) + |> Some | "get_HasValue", Some c -> Test(c, OptionTest true, r) |> Some | _ -> None // See fable-library/Option.ts for more info on how options behave in Fable runtime let options (com: ICompiler) (_: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg with - | "get_Value", Some c -> Helper.LibCall(com, "option", "value", t, [c], ?loc=r) |> Some + | "get_Value", Some c -> + Helper.LibCall(com, "option", "value", t, [ c ], ?loc = r) + |> Some | "get_IsSome", Some c -> Test(c, OptionTest true, r) |> Some | "get_IsNone", Some c -> Test(c, OptionTest false, r) |> Some | _ -> None let optionModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Expr option) (args: Expr list) = - let toArray r t arg = - Helper.LibCall(com, "option", "toArray", Array t, [arg], ?loc=r) + let toArray r t arg = Helper.LibCall(com, "option", "toArray", Array t, [ arg ], ?loc = r) + match i.CompiledName, args with | "None", _ -> NewOption(None, t, false) |> makeValue r |> Some - | "GetValue", [c] -> - Helper.LibCall(com, "option", "value", t, args, ?loc=r) |> Some - | ("OfObj" | "OfNullable"), _ -> - Helper.LibCall(com, "option", "ofNullable", t, args, ?loc=r) |> Some - | ("ToObj" | "ToNullable"), _ -> - Helper.LibCall(com, "option", "toNullable", t, args, ?loc=r) |> Some - | "IsSome", [c] -> Test(c, OptionTest true, r) |> Some - | "IsNone", [c] -> Test(c, OptionTest false, r) |> Some - | ("Filter" | "Flatten" | "Map" | "Map2" | "Map3" | "Bind" as meth), args -> - Helper.LibCall(com, "option", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some - | "ToArray", [arg] -> - toArray r t arg |> Some - | "ToList", [arg] -> + | "GetValue", [ c ] -> + Helper.LibCall(com, "option", "value", t, args, ?loc = r) + |> Some + | ("OfObj" + | "OfNullable"), + _ -> + Helper.LibCall(com, "option", "ofNullable", t, args, ?loc = r) + |> Some + | ("ToObj" + | "ToNullable"), + _ -> + Helper.LibCall(com, "option", "toNullable", t, args, ?loc = r) + |> Some + | "IsSome", [ c ] -> Test(c, OptionTest true, r) |> Some + | "IsNone", [ c ] -> Test(c, OptionTest false, r) |> Some + | ("Filter" + | "Flatten" + | "Map" + | "Map2" + | "Map3" + | "Bind" as meth), + args -> + Helper.LibCall(com, "option", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | "ToArray", [ arg ] -> toArray r t arg |> Some + | "ToList", [ arg ] -> let args = args |> List.replaceLast (toArray None t) - Helper.LibCall(com, "list", "ofArray", t, args, ?loc=r) |> Some - | "FoldBack", [folder; opt; state] -> - Helper.LibCall(com, "seq", "foldBack", t, [folder; toArray None t opt; state], i.SignatureArgTypes, ?loc=r) |> Some - | ("DefaultValue" | "OrElse"), _ -> - Helper.LibCall(com, "option", "defaultArg", t, List.rev args, ?loc=r) |> Some - | ("DefaultWith" | "OrElseWith"), _ -> - Helper.LibCall(com, "option", "defaultArgWith", t, List.rev args, List.rev i.SignatureArgTypes, ?loc=r) |> Some - | ("Count" | "Contains" | "Exists" | "Fold" | "ForAll" | "Iterate" as meth), _ -> + + Helper.LibCall(com, "list", "ofArray", t, args, ?loc = r) + |> Some + | "FoldBack", [ folder; opt; state ] -> + Helper.LibCall(com, "seq", "foldBack", t, [ folder; toArray None t opt; state ], i.SignatureArgTypes, ?loc = r) + |> Some + | ("DefaultValue" + | "OrElse"), + _ -> + Helper.LibCall(com, "option", "defaultArg", t, List.rev args, ?loc = r) + |> Some + | ("DefaultWith" + | "OrElseWith"), + _ -> + Helper.LibCall(com, "option", "defaultArgWith", t, List.rev args, List.rev i.SignatureArgTypes, ?loc = r) + |> Some + | ("Count" + | "Contains" + | "Exists" + | "Fold" + | "ForAll" + | "Iterate" as meth), + _ -> let meth = Naming.lowerFirst meth let args = args |> List.replaceLast (toArray None t) let args = injectArg com ctx r "Seq" meth i.GenericArgs args - Helper.LibCall(com, "seq", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + + Helper.LibCall(com, "seq", meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some | _ -> None let parseBool (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, args with - | ("Parse" | "TryParse" as method), args -> + | ("Parse" + | "TryParse" as method), + args -> let func = Naming.lowerFirst method - Helper.LibCall(com, "boolean", func, t, args, i.SignatureArgTypes, ?loc=r) |> Some + + Helper.LibCall(com, "boolean", func, t, args, i.SignatureArgTypes, ?loc = r) + |> Some | _ -> None let parseNum (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = @@ -2140,82 +2927,123 @@ let parseNum (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr op match i.DeclaringEntityFullName with | NumberExtKind kind -> kind | x -> failwithf "Unexpected type in parse: %A" x + let isFloatOrDecimal, numberModule, unsigned, bitsize = getParseParams kind + let outValue = - if meth = "TryParse" then [List.last args] else [] + if meth = "TryParse" then + [ List.last args ] + else + [] + let args = - if isFloatOrDecimal then [str] @ outValue - else [str; makeIntConst style; makeBoolConst unsigned; makeIntConst bitsize] @ outValue - Helper.LibCall(com, numberModule, Naming.lowerFirst meth, t, args, ?loc=r) |> Some + if isFloatOrDecimal then + [ str ] @ outValue + else + [ str; makeIntConst style; makeBoolConst unsigned; makeIntConst bitsize ] + @ outValue + + Helper.LibCall(com, numberModule, Naming.lowerFirst meth, t, args, ?loc = r) + |> Some let isFloat = match i.SignatureArgTypes.Head with - | Number((Float32 | Float64),_) -> true + | Number ((Float32 + | Float64), + _) -> true | _ -> false match i.CompiledName, args with - | "IsNaN", [_] when isFloat -> - Helper.GlobalCall("Number", t, args, memb="isNaN", ?loc=r) |> Some - | "IsInfinity", [_] when isFloat -> - Helper.LibCall(com, "double", "isInfinity", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | ("Parse" | "TryParse") as meth, - str::Value(EnumConstant(Value(NumberConstant(style,_,_),_),_),_)::_ -> + | "IsNaN", [ _ ] when isFloat -> + Helper.GlobalCall("Number", t, args, memb = "isNaN", ?loc = r) + |> Some + | "IsInfinity", [ _ ] when isFloat -> + Helper.LibCall(com, "double", "isInfinity", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | ("Parse" + | "TryParse") as meth, + str :: Value (EnumConstant (Value (NumberConstant (style, _, _), _), _), _) :: _ -> let style = int style let hexConst = int System.Globalization.NumberStyles.HexNumber let intConst = int System.Globalization.NumberStyles.Integer + if style <> hexConst && style <> intConst then sprintf "%s.%s(): NumberStyle %d is ignored" i.DeclaringEntityFullName meth style |> addWarning com ctx.InlinePath r + let acceptedArgs = if meth = "Parse" then 2 else 3 + if List.length args > acceptedArgs then // e.g. Double.Parse(string, style, IFormatProvider) etc. sprintf "%s.%s(): provider argument is ignored" i.DeclaringEntityFullName meth |> addWarning com ctx.InlinePath r + parseCall meth str args style - | ("Parse" | "TryParse") as meth, str::_ -> + | ("Parse" + | "TryParse") as meth, + str :: _ -> let acceptedArgs = if meth = "Parse" then 1 else 2 + if List.length args > acceptedArgs then // e.g. Double.Parse(string, IFormatProvider) etc. sprintf "%s.%s(): provider argument is ignored" i.DeclaringEntityFullName meth |> addWarning com ctx.InlinePath r + let style = int System.Globalization.NumberStyles.Any parseCall meth str args style - | "ToString", [ExprTypeAs(String, format)] -> - let format = emitJsExpr r String [format] "'{0:' + $0 + '}'" - Helper.LibCall(com, "string", "format", t, [format; thisArg.Value], [format.Type; thisArg.Value.Type], ?loc=r) |> Some + | "ToString", [ ExprTypeAs (String, format) ] -> + let format = emitJsExpr r String [ format ] "'{0:' + $0 + '}'" + + Helper.LibCall(com, "string", "format", t, [ format; thisArg.Value ], [ format.Type; thisArg.Value.Type ], ?loc = r) + |> Some | "ToString", _ -> - Helper.GlobalCall("String", String, [thisArg.Value], ?loc=r) |> Some - | _ -> - None + Helper.GlobalCall("String", String, [ thisArg.Value ], ?loc = r) + |> Some + | _ -> None let decimals (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, args with - | (".ctor" | "MakeDecimal"), ([low; mid; high; isNegative; scale] as args) -> - Helper.LibCall(com, "decimal", "fromParts", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | ".ctor", [Value(NewArray(([low; mid; high; signExp] as args),_),_)] -> - Helper.LibCall(com, "decimal", "fromInts", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | ".ctor", [arg] -> + | (".ctor" + | "MakeDecimal"), + ([ low; mid; high; isNegative; scale ] as args) -> + Helper.LibCall(com, "decimal", "fromParts", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | ".ctor", [ Value (NewArray (([ low; mid; high; signExp ] as args), _), _) ] -> + Helper.LibCall(com, "decimal", "fromInts", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | ".ctor", [ arg ] -> match arg.Type with - | Array (Number(Int32, None)) -> - Helper.LibCall(com, "decimal", "fromIntArray", t, args, i.SignatureArgTypes, ?loc=r) |> Some + | Array (Number (Int32, None)) -> + Helper.LibCall(com, "decimal", "fromIntArray", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | _ -> makeDecimalFromExpr com r t arg |> Some | "GetBits", _ -> - Helper.LibCall(com, "decimal", "getBits", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | ("Parse" | "TryParse"), _ -> - parseNum com ctx r t i thisArg args - | Operators.lessThan, [left; right] -> compareIf com ctx r left right BinaryLess |> Some - | Operators.lessThanOrEqual, [left; right] -> compareIf com ctx r left right BinaryLessOrEqual |> Some - | Operators.greaterThan, [left; right] -> compareIf com ctx r left right BinaryGreater |> Some - | Operators.greaterThanOrEqual, [left; right] -> compareIf com ctx r left right BinaryGreaterOrEqual |> Some - |(Operators.addition - | Operators.subtraction - | Operators.multiply - | Operators.division - | Operators.divideByInt - | Operators.modulus - | Operators.unaryNegation), _ -> - applyOp com ctx r t i.CompiledName args i.SignatureArgTypes i.GenericArgs |> Some + Helper.LibCall(com, "decimal", "getBits", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | ("Parse" + | "TryParse"), + _ -> parseNum com ctx r t i thisArg args + | Operators.lessThan, [ left; right ] -> compareIf com ctx r left right BinaryLess |> Some + | Operators.lessThanOrEqual, [ left; right ] -> + compareIf com ctx r left right BinaryLessOrEqual + |> Some + | Operators.greaterThan, [ left; right ] -> + compareIf com ctx r left right BinaryGreater + |> Some + | Operators.greaterThanOrEqual, [ left; right ] -> + compareIf com ctx r left right BinaryGreaterOrEqual + |> Some + | (Operators.addition + | Operators.subtraction + | Operators.multiply + | Operators.division + | Operators.divideByInt + | Operators.modulus + | Operators.unaryNegation), + _ -> + applyOp com ctx r t i.CompiledName args i.SignatureArgTypes i.GenericArgs + |> Some | "op_Explicit", _ -> match t with | NumberExt n -> @@ -2226,26 +3054,45 @@ let decimals (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: | Decimal -> toDecimal com ctx r t args |> Some | BigInt -> None | _ -> None - | ("Ceiling" | "Floor" | "Round" | "Truncate" | - "Add" | "Subtract" | "Multiply" | "Divide" | "Remainder" | "Negate" as meth), _ -> + | ("Ceiling" + | "Floor" + | "Round" + | "Truncate" + | "Add" + | "Subtract" + | "Multiply" + | "Divide" + | "Remainder" + | "Negate" as meth), + _ -> let meth = Naming.lowerFirst meth - Helper.LibCall(com, "decimal", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some - | "ToString", [ExprTypeAs(String, format)] -> - let format = emitJsExpr r String [format] "'{0:' + $0 + '}'" - Helper.LibCall(com, "string", "format", t, [format; thisArg.Value], [format.Type; thisArg.Value.Type], ?loc=r) |> Some - | "ToString", _ -> Helper.InstanceCall(thisArg.Value, "toString", String, [], ?loc=r) |> Some - | _,_ -> None + + Helper.LibCall(com, "decimal", meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | "ToString", [ ExprTypeAs (String, format) ] -> + let format = emitJsExpr r String [ format ] "'{0:' + $0 + '}'" + + Helper.LibCall(com, "string", "format", t, [ format; thisArg.Value ], [ format.Type; thisArg.Value.Type ], ?loc = r) + |> Some + | "ToString", _ -> + Helper.InstanceCall(thisArg.Value, "toString", String, [], ?loc = r) + |> Some + | _, _ -> None let bigints (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match thisArg, i.CompiledName with | None, ".ctor" -> match i.SignatureArgTypes with - | [Array _] -> - Helper.LibCall(com, "big_int", "fromByteArray", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | [Builtin (BclInt64|BclUInt64)] -> - Helper.LibCall(com, "big_int", "fromInt64", t, args, i.SignatureArgTypes, ?loc=r) |> Some + | [ Array _ ] -> + Helper.LibCall(com, "big_int", "fromByteArray", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | [ Builtin (BclInt64 + | BclUInt64) ] -> + Helper.LibCall(com, "big_int", "fromInt64", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | _ -> - Helper.LibCall(com, "big_int", "fromInt32", t, args, i.SignatureArgTypes, ?loc=r) |> Some + Helper.LibCall(com, "big_int", "fromInt32", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | None, "op_Explicit" -> match t with | NumberExt n -> @@ -2257,19 +3104,22 @@ let bigints (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: | BigInt -> None | _ -> None | None, "DivRem" -> - Helper.LibCall(com, "big_int", "divRem", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | None, meth when meth.StartsWith("get_") -> - Helper.LibValue(com, "big_int", meth, t) |> Some + Helper.LibCall(com, "big_int", "divRem", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | None, meth when meth.StartsWith("get_") -> Helper.LibValue(com, "big_int", meth, t) |> Some | callee, meth -> let args = match callee, meth with | None, _ -> args - | Some c, _ -> c::args - Helper.LibCall(com, "big_int", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + | Some c, _ -> c :: args + + Helper.LibCall(com, "big_int", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some // Compile static strings to their constant values // reference: https://msdn.microsoft.com/en-us/visualfsharpdocs/conceptual/languageprimitives.errorstrings-module-%5bfsharp%5d -let errorStrings = function +let errorStrings = + function | "InputArrayEmptyString" -> str "The input array was empty" |> Some | "InputSequenceEmptyString" -> str "The input sequence was empty" |> Some | "InputMustBeNonNegativeString" -> str "The input must be non-negative" |> Some @@ -2277,135 +3127,213 @@ let errorStrings = function let languagePrimitives (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, args with - | Naming.EndsWith "Dynamic" operation, arg::_ -> - let operation = if operation = Operators.divideByInt then operation else "op_" + operation - if operation = "op_Explicit" then Some arg // TODO - else applyOp com ctx r t operation args i.SignatureArgTypes i.GenericArgs |> Some - | "DivideByInt", _ -> applyOp com ctx r t i.CompiledName args i.SignatureArgTypes i.GenericArgs |> Some + | Naming.EndsWith "Dynamic" operation, arg :: _ -> + let operation = + if operation = Operators.divideByInt then + operation + else + "op_" + operation + + if operation = "op_Explicit" then + Some arg // TODO + else + applyOp com ctx r t operation args i.SignatureArgTypes i.GenericArgs + |> Some + | "DivideByInt", _ -> + applyOp com ctx r t i.CompiledName args i.SignatureArgTypes i.GenericArgs + |> Some | "GenericZero", _ -> getZero com ctx t |> Some | "GenericOne", _ -> getOne com ctx t |> Some | ("SByteWithMeasure" - | "Int16WithMeasure" - | "Int32WithMeasure" - | "Int64WithMeasure" - | "Float32WithMeasure" - | "FloatWithMeasure" - | "DecimalWithMeasure"), [arg] -> arg |> Some - | "EnumOfValue", [arg] -> + | "Int16WithMeasure" + | "Int32WithMeasure" + | "Int64WithMeasure" + | "Float32WithMeasure" + | "FloatWithMeasure" + | "DecimalWithMeasure"), + [ arg ] -> arg |> Some + | "EnumOfValue", [ arg ] -> match t with | Enum e -> EnumConstant(arg, e) |> makeValue r |> Some - | _ -> "EnumOfValue only works if the enum type is known at compile time, try inlining the function" - |> addErrorAndReturnNull com ctx.InlinePath r |> Some - | "EnumToValue", [arg] -> + | _ -> + "EnumOfValue only works if the enum type is known at compile time, try inlining the function" + |> addErrorAndReturnNull com ctx.InlinePath r + |> Some + | "EnumToValue", [ arg ] -> match arg with | IdentExpr _ -> arg |> Some - | Value(EnumConstant(v,_),_) -> v |> Some + | Value (EnumConstant (v, _), _) -> v |> Some | _ -> None - | ("GenericHash" | "GenericHashIntrinsic"), [arg] -> - structuralHash com r arg |> Some - | ("FastHashTuple2" | "FastHashTuple3" | "FastHashTuple4" | "FastHashTuple5" - | "GenericHashWithComparer" | "GenericHashWithComparerIntrinsic"), [comp; arg] -> - Helper.InstanceCall(comp, "GetHashCode", t, [arg], i.SignatureArgTypes, ?loc=r) |> Some - | ("GenericComparison" | "GenericComparisonIntrinsic"), [left; right] -> - compare com ctx r left right |> Some - | ("FastCompareTuple2" | "FastCompareTuple3" | "FastCompareTuple4" | "FastCompareTuple5" - | "GenericComparisonWithComparer" | "GenericComparisonWithComparerIntrinsic"), [comp; left; right] -> - Helper.InstanceCall(comp, "Compare", t, [left; right], i.SignatureArgTypes, ?loc=r) |> Some - | ("GenericLessThan" | "GenericLessThanIntrinsic"), [left; right] -> - compareIf com ctx r left right BinaryLess |> Some - | ("GenericLessOrEqual" | "GenericLessOrEqualIntrinsic"), [left; right] -> - compareIf com ctx r left right BinaryLessOrEqual |> Some - | ("GenericGreaterThan" | "GenericGreaterThanIntrinsic"), [left; right] -> - compareIf com ctx r left right BinaryGreater |> Some - | ("GenericGreaterOrEqual" | "GenericGreaterOrEqualIntrinsic"), [left; right] -> - compareIf com ctx r left right BinaryGreaterOrEqual |> Some - | ("GenericEquality" | "GenericEqualityIntrinsic"), [left; right] -> - equals com ctx r true left right |> Some - | ("GenericEqualityER" | "GenericEqualityERIntrinsic"), [left; right] -> + | ("GenericHash" + | "GenericHashIntrinsic"), + [ arg ] -> structuralHash com r arg |> Some + | ("FastHashTuple2" + | "FastHashTuple3" + | "FastHashTuple4" + | "FastHashTuple5" + | "GenericHashWithComparer" + | "GenericHashWithComparerIntrinsic"), + [ comp; arg ] -> + Helper.InstanceCall(comp, "GetHashCode", t, [ arg ], i.SignatureArgTypes, ?loc = r) + |> Some + | ("GenericComparison" + | "GenericComparisonIntrinsic"), + [ left; right ] -> compare com ctx r left right |> Some + | ("FastCompareTuple2" + | "FastCompareTuple3" + | "FastCompareTuple4" + | "FastCompareTuple5" + | "GenericComparisonWithComparer" + | "GenericComparisonWithComparerIntrinsic"), + [ comp; left; right ] -> + Helper.InstanceCall(comp, "Compare", t, [ left; right ], i.SignatureArgTypes, ?loc = r) + |> Some + | ("GenericLessThan" + | "GenericLessThanIntrinsic"), + [ left; right ] -> compareIf com ctx r left right BinaryLess |> Some + | ("GenericLessOrEqual" + | "GenericLessOrEqualIntrinsic"), + [ left; right ] -> + compareIf com ctx r left right BinaryLessOrEqual + |> Some + | ("GenericGreaterThan" + | "GenericGreaterThanIntrinsic"), + [ left; right ] -> + compareIf com ctx r left right BinaryGreater + |> Some + | ("GenericGreaterOrEqual" + | "GenericGreaterOrEqualIntrinsic"), + [ left; right ] -> + compareIf com ctx r left right BinaryGreaterOrEqual + |> Some + | ("GenericEquality" + | "GenericEqualityIntrinsic"), + [ left; right ] -> equals com ctx r true left right |> Some + | ("GenericEqualityER" + | "GenericEqualityERIntrinsic"), + [ left; right ] -> // TODO: In ER mode, equality on two NaNs returns "true". equals com ctx r true left right |> Some - | ("FastEqualsTuple2" | "FastEqualsTuple3" | "FastEqualsTuple4" | "FastEqualsTuple5" - | "GenericEqualityWithComparer" | "GenericEqualityWithComparerIntrinsic"), [comp; left; right] -> - Helper.InstanceCall(comp, "Equals", t, [left; right], i.SignatureArgTypes, ?loc=r) |> Some - | ("PhysicalEquality" | "PhysicalEqualityIntrinsic"), [left; right] -> - makeEqOp r left right BinaryEqualStrict |> Some - | ("PhysicalHash" | "PhysicalHashIntrinsic"), [arg] -> - Helper.LibCall(com, "util", "physicalHash", Number(Int32, None), [arg], ?loc=r) |> Some + | ("FastEqualsTuple2" + | "FastEqualsTuple3" + | "FastEqualsTuple4" + | "FastEqualsTuple5" + | "GenericEqualityWithComparer" + | "GenericEqualityWithComparerIntrinsic"), + [ comp; left; right ] -> + Helper.InstanceCall(comp, "Equals", t, [ left; right ], i.SignatureArgTypes, ?loc = r) + |> Some + | ("PhysicalEquality" + | "PhysicalEqualityIntrinsic"), + [ left; right ] -> makeEqOp r left right BinaryEqualStrict |> Some + | ("PhysicalHash" + | "PhysicalHashIntrinsic"), + [ arg ] -> + Helper.LibCall(com, "util", "physicalHash", Number(Int32, None), [ arg ], ?loc = r) + |> Some | ("GenericEqualityComparer" - | "GenericEqualityERComparer" - | "FastGenericComparer" - | "FastGenericComparerFromTable" - | "FastGenericEqualityComparer" - | "FastGenericEqualityComparerFromTable" - ), _ -> fsharpModule com ctx r t i thisArg args - | ("ParseInt32"|"ParseUInt32"), [arg] -> toInt com ctx r t [arg] |> Some - | "ParseInt64", [arg] -> toLong com ctx r false t [arg] |> Some - | "ParseUInt64", [arg] -> toLong com ctx r true t [arg] |> Some + | "GenericEqualityERComparer" + | "FastGenericComparer" + | "FastGenericComparerFromTable" + | "FastGenericEqualityComparer" + | "FastGenericEqualityComparerFromTable"), + _ -> fsharpModule com ctx r t i thisArg args + | ("ParseInt32" + | "ParseUInt32"), + [ arg ] -> toInt com ctx r t [ arg ] |> Some + | "ParseInt64", [ arg ] -> toLong com ctx r false t [ arg ] |> Some + | "ParseUInt64", [ arg ] -> toLong com ctx r true t [ arg ] |> Some | _ -> None let intrinsicFunctions (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg, args with // Erased operators - | "CheckThis", _, [arg] - | "UnboxFast", _, [arg] - | "UnboxGeneric", _, [arg] -> Some arg + | "CheckThis", _, [ arg ] + | "UnboxFast", _, [ arg ] + | "UnboxGeneric", _, [ arg ] -> Some arg | "MakeDecimal", _, _ -> decimals com ctx r t i thisArg args - | "GetString", _, [ar; idx] - | "GetArray", _, [ar; idx] -> getExpr r t ar idx |> Some - | "SetArray", _, [ar; idx; value] -> setExpr r ar idx value |> Some - | ("GetArraySlice" | "GetStringSlice"), None, [ar; lower; upper] -> + | "GetString", _, [ ar; idx ] + | "GetArray", _, [ ar; idx ] -> getExpr r t ar idx |> Some + | "SetArray", _, [ ar; idx; value ] -> setExpr r ar idx value |> Some + | ("GetArraySlice" + | "GetStringSlice"), + None, + [ ar; lower; upper ] -> let upper = match upper with - | Value(NewOption(None,_,_),_) -> getExpr None (Number(Int32, None)) ar (makeStrConst "length") + | Value (NewOption (None, _, _), _) -> getExpr None (Number(Int32, None)) ar (makeStrConst "length") | _ -> add upper (makeIntConst 1) - Helper.InstanceCall(ar, "slice", t, [lower; upper], ?loc=r) |> Some + + Helper.InstanceCall(ar, "slice", t, [ lower; upper ], ?loc = r) + |> Some | "SetArraySlice", None, args -> - Helper.LibCall(com, "array", "setSlice", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | ("TypeTestGeneric" | "TypeTestFast"), None, [expr] -> - Test(expr, TypeTest((genArg com ctx r 0 i.GenericArgs)), r) |> Some + Helper.LibCall(com, "array", "setSlice", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | ("TypeTestGeneric" + | "TypeTestFast"), + None, + [ expr ] -> + Test(expr, TypeTest((genArg com ctx r 0 i.GenericArgs)), r) + |> Some | "CreateInstance", None, _ -> match genArg com ctx r 0 i.GenericArgs with - | DeclaredType(ent, _) -> + | DeclaredType (ent, _) -> let ent = com.GetEntity(ent) - Helper.PyConstructorCall(pyConstructor com ent, t, [], ?loc=r) |> Some - | t -> sprintf "Cannot create instance of type unresolved at compile time: %A" t - |> addErrorAndReturnNull com ctx.InlinePath r |> Some + + Helper.PyConstructorCall(pyConstructor com ent, t, [], ?loc = r) + |> Some + | t -> + sprintf "Cannot create instance of type unresolved at compile time: %A" t + |> addErrorAndReturnNull com ctx.InlinePath r + |> Some // reference: https://msdn.microsoft.com/visualfsharpdocs/conceptual/operatorintrinsics.powdouble-function-%5bfsharp%5d // Type: PowDouble : float -> int -> float // Usage: PowDouble x n | "PowDouble", None, _ -> - Helper.GlobalCall("math", t, args, i.SignatureArgTypes, memb="pow", ?loc=r) |> Some + Helper.GlobalCall("math", t, args, i.SignatureArgTypes, memb = "pow", ?loc = r) + |> Some | "PowDecimal", None, _ -> - Helper.LibCall(com, "decimal", "pow", t, args, i.SignatureArgTypes, ?loc=r) |> Some + Helper.LibCall(com, "decimal", "pow", t, args, i.SignatureArgTypes, ?loc = r) + |> Some // reference: https://msdn.microsoft.com/visualfsharpdocs/conceptual/operatorintrinsics.rangechar-function-%5bfsharp%5d // Type: RangeChar : char -> char -> seq // Usage: RangeChar start stop | "RangeChar", None, _ -> - Helper.LibCall(com, "range", "rangeChar", t, args, i.SignatureArgTypes, ?loc=r) |> Some + Helper.LibCall(com, "range", "rangeChar", t, args, i.SignatureArgTypes, ?loc = r) + |> Some // reference: https://msdn.microsoft.com/visualfsharpdocs/conceptual/operatorintrinsics.rangedouble-function-%5bfsharp%5d // Type: RangeDouble: float -> float -> float -> seq // Usage: RangeDouble start step stop - | ("RangeSByte" | "RangeByte" - | "RangeInt16" | "RangeUInt16" - | "RangeInt32" | "RangeUInt32" - | "RangeSingle" | "RangeDouble"), None, args -> - Helper.LibCall(com, "range", "rangeDouble", t, args, i.SignatureArgTypes, ?loc=r) |> Some + | ("RangeSByte" + | "RangeByte" + | "RangeInt16" + | "RangeUInt16" + | "RangeInt32" + | "RangeUInt32" + | "RangeSingle" + | "RangeDouble"), + None, + args -> + Helper.LibCall(com, "range", "rangeDouble", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | "RangeInt64", None, args -> - Helper.LibCall(com, "range", "rangeInt64", t, args, i.SignatureArgTypes, ?loc=r) |> Some + Helper.LibCall(com, "range", "rangeInt64", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | "RangeUInt64", None, args -> - Helper.LibCall(com, "range", "rangeUInt64", t, args, i.SignatureArgTypes, ?loc=r) |> Some + Helper.LibCall(com, "range", "rangeUInt64", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | _ -> None let runtimeHelpers (com: ICompiler) (ctx: Context) r t (i: CallInfo) thisArg args = match i.CompiledName, args with - | "GetHashCode", [arg] -> identityHash com r arg |> Some + | "GetHashCode", [ arg ] -> identityHash com r arg |> Some | _ -> None // ExceptionDispatchInfo is used to raise exceptions through different threads in async workflows // We don't need to do anything in JS, see #2396 let exceptionDispatchInfo (com: ICompiler) (ctx: Context) r t (i: CallInfo) thisArg args = match i.CompiledName, thisArg, args with - | "Capture", _, [arg] -> Some arg + | "Capture", _, [ arg ] -> Some arg | "Throw", Some arg, _ -> makeThrow r t arg |> Some | _ -> None @@ -2414,7 +3342,8 @@ let funcs (com: ICompiler) (ctx: Context) r t (i: CallInfo) thisArg args = // Just use Emit to change the type of the arg, Fable will automatically uncurry the function | "Adapt", _ -> emitJsExpr r t args "$0" |> Some | "Invoke", Some callee -> - Helper.Application(callee, t, args, i.SignatureArgTypes, ?loc=r) |> Some + Helper.Application(callee, t, args, i.SignatureArgTypes, ?loc = r) + |> Some | _ -> None let keyValuePairs (com: ICompiler) (ctx: Context) r t (i: CallInfo) thisArg args = @@ -2428,69 +3357,94 @@ let dictionaries (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Exp match i.CompiledName, thisArg with | ".ctor", _ -> match i.SignatureArgTypes, args with - | ([]|[Number _]), _ -> - makeDictionary com ctx r t (makeArray Any []) |> Some - | [IDictionary], [arg] -> - makeDictionary com ctx r t arg |> Some - | [IDictionary; IEqualityComparer], [arg; eqComp] -> + | ([] + | [ Number _ ]), + _ -> + makeDictionary com ctx r t (makeArray Any []) + |> Some + | [ IDictionary ], [ arg ] -> makeDictionary com ctx r t arg |> Some + | [ IDictionary; IEqualityComparer ], [ arg; eqComp ] -> makeComparerFromEqualityComparer eqComp - |> makeDictionaryWithComparer com r t arg |> Some - | [IEqualityComparer], [eqComp] - | [Number _; IEqualityComparer], [_; eqComp] -> + |> makeDictionaryWithComparer com r t arg + |> Some + | [ IEqualityComparer ], [ eqComp ] + | [ Number _; IEqualityComparer ], [ _; eqComp ] -> makeComparerFromEqualityComparer eqComp - |> makeDictionaryWithComparer com r t (makeArray Any []) |> Some + |> makeDictionaryWithComparer com r t (makeArray Any []) + |> Some | _ -> None | "get_IsReadOnly", _ -> makeBoolConst false |> Some - | "get_Count", _ -> Helper.GlobalCall("len", t, [thisArg.Value], [t], ?loc=r) |> Some + | "get_Count", _ -> + Helper.GlobalCall("len", t, [ thisArg.Value ], [ t ], ?loc = r) + |> Some | "GetEnumerator", Some callee -> getEnumerator com r t callee |> Some | "ContainsValue", _ -> match thisArg, args with - | Some c, [arg] -> Helper.LibCall(com, "map_util", "contains_value", t, [arg; c], ?loc=r) |> Some + | Some c, [ arg ] -> + Helper.LibCall(com, "map_util", "contains_value", t, [ arg; c ], ?loc = r) + |> Some | _ -> None | "TryGetValue", _ -> - Helper.LibCall(com, "map_util", "tryGetValue", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + Helper.LibCall(com, "map_util", "tryGetValue", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some | "Add", _ -> - Helper.LibCall(com, "map_util", "addToDict", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + Helper.LibCall(com, "map_util", "addToDict", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some | "get_Item", _ -> - Helper.LibCall(com, "map_util", "getItemFromDict", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some - | ReplaceName ["set_Item", "set" - "get_Keys", "keys" - "get_Values", "values" - "ContainsKey", "has" - "Clear", "clear" - "Remove", "delete" ] methName, Some c -> - Helper.InstanceCall(c, methName, t, args, i.SignatureArgTypes, ?loc=r) |> Some + Helper.LibCall(com, "map_util", "getItemFromDict", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some + | ReplaceName [ "set_Item", "set" + "get_Keys", "keys" + "get_Values", "values" + "ContainsKey", "has" + "Clear", "clear" + "Remove", "delete" ] + methName, + Some c -> + Helper.InstanceCall(c, methName, t, args, i.SignatureArgTypes, ?loc = r) + |> Some | _ -> None let hashSets (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg, args with | ".ctor", _, _ -> match i.SignatureArgTypes, args with - | [], _ -> - makeHashSet com ctx r t (makeArray Any []) |> Some - | [IEnumerable], [arg] -> - makeHashSet com ctx r t arg |> Some - | [IEnumerable; IEqualityComparer], [arg; eqComp] -> + | [], _ -> makeHashSet com ctx r t (makeArray Any []) |> Some + | [ IEnumerable ], [ arg ] -> makeHashSet com ctx r t arg |> Some + | [ IEnumerable; IEqualityComparer ], [ arg; eqComp ] -> makeComparerFromEqualityComparer eqComp - |> makeHashSetWithComparer com r t arg |> Some - | [IEqualityComparer], [eqComp] -> + |> makeHashSetWithComparer com r t arg + |> Some + | [ IEqualityComparer ], [ eqComp ] -> makeComparerFromEqualityComparer eqComp - |> makeHashSetWithComparer com r t (makeArray Any []) |> Some + |> makeHashSetWithComparer com r t (makeArray Any []) + |> Some | _ -> None - | "get_Count", _, _ -> getAttachedMemberWith r t thisArg.Value "size" |> Some + | "get_Count", _, _ -> + getAttachedMemberWith r t thisArg.Value "size" + |> Some | "get_IsReadOnly", _, _ -> BoolConstant false |> makeValue r |> Some - | ReplaceName ["Clear", "clear" - "Contains", "has" - "Remove", "delete" ] methName, Some c, args -> - Helper.InstanceCall(c, methName, t, args, i.SignatureArgTypes, ?loc=r) |> Some + | ReplaceName [ "Clear", "clear"; "Contains", "has"; "Remove", "delete" ] methName, Some c, args -> + Helper.InstanceCall(c, methName, t, args, i.SignatureArgTypes, ?loc = r) + |> Some | "GetEnumerator", Some c, _ -> getEnumerator com r t c |> Some - | "Add", Some c, [arg] -> - Helper.LibCall(com, "map_util", "addToSet", t, [arg; c], ?loc=r) |> Some - | ("IsProperSubsetOf" | "IsProperSupersetOf" | "UnionWith" | "IntersectWith" | - "ExceptWith" | "IsSubsetOf" | "IsSupersetOf" as meth), Some c, args -> + | "Add", Some c, [ arg ] -> + Helper.LibCall(com, "map_util", "addToSet", t, [ arg; c ], ?loc = r) + |> Some + | ("IsProperSubsetOf" + | "IsProperSupersetOf" + | "UnionWith" + | "IntersectWith" + | "ExceptWith" + | "IsSubsetOf" + | "IsSupersetOf" as meth), + Some c, + args -> let meth = Naming.lowerFirst meth let args = injectArg com ctx r "Set" meth i.GenericArgs args - Helper.LibCall(com, "Set", meth, t, c::args, ?loc=r) |> Some + + Helper.LibCall(com, "Set", meth, t, c :: args, ?loc = r) + |> Some // | "CopyTo" // TODO!!! // | "SetEquals" // | "Overlaps" @@ -2499,7 +3453,9 @@ let hashSets (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr op let exceptions (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg with - | ".ctor", _ -> Helper.PyConstructorCall(makeIdentExpr "Exception", t, args, ?loc=r) |> Some + | ".ctor", _ -> + Helper.PyConstructorCall(makeIdentExpr "Exception", t, args, ?loc = r) + |> Some | "get_Message", Some e -> getAttachedMemberWith r t e "message" |> Some | "get_StackTrace", Some e -> getAttachedMemberWith r t e "stack" |> Some | _ -> None @@ -2507,70 +3463,79 @@ let exceptions (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr let objects (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg, args with | ".ctor", _, _ -> typedObjExpr t [] |> Some - | "ToString", Some arg, _ -> toString com ctx r [arg] |> Some - | "ReferenceEquals", _, [left; right] -> makeEqOp r left right BinaryEqualStrict |> Some - | "Equals", Some arg1, [arg2] - | "Equals", None, [arg1; arg2] -> equals com ctx r true arg1 arg2 |> Some + | "ToString", Some arg, _ -> toString com ctx r [ arg ] |> Some + | "ReferenceEquals", _, [ left; right ] -> makeEqOp r left right BinaryEqualStrict |> Some + | "Equals", Some arg1, [ arg2 ] + | "Equals", None, [ arg1; arg2 ] -> equals com ctx r true arg1 arg2 |> Some | "GetHashCode", Some arg, _ -> identityHash com r arg |> Some | "GetType", Some arg, _ -> if arg.Type = Any then "Types can only be resolved at compile time. At runtime this will be same as `typeof`" |> addWarning com ctx.InlinePath r + makeTypeInfo r arg.Type |> Some | _ -> None let valueTypes (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg, args with | ".ctor", _, _ -> typedObjExpr t [] |> Some - | "ToString", Some arg, _ -> toString com ctx r [arg] |> Some - | "Equals", Some arg1, [arg2] - | "Equals", None, [arg1; arg2] -> equals com ctx r true arg1 arg2 |> Some + | "ToString", Some arg, _ -> toString com ctx r [ arg ] |> Some + | "Equals", Some arg1, [ arg2 ] + | "Equals", None, [ arg1; arg2 ] -> equals com ctx r true arg1 arg2 |> Some | "GetHashCode", Some arg, _ -> structuralHash com r arg |> Some - | "CompareTo", Some arg1, [arg2] -> compare com ctx r arg1 arg2 |> Some + | "CompareTo", Some arg1, [ arg2 ] -> compare com ctx r arg1 arg2 |> Some | _ -> None let unchecked (com: ICompiler) (ctx: Context) r t (i: CallInfo) (_: Expr option) (args: Expr list) = match i.CompiledName, args with - | "DefaultOf", _ -> (genArg com ctx r 0 i.GenericArgs) |> defaultof com ctx |> Some - | "Hash", [arg] -> structuralHash com r arg |> Some - | "Equals", [arg1; arg2] -> equals com ctx r true arg1 arg2 |> Some - | "Compare", [arg1; arg2] -> compare com ctx r arg1 arg2 |> Some + | "DefaultOf", _ -> + (genArg com ctx r 0 i.GenericArgs) + |> defaultof com ctx + |> Some + | "Hash", [ arg ] -> structuralHash com r arg |> Some + | "Equals", [ arg1; arg2 ] -> equals com ctx r true arg1 arg2 |> Some + | "Compare", [ arg1; arg2 ] -> compare com ctx r arg1 arg2 |> Some | _ -> None let enums (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match thisArg, i.CompiledName, args with - | Some this, "HasFlag", [arg] -> + | Some this, "HasFlag", [ arg ] -> // x.HasFlags(y) => (int x) &&& (int y) <> 0 makeBinOp r (Number(Int32, None)) this arg BinaryAndBitwise |> fun bitwise -> makeEqOp r bitwise (makeIntConst 0) BinaryUnequal |> Some - | None, Patterns.DicContains (dict ["Parse", "parseEnum" - "TryParse", "tryParseEnum" - "IsDefined", "isEnumDefined" - "GetName", "getEnumName" - "GetNames", "getEnumNames" - "GetValues", "getEnumValues" - "GetUnderlyingType", "getEnumUnderlyingType"]) meth, args -> + | None, + Patterns.DicContains (dict [ "Parse", "parseEnum" + "TryParse", "tryParseEnum" + "IsDefined", "isEnumDefined" + "GetName", "getEnumName" + "GetNames", "getEnumNames" + "GetValues", "getEnumValues" + "GetUnderlyingType", "getEnumUnderlyingType" ]) + meth, + args -> let args = match meth, args with // TODO: Parse at compile time if we know the type - | "parseEnum", [value] -> [Value(TypeInfo(t), None); value] - | "tryParseEnum", [value; refValue] -> [Value(TypeInfo(genArg com ctx r 0 i.GenericArgs), None); value; refValue] + | "parseEnum", [ value ] -> [ Value(TypeInfo(t), None); value ] + | "tryParseEnum", [ value; refValue ] -> [ Value(TypeInfo(genArg com ctx r 0 i.GenericArgs), None); value; refValue ] | _ -> args - Helper.LibCall(com, "Reflection", meth, t, args, ?loc=r) |> Some + + Helper.LibCall(com, "Reflection", meth, t, args, ?loc = r) + |> Some | _ -> None let log (com: ICompiler) r t (i: CallInfo) (_: Expr option) (args: Expr list) = let args = match args with | [] -> [] - | [v] -> [v] - | (StringConst _)::_ -> [Helper.LibCall(com, "String", "format", t, args, i.SignatureArgTypes)] - | _ -> [args.Head] + | [ v ] -> [ v ] + | (StringConst _) :: _ -> [ Helper.LibCall(com, "String", "format", t, args, i.SignatureArgTypes) ] + | _ -> [ args.Head ] match com.Options.Language with - | Python -> Helper.GlobalCall("print", t, args, ?loc=r) - | _ -> Helper.GlobalCall("console", t, args, memb="log", ?loc=r) + | Python -> Helper.GlobalCall("print", t, args, ?loc = r) + | _ -> Helper.GlobalCall("console", t, args, memb = "log", ?loc = r) let bitConvert (com: ICompiler) (ctx: Context) r t (i: CallInfo) (_: Expr option) (args: Expr list) = match i.CompiledName with @@ -2578,40 +3543,54 @@ let bitConvert (com: ICompiler) (ctx: Context) r t (i: CallInfo) (_: Expr option let memberName = match args.Head.Type with | Boolean -> "getBytesBoolean" - | Char | String -> "getBytesChar" - | Number(Int16,_) -> "getBytesInt16" - | Number(Int32,_) -> "getBytesInt32" - | Number(UInt16,_) -> "getBytesUInt16" - | Number(UInt32,_) -> "getBytesUInt32" - | Number(Float32,_) -> "getBytesSingle" - | Number(Float64,_) -> "getBytesDouble" + | Char + | String -> "getBytesChar" + | Number (Int16, _) -> "getBytesInt16" + | Number (Int32, _) -> "getBytesInt32" + | Number (UInt16, _) -> "getBytesUInt16" + | Number (UInt32, _) -> "getBytesUInt32" + | Number (Float32, _) -> "getBytesSingle" + | Number (Float64, _) -> "getBytesDouble" | Builtin BclInt64 -> "getBytesInt64" | Builtin BclUInt64 -> "getBytesUInt64" | x -> failwithf "Unsupported type in BitConverter.GetBytes(): %A" x - let expr = Helper.LibCall(com, "BitConverter", memberName, Boolean, args, i.SignatureArgTypes, ?loc=r) - if com.Options.TypedArrays then expr |> Some - else toArray r t expr |> Some // convert to dynamic array + + let expr = + Helper.LibCall(com, "BitConverter", memberName, Boolean, args, i.SignatureArgTypes, ?loc = r) + + if com.Options.TypedArrays then + expr |> Some + else + toArray r t expr |> Some // convert to dynamic array | _ -> let memberName = Naming.lowerFirst i.CompiledName - Helper.LibCall(com, "BitConverter", memberName, Boolean, args, i.SignatureArgTypes, ?loc=r) |> Some + + Helper.LibCall(com, "BitConverter", memberName, Boolean, args, i.SignatureArgTypes, ?loc = r) + |> Some let convert (com: ICompiler) (ctx: Context) r t (i: CallInfo) (_: Expr option) (args: Expr list) = match i.CompiledName with - | "ToSByte" | "ToByte" - | "ToInt16" | "ToUInt16" - | "ToInt32" | "ToUInt32" - -> round com args |> toInt com ctx r t |> Some - | "ToInt64" -> round com args |> toLong com ctx r false t |> Some + | "ToSByte" + | "ToByte" + | "ToInt16" + | "ToUInt16" + | "ToInt32" + | "ToUInt32" -> round com args |> toInt com ctx r t |> Some + | "ToInt64" -> round com args |> toLong com ctx r false t |> Some | "ToUInt64" -> round com args |> toLong com ctx r true t |> Some - | "ToSingle" | "ToDouble" -> toFloat com ctx r t args |> Some + | "ToSingle" + | "ToDouble" -> toFloat com ctx r t args |> Some | "ToDecimal" -> toDecimal com ctx r t args |> Some | "ToChar" -> toChar args.Head |> Some | "ToString" -> toString com ctx r args |> Some - | "ToBase64String" | "FromBase64String" -> - if not(List.isSingle args) then + | "ToBase64String" + | "FromBase64String" -> + if not (List.isSingle args) then sprintf "Convert.%s only accepts one single argument" (Naming.upperFirst i.CompiledName) |> addWarning com ctx.InlinePath r - Helper.LibCall(com, "String", (Naming.lowerFirst i.CompiledName), t, args, i.SignatureArgTypes, ?loc=r) |> Some + + Helper.LibCall(com, "String", (Naming.lowerFirst i.CompiledName), t, args, i.SignatureArgTypes, ?loc = r) + |> Some | _ -> None let console (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = @@ -2632,122 +3611,203 @@ let debug (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr optio | "Break" -> makeDebugger r |> Some | "Assert" -> let unit = Value(Null Unit, None) + match args with - | [] | [Value(BoolConstant true,_)] -> Some unit - | [Value(BoolConstant false,_)] -> makeDebugger r |> Some - | arg::_ -> + | [] + | [ Value (BoolConstant true, _) ] -> Some unit + | [ Value (BoolConstant false, _) ] -> makeDebugger r |> Some + | arg :: _ -> // emit i "if (!$0) { debugger; }" i.args |> Some let cond = Operation(Unary(UnaryNot, arg), Boolean, r) IfThenElse(cond, makeDebugger r, unit, r) |> Some | _ -> None let dates (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = - let getTime (e: Expr) = - Helper.InstanceCall(e, "getTime", t, []) + let getTime (e: Expr) = Helper.InstanceCall(e, "getTime", t, []) + let moduleName = - if i.DeclaringEntityFullName = Types.datetime - then "Date" else "DateOffset" + if i.DeclaringEntityFullName = Types.datetime then + "Date" + else + "DateOffset" + match i.CompiledName with | ".ctor" -> match args with - | [] -> Helper.LibCall(com, moduleName, "minValue", t, [], [], ?loc=r) |> Some - | ExprType(Builtin BclInt64)::_ -> - Helper.LibCall(com, moduleName, "fromTicks", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | ExprType(DeclaredType(e,[]))::_ when e.FullName = Types.datetime -> - Helper.LibCall(com, "DateOffset", "fromDate", t, args, i.SignatureArgTypes, ?loc=r) |> Some + | [] -> + Helper.LibCall(com, moduleName, "minValue", t, [], [], ?loc = r) + |> Some + | ExprType (Builtin BclInt64) :: _ -> + Helper.LibCall(com, moduleName, "fromTicks", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | ExprType (DeclaredType (e, [])) :: _ when e.FullName = Types.datetime -> + Helper.LibCall(com, "DateOffset", "fromDate", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | _ -> let last = List.last args + match args.Length, last.Type with | 7, Enum ent when ent.FullName = "System.DateTimeKind" -> - let args = (List.take 6 args) @ [makeIntConst 0; last] - let argTypes = (List.take 6 i.SignatureArgTypes) @ [Number(Int32, None); last.Type] - Helper.LibCall(com, "Date", "create", t, args, argTypes, ?loc=r) |> Some + let args = (List.take 6 args) @ [ makeIntConst 0; last ] + + let argTypes = + (List.take 6 i.SignatureArgTypes) + @ [ Number(Int32, None); last.Type ] + + Helper.LibCall(com, "Date", "create", t, args, argTypes, ?loc = r) + |> Some | _ -> - Helper.LibCall(com, moduleName, "create", t, args, i.SignatureArgTypes, ?loc=r) |> Some + Helper.LibCall(com, moduleName, "create", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | "ToString" -> - Helper.LibCall(com, "Date", "toString", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some - | "get_Kind" | "get_Offset" -> - Naming.removeGetSetPrefix i.CompiledName |> Naming.lowerFirst |> getAttachedMemberWith r t thisArg.Value |> Some + Helper.LibCall(com, "Date", "toString", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some + | "get_Kind" + | "get_Offset" -> + Naming.removeGetSetPrefix i.CompiledName + |> Naming.lowerFirst + |> getAttachedMemberWith r t thisArg.Value + |> Some // DateTimeOffset | "get_LocalDateTime" -> - Helper.LibCall(com, "DateOffset", "toLocalTime", t, [thisArg.Value], [thisArg.Value.Type], ?loc=r) |> Some + Helper.LibCall(com, "DateOffset", "toLocalTime", t, [ thisArg.Value ], [ thisArg.Value.Type ], ?loc = r) + |> Some | "get_UtcDateTime" -> - Helper.LibCall(com, "DateOffset", "toUniversalTime", t, [thisArg.Value], [thisArg.Value.Type], ?loc=r) |> Some + Helper.LibCall(com, "DateOffset", "toUniversalTime", t, [ thisArg.Value ], [ thisArg.Value.Type ], ?loc = r) + |> Some | "get_DateTime" -> - let kind = System.DateTimeKind.Unspecified |> int |> makeIntConst - Helper.LibCall(com, "Date", "fromDateTimeOffset", t, [thisArg.Value; kind], [thisArg.Value.Type; kind.Type], ?loc=r) |> Some + let kind = + System.DateTimeKind.Unspecified + |> int + |> makeIntConst + + Helper.LibCall(com, "Date", "fromDateTimeOffset", t, [ thisArg.Value; kind ], [ thisArg.Value.Type; kind.Type ], ?loc = r) + |> Some | "FromUnixTimeSeconds" | "FromUnixTimeMilliseconds" -> - let value = Helper.LibCall(com, "Long", "toNumber", Number(Float64, None), args, i.SignatureArgTypes) let value = - if i.CompiledName = "FromUnixTimeSeconds" - then makeBinOp r t value (makeIntConst 1000) BinaryMultiply - else value - Helper.LibCall(com, "DateOffset", "datetime.fromtimestamp", t, [value; makeIntConst 0], [value.Type; Number(Int32, None)], ?loc=r) |> Some + Helper.LibCall(com, "Long", "toNumber", Number(Float64, None), args, i.SignatureArgTypes) + + let value = + if i.CompiledName = "FromUnixTimeSeconds" then + makeBinOp r t value (makeIntConst 1000) BinaryMultiply + else + value + + Helper.LibCall( + com, + "DateOffset", + "datetime.fromtimestamp", + t, + [ value; makeIntConst 0 ], + [ value.Type; Number(Int32, None) ], + ?loc = r + ) + |> Some | "ToUnixTimeSeconds" | "ToUnixTimeMilliseconds" -> let ms = getTime thisArg.Value + let args = - if i.CompiledName = "ToUnixTimeSeconds" - then [makeBinOp r t ms (makeIntConst 1000) BinaryDivide] - else [ms] - Helper.LibCall(com, "Long", "fromNumber", t, args, ?loc=r) |> Some + if i.CompiledName = "ToUnixTimeSeconds" then + [ makeBinOp r t ms (makeIntConst 1000) BinaryDivide ] + else + [ ms ] + + Helper.LibCall(com, "Long", "fromNumber", t, args, ?loc = r) + |> Some | "get_Ticks" -> - Helper.LibCall(com, "Date", "getTicks", t, [thisArg.Value], [thisArg.Value.Type], ?loc=r) |> Some + Helper.LibCall(com, "Date", "getTicks", t, [ thisArg.Value ], [ thisArg.Value.Type ], ?loc = r) + |> Some | "get_UtcTicks" -> - Helper.LibCall(com, "DateOffset", "getUtcTicks", t, [thisArg.Value], [thisArg.Value.Type], ?loc=r) |> Some + Helper.LibCall(com, "DateOffset", "getUtcTicks", t, [ thisArg.Value ], [ thisArg.Value.Type ], ?loc = r) + |> Some | "AddTicks" -> match thisArg, args with - | Some c, [ticks] -> - let ms = Helper.LibCall(com, "long", "op_Division", i.SignatureArgTypes.Head, [ticks; makeIntConst 10000], [ticks.Type; Number(Int32, None)]) - let ms = Helper.LibCall(com, "long", "toNumber", Number(Float64, None), [ms], [ms.Type]) - Helper.LibCall(com, moduleName, "addMilliseconds", Number(Float64, None), [c; ms], [c.Type; ms.Type], ?loc=r) |> Some + | Some c, [ ticks ] -> + let ms = + Helper.LibCall( + com, + "long", + "op_Division", + i.SignatureArgTypes.Head, + [ ticks; makeIntConst 10000 ], + [ ticks.Type; Number(Int32, None) ] + ) + + let ms = + Helper.LibCall(com, "long", "toNumber", Number(Float64, None), [ ms ], [ ms.Type ]) + + Helper.LibCall(com, moduleName, "addMilliseconds", Number(Float64, None), [ c; ms ], [ c.Type; ms.Type ], ?loc = r) + |> Some | _ -> None | meth -> - let meth = Naming.removeGetSetPrefix meth |> Naming.lowerFirst - Helper.LibCall(com, moduleName, meth, t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + let meth = + Naming.removeGetSetPrefix meth + |> Naming.lowerFirst + + Helper.LibCall(com, moduleName, meth, t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some let timeSpans (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = // let callee = match i.callee with Some c -> c | None -> i.args.Head match i.CompiledName with | ".ctor" -> - let meth = match args with [ticks] -> "fromTicks" | _ -> "create" - Helper.LibCall(com, "time_span", meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + let meth = + match args with + | [ ticks ] -> "fromTicks" + | _ -> "create" + + Helper.LibCall(com, "time_span", meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some | "FromMilliseconds" -> //TypeCast(args.Head, t) |> Some - Helper.LibCall(com, "time_span", "from_milliseconds", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + Helper.LibCall(com, "time_span", "from_milliseconds", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some | "get_TotalMilliseconds" -> //TypeCast(thisArg.Value, t) |> Some - Helper.LibCall(com, "time_span", "to_milliseconds", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + Helper.LibCall(com, "time_span", "to_milliseconds", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some | "ToString" when (args.Length = 1) -> "TimeSpan.ToString with one argument is not supported, because it depends of local culture, please add CultureInfo.InvariantCulture" |> addError com ctx.InlinePath r + None | "ToString" when (args.Length = 2) -> match args.Head with | StringConst "c" | StringConst "g" | StringConst "G" -> - Helper.LibCall(com, "time_span", "toString", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + Helper.LibCall(com, "time_span", "toString", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some | _ -> "TimeSpan.ToString don't support custom format. It only handles \"c\", \"g\" and \"G\" format, with CultureInfo.InvariantCulture." |> addError com ctx.InlinePath r + None | meth -> - let meth = Naming.removeGetSetPrefix meth |> Naming.lowerFirst - Helper.LibCall(com, "time_span", meth, t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + let meth = + Naming.removeGetSetPrefix meth + |> Naming.lowerFirst + + Helper.LibCall(com, "time_span", meth, t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some let timers (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg, args with - | ".ctor", _, _ -> Helper.LibCall(com, "timer", "Timer", t, args, i.SignatureArgTypes, isPyConstructor=true, ?loc=r) |> Some + | ".ctor", _, _ -> + Helper.LibCall(com, "timer", "Timer", t, args, i.SignatureArgTypes, isPyConstructor = true, ?loc = r) + |> Some | Naming.StartsWith "get_" meth, Some x, _ -> getAttachedMemberWith r t x meth |> Some - | Naming.StartsWith "set_" meth, Some x, [value] -> setExpr r x (makeStrConst meth) value |> Some - | meth, Some x, args -> Helper.InstanceCall(x, meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + | Naming.StartsWith "set_" meth, Some x, [ value ] -> setExpr r x (makeStrConst meth) value |> Some + | meth, Some x, args -> + Helper.InstanceCall(x, meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some | _ -> None let systemEnv (com: ICompiler) (ctx: Context) (_: SourceLocation option) (_: Type) (i: CallInfo) (_: Expr option) (_: Expr list) = match i.CompiledName with - | "get_NewLine" -> Some (makeStrConst "\n") + | "get_NewLine" -> Some(makeStrConst "\n") | _ -> None // Initial support, making at least InvariantCulture compile-able @@ -2762,52 +3822,84 @@ let globalization (com: ICompiler) (ctx: Context) (_: SourceLocation option) t ( let random (com: ICompiler) (ctx: Context) r t (i: CallInfo) (_: Expr option) (args: Expr list) = match i.CompiledName with - | ".ctor" -> ObjectExpr ([], t, None) |> Some + | ".ctor" -> ObjectExpr([], t, None) |> Some | "Next" -> let min, max = match args with | [] -> makeIntConst 0, makeIntConst System.Int32.MaxValue - | [max] -> makeIntConst 0, max - | [min; max] -> min, max + | [ max ] -> makeIntConst 0, max + | [ min; max ] -> min, max | _ -> failwith "Unexpected arg count for Random.Next" - Helper.LibCall(com, "util", "randomNext", t, [min; max], [min.Type; max.Type], ?loc=r) |> Some + + Helper.LibCall(com, "util", "randomNext", t, [ min; max ], [ min.Type; max.Type ], ?loc = r) + |> Some | "NextDouble" -> - Helper.GlobalCall ("math", t, [], [], memb="random") |> Some + Helper.GlobalCall("math", t, [], [], memb = "random") + |> Some | "NextBytes" -> let byteArray = match args with - | [b] -> b + | [ b ] -> b | _ -> failwith "Unexpected arg count for Random.NextBytes" - Helper.LibCall(com, "util", "randomBytes", t, [byteArray], [byteArray.Type], ?loc=r) |> Some + + Helper.LibCall(com, "util", "randomBytes", t, [ byteArray ], [ byteArray.Type ], ?loc = r) + |> Some | _ -> None let cancels (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName with | "get_None" // TODO: implement as non-cancellable token - | ".ctor" -> Helper.LibCall(com, "async_", "createCancellationToken", t, args, i.SignatureArgTypes) |> Some + | ".ctor" -> + Helper.LibCall(com, "async_", "createCancellationToken", t, args, i.SignatureArgTypes) + |> Some | "get_Token" -> thisArg - | "Cancel" | "CancelAfter" | "get_IsCancellationRequested" | "ThrowIfCancellationRequested" -> - let args, argTypes = match thisArg with Some c -> c::args, c.Type::i.SignatureArgTypes | None -> args, i.SignatureArgTypes - Helper.LibCall(com, "async_", Naming.removeGetSetPrefix i.CompiledName |> Naming.lowerFirst, t, args, argTypes, ?loc=r) |> Some + | "Cancel" + | "CancelAfter" + | "get_IsCancellationRequested" + | "ThrowIfCancellationRequested" -> + let args, argTypes = + match thisArg with + | Some c -> c :: args, c.Type :: i.SignatureArgTypes + | None -> args, i.SignatureArgTypes + + Helper.LibCall( + com, + "async_", + Naming.removeGetSetPrefix i.CompiledName + |> Naming.lowerFirst, + t, + args, + argTypes, + ?loc = r + ) + |> Some // TODO: Add check so CancellationTokenSource cannot be cancelled after disposed? | "Dispose" -> Null Type.Unit |> makeValue r |> Some - | "Register" -> Helper.InstanceCall(thisArg.Value, "register", t, args, i.SignatureArgTypes, ?loc=r) |> Some + | "Register" -> + Helper.InstanceCall(thisArg.Value, "register", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | _ -> None let monitor (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName with - | "Enter" | "Exit" -> Null Type.Unit |> makeValue r |> Some + | "Enter" + | "Exit" -> Null Type.Unit |> makeValue r |> Some | _ -> None let activator (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg, args with - | "CreateInstance", None, ([_type] | [_type; (ExprType (Array Any))]) -> - Helper.LibCall(com, "Reflection", "createInstance", t, args, ?loc=r) |> Some + | "CreateInstance", + None, + ([ _type ] + | [ _type; (ExprType (Array Any)) ]) -> + Helper.LibCall(com, "Reflection", "createInstance", t, args, ?loc = r) + |> Some | _ -> None let regex com (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = let propInt p callee = getExpr r t callee (makeIntConst p) let propStr p callee = getExpr r t callee (makeStrConst p) + let isGroup = match thisArg with | Some (ExprType (EntFullName "System.Text.RegularExpressions.Group")) -> true @@ -2815,25 +3907,39 @@ let regex com (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Exp match i.CompiledName with // TODO: Use RegexConst if no options have been passed? - | ".ctor" -> Helper.LibCall(com, "RegExp", "create", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | "get_Options" -> Helper.LibCall(com, "RegExp", "options", t, [thisArg.Value], [thisArg.Value.Type], ?loc=r) |> Some + | ".ctor" -> + Helper.LibCall(com, "RegExp", "create", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | "get_Options" -> + Helper.LibCall(com, "RegExp", "options", t, [ thisArg.Value ], [ thisArg.Value.Type ], ?loc = r) + |> Some // Capture | "get_Index" -> - if not isGroup - then propStr "index" thisArg.Value |> Some - else "Accessing index of Regex groups is not supported" - |> addErrorAndReturnNull com ctx.InlinePath r |> Some + if not isGroup then + propStr "index" thisArg.Value |> Some + else + "Accessing index of Regex groups is not supported" + |> addErrorAndReturnNull com ctx.InlinePath r + |> Some | "get_Value" -> if isGroup // In JS Regex group values can be undefined, ensure they're empty strings #838 - then Operation(Logical(LogicalOr, thisArg.Value, makeStrConst ""), t, r) |> Some - else propInt 0 thisArg.Value |> Some + then + Operation(Logical(LogicalOr, thisArg.Value, makeStrConst ""), t, r) + |> Some + else + propInt 0 thisArg.Value |> Some | "get_Length" -> - if isGroup - then propStr "length" thisArg.Value |> Some - else propInt 0 thisArg.Value |> propStr "length" |> Some + if isGroup then + propStr "length" thisArg.Value |> Some + else + propInt 0 thisArg.Value + |> propStr "length" + |> Some // Group - | "get_Success" -> makeEqOp r thisArg.Value (Value(Null thisArg.Value.Type, None)) BinaryUnequal |> Some + | "get_Success" -> + makeEqOp r thisArg.Value (Value(Null thisArg.Value.Type, None)) BinaryUnequal + |> Some // Match | "get_Groups" -> thisArg.Value |> Some // MatchCollection & GroupCollection @@ -2865,181 +3971,336 @@ let regex com (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Exp | "get_Count" -> propStr "length" thisArg.Value |> Some | "GetEnumerator" -> getEnumerator com r t thisArg.Value |> Some | meth -> - let meth = Naming.removeGetSetPrefix meth |> Naming.lowerFirst - Helper.LibCall(com, "RegExp", meth, t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + let meth = + Naming.removeGetSetPrefix meth + |> Naming.lowerFirst + + Helper.LibCall(com, "RegExp", meth, t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some let encoding (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg, args.Length with - | ("get_Unicode" | "get_UTF8"), _, _ -> - Helper.LibCall(com, "Encoding", i.CompiledName, t, args, i.SignatureArgTypes, ?loc=r) |> Some - | "GetBytes", Some callee, (1 | 3) -> + | ("get_Unicode" + | "get_UTF8"), + _, + _ -> + Helper.LibCall(com, "Encoding", i.CompiledName, t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | "GetBytes", + Some callee, + (1 + | 3) -> let meth = Naming.lowerFirst i.CompiledName - let expr = Helper.InstanceCall(callee, meth, t, args, i.SignatureArgTypes, ?loc=r) - if com.Options.TypedArrays then expr |> Some - else toArray r t expr |> Some // convert to dynamic array - | "GetString", Some callee, (1 | 3) -> + + let expr = + Helper.InstanceCall(callee, meth, t, args, i.SignatureArgTypes, ?loc = r) + + if com.Options.TypedArrays then + expr |> Some + else + toArray r t expr |> Some // convert to dynamic array + | "GetString", + Some callee, + (1 + | 3) -> let meth = Naming.lowerFirst i.CompiledName - Helper.InstanceCall(callee, meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + + Helper.InstanceCall(callee, meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some | _ -> None let enumerators (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match thisArg with | Some callee -> // Enumerators are mangled, use the fully qualified name - let isGenericCurrent = i.CompiledName = "get_Current" && i.DeclaringEntityFullName <> Types.ienumerator - let entityName = if isGenericCurrent then Types.ienumeratorGeneric else Types.ienumerator + let isGenericCurrent = + i.CompiledName = "get_Current" + && i.DeclaringEntityFullName <> Types.ienumerator + + let entityName = + if isGenericCurrent then + Types.ienumeratorGeneric + else + Types.ienumerator + let methName = entityName + "." + i.CompiledName - Helper.InstanceCall(callee, methName, t, args, ?loc=r) |> Some + + Helper.InstanceCall(callee, methName, t, args, ?loc = r) + |> Some | _ -> None let enumerables (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (_: Expr list) = match thisArg, i.CompiledName with // This property only belongs to Key and Value Collections - | Some callee, "get_Count" -> Helper.LibCall(com, "Seq", "length", t, [callee], ?loc=r) |> Some + | Some callee, "get_Count" -> + Helper.LibCall(com, "Seq", "length", t, [ callee ], ?loc = r) + |> Some | Some callee, "GetEnumerator" -> getEnumerator com r t callee |> Some | _ -> None let events (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg with - | ".ctor", _ -> Helper.LibCall(com, "Event", "default", t, args, i.SignatureArgTypes, isPyConstructor=true, ?loc=r) |> Some + | ".ctor", _ -> + Helper.LibCall(com, "Event", "default", t, args, i.SignatureArgTypes, isPyConstructor = true, ?loc = r) + |> Some | "get_Publish", Some x -> getAttachedMemberWith r t x "Publish" |> Some - | meth, Some x -> Helper.InstanceCall(x, meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some - | meth, None -> Helper.LibCall(com, "Event", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + | meth, Some x -> + Helper.InstanceCall(x, meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | meth, None -> + Helper.LibCall(com, "Event", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some let observable (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Expr option) (args: Expr list) = - Helper.LibCall(com, "Observable", Naming.lowerFirst i.CompiledName, t, args, i.SignatureArgTypes, ?loc=r) |> Some + Helper.LibCall(com, "Observable", Naming.lowerFirst i.CompiledName, t, args, i.SignatureArgTypes, ?loc = r) + |> Some let mailbox (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match thisArg with | None -> match i.CompiledName with - | ".ctor" -> Helper.LibCall(com, "mailbox_processor", "MailboxProcessor", t, args, i.SignatureArgTypes, isPyConstructor=true, ?loc=r) |> Some - | "Start" -> Helper.LibCall(com, "mailbox_processor", "start", t, args, i.SignatureArgTypes, ?loc=r) |> Some + | ".ctor" -> + Helper.LibCall(com, "mailbox_processor", "MailboxProcessor", t, args, i.SignatureArgTypes, isPyConstructor = true, ?loc = r) + |> Some + | "Start" -> + Helper.LibCall(com, "mailbox_processor", "start", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | _ -> None | Some callee -> match i.CompiledName with // `reply` belongs to AsyncReplyChannel - | "Start" | "Receive" | "PostAndAsyncReply" | "Post" -> + | "Start" + | "Receive" + | "PostAndAsyncReply" + | "Post" -> let memb = - if i.CompiledName = "Start" - then "startInstance" - else Naming.lowerFirst i.CompiledName - Helper.LibCall(com, "mailbox_processor", memb, t, args, i.SignatureArgTypes, thisArg=callee, ?loc=r) |> Some - | "Reply" -> Helper.InstanceCall(callee, "reply", t, args, i.SignatureArgTypes, ?loc=r) |> Some + if i.CompiledName = "Start" then + "startInstance" + else + Naming.lowerFirst i.CompiledName + + Helper.LibCall(com, "mailbox_processor", memb, t, args, i.SignatureArgTypes, thisArg = callee, ?loc = r) + |> Some + | "Reply" -> + Helper.InstanceCall(callee, "reply", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | _ -> None let asyncBuilder (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match thisArg, i.CompiledName, args with - | _, "Singleton", _ -> makeImportLib com t "singleton" "async_builder" |> Some + | _, "Singleton", _ -> + makeImportLib com t "singleton" "async_builder" + |> Some // For Using we need to cast the argument to IDisposable - | Some x, "Using", [arg; f] -> - Helper.InstanceCall(x, "Using", t, [arg; f], i.SignatureArgTypes, ?loc=r) |> Some - | Some x, meth, _ -> Helper.InstanceCall(x, meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some - | None, meth, _ -> Helper.LibCall(com, "async_builder", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + | Some x, "Using", [ arg; f ] -> + Helper.InstanceCall(x, "Using", t, [ arg; f ], i.SignatureArgTypes, ?loc = r) + |> Some + | Some x, meth, _ -> + Helper.InstanceCall(x, meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | None, meth, _ -> + Helper.LibCall(com, "async_builder", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some let asyncs com (ctx: Context) r t (i: CallInfo) (_: Expr option) (args: Expr list) = match i.CompiledName with // TODO: Throw error for RunSynchronously | "Start" -> - "Async.Start will behave as StartImmediate" |> addWarning com ctx.InlinePath r - Helper.LibCall(com, "async_", "start", t, args, i.SignatureArgTypes, ?loc=r) |> Some + "Async.Start will behave as StartImmediate" + |> addWarning com ctx.InlinePath r + + Helper.LibCall(com, "async_", "start", t, args, i.SignatureArgTypes, ?loc = r) + |> Some // Make sure cancellationToken is called as a function and not a getter - | "get_CancellationToken" -> Helper.LibCall(com, "async_", "cancellationToken", t, [], ?loc=r) |> Some + | "get_CancellationToken" -> + Helper.LibCall(com, "async_", "cancellationToken", t, [], ?loc = r) + |> Some // `catch` cannot be used as a function name in JS - | "Catch" -> Helper.LibCall(com, "async_", "catchAsync", t, args, i.SignatureArgTypes, ?loc=r) |> Some + | "Catch" -> + Helper.LibCall(com, "async_", "catchAsync", t, args, i.SignatureArgTypes, ?loc = r) + |> Some // Fable.Core extensions - | meth -> Helper.LibCall(com, "async_", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + | meth -> + Helper.LibCall(com, "async_", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some let tasks com (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match thisArg, i.CompiledName with - | Some x, "GetAwaiter" -> Helper.LibCall(com, "task", "get_awaiter", t, [x], i.SignatureArgTypes, ?loc=r) |> Some - | Some x, "GetResult" -> Helper.LibCall(com, "task", "get_result", t, [x], i.SignatureArgTypes, ?loc=r) |> Some - | Some x, "get_Result" -> Helper.LibCall(com, "task", "get_result", t, [x], i.SignatureArgTypes, ?loc=r) |> Some - | Some x, meth -> Helper.InstanceCall(x, meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some - | None, meth -> Helper.LibCall(com, "task", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + | Some x, "GetAwaiter" -> + Helper.LibCall(com, "task", "get_awaiter", t, [ x ], i.SignatureArgTypes, ?loc = r) + |> Some + | Some x, "GetResult" -> + Helper.LibCall(com, "task", "get_result", t, [ x ], i.SignatureArgTypes, ?loc = r) + |> Some + | Some x, "get_Result" -> + Helper.LibCall(com, "task", "get_result", t, [ x ], i.SignatureArgTypes, ?loc = r) + |> Some + | Some x, meth -> + Helper.InstanceCall(x, meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | None, meth -> + Helper.LibCall(com, "task", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some let taskBuilder (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match thisArg, i.CompiledName, args with - | _, "Singleton", _ -> makeImportLib com t "singleton" "task_builder" |> Some + | _, "Singleton", _ -> + makeImportLib com t "singleton" "task_builder" + |> Some // For Using we need to cast the argument to IDisposable - | Some x, "TaskBuilderBase.Using", [arg; f] - | Some x, "Using", [arg; f] -> - Helper.InstanceCall(x, "Using", t, [arg; f], i.SignatureArgTypes, ?loc=r) |> Some - | Some x, "TaskBuilderBase.Bind", [arg; f] -> - Helper.InstanceCall(x, "Bind", t, [arg; f], i.SignatureArgTypes, ?loc=r) |> Some + | Some x, "TaskBuilderBase.Using", [ arg; f ] + | Some x, "Using", [ arg; f ] -> + Helper.InstanceCall(x, "Using", t, [ arg; f ], i.SignatureArgTypes, ?loc = r) + |> Some + | Some x, "TaskBuilderBase.Bind", [ arg; f ] -> + Helper.InstanceCall(x, "Bind", t, [ arg; f ], i.SignatureArgTypes, ?loc = r) + |> Some - | Some x, meth, _ -> Helper.InstanceCall(x, meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some - | None, meth, _ -> Helper.LibCall(com, "task_builder", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc=r) |> Some + | Some x, meth, _ -> + Helper.InstanceCall(x, meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | None, meth, _ -> + Helper.LibCall(com, "task_builder", Naming.lowerFirst meth, t, args, i.SignatureArgTypes, ?loc = r) + |> Some let guids (com: ICompiler) (ctx: Context) (r: SourceLocation option) t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = let parseGuid (literalGuid: string) = try - System.Guid.Parse(literalGuid) |> string |> makeStrConst - with e -> - e.Message |> addErrorAndReturnNull com ctx.InlinePath r + System.Guid.Parse(literalGuid) + |> string + |> makeStrConst + with + | e -> + e.Message + |> addErrorAndReturnNull com ctx.InlinePath r |> Some match i.CompiledName with - | "NewGuid" -> Helper.LibCall(com, "Guid", "new_guid", t, []) |> Some - | "Parse" -> + | "NewGuid" -> + Helper.LibCall(com, "Guid", "new_guid", t, []) + |> Some + | "Parse" -> match args with - | [StringConst literalGuid] -> parseGuid literalGuid - | _-> Helper.LibCall(com, "Guid", "parse", t, args, i.SignatureArgTypes) |> Some - | "TryParse" -> Helper.LibCall(com, "Guid", "tryParse", t, args, i.SignatureArgTypes) |> Some - | "ToByteArray" -> Helper.LibCall(com, "Guid", "guidToArray", t, [thisArg.Value], [thisArg.Value.Type]) |> Some + | [ StringConst literalGuid ] -> parseGuid literalGuid + | _ -> + Helper.LibCall(com, "Guid", "parse", t, args, i.SignatureArgTypes) + |> Some + | "TryParse" -> + Helper.LibCall(com, "Guid", "tryParse", t, args, i.SignatureArgTypes) + |> Some + | "ToByteArray" -> + Helper.LibCall(com, "Guid", "guidToArray", t, [ thisArg.Value ], [ thisArg.Value.Type ]) + |> Some | "ToString" when (args.Length = 0) -> - Helper.GlobalCall("str", t, [ thisArg.Value ], ?loc=r) |> Some + Helper.GlobalCall("str", t, [ thisArg.Value ], ?loc = r) + |> Some | "ToString" when (args.Length = 1) -> match args with - | [StringConst literalFormat] -> + | [ StringConst literalFormat ] -> match literalFormat with - | "N" | "D" | "B" | "P" | "X" -> - Helper.LibCall(com, "Guid", "toString", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + | "N" + | "D" + | "B" + | "P" + | "X" -> + Helper.LibCall(com, "Guid", "toString", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some | _ -> "Guid.ToString doesn't support a custom format. It only handles \"N\", \"D\", \"B\", \"P\" and \"X\" format." |> addError com ctx.InlinePath r + None - | _ -> Helper.LibCall(com, "Guid", "toString", t, args, i.SignatureArgTypes, ?thisArg=thisArg, ?loc=r) |> Some + | _ -> + Helper.LibCall(com, "Guid", "toString", t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) + |> Some | ".ctor" -> match args with - | [] -> emptyGuid() |> Some - | [ExprType (Array _)] -> Helper.LibCall(com, "Guid", "arrayToGuid", t, args, i.SignatureArgTypes) |> Some - | [StringConst literalGuid] -> parseGuid literalGuid - | [ExprType String] -> Helper.LibCall(com, "Guid", "parse", t, args, i.SignatureArgTypes) |> Some + | [] -> emptyGuid () |> Some + | [ ExprType (Array _) ] -> + Helper.LibCall(com, "Guid", "arrayToGuid", t, args, i.SignatureArgTypes) + |> Some + | [ StringConst literalGuid ] -> parseGuid literalGuid + | [ ExprType String ] -> + Helper.LibCall(com, "Guid", "parse", t, args, i.SignatureArgTypes) + |> Some | _ -> None | _ -> None let uris (com: ICompiler) (ctx: Context) (r: SourceLocation option) t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName with - | ".ctor" -> Helper.LibCall(com, "Uri", "Uri", t, args, i.SignatureArgTypes, isPyConstructor=true, ?loc=r) |> Some - | "UnescapeDataString" -> Helper.LibCall(com, "Util", "unescapeDataString", t, args, i.SignatureArgTypes) |> Some - | "EscapeDataString" -> Helper.LibCall(com, "Util", "escapeDataString", t, args, i.SignatureArgTypes) |> Some - | "EscapeUriString" -> Helper.LibCall(com, "Util", "escapeUriString", t, args, i.SignatureArgTypes) |> Some + | ".ctor" -> + Helper.LibCall(com, "Uri", "Uri", t, args, i.SignatureArgTypes, isPyConstructor = true, ?loc = r) + |> Some + | "UnescapeDataString" -> + Helper.LibCall(com, "Util", "unescapeDataString", t, args, i.SignatureArgTypes) + |> Some + | "EscapeDataString" -> + Helper.LibCall(com, "Util", "escapeDataString", t, args, i.SignatureArgTypes) + |> Some + | "EscapeUriString" -> + Helper.LibCall(com, "Util", "escapeUriString", t, args, i.SignatureArgTypes) + |> Some | "get_IsAbsoluteUri" -> - Naming.removeGetSetPrefix i.CompiledName |> Naming.lowerFirst |> getAttachedMemberWith r t thisArg.Value |> Some + Naming.removeGetSetPrefix i.CompiledName + |> Naming.lowerFirst + |> getAttachedMemberWith r t thisArg.Value + |> Some | "get_Scheme" -> - Naming.removeGetSetPrefix i.CompiledName |> Naming.lowerFirst |> getAttachedMemberWith r t thisArg.Value |> Some + Naming.removeGetSetPrefix i.CompiledName + |> Naming.lowerFirst + |> getAttachedMemberWith r t thisArg.Value + |> Some | "get_Host" -> - Naming.removeGetSetPrefix i.CompiledName |> Naming.lowerFirst |> getAttachedMemberWith r t thisArg.Value |> Some + Naming.removeGetSetPrefix i.CompiledName + |> Naming.lowerFirst + |> getAttachedMemberWith r t thisArg.Value + |> Some | "get_AbsolutePath" -> - Naming.removeGetSetPrefix i.CompiledName |> Naming.lowerFirst |> getAttachedMemberWith r t thisArg.Value |> Some + Naming.removeGetSetPrefix i.CompiledName + |> Naming.lowerFirst + |> getAttachedMemberWith r t thisArg.Value + |> Some | "get_AbsoluteUri" -> - Naming.removeGetSetPrefix i.CompiledName |> Naming.lowerFirst |> getAttachedMemberWith r t thisArg.Value |> Some + Naming.removeGetSetPrefix i.CompiledName + |> Naming.lowerFirst + |> getAttachedMemberWith r t thisArg.Value + |> Some | "get_PathAndQuery" -> - Naming.removeGetSetPrefix i.CompiledName |> Naming.lowerFirst |> getAttachedMemberWith r t thisArg.Value |> Some + Naming.removeGetSetPrefix i.CompiledName + |> Naming.lowerFirst + |> getAttachedMemberWith r t thisArg.Value + |> Some | "get_Query" -> - Naming.removeGetSetPrefix i.CompiledName |> Naming.lowerFirst |> getAttachedMemberWith r t thisArg.Value |> Some + Naming.removeGetSetPrefix i.CompiledName + |> Naming.lowerFirst + |> getAttachedMemberWith r t thisArg.Value + |> Some | "get_Fragment" -> - Naming.removeGetSetPrefix i.CompiledName |> Naming.lowerFirst |> getAttachedMemberWith r t thisArg.Value |> Some + Naming.removeGetSetPrefix i.CompiledName + |> Naming.lowerFirst + |> getAttachedMemberWith r t thisArg.Value + |> Some | _ -> None let laziness (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg, args with - | (".ctor"|"Create"),_,_ -> Helper.LibCall(com, "Util", "Lazy", t, args, i.SignatureArgTypes, isPyConstructor=true, ?loc=r) |> Some - | "CreateFromValue",_,_ -> Helper.LibCall(com, "Util", "lazyFromValue", t, args, i.SignatureArgTypes, ?loc=r) |> Some + | (".ctor" + | "Create"), + _, + _ -> + Helper.LibCall(com, "Util", "Lazy", t, args, i.SignatureArgTypes, isPyConstructor = true, ?loc = r) + |> Some + | "CreateFromValue", _, _ -> + Helper.LibCall(com, "Util", "lazyFromValue", t, args, i.SignatureArgTypes, ?loc = r) + |> Some | "Force", Some callee, _ -> getAttachedMemberWith r t callee "Value" |> Some - | ("get_Value"|"get_IsValueCreated"), Some callee, _ -> - Naming.removeGetSetPrefix i.CompiledName |> getAttachedMemberWith r t callee |> Some + | ("get_Value" + | "get_IsValueCreated"), + Some callee, + _ -> + Naming.removeGetSetPrefix i.CompiledName + |> getAttachedMemberWith r t callee + |> Some | _ -> None let controlExtensions (com: ICompiler) (ctx: Context) (_: SourceLocation option) t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = @@ -3050,68 +4311,102 @@ let controlExtensions (com: ICompiler) (ctx: Context) (_: SourceLocation option) |> Option.map (fun meth -> let args, argTypes = thisArg - |> Option.map (fun thisArg -> thisArg::args, thisArg.Type::i.SignatureArgTypes) + |> Option.map (fun thisArg -> thisArg :: args, thisArg.Type :: i.SignatureArgTypes) |> Option.defaultValue (args, i.SignatureArgTypes) |> fun (args, argTypes) -> List.rev args, List.rev argTypes + Helper.LibCall(com, "Observable", meth, t, args, argTypes)) let types (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = let returnString r x = StringConstant x |> makeValue r |> Some + let resolved = // Some optimizations when the type is known at compile time match thisArg with - | Some(Value(TypeInfo exprType, exprRange) as thisArg) -> + | Some (Value (TypeInfo exprType, exprRange) as thisArg) -> match exprType with - | GenericParam(name,_) -> genericTypeInfoError name |> addError com ctx.InlinePath exprRange + | GenericParam (name, _) -> + genericTypeInfoError name + |> addError com ctx.InlinePath exprRange | _ -> () + match i.CompiledName with | "GetInterface" -> match exprType, args with - | DeclaredType(e, genArgs), [StringConst name] -> Some(e, genArgs, name, false) - | DeclaredType(e, genArgs), [StringConst name; BoolConst ignoreCase] -> Some(e, genArgs, name, ignoreCase) + | DeclaredType (e, genArgs), [ StringConst name ] -> Some(e, genArgs, name, false) + | DeclaredType (e, genArgs), [ StringConst name; BoolConst ignoreCase ] -> Some(e, genArgs, name, ignoreCase) | _ -> None |> Option.map (fun (e, genArgs, name, ignoreCase) -> let e = com.GetEntity(e) - let genMap = List.zip (e.GenericParameters |> List.map (fun p -> p.Name)) genArgs |> Map - let comp = if ignoreCase then System.StringComparison.OrdinalIgnoreCase else System.StringComparison.Ordinal - e.AllInterfaces |> Seq.tryPick (fun ifc -> + + let genMap = + List.zip (e.GenericParameters |> List.map (fun p -> p.Name)) genArgs + |> Map + + let comp = + if ignoreCase then + System.StringComparison.OrdinalIgnoreCase + else + System.StringComparison.Ordinal + + e.AllInterfaces + |> Seq.tryPick (fun ifc -> let ifcName = getTypeNameFromFullName ifc.Entity.FullName + if ifcName.Equals(name, comp) then - let genArgs = ifc.GenericArgs |> List.map (function - | GenericParam(name,_) as gen -> Map.tryFind name genMap |> Option.defaultValue gen - | gen -> gen) + let genArgs = + ifc.GenericArgs + |> List.map (function + | GenericParam (name, _) as gen -> Map.tryFind name genMap |> Option.defaultValue gen + | gen -> gen) + Some(ifc.Entity, genArgs) - else None) + else + None) |> function - | Some(ifcEnt, genArgs) -> Value(TypeInfo(DeclaredType(ifcEnt, genArgs)), r) + | Some (ifcEnt, genArgs) -> Value(TypeInfo(DeclaredType(ifcEnt, genArgs)), r) | None -> Value(Null t, r)) | "get_FullName" -> getTypeFullName false exprType |> returnString r | "get_Namespace" -> let fullname = getTypeFullName false exprType + match fullname.LastIndexOf(".") with | -1 -> "" |> returnString r | i -> fullname.Substring(0, i) |> returnString r | "get_IsArray" -> - match exprType with Array _ -> true | _ -> false - |> BoolConstant |> makeValue r |> Some + match exprType with + | Array _ -> true + | _ -> false + |> BoolConstant + |> makeValue r + |> Some | "get_IsEnum" -> match exprType with - | Enum t -> true | _ -> false - |> BoolConstant |> makeValue r |> Some + | Enum t -> true + | _ -> false + |> BoolConstant + |> makeValue r + |> Some | "GetElementType" -> match exprType with | Array t -> TypeInfo t |> makeValue r |> Some | _ -> Null t |> makeValue r |> Some | "get_IsGenericType" -> - List.isEmpty exprType.Generics |> not |> BoolConstant |> makeValue r |> Some - | "get_GenericTypeArguments" | "GetGenericArguments" -> + List.isEmpty exprType.Generics + |> not + |> BoolConstant + |> makeValue r + |> Some + | "get_GenericTypeArguments" + | "GetGenericArguments" -> let arVals = exprType.Generics |> List.map (makeTypeInfo r) NewArray(arVals, Any) |> makeValue r |> Some | "GetGenericTypeDefinition" -> let newGen = exprType.Generics |> List.map (fun _ -> Any) + let exprType = match exprType with - | Option(_, isStruct) -> Option(newGen.Head, isStruct) + | Option (_, isStruct) -> Option(newGen.Head, isStruct) | Array _ -> Array newGen.Head | List _ -> List newGen.Head | LambdaType _ -> @@ -3123,206 +4418,244 @@ let types (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr optio | Tuple (_, isStruct) -> Tuple(newGen, isStruct) | DeclaredType (ent, _) -> DeclaredType(ent, newGen) | t -> t + TypeInfo exprType |> makeValue exprRange |> Some | _ -> None - | _ -> None + | _ -> None + match resolved, thisArg with | Some _, _ -> resolved | None, Some thisArg -> match i.CompiledName with | "GetTypeInfo" -> Some thisArg - | "get_GenericTypeArguments" | "GetGenericArguments" -> - Helper.LibCall(com, "Reflection", "getGenerics", t, [thisArg], ?loc=r) |> Some + | "get_GenericTypeArguments" + | "GetGenericArguments" -> + Helper.LibCall(com, "Reflection", "getGenerics", t, [ thisArg ], ?loc = r) + |> Some | "MakeGenericType" -> - Helper.LibCall(com, "Reflection", "makeGenericType", t, thisArg::args, ?loc=r) |> Some - | "get_FullName" | "get_Namespace" - | "get_IsArray" | "GetElementType" - | "get_IsGenericType" | "GetGenericTypeDefinition" - | "get_IsEnum" | "GetEnumUnderlyingType" | "GetEnumValues" | "GetEnumNames" | "IsSubclassOf" -> - let meth = Naming.removeGetSetPrefix i.CompiledName |> Naming.lowerFirst - Helper.LibCall(com, "Reflection", meth, t, thisArg::args, ?loc=r) |> Some + Helper.LibCall(com, "Reflection", "makeGenericType", t, thisArg :: args, ?loc = r) + |> Some + | "get_FullName" + | "get_Namespace" + | "get_IsArray" + | "GetElementType" + | "get_IsGenericType" + | "GetGenericTypeDefinition" + | "get_IsEnum" + | "GetEnumUnderlyingType" + | "GetEnumValues" + | "GetEnumNames" + | "IsSubclassOf" -> + let meth = + Naming.removeGetSetPrefix i.CompiledName + |> Naming.lowerFirst + + Helper.LibCall(com, "Reflection", meth, t, thisArg :: args, ?loc = r) + |> Some | _ -> None | None, None -> None let fsharpType com methName (r: SourceLocation option) t (i: CallInfo) (args: Expr list) = match methName with | "MakeTupleType" -> - Helper.LibCall(com, "Reflection", "tuple_type", t, args, i.SignatureArgTypes, hasSpread=true, ?loc=r) |> Some + Helper.LibCall(com, "Reflection", "tuple_type", t, args, i.SignatureArgTypes, hasSpread = true, ?loc = r) + |> Some // Prevent name clash with FSharpValue.GetRecordFields | "GetRecordFields" -> - Helper.LibCall(com, "Reflection", "getRecordElements", t, args, i.SignatureArgTypes, ?loc=r) |> Some - | "GetUnionCases" | "GetTupleElements" | "GetFunctionElements" - | "IsUnion" | "IsRecord" | "IsTuple" | "IsFunction" -> - Helper.LibCall(com, "Reflection", Naming.lowerFirst methName, t, args, i.SignatureArgTypes, ?loc=r) |> Some - | "IsExceptionRepresentation" | "GetExceptionFields" -> None // TODO!!! + Helper.LibCall(com, "Reflection", "getRecordElements", t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | "GetUnionCases" + | "GetTupleElements" + | "GetFunctionElements" + | "IsUnion" + | "IsRecord" + | "IsTuple" + | "IsFunction" -> + Helper.LibCall(com, "Reflection", Naming.lowerFirst methName, t, args, i.SignatureArgTypes, ?loc = r) + |> Some + | "IsExceptionRepresentation" + | "GetExceptionFields" -> None // TODO!!! | _ -> None let fsharpValue com methName (r: SourceLocation option) t (i: CallInfo) (args: Expr list) = match methName with - | "GetUnionFields" | "GetRecordFields" | "GetRecordField" | "GetTupleFields" | "GetTupleField" - | "MakeUnion" | "MakeRecord" | "MakeTuple" -> - Helper.LibCall(com, "Reflection", Naming.lowerFirst methName, t, args, i.SignatureArgTypes, ?loc=r) |> Some + | "GetUnionFields" + | "GetRecordFields" + | "GetRecordField" + | "GetTupleFields" + | "GetTupleField" + | "MakeUnion" + | "MakeRecord" + | "MakeTuple" -> + Helper.LibCall(com, "Reflection", Naming.lowerFirst methName, t, args, i.SignatureArgTypes, ?loc = r) + |> Some | "GetExceptionFields" -> None // TODO!!! | _ -> None -let curryExprAtRuntime com arity (expr: Expr) = - Helper.LibCall(com, "Util", "curry", expr.Type, [makeIntConst arity; expr]) +let curryExprAtRuntime com arity (expr: Expr) = Helper.LibCall(com, "Util", "curry", expr.Type, [ makeIntConst arity; expr ]) -let uncurryExprAtRuntime com arity (expr: Expr) = - Helper.LibCall(com, "Util", "uncurry", expr.Type, [makeIntConst arity; expr]) +let uncurryExprAtRuntime com arity (expr: Expr) = Helper.LibCall(com, "Util", "uncurry", expr.Type, [ makeIntConst arity; expr ]) let partialApplyAtRuntime com t arity (fn: Expr) (args: Expr list) = let args = NewArray(args, Any) |> makeValue None - Helper.LibCall(com, "Util", "partialApply", t, [makeIntConst arity; fn; args]) + Helper.LibCall(com, "Util", "partialApply", t, [ makeIntConst arity; fn; args ]) let tryField com returnTyp ownerTyp fieldName = match ownerTyp, fieldName with | Builtin BclDecimal, _ -> - Helper.LibValue(com, coreModFor BclDecimal, "get_" + fieldName, returnTyp) |> Some + Helper.LibValue(com, coreModFor BclDecimal, "get_" + fieldName, returnTyp) + |> Some | String, "Empty" -> makeStrConst "" |> Some - | Builtin BclGuid, "Empty" -> emptyGuid() |> Some + | Builtin BclGuid, "Empty" -> emptyGuid () |> Some | Builtin BclTimeSpan, "Zero" -> makeIntConst 0 |> Some - | Builtin BclDateTime, ("MaxValue" | "MinValue") -> - Helper.LibCall(com, coreModFor BclDateTime, Naming.lowerFirst fieldName, returnTyp, []) |> Some - | Builtin BclDateTimeOffset, ("MaxValue" | "MinValue") -> - Helper.LibCall(com, coreModFor BclDateTimeOffset, Naming.lowerFirst fieldName, returnTyp, []) |> Some - | DeclaredType(ent, genArgs), fieldName -> + | Builtin BclDateTime, + ("MaxValue" + | "MinValue") -> + Helper.LibCall(com, coreModFor BclDateTime, Naming.lowerFirst fieldName, returnTyp, []) + |> Some + | Builtin BclDateTimeOffset, + ("MaxValue" + | "MinValue") -> + Helper.LibCall(com, coreModFor BclDateTimeOffset, Naming.lowerFirst fieldName, returnTyp, []) + |> Some + | DeclaredType (ent, genArgs), fieldName -> match ent.FullName with | "System.BitConverter" -> - Helper.LibCall(com, "BitConverter", Naming.lowerFirst fieldName, returnTyp, []) |> Some + Helper.LibCall(com, "BitConverter", Naming.lowerFirst fieldName, returnTyp, []) + |> Some | _ -> None | _ -> None let private replacedModules = - dict [ - "System.Math", operators - "Microsoft.FSharp.Core.Operators", operators - "Microsoft.FSharp.Core.Operators.Checked", operators - "Microsoft.FSharp.Core.Operators.Unchecked", unchecked - "Microsoft.FSharp.Core.Operators.OperatorIntrinsics", intrinsicFunctions - "Microsoft.FSharp.Core.ExtraTopLevelOperators", operators - "Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicFunctions", intrinsicFunctions - "Microsoft.FSharp.Core.LanguagePrimitives", languagePrimitives - "Microsoft.FSharp.Core.LanguagePrimitives.HashCompare", languagePrimitives - "Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators", operators - "System.Runtime.CompilerServices.RuntimeHelpers", runtimeHelpers - "System.Runtime.ExceptionServices.ExceptionDispatchInfo", exceptionDispatchInfo - Types.char, chars - Types.string, strings - "Microsoft.FSharp.Core.StringModule", stringModule - "System.FormattableString", formattableString - "System.Runtime.CompilerServices.FormattableStringFactory", formattableString - "System.Text.StringBuilder", bclType - Types.array, arrays - Types.list, lists - "Microsoft.FSharp.Collections.ArrayModule", arrayModule - "Microsoft.FSharp.Collections.ListModule", listModule - "Microsoft.FSharp.Collections.HashIdentity", fsharpModule - "Microsoft.FSharp.Collections.ComparisonIdentity", fsharpModule - "Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers", seqModule - "Microsoft.FSharp.Collections.SeqModule", seqModule - Types.keyValuePair, keyValuePairs - "System.Collections.Generic.Comparer`1", bclType - "System.Collections.Generic.EqualityComparer`1", bclType - Types.dictionary, dictionaries - Types.idictionary, dictionaries - Types.ireadonlydictionary, dictionaries - Types.ienumerableGeneric, enumerables - Types.ienumerable, enumerables - "System.Collections.Generic.Dictionary`2.ValueCollection", enumerables - "System.Collections.Generic.Dictionary`2.KeyCollection", enumerables - "System.Collections.Generic.Dictionary`2.Enumerator", enumerators - "System.Collections.Generic.Dictionary`2.ValueCollection.Enumerator", enumerators - "System.Collections.Generic.Dictionary`2.KeyCollection.Enumerator", enumerators - "System.Collections.Generic.List`1.Enumerator", enumerators - "System.Collections.Generic.HashSet`1.Enumerator", enumerators - "System.CharEnumerator", enumerators - Types.resizeArray, resizeArrays - "System.Collections.Generic.IList`1", resizeArrays - "System.Collections.IList", resizeArrays - Types.icollectionGeneric, resizeArrays - Types.icollection, resizeArrays - Types.hashset, hashSets - Types.iset, hashSets - Types.option, options - Types.valueOption, options - "System.Nullable`1", nullables - "Microsoft.FSharp.Core.OptionModule", optionModule - "Microsoft.FSharp.Core.ResultModule", results - Types.bigint, bigints - "Microsoft.FSharp.Core.NumericLiterals.NumericLiteralI", bigints - Types.reference, references - Types.object, objects - Types.valueType, valueTypes - "System.Enum", enums - "System.BitConverter", bitConvert - Types.bool, parseBool - Types.int8, parseNum - Types.uint8, parseNum - Types.int16, parseNum - Types.uint16, parseNum - Types.int32, parseNum - Types.uint32, parseNum - Types.int64, parseNum - Types.uint64, parseNum - Types.float32, parseNum - Types.float64, parseNum - Types.decimal, decimals - "System.Convert", convert - "System.Console", console - "System.Diagnostics.Debug", debug - "System.Diagnostics.Debugger", debug - Types.datetime, dates - Types.datetimeOffset, dates - Types.timespan, timeSpans - "System.Timers.Timer", timers - "System.Environment", systemEnv - "System.Globalization.CultureInfo", globalization - "System.Random", random - "System.Runtime.CompilerServices.TaskAwaiter`1", tasks - "System.Threading.CancellationToken", cancels - "System.Threading.CancellationTokenSource", cancels - "System.Threading.Monitor", monitor - "System.Threading.Tasks.Task`1", tasks - "System.Threading.Tasks.Task", tasks - "System.Activator", activator - "System.Text.Encoding", encoding - "System.Text.UnicodeEncoding", encoding - "System.Text.UTF8Encoding", encoding - "System.Text.RegularExpressions.Capture", regex - "System.Text.RegularExpressions.Match", regex - "System.Text.RegularExpressions.Group", regex - "System.Text.RegularExpressions.MatchCollection", regex - "System.Text.RegularExpressions.GroupCollection", regex - Types.regex, regex - Types.fsharpSet, sets - "Microsoft.FSharp.Collections.SetModule", setModule - Types.fsharpMap, maps - "Microsoft.FSharp.Collections.MapModule", mapModule - "Microsoft.FSharp.Control.FSharpMailboxProcessor`1", mailbox - "Microsoft.FSharp.Control.FSharpAsyncReplyChannel`1", mailbox - "Microsoft.FSharp.Control.FSharpAsyncBuilder", asyncBuilder - "Microsoft.FSharp.Control.AsyncActivation`1", asyncBuilder - "Microsoft.FSharp.Control.FSharpAsync", asyncs - "Microsoft.FSharp.Control.AsyncPrimitives", asyncs - "Microsoft.FSharp.Control.TaskBuilder", tasks - "Microsoft.FSharp.Control.TaskBuilderBase", taskBuilder - "Microsoft.FSharp.Control.TaskBuilderModule", taskBuilder - "Microsoft.FSharp.Control.TaskBuilderExtensions.HighPriority", taskBuilder - "Microsoft.FSharp.Control.TaskBuilderExtensions.LowPriority", taskBuilder - Types.guid, guids - "System.Uri", uris - "System.Lazy`1", laziness - "Microsoft.FSharp.Control.Lazy", laziness - "Microsoft.FSharp.Control.LazyExtensions", laziness - "Microsoft.FSharp.Control.CommonExtensions", controlExtensions - "Microsoft.FSharp.Control.FSharpEvent`1", events - "Microsoft.FSharp.Control.FSharpEvent`2", events - "Microsoft.FSharp.Control.EventModule", events - "Microsoft.FSharp.Control.ObservableModule", observable - Types.type_, types - "System.Reflection.TypeInfo", types -] + dict [ + "System.Math", operators + "Microsoft.FSharp.Core.Operators", operators + "Microsoft.FSharp.Core.Operators.Checked", operators + "Microsoft.FSharp.Core.Operators.Unchecked", unchecked + "Microsoft.FSharp.Core.Operators.OperatorIntrinsics", intrinsicFunctions + "Microsoft.FSharp.Core.ExtraTopLevelOperators", operators + "Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicFunctions", intrinsicFunctions + "Microsoft.FSharp.Core.LanguagePrimitives", languagePrimitives + "Microsoft.FSharp.Core.LanguagePrimitives.HashCompare", languagePrimitives + "Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators", operators + "System.Runtime.CompilerServices.RuntimeHelpers", runtimeHelpers + "System.Runtime.ExceptionServices.ExceptionDispatchInfo", exceptionDispatchInfo + Types.char, chars + Types.string, strings + "Microsoft.FSharp.Core.StringModule", stringModule + "System.FormattableString", formattableString + "System.Runtime.CompilerServices.FormattableStringFactory", formattableString + "System.Text.StringBuilder", bclType + Types.array, arrays + Types.list, lists + "Microsoft.FSharp.Collections.ArrayModule", arrayModule + "Microsoft.FSharp.Collections.ListModule", listModule + "Microsoft.FSharp.Collections.HashIdentity", fsharpModule + "Microsoft.FSharp.Collections.ComparisonIdentity", fsharpModule + "Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers", seqModule + "Microsoft.FSharp.Collections.SeqModule", seqModule + Types.keyValuePair, keyValuePairs + "System.Collections.Generic.Comparer`1", bclType + "System.Collections.Generic.EqualityComparer`1", bclType + Types.dictionary, dictionaries + Types.idictionary, dictionaries + Types.ireadonlydictionary, dictionaries + Types.ienumerableGeneric, enumerables + Types.ienumerable, enumerables + "System.Collections.Generic.Dictionary`2.ValueCollection", enumerables + "System.Collections.Generic.Dictionary`2.KeyCollection", enumerables + "System.Collections.Generic.Dictionary`2.Enumerator", enumerators + "System.Collections.Generic.Dictionary`2.ValueCollection.Enumerator", enumerators + "System.Collections.Generic.Dictionary`2.KeyCollection.Enumerator", enumerators + "System.Collections.Generic.List`1.Enumerator", enumerators + "System.Collections.Generic.HashSet`1.Enumerator", enumerators + "System.CharEnumerator", enumerators + Types.resizeArray, resizeArrays + "System.Collections.Generic.IList`1", resizeArrays + "System.Collections.IList", resizeArrays + Types.icollectionGeneric, resizeArrays + Types.icollection, resizeArrays + Types.hashset, hashSets + Types.iset, hashSets + Types.option, options + Types.valueOption, options + "System.Nullable`1", nullables + "Microsoft.FSharp.Core.OptionModule", optionModule + "Microsoft.FSharp.Core.ResultModule", results + Types.bigint, bigints + "Microsoft.FSharp.Core.NumericLiterals.NumericLiteralI", bigints + Types.reference, references + Types.object, objects + Types.valueType, valueTypes + "System.Enum", enums + "System.BitConverter", bitConvert + Types.bool, parseBool + Types.int8, parseNum + Types.uint8, parseNum + Types.int16, parseNum + Types.uint16, parseNum + Types.int32, parseNum + Types.uint32, parseNum + Types.int64, parseNum + Types.uint64, parseNum + Types.float32, parseNum + Types.float64, parseNum + Types.decimal, decimals + "System.Convert", convert + "System.Console", console + "System.Diagnostics.Debug", debug + "System.Diagnostics.Debugger", debug + Types.datetime, dates + Types.datetimeOffset, dates + Types.timespan, timeSpans + "System.Timers.Timer", timers + "System.Environment", systemEnv + "System.Globalization.CultureInfo", globalization + "System.Random", random + "System.Runtime.CompilerServices.TaskAwaiter`1", tasks + "System.Threading.CancellationToken", cancels + "System.Threading.CancellationTokenSource", cancels + "System.Threading.Monitor", monitor + "System.Threading.Tasks.Task`1", tasks + "System.Threading.Tasks.Task", tasks + "System.Activator", activator + "System.Text.Encoding", encoding + "System.Text.UnicodeEncoding", encoding + "System.Text.UTF8Encoding", encoding + "System.Text.RegularExpressions.Capture", regex + "System.Text.RegularExpressions.Match", regex + "System.Text.RegularExpressions.Group", regex + "System.Text.RegularExpressions.MatchCollection", regex + "System.Text.RegularExpressions.GroupCollection", regex + Types.regex, regex + Types.fsharpSet, sets + "Microsoft.FSharp.Collections.SetModule", setModule + Types.fsharpMap, maps + "Microsoft.FSharp.Collections.MapModule", mapModule + "Microsoft.FSharp.Control.FSharpMailboxProcessor`1", mailbox + "Microsoft.FSharp.Control.FSharpAsyncReplyChannel`1", mailbox + "Microsoft.FSharp.Control.FSharpAsyncBuilder", asyncBuilder + "Microsoft.FSharp.Control.AsyncActivation`1", asyncBuilder + "Microsoft.FSharp.Control.FSharpAsync", asyncs + "Microsoft.FSharp.Control.AsyncPrimitives", asyncs + "Microsoft.FSharp.Control.TaskBuilder", tasks + "Microsoft.FSharp.Control.TaskBuilderBase", taskBuilder + "Microsoft.FSharp.Control.TaskBuilderModule", taskBuilder + "Microsoft.FSharp.Control.TaskBuilderExtensions.HighPriority", taskBuilder + "Microsoft.FSharp.Control.TaskBuilderExtensions.LowPriority", taskBuilder + Types.guid, guids + "System.Uri", uris + "System.Lazy`1", laziness + "Microsoft.FSharp.Control.Lazy", laziness + "Microsoft.FSharp.Control.LazyExtensions", laziness + "Microsoft.FSharp.Control.CommonExtensions", controlExtensions + "Microsoft.FSharp.Control.FSharpEvent`1", events + "Microsoft.FSharp.Control.FSharpEvent`2", events + "Microsoft.FSharp.Control.EventModule", events + "Microsoft.FSharp.Control.ObservableModule", observable + Types.type_, types + "System.Reflection.TypeInfo", types + ] let tryCall (com: ICompiler) (ctx: Context) r t (info: CallInfo) (thisArg: Expr option) (args: Expr list) = match info.DeclaringEntityFullName with @@ -3346,24 +4679,33 @@ let tryCall (com: ICompiler) (ctx: Context) r t (info: CallInfo) (thisArg: Expr // with names like `FSharpType.GetExceptionFields.Static` let isFSharpType = info.CompiledName.StartsWith("FSharpType") let methName = info.CompiledName |> Naming.extensionMethodName - if isFSharpType - then fsharpType com methName r t info args - else fsharpValue com methName r t info args + + if isFSharpType then + fsharpType com methName r t info args + else + fsharpValue com methName r t info args | "Microsoft.FSharp.Reflection.UnionCaseInfo" | "System.Reflection.PropertyInfo" | "System.Reflection.MemberInfo" -> match thisArg, info.CompiledName with | Some c, "get_Tag" -> makeStrConst "tag" |> getExpr r t c |> Some | Some c, "get_PropertyType" -> makeIntConst 1 |> getExpr r t c |> Some - | Some c, "GetFields" -> Helper.LibCall(com, "Reflection", "getUnionCaseFields", t, [c], ?loc=r) |> Some - | Some c, "GetValue" -> Helper.LibCall(com, "Reflection", "getValue", t, c::args, ?loc=r) |> Some + | Some c, "GetFields" -> + Helper.LibCall(com, "Reflection", "getUnionCaseFields", t, [ c ], ?loc = r) + |> Some + | Some c, "GetValue" -> + Helper.LibCall(com, "Reflection", "getValue", t, c :: args, ?loc = r) + |> Some | Some c, "get_Name" -> match c with - | Value(TypeInfo exprType, loc) -> + | Value (TypeInfo exprType, loc) -> getTypeName com ctx loc exprType - |> StringConstant |> makeValue r |> Some + |> StringConstant + |> makeValue r + |> Some | c -> - Helper.LibCall(com, "Reflection", "name", t, [c], ?loc=r) |> Some + Helper.LibCall(com, "Reflection", "name", t, [ c ], ?loc = r) + |> Some | _ -> None | _ -> None @@ -3374,42 +4716,39 @@ let tryBaseConstructor com ctx (ent: Entity) (argTypes: Lazy) genArgs | Types.dictionary -> let args = match argTypes.Value, args with - | ([]|[Number _]), _ -> - [makeArray Any []; makeEqualityComparer com ctx (Seq.head genArgs)] - | [IDictionary], [arg] -> - [arg; makeEqualityComparer com ctx (Seq.head genArgs)] - | [IDictionary; IEqualityComparer], [arg; eqComp] -> - [arg; makeComparerFromEqualityComparer eqComp] - | [IEqualityComparer], [eqComp] - | [Number _; IEqualityComparer], [_; eqComp] -> - [makeArray Any []; makeComparerFromEqualityComparer eqComp] + | ([] + | [ Number _ ]), + _ -> [ makeArray Any []; makeEqualityComparer com ctx (Seq.head genArgs) ] + | [ IDictionary ], [ arg ] -> [ arg; makeEqualityComparer com ctx (Seq.head genArgs) ] + | [ IDictionary; IEqualityComparer ], [ arg; eqComp ] -> [ arg; makeComparerFromEqualityComparer eqComp ] + | [ IEqualityComparer ], [ eqComp ] + | [ Number _; IEqualityComparer ], [ _; eqComp ] -> [ makeArray Any []; makeComparerFromEqualityComparer eqComp ] | _ -> failwith "Unexpected dictionary constructor" + let entityName = Naming.cleanNameAsPyIdentifier "Dictionary" Some(makeImportLib com Any entityName "MutableMap", args) | Types.hashset -> let args = match argTypes.Value, args with - | [], _ -> - [makeArray Any []; makeEqualityComparer com ctx (Seq.head genArgs)] - | [IEnumerable], [arg] -> - [arg; makeEqualityComparer com ctx (Seq.head genArgs)] - | [IEnumerable; IEqualityComparer], [arg; eqComp] -> - [arg; makeComparerFromEqualityComparer eqComp] - | [IEqualityComparer], [eqComp] -> - [makeArray Any []; makeComparerFromEqualityComparer eqComp] + | [], _ -> [ makeArray Any []; makeEqualityComparer com ctx (Seq.head genArgs) ] + | [ IEnumerable ], [ arg ] -> [ arg; makeEqualityComparer com ctx (Seq.head genArgs) ] + | [ IEnumerable; IEqualityComparer ], [ arg; eqComp ] -> [ arg; makeComparerFromEqualityComparer eqComp ] + | [ IEqualityComparer ], [ eqComp ] -> [ makeArray Any []; makeComparerFromEqualityComparer eqComp ] | _ -> failwith "Unexpected hashset constructor" + let entityName = Naming.cleanNameAsPyIdentifier "HashSet" Some(makeImportLib com Any entityName "MutableSet", args) | _ -> None -let tryType = function +let tryType = + function | Fable.Boolean -> Some(Types.bool, parseBool, []) - | Fable.Number(kind, uom) -> Some(getNumberFullName uom kind, parseNum, []) + | Fable.Number (kind, uom) -> Some(getNumberFullName uom kind, parseNum, []) | Fable.String -> Some(Types.string, strings, []) - | Fable.Tuple(genArgs, _) as t -> Some(getTypeFullName false t, tuples, genArgs) - | Fable.Option(genArg, _) -> Some(Types.option, options, [genArg]) - | Fable.Array genArg -> Some(Types.array, arrays, [genArg]) - | Fable.List genArg -> Some(Types.list, lists, [genArg]) + | Fable.Tuple (genArgs, _) as t -> Some(getTypeFullName false t, tuples, genArgs) + | Fable.Option (genArg, _) -> Some(Types.option, options, [ genArg ]) + | Fable.Array genArg -> Some(Types.array, arrays, [ genArg ]) + | Fable.List genArg -> Some(Types.list, lists, [ genArg ]) | Builtin kind -> match kind with | BclGuid -> Some(Types.guid, guids, []) @@ -3421,12 +4760,12 @@ let tryType = function | BclUInt64 -> Some(Types.uint64, parseNum, []) | BclDecimal -> Some(Types.decimal, decimals, []) | BclBigInt -> Some(Types.bigint, bigints, []) - | BclHashSet genArg -> Some(Types.hashset, hashSets, [genArg]) - | BclDictionary(key, value) -> Some(Types.dictionary, dictionaries, [key; value]) - | BclKeyValuePair(key, value) -> Some(Types.keyValuePair, keyValuePairs, [key; value]) - | FSharpMap(key, value) -> Some(Types.fsharpMap, maps, [key; value]) - | FSharpSet genArg -> Some(Types.fsharpSet, sets, [genArg]) - | FSharpResult(genArg1, genArg2) -> Some(Types.result, results, [genArg1; genArg2]) + | BclHashSet genArg -> Some(Types.hashset, hashSets, [ genArg ]) + | BclDictionary (key, value) -> Some(Types.dictionary, dictionaries, [ key; value ]) + | BclKeyValuePair (key, value) -> Some(Types.keyValuePair, keyValuePairs, [ key; value ]) + | FSharpMap (key, value) -> Some(Types.fsharpMap, maps, [ key; value ]) + | FSharpSet genArg -> Some(Types.fsharpSet, sets, [ genArg ]) + | FSharpResult (genArg1, genArg2) -> Some(Types.result, results, [ genArg1; genArg2 ]) | FSharpChoice genArgs -> Some($"{Types.choiceNonGeneric}`{List.length genArgs}", results, genArgs) - | FSharpReference genArg -> Some(Types.reference, references, [genArg]) + | FSharpReference genArg -> Some(Types.reference, references, [ genArg ]) | _ -> None From 3f619ed6e49df02fe264c63b35d2740acfde0e0f Mon Sep 17 00:00:00 2001 From: Dag Brattli Date: Sun, 16 Jan 2022 10:45:05 +0100 Subject: [PATCH 2/4] Check formatting in CI --- .github/workflows/test.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index de80fecc25..95e3c64e81 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,6 +39,12 @@ jobs: with: dotnet-version: '6.0.x' + - name: Setup dotnet tools + run: dotnet tool restore + + - name: Check formatting + run: dotnet fantomas src/Fable.Transforms/Python -check + - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: From 5634f9109ff5a10abe8f49af7055b8856ba95443 Mon Sep 17 00:00:00 2001 From: Dag Brattli Date: Mon, 17 Jan 2022 08:20:59 +0100 Subject: [PATCH 3/4] Fix merge conflicts --- src/Fable.Transforms/Python/Fable2Python.fs | 16 ++- src/Fable.Transforms/Python/PythonPrinter.fs | 143 +++++-------------- src/Fable.Transforms/Python/Replacements.fs | 52 ++++--- 3 files changed, 76 insertions(+), 135 deletions(-) diff --git a/src/Fable.Transforms/Python/Fable2Python.fs b/src/Fable.Transforms/Python/Fable2Python.fs index b02e91d1ca..2a4e3ce989 100644 --- a/src/Fable.Transforms/Python/Fable2Python.fs +++ b/src/Fable.Transforms/Python/Fable2Python.fs @@ -1243,7 +1243,11 @@ module Util = | Fable.WhileLoop _ -> true | Fable.Extended (kind, _) -> match kind with - | Fable.Throw _ | Fable.Return _ | Fable.Break _ | Fable.Debugger | Fable.RegionStart _ -> true + | Fable.Throw _ + | Fable.Return _ + | Fable.Break _ + | Fable.Debugger + | Fable.RegionStart _ -> true | Fable.Curry _ -> false // TODO: If IsJsSatement is false, still try to infer it? See #2414 @@ -3073,8 +3077,12 @@ module Util = | Fable.TryCatch _ -> iife com ctx expr | Fable.Extended (instruction, _) -> match instruction with - | Fable.Curry(e, arity) -> transformCurry com ctx e arity - | Fable.Throw _ | Fable.Return _ | Fable.Break _ | Fable.Debugger | Fable.RegionStart _ -> iife com ctx expr + | Fable.Curry (e, arity) -> transformCurry com ctx e arity + | Fable.Throw _ + | Fable.Return _ + | Fable.Break _ + | Fable.Debugger + | Fable.RegionStart _ -> iife com ctx expr let rec transformAsStatements (com: IPythonCompiler) ctx returnStrategy (expr: Fable.Expr) : Statement list = match expr with @@ -3092,7 +3100,7 @@ module Util = | Fable.Throw (TransformExpr com ctx (e, stmts), _) -> stmts @ [ Statement.raise (e) ] | Fable.Return (TransformExpr com ctx (e, stmts)) -> stmts @ [ Statement.return' (e) ] | Fable.Debugger -> [] - | Fable.Break _ -> [ Statement.break'() ] + | Fable.Break _ -> [ Statement.break' () ] | Fable.RegionStart header -> [ Statement.RegionStart header ] | Fable.TypeCast (e, t) -> diff --git a/src/Fable.Transforms/Python/PythonPrinter.fs b/src/Fable.Transforms/Python/PythonPrinter.fs index 7e5ee1b33b..508f2cb1d7 100644 --- a/src/Fable.Transforms/Python/PythonPrinter.fs +++ b/src/Fable.Transforms/Python/PythonPrinter.fs @@ -5,87 +5,7 @@ open System open Fable open Fable.AST open Fable.AST.Python -<<<<<<< HEAD - -type SourceMapGenerator = - abstract AddMapping: originalLine: int * originalColumn: int * generatedLine: int * generatedColumn: int * ?name: string -> unit - -type Writer = - inherit IDisposable - abstract Write: string -> Async - -type Printer = - abstract Line: int - abstract Column: int - abstract PushIndentation: unit -> unit - abstract PopIndentation: unit -> unit - abstract Print: string * ?loc: SourceLocation -> unit - abstract PrintNewLine: unit -> unit - abstract AddLocation: SourceLocation option -> unit - abstract MakeImportPath: string -> string - -type PrinterImpl (writer: Writer, map: SourceMapGenerator) = - // TODO: We can make this configurable later - let indentSpaces = " " - let builder = Text.StringBuilder() - let mutable indent = 0 - let mutable line = 1 - let mutable column = 0 - - let addLoc (loc: SourceLocation option) = - match loc with - | None -> () - | Some loc -> - map.AddMapping( - originalLine = loc.start.line, - originalColumn = loc.start.column, - generatedLine = line, - generatedColumn = column, - ?name = loc.identifierName - ) - - member _.Flush() : Async = - async { - do! writer.Write(builder.ToString()) - builder.Clear() |> ignore - } - - member _.PrintNewLine() = - builder.AppendLine() |> ignore - line <- line + 1 - column <- 0 - - interface IDisposable with - member _.Dispose() = writer.Dispose() - - interface Printer with - member _.Line = line - member _.Column = column - - member _.PushIndentation() = indent <- indent + 1 - - member _.PopIndentation() = if indent > 0 then indent <- indent - 1 - - member _.AddLocation(loc) = addLoc loc - - member _.Print(str, loc) = - addLoc loc - - if column = 0 then - let indent = String.replicate indent indentSpaces - builder.Append(indent) |> ignore - column <- indent.Length - - builder.Append(str) |> ignore - column <- column + str.Length - - member this.PrintNewLine() = this.PrintNewLine() - - member this.MakeImportPath(path) = path - -======= open Fable.Transforms.Printer ->>>>>>> beyond module PrinterExtensions = type Printer with @@ -817,7 +737,7 @@ module PrinterExtensions = open PrinterExtensions -let run writer (currentLines: CurrentLines) (program: Module): Async = +let run writer (currentLines: CurrentLines) (program: Module) : Async = let printDeclWithExtraLine extraLine (printer: Printer) (decl: Statement) = printer.Print(decl) @@ -831,43 +751,46 @@ let run writer (currentLines: CurrentLines) (program: Module): Async = printer.Print(line) printer.PrintNewLine() - let rec printDeclarations (printer: PrinterImpl) nextHeader (currentLines: CurrentLines) imports restDecls = async { - match currentLines.IsEmpty, imports, restDecls with - | true, [], [] -> do! printer.Flush() - | _ -> - let nextDelimiter, currentLines = - currentLines.PrintUntilDelimiter(printLine printer) - - do! printer.Flush() + let rec printDeclarations (printer: PrinterImpl) nextHeader (currentLines: CurrentLines) imports restDecls = + async { + match currentLines.IsEmpty, imports, restDecls with + | true, [], [] -> do! printer.Flush() + | _ -> + let nextDelimiter, currentLines = + currentLines.PrintUntilDelimiter(printLine printer) - match imports with - | [] -> () - | imports -> - for decl in imports do - printDeclWithExtraLine false printer decl - (printer :> Printer).PrintNewLine() do! printer.Flush() - nextHeader |> Option.iter (fun header -> printLine printer $"#region {header}") + match imports with + | [] -> () + | imports -> + for decl in imports do + printDeclWithExtraLine false printer decl - let rec splitDecls decls restDecls = - match restDecls with - | [] -> None, List.rev decls, [] - | RegionStart header::restDecls -> Some header, List.rev decls, restDecls - | decl::restDecls -> splitDecls (decl::decls) restDecls + (printer :> Printer).PrintNewLine() + do! printer.Flush() - let nextHeader, decls, restDecls = splitDecls [] restDecls + nextHeader + |> Option.iter (fun header -> printLine printer $"#region {header}") - for decl in decls do - printDeclWithExtraLine true printer decl - // TODO: Only flush every XXX lines? - do! printer.Flush() + let rec splitDecls decls restDecls = + match restDecls with + | [] -> None, List.rev decls, [] + | RegionStart header :: restDecls -> Some header, List.rev decls, restDecls + | decl :: restDecls -> splitDecls (decl :: decls) restDecls - // Print the next delimiter if there's one - nextDelimiter |> Option.iter (printLine printer) + let nextHeader, decls, restDecls = splitDecls [] restDecls - return! printDeclarations printer nextHeader currentLines [] restDecls - } + for decl in decls do + printDeclWithExtraLine true printer decl + // TODO: Only flush every XXX lines? + do! printer.Flush() + + // Print the next delimiter if there's one + nextDelimiter |> Option.iter (printLine printer) + + return! printDeclarations printer nextHeader currentLines [] restDecls + } async { use printer = new PrinterImpl(writer) diff --git a/src/Fable.Transforms/Python/Replacements.fs b/src/Fable.Transforms/Python/Replacements.fs index fe87f9b19e..5bc9fd139e 100644 --- a/src/Fable.Transforms/Python/Replacements.fs +++ b/src/Fable.Transforms/Python/Replacements.fs @@ -838,25 +838,31 @@ let findInScope (ctx: Context) identName = let rec findInScopeInner scope identName = match scope with | [] -> None - | (ident2: Ident, expr: Expr option)::prevScope -> + | (ident2: Ident, expr: Expr option) :: prevScope -> if identName = ident2.Name then match expr with - | Some(MaybeCasted(IdentExpr ident)) when not ident.IsMutable -> findInScopeInner prevScope ident.Name + | Some (MaybeCasted (IdentExpr ident)) when not ident.IsMutable -> findInScopeInner prevScope ident.Name | expr -> expr - else findInScopeInner prevScope identName - let scope1 = ctx.Scope |> List.map (fun (_,i,e) -> i,e) - let scope2 = ctx.ScopeInlineArgs |> List.map (fun (i,e) -> i, Some e) + else + findInScopeInner prevScope identName + + let scope1 = ctx.Scope |> List.map (fun (_, i, e) -> i, e) + + let scope2 = + ctx.ScopeInlineArgs + |> List.map (fun (i, e) -> i, Some e) + findInScopeInner (scope1 @ scope2) identName let (|RequireStringConst|_|) com (ctx: Context) r e = (match e with | StringConst s -> Some s - | MaybeCasted(IdentExpr ident) -> - match findInScope ctx ident.Name with - | Some(StringConst s) -> Some s - | _ -> None + | MaybeCasted (IdentExpr ident) -> + match findInScope ctx ident.Name with + | Some (StringConst s) -> Some s + | _ -> None | _ -> None) - |> Option.orElseWith(fun () -> + |> Option.orElseWith (fun () -> addError com ctx.InlinePath r "Expecting string literal" Some "") @@ -1450,9 +1456,11 @@ let fableCoreLib (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Exp | _, ".ctor" -> typedObjExpr t [] |> Some | _, "region" -> match args with - | [RequireStringConst com ctx r header] -> Extended(RegionStart header, r) |> Some + | [ RequireStringConst com ctx r header ] -> Extended(RegionStart header, r) |> Some | _ -> None - | _, ("pyNative"|"nativeOnly") -> + | _, + ("pyNative" + | "nativeOnly") -> // TODO: Fail at compile time? addWarning com ctx.InlinePath r $"{i.CompiledName} is being compiled without replacement, this will fail at runtime." @@ -1480,10 +1488,10 @@ let fableCoreLib (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Exp ("nameofLambda" | "namesofLambda" as meth) -> match args with - | [Lambda(_, (Namesof com ctx names), _)] -> Some names - | [MaybeCasted(IdentExpr ident)] -> + | [ Lambda (_, (Namesof com ctx names), _) ] -> Some names + | [ MaybeCasted (IdentExpr ident) ] -> match findInScope ctx ident.Name with - | Some(Lambda(_, (Namesof com ctx names), _)) -> Some names + | Some (Lambda (_, (Namesof com ctx names), _)) -> Some names | _ -> None | _ -> None |> Option.defaultWith (fun () -> @@ -1531,8 +1539,10 @@ let fableCoreLib (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Exp | _ -> None match args with - | [MaybeCasted(IdentExpr ident)] -> findInScope ctx ident.Name |> Option.bind inferCasename - | [e] -> inferCasename e + | [ MaybeCasted (IdentExpr ident) ] -> + findInScope ctx ident.Name + |> Option.bind inferCasename + | [ e ] -> inferCasename e | _ -> None |> Option.orElseWith (fun () -> "Cannot infer case name of expression" @@ -1622,10 +1632,10 @@ let fableCoreLib (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Exp let (|RequireStringConst|_|) e = (match e with | StringConst s -> Some s - | MaybeCasted(IdentExpr ident) -> - match findInScope ctx ident.Name with - | Some(StringConst s) -> Some s - | _ -> None + | MaybeCasted (IdentExpr ident) -> + match findInScope ctx ident.Name with + | Some (StringConst s) -> Some s + | _ -> None | _ -> None) |> Option.orElseWith (fun () -> addError com ctx.InlinePath r "Import only accepts string literals" From 53c4615f2ea19dd8c62137713a2eed629fceda30 Mon Sep 17 00:00:00 2001 From: Dag Brattli Date: Mon, 17 Jan 2022 17:23:37 +0100 Subject: [PATCH 4/4] Remove fantomas defaults --- .editorconfig | 5 - src/Fable.Transforms/Python/Fable2Python.fs | 331 ++++++----- src/Fable.Transforms/Python/Prelude.fs | 118 ++-- src/Fable.Transforms/Python/Python.fs | 36 +- src/Fable.Transforms/Python/PythonPrinter.fs | 34 +- src/Fable.Transforms/Python/Replacements.fs | 544 ++++++++++--------- 6 files changed, 556 insertions(+), 512 deletions(-) diff --git a/.editorconfig b/.editorconfig index 7accf0334e..0c4f918b4a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,9 +10,4 @@ indent_size = 2 # Fantomas (see https://github.com/fsprojects/fantomas/blob/master/docs/Documentation.md) [*.fs] -indent_size=4 max_line_length=140 -fsharp_space_before_uppercase_invocation=false -fsharp_space_before_member=false -fsharp_space_around_delimiter=true -fsharp_multiline_block_brackets_on_same_column=false \ No newline at end of file diff --git a/src/Fable.Transforms/Python/Fable2Python.fs b/src/Fable.Transforms/Python/Fable2Python.fs index 2a4e3ce989..1afcd4bb35 100644 --- a/src/Fable.Transforms/Python/Fable2Python.fs +++ b/src/Fable.Transforms/Python/Fable2Python.fs @@ -107,7 +107,8 @@ module Lib = let libConsCall (com: IPythonCompiler) ctx r moduleName memberName args = Expression.call (com.TransformImport(ctx, memberName, getLibPath com moduleName), args, ?loc = r) - let libValue (com: IPythonCompiler) ctx moduleName memberName = com.TransformImport(ctx, memberName, getLibPath com moduleName) + let libValue (com: IPythonCompiler) ctx moduleName memberName = + com.TransformImport(ctx, memberName, getLibPath com moduleName) let tryPyConstructor (com: IPythonCompiler) ctx ent = match PY.Replacements.tryPyConstructor com ent with @@ -121,7 +122,8 @@ module Lib = module Reflection = open Lib - let private libReflectionCall (com: IPythonCompiler) ctx r memberName args = libCall com ctx r "reflection" (memberName + "_type") args + let private libReflectionCall (com: IPythonCompiler) ctx r memberName args = + libCall com ctx r "reflection" (memberName + "_type") args let private transformRecordReflectionInfo com ctx r (ent: Fable.Entity) generics = // TODO: Refactor these three bindings to reuse in transformUnionReflectionInfo @@ -139,19 +141,24 @@ module Reflection = let fields, stmts = ent.FSharpFields |> Seq.map (fun fi -> - let typeInfo, stmts = - transformTypeInfo com ctx r genMap fi.FieldType + let typeInfo, stmts = transformTypeInfo com ctx r genMap fi.FieldType - (Expression.list ([ Expression.constant (fi.Name); typeInfo ])), stmts) + (Expression.list ( + [ Expression.constant (fi.Name) + typeInfo ] + )), + stmts) |> Seq.toList |> Helpers.unzipArgs - let fields = - Expression.lambda (Arguments.arguments [], Expression.list (fields)) + let fields = Expression.lambda (Arguments.arguments [], Expression.list (fields)) let py, stmts' = pyConstructor com ctx ent - [ fullnameExpr; Expression.list (generics); py; fields ] + [ fullnameExpr + Expression.list (generics) + py + fields ] |> libReflectionCall com ctx None "record", stmts @ stmts' @@ -174,26 +181,30 @@ module Reflection = |> List.map (fun fi -> Expression.list ( [ fi.Name |> Expression.constant - let expr, stmts = - transformTypeInfo com ctx r genMap fi.FieldType + let expr, stmts = transformTypeInfo com ctx r genMap fi.FieldType expr ] )) |> Expression.list) |> Seq.toList - let cases = - Expression.lambda (Arguments.arguments [], Expression.list (cases)) + let cases = Expression.lambda (Arguments.arguments [], Expression.list (cases)) let py, stmts = pyConstructor com ctx ent - [ fullnameExpr; Expression.list (generics); py; cases ] + [ fullnameExpr + Expression.list (generics) + py + cases ] |> libReflectionCall com ctx None "union", stmts let transformTypeInfo (com: IPythonCompiler) ctx r (genMap: Map) t : Expression * Statement list = - let primitiveTypeInfo name = libValue com ctx "Reflection" (name + "_type") - let numberInfo kind = getNumberKindName kind |> primitiveTypeInfo + let primitiveTypeInfo name = + libValue com ctx "Reflection" (name + "_type") + + let numberInfo kind = + getNumberKindName kind |> primitiveTypeInfo let nonGenericTypeInfo fullname = [ Expression.constant (fullname) ] @@ -255,12 +266,17 @@ module Reflection = | Some v -> System.Convert.ToDouble v | None -> 0. - Expression.list ([ Expression.constant (name); Expression.constant (value) ]) + Expression.list ( + [ Expression.constant (name) + Expression.constant (value) ] + ) |> Some) |> Seq.toList |> Expression.list - [ Expression.constant (entRef.FullName); numberInfo numberKind; cases ] + [ Expression.constant (entRef.FullName) + numberInfo numberKind + cases ] |> libReflectionCall com ctx None "enum", [] | Fable.Number (kind, _) -> numberInfo kind, [] @@ -313,8 +329,7 @@ module Reflection = let ok', stmts = transformTypeInfo com ctx r genMap ok let err', stmts' = transformTypeInfo com ctx r genMap err - let expr, stmts'' = - transformUnionReflectionInfo com ctx r ent [ ok'; err' ] + let expr, stmts'' = transformUnionReflectionInfo com ctx r ent [ ok'; err' ] expr, stmts @ stmts' @ stmts'' | Replacements.FSharpChoice gen -> @@ -324,8 +339,7 @@ module Reflection = List.map (transformTypeInfo com ctx r genMap) gen |> Helpers.unzipArgs - let expr, stmts' = - gen |> transformUnionReflectionInfo com ctx r ent + let expr, stmts' = gen |> transformUnionReflectionInfo com ctx r ent expr, stmts @ stmts' | Replacements.FSharpReference gen -> @@ -354,8 +368,7 @@ module Reflection = let reflectionMethodExpr = FSharp2Fable.Util.entityRefWithSuffix com ent Naming.reflectionSuffix - let callee, stmts' = - com.TransformAsExpr(ctx, reflectionMethodExpr) + let callee, stmts' = com.TransformAsExpr(ctx, reflectionMethodExpr) Expression.call (callee, generics), stmts @ stmts' @@ -559,7 +572,8 @@ module Helpers = // printfn $"ProjectFile: {com.ProjectFile}" let commonPrefix = - Path.getCommonBaseDir [ modulePathname; com.ProjectFile ] + Path.getCommonBaseDir [ modulePathname + com.ProjectFile ] let relativePath = // We know all modules will be placed somewhere in outDir or in a subdir below @@ -580,7 +594,8 @@ module Helpers = // Relative path from current file (up) to project dir let fileRelative = let commonPrefix = - Path.getCommonBaseDir [ com.CurrentFile; com.ProjectFile ] + Path.getCommonBaseDir [ com.CurrentFile + com.ProjectFile ] Path .GetDirectoryName(com.CurrentFile.Replace(commonPrefix, String.Empty)) @@ -616,7 +631,8 @@ module Helpers = /// let rewriteFablePathImport (com: IPythonCompiler) (modulePath: string) = let commonPrefix = - Path.getCommonBaseDir [ com.ProjectFile; com.CurrentFile ] + Path.getCommonBaseDir [ com.ProjectFile + com.CurrentFile ] let normalizedPath = normalizeModulePath com modulePath let projDir = Path.GetDirectoryName(com.ProjectFile) @@ -749,11 +765,11 @@ module Annotation = let generic = Expression.name "Generic" [ Expression.subscript (generic, Expression.tuple genParams) ] - let private libReflectionCall (com: IPythonCompiler) ctx r memberName args = libCall com ctx r "reflection" (memberName + "_type") args + let private libReflectionCall (com: IPythonCompiler) ctx r memberName args = + libCall com ctx r "reflection" (memberName + "_type") args let fableModuleAnnotation (com: IPythonCompiler) ctx moduleName memberName args = - let expr = - com.TransformImport(ctx, memberName, getLibPath com moduleName) + let expr = com.TransformImport(ctx, memberName, getLibPath com moduleName) match args with | [] -> expr @@ -781,8 +797,7 @@ module Annotation = | _, args -> Expression.subscript (expr, Expression.tuple (args)) let fableModuleTypeHint com ctx moduleName memberName genArgs repeatedGenerics = - let resolved, stmts = - resolveGenerics com ctx genArgs repeatedGenerics + let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics fableModuleAnnotation com ctx moduleName memberName resolved, stmts @@ -808,8 +823,7 @@ module Annotation = stdlibModuleAnnotation com ctx "__future__" "annotations" [] |> ignore - let typeParamInst = - makeGenTypeParamInst com ctx genArgs repeatedGenerics + let typeParamInst = makeGenTypeParamInst com ctx genArgs repeatedGenerics let name = Expression.name id @@ -864,7 +878,8 @@ module Annotation = | Float32 | Float64 -> "float" - let numberInfo kind = Expression.name (getNumberKindName kind) + let numberInfo kind = + Expression.name (getNumberKindName kind) // printfn "typeAnnotation: %A" t match t with @@ -910,12 +925,17 @@ module Annotation = | Some v -> System.Convert.ToDouble v | None -> 0. - Expression.list ([ Expression.constant (name); Expression.constant (value) ]) + Expression.list ( + [ Expression.constant (name) + Expression.constant (value) ] + ) |> Some) |> Seq.toList |> Expression.list - [ Expression.constant (entRef.FullName); numberInfo numberKind; cases ] + [ Expression.constant (entRef.FullName) + numberInfo numberKind + cases ] |> libReflectionCall com ctx None "enum", [] | Fable.Number (kind, _) -> numberInfo kind, [] @@ -945,8 +965,7 @@ module Annotation = | _ -> stdlibModuleTypeHint com ctx "typing" "Any" [] let makeImportTypeId (com: IPythonCompiler) ctx moduleName typeName = - let expr = - com.GetImportExpr(ctx, getLibPath com moduleName, typeName) + let expr = com.GetImportExpr(ctx, getLibPath com moduleName, typeName) match expr with | Expression.Name ({ Id = Identifier id }) -> id @@ -960,8 +979,7 @@ module Annotation = // printfn "DeclaredType: %A" entRef.FullName match entRef.FullName, genArgs with | Types.result, _ -> - let resolved, stmts = - resolveGenerics com ctx genArgs repeatedGenerics + let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics fableModuleAnnotation com ctx "choice" "FSharpResult_2" resolved, stmts | Replacements.BuiltinEntity kind -> @@ -987,61 +1005,50 @@ module Annotation = makeUnionTypeAnnotation com ctx genArgs *) | Types.fsharpAsyncGeneric, _ -> - let resolved, stmts = - resolveGenerics com ctx genArgs repeatedGenerics + let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics fableModuleAnnotation com ctx "async_builder" "Async" resolved, stmts | Types.taskGeneric, _ -> stdlibModuleTypeHint com ctx "typing" "Awaitable" genArgs | Types.icomparable, _ -> - let resolved, stmts = - stdlibModuleTypeHint com ctx "typing" "Any" [] + let resolved, stmts = stdlibModuleTypeHint com ctx "typing" "Any" [] fableModuleAnnotation com ctx "util" "IComparable" [ resolved ], stmts | Types.comparer, _ -> - let resolved, stmts = - resolveGenerics com ctx genArgs repeatedGenerics + let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics fableModuleAnnotation com ctx "util" "IComparer" resolved, stmts | Types.equalityComparer, _ -> - let resolved, stmts = - stdlibModuleTypeHint com ctx "typing" "Any" [] + let resolved, stmts = stdlibModuleTypeHint com ctx "typing" "Any" [] fableModuleAnnotation com ctx "util" "IEqualityComparer" [ resolved ], stmts | Types.ienumerator, _ -> - let resolved, stmts = - stdlibModuleTypeHint com ctx "typing" "Any" [] + let resolved, stmts = stdlibModuleTypeHint com ctx "typing" "Any" [] fableModuleAnnotation com ctx "util" "IEnumerator" [ resolved ], stmts | Types.ienumeratorGeneric, _ -> - let resolved, stmts = - resolveGenerics com ctx genArgs repeatedGenerics + let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics fableModuleAnnotation com ctx "util" "IEnumerator" resolved, stmts | Types.ienumerable, _ -> - let resolved, stmts = - stdlibModuleTypeHint com ctx "typing" "Any" [] + let resolved, stmts = stdlibModuleTypeHint com ctx "typing" "Any" [] fableModuleAnnotation com ctx "util" "IEnumerable" [ resolved ], stmts | Types.ienumerableGeneric, _ -> - let resolved, stmts = - resolveGenerics com ctx genArgs repeatedGenerics + let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics fableModuleAnnotation com ctx "util" "IEnumerable" resolved, stmts | Types.icollection, _ | Types.icollectionGeneric, _ -> - let resolved, stmts = - resolveGenerics com ctx genArgs repeatedGenerics + let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics fableModuleAnnotation com ctx "util" "ICollection" resolved, stmts | Types.idisposable, _ -> libValue com ctx "util" "IDisposable", [] | Types.iobserverGeneric, _ -> - let resolved, stmts = - resolveGenerics com ctx genArgs repeatedGenerics + let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics fableModuleAnnotation com ctx "observable" "IObserver" resolved, stmts | Types.iobservableGeneric, _ -> - let resolved, stmts = - resolveGenerics com ctx genArgs repeatedGenerics + let resolved, stmts = resolveGenerics com ctx genArgs repeatedGenerics fableModuleAnnotation com ctx "observable" "IObservable" resolved, stmts | Types.cancellationToken, _ -> libValue com ctx "async_builder" "CancellationToken", [] @@ -1054,8 +1061,7 @@ module Annotation = match entRef.SourcePath with | Some path when path <> com.CurrentFile -> // this is just to import the interface - let importPath = - Path.getRelativeFileOrDirPath false com.CurrentFile false path + let importPath = Path.getRelativeFileOrDirPath false com.CurrentFile false path com.GetImportExpr(ctx, importPath, name) |> ignore | _ -> () @@ -1102,8 +1108,7 @@ module Annotation = |> makeImportTypeAnnotation com ctx genArgs "Fable.Core" *) | Replacements.FSharpResult (ok, err) -> - let resolved, stmts = - resolveGenerics com ctx [ ok; err ] repeatedGenerics + let resolved, stmts = resolveGenerics com ctx [ ok; err ] repeatedGenerics fableModuleAnnotation com ctx "choice" "FSharpResult_2" resolved, stmts | _ -> stdlibModuleTypeHint com ctx "typing" "Any" [] @@ -1111,24 +1116,19 @@ module Annotation = let transformFunctionWithAnnotations (com: IPythonCompiler) ctx name (args: Fable.Ident list) (body: Fable.Expr) = let argTypes = args |> List.map (fun id -> id.Type) - let genTypeParams = - Util.getGenericTypeParams (argTypes @ [ body.Type ]) + let genTypeParams = Util.getGenericTypeParams (argTypes @ [ body.Type ]) - let newTypeParams = - Set.difference genTypeParams ctx.ScopedTypeParams + let newTypeParams = Set.difference genTypeParams ctx.ScopedTypeParams let ctx = { ctx with ScopedTypeParams = Set.union ctx.ScopedTypeParams newTypeParams } // In Python a generic type arg must appear both in the argument and the return type (cannot appear only once) - let repeatedGenerics = - Util.getRepeatedGenericTypeParams (argTypes @ [ body.Type ]) + let repeatedGenerics = Util.getRepeatedGenericTypeParams (argTypes @ [ body.Type ]) - let args', body' = - com.TransformFunction(ctx, name, args, body, repeatedGenerics) + let args', body' = com.TransformFunction(ctx, name, args, body, repeatedGenerics) - let returnType, stmts = - typeAnnotation com ctx (Some repeatedGenerics) body.Type + let returnType, stmts = typeAnnotation com ctx (Some repeatedGenerics) body.Type args', stmts @ body', returnType @@ -1191,15 +1191,14 @@ module Util = name - type NamedTailCallOpportunity (com: IPythonCompiler, ctx, name, args: Fable.Ident list) = + type NamedTailCallOpportunity(com: IPythonCompiler, ctx, name, args: Fable.Ident list) = // Capture the current argument values to prevent delayed references from getting corrupted, // for that we use block-scoped ES2015 variable declarations. See #681, #1859 // TODO: Local unique ident names let argIds = discardUnitArg args |> List.map (fun arg -> - let name = - getUniqueNameInDeclarationScope ctx (arg.Name + "_mut") + let name = getUniqueNameInDeclarationScope ctx (arg.Name + "_mut") let ta, _ = typeAnnotation com ctx None arg.Type Arg.arg (name, ta)) @@ -1390,7 +1389,8 @@ module Util = |> List.unzip |> Expression.dict - let assign range left right = Expression.namedExpr (left, right, ?loc = range) + let assign range left right = + Expression.namedExpr (left, right, ?loc = range) /// Immediately Invoked Function Expression let iife (com: IPythonCompiler) ctx (expr: Fable.Expr) = @@ -1455,7 +1455,8 @@ module Util = | [], [ Statement.Pass ] -> [] // Remove empty `__init__` with no arguments | _ -> [ Statement.functionDef (name, args_, body = body, returns = Expression.none) ] - let callFunction r funcExpr (args: Expression list) (kw: Keyword list) = Expression.call (funcExpr, args, kw = kw, ?loc = r) + let callFunction r funcExpr (args: Expression list) (kw: Keyword list) = + Expression.call (funcExpr, args, kw = kw, ?loc = r) let callFunctionWithThisContext com ctx r funcExpr (args: Expression list) = let args = thisExpr :: args @@ -1556,8 +1557,7 @@ module Util = let getUnionExprTag (com: IPythonCompiler) ctx r (fableExpr: Fable.Expr) = let expr, stmts = com.TransformAsExpr(ctx, fableExpr) - let expr, stmts' = - getExpr com ctx r expr (Expression.constant ("tag")) + let expr, stmts' = getExpr com ctx r expr (Expression.constant ("tag")) expr, stmts @ stmts' @@ -1631,8 +1631,7 @@ module Util = |> Option.map (fun name -> com.GetIdentifier(ctx, name)) |> Option.defaultValue (Helpers.getUniqueIdentifier "expr") - let func = - makeFunction name (args, body, decoratorList, returnType) + let func = makeFunction name (args, body, decoratorList, returnType) Expression.name (name), [ func ] @@ -1651,8 +1650,7 @@ module Util = let tempVars = if found then - let tempVarName = - getUniqueNameInDeclarationScope ctx (argId + "_tmp") + let tempVarName = getUniqueNameInDeclarationScope ctx (argId + "_tmp") Map.add argId tempVarName tempVars else @@ -1670,8 +1668,7 @@ module Util = let tempVars = checkCrossRefs Map.empty args zippedArgs - let tempVarReplacements = - tempVars |> Map.map (fun _ v -> makeIdentExpr v) + let tempVarReplacements = tempVars |> Map.map (fun _ v -> makeIdentExpr v) [ // First declare temp variables @@ -1822,8 +1819,7 @@ module Util = | Fable.IdentExpr id -> com.GetIdentifierAsExpr(ctx, id.Name), [] | _ -> transformAsExpr com ctx baseRef - let expr, keywords, stmts' = - transformCallArgs com ctx None (CallInfo info) + let expr, keywords, stmts' = transformCallArgs com ctx None (CallInfo info) Some(baseExpr, (expr, keywords, stmts @ stmts')) | Some (Fable.Value _), Some baseType -> @@ -1894,8 +1890,7 @@ module Util = let decorators = [ Expression.name $"{memb.Name}.setter" ] [ makeMethod memb.Name false memb.Args memb.Body decorators ] elif info.IsEnumerator then - let method = - makeMethod memb.Name info.HasSpread memb.Args memb.Body [] + let method = makeMethod memb.Name info.HasSpread memb.Args memb.Body [] let iterator = let body = enumerator2iterator com ctx @@ -1925,8 +1920,7 @@ module Util = let name = Helpers.getUniqueIdentifier "ObjectExpr" - let stmt = - Statement.classDef (name, body = classBody, bases = interfaces @ []) + let stmt = Statement.classDef (name, body = classBody, bases = interfaces @ []) Expression.call (Expression.name name), [ stmt ] @@ -2134,8 +2128,7 @@ module Util = |> Option.toList |> Helpers.unzipArgs - let exprs, _, stmts' = - transformCallArgs com ctx range (CallInfo info) + let exprs, _, stmts' = transformCallArgs com ctx range (CallInfo info) if macro.StartsWith("functools") then com.GetImportExpr(ctx, "functools") |> ignore @@ -2147,8 +2140,7 @@ module Util = // printfn "transformCall: %A" (callee, callInfo) let callee', stmts = com.TransformAsExpr(ctx, callee) - let args, kw, stmts' = - transformCallArgs com ctx range (CallInfo callInfo) + let args, kw, stmts' = transformCallArgs com ctx range (CallInfo callInfo) match callee, callInfo.ThisArg with | Fable.Get (expr, Fable.FieldGet(fieldName = "Dispose"), _, _), _ -> @@ -2158,8 +2150,7 @@ module Util = // printfn "Type: %A" expr.Type let right, stmts = com.TransformAsExpr(ctx, callInfo.Args.Head) - let arg, stmts' = - com.TransformAsExpr(ctx, callInfo.Args.Tail.Head) + let arg, stmts' = com.TransformAsExpr(ctx, callInfo.Args.Tail.Head) let value, stmts'' = com.TransformAsExpr(ctx, expr) @@ -2214,8 +2205,7 @@ module Util = -> optimizeTailCall com ctx range tc args | _ -> - let expr, stmts = - transformCurriedApply com ctx range callee args + let expr, stmts = transformCurriedApply com ctx range callee args stmts @ (expr |> resolveExpr ctx t returnStrategy) @@ -2391,11 +2381,9 @@ module Util = | Fable.UnionField (_, fieldIndex) -> let expr, stmts = com.TransformAsExpr(ctx, fableExpr) - let expr, stmts' = - getExpr com ctx None expr (Expression.constant ("fields")) + let expr, stmts' = getExpr com ctx None expr (Expression.constant ("fields")) - let expr, stmts'' = - getExpr com ctx range expr (ofInt fieldIndex) + let expr, stmts'' = getExpr com ctx range expr (ofInt fieldIndex) expr, stmts @ stmts' @ stmts'' @@ -2438,15 +2426,13 @@ module Util = let transformBindingAsStatements (com: IPythonCompiler) ctx (var: Fable.Ident) (value: Fable.Expr) = // printfn "transformBindingAsStatements: %A" (var, value) if isPyStatement ctx false value then - let varName, varExpr = - Expression.name (var.Name), identAsExpr com ctx var + let varName, varExpr = Expression.name (var.Name), identAsExpr com ctx var ctx.BoundVars.Bind(var.Name) let ta, stmts = typeAnnotation com ctx None var.Type let decl = Statement.assign (varName, ta) - let body = - com.TransformAsStatements(ctx, Some(Assign varExpr), value) + let body = com.TransformAsStatements(ctx, Some(Assign varExpr), value) stmts @ [ decl ] @ body else @@ -2503,8 +2489,7 @@ module Util = let expr, stmts = com.TransformAsExpr(ctx, e) (stmts, Some expr)) - let caseBody = - com.TransformAsStatements(ctx, returnStrategy, expr) + let caseBody = com.TransformAsStatements(ctx, returnStrategy, expr) let caseBody = match returnStrategy with @@ -2517,8 +2502,7 @@ module Util = let cases = match defaultCase with | Some expr -> - let defaultCaseBody = - com.TransformAsStatements(ctx, returnStrategy, expr) + let defaultCaseBody = com.TransformAsStatements(ctx, returnStrategy, expr) cases @ [ (defaultCaseBody, None) ] | None -> cases @@ -2532,8 +2516,7 @@ module Util = match test with | None -> body | Some test -> - let expr = - Expression.compare (left = value, ops = [ Eq ], comparators = [ test ]) + let expr = Expression.compare (left = value, ops = [ Eq ], comparators = [ test ]) let test = match fallThrough with @@ -2582,8 +2565,7 @@ module Util = let getDecisionTargetAndBindValues (com: IPythonCompiler) (ctx: Context) targetIndex boundValues = let idents, target = getDecisionTarget ctx targetIndex - let identsAndValues = - matchTargetIdentAndValues idents boundValues + let identsAndValues = matchTargetIdentAndValues idents boundValues if not com.Options.DebugMode then let bindings, replacements = @@ -2674,8 +2656,7 @@ module Util = function | Fable.Operation (Fable.Binary (BinaryEqualStrict, expr, right), _, _) -> Some(expr, right) | Fable.Test (expr, Fable.UnionCaseTest tag, _) -> - let evalExpr = - Fable.Get(expr, Fable.UnionTag, Fable.Number(Int32, None), None) + let evalExpr = Fable.Get(expr, Fable.UnionTag, Fable.Number(Int32, None), None) let right = makeIntConst tag Some(evalExpr, right) @@ -2812,8 +2793,7 @@ module Util = multiVarDecl @ switch1 @ switch2 | None -> - let decisionTree = - com.TransformAsStatements(ctx, Some targetAssign, treeExpr) + let decisionTree = com.TransformAsStatements(ctx, Some targetAssign, treeExpr) multiVarDecl @ decisionTree @ switch2 @@ -2845,8 +2825,7 @@ module Util = |> List.map (fun (caseExpr, targetIndex, boundValues) -> [ caseExpr ], Fable.DecisionTreeSuccess(targetIndex, boundValues, t)) - let defaultCase = - Fable.DecisionTreeSuccess(defaultIndex, defaultBoundValues, t) + let defaultCase = Fable.DecisionTreeSuccess(defaultIndex, defaultBoundValues, t) transformSwitch com ctx true returnStrategy evalExpr cases (Some defaultCase) | None -> com.TransformAsStatements(ctx, returnStrategy, treeExpr) @@ -2870,13 +2849,11 @@ module Util = | Some (evalExpr, cases, (defaultIndex, defaultBoundValues)) -> let t = treeExpr.Type - let cases = - groupSwitchCases t cases (defaultIndex, defaultBoundValues) + let cases = groupSwitchCases t cases (defaultIndex, defaultBoundValues) let ctx = { ctx with DecisionTargets = targets } - let defaultCase = - Fable.DecisionTreeSuccess(defaultIndex, defaultBoundValues, t) + let defaultCase = Fable.DecisionTreeSuccess(defaultIndex, defaultBoundValues, t) transformSwitch com ctx true returnStrategy evalExpr cases (Some defaultCase) | None -> transformDecisionTreeWithTwoSwitches com ctx returnStrategy targets treeExpr @@ -3027,8 +3004,7 @@ module Util = | Fable.DecisionTreeSuccess (idx, boundValues, _) -> transformDecisionTreeSuccessAsExpr com ctx idx boundValues | Fable.Set (expr, kind, typ, value, range) -> - let expr', stmts = - transformSet com ctx range expr typ value kind + let expr', stmts = transformSet com ctx range expr typ value kind //printfn "Fable.Set: %A" expr match expr' with | Expression.NamedExpr ({ Target = target; Value = _; Loc = _ }) -> @@ -3056,8 +3032,7 @@ module Util = let expr, stmts' = com.TransformAsExpr(ctx, body) - let expr, stmts'' = - transformSequenceExpr' com ctx (values @ [ expr ]) [] + let expr, stmts'' = transformSequenceExpr' com ctx (values @ [ expr ]) [] expr, stmts @ stmts' @ stmts'' else @@ -3193,8 +3168,7 @@ module Util = _) when valueName = disposeName -> let id = Identifier valueName - let body = - com.TransformAsStatements(ctx, Some ResourceManager, body) + let body = com.TransformAsStatements(ctx, Some ResourceManager, body) let value, stmts = com.TransformAsExpr(ctx, value) let items = [ WithItem.withItem (value, Expression.name id) ] @@ -3212,8 +3186,7 @@ module Util = List.append bindings (transformAsStatements com ctx returnStrategy body) | Fable.Set (expr, kind, typ, value, range) -> - let expr', stmts = - transformSet com ctx range expr typ value kind + let expr', stmts = transformSet com ctx range expr typ value kind // printfn "Fable.Set: %A" (expr', value) match expr' with | Expression.NamedExpr ({ Target = target @@ -3287,13 +3260,11 @@ module Util = | Fable.ForLoop (var, TransformExpr com ctx (start, stmts), TransformExpr com ctx (limit, stmts'), body, isUp, range) -> let limit, step = if isUp then - let limit = - Expression.binOp (limit, Add, Expression.constant (1)) // Python `range` has exclusive end. + let limit = Expression.binOp (limit, Add, Expression.constant (1)) // Python `range` has exclusive end. limit, 1 else - let limit = - Expression.binOp (limit, Sub, Expression.constant (1)) // Python `range` has exclusive end. + let limit = Expression.binOp (limit, Sub, Expression.constant (1)) // Python `range` has exclusive end. limit, -1 @@ -3372,8 +3343,7 @@ module Util = |> List.map (fun (_id, { Arg = Identifier tcArg }) -> let id = com.GetIdentifier(ctx, tcArg) - let ta, _ = - typeAnnotation com ctx (Some repeatedGenerics) _id.Type + let ta, _ = typeAnnotation com ctx (Some repeatedGenerics) _id.Type Arg.arg (id, annotation = ta)) @@ -3404,8 +3374,7 @@ module Util = let args' = args |> List.map (fun id -> - let ta, _ = - typeAnnotation com ctx (Some repeatedGenerics) id.Type + let ta, _ = typeAnnotation com ctx (Some repeatedGenerics) id.Type Arg.arg (ident com ctx id, annotation = ta)) @@ -3457,8 +3426,7 @@ module Util = let typ = field.FieldType - let id: Fable.Ident = - { makeTypedIdent typ name with IsMutable = field.IsMutable } + let id: Fable.Ident = { makeTypedIdent typ name with IsMutable = field.IsMutable } id) |> Seq.toArray @@ -3489,14 +3457,15 @@ module Util = // printfn "declareClassType: %A" consBody let generics = makeEntityTypeParamDecl com ctx ent - let classCons = - makeClassConstructor consArgs isOptional consBody + let classCons = makeClassConstructor consArgs isOptional consBody let classFields = slotMembers // TODO: annotations let classMembers = classCons @ classMembers //printfn "ClassMembers: %A" classMembers let classBody = - let body = [ yield! classFields; yield! classMembers ] + let body = + [ yield! classFields + yield! classMembers ] match body with | [] -> [ Pass ] @@ -3557,8 +3526,7 @@ module Util = declareClassType com ctx ent entName consArgs isOptional consBody baseExpr classMembers slotMembers let reflectionDeclaration, stmts = - let ta = - fableModuleAnnotation com ctx "Reflection" "TypeInfo" [] + let ta = fableModuleAnnotation com ctx "Reflection" "TypeInfo" [] let genArgs = Array.init ent.GenericParameters.Length (fun i -> "gen" + string i |> makeIdent) @@ -3571,17 +3539,14 @@ module Util = let generics = genArgs |> Array.mapToList (identAsExpr com ctx) - let body, stmts = - transformReflectionInfo com ctx None ent generics + let body, stmts = transformReflectionInfo com ctx None ent generics // https://github.com/fable-compiler/Fable.Python/issues/42 - let decoratorList = - [ com.GetImportExpr(ctx, "functools", "lru_cache") ] + let decoratorList = [ com.GetImportExpr(ctx, "functools", "lru_cache") ] let expr, stmts' = makeFunctionExpression com ctx None (args, body, decoratorList, ta) - let name = - com.GetIdentifier(ctx, entName + Naming.reflectionSuffix) + let name = com.GetIdentifier(ctx, entName + Naming.reflectionSuffix) expr |> declareModuleMember ctx ent.IsPublic name None, @@ -3734,7 +3699,12 @@ module Util = let right = match id.Type with - | Fable.Number _ -> Expression.boolOp (BoolOperator.Or, [ identAsExpr com ctx id; Expression.constant (0) ]) + | Fable.Number _ -> + Expression.boolOp ( + BoolOperator.Or, + [ identAsExpr com ctx id + Expression.constant (0) ] + ) | Fable.Array _ -> // Convert varArg from tuple to list. TODO: we might need to do this other places as well. Expression.call (Expression.name ("list"), [ identAsExpr com ctx id ]) @@ -3755,8 +3725,7 @@ module Util = let decorators = [ Expression.name ("staticmethod") ] let value = com.GetImportExpr(ctx, "typing", "List") - let returnType = - Expression.subscript (value, Expression.name ("str")) + let returnType = Expression.subscript (value, Expression.name ("str")) Statement.functionDef (name, Arguments.arguments (), body = body, returns = returnType, decoratorList = decorators) @@ -3792,8 +3761,7 @@ module Util = yield! (ent.FSharpFields |> List.collecti (fun i field -> - let left = - get com ctx None thisExpr (Naming.toSnakeCase field.Name) false + let left = get com ctx None thisExpr (Naming.toSnakeCase field.Name) false let right = args.[i] |> wrapIntExpression field.FieldType assign None left right |> exprAsStatement ctx)) ] @@ -3817,8 +3785,7 @@ module Util = // printfn "transformClassWithImplicitConstructor: %A" classDecl let classEnt = com.GetEntity(classDecl.Entity) - let classIdent = - Expression.name (com.GetIdentifier(ctx, classDecl.Name)) + let classIdent = Expression.name (com.GetIdentifier(ctx, classDecl.Name)) let consArgs, consBody, _returnType = getMemberArgsAndBody com ctx ClassConstructor cons.Info.HasSpread cons.Args cons.Body @@ -3860,12 +3827,12 @@ module Util = Some baseExpr, consBody) |> Option.defaultValue (None, consBody) - [ yield! declareType com ctx classEnt classDecl.Name consArgs isOptional consBody baseExpr classMembers; exposedCons ] + [ yield! declareType com ctx classEnt classDecl.Name consArgs isOptional consBody baseExpr classMembers + exposedCons ] let transformInterface (com: IPythonCompiler) ctx (classEnt: Fable.Entity) (classDecl: Fable.ClassDecl) = // printfn "transformInterface" - let classIdent = - com.GetIdentifier(ctx, Helpers.removeNamespace classEnt.FullName) + let classIdent = com.GetIdentifier(ctx, Helpers.removeNamespace classEnt.FullName) let members = classEnt.MembersFunctionsAndValues @@ -3906,8 +3873,7 @@ module Util = Arguments.arguments (args) - let returnType, _ = - typeAnnotation com ctx None memb.ReturnParameter.Type + let returnType, _ = typeAnnotation com ctx None memb.ReturnParameter.Type let body = [ Statement.expr (Expression.name ("...")) ] Statement.functionDef (name, args, body, returns = returnType, decoratorList = decorators) @@ -4073,7 +4039,7 @@ module Util = module Compiler = open Util - type PythonCompiler (com: Compiler) = + type PythonCompiler(com: Compiler) = let onlyOnceWarnings = HashSet() let imports = Dictionary() @@ -4125,7 +4091,9 @@ module Compiler = | Some localId -> Expression.identifier (localId) | None -> Expression.none - member _.GetAllImports() = imports.Values :> Import seq |> List.ofSeq + member _.GetAllImports() = + imports.Values :> Import seq |> List.ofSeq + member _.GetAllTypeVars() = typeVars member _.AddTypeVar(ctx, name: string) = @@ -4147,10 +4115,17 @@ module Compiler = member bcom.TransformAsExpr(ctx, e) = transformAsExpr bcom ctx e member bcom.TransformAsStatements(ctx, ret, e) = transformAsStatements bcom ctx ret e - member bcom.TransformFunction(ctx, name, args, body, generics) = transformFunction bcom ctx name args body generics - member bcom.TransformImport(ctx, selector, path) = transformImport bcom ctx None selector path + + member bcom.TransformFunction(ctx, name, args, body, generics) = + transformFunction bcom ctx name args body generics + + member bcom.TransformImport(ctx, selector, path) = + transformImport bcom ctx None selector path + member bcom.GetIdentifier(ctx, name) = getIdentifier bcom ctx name - member bcom.GetIdentifierAsExpr(ctx, name) = getIdentifier bcom ctx name |> Expression.name + + member bcom.GetIdentifierAsExpr(ctx, name) = + getIdentifier bcom ctx name |> Expression.name interface Compiler with member _.Options = com.Options @@ -4161,8 +4136,7 @@ module Compiler = member _.OutputType = com.OutputType member _.ProjectFile = com.ProjectFile - member _.IsPrecompilingInlineFunction = - com.IsPrecompilingInlineFunction + member _.IsPrecompilingInlineFunction = com.IsPrecompilingInlineFunction member _.WillPrecompileInlineFunction(file) = com.WillPrecompileInlineFunction(file) member _.GetImplementationFile(fileName) = com.GetImplementationFile(fileName) @@ -4203,8 +4177,7 @@ module Compiler = OptimizeTailCall = fun () -> () ScopedTypeParams = Set.empty } - let rootDecls = - List.collect (transformDeclaration com ctx) file.Declarations + let rootDecls = List.collect (transformDeclaration com ctx) file.Declarations let typeVars = com.GetAllTypeVars() |> transformTypeVars com ctx let importDecls = com.GetAllImports() |> transformImports com diff --git a/src/Fable.Transforms/Python/Prelude.fs b/src/Fable.Transforms/Python/Prelude.fs index ad62310dda..17ddb0ae94 100644 --- a/src/Fable.Transforms/Python/Prelude.fs +++ b/src/Fable.Transforms/Python/Prelude.fs @@ -52,70 +52,66 @@ module Naming = let pyKeywords = // https://docs.python.org/3/reference/lexical_analysis.html#keywords - System.Collections.Generic.HashSet [ - "False" - "await" - "else" - "import" - "pass" - "None" - "break" - "except" - "in" - "raise" - "True" - "class" - "finally" - "is" - "return" - "and" - "continue" - "for" - "lambda" - "try" - "as" - "def" - "from" - "nonlocal" - "while" - "assert" - "del" - "global" - "not" - "with" - "async" - "elif" - "if" - "or" - "yield" - ] + System.Collections.Generic.HashSet [ "False" + "await" + "else" + "import" + "pass" + "None" + "break" + "except" + "in" + "raise" + "True" + "class" + "finally" + "is" + "return" + "and" + "continue" + "for" + "lambda" + "try" + "as" + "def" + "from" + "nonlocal" + "while" + "assert" + "del" + "global" + "not" + "with" + "async" + "elif" + "if" + "or" + "yield" ] // Other global builtins we should avoid https://docs.python.org/3/library/functions.html let pyBuiltins = - System.Collections.Generic.HashSet [ - "len" - "str" - "int" - "float" - "set" - "enumerate" - "next" - "super" - "callable" - "hash" - "classmethod" - "staticmethod" - "list" - "dict" - "bool" - "isinstance" - "issubclass" - "hasattr" - "getattr" - - // Other names - "self" - ] + System.Collections.Generic.HashSet [ "len" + "str" + "int" + "float" + "set" + "enumerate" + "next" + "super" + "callable" + "hash" + "classmethod" + "staticmethod" + "list" + "dict" + "bool" + "isinstance" + "issubclass" + "hasattr" + "getattr" + + // Other names + "self" ] let reflectionSuffix = "_reflection" diff --git a/src/Fable.Transforms/Python/Python.fs b/src/Fable.Transforms/Python/Python.fs index c40b6dfc19..f4f8c9057c 100644 --- a/src/Fable.Transforms/Python/Python.fs +++ b/src/Fable.Transforms/Python/Python.fs @@ -358,7 +358,8 @@ type Raise = { Exception: Expression Cause: Expression option } - static member Create(exc, ?cause) : Statement = { Exception = exc; Cause = cause } |> Raise + static member Create(exc, ?cause) : Statement = + { Exception = exc; Cause = cause } |> Raise /// A function definition. /// @@ -762,7 +763,9 @@ module PythonExtensions = static member continue' ?loc : Statement = Continue static member import(names) : Statement = Import { Names = names } static member expr(value) : Statement = { Expr.Value = value } |> Expr - static member raise(value) : Statement = { Exception = value; Cause = None } |> Raise + + static member raise(value) : Statement = + { Exception = value; Cause = None } |> Raise static member try'(body, ?handlers, ?orElse, ?finalBody, ?loc) : Statement = Try.try' (body, ?handlers = handlers, ?orElse = orElse, ?finalBody = finalBody, ?loc = loc) @@ -829,7 +832,8 @@ module PythonExtensions = ImportFrom.importFrom (``module``, names, ?level = level) |> ImportFrom - static member nonLocal(ids) = NonLocal.Create ids |> Statement.NonLocal + static member nonLocal(ids) = + NonLocal.Create ids |> Statement.NonLocal type Expression with @@ -839,11 +843,18 @@ module PythonExtensions = Loc = loc } |> Name - static member name(name, ?ctx) : Expression = Expression.name (Identifier(name), ?ctx = ctx) - static member identifier(name, ?ctx, ?loc) : Expression = Expression.name (Identifier(name), ?ctx = ctx, ?loc = loc) - static member identifier(identifier, ?ctx, ?loc) : Expression = Expression.name (identifier, ?ctx = ctx, ?loc = loc) + static member name(name, ?ctx) : Expression = + Expression.name (Identifier(name), ?ctx = ctx) + + static member identifier(name, ?ctx, ?loc) : Expression = + Expression.name (Identifier(name), ?ctx = ctx, ?loc = loc) + + static member identifier(identifier, ?ctx, ?loc) : Expression = + Expression.name (identifier, ?ctx = ctx, ?loc = loc) + + static member dict(keys, values) : Expression = + { Keys = keys; Values = values } |> Dict - static member dict(keys, values) : Expression = { Keys = keys; Values = values } |> Dict static member tuple(elts, ?loc) : Expression = { Elements = elts; Loc = loc } |> Tuple static member slice(?lower, ?upper, ?slice) : Expression = Slice(lower, upper, slice) @@ -974,8 +985,12 @@ module PythonExtensions = static member constant(value: obj, ?loc) : Expression = Constant(value = value, loc = loc) static member string(value: string, ?loc) : Expression = Constant(value = value, loc = loc) - static member starred(value: Expression, ?ctx: ExpressionContext) : Expression = Starred(value, ctx |> Option.defaultValue Load) - static member list(elts: Expression list, ?ctx: ExpressionContext) : Expression = List(elts, ctx |> Option.defaultValue Load) + + static member starred(value: Expression, ?ctx: ExpressionContext) : Expression = + Starred(value, ctx |> Option.defaultValue Load) + + static member list(elts: Expression list, ?ctx: ExpressionContext) : Expression = + List(elts, ctx |> Option.defaultValue Load) type List with @@ -1031,7 +1046,8 @@ module PythonExtensions = Annotation = annotation TypeComment = typeComment } - static member arg(arg, ?annotation, ?typeComment) = Arg.arg (Identifier(arg), ?annotation = annotation, ?typeComment = typeComment) + static member arg(arg, ?annotation, ?typeComment) = + Arg.arg (Identifier(arg), ?annotation = annotation, ?typeComment = typeComment) type Keyword with diff --git a/src/Fable.Transforms/Python/PythonPrinter.fs b/src/Fable.Transforms/Python/PythonPrinter.fs index 508f2cb1d7..2d3b366e20 100644 --- a/src/Fable.Transforms/Python/PythonPrinter.fs +++ b/src/Fable.Transforms/Python/PythonPrinter.fs @@ -225,8 +225,7 @@ module PrinterExtensions = printer.Print(")") member printer.Print(im: ImportFrom) = - let (Identifier path) = - im.Module |> Option.defaultValue (Identifier ".") + let (Identifier path) = im.Module |> Option.defaultValue (Identifier ".") printer.Print("from ") printer.Print(path) @@ -265,7 +264,8 @@ module PrinterExtensions = printer.Print("]") - member printer.Print(node: BinOp) = printer.PrintOperation(node.Left, node.Operator, node.Right) + member printer.Print(node: BinOp) = + printer.PrintOperation(node.Left, node.Operator, node.Right) member printer.Print(node: BoolOp) = for i, value in node.Values |> List.indexed do @@ -318,8 +318,7 @@ module PrinterExtensions = if segmentLength > 0 then let segment = value.Substring(segmentStart, segmentLength) - let subSegments = - System.Text.RegularExpressions.Regex.Split(segment, @"\r?\n") + let subSegments = System.Text.RegularExpressions.Regex.Split(segment, @"\r?\n") for i = 1 to subSegments.Length do let subSegment = @@ -371,8 +370,7 @@ module PrinterExtensions = | Some (Constant (value, _)) when (value :? string) -> unbox value | _ -> "") - let matches = - System.Text.RegularExpressions.Regex.Matches(value, @"\$\d+") + let matches = System.Text.RegularExpressions.Regex.Matches(value, @"\$\d+") if matches.Count > 0 then for i = 0 to matches.Count - 1 do @@ -660,7 +658,8 @@ module PrinterExtensions = | None -> () | Some node -> printer.Print(node) - member printer.PrintOptional(node: Expression option) = printer.PrintOptional(node |> Option.map AST.Expression) + member printer.PrintOptional(node: Expression option) = + printer.PrintOptional(node |> Option.map AST.Expression) member printer.PrintOptional(node: Identifier option) = match node with @@ -680,11 +679,20 @@ module PrinterExtensions = member printer.PrintCommaSeparatedList(nodes: Expression list) = printer.PrintList(nodes, (fun p x -> printer.Print(x)), (fun p -> p.Print(", "))) - member printer.PrintCommaSeparatedList(nodes: Arg list) = printer.PrintCommaSeparatedList(nodes |> List.map AST.Arg) - member printer.PrintCommaSeparatedList(nodes: Keyword list) = printer.PrintCommaSeparatedList(nodes |> List.map AST.Keyword) - member printer.PrintCommaSeparatedList(nodes: Alias list) = printer.PrintCommaSeparatedList(nodes |> List.map AST.Alias) - member printer.PrintCommaSeparatedList(nodes: Identifier list) = printer.PrintCommaSeparatedList(nodes |> List.map AST.Identifier) - member printer.PrintCommaSeparatedList(nodes: WithItem list) = printer.PrintCommaSeparatedList(nodes |> List.map AST.WithItem) + member printer.PrintCommaSeparatedList(nodes: Arg list) = + printer.PrintCommaSeparatedList(nodes |> List.map AST.Arg) + + member printer.PrintCommaSeparatedList(nodes: Keyword list) = + printer.PrintCommaSeparatedList(nodes |> List.map AST.Keyword) + + member printer.PrintCommaSeparatedList(nodes: Alias list) = + printer.PrintCommaSeparatedList(nodes |> List.map AST.Alias) + + member printer.PrintCommaSeparatedList(nodes: Identifier list) = + printer.PrintCommaSeparatedList(nodes |> List.map AST.Identifier) + + member printer.PrintCommaSeparatedList(nodes: WithItem list) = + printer.PrintCommaSeparatedList(nodes |> List.map AST.WithItem) member printer.PrintFunction ( diff --git a/src/Fable.Transforms/Python/Replacements.fs b/src/Fable.Transforms/Python/Replacements.fs index 5bc9fd139e..4460542c0b 100644 --- a/src/Fable.Transforms/Python/Replacements.fs +++ b/src/Fable.Transforms/Python/Replacements.fs @@ -72,6 +72,7 @@ type Helper = | None -> makeIdentExpr ident let info = makeCallInfo None args (defaultArg argTypes []) + Call(callee, { info with IsConstructor = defaultArg isPyConstructor false }, returnType, loc) static member GlobalIdent(ident: string, memb: string, typ: Type, ?loc: SourceLocation) = @@ -83,8 +84,7 @@ module Atts = let decorator = "Fable.Core.PY.DecoratorAttribute" // typeof.FullName [] - let reflectedDecorator = - "Fable.Core.PY.ReflectedDecoratorAttribute" // typeof.FullName + let reflectedDecorator = "Fable.Core.PY.ReflectedDecoratorAttribute" // typeof.FullName module Helpers = let getTypedArrayName (com: Compiler) numberKind = @@ -132,21 +132,28 @@ module Helpers = Info = FSharp2Fable.MemberInfo(isValue = true) ExportDefault = false } - let typedObjExpr t kvs = ObjectExpr(List.map objValue kvs, t, None) + let typedObjExpr t kvs = + ObjectExpr(List.map objValue kvs, t, None) let objExpr kvs = typedObjExpr Any kvs - let add left right = Operation(Binary(BinaryPlus, left, right), left.Type, None) + let add left right = + Operation(Binary(BinaryPlus, left, right), left.Type, None) - let sub left right = Operation(Binary(BinaryMinus, left, right), left.Type, None) + let sub left right = + Operation(Binary(BinaryMinus, left, right), left.Type, None) - let eq left right = Operation(Binary(BinaryEqualStrict, left, right), Boolean, None) + let eq left right = + Operation(Binary(BinaryEqualStrict, left, right), Boolean, None) - let neq left right = Operation(Binary(BinaryUnequalStrict, left, right), Boolean, None) + let neq left right = + Operation(Binary(BinaryUnequalStrict, left, right), Boolean, None) - let isNull expr = Operation(Binary(BinaryEqual, expr, Value(Null Any, None)), Boolean, None) + let isNull expr = + Operation(Binary(BinaryEqual, expr, Value(Null Any, None)), Boolean, None) - let error msg = Helper.PyConstructorCall(makeIdentExpr "Exception", Any, [ msg ]) + let error msg = + Helper.PyConstructorCall(makeIdentExpr "Exception", Any, [ msg ]) let str txt = Value(StringConstant txt, None) @@ -305,7 +312,9 @@ let rec namesof com ctx acc e = | acc, _ -> Some acc let (|Namesof|_|) com ctx e = namesof com ctx [] e -let (|Nameof|_|) com ctx e = namesof com ctx [] e |> Option.bind List.tryLast + +let (|Nameof|_|) com ctx e = + namesof com ctx [] e |> Option.bind List.tryLast let (|ReplaceName|_|) (namesAndReplacements: (string * string) list) name = namesAndReplacements @@ -400,13 +409,14 @@ let makeLongInt com r t signed (x: uint64) = let unsigned = BoolConstant(not signed) let args = - [ makeValue None lowBits; makeValue None highBits; makeValue None unsigned ] + [ makeValue None lowBits + makeValue None highBits + makeValue None unsigned ] Helper.LibCall(com, "long", "fromBits", t, args, ?loc = r) let makeDecimal com r t (x: decimal) = - let str = - x.ToString(System.Globalization.CultureInfo.InvariantCulture) + let str = x.ToString(System.Globalization.CultureInfo.InvariantCulture) Helper.LibCall(com, "decimal", "Decimal", t, [ makeStrConst str ], isPyConstructor = true, ?loc = r) @@ -550,8 +560,7 @@ let makeRefFromMutableValue com ctx r t (value: Expr) = Helper.LibCall(com, "types", "FSharpRef", t, [ getter; setter ], isPyConstructor = true) let makeRefFromMutableField com ctx r t callee key = - let getter = - Delegate([], Get(callee, FieldGet(key, true), t, r), None) + let getter = Delegate([], Get(callee, FieldGet(key, true), t, r), None) let setter = let v = makeUniqueIdent ctx t "v" @@ -722,11 +731,12 @@ let stringToInt com (ctx: Context) r targetType (args: Expr list) : Expr = let style = int System.Globalization.NumberStyles.Any - let _isFloatOrDecimal, numberModule, unsigned, bitsize = - getParseParams kind + let _isFloatOrDecimal, numberModule, unsigned, bitsize = getParseParams kind let parseArgs = - [ makeIntConst style; makeBoolConst unsigned; makeIntConst bitsize ] + [ makeIntConst style + makeBoolConst unsigned + makeIntConst bitsize ] Helper.LibCall(com, numberModule, "parse", targetType, [ args.Head ] @ parseArgs @ args.Tail, ?loc = r) @@ -747,8 +757,7 @@ let toLong com (ctx: Context) r (unsigned: bool) targetType (args: Expr list) : | BigInt -> Helper.LibCall(com, "big_int", castBigIntMethod targetType, targetType, args) | Long _ -> Helper.LibCall(com, "long", "fromValue", targetType, args @ [ makeBoolConst unsigned ]) | Decimal -> - let n = - Helper.LibCall(com, "decimal", "toNumber", Number(Float64, None), args) + let n = Helper.LibCall(com, "decimal", "toNumber", Number(Float64, None), args) Helper.LibCall(com, "long", "fromNumber", targetType, [ n; makeBoolConst unsigned ]) | JsNumber (Integer as kind) -> fromInteger kind args.Head @@ -801,8 +810,7 @@ let round com (args: Expr list) = let n = Helper.LibCall(com, "decimal", "toNumber", Number(Float64, None), [ args.Head ]) - let rounded = - Helper.LibCall(com, "util", "round", Number(Float64, None), [ n ]) + let rounded = Helper.LibCall(com, "util", "round", Number(Float64, None), [ n ]) rounded :: args.Tail | Number (Float, _) -> @@ -812,7 +820,8 @@ let round com (args: Expr list) = rounded :: args.Tail | _ -> args -let toList com returnType expr = Helper.LibCall(com, "list", "ofSeq", returnType, [ expr ]) +let toList com returnType expr = + Helper.LibCall(com, "list", "ofSeq", returnType, [ expr ]) let toArray r t expr = let t = @@ -824,7 +833,8 @@ let toArray r t expr = Value(NewArrayFrom(expr, t), r) -let stringToCharArray t e = Helper.InstanceCall(e, "split", t, [ makeStrConst "" ]) +let stringToCharArray t e = + Helper.InstanceCall(e, "split", t, [ makeStrConst "" ]) let toSeq t (e: Expr) = match e.Type with @@ -875,15 +885,19 @@ let (|CustomOp|_|) (com: ICompiler) (ctx: Context) opName argTypes sourceTypes = | _ -> None) let applyOp (com: ICompiler) (ctx: Context) r t opName (args: Expr list) argTypes genArgs = - let unOp operator operand = Operation(Unary(operator, operand), t, r) - let binOp op left right = Operation(Binary(op, left, right), t, r) + let unOp operator operand = + Operation(Unary(operator, operand), t, r) + + let binOp op left right = + Operation(Binary(op, left, right), t, r) let truncateUnsigned operation = // see #1550 match t with | Number (UInt32, _) -> Operation(Binary(BinaryShiftRightZeroFill, operation, makeIntConst 0), t, r) | _ -> operation - let logicOp op left right = Operation(Logical(op, left, right), Boolean, r) + let logicOp op left right = + Operation(Logical(op, left, right), Boolean, r) let nativeOp opName argTypes args = match opName, args with @@ -944,8 +958,7 @@ let applyOp (com: ICompiler) (ctx: Context) r t opName (args: Expr list) argType Helper.LibCall(com, coreModFor bt, opName, t, args, argTypes, ?loc = r) | Builtin (FSharpSet _) :: _ -> - let mangledName = - Naming.buildNameWithoutSanitationFrom "FSharpSet" true opName "" + let mangledName = Naming.buildNameWithoutSanitationFrom "FSharpSet" true opName "" Helper.LibCall(com, "set", mangledName, t, args, argTypes, ?loc = r) // | Builtin (FSharpMap _)::_ -> @@ -1144,7 +1157,8 @@ and makeComparerFunction (com: ICompiler) ctx typArg = let body = compare com ctx None (IdentExpr x) (IdentExpr y) Delegate([ x; y ], body, None) -and makeComparer (com: ICompiler) ctx typArg = objExpr [ "Compare", makeComparerFunction com ctx typArg ] +and makeComparer (com: ICompiler) ctx typArg = + objExpr [ "Compare", makeComparerFunction com ctx typArg ] and makeEqualityFunction (com: ICompiler) ctx typArg = let x = makeUniqueIdent ctx typArg "x" @@ -1156,10 +1170,8 @@ let makeEqualityComparer (com: ICompiler) ctx typArg = let x = makeUniqueIdent ctx typArg "x" let y = makeUniqueIdent ctx typArg "y" - objExpr [ - "Equals", Delegate([ x; y ], equals com ctx None true (IdentExpr x) (IdentExpr y), None) - "GetHashCode", Delegate([ x ], structuralHash com None (IdentExpr x), None) - ] + objExpr [ "Equals", Delegate([ x; y ], equals com ctx None true (IdentExpr x) (IdentExpr y), None) + "GetHashCode", Delegate([ x ], structuralHash com None (IdentExpr x), None) ] // TODO: Try to detect at compile-time if the object already implements `Compare`? let inline makeComparerFromEqualityComparer e = e // leave it as is, if implementation supports it @@ -1234,7 +1246,8 @@ let makeAddFunction (com: ICompiler) ctx t = Delegate([ x; y ], body, None) let makeGenericAdder (com: ICompiler) ctx t = - objExpr [ "GetZero", getZero com ctx t |> makeDelegate []; "Add", makeAddFunction com ctx t ] + objExpr [ "GetZero", getZero com ctx t |> makeDelegate [] + "Add", makeAddFunction com ctx t ] let makeGenericAverager (com: ICompiler) ctx t = let divideFn = @@ -1246,7 +1259,9 @@ let makeGenericAverager (com: ICompiler) ctx t = Delegate([ x; i ], body, None) - objExpr [ "GetZero", getZero com ctx t |> makeDelegate []; "Add", makeAddFunction com ctx t; "DivideByInt", divideFn ] + objExpr [ "GetZero", getZero com ctx t |> makeDelegate [] + "Add", makeAddFunction com ctx t + "DivideByInt", divideFn ] let makePojoFromLambda com arg = let rec flattenSequential = @@ -1400,13 +1415,15 @@ let pyConstructor com ent = |> sprintf "Cannot find %s constructor" |> addErrorAndReturnNull com [] None -let tryOp com r t op args = Helper.LibCall(com, "option", "tryOp", t, op :: args, ?loc = r) +let tryOp com r t op args = + Helper.LibCall(com, "option", "tryOp", t, op :: args, ?loc = r) let tryCoreOp com r t coreModule coreMember args = let op = Helper.LibValue(com, coreModule, coreMember, Any) tryOp com r t op args -let emptyGuid () = makeStrConst "00000000-0000-0000-0000-000000000000" +let emptyGuid () = + makeStrConst "00000000-0000-0000-0000-000000000000" let rec defaultof (com: ICompiler) ctx (t: Type) = match t with @@ -1574,8 +1591,7 @@ let fableCoreLib (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Exp | "version" -> makeStrConst Literals.VERSION |> Some | "majorMinorVersion" -> try - let m = - System.Text.RegularExpressions.Regex.Match(Literals.VERSION, @"^\d+\.\d+") + let m = System.Text.RegularExpressions.Regex.Match(Literals.VERSION, @"^\d+\.\d+") float m.Value |> makeFloatConst |> Some with @@ -1734,8 +1750,11 @@ let fableCoreLib (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Exp | _ -> None | _ -> None -let getReference r t expr = getAttachedMemberWith r t expr "contents" -let setReference r expr value = setExpr r expr (makeStrConst "contents") value +let getReference r t expr = + getAttachedMemberWith r t expr "contents" + +let setReference r expr value = + setExpr r expr (makeStrConst "contents") value let newReference com r t value = Helper.LibCall(com, "types", "FSharpRef", t, [ value ], isPyConstructor = true, ?loc = r) @@ -1760,8 +1779,7 @@ let getMangledNames (i: CallInfo) (thisArg: Expr option) = i.DeclaringEntityFullName.Substring(pos + 1) |> Naming.cleanNameAsPyIdentifier - let memberName = - i.CompiledName |> Naming.cleanNameAsPyIdentifier + let memberName = i.CompiledName |> Naming.cleanNameAsPyIdentifier let mangledName = Naming.buildNameWithoutSanitationFrom entityName isStatic memberName i.OverloadSuffix @@ -1844,7 +1862,7 @@ let fsFormat (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr op Helper.LibCall(com, "string", "toFail", t, args, i.SignatureArgTypes, ?loc = r) |> Some | ("PrintFormatToStringBuilder" // bprintf - | "PrintFormatToStringBuilderThen"), // Printf.kbprintf + | "PrintFormatToStringBuilderThen"), _, _ -> fsharpModule com ctx r t i thisArg args | ".ctor", _, str :: (Value (NewArray _, _) as values) :: _ -> @@ -1974,14 +1992,14 @@ let operators (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr o | "PrintFormatThen" // Printf.kprintf | "PrintFormatToStringThenFail" // Printf.failwithf | "PrintFormatToStringBuilder" // bprintf - | "PrintFormatToStringBuilderThen"), // Printf.kbprintf + | "PrintFormatToStringBuilderThen"), _ -> fsFormat com ctx r t i thisArg args | ("Failure" | "FailurePattern" // (|Failure|_|) | "LazyPattern" // (|Lazy|_|) | "Lock" // lock | "NullArg" // nullArg - | "Using"), // using + | "Using"), _ -> fsharpModule com ctx r t i thisArg args // Exceptions | "FailWith", [ msg ] @@ -2027,11 +2045,9 @@ let operators (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr o math r t args i.SignatureArgTypes meth |> Some | "Log", [ arg1; arg2 ] -> // "Math.log($0) / Math.log($1)" - let dividend = - math None t [ arg1 ] (List.take 1 i.SignatureArgTypes) "log" + let dividend = math None t [ arg1 ] (List.take 1 i.SignatureArgTypes) "log" - let divisor = - math None t [ arg2 ] (List.skip 1 i.SignatureArgTypes) "log" + let divisor = math None t [ arg2 ] (List.skip 1 i.SignatureArgTypes) "log" makeBinOp r t dividend divisor BinaryDivide |> Some @@ -2217,23 +2233,22 @@ let chars (com: ICompiler) (ctx: Context) r t (i: CallInfo) (_: Expr option) (ar | _ -> None let implementedStringFunctions = - set [| - "Compare" - "CompareTo" - "EndsWith" - "Format" - "IndexOfAny" - "Insert" - "IsNullOrEmpty" - "IsNullOrWhiteSpace" - "PadLeft" - "PadRight" - "Remove" - "Replace" - "Substring" - |] - -let getEnumerator com r t expr = Helper.LibCall(com, "util", "getEnumerator", t, [ toSeq Any expr ], ?loc = r) + set [| "Compare" + "CompareTo" + "EndsWith" + "Format" + "IndexOfAny" + "Insert" + "IsNullOrEmpty" + "IsNullOrWhiteSpace" + "PadLeft" + "PadRight" + "Remove" + "Replace" + "Substring" |] + +let getEnumerator com r t expr = + Helper.LibCall(com, "util", "getEnumerator", t, [ toSeq Any expr ], ?loc = r) let strings (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = match i.CompiledName, thisArg, args with @@ -2275,14 +2290,12 @@ let strings (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr opt if (List.length args) > 1 then addWarning com ctx.InlinePath r "String.Contains: second argument is ignored" - let left = - Helper.InstanceCall(c, "find", Number(Int32, None), [ arg ]) + let left = Helper.InstanceCall(c, "find", Number(Int32, None), [ arg ]) makeEqOp r left (makeIntConst 0) BinaryGreaterOrEqual |> Some | "StartsWith", Some c, [ _str ] -> - let left = - Helper.InstanceCall(c, "find", Number(Int32, None), args) + let left = Helper.InstanceCall(c, "find", Number(Int32, None), args) makeEqOp r left (makeIntConst 0) BinaryEqualStrict |> Some @@ -2314,7 +2327,16 @@ let strings (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr opt |> Some | [ ExprType Char as str; ExprType (Number (Int32, None)) as start ] | [ ExprType String as str; ExprType (Number (Int32, None)) as start ] -> - Helper.InstanceCall(c, "rfind", t, [ str; Value(NumberConstant(0.0, Int32, None), None); start ], i.SignatureArgTypes, ?loc = r) + Helper.InstanceCall( + c, + "rfind", + t, + [ str + Value(NumberConstant(0.0, Int32, None), None) + start ], + i.SignatureArgTypes, + ?loc = r + ) |> Some | _ -> "The only extra argument accepted for String.IndexOf/LastIndexOf is startIndex." @@ -2523,20 +2545,17 @@ let resizeArrays (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (this Helper.LibCall(com, "Util", "clear", t, [ ar ], ?loc = r) |> Some | "Find", Some ar, [ arg ] -> - let opt = - Helper.LibCall(com, "array", "tryFind", t, [ arg; ar ], ?loc = r) + let opt = Helper.LibCall(com, "array", "tryFind", t, [ arg; ar ], ?loc = r) Helper.LibCall(com, "Option", "defaultArg", t, [ opt; defaultof com ctx t ], ?loc = r) |> Some | "Exists", Some ar, [ arg ] -> - let left = - Helper.InstanceCall(ar, "index", Number(Int32, None), [ arg ], ?loc = r) + let left = Helper.InstanceCall(ar, "index", Number(Int32, None), [ arg ], ?loc = r) makeEqOp r left (makeIntConst -1) BinaryGreater |> Some | "FindLast", Some ar, [ arg ] -> - let opt = - Helper.LibCall(com, "array", "tryFindBack", t, [ arg; ar ], ?loc = r) + let opt = Helper.LibCall(com, "array", "tryFindBack", t, [ arg; ar ], ?loc = r) Helper.LibCall(com, "Option", "defaultArg", t, [ opt; defaultof com ctx t ], ?loc = r) |> Some @@ -2588,14 +2607,14 @@ let resizeArrays (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (this let nativeArrayFunctions = dict [| //"Exists", "some" - //"Filter", "filter" - //"Find", "find" - //"FindIndex", "index" - //"ForAll", "all" - //"Iterate", "forEach" - //"Reduce", "reduce" - //"ReduceBack", "reduceRight" - |] + //"Filter", "filter" + //"Find", "find" + //"FindIndex", "index" + //"ForAll", "all" + //"Iterate", "forEach" + //"Reduce", "reduce" + //"ReduceBack", "reduceRight" + |] let tuples (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Expr option) (args: Expr list) = let changeKind isStruct = @@ -2608,8 +2627,7 @@ let tuples (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: E | (".ctor" | "Create"), _ -> - let isStruct = - i.DeclaringEntityFullName.StartsWith("System.ValueTuple") + let isStruct = i.DeclaringEntityFullName.StartsWith("System.ValueTuple") Value(NewTuple(args, isStruct), r) |> Some | "get_Item1", Some x -> Get(x, TupleIndex 0, t, r) |> Some @@ -2642,7 +2660,17 @@ let arrays (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: E | "get_Item", Some arg, [ idx ] -> getExpr r t arg idx |> Some | "set_Item", Some arg, [ idx; value ] -> setExpr r arg idx value |> Some | "Copy", None, [ _source; _sourceIndex; _target; _targetIndex; _count ] -> copyToArray com r t i args - | "Copy", None, [ source; target; count ] -> copyToArray com r t i [ source; makeIntConst 0; target; makeIntConst 0; count ] + | "Copy", None, [ source; target; count ] -> + copyToArray + com + r + t + i + [ source + makeIntConst 0 + target + makeIntConst 0 + count ] | "IndexOf", None, args -> Helper.LibCall(com, "array", "index_of", t, args, i.SignatureArgTypes, ?loc = r) |> Some @@ -2660,7 +2688,16 @@ let arrayModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Ex value |> Option.defaultWith (fun () -> getZero com ctx t2) // If we don't fill the array some operations may behave unexpectedly, like Array.prototype.reduce - Helper.LibCall(com, "array", "fill", t, [ newArray size t2; makeIntConst 0; size; value ]) + Helper.LibCall( + com, + "array", + "fill", + t, + [ newArray size t2 + makeIntConst 0 + size + value ] + ) | _ -> $"Expecting an array type but got {t}" |> addErrorAndReturnNull com ctx.InlinePath r @@ -2708,8 +2745,7 @@ let arrayModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Ex let args, thisArg = List.splitLast args let argTypes = List.take (List.length args) i.SignatureArgTypes - let call = - Helper.GlobalCall(meth, t, args @ [ thisArg ], ?loc = r) + let call = Helper.GlobalCall(meth, t, args @ [ thisArg ], ?loc = r) Helper.GlobalCall("list", t, [ call ], ?loc = r) |> Some @@ -2806,8 +2842,7 @@ let sets (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Exp let mangledName = Naming.buildNameWithoutSanitationFrom "FSharpSet" isStatic i.CompiledName "" - let args = - injectArg com ctx r "Set" mangledName i.GenericArgs args + let args = injectArg com ctx r "Set" mangledName i.GenericArgs args Helper.LibCall(com, "set", mangledName, t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) |> Some @@ -2831,8 +2866,7 @@ let maps (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (thisArg: Exp let mangledName = Naming.buildNameWithoutSanitationFrom "FSharpMap" isStatic i.CompiledName "" - let args = - injectArg com ctx r "Map" mangledName i.GenericArgs args + let args = injectArg com ctx r "Map" mangledName i.GenericArgs args Helper.LibCall(com, "map", mangledName, t, args, i.SignatureArgTypes, ?thisArg = thisArg, ?loc = r) |> Some @@ -2873,7 +2907,8 @@ let options (com: ICompiler) (_: Context) r (t: Type) (i: CallInfo) (thisArg: Ex | _ -> None let optionModule (com: ICompiler) (ctx: Context) r (t: Type) (i: CallInfo) (_: Expr option) (args: Expr list) = - let toArray r t arg = Helper.LibCall(com, "option", "toArray", Array t, [ arg ], ?loc = r) + let toArray r t arg = + Helper.LibCall(com, "option", "toArray", Array t, [ arg ], ?loc = r) match i.CompiledName, args with | "None", _ -> NewOption(None, t, false) |> makeValue r |> Some @@ -2953,8 +2988,7 @@ let parseNum (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr op | NumberExtKind kind -> kind | x -> failwithf "Unexpected type in parse: %A" x - let isFloatOrDecimal, numberModule, unsigned, bitsize = - getParseParams kind + let isFloatOrDecimal, numberModule, unsigned, bitsize = getParseParams kind let outValue = if meth = "TryParse" then @@ -2966,7 +3000,10 @@ let parseNum (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr op if isFloatOrDecimal then [ str ] @ outValue else - [ str; makeIntConst style; makeBoolConst unsigned; makeIntConst bitsize ] + [ str + makeIntConst style + makeBoolConst unsigned + makeIntConst bitsize ] @ outValue Helper.LibCall(com, numberModule, Naming.lowerFirst meth, t, args, ?loc = r) @@ -3543,7 +3580,10 @@ let enums (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr optio match meth, args with // TODO: Parse at compile time if we know the type | "parseEnum", [ value ] -> [ Value(TypeInfo(t), None); value ] - | "tryParseEnum", [ value; refValue ] -> [ Value(TypeInfo(genArg com ctx r 0 i.GenericArgs), None); value; refValue ] + | "tryParseEnum", [ value; refValue ] -> + [ Value(TypeInfo(genArg com ctx r 0 i.GenericArgs), None) + value + refValue ] | _ -> args Helper.LibCall(com, "Reflection", meth, t, args, ?loc = r) @@ -3648,7 +3688,8 @@ let debug (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr optio | _ -> None let dates (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr option) (args: Expr list) = - let getTime (e: Expr) = Helper.InstanceCall(e, "getTime", t, []) + let getTime (e: Expr) = + Helper.InstanceCall(e, "getTime", t, []) let moduleName = if i.DeclaringEntityFullName = Types.datetime then @@ -4017,8 +4058,7 @@ let encoding (com: ICompiler) (ctx: Context) r t (i: CallInfo) (thisArg: Expr op | 3) -> let meth = Naming.lowerFirst i.CompiledName - let expr = - Helper.InstanceCall(callee, meth, t, args, i.SignatureArgTypes, ?loc = r) + let expr = Helper.InstanceCall(callee, meth, t, args, i.SignatureArgTypes, ?loc = r) if com.Options.TypedArrays then expr |> Some @@ -4517,9 +4557,11 @@ let fsharpValue com methName (r: SourceLocation option) t (i: CallInfo) (args: E | "GetExceptionFields" -> None // TODO!!! | _ -> None -let curryExprAtRuntime com arity (expr: Expr) = Helper.LibCall(com, "Util", "curry", expr.Type, [ makeIntConst arity; expr ]) +let curryExprAtRuntime com arity (expr: Expr) = + Helper.LibCall(com, "Util", "curry", expr.Type, [ makeIntConst arity; expr ]) -let uncurryExprAtRuntime com arity (expr: Expr) = Helper.LibCall(com, "Util", "uncurry", expr.Type, [ makeIntConst arity; expr ]) +let uncurryExprAtRuntime com arity (expr: Expr) = + Helper.LibCall(com, "Util", "uncurry", expr.Type, [ makeIntConst arity; expr ]) let partialApplyAtRuntime com t arity (fn: Expr) (args: Expr list) = let args = NewArray(args, Any) |> makeValue None @@ -4552,135 +4594,133 @@ let tryField com returnTyp ownerTyp fieldName = | _ -> None let private replacedModules = - dict [ - "System.Math", operators - "Microsoft.FSharp.Core.Operators", operators - "Microsoft.FSharp.Core.Operators.Checked", operators - "Microsoft.FSharp.Core.Operators.Unchecked", unchecked - "Microsoft.FSharp.Core.Operators.OperatorIntrinsics", intrinsicFunctions - "Microsoft.FSharp.Core.ExtraTopLevelOperators", operators - "Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicFunctions", intrinsicFunctions - "Microsoft.FSharp.Core.LanguagePrimitives", languagePrimitives - "Microsoft.FSharp.Core.LanguagePrimitives.HashCompare", languagePrimitives - "Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators", operators - "System.Runtime.CompilerServices.RuntimeHelpers", runtimeHelpers - "System.Runtime.ExceptionServices.ExceptionDispatchInfo", exceptionDispatchInfo - Types.char, chars - Types.string, strings - "Microsoft.FSharp.Core.StringModule", stringModule - "System.FormattableString", formattableString - "System.Runtime.CompilerServices.FormattableStringFactory", formattableString - "System.Text.StringBuilder", bclType - Types.array, arrays - Types.list, lists - "Microsoft.FSharp.Collections.ArrayModule", arrayModule - "Microsoft.FSharp.Collections.ListModule", listModule - "Microsoft.FSharp.Collections.HashIdentity", fsharpModule - "Microsoft.FSharp.Collections.ComparisonIdentity", fsharpModule - "Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers", seqModule - "Microsoft.FSharp.Collections.SeqModule", seqModule - Types.keyValuePair, keyValuePairs - "System.Collections.Generic.Comparer`1", bclType - "System.Collections.Generic.EqualityComparer`1", bclType - Types.dictionary, dictionaries - Types.idictionary, dictionaries - Types.ireadonlydictionary, dictionaries - Types.ienumerableGeneric, enumerables - Types.ienumerable, enumerables - "System.Collections.Generic.Dictionary`2.ValueCollection", enumerables - "System.Collections.Generic.Dictionary`2.KeyCollection", enumerables - "System.Collections.Generic.Dictionary`2.Enumerator", enumerators - "System.Collections.Generic.Dictionary`2.ValueCollection.Enumerator", enumerators - "System.Collections.Generic.Dictionary`2.KeyCollection.Enumerator", enumerators - "System.Collections.Generic.List`1.Enumerator", enumerators - "System.Collections.Generic.HashSet`1.Enumerator", enumerators - "System.CharEnumerator", enumerators - Types.resizeArray, resizeArrays - "System.Collections.Generic.IList`1", resizeArrays - "System.Collections.IList", resizeArrays - Types.icollectionGeneric, resizeArrays - Types.icollection, resizeArrays - Types.hashset, hashSets - Types.iset, hashSets - Types.option, options - Types.valueOption, options - "System.Nullable`1", nullables - "Microsoft.FSharp.Core.OptionModule", optionModule - "Microsoft.FSharp.Core.ResultModule", results - Types.bigint, bigints - "Microsoft.FSharp.Core.NumericLiterals.NumericLiteralI", bigints - Types.reference, references - Types.object, objects - Types.valueType, valueTypes - "System.Enum", enums - "System.BitConverter", bitConvert - Types.bool, parseBool - Types.int8, parseNum - Types.uint8, parseNum - Types.int16, parseNum - Types.uint16, parseNum - Types.int32, parseNum - Types.uint32, parseNum - Types.int64, parseNum - Types.uint64, parseNum - Types.float32, parseNum - Types.float64, parseNum - Types.decimal, decimals - "System.Convert", convert - "System.Console", console - "System.Diagnostics.Debug", debug - "System.Diagnostics.Debugger", debug - Types.datetime, dates - Types.datetimeOffset, dates - Types.timespan, timeSpans - "System.Timers.Timer", timers - "System.Environment", systemEnv - "System.Globalization.CultureInfo", globalization - "System.Random", random - "System.Runtime.CompilerServices.TaskAwaiter`1", tasks - "System.Threading.CancellationToken", cancels - "System.Threading.CancellationTokenSource", cancels - "System.Threading.Monitor", monitor - "System.Threading.Tasks.Task`1", tasks - "System.Threading.Tasks.Task", tasks - "System.Activator", activator - "System.Text.Encoding", encoding - "System.Text.UnicodeEncoding", encoding - "System.Text.UTF8Encoding", encoding - "System.Text.RegularExpressions.Capture", regex - "System.Text.RegularExpressions.Match", regex - "System.Text.RegularExpressions.Group", regex - "System.Text.RegularExpressions.MatchCollection", regex - "System.Text.RegularExpressions.GroupCollection", regex - Types.regex, regex - Types.fsharpSet, sets - "Microsoft.FSharp.Collections.SetModule", setModule - Types.fsharpMap, maps - "Microsoft.FSharp.Collections.MapModule", mapModule - "Microsoft.FSharp.Control.FSharpMailboxProcessor`1", mailbox - "Microsoft.FSharp.Control.FSharpAsyncReplyChannel`1", mailbox - "Microsoft.FSharp.Control.FSharpAsyncBuilder", asyncBuilder - "Microsoft.FSharp.Control.AsyncActivation`1", asyncBuilder - "Microsoft.FSharp.Control.FSharpAsync", asyncs - "Microsoft.FSharp.Control.AsyncPrimitives", asyncs - "Microsoft.FSharp.Control.TaskBuilder", tasks - "Microsoft.FSharp.Control.TaskBuilderBase", taskBuilder - "Microsoft.FSharp.Control.TaskBuilderModule", taskBuilder - "Microsoft.FSharp.Control.TaskBuilderExtensions.HighPriority", taskBuilder - "Microsoft.FSharp.Control.TaskBuilderExtensions.LowPriority", taskBuilder - Types.guid, guids - "System.Uri", uris - "System.Lazy`1", laziness - "Microsoft.FSharp.Control.Lazy", laziness - "Microsoft.FSharp.Control.LazyExtensions", laziness - "Microsoft.FSharp.Control.CommonExtensions", controlExtensions - "Microsoft.FSharp.Control.FSharpEvent`1", events - "Microsoft.FSharp.Control.FSharpEvent`2", events - "Microsoft.FSharp.Control.EventModule", events - "Microsoft.FSharp.Control.ObservableModule", observable - Types.type_, types - "System.Reflection.TypeInfo", types - ] + dict [ "System.Math", operators + "Microsoft.FSharp.Core.Operators", operators + "Microsoft.FSharp.Core.Operators.Checked", operators + "Microsoft.FSharp.Core.Operators.Unchecked", unchecked + "Microsoft.FSharp.Core.Operators.OperatorIntrinsics", intrinsicFunctions + "Microsoft.FSharp.Core.ExtraTopLevelOperators", operators + "Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicFunctions", intrinsicFunctions + "Microsoft.FSharp.Core.LanguagePrimitives", languagePrimitives + "Microsoft.FSharp.Core.LanguagePrimitives.HashCompare", languagePrimitives + "Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators", operators + "System.Runtime.CompilerServices.RuntimeHelpers", runtimeHelpers + "System.Runtime.ExceptionServices.ExceptionDispatchInfo", exceptionDispatchInfo + Types.char, chars + Types.string, strings + "Microsoft.FSharp.Core.StringModule", stringModule + "System.FormattableString", formattableString + "System.Runtime.CompilerServices.FormattableStringFactory", formattableString + "System.Text.StringBuilder", bclType + Types.array, arrays + Types.list, lists + "Microsoft.FSharp.Collections.ArrayModule", arrayModule + "Microsoft.FSharp.Collections.ListModule", listModule + "Microsoft.FSharp.Collections.HashIdentity", fsharpModule + "Microsoft.FSharp.Collections.ComparisonIdentity", fsharpModule + "Microsoft.FSharp.Core.CompilerServices.RuntimeHelpers", seqModule + "Microsoft.FSharp.Collections.SeqModule", seqModule + Types.keyValuePair, keyValuePairs + "System.Collections.Generic.Comparer`1", bclType + "System.Collections.Generic.EqualityComparer`1", bclType + Types.dictionary, dictionaries + Types.idictionary, dictionaries + Types.ireadonlydictionary, dictionaries + Types.ienumerableGeneric, enumerables + Types.ienumerable, enumerables + "System.Collections.Generic.Dictionary`2.ValueCollection", enumerables + "System.Collections.Generic.Dictionary`2.KeyCollection", enumerables + "System.Collections.Generic.Dictionary`2.Enumerator", enumerators + "System.Collections.Generic.Dictionary`2.ValueCollection.Enumerator", enumerators + "System.Collections.Generic.Dictionary`2.KeyCollection.Enumerator", enumerators + "System.Collections.Generic.List`1.Enumerator", enumerators + "System.Collections.Generic.HashSet`1.Enumerator", enumerators + "System.CharEnumerator", enumerators + Types.resizeArray, resizeArrays + "System.Collections.Generic.IList`1", resizeArrays + "System.Collections.IList", resizeArrays + Types.icollectionGeneric, resizeArrays + Types.icollection, resizeArrays + Types.hashset, hashSets + Types.iset, hashSets + Types.option, options + Types.valueOption, options + "System.Nullable`1", nullables + "Microsoft.FSharp.Core.OptionModule", optionModule + "Microsoft.FSharp.Core.ResultModule", results + Types.bigint, bigints + "Microsoft.FSharp.Core.NumericLiterals.NumericLiteralI", bigints + Types.reference, references + Types.object, objects + Types.valueType, valueTypes + "System.Enum", enums + "System.BitConverter", bitConvert + Types.bool, parseBool + Types.int8, parseNum + Types.uint8, parseNum + Types.int16, parseNum + Types.uint16, parseNum + Types.int32, parseNum + Types.uint32, parseNum + Types.int64, parseNum + Types.uint64, parseNum + Types.float32, parseNum + Types.float64, parseNum + Types.decimal, decimals + "System.Convert", convert + "System.Console", console + "System.Diagnostics.Debug", debug + "System.Diagnostics.Debugger", debug + Types.datetime, dates + Types.datetimeOffset, dates + Types.timespan, timeSpans + "System.Timers.Timer", timers + "System.Environment", systemEnv + "System.Globalization.CultureInfo", globalization + "System.Random", random + "System.Runtime.CompilerServices.TaskAwaiter`1", tasks + "System.Threading.CancellationToken", cancels + "System.Threading.CancellationTokenSource", cancels + "System.Threading.Monitor", monitor + "System.Threading.Tasks.Task`1", tasks + "System.Threading.Tasks.Task", tasks + "System.Activator", activator + "System.Text.Encoding", encoding + "System.Text.UnicodeEncoding", encoding + "System.Text.UTF8Encoding", encoding + "System.Text.RegularExpressions.Capture", regex + "System.Text.RegularExpressions.Match", regex + "System.Text.RegularExpressions.Group", regex + "System.Text.RegularExpressions.MatchCollection", regex + "System.Text.RegularExpressions.GroupCollection", regex + Types.regex, regex + Types.fsharpSet, sets + "Microsoft.FSharp.Collections.SetModule", setModule + Types.fsharpMap, maps + "Microsoft.FSharp.Collections.MapModule", mapModule + "Microsoft.FSharp.Control.FSharpMailboxProcessor`1", mailbox + "Microsoft.FSharp.Control.FSharpAsyncReplyChannel`1", mailbox + "Microsoft.FSharp.Control.FSharpAsyncBuilder", asyncBuilder + "Microsoft.FSharp.Control.AsyncActivation`1", asyncBuilder + "Microsoft.FSharp.Control.FSharpAsync", asyncs + "Microsoft.FSharp.Control.AsyncPrimitives", asyncs + "Microsoft.FSharp.Control.TaskBuilder", tasks + "Microsoft.FSharp.Control.TaskBuilderBase", taskBuilder + "Microsoft.FSharp.Control.TaskBuilderModule", taskBuilder + "Microsoft.FSharp.Control.TaskBuilderExtensions.HighPriority", taskBuilder + "Microsoft.FSharp.Control.TaskBuilderExtensions.LowPriority", taskBuilder + Types.guid, guids + "System.Uri", uris + "System.Lazy`1", laziness + "Microsoft.FSharp.Control.Lazy", laziness + "Microsoft.FSharp.Control.LazyExtensions", laziness + "Microsoft.FSharp.Control.CommonExtensions", controlExtensions + "Microsoft.FSharp.Control.FSharpEvent`1", events + "Microsoft.FSharp.Control.FSharpEvent`2", events + "Microsoft.FSharp.Control.EventModule", events + "Microsoft.FSharp.Control.ObservableModule", observable + Types.type_, types + "System.Reflection.TypeInfo", types ] let tryCall (com: ICompiler) (ctx: Context) r t (info: CallInfo) (thisArg: Expr option) (args: Expr list) = match info.DeclaringEntityFullName with @@ -4743,11 +4783,19 @@ let tryBaseConstructor com ctx (ent: Entity) (argTypes: Lazy) genArgs match argTypes.Value, args with | ([] | [ Number _ ]), - _ -> [ makeArray Any []; makeEqualityComparer com ctx (Seq.head genArgs) ] - | [ IDictionary ], [ arg ] -> [ arg; makeEqualityComparer com ctx (Seq.head genArgs) ] - | [ IDictionary; IEqualityComparer ], [ arg; eqComp ] -> [ arg; makeComparerFromEqualityComparer eqComp ] + _ -> + [ makeArray Any [] + makeEqualityComparer com ctx (Seq.head genArgs) ] + | [ IDictionary ], [ arg ] -> + [ arg + makeEqualityComparer com ctx (Seq.head genArgs) ] + | [ IDictionary; IEqualityComparer ], [ arg; eqComp ] -> + [ arg + makeComparerFromEqualityComparer eqComp ] | [ IEqualityComparer ], [ eqComp ] - | [ Number _; IEqualityComparer ], [ _; eqComp ] -> [ makeArray Any []; makeComparerFromEqualityComparer eqComp ] + | [ Number _; IEqualityComparer ], [ _; eqComp ] -> + [ makeArray Any [] + makeComparerFromEqualityComparer eqComp ] | _ -> failwith "Unexpected dictionary constructor" let entityName = Naming.cleanNameAsPyIdentifier "Dictionary" @@ -4755,10 +4803,18 @@ let tryBaseConstructor com ctx (ent: Entity) (argTypes: Lazy) genArgs | Types.hashset -> let args = match argTypes.Value, args with - | [], _ -> [ makeArray Any []; makeEqualityComparer com ctx (Seq.head genArgs) ] - | [ IEnumerable ], [ arg ] -> [ arg; makeEqualityComparer com ctx (Seq.head genArgs) ] - | [ IEnumerable; IEqualityComparer ], [ arg; eqComp ] -> [ arg; makeComparerFromEqualityComparer eqComp ] - | [ IEqualityComparer ], [ eqComp ] -> [ makeArray Any []; makeComparerFromEqualityComparer eqComp ] + | [], _ -> + [ makeArray Any [] + makeEqualityComparer com ctx (Seq.head genArgs) ] + | [ IEnumerable ], [ arg ] -> + [ arg + makeEqualityComparer com ctx (Seq.head genArgs) ] + | [ IEnumerable; IEqualityComparer ], [ arg; eqComp ] -> + [ arg + makeComparerFromEqualityComparer eqComp ] + | [ IEqualityComparer ], [ eqComp ] -> + [ makeArray Any [] + makeComparerFromEqualityComparer eqComp ] | _ -> failwith "Unexpected hashset constructor" let entityName = Naming.cleanNameAsPyIdentifier "HashSet"