Introduction
This document describes the programming language Fram, and is divided into the following parts.
- Part I is intended to be a general introduction to the language.
- Part II serves as a reference manual as well as the informal specification of Fram.
- Part III documents the standard library.
Installation
The most complete implementation of Fram currently available is the interpreter called DBL, written in OCaml and built using dune.
Getting Started
Notational Conventions
This reference manual will often present the grammars of various elements of
Fram's syntax. We use a variant of the BNF notation to specify the grammars.
Non-terminal symbols have no special formatting, while the terminals are
enclosed in quotation marks. Alternatives are separated by |
, and grouping is
achieved with parentheses: (E)
. We also use {E}
to denote repetition, and
[E]
to denote the optional inclusion of E
. See the following grammar for
a simple example (not specifically related to Fram).
digit ::= "0"..."9"
letter ::= "a"..."z" | "A"..."Z"
lower-ident ::= ( "a"..."z" | "_" ) { letter | digit | "_" | "'" }
integer ::= "0" | [ "-" ] "1"..."9" { digit }
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 ::= "<" | ">" | "&" | "$" | "?" | "!" | "@" | "^" | "+" | "-"
| "~" | "*" | "%" | ";" | "," | "=" | "|" | ":" | "." | "/"
Prelude
The Prelude
module is automatically imported and opened in all programs.