Skip to content

Lexical Elements

2.1 Keywords

let       mut       fun       type      match     with
when      if        then      else      elif      end
for       in        do        while     try       finally
return    break     continue  export    true      false
Ok        Error     Some      None      rec       and
of        as        global    lazy

2.2 Reserved Operators

|>        |         ->        <-        =>        ::
&&        ||        ==        !=        <=        >=
<         >         +         -         *         /        %
**        >>        <<        @         #         ?        !

2.3 Delimiters

( )       [ ]       { }       ;         ,         .

2.4 Comments

# Single line comment (shell style)
// Single line comment (C style)
(*
   Multi-line comment
   F# style
*)

Formatter directives

endo format recognizes two directive comments that disable and re-enable reformatting for a region of source, analogous to // clang-format off / on. A # endo format off comment suppresses formatting until a matching # endo format on comment; everything in between is reproduced verbatim, preserving the original spacing and line breaks. This is useful for source whose exact layout matters — for example a deliberately multi-line pipeline that the formatter would otherwise collapse onto a single line.

# endo format off
5 |>
inc |>
double |>
println
# endo format on

Rules:

  • The directives must be standalone shell-style (#) comments. The marker text is matched after stripping the leading # and surrounding whitespace.
  • An off with no matching on preserves everything to the end of the file.
  • A nested off inside an already-open region is ignored (the first off wins until the next on); a stray on with no preceding off has no effect.

2.5 String Literals

# Double-quoted strings (with interpolation)
"Hello, $name"
"Value: ${expression}"
"Command output: $(whoami)"
"Arithmetic: $((1 + 2))"

# Single-quoted strings (literal, no interpolation)
'No $interpolation here'
'Literal backslash: \'

# Escape sequences in double-quoted strings
"\n"      # Newline
"\t"      # Tab
"\\"      # Backslash
"\$"      # Literal dollar sign
"\""      # Literal double quote

# F#-style interpolated strings (expression holes with {expr})
$"Hello, {name}"
$"Sum is {3 + 4}"
$"a={a}, b={b}"
$"result: {f 5}"
$"val: {if x > 0 then "positive" else "negative"}"

# Escaped braces in F#-style interpolated strings
$"{{literal braces}}"   # produces: {literal braces}

2.6 Numeric Literals

# Integers
42
-17
0xFF        # Hexadecimal
0o755       # Octal
0b1010      # Binary

# Floating point
3.14
-0.5
1e10
2.5e-3

2.7 Size Literals

Size literals represent byte counts and produce a Size value. They are formed by an integer or float followed by a unit suffix:

42B         # 42 bytes
1KB         # 1 kilobyte  (1024 bytes)
5MB         # 5 megabytes (5 * 1024^2 bytes)
2GB         # 2 gigabytes (2 * 1024^3 bytes)
1TB         # 1 terabyte  (1 * 1024^4 bytes)

Float values are supported for all units except B (which requires whole numbers):

3.5KB       # 3584 bytes (3.5 * 1024)
1.5MB       # 1572864 bytes (1.5 * 1024^2)
1.0B        # 1 byte (whole float OK)

Size values display in the most appropriate unit (e.g., 1536 bytes displays as 1.5 KB). The raw byte count is accessible via the .bytes field:

let s = 10MB
print s           # 10 MB
print s.bytes     # 10485760

Size values support comparison operators:

1KB < 1MB       # true
1KB == Size.fromBytes 1024  # true

2.8 TimeSpan Literals

TimeSpan literals represent durations and produce a TimeSpan value. They are formed by an integer or float followed by a unit suffix:

100ms       # 100 milliseconds
5s          # 5 seconds (5000 ms)
2min        # 2 minutes (120000 ms)
1h          # 1 hour (3600000 ms)

Float values are supported for all units except ms (which requires whole numbers):

1.5h        # 1h 30m (5400000 ms)
2.5s        # 2s 500ms (2500 ms)
1.0ms       # 1ms (whole float OK)

The raw millisecond count is accessible via the .milliseconds field:

let t = 5s
print t               # 5s
print t.milliseconds  # 5000

TimeSpan values support comparison operators:

1s < 1min   # true

2.9 Line Endings and Statement Termination

A newline normally ends the current statement. Within shell commands and pipelines, however, a newline can be absorbed as whitespace when the surrounding context implies continuation: a trailing or leading |, |>, &&, ||, or an indented line following the command's program name. See Multi-line Commands for the full rules.


See also: Type System | Grammar | Philosophy & Goals