Skip to content

Commit

Permalink
WIP #660 Erased Optional type
Browse files Browse the repository at this point in the history
  • Loading branch information
Jand42 committed Feb 18, 2017
1 parent 3ea717c commit a02826e
Show file tree
Hide file tree
Showing 13 changed files with 257 additions and 43 deletions.
40 changes: 39 additions & 1 deletion src/compiler/WebSharper.Compiler/Recognize.fs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,41 @@ let setValue (env: Environment) expr value =
let glob = Global []
let wsruntime = Global ["IntelliFactory"; "Runtime"]

let wsRuntimeFunctions =
System.Collections.Generic.HashSet [
"Ctor"
"Cctor"
"Class"
"NewObject"
"DeleteEmptyFields"
"GetOptional"
"SetOptional"
"SetOrDelete"
"Bind"
"CreateFuncWithArgs"
"CreateFuncWithOnlyThis"
"CreateFuncWithThis"
"CreateFuncWithThisArgs"
"CreateFuncWithRest"
"CreateFuncWithArgsRest"
"BindDelegate"
"CreateDelegate"
"CombineDelegates"
"DelegateEqual"
"ThisFunc"
"ThisFuncOut"
"ParamsFunc"
"ParamsFuncOut"
"ThisParamsFunc"
"ThisParamsFuncOut"
"Curried"
"Curried2"
"Curried3"
"Apply"
"PipeApply"
"UnionByType"
]

let rec transformExpression (env: Environment) (expr: S.Expression) =
let inline trE e = transformExpression env e
let checkNotMutating a f =
Expand Down Expand Up @@ -189,7 +224,10 @@ let rec transformExpression (env: Environment) (expr: S.Expression) =
if trA = wsruntime then
match trC with
| Value (String f) ->
Global ["IntelliFactory"; "Runtime"; f]
if wsRuntimeFunctions.Contains f then
Global ["IntelliFactory"; "Runtime"; f]
else
failwithf "Unrecognized IntelliFactory.Runtime function: %s" f
| _ -> failwith "expected a function of IntelliFactory.Runtime"
elif env.IsPure then ItemGet(trA, trC)
else ItemGetNonPure(trA, trC)
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/WebSharper.Compiler/Translator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,7 @@ type DotNetToJavaScript private (comp: Compilation, ?inProgress) =
let t = typ.Entity
if erasedUnions.Contains t then
match args with
| [] -> Undefined
| [ a ] -> this.TransformExpression a
| _ -> this.Error("Erased union constructor expects a single argument")
else
Expand All @@ -992,6 +993,10 @@ type DotNetToJavaScript private (comp: Compilation, ?inProgress) =

override this.TransformUnionCaseTest(expr, typ, case) =
if erasedUnions.Contains typ.Entity then
match case with
| "Undefined" -> this.TransformExpression expr ^=== Undefined
| "Defined" -> this.TransformExpression expr ^!== Undefined
| _ ->
let i = int case.[5] - 49 // int '1' is 49
try
this.TransformTypeCheck(expr, typ.Generics.[i])
Expand Down
28 changes: 10 additions & 18 deletions src/compiler/WebSharper.Compiler/WIGCompile.fs
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,9 @@ type InlineGenerator() =

member g.GetMethodBaseInline(td: Code.TypeDeclaration, t: T, m: Code.MethodBase) =
let withOutTransform retT mInl =
let withInterop t =
match t with
| Type.InteropType (_, tr) -> tr.Out mInl
| _ -> mInl
match retT with
| Type.OptionType rt -> "$wsruntime.GetOptional(" + withInterop rt + ")"
| rt -> withInterop rt
match retT with
| Type.InteropType (_, tr) -> tr.Out mInl
| _ -> mInl
let t, interop =
match t with
| Type.NoInteropType t -> t, false
Expand Down Expand Up @@ -131,13 +127,9 @@ type InlineGenerator() =

