The compiler is organized into passes. Each pass converts definitions of the language from a previous representation, performs some changes and/or optimization, and outputs definition in the newer, lower-level representation.
The definitions are organized into streams, i.e. a lazy infinite sequence of elements. A pass is just a stream transformer, that transforms data from one stream to another. Transformations need not be one-to-one: i.e. a single element from the previous language can be translated to no, or several, elements. Also, a pass can keep an internal state (to record translation information).
There are several ways to write a compilation pass as a stream
transformer. In a lexer and a parser, the internal state is kept
mainly in the stack, and the lexer and parser will repeatedly
request new elements of the stream from various points in the code.
In later passes, when the language is more structured into a
succession of definitions, is is more natural to have the code
handle one definition at a time, using a filter
(a function that
maps an element of the input stream to zero, one or several
elements in the output stream; and can update its internal state).
There are many advantages to using streams to model compilation passes:
module Stream = Extensions.Stream
let print_stream cond printf print_elt stream =
if cond
then Stream.iter_and_copy
(fun elt → printf (format_of_string "@.%a") print_elt elt) stream
else stream
Log.Compilation_passes.info "================ File %s================" file;
let token_stream = Token.Stream.make file in
let parsetree_stream = Parser.definition_stream token_stream in
let ast_stream = Ast.Ast_from_term.from_stream parsetree_stream in
let ast_stream = print_stream (Log.Ast_elaboration.is_output Log.Debug)
Log.Ast_elaboration.debug Ast.Print.definition ast_stream in
let cps_stream = Cpstransform.from_stream ast_stream in
let cps_stream = print_stream (Log.Cps_transformation.is_output Log.Debug)
Log.Cps_transformation.debug Cpsbase.Print.definition cps_stream in
let converted_stream =
Stream.iter_and_copy Cpsconvertclosures.in_definition cps_stream in
let converted_stream =
print_stream (Log.Closure_conversion.is_output Log.Debug)
Log.Closure_conversion.debug Cpsbase.Print.definition converted_stream in
let llvm_stream = Cpsllvm.from_stream converted_stream in
Stream.iter (fun elt → Llvmexec.exec_nodef () elt) llvm_stream