···89 string ->
90 (Toplevel_api_gen.exec_result, Toplevel_api_gen.err) result Lwt.t
9192- val compile_js : rpc -> string -> string -> (string, Toplevel_api_gen.err) result Lwt.t
93end = struct
94 type init_libs = Toplevel_api_gen.init_libs
95 type err = Toplevel_api_gen.err
···89 string ->
90 (Toplevel_api_gen.exec_result, Toplevel_api_gen.err) result Lwt.t
9192+ val compile_js : rpc -> string option -> string -> (string, Toplevel_api_gen.err) result Lwt.t
93end = struct
94 type init_libs = Toplevel_api_gen.init_libs
95 type err = Toplevel_api_gen.err
+1-1
idl/js_top_worker_client.mli
···52 (** Execute a phrase using the toplevel. The toplevel must have been
53 initialised first. *)
5455- val compile_js : rpc -> string -> string -> (string, err) result Lwt.t
56end
···52 (** Execute a phrase using the toplevel. The toplevel must have been
53 initialised first. *)
5455+ val compile_js : rpc -> string option -> string -> (string, err) result Lwt.t
56end
···56type captured = { stdout : string; stderr : string }
70000000000000000000000000008module type S = sig
9 val capture : (unit -> 'a) -> unit -> captured * 'a
10 val create_file : name:string -> content:string -> unit
···59 let o, () = exec' s in
60 combine o
61 in
62- Logs.info (fun m -> m "Setting up toplevel");
63 Sys.interactive := false;
64- Logs.info (fun m -> m "Finished this bit 1");
6566 Toploop.input_name := "//toplevel//";
67- Logs.info (fun m -> m "Finished this bit 2");
68 let path =
69 match !path with Some p -> p | None -> failwith "Path not set"
70 in
7172 Topdirs.dir_directory path;
7374- List.iter Topdirs.dir_directory [
75- "/Users/jonathanludlam/devel/learno/_opam/lib/note";
76- "/Users/jonathanludlam/devel/learno/_opam/lib/js_of_ocaml-compiler/runtime";
77-"/Users/jonathanludlam/devel/learno/_opam/lib/brr";
78-"/Users/jonathanludlam/devel/learno/_opam/lib/note/brr";
79-"/Users/jonathanludlam/devel/learno/codemirror3/odoc_notebook/_build/default/mime_printer/.mime_printer.objs/byte"
80- ];
81-82- Logs.info (fun m -> m "Finished this bit 3");
83 Toploop.initialize_toplevel_env ();
84- Logs.info (fun m -> m "Finished this bit 4");
8586 List.iter (fun f -> f ()) functions;
87 exec' "open Stdlib";
···184 reset ();
185 List.iter (fun p -> prepend_dir (Dir.create p)) dirs
186000000187 let add_dynamic_cmis dcs =
188- let open Ocaml_typing.Persistent_env.Persistent_signature in
189- let old_loader = !load in
190-191 let fetch filename =
192 let url = Filename.concat dcs.Toplevel_api_gen.dcs_url filename in
193 S.sync_get url
···206 | None -> ())
207 dcs.dcs_toplevel_modules;
208209- let new_load ~unit_name =
0210 let filename = filename_of_module unit_name in
211212 let fs_name = Filename.(concat path filename) in
213 (* Check if it's already been downloaded. This will be the
214 case for all toplevel cmis. Also check whether we're supposed
215 to handle this cmi *)
00216 (if
217 (not (Sys.file_exists fs_name))
218 && List.exists
219 (fun prefix -> String.starts_with ~prefix filename)
220 dcs.dcs_file_prefixes
221- then
0222 match fetch filename with
223 | Some x ->
224 S.create_file ~name:fs_name ~content:x;
225 (* At this point we need to tell merlin that the dir contents
226 have changed *)
227- reset_dirs ()
228 | None ->
229 Printf.eprintf "Warning: Expected to find cmi at: %s\n%!"
230- (Filename.concat dcs.Toplevel_api_gen.dcs_url filename));
231 old_loader ~unit_name
232 in
233- load := new_load
0000000000000234235 let init (init_libs : Toplevel_api_gen.init_libs) =
236 try
···246 let name = Filename.(concat init_libs.path filename) in
247 S.create_file ~name ~content:sc_content)
248 init_libs.cmis.static_cmis;
249- Option.iter add_dynamic_cmis init_libs.cmis.dynamic_cmis;
250251 (*import_scripts
252 (List.map (fun cma -> cma.Toplevel_api_gen.url) init_libs.cmas);
···360 in
361 Array.of_list (split 0 0)
362363- let compile_js id prog =
364- let open Js_of_ocaml_compiler in
365- let open Js_of_ocaml_compiler.Stdlib in
366 try
367- let str = Printf.sprintf "let _ = Mime_printer.id := \"%s\"\n%s" id prog in
368- let l = Lexing.from_string str in
369 let phr = Parse.toplevel_phrase l in
370 Typecore.reset_delayed_checks ();
371 Env.reset_cache_toplevel ();
372 let oldenv = !Toploop.toplevel_env in
373 (* let oldenv = Compmisc.initial_env() in *)
0374 match phr with
375 | Ptop_def sstr ->
0376 let str, sg, sn, _shape, newenv =
377 try Typemod.type_toplevel_phrase oldenv sstr
378 with Env.Error e ->
379 Env.report_error Format.err_formatter e;
380- exit 1
00381 in
0382 let sg' = Typemod.Signature_names.simplify newenv sn sg in
383 ignore (Includemod.signatures ~mark:Mark_positive oldenv sg sg');
384 Typecore.force_delayed_checks ();
0385 let lam = Translmod.transl_toplevel_definition str in
0386 let slam = Simplif.simplify_lambda lam in
0387 let init_code, fun_code = Bytegen.compile_phrase slam in
0388 let code, reloc, _events = Emitcode.to_memory init_code fun_code in
389 Toploop.toplevel_env := newenv;
390 (* let prims = split_primitives (Symtable.data_primitive_names ()) in *)
···404 cu_debugsize = 0;
405 }
406 in
407- let fmt = Pretty_print.to_buffer b in
0408 (* Symtable.patch_object code reloc;
409 Symtable.check_global_initialized reloc;
410 Symtable.update_global_table(); *)
···413414 (* let code = String.init (Misc.LongString.length code) ~f:(fun i -> Misc.LongString.get code i) in *)
415 close_out oc;
416- Driver.configure fmt;
0417 let ic = open_in "/tmp/test.cmo" in
418- let p = Parse_bytecode.from_cmo cmo ic in
419- Driver.f' ~standalone:false ~wrap_with_fun:(`Named id) ~linkall:false
00000420 fmt p.debug p.code;
421 Format.(pp_print_flush std_formatter ());
422 Format.(pp_print_flush err_formatter ());
···539540 let complete_prefix source position =
541 let source = Merlin_kernel.Msource.make source in
00000000000000000542 match Completion.at_pos source position with
543 | Some (from, to_, compl) ->
544- let entries = compl.entries in
00000000545 IdlM.ErrM.return { Toplevel_api_gen.from; to_; entries }
546 | None ->
547 IdlM.ErrM.return { Toplevel_api_gen.from = 0; to_ = 0; entries = [] }
···577 IdlM.ErrM.return errors
578579 let type_enclosing source position =
000000580 let source = Merlin_kernel.Msource.make source in
581 let query = Query_protocol.Type_enclosing (None, position, None) in
582 let enclosing = wdispatch source query in
000583 IdlM.ErrM.return enclosing
584end
···56type captured = { stdout : string; stderr : string }
78+9+module JsooTopPpx = struct
10+ open Js_of_ocaml_compiler.Stdlib
11+12+ let ppx_rewriters = ref [fun _ -> Logs.info (fun m -> m "Rewriting..."); Ppx_js.mapper]
13+14+ let () = Ast_mapper.register_function := fun _ f -> ppx_rewriters := f :: !ppx_rewriters
15+16+ let preprocess_structure str =
17+ let open Ast_mapper in
18+ List.fold_right !ppx_rewriters ~init:str ~f:(fun ppx_rewriter str ->
19+ let mapper = ppx_rewriter [] in
20+ mapper.structure mapper str)
21+22+ let preprocess_signature str =
23+ let open Ast_mapper in
24+ List.fold_right !ppx_rewriters ~init:str ~f:(fun ppx_rewriter str ->
25+ let mapper = ppx_rewriter [] in
26+ mapper.signature mapper str)
27+28+ let preprocess_phrase phrase =
29+ let open Parsetree in
30+ match phrase with
31+ | Ptop_def str -> Ptop_def (preprocess_structure str)
32+ | Ptop_dir _ as x -> x
33+34+end
35module type S = sig
36 val capture : (unit -> 'a) -> unit -> captured * 'a
37 val create_file : name:string -> content:string -> unit
···86 let o, () = exec' s in
87 combine o
88 in
089 Sys.interactive := false;
09091 Toploop.input_name := "//toplevel//";
092 let path =
93 match !path with Some p -> p | None -> failwith "Path not set"
94 in
9596 Topdirs.dir_directory path;
9700000000098 Toploop.initialize_toplevel_env ();
099100 List.iter (fun f -> f ()) functions;
101 exec' "open Stdlib";
···198 reset ();
199 List.iter (fun p -> prepend_dir (Dir.create p)) dirs
200201+ let reset_dirs_comp () =
202+ let open Load_path in
203+ let dirs = get_paths () in
204+ reset ();
205+ List.iter (fun p -> prepend_dir (Dir.create p)) dirs
206+207 let add_dynamic_cmis dcs =
000208 let fetch filename =
209 let url = Filename.concat dcs.Toplevel_api_gen.dcs_url filename in
210 S.sync_get url
···223 | None -> ())
224 dcs.dcs_toplevel_modules;
225226+ let new_load ~s ~old_loader ~unit_name =
227+ Logs.info (fun m -> m "%s Loading: %s" s unit_name);
228 let filename = filename_of_module unit_name in
229230 let fs_name = Filename.(concat path filename) in
231 (* Check if it's already been downloaded. This will be the
232 case for all toplevel cmis. Also check whether we're supposed
233 to handle this cmi *)
234+ (if Sys.file_exists fs_name then
235+ Logs.info (fun m -> m "Found: %s" fs_name));
236 (if
237 (not (Sys.file_exists fs_name))
238 && List.exists
239 (fun prefix -> String.starts_with ~prefix filename)
240 dcs.dcs_file_prefixes
241+ then (
242+ Logs.info (fun m -> m "Fetching %s\n%!" filename);
243 match fetch filename with
244 | Some x ->
245 S.create_file ~name:fs_name ~content:x;
246 (* At this point we need to tell merlin that the dir contents
247 have changed *)
248+ if s = "merl" then reset_dirs () else reset_dirs_comp ()
249 | None ->
250 Printf.eprintf "Warning: Expected to find cmi at: %s\n%!"
251+ (Filename.concat dcs.Toplevel_api_gen.dcs_url filename)));
252 old_loader ~unit_name
253 in
254+ let furl = "file://" in
255+ let l = String.length furl in
256+ if String.length dcs.dcs_url > l && String.sub dcs.dcs_url 0 l = furl then begin
257+ let path = String.sub dcs.dcs_url l (String.length dcs.dcs_url - l) in
258+ Topdirs.dir_directory path
259+ end else begin
260+ let open Persistent_env.Persistent_signature in
261+ let old_loader = !load in
262+ load := (new_load ~s:"comp" ~old_loader);
263+264+ let open Ocaml_typing.Persistent_env.Persistent_signature in
265+ let old_loader = !load in
266+ load := (new_load ~s:"merl" ~old_loader)
267+ end
268269 let init (init_libs : Toplevel_api_gen.init_libs) =
270 try
···280 let name = Filename.(concat init_libs.path filename) in
281 S.create_file ~name ~content:sc_content)
282 init_libs.cmis.static_cmis;
283+ List.iter add_dynamic_cmis init_libs.cmis.dynamic_cmis;
284285 (*import_scripts
286 (List.map (fun cma -> cma.Toplevel_api_gen.url) init_libs.cmas);
···394 in
395 Array.of_list (split 0 0)
396397+ let compile_js (id : string option) prog =
00398 try
399+400+ let l = Lexing.from_string prog in
401 let phr = Parse.toplevel_phrase l in
402 Typecore.reset_delayed_checks ();
403 Env.reset_cache_toplevel ();
404 let oldenv = !Toploop.toplevel_env in
405 (* let oldenv = Compmisc.initial_env() in *)
406+ let phr = JsooTopPpx.preprocess_phrase phr in
407 match phr with
408 | Ptop_def sstr ->
409+ Logs.info (fun m -> m "Typing...");
410 let str, sg, sn, _shape, newenv =
411 try Typemod.type_toplevel_phrase oldenv sstr
412 with Env.Error e ->
413 Env.report_error Format.err_formatter e;
414+ (* exit 1 *)
415+ let err = Format.asprintf "%a" Env.report_error e in
416+ failwith ("Error: " ^ err)
417 in
418+ Logs.info (fun m -> m "simplify...");
419 let sg' = Typemod.Signature_names.simplify newenv sn sg in
420 ignore (Includemod.signatures ~mark:Mark_positive oldenv sg sg');
421 Typecore.force_delayed_checks ();
422+ Logs.info (fun m -> m "Translmod...");
423 let lam = Translmod.transl_toplevel_definition str in
424+ Logs.info (fun m -> m "Simplif...");
425 let slam = Simplif.simplify_lambda lam in
426+ Logs.info (fun m -> m "Bytegen...");
427 let init_code, fun_code = Bytegen.compile_phrase slam in
428+ Logs.info (fun m -> m "Emitcode...");
429 let code, reloc, _events = Emitcode.to_memory init_code fun_code in
430 Toploop.toplevel_env := newenv;
431 (* let prims = split_primitives (Symtable.data_primitive_names ()) in *)
···445 cu_debugsize = 0;
446 }
447 in
448+449+ let fmt = Js_of_ocaml_compiler.Pretty_print.to_buffer b in
450 (* Symtable.patch_object code reloc;
451 Symtable.check_global_initialized reloc;
452 Symtable.update_global_table(); *)
···455456 (* let code = String.init (Misc.LongString.length code) ~f:(fun i -> Misc.LongString.get code i) in *)
457 close_out oc;
458+ (* Js_of_ocaml_compiler.Config.Flag.enable "pretty"; *)
459+ Js_of_ocaml_compiler.Driver.configure fmt;
460 let ic = open_in "/tmp/test.cmo" in
461+ let p = Js_of_ocaml_compiler.Parse_bytecode.from_cmo cmo ic in
462+ let wrap_with_fun =
463+ match id with
464+ | Some id -> `Named id
465+ | None -> `Iife
466+ in
467+ Js_of_ocaml_compiler.Driver.f' ~standalone:false ~wrap_with_fun ~linkall:false
468 fmt p.debug p.code;
469 Format.(pp_print_flush std_formatter ());
470 Format.(pp_print_flush err_formatter ());
···587588 let complete_prefix source position =
589 let source = Merlin_kernel.Msource.make source in
590+ let map_kind : [`Value|`Constructor|`Variant|`Label|
591+ `Module|`Modtype|`Type|`MethodCall|`Keyword] -> Toplevel_api_gen.kind_ty = function
592+ | `Value -> Value
593+ | `Constructor -> Constructor
594+ | `Variant -> Variant
595+ | `Label -> Label
596+ | `Module -> Module
597+ | `Modtype -> Modtype
598+ | `Type -> Type
599+ | `MethodCall -> MethodCall
600+ | `Keyword -> Keyword in
601+ let position =
602+ match position with
603+ | Toplevel_api_gen.Start -> `Start
604+ | Offset x -> `Offset x
605+ | Logical (x, y) -> `Logical (x, y)
606+ | End -> `End in
607 match Completion.at_pos source position with
608 | Some (from, to_, compl) ->
609+ let entries =
610+ List.map (fun (entry : Query_protocol.Compl.entry) ->
611+ {
612+ Toplevel_api_gen.name = entry.name;
613+ kind = map_kind entry.kind;
614+ desc = entry.desc;
615+ info = entry.info;
616+ deprecated = entry.deprecated;
617+ } ) compl.entries in
618 IdlM.ErrM.return { Toplevel_api_gen.from; to_; entries }
619 | None ->
620 IdlM.ErrM.return { Toplevel_api_gen.from = 0; to_ = 0; entries = [] }
···650 IdlM.ErrM.return errors
651652 let type_enclosing source position =
653+ let position =
654+ match position with
655+ | Toplevel_api_gen.Start -> `Start
656+ | Offset x -> `Offset x
657+ | Logical (x, y) -> `Logical (x, y)
658+ | End -> `End in
659 let source = Merlin_kernel.Msource.make source in
660 let query = Query_protocol.Type_enclosing (None, position, None) in
661 let enclosing = wdispatch source query in
662+ let map_index_or_string = function | `Index i -> Toplevel_api_gen.Index i | `String s -> String s in
663+ let map_tail_position = function | `No -> Toplevel_api_gen.No | `Tail_position -> Tail_position | `Tail_call -> Tail_call in
664+ let enclosing = List.map (fun (x,y,z) -> (x,map_index_or_string y,map_tail_position z)) enclosing in
665 IdlM.ErrM.return enclosing
666end