member g.GetPropertyGetterInline(td: Code.TypeDeclaration, t: T, p: Code.Property) =
let withOutTransform inl =
let withInterop t =
match t with
| Type.InteropType (_, tr) -> tr.Out inl
| _ -> inl
match t with
| Type.OptionType t -> "$wsruntime.GetOptional(" + withInterop t + ")"
| _ -> withInterop t
match t with
| Type.InteropType (_, tr) -> tr.Out inl
| _ -> inl
let index() =
match p.IndexerType with
| Some (Type.InteropType (_, tr)) -> tr.In "$index"
Expand Down Expand Up @@ -211,13 +203,13 @@ type InlineGenerator() =
if opt then
if name = "" then
if p.IndexerType.IsSome
then sprintf "$wsruntime.SetOptional(%s, %s, %s)" pfx (index()) value
then sprintf "$wsruntime.SetOrDelete(%s, %s, %s)" pfx (index()) value
else failwith "Optional property with empty name not allowed."
else
if p.IndexerType.IsSome then
sprintf "$wsruntime.SetOptional(%s, %s, %s)" (prop()) (index()) value
sprintf "$wsruntime.SetOrDelete(%s, %s, %s)" (prop()) (index()) value
else
sprintf "$wsruntime.SetOptional(%s, '%s', %s)" pfx name value
sprintf "$wsruntime.SetOrDelete(%s, '%s', %s)" pfx name value
else
let ind = if p.IndexerType.IsSome then "[" + index() + "]" else ""
if name = "" then sprintf "void (%s%s = %s)" pfx ind value
Expand Down Expand Up @@ -261,7 +253,6 @@ type TypeBuilder(aR: IAssemblyResolver, out: AssemblyDefinition, fsCoreFullName:
|> main.Import

let funcType = fromFsCore "FSharpFunc`2"
let optionType = fromFsCore "FSharpOption`1"

let fromSystem (name: string) =
mscorlib.MainModule.GetType("System", name)
Expand Down Expand Up @@ -337,6 +328,7 @@ type TypeBuilder(aR: IAssemblyResolver, out: AssemblyDefinition, fsCoreFullName:
let funcWithThis = fromInterop "FuncWithThis`2"
let funcWithOnlyThis = fromInterop "FuncWithOnlyThis`2"
let funcWithArgsRest = fromInterop "FuncWithArgsRest`3"
let optionType = fromInterop "Optional`1"

member b.Action ts =
commonType mscorlib "System" "Action" ts
Expand Down
9 changes: 9 additions & 0 deletions src/compiler/WebSharper.Core.JavaScript/Runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ IntelliFactory = {
}
},

SetOrDelete:
function (obj, field, value) {
if (value !== void (0)) {
obj[field] = value;
} else {
delete obj[field];
}
},

Bind: function (f, obj) {
return function () { return f.apply(this, arguments) };
},
Expand Down
6 changes: 5 additions & 1 deletion src/compiler/WebSharper.Core/ASTHelpers.fs
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,14 @@ let (|UnaryOpName|_|) = function
let erasedUnions =
System.Collections.Generic.HashSet (
seq {
yield TypeDefinition {
Assembly = "WebSharper.Core"
FullName = "WebSharper.JavaScript.Optional`1"
}
for i in 2 .. 7 ->
TypeDefinition {
Assembly = "WebSharper.Core"
FullName = "WebSharper.JavaScript.Union`" + string i
}
}
}
)
33 changes: 33 additions & 0 deletions src/compiler/WebSharper.Core/Interop.fs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ type FuncWithArgsRest<'TArgs, 'TRest, 'TResult> =
new (func: 'TArgs * 'TRest[] -> 'TResult) = { }
member this.Call (args: 'TArgs, [<PA>] rest: 'TRest[]) = X<'TResult>

type Optional<'T> =
| Undefined
| Defined of 'T

member this.Value = X<'T>

// {{ generated by genInterop.fsx, do not modify
type FuncWithRest<'TRest, 'TResult> =
inherit Function
Expand Down Expand Up @@ -298,28 +304,48 @@ type ThisParamsFunc<'TThis, 'T1, 'T2, 'T3, 'T4, 'T5, 'T6, 'TParams, 'TResult> =
type Union<'T1, 'T2> =
| Union1Of2 of 'T1
| Union2Of2 of 'T2
member this.Value1 = X<'T1>
member this.Value2 = X<'T2>
type Union<'T1, 'T2, 'T3> =
| Union1Of3 of 'T1
| Union2Of3 of 'T2
| Union3Of3 of 'T3
member this.Value1 = X<'T1>
member this.Value2 = X<'T2>
member this.Value3 = X<'T3>
type Union<'T1, 'T2, 'T3, 'T4> =
| Union1Of4 of 'T1
| Union2Of4 of 'T2
| Union3Of4 of 'T3
| Union4Of4 of 'T4
member this.Value1 = X<'T1>
member this.Value2 = X<'T2>
member this.Value3 = X<'T3>
member this.Value4 = X<'T4>
type Union<'T1, 'T2, 'T3, 'T4, 'T5> =
| Union1Of5 of 'T1
| Union2Of5 of 'T2
| Union3Of5 of 'T3
| Union4Of5 of 'T4
| Union5Of5 of 'T5
member this.Value1 = X<'T1>
member this.Value2 = X<'T2>
member this.Value3 = X<'T3>
member this.Value4 = X<'T4>
member this.Value5 = X<'T5>
type Union<'T1, 'T2, 'T3, 'T4, 'T5, 'T6> =
| Union1Of6 of 'T1
| Union2Of6 of 'T2
| Union3Of6 of 'T3
| Union4Of6 of 'T4
| Union5Of6 of 'T5
| Union6Of6 of 'T6
member this.Value1 = X<'T1>
member this.Value2 = X<'T2>
member this.Value3 = X<'T3>
member this.Value4 = X<'T4>
member this.Value5 = X<'T5>
member this.Value6 = X<'T6>
type Union<'T1, 'T2, 'T3, 'T4, 'T5, 'T6, 'T7> =
| Union1Of7 of 'T1
| Union2Of7 of 'T2
Expand All @@ -328,4 +354,11 @@ type Union<'T1, 'T2, 'T3, 'T4, 'T5, 'T6, 'T7> =
| Union5Of7 of 'T5
| Union6Of7 of 'T6
| Union7Of7 of 'T7
member this.Value1 = X<'T1>
member this.Value2 = X<'T2>
member this.Value3 = X<'T3>
member this.Value4 = X<'T4>
member this.Value5 = X<'T5>
member this.Value6 = X<'T6>
member this.Value7 = X<'T7>
// }}
2 changes: 2 additions & 0 deletions src/compiler/WebSharper.Core/genInterop.fsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ let code =
cprintfn "type Union<%s> =" (tArgs i |> String.concat ", ")
for j = 1 to i do
cprintfn " | Union%dOf%d of 'T%d" j i j
for j = 1 to i do
cprintfn " member this.Value%d = X<'T%d>" j j

code.ToArray()

Expand Down
101 changes: 101 additions & 0 deletions src/stdlib/WebSharper.Main/Interop.fs
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,14 @@ type FuncWithArgsRestProxy<'TArgs, 'TRest, 'TResult> =
[<Inline "$this.apply(null, $args.concat($rest))">]
member this.Call (args: 'TArgs, [<PA>] rest: 'TRest[]) = Unchecked.defaultof<'TResult>

[<Proxy(typeof<Optional<_>>)>]
type Optional<'T> =
| Undefined
| Defined of 'T

[<Inline>]
member this.Value = As<'T> this

// {{ generated by genInterop.fsx, do not modify
[<Proxy (typeof<ThisAction<_>>)>]
type ThisActionProxy<'TThis> =
Expand Down Expand Up @@ -451,4 +459,97 @@ type ThisParamsFuncProxy<'TThis, 'T1, 'T2, 'T3, 'T4, 'T5, 'T6, 'TParams, 'TResul
member this.Bind(thisArg: 'TThis) = X<ParamsFunc<'T1, 'T2, 'T3, 'T4, 'T5, 'T6, 'TParams, 'TResult>>
[<Macro(typeof<Macro.JSThisParamsCall>)>]
member this.Call(thisArg: 'TThis, arg1: 'T1, arg2: 'T2, arg3: 'T3, arg4: 'T4, arg5: 'T5, arg6: 'T6, [<PA>] rest: 'TParams[]) = X<'TResult>
[<Proxy (typeof<Union<_,_>>)>]
type UnionProxy<'T1, 'T2> =
| Union1Of2 of 'T1
| Union2Of2 of 'T2
[<Inline>]
member this.Value1 = As<'T1> this
[<Inline>]
member this.Value2 = As<'T2> this
[<Proxy (typeof<Union<_,_,_>>)>]
type UnionProxy<'T1, 'T2, 'T3> =
| Union1Of3 of 'T1
| Union2Of3 of 'T2
| Union3Of3 of 'T3
[<Inline>]
member this.Value1 = As<'T1> this
[<Inline>]
member this.Value2 = As<'T2> this
[<Inline>]
member this.Value3 = As<'T3> this
[<Proxy (typeof<Union<_,_,_,_>>)>]
type UnionProxy<'T1, 'T2, 'T3, 'T4> =
| Union1Of4 of 'T1
| Union2Of4 of 'T2
| Union3Of4 of 'T3
| Union4Of4 of 'T4
[<Inline>]
member this.Value1 = As<'T1> this
[<Inline>]
member this.Value2 = As<'T2> this
[<Inline>]
member this.Value3 = As<'T3> this
[<Inline>]
member this.Value4 = As<'T4> this
[<Proxy (typeof<Union<_,_,_,_,_>>)>]
type UnionProxy<'T1, 'T2, 'T3, 'T4, 'T5> =
| Union1Of5 of 'T1
| Union2Of5 of 'T2
| Union3Of5 of 'T3
| Union4Of5 of 'T4
| Union5Of5 of 'T5
[<Inline>]
member this.Value1 = As<'T1> this
[<Inline>]
member this.Value2 = As<'T2> this
[<Inline>]
member this.Value3 = As<'T3> this
[<Inline>]
member this.Value4 = As<'T4> this
[<Inline>]
member this.Value5 = As<'T5> this
[<Proxy (typeof<Union<_,_,_,_,_,_>>)>]
type UnionProxy<'T1, 'T2, 'T3, 'T4, 'T5, 'T6> =
| Union1Of6 of 'T1
| Union2Of6 of 'T2
| Union3Of6 of 'T3
| Union4Of6 of 'T4
| Union5Of6 of 'T5
| Union6Of6 of 'T6
[<Inline>]
member this.Value1 = As<'T1> this
[<Inline>]
member this.Value2 = As<'T2> this
[<Inline>]
member this.Value3 = As<'T3> this
[<Inline>]
member this.Value4 = As<'T4> this
[<Inline>]
member this.Value5 = As<'T5> this
[<Inline>]
member this.Value6 = As<'T6> this
[<Proxy (typeof<Union<_,_,_,_,_,_,_>>)>]
type UnionProxy<'T1, 'T2, 'T3, 'T4, 'T5, 'T6, 'T7> =
| Union1Of7 of 'T1
| Union2Of7 of 'T2
| Union3Of7 of 'T3
| Union4Of7 of 'T4
| Union5Of7 of 'T5
| Union6Of7 of 'T6
| Union7Of7 of 'T7
[<Inline>]
member this.Value1 = As<'T1> this
[<Inline>]
member this.Value2 = As<'T2> this
[<Inline>]
member this.Value3 = As<'T3> this
[<Inline>]
member this.Value4 = As<'T4> this
[<Inline>]
member this.Value5 = As<'T5> this
[<Inline>]
member this.Value6 = As<'T6> this
[<Inline>]
member this.Value7 = As<'T7> this
// }}
Loading

0 comments on commit a02826e

Please sign in to comment.