Lexical Structure
Whitespace
The following characters are considered as whitespace (blanks): horizontal tab
(0x09
), new line (0x10
), vertical tab (0x11
), form feed (0x12
),
carriage return (0x13
), and space (0x20
). Whitespace characters are ignored
by the lexer, but they separate tokens, e.g., identifiers or literals.
Comments
Fram supports two kinds of comments: single-line and block comments. Comments are treated similarly to whitespace: they are ignored by the lexer, but they always separate tokens.
Single-line comments start with the #
character and end with a new line or
the end of file.
Block comments are introduced by the sequence {#
followed by any, possibly
empty, sequence name of any characters except control characters
(0x00-0x1f
, 0x7f
), space, and curly braces ({
and }
). Such a block
comment is terminated by the first occurrence of name that is immediately
followed by #}
. More precisely, it can be described by the following grammar.
block-comment-name ::= { "!"..."z" | "|" | "~" | non-ascii-character }
block-comment-start ::= "{#" block-comment-name
block-comment-end ::= block-comment-name "#}"
At the comment opening, the longest consecutive sequence described by
block-comment-name
is taken as the comment name. This name should be a suffix
of the name provided at comment closing. Comments using the same name cannot
be nested. This is not an issue in practice, since the programmer can always
choose a unique name to accomplish nesting.
By convention, single-line comments starting with ##
and block comments
with a name starting with #
are used as documentation comments, and can be
recognized by some external tools.
Examples
The following code contains some valid comments.
# This is a single-line comment.
{# This is a block comment. #}
{# Block comments
may span multiple lines.
#}
let id x = x # A single-line comment may appear at the end of a line.
let n {# A block comment may span a part of a single line. #} = 42
{#aaa
Comments cannot be nested,
{# but the programmer may choose the comment delimiters. #}
aaa#}
{#!a! Comment names may contain operators. !a!#}
{#abc
This comment is ended by `abc` immediately followed by `#}`,
even if the closing sequence is preceded by other characters.
zzabc#}
let {#
# This is not a single-line comment,
# because comments are not nested.
# This comment can be ended #} here = 13
## This is a documentation comment.
let foo x = x
{## This is another documentation comment. ##}
let bar = foo
{###
Documentation comments can contain some code
```
{## with another documentation comment (with a different name). ##}
let some_code = 42
```
###}
let baz = bar
Literals
digit ::= "0"..."9"
lower-char ::= "a"..."z" | "_"
upper-char ::= "A"..."Z"
ident-char ::= lower-char | upper-char | digit | "'"
Keywords
Identifiers
Operators
op-char ::= "<" | ">" | "&" | "$" | "?" | "!" | "@" | "^" | "+" | "-"
| "~" | "*" | "%" | ";" | "," | "=" | "|" | ":" | "." | "/"