Numbers (num) are 30-bit
positive integers. (numbers may be preceded by a minus sign, but the
minus sign should be lexed as a
separate token.)

Fun reserves the following
keywords.

fun

in

let

while

do

if

then

else

printint

ref

not

int

Program Structure

A program is a sequence of (mutually recursive) function declarations
followed by the keyword in followed by an expression. A Fun
compiler will expect there to be a single Fun program per file.

prog ::= fundecl ... fundecl in exp

Function Declaration Structure

A function declaration specifies the name of the function, its argument,
argument type, return type and expression body. Functions are interpreted
in call-by-value evaluation order. All functions must have different names
(argument names may be repeated).

fundecl ::= fun id ( id : tp ) : tp = exp

Type Structure

The types are integers (int), n-ary tuples, single-argument/single-result
function and references (ref). The ref constructor has higher precedence than the
function type constructor (->).
The function type constructor is right associative and the ref type constructor
is left associative.

tp ::= int | <tp, ..., tp> | tp -> tp | tp ref | (tp)

Expression Structure

Expressions are evaluated in left-to-right
order. Expression structure is given by the following BNF.

Basic values include identifiers, () (the unit value) and numbers.
Sometimes numbers are interpreted as Boolean values (eg: in logical
operations; if statements; while loops). In this case, 0 should be
interpreted as "false" and non-zero should be interpreted as "true."

Unary operations include - (unary minus), not (logical negation: 0
=> 1; non-zero => 0), and printint. printint takes
an integer argument and returns <>, the 0-length tuple. The unary
operator #i extracts the ith field from a tuple. Tuples are indexed
starting with 0. The i in #i must a non-negative integer and #-0
is not legal.

The operators ref, :=, and ! creates a reference, assigns a value
to reference and dereferences a reference respectively. Notice that when
you allocate a reference, you must specify the type of objects held in that
ref cell.

If expressions (if exp then exp else exp) execute the
"then" branch if the first expression evaluates to a non-zero integer and
execute the "else" branch if the first expression evaluates to 0. The
else branch extends as far as possible. Similarly, the
do-expression of the while and in-expression of the
let extend as far as possible.

In a call expression, the function argument is surrounded by parens. Function call is left-associative so f
(x) (y) is (f (x)) (y).

Typing

Fun has a strong type system with subtyping. The following sections
define the typing rules for the language.

Subtyping

The judgment (tp1 < tp2) states that
tp1 is a subtype of tp2.

-------

tp < tp

tp1 < tp2 tp2
< tp3

------------------------

tp1 < tp3

tp0 < tp0'
... tpn < tpn'

---------------------------------

<tp0, ..., tpn> < <tp0',
..., tpn'>

(0 <= n < k)

-------------------------------------------

<tp0, ..., tpn, ..., tpk> < <tp0, ..., tpn>

tp1' < tp1
tp2 < tp2'

---------------------------

tp1 ->
tp2 < tp1' -> tp2'

tp < tp' tp'
< tp

--------------------

tp ref < tp' ref

Expression Typing

The judgment (G |-- exp : tp) states that expression exp has type tp in
context G. A context G is a finite partial map from identifiers to types.
The context "nil" is the empty context. The context G [x : tp] is the same
as G except it maps identifier x to tp. The following rules define the
expression typing judgement.