(** The front half of a compile: read a file, load it with its imports, check it, and decide the link. What [flan build], [flan run], [flan emit] and [flan check] do before a backend is reached, and what the test binaries do before theirs, so that the two cannot drift apart. [all] chooses how a refusal is reported. With it, the parser and the checker keep going and raise [Loc.Errors] with every declaration they refused, which is what the command-line drivers want: write everything, compile at the end, work through the list. Without it they stop at the first and raise [Loc.Error], which is what a test asserting on one message wants. For a program with no errors the two are the same. *) let load ?(all = false) path : Load.t = Load.program ~file:path ~parse:(if all then Parse.program_all else Parse.program) (Source.read_file path) let check ?(all = false) (l : Load.t) : Tast.program = (if all then Check.program_all else Check.program) l.Load.decls let checked ?all path = let l = load ?all path in (l, check ?all l) type linked = { load : Load.t; (* the declarations, as loaded *) program : Tast.program; (* checked, and pruned to what is reached *) csrcs : string list; (* the packages' C that the link needs *) lflags : string list; (* ...and their linker arguments *) } (* [before_link] sees the checked program before [Reach.link] prunes it. The questions asked there — [Check.no_gc], the memory warnings — are about what was written, and a function nothing calls is still something somebody wrote. *) let linked ?(dev = false) ?all ?(before_link = fun _ -> ()) path = let l, p = checked ?all path in before_link p; let program, csrcs, lflags = Reach.link ~dev l p in { load = l; program; csrcs; lflags }