Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 29 additions & 36 deletions FSharp.Interop.Dynamic/Dyn.fs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,13 @@
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.


// limitations under the License.

namespace FSharp.Interop.Dynamic
open System

type Calling =
| GenericMember of string * Type array
type Calling =
| GenericMember of string * Type array
| Member of string
| Direct

Expand All @@ -30,35 +29,31 @@ module Dyn =
let staticContext (target:Type) = InvokeContext.CreateStatic.Invoke(target)

let staticTarget<'TTarget> = InvokeContext.CreateStatic.Invoke(typeof<'TTarget>)
let implicitConvertTo (convertType:Type) (target:obj) : 'TResult =
match target with
let implicitConvertTo (convertType:Type) (target:obj) : 'TResult =
match target with
| null -> target
| t -> Dynamic.InvokeConvert(t, convertType, explicit = false)
|> unbox<'TResult>


| t -> Dynamic.InvokeConvert(t, convertType, explicit = false)
|> unbox<'TResult>

let implicitConvert(target:obj) : 'TResult =
implicitConvertTo typeof<'TResult> target


let explicitConvertTo (convertType:Type) (target:obj) : 'TResult =
implicitConvertTo typeof<'TResult> target

let explicitConvertTo (convertType:Type) (target:obj) : 'TResult =
Dynamic.InvokeConvert(target, convertType, explicit = true) |> unbox<'TResult>

let explicitConvert (target:obj) : 'TResult =
let explicitConvert (target:obj) : 'TResult =
explicitConvertTo typeof<'TResult> target

let namedArg (name:string) (argValue:obj) =
InvokeArg(name, argValue)

let memberAddAssign (memberName:string) (value:obj) (target:obj) =
Dynamic.InvokeAddAssignMember(target, memberName, value)


Dynamic.InvokeAddAssignMember(target, memberName, value)

let memberSubtractAssign (memberName:string) (value:obj) (target:obj) =
Dynamic.InvokeSubtractAssignMember(target, memberName, value)


Dynamic.InvokeSubtractAssignMember(target, memberName, value)

