Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Detect expunged toplevel and point at utop-full #438

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/lib/uTop.ml
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,18 @@ let split_words str =
in
List.rev (skip [] 0)

let is_expunged = lazy (not (List.mem_assoc "Env" (Env.imports ())))

let needs_full_toplevel = function
| "compiler-libs.common" -> true
| _ -> false

let check_expunged library =
if Lazy.force is_expunged && needs_full_toplevel library then
Printf.eprintf "Library %S is part of the compiler libraries, but the current toplevel is expunged. This might not work. Please try in utop-full.\n%!" library

let require packages =
List.iter check_expunged packages;
try
let eff_packages = Findlib.package_deep_ancestors !Topfind.predicates packages in
Topfind.load eff_packages
Expand Down
113 changes: 103 additions & 10 deletions src/lib/uTop_main.ml
Original file line number Diff line number Diff line change
Expand Up @@ -756,7 +756,52 @@ let print_error term msg =
LTerm.set_style term LTerm_style.none >>= fun () ->
LTerm.flush term

let rec loop term =
module Ops = struct
type t =
| Term of LTerm.t
| Test of Stdlib.in_channel

let read_phrase = function
| Term t -> read_phrase t
| Test ic ->
let rec loop () =
let r =
match Stdlib.input_line ic with
| exception End_of_file -> `Eof
| s ->
let n = String.length s in
begin
if n >= 1 && s.[0] = '#' then
`Input (String.sub s 1 (n - 1))
else
`Output
end
in
match r with
| `Eof -> exit 0
| `Input s -> s
| `Output -> loop ()
in
let input = loop () in
Printf.printf "#%s\n%!" input;
let r = parse_and_check input false in
Stdlib.flush Stdlib.stderr;
Lwt.return r

let print_error ops e = match ops with
| Term t -> print_error t e
| Test _ -> Printf.printf "%s%!" e; Lwt.return_unit

let flush = function
| Term t -> LTerm.flush t
| Test _ -> Lwt.return_unit

let render_out_phrase ops s = match ops with
| Term t -> render_out_phrase t s
| Test _ -> Printf.printf "%s%!" s;Lwt.return_unit
end

let rec loop ops =
(* Reset completion. *)
UTop_complete.reset ();

Expand All @@ -771,16 +816,16 @@ let rec loop term =
Lwt_main.run (
Lwt.finalize
(fun () ->
read_phrase term >>= fun (result, warnings) ->
Ops.read_phrase ops >>= fun (result, warnings) ->
(* Print warnings before errors. *)
Lwt_io.print warnings >>= fun () ->
match result with
| UTop.Value phrase ->
return (Some phrase)
| UTop.Error (locs, msg) ->
print_error term msg >>= fun () ->
Ops.print_error ops msg >>= fun () ->
return None)
(fun () -> LTerm.flush term)
(fun () -> Ops.flush ops)
)
in
match phrase_opt with
Expand Down Expand Up @@ -819,10 +864,10 @@ let rec loop term =
match phrase with
| Parsetree.Ptop_def _ ->
(* The string is an output phrase, colorize it. *)
Lwt_main.run (render_out_phrase term string)
Lwt_main.run (Ops.render_out_phrase ops string)
| Parsetree.Ptop_dir _ ->
(* The string is an error message. *)
Lwt_main.run (print_error term string)
Lwt_main.run (Ops.print_error ops string)
with exn ->
(* The only possible errors are directive errors. *)
let msg = UTop.get_message Errors.report_error exn in
Expand All @@ -834,10 +879,10 @@ let rec loop term =
with Not_found ->
msg
in
Lwt_main.run (print_error term msg));
loop term
Lwt_main.run (Ops.print_error ops msg));
loop ops
| None ->
loop term
loop ops

