// [snippet:Evaluate expression] open System open Microsoft.FSharp.Reflection open Microsoft.FSharp.Quotations open Microsoft.FSharp.Quotations.Patterns /// Evaluates expression untyped let rec eval = function | Value(v,t) -> v | Coerce(e,t) -> eval e | NewObject(ci,args) -> ci.Invoke(evalAll args) | NewArray(t,args) -> let array = Array.CreateInstance(t, args.Length) args |> List.iteri (fun i arg -> array.SetValue(eval arg, i)) box array | NewUnionCase(case,args) -> FSharpValue.MakeUnion(case, evalAll args) | NewRecord(t,args) -> FSharpValue.MakeRecord(t, evalAll args) | NewTuple(args) -> let t = FSharpType.MakeTupleType [|for arg in args -> arg.Type|] FSharpValue.MakeTuple(evalAll args, t) | FieldGet(Some(Value(v,_)),fi) -> fi.GetValue(v) | PropertyGet(None, pi, args) -> pi.GetValue(null, evalAll args) | PropertyGet(Some(x),pi,args) -> pi.GetValue(eval x, evalAll args) | Call(None,mi,args) -> mi.Invoke(null, evalAll args) | Call(Some(x),mi,args) -> mi.Invoke(eval x, evalAll args) | arg -> raise <| NotSupportedException(arg.ToString()) and evalAll args = [|for arg in args -> eval arg|] // [/snippet] type PersonRecord = { Name:string; Age:int } type PersonClass (name, age) = member val Name = name member val Age = age override a.GetHashCode() = hash a.Name ^^^ hash a.Age override a.Equals(b) = b |> function | :? PersonClass as b -> a.Name = b.Name && a.Age = b.Age | _ -> false // [snippet:Unit tests] open NUnit.Framework type Tests () = static member Expressions = let (==) quote value = TestCaseData([|quote|]).Returns(value) [ <@ 1 @> == 1 <@ 1 + 1 @> == 2 <@ 2 * 2 @> == 4 <@ 9.9M @> == 9.9M <@ "Hello World" @> == "Hello World" <@ [1;2;3] @> == [1;2;3] <@ [|1;2;3|] @> == [|1;2;3|] <@ (1,2,3) @> == (1,2,3) <@ Some(1) @> == Some(1) <@ {Name="Phil"; Age=27} @> == {Name = "Phil"; Age=27} <@ PersonClass("Phil", 27) @> == PersonClass("Phil", 27) ] [] static member ``evaluates`` (expr:Expr) = eval expr member test.LocalProperty = 1 [] member test.``local property getter`` () = Assert.AreEqual(test.LocalProperty, eval <@ test.LocalProperty @>) member test.LocalMethod() = 1 [] member test.``local property method`` () = Assert.AreEqual(test.LocalMethod(), eval <@ test.LocalMethod() @>) static member GlobalProperty = 1 [] member test.``global property getter`` () = Assert.AreEqual(Tests.GlobalProperty, eval <@ Tests.GlobalProperty @>) static member GlobalMethod() = 1 [] member test.``global property method`` () = Assert.AreEqual(Tests.GlobalMethod(), eval <@ Tests.GlobalMethod() @>) // [/snippet]