Compilation phases (by sub-directories of "src"):
1) parsing:
* Transforms the source file into an AST
2) desugaring:
* Decomposes syntactic sugars from the parse-tree
3) pre-typing:
* Fixes the type of recursive values (mandatory)
* Check that recursive values are not referenced before the first abstraction (forbidden/unsafe)
4) typing:
* Type-checks everything (we don't need types anymore after that)
* Compile pattern matching using Maranget's algorithm: http://moscova.inria.fr/~maranget/papers/ml05e-maranget.pdf
5) lambda:
* Gives a unique name to all values (LIdent + Lambda.scan)
* Encode variants and foreign declarations
* Introduces lets instead of recursing over the AST
6) flatten:
* Set all lets to the same level for each function (no nested lets)
* Propagate abstractions to applications [a = (λx.t); b = a y] --> [x = y; a = (λx.t); b = t]
* Propagate names [a = b; c = a] --> [c = b]
7) optimization:
* Fixes free variables on λ-abstractions
8) backend:
* Transforms AST to LLVM-IR using:
* setjmp/longjmp to encode exceptions
* one-argument functions to encode lambdas