(* +-----------------------------------------------------------------+
| Welcome message |
Expand Down Expand Up @@ -1345,9 +1390,47 @@ let print_version_num () =
Printf.printf "%s\n" UTop.version;
exit 0

module Test = struct
let map_loc f {Location.loc;txt} = {Location.loc; txt= f txt}

let shorten_warning_name s =
Scanf.sscanf s "%d" string_of_int

let shorten_kind = function
| Location.Report_warning s -> Location.Report_warning (shorten_warning_name s)
| k -> k

let short_warning_reporter loc warn =
Option.map
(fun report ->
{ report with
Location.kind = shorten_kind report.Location.kind }
)
(Location.default_warning_reporter loc warn)

let short_report_printer () =
let def = Location.batch_mode_printer in
let pp self ppf report =
Format.fprintf ppf "%a\n" (self.Location.pp_report_kind self report) report.kind;
in
{ def with pp }

let setup () =
Location.warning_reporter := short_warning_reporter;
Location.report_printer := short_report_printer

let run path =
let ic = Stdlib.open_in_bin path in
Fun.protect
(fun () -> loop (Test ic))
~finally:(fun () -> Stdlib.close_in_noerr ic)
end

(* Config from command line *)
let autoload = ref true

let test_file = ref None

let args = Arg.align [
"-absname", Arg.Set Clflags.absname, " Show absolute filenames in error message";
"-I", Arg.String (fun dir -> Clflags.include_dirs := dir :: !Clflags.include_dirs), "<dir> Add <dir> to the list of include directories";
Expand Down Expand Up @@ -1402,6 +1485,7 @@ let args = Arg.align [
"<package> Load this package";
"-dparsetree", Arg.Set Clflags.dump_parsetree, " Dump OCaml AST after rewriting";
"-dsource", Arg.Set Clflags.dump_source, " Dump OCaml source after rewriting";
"-test", Arg.String (fun s -> test_file := Some s), " Test mode (internal)";
]

let () = Clflags.real_paths := false
Expand Down Expand Up @@ -1499,6 +1583,14 @@ let main_aux ~initial_env =
Topcommon.load_topdirs_signature ();
#endif
if not (prepare ()) then exit 2;
match !test_file with
| Some f -> begin
common_init ~initial_env;
Test.setup ();
Test.run f
end
| None ->
begin
if !emacs_mode then begin
Printf.printf "protocol-version:%d\n%!" protocol_version;
UTop_private.set_ui UTop_private.Emacs;
Expand All @@ -1523,7 +1615,7 @@ let main_aux ~initial_env =
flush stdout;
(* Main loop. *)
try
loop term
loop (Ops.Term term)
with LTerm_read_line.Interrupt ->
()
end else begin
Expand All @@ -1535,6 +1627,7 @@ let main_aux ~initial_env =
end;
(* Don't let the standard toplevel run... *)
exit 0
end

let main_internal ~initial_env =
try
Expand Down
5 changes: 5 additions & 0 deletions test/demo.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# type t = () of unit;;
Warning 65
type t = () of unit
# 0;;
- : int = 0
26 changes: 26 additions & 0 deletions test/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
(rule
(with-outputs-to
demo.txt.corrected
(run %{bin:utop} -test %{dep:demo.txt})))

(alias
(name runtest)
(action (diff demo.txt demo.txt.corrected)))

(rule
(with-outputs-to
expunged.txt.corrected
(run %{bin:utop} -test %{dep:expunged.txt})))

(alias
(name runtest)
(action (diff expunged.txt expunged.txt.corrected)))

(rule
(with-outputs-to
expunged-full.txt.corrected
(run %{bin:utop-full} -test %{dep:expunged-full.txt})))

(alias
(name runtest)
(action (diff expunged-full.txt expunged-full.txt.corrected)))
3 changes: 3 additions & 0 deletions test/expunged-full.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# #require "compiler-libs.common";;
# Location.report_warning;;
- : Warnings.loc -> Warnings.t -> Location.report option = <fun>
4 changes: 4 additions & 0 deletions test/expunged.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# #require "compiler-libs.common";;
Library "compiler-libs.common" is part of the compiler libraries, but the current toplevel is expunged. This might not work. Please try in utop-full.
# Location.report_warning;;
Error