+
+(* There are several circular dependencies between the lexer
+ * (caused by includes) and eval. These references break
+ * the circular dependencies. They are initialized when
+ * the program starts, hence are never really None.
+ *)
+let lexer_read = ref None
+let eval_substitute = ref None
+
+let find_on_include_path filename =
+ if not (Filename.is_implicit filename) then filename
+ else (
+ let rec loop = function
+ | [] -> filename
+ | inc :: incs ->
+ let path = inc // filename in
+ if Sys.file_exists path then path else loop incs
+ in
+ loop (Cmdline.includes ())
+ )
+
+let do_include env loc filename optflag file =
+ let eval_substitute =
+ match !eval_substitute with None -> assert false | Some f -> f in
+ let filename = eval_substitute env loc filename in
+ let filename = find_on_include_path filename in
+ if optflag && not (Sys.file_exists filename) then env
+ else (
+ let fp = open_in filename in
+ let lexbuf = Lexing.from_channel fp in
+ lexbuf.lex_curr_p <- { lexbuf.lex_curr_p with pos_fname = filename };
+ let lexer_read =
+ match !lexer_read with None -> assert false | Some r -> r in
+ let env' = file lexer_read lexbuf in
+ close_in fp;
+ Ast.Env.merge env env'
+ )