| | | 1 | | namespace FSharp.Interop.Dlr |
| | | 2 | | |
| | | 3 | | open System |
| | | 4 | | open System.Dynamic |
| | | 5 | | open System.Linq.Expressions |
| | | 6 | | open System.Reflection |
| | | 7 | | open System.Runtime.CompilerServices |
| | | 8 | | open Microsoft.CSharp.RuntimeBinder |
| | | 9 | | open FSharp.Quotations |
| | | 10 | | |
| | | 11 | | /// Raised when a `dlr { }` body uses something the translator does not handle. |
| | | 12 | | type DlrTranslationException = |
| | | 13 | | inherit Exception |
| | | 14 | | new(message: string) = { inherit Exception(message) } |
| | | 15 | | /// With the failure that caused it, whose stack a message alone loses. |
| | | 16 | | new(message: string, inner: exn) = { inherit Exception(message, inner) } |
| | | 17 | | |
| | | 18 | | /// Control-flow helpers the compiled block calls: `LeafExpressionConverter` cannot translate F# loop |
| | | 19 | | /// or try nodes, but it can translate lambdas, so those become calls to these with the bodies as lambdas. |
| | | 20 | | /// |
| | | 21 | | /// The bodies are plain delegates (`Func`, returning `unit` where there is nothing to return - a |
| | | 22 | | /// quoted `unit` body is not `void`, so `Action` cannot take it), not F# functions. Quoting them as F# lambdas |
| | | 23 | | /// would have `LeafExpressionConverter` wrap each compiled delegate in an `FSharpFunc` via |
| | | 24 | | /// `FuncConvert`, and on Mono's browser-wasm runtime a non-capturing nested lambda invoked through |
| | | 25 | | /// that wrapper loses its argument (a `try .. with` handler saw a null exception; `fun i -> i + 1` |
| | | 26 | | /// returned 1) while the same delegate invoked directly is fine. The translator therefore emits |
| | | 27 | | /// `NewDelegate` nodes, which convert to the delegate lambda itself with nothing in between. |
| | | 28 | | /// Not part of the supported API: public only because compiled blocks call it, and it may change in any release. |
| | | 29 | | [<System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)>] |
| | | 30 | | module DlrRuntime = |
| | | 31 | | /// `for x in items do body x` |
| | | 32 | | let forEach (items: seq<'T>) (body: Func<'T, unit>) : unit = |
| | 23869 | 33 | | for x in items do body.Invoke x |
| | | 34 | | |
| | | 35 | | /// `while guard () do body ()` |
| | | 36 | | let whileLoop (guard: Func<bool>) (body: Func<unit>) : unit = |
| | 744 | 37 | | while guard.Invoke() do body.Invoke() |
| | | 38 | | |
| | | 39 | | /// `for i in low .. high do body i` (F#'s ForIntegerRangeLoop: step 1, bounds evaluated once) |
| | | 40 | | let forRange (low: int) (high: int) (body: Func<int, unit>) : unit = |
| | 672 | 41 | | for i in low .. high do body.Invoke i |
| | | 42 | | |
| | | 43 | | /// `try body () with e -> handler e` (F# already puts the rethrow of unmatched exceptions in `handler`) |
| | | 44 | | let tryWith (body: Func<'T>) (handler: Func<exn, 'T>) : 'T = |
| | 15672 | 45 | | try body.Invoke() with e -> handler.Invoke e |
| | | 46 | | |
| | | 47 | | /// `reraise ()` in a handler that runs as a delegate (above), outside any catch block: the |
| | | 48 | | /// caught exception thrown again with its original stack trace, as a rethrow keeps it. |
| | | 49 | | let rethrow<'T> (e: exn) : 'T = |
| | 104 | 50 | | System.Runtime.ExceptionServices.ExceptionDispatchInfo.Capture(e).Throw() |
| | 0 | 51 | | Unchecked.defaultof<'T> |
| | | 52 | | |
| | | 53 | | /// `try body () finally compensation ()` |
| | | 54 | | let tryFinally (body: Func<'T>) (compensation: Func<unit>) : 'T = |
| | 896 | 55 | | try body.Invoke() finally compensation.Invoke() |
| | | 56 | | |
| | | 57 | | /// `use x = resource in body x`; a null resource is allowed, as in F#. |
| | | 58 | | let using (resource: 'R when 'R :> IDisposable) (body: Func<'R, 'T>) : 'T = |
| | 24 | 59 | | try body.Invoke resource |
| | 12 | 60 | | finally |
| | 12 | 61 | | match box resource with |
| | 4 | 62 | | | null -> () |
| | 8 | 63 | | | d -> (d :?> IDisposable).Dispose() |