-
Notifications
You must be signed in to change notification settings - Fork 24
UserGuide
Unquote targets netstandard2.0 and FSharp.Core 8.0.100.
To use Unquote, install the latest version via NuGet
You must also obtain and install your unit testing framework of choice separately (NUnit, xUnit.net, and Fuchu/Expecto have been given special support, but any exception-based unit testing framework including MSTest is supported as well).
To use Unquote within FSI, locate and add a reference to Unquote.dll using the #r directive (.NET 4.5 build).
- Support for .NET 4.0 and PCL builds dropped
- The long obsolete '?' suffixed have been removed
Support for Silverlight 4 has been dropped.
The '?' suffixed operators have all been replaced with equivalent '!' suffixed operators in Unquote 3.0.0 in order to avoid conflicts with Nullable operators introduced by F# 3.0. You may open the package Swensen.Unquote.Assertions.Obsolete to continue using the now obsolete '?' suffixed operators.
The signature of Swensen.Unquote.Operators.unquote has been changed from Quotations.Expr -> unit to Quotations.Expr -> UnquotedExpression.
The Swensen.Unquote namespace contains three AutoOpen modules: Assertions, Operators, and Extensions. Therefore you may choose to bring all of Unquote's features into top-level scope simply by opening Swensen.Unquote or you may choose to open individual modules or even alias individual modules for a finer level of control.
The Swensen.Unquote.Assertions module contains all functions used for performing unit testing assertions. These include test, raises, and a series of '!' suffixed binary infix operators. All of these operators can be used within a unit test enabled project or FSI.
Unquote chooses its output source as follows
- if loaded in FSI then print to the console (unless Fuchu is loaded)
- else if xUnit or NUnit loaded in currently executing assembly, then use appropriate test failed methods
- else throw a
Swensen.Unquote.AssertionFailedExceptionwith a message
The following is a reference of the functions available and some examples:
val inline test : Quotations.Expr<bool> -> unit
> test <@ (1+2)/3 = 1 @>;;
val it : unit = ()
> test <@ (1+2)/3 = 2 @>;;
Test failed:
(1 + 2) / 3 = 2
3 / 3 = 2
1 = 2
false
val it : unit = ()
val inline ( =! ) : 'a -> 'a -> unit when 'a : equality
> [1;2;3;4] =! [4;3;2;1];;
Test failed:
[1; 2; 3; 4] = [4; 3; 2; 1]
false
val it : unit = ()
val inline ( <! ) : 'a -> 'a -> unit when 'a : comparisonval inline ( >! ) : 'a -> 'a -> unit when 'a : comparisonval inline ( <=! ) : 'a -> 'a -> unit when 'a : comparisonval inline ( >=! ) : 'a -> 'a -> unit when 'a : comparisonval inline ( <>! ) : 'a -> 'a -> unit when 'a : equalityval inline raises<'a when 'a :> exn> : Quotations.Expr -> unit
> raises<exn> <@ (null:string).Length @>;;
val it : unit = ()
> raises<NullReferenceException> <@ (null:string).Length @>;;
val it : unit = ()
> raises<System.ArgumentException> <@ (null:string).Length @>;;
Test failed:
Expected exception of type 'ArgumentException', but 'NullReferenceException' was raised instead
null.Length
System.NullReferenceException: Object reference not set to an instance of an object.
at Swensen.Unquote.Evaluation.evalInstance@275(FSharpList`1 env, FSharpOption`1 expr)
at Swensen.Unquote.Evaluation.eval@133(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.reduce(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.loop@132(FSharpList`1 env, FSharpExpr expr, FSharpList`1 acc)
val it : unit = ()
> raises<exn> <@ 3 @>;;
Test failed:
Expected exception of type 'Exception', but no exception was raised
3
val it : unit = ()
val inline raisesWith : Expr -> (#exn -> Expr<bool>) -> unit
> raisesWith<System.NullReferenceException> <@ (null:string).Length @> (fun e -> <@ e.ToString() = null @>);;
Test failed:
The expected exception was raised, but the exception assertion failed:
Exception Assertion:
System.NullReferenceException: Object reference not set to an instance of an object.
at Swensen.Unquote.Evaluation.evalInstance@275(FSharpList`1 env, FSharpOption`1 expr)
at Swensen.Unquote.Evaluation.eval@133(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.reduce(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.loop@132(FSharpList`1 env, FSharpExpr expr, FSharpList`1 acc).ToString() = null
"System.NullReferenceException: Object reference not set to an instance of an object.
at Swensen.Unquote.Evaluation.evalInstance@275(FSharpList`1 env, FSharpOption`1 expr)
at Swensen.Unquote.Evaluation.eval@133(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.reduce(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.loop@132(FSharpList`1 env, FSharpExpr expr, FSharpList`1 acc)" = null
false
Test Expression:
null.Length
System.NullReferenceException: Object reference not set to an instance of an object.
at Swensen.Unquote.Evaluation.evalInstance@275(FSharpList`1 env, FSharpOption`1 expr)
at Swensen.Unquote.Evaluation.eval@133(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Evaluation.eval(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.reduce(FSharpList`1 env, FSharpExpr expr)
at Swensen.Unquote.Reduction.loop@132(FSharpList`1 env, FSharpExpr expr, FSharpList`1 acc)
val it : unit = ()
The Swensen.Unquote.Operators module contains additional functions for decompiling, evaluating, and reducing quotation expressions. The following is a reference of the functions available and some examples:
val inline decompile : Quotations.Expr -> string
> decompile <@ (1+2)/3 @>;;
val it : string = "(1 + 2) / 3"
val inline eval : Quotations.Expr<'a> -> 'a
> eval <@ "Hello World".Length + 20 @>;;
val it : int = 31
val inline evalRaw : Quotations.Expr -> 'a
> evalRaw<int> <@@ "Hello World".Length + 20 @@>;;
val it : int = 31
val inline reduce : Quotations.Expr -> Quotations.Expr
> <@ (1+2)/3 @> |> reduce |> decompile;;
val it : string = "3 / 3"
val inline reduceFully : Quotations.Expr -> Quotations.Expr list
> <@ (1+2)/3 @> |> reduceFully |> List.map decompile;;
val it : string list = ["(1 + 2) / 3"; "3 / 3"; "1"]
val inline isReduced : Quotations.Expr -> bool
> <@ (1+2)/3 @> |> isReduced;;
val it : bool = false
> <@ 1 @> |> isReduced;;
val it : bool = true
val inline unquote : Quotations.Expr -> UnquotedExpression
> unquote <@ (1+2)/3 @>;;
val it : UnquotedExpression =
(1 + 2) / 3
3 / 3
1
val it : unit = ()
The following are functions which accept a variable environment for processing synthetic expressions with unbound variables:
val inline evalWith : Map<Var,obj> -> Quotations.Expr<'a> -> 'aval inline evalRawWith : Map<Var,obj> -> Expr -> 'aval inline reduceWith : Map<Var,obj> -> Quotations.Expr<'a> -> Quotations.Exprval inline reduceFullyWith : Map<Var,obj> -> Quotations.Expr<'a> -> Quotations.Expr list
The Swensen.Unquote.Extensions module duplicates functions in the Swensen.Unquote.Operators as instance type extensions on Quotations.Expr and Quotations.Expr<'a>. But it also includes an instance property extension on System.Type, FSharpName, which returns the F#-style signature of a type:
> typeof<int>.FSharpName;;
val it : string = "int"
> typeof<int[]>.FSharpName;;
val it : string = "int[]"
> typeof<int[,,,]>.FSharpName;;
val it : string = "int[,,,]"
> typeof<System.Collections.Generic.Dictionary<string, float>>.FSharpName;;
val it : string = "Dictionary<string, float>"
> typeof<unit -> int -> string>.FSharpName;;
val it : string = "unit -> int -> string"
> typeof<unit -> (float -> int) -> string>.FSharpName;;
val it : string = "unit -> (float -> int) -> string"
> typeof<int * float * string>.FSharpName;;
val it : string = "int * float * string"
> typeof<int * (bool * float) * string>.FSharpName;;
val it : string = "int * (bool * float) * string"
> typeof<int -> (list<(int * (int -> string))[]> * string[,,])>.FSharpName;;
val it : string = "int -> list<(int * (int -> string))[]> * string[,,]"
> typedefof<int -> int>.FSharpName;;
val it : string = "'T -> 'TResult"