Inline source code - IS4Code/Sona GitHub Wiki

With the use of the #inline and #endinline directives, it is possible to write F# code directly in the source. This option is available only in privileged code, as direct F# may bypass safety restrictions on the generated CIL.

The directive is usable only in place of a single statement, expression, type, or pattern. It must not be surrounded by any operators, otherwise it must be in parentheses.

Syntax

inline_source:
  '#inline "F#"'
  code
  '#endinline' ('return' | 'throw')?;

The #inline token is followed by a string indicating the language of the inline code, which must be "F#". The F# code starts immediately after the string, without requiring a newline. In order for it to be recognized, the #endinline keyword must be located at the beginning of a line, must not be followed by a non-whitespace character, and must not be a part of any of the following:

  • a comment,
  • a string,
  • a string interpolation.

In other words, the #endline directive is recognized per standard F# syntax rules. When used as a statement, it may optionally be followed by either return or throw, indicating the syntactic category of the statement ‒ return if the code is supposed to be returning a value (from its last expression), or throw if the code should be regarded as never-returning.

F# code within the inline source section must be properly formatted per F#'s indentation rules. To aid this, there are several transformations performed on the code when it becomes a part of the output:

  • The code that immediately follows the #inline directive is placed on a single line, with the first token properly indented to a position where normal code would otherwise be generated. Any whitespace that precedes the token is ignored.
  • Likewise, each following line that starts with a non-whitespace token is indented to the same position. Of these, the first line sets the input indentation that must be respected by all further lines ‒ any line starting with a less indented token is invalid.
  • Comments (both //… and (*…*)) are treated as whitespace, but are copied directly to the output (unless they form indentation). Newlines in block comments are treated as line separators, per F#'s rules. Newlines in strings are not considered line separators.
  • Directives are never indented.

It should be noted that the F# code should correspond to a self-contained code element. Code that syntactically affects other parts of the source or depends on them is not supported.

Invalid code example
#inline "F#"
let f() = begin
  printfn "First line in F#"
#endinline
  printfn("Second line outside F#")
#inline "F#"
  printfn "Last line in F#"
end
#endinline

This code attempts to begin a function in one code snippet and end it in another. This is not possible, however, as the indentation maintained by the first F# snippet does not extend to the statement that prints "Second line outside F#", which thus does not get indented at all. Worse even, the last statement starts indented, but the end following it is 2 character below its level, making the code invalid.

Examples

F# source may be used as a body of a single function, to embed pre-existing code or use code that would not be normally expressible. The code may freely access variables created prior, and can reference variables created in the F# source.

function f()
  let arr = [1, 2, 3]
#inline "F#"
  use ptr = fixed &arr[0]
#endinline
  Console.WriteLine(NativePtr.toNativeInt(ptr))
end
F# source
let rec f() =
 let arr = [| 1;2;3 |]
 use ptr = fixed &arr[0]
 Console.WriteLine(NativePtr.toNativeInt(ptr))
 ()

Regardless of the indentation of the input, the meaningful lines of F# code are aligned with the other statements.

⚠️ **GitHub.com Fallback** ⚠️