@@ -72,6 +72,7 @@ open Ast_defs
7272open Ast_util
7373open Interpreter
7474open Pretty_print_sail
75+ open Reporting.Position
7576
7677module Callgraph_commands = Callgraph_commands
7778
@@ -141,7 +142,8 @@ let prompt istate =
141142 )
142143 (IdSet. elements istate.display_options.registers)
143144 );
144- match istate.mode with Normal -> " sail> " | Evaluation _ -> " eval> "
145+ let l = Sail_file. repl_prompt_line () in
146+ match istate.mode with Normal -> Printf. sprintf " REPL:%d> " l | Evaluation _ -> Printf. sprintf " REPL:%d eval> " l
145147
146148let mode_clear istate =
147149 match istate.mode with
@@ -417,7 +419,23 @@ let help =
417419 (color green " :help :help" )
418420 )
419421
420- type input = Command of string * string | Expression of string | Empty
422+ type input = Command of string * string * Lexing .position | Expression of string * Lexing .position | Empty
423+
424+ let editor = ref " vim"
425+
426+ let editor_command cmd =
427+ let open Lexing in
428+ let temp_file = Filename. temp_file " repl" " .sail" in
429+ Reporting. system_checked (! editor ^ " " ^ temp_file);
430+ let contents = Util. read_whole_file temp_file in
431+ let start_line, start_bol = Sail_file. add_to_repl_contents ~command: contents in
432+ let pos = { pos_fname = " REPL" ; pos_lnum = start_line; pos_bol = start_bol; pos_cnum = start_bol } in
433+ if cmd = " " then Expression (contents, pos) else Command (cmd, contents, pos)
434+
435+ let () =
436+ let open Interactive in
437+ ArgString (" command" , fun cmd -> ActionUnit (fun _ -> editor := cmd))
438+ |> register_command ~name: " set_editor" ~help: " Set the editor for the :edit command. Default vim"
421439
422440(* This function is called on every line of input passed to the interpreter *)
423441let handle_input' istate input =
@@ -426,16 +444,22 @@ let handle_input' istate input =
426444 (* Process the input and check if it's a command, a raw expression,
427445 or empty. *)
428446 let input =
447+ let open Lexing in
429448 if input <> " " && input.[0 ] = ':' then (
449+ let start_line, start_bol = Sail_file. add_to_repl_contents ~command: input in
430450 let n = try String. index input ' ' with Not_found -> String. length input in
431451 let cmd = Str. string_before input n in
432- let arg = String. trim (Str. string_after input n) in
433- Command (cmd, arg)
452+ let arg = Str. string_after input n in
453+ let pos = { pos_fname = " REPL" ; pos_lnum = start_line; pos_bol = start_bol; pos_cnum = start_bol + n } in
454+ Command (cmd, String. trim arg, trim_position arg pos)
434455 )
435456 else if String. length input > = 2 && input.[0 ] = '/' && input.[1 ] = '/' then
436457 (* Treat anything starting with // as a comment *)
437458 Empty
438- else if input <> " " then Expression input
459+ else if input <> " " then (
460+ let start_line, start_bol = Sail_file. add_to_repl_contents ~command: input in
461+ Expression (input, { pos_fname = " REPL" ; pos_lnum = start_line; pos_bol = start_bol; pos_cnum = start_bol })
462+ )
439463 else Empty
440464 in
441465
@@ -446,10 +470,12 @@ let handle_input' istate input =
446470 istate
447471 in
448472
473+ let input = match input with Command (":edit" , arg , pos ) -> editor_command arg | input -> input in
474+
449475 (* First handle commands that are mode-independent *)
450476 let istate =
451477 match input with
452- | Command (cmd , arg ) -> begin
478+ | Command (cmd , arg , pos ) -> begin
453479 match cmd with
454480 | ":n" | ":normal" -> { istate with mode = Normal }
455481 | ":t" | ":type" ->
@@ -461,17 +487,17 @@ let handle_input' istate input =
461487 Value. output_close () ;
462488 exit 0
463489 | ":i" | ":infer" ->
464- let exp = Initial_check. exp_of_string arg in
490+ let exp = Initial_check. exp_of_string ~inline: pos arg in
465491 let exp = Type_check. infer_exp istate.env exp in
466492 Document. to_channel stdout (doc_typ (Type_check. typ_of exp));
467493 print_newline () ;
468494 istate
469495 | ":prove" ->
470- let nc = Initial_check. constraint_of_string arg in
496+ let nc = Initial_check. constraint_of_string ~inline: pos arg in
471497 print_endline (string_of_bool (Type_check. prove __POS__ istate.env nc));
472498 istate
473499 | ":assume" ->
474- let nc = Initial_check. constraint_of_string arg in
500+ let nc = Initial_check. constraint_of_string ~inline: pos arg in
475501 { istate with env = Type_check.Env. add_constraint nc istate.env }
476502 | ":v" | ":verbose" ->
477503 Type_check. set_tc_debug (int_of_string arg);
@@ -491,8 +517,7 @@ let handle_input' istate input =
491517 [
492518 " Universal commands - :(t)ype :(i)nfer :(q)uit :(v)erbose :prove :assume :clear :commands :help \
493519 :output :option :show_register :hide_register" ;
494- " Normal mode commands - :elf :(l)oad :(u)nload :let :def :(b)ind :recheck :compile :reset "
495- ^ more_commands;
520+ " Normal mode commands - :elf :let :def :(b)ind :recheck :compile :reset " ^ more_commands;
496521 " Evaluation mode commands - :(r)un :(s)tep :step_(f)unction :(n)ormal" ;
497522 " " ;
498523 " :(c)ommand can be called as either :c or :command." ;
@@ -573,36 +598,44 @@ let handle_input' istate input =
573598 match istate.mode with
574599 | Normal -> begin
575600 match input with
576- | Command (cmd , arg ) -> begin
601+ | Command (cmd , arg , pos ) -> begin
577602 (* Normal mode commands *)
578603 match cmd with
579- | ":b" | ":bind" ->
580- let args = Str. split (Str. regexp " +" ) arg in
581- begin
582- match args with
583- | v :: ":" :: args ->
584- let typ = Initial_check. typ_of_string (String. concat " " args) in
585- let _, env, _ = Type_check. bind_pat istate.env (mk_pat (P_id (mk_id v))) typ in
586- { istate with env }
587- | _ -> failwith " Invalid arguments for :bind"
588- end
589- | ":let" ->
590- let args = Str. split (Str. regexp " +" ) arg in
591- begin
592- match args with
593- | v :: "=" :: args ->
594- let exp = Initial_check. exp_of_string (String. concat " " args) in
595- let defs, env =
596- Type_check. check_defs istate.env [mk_def (DEF_let (mk_letbind (mk_pat (P_id (mk_id v))) exp)) () ]
597- in
598- { istate with ast = append_ast_defs istate.ast defs; env }
599- | _ -> failwith " Invalid arguments for :let"
600- end
604+ | ":b" | ":bind" -> begin
605+ match Util. split_on_char ':' arg with
606+ | [v; arg] ->
607+ let typ = Initial_check. typ_of_string ~inline: (advance_position ~after: 1 ~trim: false v pos) arg in
608+ let v_l = string_location ~start: pos ~trim: true v in
609+ let _, env, _ =
610+ Type_check. bind_pat istate.env (mk_pat ~loc: v_l (P_id (mk_id ~loc: v_l (String. trim v)))) typ
611+ in
612+ { istate with env }
613+ | _ -> failwith " Invalid arguments for :bind"
614+ end
615+ | ":let" -> begin
616+ match Util. split_on_char '=' arg with
617+ | [v; exp_str] ->
618+ let exp = Initial_check. exp_of_string ~inline: (advance_position ~after: 1 ~trim: false v pos) exp_str in
619+ let arg_l = string_location ~start: pos ~trim: true arg in
620+ let v_l = string_location ~start: pos ~trim: true v in
621+ let defs, env =
622+ Type_check. check_defs istate.env
623+ [
624+ mk_def ~loc: arg_l
625+ (DEF_let (mk_letbind ~loc: arg_l (mk_pat ~loc: v_l (P_id (mk_id ~loc: v_l (String. trim v)))) exp))
626+ () ;
627+ ]
628+ in
629+ { istate with ast = append_ast_defs istate.ast defs; env }
630+ | _ -> failwith " Invalid arguments for :let"
631+ end
601632 | ":def" ->
633+ (* Add an extra blank line so we can handle directives that require a newline to be parsed. *)
634+ ignore (Sail_file. add_to_repl_contents ~command: " " );
602635 let ast =
603- Initial_check. ast_of_def_string_with __POS__
636+ Initial_check. ast_of_def_string_with ~inline: pos __POS__
604637 (Preprocess. preprocess istate.default_sail_dir None istate.options)
605- arg
638+ ( arg ^ " \n " )
606639 in
607640 let ast, env = Type_check. check istate.env ast in
608641 { istate with ast = append_ast istate.ast ast; env }
@@ -652,10 +685,10 @@ let handle_input' istate input =
652685 | None -> unrecognised_command istate cmd
653686 )
654687 end
655- | Expression str ->
688+ | Expression ( str , pos ) ->
656689 (* An expression in normal mode is type checked, then puts
657690 us in evaluation mode. *)
658- let exp = Type_check. infer_exp istate.env (Initial_check. exp_of_string str) in
691+ let exp = Type_check. infer_exp istate.env (Initial_check. exp_of_string ~inline: pos str) in
659692 let istate = setup_interpreter_state istate in
660693 let istate = { istate with mode = Evaluation (eval_frame (Step (lazy " " , istate.state, return exp, [] ))) } in
661694 print_program istate;
@@ -664,7 +697,7 @@ let handle_input' istate input =
664697 end
665698 | Evaluation frame -> begin
666699 match input with
667- | Command (cmd , arg ) -> begin
700+ | Command (cmd , arg , pos ) -> begin
668701 (* Evaluation mode commands *)
669702 match cmd with
670703 | ":r" | ":run" -> run istate
@@ -720,8 +753,9 @@ let handle_input istate input =
720753 | Failure str ->
721754 print_endline (" Error: " ^ str);
722755 istate
723- | Type_error. Type_error (_ , err ) ->
724- print_endline (fst (Type_error. string_of_type_error err));
756+ | Type_error. Type_error (l , err ) ->
757+ let msg, hint = Type_error. string_of_type_error err in
758+ Reporting. print_type_error ?hint l msg;
725759 istate
726760 | Reporting. Fatal_error err ->
727761 Reporting. print_error ~interactive: true err;
0 commit comments