this repo has no description
at main 153 lines 4.5 kB view raw
1open Js_of_ocaml_toplevel 2open X_protocol 3 4module Value_env : sig 5 type t 6 7 val empty : t 8 val capture : t -> Ident.t list -> t 9 val restore : t -> unit 10end = struct 11 module String_map = Map.Make (String) 12 13 type t = Obj.t String_map.t 14 15 let empty = String_map.empty 16 17 let capture t idents = 18 List.fold_left 19 (fun t ident -> 20 let name = Translmod.toplevel_name ident in 21#if defined OXCAML 22 let v = Toploop.getvalue name in 23#else 24 let v = Topeval.getvalue name in 25#endif 26 String_map.add name v t) 27 t idents 28 29 let restore t = String_map.iter (fun name v -> 30#if defined OXCAML 31 Toploop.setvalue name v 32#else 33 Topeval.setvalue name v 34#endif 35 ) t 36end 37 38module Environment = struct 39 let environments = ref [] 40 let init () = environments := [ (0, !Toploop.toplevel_env, Value_env.empty) ] 41 42 let reset id = 43 let rec go id = function 44 | [] -> failwith ("no environment " ^ string_of_int id) 45 | (id', _, _) :: xs when id' >= id && xs <> [] -> go id xs 46 | ((_, typing_env, value_env) as x) :: xs -> 47 Toploop.toplevel_env := typing_env; 48 Value_env.restore value_env; 49 x :: xs 50 in 51 environments := go id !environments 52 53 let capture id = 54 let values = 55 match !environments with 56 | [] -> invalid_arg "empty environment" 57 | (_, previous_env, previous_values) :: _ -> 58 let idents = Env.diff previous_env !Toploop.toplevel_env in 59 Value_env.capture previous_values idents 60 in 61 environments := (id, !Toploop.toplevel_env, values) :: !environments 62end 63 64let setup_toplevel () = 65 let _ = JsooTop.initialize () in 66 Sys.interactive := false; 67 Environment.init () 68 69let rec parse_use_file ~caml_ppf lex = 70 let _at = lex.Lexing.lex_curr_pos in 71 match !Toploop.parse_toplevel_phrase lex with 72 | ok -> Ok ok :: parse_use_file ~caml_ppf lex 73 | exception End_of_file -> [] 74 | exception err -> [ Error err ] 75 76let ppx_rewriters = ref [] 77 78let preprocess_structure str = 79 let open Ast_mapper in 80 List.fold_right 81 (fun ppx_rewriter str -> 82 let mapper = ppx_rewriter [] in 83 mapper.structure mapper str) 84 !ppx_rewriters str 85 86let preprocess_phrase phrase = 87 let open Parsetree in 88 match phrase with 89 | Ptop_def str -> Ptop_def (preprocess_structure str) 90 | Ptop_dir _ as x -> x 91 92let execute ~id ~line_number ~output code_text = 93 Environment.reset id; 94 let outputs = ref [] in 95 let buf = Buffer.create 64 in 96 let caml_ppf = Format.formatter_of_buffer buf in 97 let content = code_text ^ " ;;" in 98 let lexer = Lexing.from_string content in 99 Lexing.set_position lexer 100 { pos_fname = ""; pos_lnum = line_number; pos_bol = 0; pos_cnum = 0 }; 101 let phrases = parse_use_file ~caml_ppf lexer in 102 Js_of_ocaml.Sys_js.set_channel_flusher stdout (fun str -> 103 outputs := Stdout str :: !outputs); 104 Js_of_ocaml.Sys_js.set_channel_flusher stderr (fun str -> 105 outputs := Stderr str :: !outputs); 106 let get_out () = 107 Format.pp_print_flush caml_ppf (); 108 let meta = Buffer.contents buf in 109 Buffer.clear buf; 110 let out = if meta = "" then !outputs else Meta meta :: !outputs in 111 outputs := []; 112 List.rev out 113 in 114 let respond ~(at_loc : Location.t) = 115 let loc = at_loc.loc_end.pos_cnum in 116 let out = get_out () in 117 output ~loc out 118 in 119 List.iter 120 (function 121 | Error err -> Errors.report_error caml_ppf err 122 | Ok phrase -> 123 let sub_phrases = 124 match phrase with 125 | Parsetree.Ptop_def s -> 126 List.map (fun s -> Parsetree.Ptop_def [ s ]) s 127 | Ptop_dir _ -> [ phrase ] 128 in 129 List.iter 130 (fun phrase -> 131 let at_loc = 132 match phrase with 133 | Parsetree.Ptop_def ({ pstr_loc = loc; _ } :: _) -> loc 134 | Ptop_dir { pdir_loc = loc; _ } -> loc 135 | _ -> assert false 136 in 137 X_ocaml_lib.id := (id, at_loc.loc_end.pos_cnum); 138 try 139 Location.reset (); 140 let phrase = preprocess_phrase phrase in 141 let _r = Toploop.execute_phrase true caml_ppf phrase in 142 respond ~at_loc 143 with _exn -> 144 Errors.report_error caml_ppf _exn; 145 respond ~at_loc) 146 sub_phrases) 147 phrases; 148 Environment.capture id; 149 get_out () 150 151let () = 152 Ast_mapper.register_function := 153 fun _ f -> ppx_rewriters := f :: !ppx_rewriters