let invocation (target:obj) (memberName:Calling) : 'TResult =
let resultType = typeof<'TResult>
//Helper to dynamically call call FSharpFuncs
Expand All @@ -70,12 +65,12 @@ module Dyn =
| Member name -> Dynamic.InvokeGet(target', name)
| Direct -> target'
Dynamic.InvokeMember(invokeContext(start), invokeName, [|arg'|])
let (|NoConversion| Conversion|) t =
let (|NoConversion| Conversion|) t =
if t = typeof<obj> then NoConversion else Conversion
let finalConvertResult finalType result :'TResult =
let finalConvertResult finalType result :'TResult =
match finalType with
| x when FSharpType.IsFunction x -> // if return type is a function
let rec curriedLambda target type' arg' =
let rec curriedLambda target type' arg' =
let result' = fsharpInvoke target Direct arg'
let _,retType = FSharpType.GetFunctionElements type'
if FSharpType.IsFunction retType then
Expand All @@ -101,11 +96,11 @@ module Dyn =
| a when FSharpType.IsTuple(a) -> FSharpValue.GetTupleFields(arg)
| a when a = typeof<unit> -> [| |]
| ____________________________ -> [|arg|]
let invoker k =
let invoker k =
let memberName =
memberName |> function | GenericMember (name, targs) ->
InvokeMemberName(name, targs)
| Member name ->
| Member name ->
InvokeMemberName(name, null)
| Direct -> null
Invocation(k, memberName).Invoke(target, argArray)
Expand Down Expand Up @@ -136,13 +131,11 @@ module Dyn =
FSharpValue.MakeFunction(resultType, lambda) |> unbox<'TResult>

let invokeDirect value (target:obj) : 'TResult =
invocation target Direct value


invocation target Direct value

let invokeMember (memberName:string) value (target:obj) : 'TResult =
invocation target (Member memberName) value


invocation target (Member memberName) value

let invokeGeneric (memberName:string) (typeArgs:Type seq) value (target:obj) : 'TResult =
let typeArgs' = typeArgs |> Array.ofSeq
let genericMember = GenericMember (memberName, typeArgs')
Expand Down Expand Up @@ -184,7 +177,7 @@ module Dyn =
Dynamic.InvokeSet(target, propertyName, value) |> ignore

let setChain (chainOfMembers: string seq) (value:obj) (target:obj) =
let chainOfMembers' = String.concat "." chainOfMembers
let chainOfMembers' = String.concat "." chainOfMembers
Dynamic.InvokeSetChain(target, chainOfMembers', value) |> ignore

/// dynamically call set index
Expand All @@ -203,7 +196,7 @@ module Dyn =
[<Obsolete("Replaced with partial application version `memberAddAssign`")>]
let addAssignMember (target:obj) (memberName:string) (value:obj) =
target |> memberAddAssign memberName value
[<Obsolete("Replaced with partial application version `memberSubtractAssign`")>]
let subtractAssignMember (target:obj) (memberName:string) (value:obj) =
target |> memberSubtractAssign memberName value
Expand Down
4 changes: 2 additions & 2 deletions FSharp.Interop.Dynamic/Dyn.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace FSharp.Interop.Dynamic
| Member of string
/// Invoke the target itself, not a named member.
| Direct
/// <summary>
/// Function surface behind the operators. Use when you want piping, a name as data, or an operation <c>?</c> does not spell. Target is last on most members so <c>target |> Dyn.get "Name"</c> works; <c>invocation</c> is the exception.
/// </summary>
Expand Down Expand Up @@ -118,4 +118,4 @@ namespace FSharp.Interop.Dynamic
/// <summary>Obsolete. Use <c>invocation</c> with <c>Member</c> or <c>Direct</c> instead of <c>Some</c> name or <c>None</c>.</summary>
[<System.Obsolete("Replaced with `invocation`")>]
val invoke : target:obj -> memberName:string option -> 'TResult
end
end
40 changes: 19 additions & 21 deletions FSharp.Interop.Dynamic/Operators.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,52 +3,50 @@ namespace FSharp.Interop.Dynamic
module Operators=
open Dynamitey
open System.Linq.Expressions
let (?%?) (left:obj) (right: obj) : 'TResult =
let (?%?) (left:obj) (right: obj) : 'TResult =
(Dynamic.InvokeBinaryOperator(left, ExpressionType.Modulo, right)) :?> 'TResult
let (?*?) (left:obj) (right: obj) : 'TResult =
let (?*?) (left:obj) (right: obj) : 'TResult =
(Dynamic.InvokeBinaryOperator(left, ExpressionType.Multiply, right)) :?> 'TResult

let (?+?) (left:obj) (right: obj) : 'TResult =
let (?+?) (left:obj) (right: obj) : 'TResult =
(Dynamic.InvokeBinaryOperator(left, ExpressionType.Add, right)) :?> 'TResult
let (?-?) (left:obj) (right: obj) : 'TResult =
let (?-?) (left:obj) (right: obj) : 'TResult =
(Dynamic.InvokeBinaryOperator(left, ExpressionType.Subtract, right)) :?> 'TResult

let (?/?) (left:obj) (right: obj) : 'TResult =
let (?/?) (left:obj) (right: obj) : 'TResult =
(Dynamic.InvokeBinaryOperator(left, ExpressionType.Divide, right)) :?> 'TResult

let (?&&&?) (left:obj) (right: obj) : 'TResult =
let (?&&&?) (left:obj) (right: obj) : 'TResult =
(Dynamic.InvokeBinaryOperator(left, ExpressionType.And, right)) :?> 'TResult

let (?|||?) (left:obj) (right: obj) : 'TResult =
let (?|||?) (left:obj) (right: obj) : 'TResult =
(Dynamic.InvokeBinaryOperator(left, ExpressionType.Or, right)) :?> 'TResult

let (?^^^?) (left:obj) (right: obj) : 'TResult =
let (?^^^?) (left:obj) (right: obj) : 'TResult =
(Dynamic.InvokeBinaryOperator(left, ExpressionType.ExclusiveOr, right)) :?> 'TResult

let (?<<<?) (left:obj) (right: obj) : 'TResult =
let (?<<<?) (left:obj) (right: obj) : 'TResult =
(Dynamic.InvokeBinaryOperator(left, ExpressionType.LeftShift, right)) :?> 'TResult

let (?>>>?) (left:obj) (right: obj) : 'TResult =
let (?>>>?) (left:obj) (right: obj) : 'TResult =
(Dynamic.InvokeBinaryOperator(left, ExpressionType.RightShift, right)) :?> 'TResult

let (?<=?) (left:obj) (right: obj) : bool =
let (?<=?) (left:obj) (right: obj) : bool =
Dynamic.InvokeBinaryOperator(left, ExpressionType.LessThanOrEqual, right) |> Dyn.explicitConvert

let (?<>?) (left:obj) (right: obj) : bool =
let (?<>?) (left:obj) (right: obj) : bool =
Dynamic.InvokeBinaryOperator(left, ExpressionType.NotEqual, right) |> Dyn.explicitConvert

let (?<?) (left:obj) (right: obj) : bool =
let (?<?) (left:obj) (right: obj) : bool =
Dynamic.InvokeBinaryOperator(left, ExpressionType.LessThan, right) |> Dyn.explicitConvert

let (?=?) (left:obj) (right: obj) : bool =
let (?=?) (left:obj) (right: obj) : bool =
Dynamic.InvokeBinaryOperator(left, ExpressionType.Equal, right) |> Dyn.explicitConvert

let (?>?) (left:obj) (right: obj) : bool =
let (?>?) (left:obj) (right: obj) : bool =
Dynamic.InvokeBinaryOperator(left, ExpressionType.GreaterThan, right) |> Dyn.explicitConvert

let (?>=?) (left:obj) (right: obj) : bool =
Dynamic.InvokeBinaryOperator(left, ExpressionType.GreaterThanOrEqual, right) |> Dyn.explicitConvert


let (?>=?) (left:obj) (right: obj) : bool =
Dynamic.InvokeBinaryOperator(left, ExpressionType.GreaterThanOrEqual, right) |> Dyn.explicitConvert
2 changes: 1 addition & 1 deletion FSharp.Interop.Dynamic/Operators.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ namespace FSharp.Interop.Dynamic
val ( ?>? ) : left:obj -> right:obj -> bool
/// <summary>Dynamically compare whether <paramref name="left"/> is greater than or equal to <paramref name="right"/>. Converts the DLR result to <c>bool</c>.</summary>
val ( ?>=? ) : left:obj -> right:obj -> bool
end
end
17 changes: 8 additions & 9 deletions FSharp.Interop.Dynamic/SymbolicString.fs
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@ module SymbolicString =

/// Typed hole for quotations only. Do not evaluate; calling it throws.
let sym<'TTarget> : 'TTarget = failwith "don't call the sym function, meant for quotations only!"
/// Name, return type, and optional declaring type of a quoted leaf.
type LeafInfo =
type LeafInfo =
{ /// Return type of the quoted leaf.
ReturnType : System.Type
/// Member, union-case, or value name of the quoted leaf.
Name : string
/// Declaring type when the leaf is a member, field, union case, or call; None for a named value.
DeclaringType: System.Type option
}
/// Extracts name and type information from an F# quotation of a member, union case, or value.
type Symbol =

Expand All @@ -31,9 +31,9 @@ module SymbolicString =
static member leafInfoOf([<ReflectedDefinition>] value:Expr<'T>) : LeafInfo =
let rec finalName value' =
match value' with
| ValueWithName(_, type', name) ->
| ValueWithName(_, type', name) ->
{ ReturnType= type'; Name= name; DeclaringType = None }
| NewUnionCase(caseInfo, _) ->
| NewUnionCase(caseInfo, _) ->
{ ReturnType= caseInfo.DeclaringType
Name= caseInfo.Name
DeclaringType= Some <| caseInfo.DeclaringType }
Expand All @@ -53,10 +53,9 @@ module SymbolicString =
| Let(_,_, expr) -> finalName expr
| ________________________________ -> invalidArg "value" (sprintf "Couldn't figure out how to make '%A' a name" value)
finalName value
/// Member, union-case, or value name of the quoted leaf.
static member nameOf([<ReflectedDefinition>] value:Expr<'T>) : string = (value |> Symbol.leafInfoOf).Name
/// Return type of the quoted leaf.
static member typeOf([<ReflectedDefinition>] value:Expr<'T>) : System.Type = (value |> Symbol.leafInfoOf).ReturnType

static member typeOf([<ReflectedDefinition>] value:Expr<'T>) : System.Type = (value |> Symbol.leafInfoOf).ReturnType
7 changes: 3 additions & 4 deletions FSharp.Interop.Dynamic/TopLevelOperators.fs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

namespace FSharp.Interop.Dynamic


namespace FSharp.Interop.Dynamic

[<AutoOpen>]
module TopLevelOperators=
let (?) (target : obj) (name:string) : 'TResult =
Expand All @@ -25,4 +24,4 @@ module TopLevelOperators=
target |> Dyn.set name value

let (!?) (target:obj) : 'TResult =
Dyn.invocation target Direct
Dyn.invocation target Direct
2 changes: 1 addition & 1 deletion FSharp.Interop.Dynamic/TopLevelOperators.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ namespace FSharp.Interop.Dynamic
/// <paramref name="target"/>.
/// </returns>
val ( !? ) : target:obj -> 'TResult
end
end
2 changes: 1 addition & 1 deletion Tests/Invocation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,4 @@ module Invocation =
[<Fact>]
let ``a throwing getter is not wrapped after a binder failure`` () =
(fun () -> PropThrows() |> Dyn.invokeMember "Bad" () |> ignore)
|> should throw typeof<InvalidOperationException>
|> should throw typeof<InvalidOperationException>
Loading
Loading