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.
un ::= - | not | printint | ! | #i
bin ::= + | - | * | & | || | = | < | :=
exp ::= (exp) | id | num | exp; exp | un exp | exp bin exp | <exp, ..., exp> | exp ( exp )
| if exp then exp else exp | while exp do exp | let id = exp in exp | ref (exp : tp)
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.
------------------
G |-- id : G(id)
----------------
G |-- num : int
G |-- exp1 : tp1 G |-- exp2 : tp2
---------------------------------------
G |-- exp1 ; exp2 : tp2
optype (un) = tp1-> tp2 G |-- exp : tp1
-----------------------------------------------
G |-- un exp : tp2
optype (bin) = tp1-> tp2 -> tp3 G |-- exp1 : tp1 G |-- exp2 : tp2
-------------------------------------------------------------------------------
G |-- exp1 bin exp2 : tp3
G |-- exp0 : tp0 ... G |-- expn : tpn
--------------------------------------------
G |-- <exp0, ..., expn> : <tp0, ..., tpn>
G |-- exp : <tp0, ..., tpn> (0 <= i <= n)
-----------------------------------------------
G |-- #i exp : tpi
G |-- exp1 : tp1 -> tp2 G |-- exp2 : tp1
-----------------------------------------------
G |-- exp1 exp2 : tp2
G |-- exp1 : int G |-- exp2 : tp G |-- exp3 : tp
--------------------------------------------------------
G |-- if exp1 then exp2 else exp3 : tp
G |-- exp1 : int G |-- exp2 : <>
--------------------------------------
G |-- while exp1 do exp2 : <>
G |-- exp1 : tp1 G [x : tp1] |-- exp2 : tp2
-------------------------------------------------
G |-- let x = exp1 in exp2 : tp2
G |-- exp : tp
----------------------
G |-- ref (exp : tp) : tp ref
G |-- exp : tp ref
----------------------
G |-- ! exp : tp
G |-- exp1 : tp ref G |-- exp2 : tp
---------------------------------------
G |-- exp1 := exp2 : <>
G |-- exp : tp' tp' < tp
--------------------------- (subsumption rule)
G |-- exp : tp
The typeof function is defined by the following table.
operator | typeof (operator) |
- (unary) , not | int -> int |
printint | int -> <> |
+ , - (binary) , * , & , || , = , < | int -> int -> int |
Function Declaration Typing
G [id2 : tp1] |-- exp : tp2
----------------------------------------------------------------------
G |-- (fun id1 ( id2 : tp1 ) : tp2 = exp) ==> id1 : tp1 -> tp2
Program Typing
contextof(fundecl1 ... fundecln) = G
G |-- fundecl1 ok ... G |-- fundecln ok G |-- exp : int
------------------------------------------------------------------
|-- fundecl1 ... fundecln in exp ok
where
1. None of the function declarations (fundecl1...fundecln) are allowed to declare the same function name (argument names may be repeated) and
2. contextof((fun id11 ( id12 : tp11 ) : tp12 = exp1) ... (fun idn1 ( idn2 : tpn1 ) : tpn2 = expn)) =
nil [id11 : tp11 -> tp12] ... [idn : tpn1 -> tpn2]