Source file direct.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
(* Js_of_ocaml library
 * http://www.ocsigen.org/js_of_ocaml/
 * Copyright (C) 2014 Hugo Heuzard
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, with linking exception;
 * either version 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *)

open Js_of_ocaml_compiler
open Js_of_ocaml_compiler.Stdlib

let setup =
  lazy
    (Toploop.add_directive
       "enable"
       (Toploop.Directive_string Config.Flag.enable)
       { section = "js_of_ocaml"; doc = "Enable the given flag" };
     Toploop.add_directive
       "disable"
       (Toploop.Directive_string Config.Flag.disable)
       { section = "js_of_ocaml"; doc = "Disable the given flag" };
     Toploop.add_directive
       "debug_on"
       (Toploop.Directive_string Debug.enable)
       { section = "js_of_ocaml"; doc = "Enable debug for the given section" };
     Toploop.add_directive
       "debug_off"
       (Toploop.Directive_string Debug.disable)
       { section = "js_of_ocaml"; doc = "Disable debug for the given section" };
     Toploop.add_directive
       "tailcall"
       (Toploop.Directive_string (Config.Param.set "tc"))
       { section = "js_of_ocaml"
       ; doc = "Set the depth of tail calls before going through a trampoline"
       })

let init_loc lb filename =
  Location.init lb filename;
  (* [Location.init] points [input_lexbuf] at [lb]; clear it so rendered errors
     do not inline a source excerpt (locations are reported on their own). *)
  Location.input_lexbuf := None

(* Reimplements [Toploop.use_silently] so that the toplevel's in-process ppx
   rewriters are applied (via [Ppx.preprocess_phrase]); [use_silently] only
   knows about external [-ppx] executables, which cannot run in the browser. *)
let use ?(print_outcome = false) ffp content =
  let lb = Lexing.from_string content in
  init_loc lb "//toplevel//";
  try
    List.iter
      ~f:(fun phr ->
        if not (Toploop.execute_phrase print_outcome ffp phr)
        then raise Exit
        else Format.pp_print_flush ffp ())
      (List.map ~f:Ppx.preprocess_phrase (!Toploop.parse_use_file lb));
    flush_all ();
    true
  with
  | Exit ->
      flush_all ();
      false
  | x ->
      flush_all ();
      Errors.report_error ffp x;
      false

let execute printval ?pp_code ?highlight_location pp_answer s =
  let lb = Lexing.from_function (Refill.lexbuf s (ref 0) pp_code) in
  init_loc lb "//toplevel//";
  (try
     while true do
       try
         let phr = !Toploop.parse_toplevel_phrase lb in
         let phr = Ppx.preprocess_phrase phr in
         ignore (Toploop.execute_phrase printval pp_answer phr : bool)
       with
       | End_of_file -> raise End_of_file
       | x ->
           (match highlight_location with
           | None -> ()
           | Some f -> (
               match Error_loc.loc x with
               | None -> ()
               | Some loc -> f loc));
           Errors.report_error Format.err_formatter x
     done
   with End_of_file -> ());
  flush_all ()

let initialized = ref false

let reset_toplevel_env () =
  (* Register the directory holding the runtime cmi bundles both before and
     after [initialize_toplevel_env]: before, so building the environment can
     load Stdlib from there; after, because [initialize_toplevel_env] resets the
     load path and later lookups of other libraries would otherwise fail. *)
  Topdirs.dir_directory "/static/cmis";
  Toploop.initialize_toplevel_env ();
  Topdirs.dir_directory "/static/cmis"

let initialize () =
  if not !initialized
  then (
    initialized := true;
    Sys.interactive := false;
    Lazy.force setup;
    reset_toplevel_env ();
    Toploop.input_name := "//toplevel//";
    Sys.interactive := true)