Skip to content

Commit

Permalink
#881 Re-add WS4.0 logic of ClientSide as a fallback
Browse files Browse the repository at this point in the history
  • Loading branch information
Jand42 committed Jan 8, 2018
1 parent b617ee7 commit d881871
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 6 deletions.
10 changes: 9 additions & 1 deletion src/compiler/WebSharper.Compiler.FSharp/CodeReader.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1157,7 +1157,15 @@ let scanExpression (env: Environment) (containingMethodName: string) (expr: FSha
let f = Lambda([ for (_, id, _) in env.FreeVars -> id ], e)
// emptying FreeVars so that env can be reused for reading multiple quotation arguments
env.FreeVars.Clear()
quotations.Add(pos, qm, argNames, f)
// if the quotation is a single static call, the runtime fallback will be able to
// handle it without introducing a pre-compiled function for it
let isTrivial =
match e with
| I.Call(None, _, _, args) ->
args |> List.forall (function I.Var _ | I.Value _ -> true | _ -> false)
| _ -> false
if not isTrivial then
quotations.Add(pos, qm, argNames, f)
)
)
| _ -> default'()
Expand Down
51 changes: 46 additions & 5 deletions src/sitelets/WebSharper.Web/Control.fs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,49 @@ module ClientSideInternals =
| None -> failwithf "Failed to find location of quotation: %A" q
compile reqs q

type private FSV = Reflection.FSharpValue

let internal compileClientSideFallback (elt: Expr) =
let declType, meth, args, fReqs, subs =
let elt =
match elt with
| Coerce (e, _) -> e
| e -> e
let rec get subs expr =
match expr with
| PropertyGet(None, p, args) ->
let m = p.GetGetMethod(true)
let dt = R.ReadTypeDefinition p.DeclaringType
let meth = R.ReadMethod m
dt, meth, args, [M.MethodNode (dt, meth)], subs
| Call(None, m, args) ->
let dt = R.ReadTypeDefinition m.DeclaringType
let meth = R.ReadMethod m
dt, meth, args, [M.MethodNode (dt, meth)], subs
| Let(var, value, body) ->
get (subs |> Map.add var value) body
| e -> failwithf "Wrong format for InlineControl at %s: expected global value or function access, got: %A" (getLocation' elt) e
get Map.empty elt
let args, argReqs =
args
|> List.mapi (fun i value ->
let rec get expr =
match expr with
| Value (v, t) ->
let v = match v with null -> WebSharper.Core.Json.Internal.MakeTypedNull t | _ -> v
v, M.TypeNode (R.ReadTypeDefinition t)
| TupleGet(v, i) ->
let v, n = get v
FSV.GetTupleField(v, i), n
| Var v when subs.ContainsKey v ->
get subs.[v]
| _ -> failwithf "Wrong format for InlineControl at %s: argument #%i is not a literal or a local variable" (getLocation' elt) (i+1)
get value
)
|> List.unzip
let args = Array.ofList args
args, declType, meth, fReqs @ argReqs

open ClientSideInternals

/// Implements a web control based on a quotation-wrapped top-level body.
Expand Down Expand Up @@ -280,11 +323,9 @@ type InlineControl<'T when 'T :> IControlBody>(elt: Expr<'T>) =
args <- argVals
ty, m, deps
| false, _ ->
let all =
meta.Quotations.Keys
|> Seq.map (sprintf " %O")
|> String.concat "\n"
failwithf "Failed to find compiled quotation at position %O\nExisting ones:\n%O" p all
let argVals, ty, m, deps = compileClientSideFallback elt
args <- argVals
ty, m, deps

// set funcName
let fail() =
Expand Down

0 comments on commit d881871

Please sign in to comment.