···11-(*
22- * uTop.ml
33- * -------
44- * Copyright : (c) 2011, Jeremie Dimino <jeremie@dimino.org>
55- * Licence : BSD3
66- *
77- * This file is a part of utop.
88- *)
99-1010-[@@@warning "-27"]
1111-1212-1313-module String_set = Set.Make(String)
1414-1515-let version = "2.7.0"
1616-1717-(* +-----------------------------------------------------------------+
1818- | Keywords |
1919- +-----------------------------------------------------------------+ *)
2020-2121-let default_keywords = [
2222- "and"; "as"; "assert"; "begin"; "class"; "constraint"; "do";
2323- "done"; "downto"; "else"; "end"; "exception"; "external";
2424- "for"; "fun"; "function"; "functor"; "if"; "in"; "include";
2525- "inherit"; "initializer"; "lazy"; "let"; "match"; "method"; "module";
2626- "mutable"; "new"; "object"; "of"; "open"; "private"; "rec"; "sig";
2727- "struct"; "then"; "to"; "try"; "type"; "val"; "virtual";
2828- "when"; "while"; "with"; "try_lwt"; "finally"; "for_lwt"; "lwt";
2929-]
3030-3131-let keywords = ref (String_set.of_list default_keywords)
3232-let add_keyword kwd = keywords := String_set.add kwd !keywords
3333-3434-(* +-----------------------------------------------------------------+
3535- | Span of Lines |
3636- +-----------------------------------------------------------------+ *)
3737-3838-type lines = {
3939- start: int;
4040- stop: int;
4141-}
4242-4343-(* +-----------------------------------------------------------------+
4444- | Error reporting |
4545- +-----------------------------------------------------------------+ *)
4646-4747-let get_message func x =
4848- let buffer = Buffer.create 1024 in
4949- let pp = Format.formatter_of_buffer buffer in
5050- func pp x;
5151- Format.pp_print_flush pp ();
5252- Buffer.contents buffer
5353-5454-let get_ocaml_error_message exn =
5555- let buffer = Buffer.create 1024 in
5656- let pp = Format.formatter_of_buffer buffer in
5757- Errors.report_error pp exn;
5858- Format.pp_print_flush pp ();
5959- let str = Buffer.contents buffer in
6060- try
6161- Scanf.sscanf
6262- str
6363- "Characters %d-%d:\n%[\000-\255]"
6464- (fun start stop msg -> ((start, stop), msg, None))
6565- with Scanf.Scan_failure(_) ->
6666- try
6767- Scanf.sscanf
6868- str
6969- "Line %d, characters %d-%d:\n%[\000-\255]"
7070- (fun line start stop msg -> ((start, stop), msg, Some{start=line; stop=line}))
7171- with Scanf.Scan_failure(_) ->
7272- try
7373- Scanf.sscanf
7474- str
7575- "Lines %d-%d, characters %d-%d:\n%[\000-\255]"
7676- (fun start_line stop_line start stop msg -> ((start, stop),
7777- msg, Some{start=start_line;stop=stop_line}))
7878- with Scanf.Scan_failure(_) ->
7979- ((0, 0), str, None)
8080-8181-let collect_formatters buf pps f =
8282- (* First flush all formatters. *)
8383- List.iter (fun pp -> Format.pp_print_flush pp ()) pps;
8484- (* Save all formatter functions. *)
8585- let save = List.map (fun pp -> Format.pp_get_formatter_out_functions pp ()) pps in
8686- let restore () =
8787- List.iter2
8888- (fun pp out_functions ->
8989- Format.pp_print_flush pp ();
9090- Format.pp_set_formatter_out_functions pp out_functions)
9191- pps save
9292- in
9393- (* Output functions. *)
9494- let out_functions =
9595- let ppb = Format.formatter_of_buffer buf in
9696- Format.pp_get_formatter_out_functions ppb ()
9797- in
9898- (* Replace formatter functions. *)
9999- List.iter
100100- (fun pp ->
101101- Format.pp_set_formatter_out_functions pp out_functions)
102102- pps;
103103- try
104104- let x = f () in
105105- restore ();
106106- x
107107- with exn ->
108108- restore ();
109109- raise exn
110110-111111-let discard_formatters pps f =
112112- (* First flush all formatters. *)
113113- List.iter (fun pp -> Format.pp_print_flush pp ()) pps;
114114- (* Save all formatter functions. *)
115115- let save = List.map (fun pp -> Format.pp_get_formatter_out_functions pp ()) pps in
116116- let restore () =
117117- List.iter2
118118- (fun pp out_functions ->
119119- Format.pp_print_flush pp ();
120120- Format.pp_set_formatter_out_functions pp out_functions)
121121- pps save
122122- in
123123- (* Output functions. *)
124124- let out_functions = {
125125- Format.out_string = (fun _ _ _ -> ()); out_flush = ignore;
126126- out_newline = ignore; out_spaces = ignore
127127-#if OCAML_VERSION >= (4, 06, 0)
128128- ; out_indent = ignore
129129-#endif
130130- } in
131131- (* Replace formatter functions. *)
132132- List.iter (fun pp -> Format.pp_set_formatter_out_functions pp out_functions) pps;
133133- try
134134- let x = f () in
135135- restore ();
136136- x
137137- with exn ->
138138- restore ();
139139- raise exn
140140-141141-(* +-----------------------------------------------------------------+
142142- | Parsing |
143143- +-----------------------------------------------------------------+ *)
144144-145145-type location = int * int
146146-147147-type 'a result =
148148- | Value of 'a
149149- | Error of location list * string
150150-151151-exception Need_more
152152-153153-let input_name = "//toplevel//"
154154-155155-let lexbuf_of_string eof str =
156156- let pos = ref 0 in
157157- let lexbuf =
158158- Lexing.from_function
159159- (fun buf len ->
160160- if !pos = String.length str then begin
161161- eof := true;
162162- 0
163163- end else begin
164164- let len = min len (String.length str - !pos) in
165165- String.blit str !pos buf 0 len;
166166- pos := !pos + len;
167167- len
168168- end)
169169- in
170170- Location.init lexbuf input_name;
171171- lexbuf
172172-173173-let mkloc loc =
174174- (loc.Location.loc_start.Lexing.pos_cnum,
175175- loc.Location.loc_end.Lexing.pos_cnum)
176176-177177- let inline_code =
178178- Misc.Style.inline_code
179179-let invalid_package_error_to_string err =
180180- let invalid ppf ipt = match ipt with
181181- | Syntaxerr.Parameterized_types ->
182182- Format.fprintf ppf "parametrized types are not supported"
183183- | Constrained_types ->
184184- Format.fprintf ppf "constrained types are not supported"
185185- | Private_types ->
186186- Format.fprintf ppf "private types are not supported"
187187- | Not_with_type ->
188188- Format.fprintf ppf "only %a constraints are supported"
189189- inline_code "with type t ="
190190- | Neither_identifier_nor_with_type ->
191191- Format.fprintf ppf
192192- "only module type identifier and %a constraints are supported"
193193- inline_code "with type"
194194- in
195195- let buf = Buffer.create 128 in
196196- let fmt = Format.formatter_of_buffer buf in
197197- Format.fprintf fmt "Invalid package type: %a%!" invalid err;
198198- Buffer.contents buf
199199-200200-let parse_default parse str eos_is_error =
201201- let eof = ref false in
202202- let lexbuf = lexbuf_of_string eof str in
203203- try
204204- (* Try to parse the phrase. *)
205205- let phrase = parse lexbuf in
206206- Value phrase
207207- with
208208- | _ when !eof && not eos_is_error ->
209209- (* This is not an error, we just need more input. *)
210210- raise Need_more
211211- | End_of_file ->
212212- (* If the string is empty, do not report an error. *)
213213- raise Need_more
214214- | Lexer.Error (error, loc) ->
215215- (match Location.error_of_exn (Lexer.Error (error, loc)) with
216216- | Some (`Ok error)->
217217- Error ([mkloc loc], get_message Location.print_report error)
218218- | _-> raise Need_more)
219219- | Syntaxerr.Error error -> begin
220220- match error with
221221- | Syntaxerr.Unclosed (opening_loc, opening, closing_loc, closing) ->
222222- Error ([mkloc opening_loc; mkloc closing_loc],
223223- Printf.sprintf "Syntax error: '%s' expected, the highlighted '%s' might be unmatched" closing opening)
224224- | Syntaxerr.Applicative_path loc ->
225225- Error ([mkloc loc],
226226- "Syntax error: applicative paths of the form F(X).t are not supported when the option -no-app-funct is set.")
227227- | Syntaxerr.Other loc ->
228228- Error ([mkloc loc],
229229- "Syntax error")
230230- | Syntaxerr.Expecting (loc, nonterm) ->
231231- Error ([mkloc loc],
232232- Printf.sprintf "Syntax error: %s expected." nonterm)
233233- | Syntaxerr.Variable_in_scope (loc, var) ->
234234- Error ([mkloc loc],
235235- Printf.sprintf "In this scoped type, variable '%s is reserved for the local type %s." var var)
236236- | Syntaxerr.Not_expecting (loc, nonterm) ->
237237- Error ([mkloc loc],
238238- Printf.sprintf "Syntax error: %s not expected" nonterm)
239239- | Syntaxerr.Ill_formed_ast (loc, s) ->
240240- Error ([mkloc loc],
241241- Printf.sprintf "Error: broken invariant in parsetree: %s" s)
242242- | Syntaxerr.Invalid_package_type (loc, s) ->
243243- Error ([mkloc loc],
244244- Printf.sprintf "Invalid package type: %s" (invalid_package_error_to_string s))
245245-#if OCAML_VERSION >= (5, 0, 0)
246246- | Syntaxerr.Removed_string_set loc ->
247247- Error ([mkloc loc],
248248- "Syntax error: strings are immutable, there is no assignment \
249249- syntax for them.\n\
250250- Hint: Mutable sequences of bytes are available in the Bytes module.\n\
251251- Hint: Did you mean to use 'Bytes.set'?")
252252-#endif
253253- end
254254- | Syntaxerr.Escape_error | Parsing.Parse_error ->
255255- Error ([mkloc (Location.curr lexbuf)],
256256- "Syntax error")
257257- | exn ->
258258- Error ([], "Unknown parsing error (please report it to the utop project): " ^ Printexc.to_string exn)
259259-260260-let parse_toplevel_phrase_default = parse_default Parse.toplevel_phrase
261261-let parse_toplevel_phrase = ref parse_toplevel_phrase_default
262262-263263-(* +-----------------------------------------------------------------+
264264- | Safety checking |
265265- +-----------------------------------------------------------------+ *)
266266-267267-let null = Format.make_formatter (fun str ofs len -> ()) ignore
268268-269269-let rec last head tail =
270270- match tail with
271271- | [] ->
272272- head
273273- | head :: tail ->
274274- last head tail
275275-276276-let with_loc loc str = {
277277- Location.txt = str;
278278- Location.loc = loc;
279279-}
280280-281281- let fun_ ~loc p e =
282282- let open Parsetree in
283283- let open Ast_helper in
284284- let args = [{
285285- pparam_loc=loc;
286286- pparam_desc=Pparam_val (Nolabel, None, p);
287287- }] in
288288- (Exp.function_ args None (Pfunction_body e))
289289-290290-(* Check that the given phrase can be evaluated without typing/compile
291291- errors. *)
292292-let check_phrase phrase =
293293- let open Parsetree in
294294- match phrase with
295295- | Ptop_dir _ ->
296296- None
297297- | Ptop_def [] ->
298298- None
299299- | Ptop_def (item :: items) ->
300300- let loc = {
301301- Location.loc_start = item.pstr_loc.Location.loc_start;
302302- Location.loc_end = (last item items).pstr_loc.Location.loc_end;
303303- Location.loc_ghost = false;
304304- } in
305305- (* Backup. *)
306306- let snap = Btype.snapshot () in
307307- let env = !Toploop.toplevel_env in
308308- (* Construct "let _ () = let module _ = struct <items> end in ()" in order to test
309309- the typing and compilation of [items] without evaluating them. *)
310310- let unit =
311311- let (%.) a b = Longident.Ldot (a, b) in
312312- with_loc loc (Lident "Stdlib" %. "Unit" %. "()")
313313- in
314314- let top_def =
315315- let open Ast_helper in
316316- with_default_loc loc
317317- (fun () ->
318318- let punit = (Pat.construct unit None) in
319319- let body = (Exp.letmodule ~loc:loc
320320- (with_loc loc (Some "_"))
321321- (Mod.structure (item :: items))
322322- (Exp.construct unit None)) in
323323- Str.eval (fun_ ~loc punit body))
324324- in
325325- let check_phrase = Ptop_def [top_def] in
326326- try
327327- let _ =
328328- discard_formatters [Format.err_formatter] (fun () ->
329329- Env.reset_cache_toplevel ();
330330- Toploop.execute_phrase false null check_phrase)
331331- in
332332- (* The phrase is safe. *)
333333- Toploop.toplevel_env := env;
334334- Btype.backtrack snap;
335335- None
336336- with exn ->
337337- (* The phrase contains errors. *)
338338- let loc, msg, line = get_ocaml_error_message exn in
339339- Toploop.toplevel_env := env;
340340- Btype.backtrack snap;
341341- Some ([loc], msg, [line])
342342-343343-344344-345345-(*let try_finally ~always work=
346346-#if OCAML_VERSION >= (4, 08, 0)
347347- Misc.try_finally ~always work
348348-#else
349349- Misc.try_finally work always
350350-#endif
351351-352352-let use_output command =
353353- let fn = Filename.temp_file "ocaml" "_toploop.ml" in
354354- try_finally ~always:(fun () ->
355355- try Sys.remove fn with Sys_error _ -> ())
356356- (fun () ->
357357- match
358358- Printf.ksprintf Sys.command "%s > %s"
359359- command
360360- (Filename.quote fn)
361361- with
362362- | 0 ->
363363- ignore (Toploop.use_file Format.std_formatter fn : bool)
364364- | n ->
365365- Format.printf "Command exited with code %d.@." n)
366366-367367-let () =
368368- let name = "use_output" in
369369- if not (Hashtbl.mem Toploop.directive_table name) then
370370- Hashtbl.add
371371- Toploop.directive_table
372372- name
373373- (Toploop.Directive_string use_output)
374374-*)
375375-376376- (* +-----------------------------------------------------------------+
377377- | Compiler-libs re-exports |
378378- +-----------------------------------------------------------------+ *)
379379-380380-let get_load_path () =
381381- let {Load_path.visible; hidden} = Load_path.get_paths () in
382382- visible @ hidden
383383-384384-385385-#if OCAML_VERSION >= (5, 0, 0)
386386-let set_load_path visible =
387387- Load_path.init ~auto_include:Load_path.no_auto_include ~visible ~hidden:[]
388388-#else
389389-let set_load_path path = Load_path.init path
390390-#endif
-108
lib/uTop.mli
···11-(*
22- * uTop.mli
33- * --------
44- * Copyright : (c) 2011, Jeremie Dimino <jeremie@dimino.org>
55- * Licence : BSD3
66- *
77- * This file is a part of utop.
88- *)
99-1010-(** UTop configuration. *)
1111-1212-val version : string
1313-(** Version of utop. *)
1414-1515-val keywords : Set.Make(String).t ref
1616-(** The set of OCaml keywords. *)
1717-1818-val add_keyword : string -> unit
1919-(** Add a new OCaml keyword. *)
2020-2121-(** {6 Parsing} *)
2222-2323-type location = int * int
2424-(** Type of a string-location. It is composed of a start and stop offsets (in
2525- bytes). *)
2626-2727-type lines = { start : int; stop : int }
2828-(** Type for a range of lines in a buffer from start to stop. *)
2929-3030-(** Result of a function processing a programx. *)
3131-type 'a result =
3232- | Value of 'a (** The function succeeded and returned this value. *)
3333- | Error of location list * string
3434- (** The function failed. Arguments are a list of locations to highlight in
3535- the source and an error message. *)
3636-3737-exception Need_more
3838-(** Exception raised by a parser when it need more data. *)
3939-4040-val parse_toplevel_phrase :
4141- (string -> bool -> Parsetree.toplevel_phrase result) ref
4242-(** [parse_toplevel_phrase] is the function used to parse a phrase typed in the
4343- toplevel.
4444-4545- Its arguments are:
4646-4747- - [input]: the string to parse
4848- - [eos_is_error]
4949-5050- If [eos_is_error] is [true] and the parser reach the end of input, then
5151- {!Parse_failure} should be returned.
5252-5353- If [eos_is_error] is [false] and the parser reach the end of input, the
5454- exception {!Need_more} must be thrown.
5555-5656- Except for {!Need_more}, the function must not raise any exception. *)
5757-5858-val parse_toplevel_phrase_default :
5959- string -> bool -> Parsetree.toplevel_phrase result
6060-(** The default parser for toplevel phrases. It uses the standard ocaml parser.
6161-*)
6262-6363-val parse_default : (Lexing.lexbuf -> 'a) -> string -> bool -> 'a result
6464-(** The default parser. It uses the standard ocaml parser. *)
6565-6666-val input_name : string
6767-(** The name you must use in location to let ocaml know that it is from the
6868- toplevel. *)
6969-7070-val lexbuf_of_string : bool ref -> string -> Lexing.lexbuf
7171-(** [lexbuf_of_string eof str] is the same as [Lexing.from_string str] except
7272- that if the lexer reach the end of [str] then [eof] is set to [true]. *)
7373-7474-(** {6 Helpers} *)
7575-7676-val get_message : (Format.formatter -> 'a -> unit) -> 'a -> string
7777-(** [get_message printer x] applies [printer] on [x] and returns everything it
7878- prints as a string. *)
7979-8080-val get_ocaml_error_message : exn -> location * string * lines option
8181-(** [get_ocaml_error_message exn] returns the location and error message for the
8282- exception [exn] which must be an exception from the compiler. *)
8383-8484-val check_phrase :
8585- Parsetree.toplevel_phrase ->
8686- (location list * string * lines option list) option
8787-(** [check_phrase phrase] checks that [phrase] can be executed without typing or
8888- compilation errors. It returns [None] if [phrase] is OK and an error message
8989- otherwise. If the result is [None] it is guaranteed that
9090- [Toploop.execute_phrase] won't raise any exception. *)
9191-9292-val collect_formatters : Buffer.t -> Format.formatter list -> (unit -> 'a) -> 'a
9393-(** [collect_formatters buf pps f] executes [f] and redirect everything it
9494- prints on [pps] to [buf]. *)
9595-9696-val discard_formatters : Format.formatter list -> (unit -> 'a) -> 'a
9797-(** [discard_formatters pps f] executes [f], dropping everything it prints on
9898- [pps]. *)
9999-100100-(** {6 compiler-libs reexports} *)
101101-102102-val get_load_path : unit -> string list
103103-104104-val set_load_path : string list -> unit
105105-(** [get_load_path] and [set_load_path] manage the include directories.
106106-107107- The internal variable contains the list of directories added by
108108- findlib-required packages and [#directory] directives. *)
-152
lib/uTop_compat.ml
···11-let get_desc x =
22-#if OCAML_VERSION >= (4, 14, 0)
33- Types.get_desc x
44-#else
55- x.Types.desc
66-#endif
77-88-let toploop_get_directive name =
99-#if OCAML_VERSION >= (4, 13, 0)
1010- Toploop.get_directive name
1111-#else
1212- try Some (Hashtbl.find Toploop.directive_table name) with Not_found -> None
1313-#endif
1414-1515-let toploop_all_directive_names () =
1616-#if OCAML_VERSION >= (4, 13, 0)
1717- Toploop.all_directive_names ()
1818-#else
1919- Hashtbl.fold (fun dir _ acc -> dir::acc) Toploop.directive_table []
2020-#endif
2121-2222-let get_load_path () =
2323-#if OCAML_VERSION >= (5, 2, 0)
2424- let {Load_path.visible; hidden} = Load_path.get_paths () in
2525- visible @ hidden
2626-#else
2727- Load_path.get_paths ()
2828-#endif
2929-3030-let set_load_path visible =
3131-#if OCAML_VERSION >= (5, 2, 0)
3232- Load_path.init ~auto_include:Load_path.no_auto_include ~visible ~hidden:[]
3333-#elif OCAML_VERSION >= (5, 0, 0)
3434- Load_path.init ~auto_include:Load_path.no_auto_include visible
3535-#else
3636- Load_path.init visible
3737-#endif
3838-3939-let toploop_use_silently fmt name =
4040-#if OCAML_VERSION >= (4, 14, 0)
4141- Toploop.use_silently fmt (match name with "" -> Stdin | _ -> File name)
4242-#else
4343- Toploop.use_silently fmt name
4444-#endif
4545-4646-let toploop_set_paths () =
4747-#if OCAML_VERSION >= (5, 0, 0)
4848- Toploop.set_paths ~auto_include:Load_path.no_auto_include ()
4949-#else
5050- Toploop.set_paths ()
5151-#endif
5252-5353-let toploop_load_file ppf fn =
5454-#if OCAML_VERSION >= (4, 13, 0)
5555- Toploop.load_file ppf fn
5656-#else
5757- Topdirs.load_file ppf fn
5858-#endif
5959-6060-(** Returns whether the given path is persistent. *)
6161-let rec is_persistent_path = function
6262- | Path.Pident id -> Ident.persistent id
6363- | Path.Pdot (p, _) -> is_persistent_path p
6464- | Path.Papply (_, p) -> is_persistent_path p
6565-#if OCAML_VERSION >= (5, 1, 0)
6666- | Path.Pextra_ty (p, _) -> is_persistent_path p
6767-#endif
6868-6969-#if OCAML_VERSION >= (5, 2, 0)
7070-let inline_code =
7171-#if OCAML_VERSION >= (5, 3, 0)
7272- (Format_doc.compat Misc.Style.inline_code)
7373-#else
7474- Misc.Style.inline_code
7575-#endif
7676-#endif
7777-7878-let invalid_package_error_to_string err =
7979-#if OCAML_VERSION >= (5, 2, 0)
8080- (* NOTE: from https://github.com/ocaml/ocaml/blob/9b059b1e7a66e9d2f04d892a4de34c418cd96f69/parsing/parse.ml#L149 *)
8181- let invalid ppf ipt = match ipt with
8282- | Syntaxerr.Parameterized_types ->
8383- Format.fprintf ppf "parametrized types are not supported"
8484- | Constrained_types ->
8585- Format.fprintf ppf "constrained types are not supported"
8686- | Private_types ->
8787- Format.fprintf ppf "private types are not supported"
8888- | Not_with_type ->
8989- Format.fprintf ppf "only %a constraints are supported"
9090- inline_code "with type t ="
9191- | Neither_identifier_nor_with_type ->
9292- Format.fprintf ppf
9393- "only module type identifier and %a constraints are supported"
9494- inline_code "with type"
9595- in
9696- let buf = Buffer.create 128 in
9797- let fmt = Format.formatter_of_buffer buf in
9898- Format.fprintf fmt "Invalid package type: %a%!" invalid err;
9999- Buffer.contents buf
100100-#else
101101- err
102102-#endif
103103-104104-module Exp = struct
105105- open Ast_helper
106106-#if OCAML_VERSION >= (5, 2, 0)
107107- open Parsetree
108108- let fun_ ~loc p e =
109109- let args = [{
110110- pparam_loc=loc;
111111- pparam_desc=Pparam_val (Nolabel, None, p);
112112- }] in
113113- (Exp.function_ args None (Pfunction_body e))
114114-#else
115115- let fun_ ~loc p e = Exp.fun_ ~loc Nolabel None p e
116116-#endif
117117-end
118118-119119-let abstract_type_kind =
120120-#if OCAML_VERSION >= (5, 2, 0)
121121- Types.(Type_abstract Definition)
122122-#else
123123- Types.Type_abstract
124124-#endif
125125-126126-let find_in_path_normalized =
127127-#if OCAML_VERSION >= (5, 2, 0)
128128- Misc.find_in_path_normalized
129129-#else
130130- Misc.find_in_path_uncap
131131-#endif
132132-133133-let visible_paths_for_cmt_infos (cmt_infos: Cmt_format.cmt_infos) =
134134-#if OCAML_VERSION >= (5, 2, 0)
135135- cmt_infos.cmt_loadpath.visible
136136-#else
137137- cmt_infos.cmt_loadpath
138138-#endif
139139-140140-let add_cmi_hook f =
141141- let default_load = !Persistent_env.Persistent_signature.load in
142142-#if OCAML_VERSION >= (5, 2, 0)
143143- let load ~allow_hidden ~unit_name =
144144- let res = default_load ~unit_name ~allow_hidden in
145145-#else
146146- let load ~unit_name =
147147- let res = default_load ~unit_name in
148148-#endif
149149- (match res with None -> () | Some x -> f x.cmi);
150150- res
151151- in
152152- Persistent_env.Persistent_signature.load := load
-1095
lib/uTop_complete.ml
···11-(*
22- * uTop_complete.ml
33- * ----------------
44- * Copyright : (c) 2011, Jeremie Dimino <jeremie@dimino.org>
55- * Licence : BSD3
66- *
77- * This file is a part of utop.
88- *)
99-1010-[@@@warning "-9-27-32"]
1111-1212-open Types
1313-open UTop_token
1414-1515-module String_set = Set.Make(String)
1616-module String_map = Map.Make(String)
1717-1818-let lookup_assoc word words = List.filter (fun (word', _) -> Astring.String.is_prefix ~affix:word word') words
1919-let lookup word words = List.filter (fun word' -> Astring.String.is_prefix word' ~affix:word) words
2020-2121-let set_of_list = List.fold_left (fun set x -> String_set.add x set) String_set.empty
2222-2323-(* +-----------------------------------------------------------------+
2424- | Utils |
2525- +-----------------------------------------------------------------+ *)
2626-let get_desc x =
2727-#if OCAML_VERSION >= (4, 14, 0)
2828- Types.get_desc x
2929-#else
3030- x.Types.desc
3131-#endif
3232-3333-(* Transform a non-empty list of strings into a long-identifier. *)
3434-let longident_of_list = function
3535- | [] ->
3636- invalid_arg "UTop_complete.longident_of_list"
3737- | component :: rest ->
3838- let rec loop acc = function
3939- | [] -> acc
4040- | component :: rest -> loop (Longident.Ldot(acc, component)) rest
4141- in
4242- loop (Longident.Lident component) rest
4343-4444-(* Check whether an identifier is a valid one. *)
4545-let is_valid_identifier id =
4646- id <> "" &&
4747- (match id.[0] with
4848- | 'A' .. 'Z' | 'a' .. 'z' | '_' -> true
4949- | _ -> false)
5050-5151-let add id set = if is_valid_identifier id then String_set.add id set else set
5252-5353-let lookup_env f x env =
5454- try
5555- Some (f x env)
5656- with Not_found | Env.Error _ ->
5757- None
5858-5959-(* +-----------------------------------------------------------------+
6060- | Parsing |
6161- +-----------------------------------------------------------------+ *)
6262-6363-(* The following functions takes a list of tokens in reverse order. *)
6464-6565-type value_or_field = Value | Field
6666- (* Either a value, or a record field. *)
6767-6868-(* Parse something of the form [M1.M2. ... .Mn.id] or
6969- [field.M1.M2. ... .Mn.id] *)
7070-let parse_longident tokens =
7171- let rec loop acc tokens =
7272- match tokens with
7373- | (Symbol ".", _) :: (Uident id, _) :: tokens ->
7474- loop (id :: acc) tokens
7575- | (Symbol ".", _) :: (Lident id, _) :: tokens ->
7676- (Field,
7777- match acc with
7878- | [] -> None
7979- | l -> Some (longident_of_list l))
8080- | _ ->
8181- (Value,
8282- match acc with
8383- | [] -> None
8484- | l -> Some (longident_of_list l))
8585- in
8686- match tokens with
8787- | ((Comment (_, false) | String (_, false) | Quotation (_, false)), _) :: _ ->
8888- (* An unterminated command, string, or quotation. *)
8989- None
9090- | ((Uident id | Lident id), { idx1 = start }) :: tokens ->
9191- (* An identifier. *)
9292- let kind, path = loop [] tokens in
9393- Some (kind, path, start, id)
9494- | (Blanks, { idx2 = stop }) :: tokens ->
9595- (* Some blanks at the end. *)
9696- let kind, path = loop [] tokens in
9797- Some (kind, path, stop, "")
9898- | (_, { idx2 = stop }) :: _ ->
9999- (* Otherwise complete after the last token. *)
100100- let kind, path = loop [] tokens in
101101- Some (kind, path, stop, "")
102102- | [] ->
103103- None
104104-105105-(* Parse something of the form [M1.M2. ... .Mn.id#m1#m2# ... #mp#m] *)
106106-let parse_method tokens =
107107- (* Collect [M1.M2. ... .Mn.id] and returns the corresponding
108108- longidentifier. *)
109109- let rec loop_uidents acc tokens =
110110- match tokens with
111111- | (Symbol ".", _) :: (Uident id, _) :: tokens ->
112112- loop_uidents (id :: acc) tokens
113113- | _ ->
114114- longident_of_list acc
115115- in
116116- (* Collect [m1#m2# ... #mp] *)
117117- let rec loop_methods acc tokens =
118118- match tokens with
119119- | (Lident meth, _) :: (Symbol "#", _) :: tokens ->
120120- loop_methods (meth :: acc) tokens
121121- | (Lident id, _) :: tokens ->
122122- Some (loop_uidents [id] tokens, acc)
123123- | _ ->
124124- None
125125- in
126126- match tokens with
127127- | (Lident meth, { idx1 = start }) :: (Symbol "#", _) :: tokens -> begin
128128- match loop_methods [] tokens with
129129- | None -> None
130130- | Some (path, meths) -> Some (path, meths, start, meth)
131131- end
132132- | (Symbol "#", { idx2 = stop }) :: tokens
133133- | (Blanks, { idx2 = stop }) :: (Symbol "#", _) :: tokens -> begin
134134- match loop_methods [] tokens with
135135- | None -> None
136136- | Some (path, meths) -> Some (path, meths, stop, "")
137137- end
138138- | _ ->
139139- None
140140-141141-type label_kind = Required | Optional
142142- (* Kind of labels: required or optional. *)
143143-144144-type fun_or_new = Fun | New
145145- (* Either a function application, either an object creation. *)
146146-147147-(* Parse something of the form [M1.M2. ... .Mn.id#m1#m2# ... #mp expr1 ... exprq ~label]
148148- or [new M1.M2. ... .Mn.id expr1 ... exprq ~label] *)
149149-let parse_label tokens =
150150- (* Collect [M1.M2. ... .Mn] *)
151151- let rec loop_uidents acc_uidents acc_methods tokens =
152152- match tokens with
153153- | (Lident "new", _) :: _ ->
154154- Some (New, longident_of_list acc_uidents, acc_methods)
155155- | ((Lident id | Uident id), _) :: _ when String_set.mem id !UTop.keywords ->
156156- Some (Fun, longident_of_list acc_uidents, acc_methods)
157157- | (Symbol ".", _) :: (Uident id, _) :: tokens ->
158158- loop_uidents (id :: acc_uidents) acc_methods tokens
159159- | (Symbol ("~" | "?" | ":" | "." | "#" | "!" | "`"), _) :: tokens ->
160160- search tokens
161161- | (Symbol ")", _) :: tokens ->
162162- skip tokens "(" []
163163- | (Symbol "}", _) :: tokens ->
164164- skip tokens "{" []
165165- | (Symbol "]", _) :: tokens ->
166166- skip tokens "[" []
167167- | (Symbol _, _) :: _ ->
168168- Some (Fun, longident_of_list acc_uidents, acc_methods)
169169- | [] ->
170170- Some (Fun, longident_of_list acc_uidents, acc_methods)
171171- | _ ->
172172- search tokens
173173- and loop_methods acc tokens =
174174- match tokens with
175175- | ((Lident id | Uident id), _) :: _ when String_set.mem id !UTop.keywords ->
176176- None
177177- | (Symbol ("~" | "?" | ":" | "." | "#" | "!" | "`"), _) :: tokens ->
178178- search tokens
179179- | (Symbol ")", _) :: tokens ->
180180- skip tokens "(" []
181181- | (Symbol "}", _) :: tokens ->
182182- skip tokens "{" []
183183- | (Symbol "]", _) :: tokens ->
184184- skip tokens "[" []
185185- | (Symbol _, _) :: _ ->
186186- None
187187- | (Lident id, _) :: (Symbol "#", _) :: tokens ->
188188- loop_methods (id :: acc) tokens
189189- | (Lident id, _) :: tokens ->
190190- loop_uidents [id] acc tokens
191191- | [] ->
192192- None
193193- | _ ->
194194- search tokens
195195- and search tokens =
196196- match tokens with
197197- | ((Lident id | Uident id), _) :: _ when String_set.mem id !UTop.keywords ->
198198- None
199199- | (Symbol ("~" | "?" | ":" | "." | "#" | "!" | "`"), _) :: tokens ->
200200- search tokens
201201- | (Symbol ")", _) :: tokens ->
202202- skip tokens "(" []
203203- | (Symbol "}", _) :: tokens ->
204204- skip tokens "{" []
205205- | (Symbol "]", _) :: tokens ->
206206- skip tokens "[" []
207207- | (Symbol _, _) :: _ ->
208208- None
209209- | (Lident id, _) :: (Symbol "#", _) :: tokens ->
210210- loop_methods [id] tokens
211211- | (Lident id, _) :: tokens ->
212212- loop_uidents [id] [] tokens
213213- | _ :: tokens ->
214214- search tokens
215215- | [] ->
216216- None
217217- and skip tokens top stack =
218218- match tokens with
219219- | (Symbol symbol, _) :: tokens when symbol = top -> begin
220220- match stack with
221221- | [] -> search tokens
222222- | top :: stack -> skip tokens top stack
223223- end
224224- | (Symbol ")", _) :: tokens ->
225225- skip tokens "(" (top :: stack)
226226- | (Symbol "}", _) :: tokens ->
227227- skip tokens "{" (top :: stack)
228228- | (Symbol "]", _) :: tokens ->
229229- skip tokens "[" (top :: stack)
230230- | _ :: tokens ->
231231- skip tokens top stack
232232- | [] ->
233233- None
234234- in
235235- match tokens with
236236- | (Lident label, { idx1 = start }) :: (Symbol "~", _) :: tokens -> begin
237237- match search tokens with
238238- | None -> None
239239- | Some (kind, id, meths) -> Some (kind, id, meths, Required, start, label)
240240- end
241241- | (Symbol "~", { idx2 = stop }) :: tokens -> begin
242242- match search tokens with
243243- | None -> None
244244- | Some (kind, id, meths) -> Some (kind, id, meths, Required, stop, "")
245245- end
246246- | (Lident label, { idx1 = start }) :: (Symbol "?", _) :: tokens -> begin
247247- match search tokens with
248248- | None -> None
249249- | Some (kind, id, meths) -> Some (kind, id, meths, Optional, start, label)
250250- end
251251- | (Symbol "?", { idx2 = stop }) :: tokens -> begin
252252- match search tokens with
253253- | None -> None
254254- | Some (kind, id, meths) -> Some (kind, id, meths, Optional, stop, "")
255255- end
256256- | _ ->
257257- None
258258-259259-(* +-----------------------------------------------------------------+
260260- | Directive listing |
261261- +-----------------------------------------------------------------+ *)
262262-263263-let[@alert "-deprecated"] list_directives phrase_terminator =
264264- String_map.bindings
265265- (Hashtbl.fold
266266- (fun dir kind map ->
267267- let suffix =
268268- match kind with
269269- | Toploop.Directive_none _ -> phrase_terminator
270270- | Toploop.Directive_string _ -> " \""
271271- | Toploop.Directive_bool _ | Toploop.Directive_int _ | Toploop.Directive_ident _ -> " "
272272- in
273273- String_map.add dir suffix map)
274274- Toploop.directive_table
275275- String_map.empty)
276276-277277-(* +-----------------------------------------------------------------+
278278- | File listing |
279279- +-----------------------------------------------------------------+ *)
280280-281281-type file_kind = Directory | File
282282-283283-let basename name =
284284- let name' = Filename.basename name in
285285- if name' = "." && not (Astring.String.is_suffix name ~affix:".") then
286286- ""
287287- else
288288- name'
289289-290290-let add_files filter acc dir =
291291- Array.fold_left
292292- (fun map name ->
293293- let absolute_name = Filename.concat dir name in
294294- if try Sys.is_directory absolute_name with Sys_error _ -> false then
295295- String_map.add (Filename.concat name "") Directory map
296296- else if filter name then
297297- String_map.add name File map
298298- else
299299- map)
300300- acc
301301- (try Sys.readdir dir with Sys_error _ -> [||])
302302-303303-let list_directories dir =
304304- String_set.elements
305305- (Array.fold_left
306306- (fun set name ->
307307- let absolute_name = Filename.concat dir name in
308308- if try Sys.is_directory absolute_name with Sys_error _ -> false then
309309- String_set.add name set
310310- else
311311- set)
312312- String_set.empty
313313- (try Sys.readdir (if dir = "" then Filename.current_dir_name else dir) with Sys_error _ -> [||]))
314314-315315-let path () = []
316316-317317-(* +-----------------------------------------------------------------+
318318- | Names listing |
319319- +-----------------------------------------------------------------+ *)
320320-321321-module Path_map = Map.Make(struct type t = Path.t let compare = compare end)
322322-module Longident_map = Map.Make(struct type t = Longident.t let compare = compare end)
323323-324324-(* All names accessible without a path. *)
325325-let global_names = ref None
326326-let global_names_revised = ref None
327327-328328-(* All names accessible with a path, by path. *)
329329-let local_names_by_path = ref Path_map.empty
330330-331331-(* All names accessible with a path, by long identifier. *)
332332-let local_names_by_longident = ref Longident_map.empty
333333-334334-(* All record fields accessible without a path. *)
335335-let global_fields = ref None
336336-337337-(* All record fields accessible with a path, by path. *)
338338-let local_fields_by_path = ref Path_map.empty
339339-340340-(* All record fields accessible with a path, by long identifier. *)
341341-let local_fields_by_longident = ref Longident_map.empty
342342-343343-(* All visible modules according to Config.load_path. *)
344344-let visible_modules = ref None
345345-346346-let reset () =
347347- visible_modules := None;
348348- global_names := None;
349349- global_names_revised := None;
350350- local_names_by_path := Path_map.empty;
351351- local_names_by_longident := Longident_map.empty;
352352- global_fields := None;
353353- local_fields_by_path := Path_map.empty;
354354- local_fields_by_longident := Longident_map.empty
355355-356356-let get_cached var f =
357357- match !var with
358358- | Some x ->
359359- x
360360- | None ->
361361- let x = f () in
362362- var := Some x;
363363- x
364364-365365-(* List all visible modules. *)
366366-let visible_modules () =
367367- get_cached visible_modules
368368- (fun () ->
369369- List.fold_left
370370- (fun acc dir ->
371371- try
372372- Array.fold_left
373373- (fun acc fname ->
374374- if Filename.check_suffix fname ".cmi" then
375375- String_set.add (String.capitalize_ascii (Filename.chop_suffix fname ".cmi")) acc
376376- else
377377- acc)
378378- acc
379379- (Sys.readdir (if dir = "" then Filename.current_dir_name else dir))
380380- with Sys_error _ ->
381381- acc)
382382-#if OCAML_VERSION >= (4, 08, 0)
383383- String_set.empty @@ UTop_compat.get_load_path ()
384384-#else
385385- String_set.empty !Config.load_path
386386-#endif
387387- )
388388-389389-let field_name { ld_id = id } = Ident.name id
390390-let constructor_name { cd_id = id } = Ident.name id
391391-392392-let add_fields_of_type decl acc =
393393- match decl.type_kind with
394394-#if OCAML_VERSION >= (4, 13, 0)
395395- | Type_variant (constructors,_) ->
396396-#else
397397- | Type_variant constructors ->
398398-#endif
399399- acc
400400- | Type_record (fields, _) ->
401401- List.fold_left (fun acc field -> add (field_name field) acc) acc fields
402402-#if OCAML_VERSION >= (5, 2, 0)
403403- | Type_abstract _ ->
404404-#else
405405- | Type_abstract ->
406406-#endif
407407- acc
408408- | Type_open ->
409409- acc
410410-411411-let add_names_of_type decl acc =
412412- match decl.type_kind with
413413-#if OCAML_VERSION >= (4, 13, 0)
414414- | Type_variant (constructors,_) ->
415415-#else
416416- | Type_variant constructors ->
417417-#endif
418418- List.fold_left (fun acc cstr -> add (constructor_name cstr) acc) acc constructors
419419- | Type_record (fields, _) ->
420420- List.fold_left (fun acc field -> add (field_name field) acc) acc fields
421421-#if OCAML_VERSION >= (5, 2, 0)
422422- | Type_abstract _ ->
423423-#else
424424- | Type_abstract ->
425425-#endif
426426- acc
427427- | Type_open ->
428428- acc
429429-430430-#if OCAML_VERSION >= (4, 08, 0)
431431-let path_of_mty_alias = function
432432- | Mty_alias path -> path
433433- | _ -> assert false
434434-#elif OCAML_VERSION >= (4, 04, 0)
435435-let path_of_mty_alias = function
436436- | Mty_alias (_, path) -> path
437437- | _ -> assert false
438438-#else
439439-let path_of_mty_alias = function
440440- | Mty_alias path -> path
441441- | _ -> assert false
442442-#endif
443443-444444-let rec names_of_module_type = function
445445- | Mty_signature decls ->
446446- List.fold_left
447447- (fun acc decl -> match decl with
448448-#if OCAML_VERSION >= (4, 08, 0)
449449- | Sig_value (id, _, _)
450450- | Sig_typext (id, _, _, _)
451451- | Sig_module (id, _, _, _, _)
452452- | Sig_modtype (id, _, _)
453453- | Sig_class (id, _, _, _)
454454- | Sig_class_type (id, _, _, _) ->
455455-#else
456456- | Sig_value (id, _)
457457- | Sig_typext (id, _, _)
458458- | Sig_module (id, _, _)
459459- | Sig_modtype (id, _)
460460- | Sig_class (id, _, _)
461461- | Sig_class_type (id, _, _) ->
462462-#endif
463463- add (Ident.name id) acc
464464-#if OCAML_VERSION >= (4, 08, 0)
465465- | Sig_type (id, decl, _, _) ->
466466-#else
467467- | Sig_type (id, decl, _) ->
468468-#endif
469469- add_names_of_type decl (add (Ident.name id) acc))
470470- String_set.empty decls
471471- | Mty_ident path -> begin
472472- match lookup_env Env.find_modtype path !Toploop.toplevel_env with
473473- | Some { mtd_type = None } -> String_set.empty
474474- | Some { mtd_type = Some module_type } -> names_of_module_type module_type
475475- | None -> String_set.empty
476476- end
477477- | Mty_alias _ as mty_alias -> begin
478478- let path = path_of_mty_alias mty_alias in
479479- match lookup_env Env.find_module path !Toploop.toplevel_env with
480480- | None -> String_set.empty
481481- | Some { md_type = module_type } -> names_of_module_type module_type
482482- end
483483- | _ ->
484484- String_set.empty
485485-486486-let rec fields_of_module_type = function
487487- | Mty_signature decls ->
488488- List.fold_left
489489- (fun acc decl -> match decl with
490490- | Sig_value _
491491- | Sig_typext _
492492- | Sig_module _
493493- | Sig_modtype _
494494- | Sig_class _
495495- | Sig_class_type _ ->
496496- acc
497497-#if OCAML_VERSION >= (4, 08, 0)
498498- | Sig_type (_, decl, _, _) ->
499499-#else
500500- | Sig_type (_, decl, _) ->
501501-#endif
502502- add_fields_of_type decl acc)
503503- String_set.empty decls
504504- | Mty_ident path -> begin
505505- match lookup_env Env.find_modtype path !Toploop.toplevel_env with
506506- | Some { mtd_type = None } -> String_set.empty
507507- | Some { mtd_type = Some module_type } -> fields_of_module_type module_type
508508- | None -> String_set.empty
509509- end
510510- | Mty_alias _ as mty_alias -> begin
511511- let path = path_of_mty_alias mty_alias in
512512- match lookup_env Env.find_module path !Toploop.toplevel_env with
513513- | None -> String_set.empty
514514- | Some { md_type = module_type } -> fields_of_module_type module_type
515515- end
516516- | _ ->
517517- String_set.empty
518518-519519-let lookup_module id env =
520520-#if OCAML_VERSION >= (4, 10, 0)
521521- let path, decl = Env.find_module_by_name id env in
522522- (path, decl.md_type)
523523-#else
524524- let path = Env.lookup_module id env ~load:true in
525525- (path, (Env.find_module path env).md_type)
526526-#endif
527527-528528-let find_module path env = (Env.find_module path env).md_type
529529-530530-let names_of_module longident =
531531- try
532532- Longident_map.find longident !local_names_by_longident
533533- with Not_found ->
534534- match lookup_env lookup_module longident !Toploop.toplevel_env with
535535- | Some(path, module_type) ->
536536- let names = names_of_module_type module_type in
537537- local_names_by_path := Path_map.add path names !local_names_by_path;
538538- local_names_by_longident := Longident_map.add longident names !local_names_by_longident;
539539- names
540540- | None ->
541541- local_names_by_longident := Longident_map.add longident String_set.empty !local_names_by_longident;
542542- String_set.empty
543543-544544-let fields_of_module longident =
545545- try
546546- Longident_map.find longident !local_fields_by_longident
547547- with Not_found ->
548548- match lookup_env lookup_module longident !Toploop.toplevel_env with
549549- | Some(path, module_type) ->
550550- let fields = fields_of_module_type module_type in
551551- local_fields_by_path := Path_map.add path fields !local_fields_by_path;
552552- local_fields_by_longident := Longident_map.add longident fields !local_fields_by_longident;
553553- fields
554554- | None ->
555555- local_fields_by_longident := Longident_map.add longident String_set.empty !local_fields_by_longident;
556556- String_set.empty
557557-558558-let list_global_names () =
559559- let rec loop acc = function
560560- | Env.Env_empty -> acc
561561-#if OCAML_VERSION >= (4, 10, 0)
562562- | Env.Env_value_unbound _-> acc
563563- | Env.Env_module_unbound _-> acc
564564-#endif
565565- | Env.Env_value(summary, id, _) ->
566566- loop (add (Ident.name id) acc) summary
567567- | Env.Env_type(summary, id, decl) ->
568568- loop (add_names_of_type decl (add (Ident.name id) acc)) summary
569569- | Env.Env_extension(summary, id, _) ->
570570- loop (add (Ident.name id) acc) summary
571571-#if OCAML_VERSION >= (4, 08, 0)
572572- | Env.Env_module(summary, id, _, _) ->
573573-#else
574574- | Env.Env_module(summary, id, _) ->
575575-#endif
576576- loop (add (Ident.name id) acc) summary
577577- | Env.Env_modtype(summary, id, _) ->
578578- loop (add (Ident.name id) acc) summary
579579- | Env.Env_class(summary, id, _) ->
580580- loop (add (Ident.name id) acc) summary
581581- | Env.Env_cltype(summary, id, _) ->
582582- loop (add (Ident.name id) acc) summary
583583- | Env.Env_functor_arg(summary, id) ->
584584- loop (add (Ident.name id) acc) summary
585585-#if OCAML_VERSION >= (4, 08, 0)
586586- | Env.Env_persistent (summary, id) ->
587587- loop (add (Ident.name id) acc) summary
588588-#endif
589589-#if OCAML_VERSION >= (4, 04, 0)
590590- | Env.Env_constraints (summary, _) ->
591591- loop acc summary
592592-#endif
593593-#if OCAML_VERSION >= (4, 10, 0)
594594- | Env.Env_copy_types summary ->
595595- loop acc summary
596596-#elif OCAML_VERSION >= (4, 06, 0)
597597- | Env.Env_copy_types (summary, _) ->
598598- loop acc summary
599599-#endif
600600-#if OCAML_VERSION >= (4, 08, 0)
601601- | Env.Env_open(summary, path) ->
602602-#elif OCAML_VERSION >= (4, 07, 0)
603603- | Env.Env_open(summary, _, path) ->
604604-#else
605605- | Env.Env_open(summary, path) ->
606606-#endif
607607- match try Some (Path_map.find path !local_names_by_path) with Not_found -> None with
608608- | Some names ->
609609- loop (String_set.union acc names) summary
610610- | None ->
611611- match lookup_env find_module path !Toploop.toplevel_env with
612612- | Some module_type ->
613613- let names = names_of_module_type module_type in
614614- local_names_by_path := Path_map.add path names !local_names_by_path;
615615- loop (String_set.union acc names) summary
616616- | None ->
617617- local_names_by_path := Path_map.add path String_set.empty !local_names_by_path;
618618- loop acc summary
619619- in
620620- (* Add names of the environment: *)
621621- let acc = loop String_set.empty (Env.summary !Toploop.toplevel_env) in
622622- (* Add accessible modules: *)
623623- String_set.union acc (visible_modules ())
624624-625625-let global_names () = get_cached global_names list_global_names
626626-627627-let replace x y set =
628628- if String_set.mem x set then
629629- String_set.add y (String_set.remove x set)
630630- else
631631- set
632632-633633-let list_global_fields () =
634634- let rec loop acc = function
635635- | Env.Env_empty -> acc
636636-#if OCAML_VERSION >= (4, 10, 0)
637637- | Env.Env_value_unbound _-> acc
638638- | Env.Env_module_unbound _-> acc
639639-#endif
640640- | Env.Env_value(summary, id, _) ->
641641- loop (add (Ident.name id) acc) summary
642642- | Env.Env_type(summary, id, decl) ->
643643- loop (add_fields_of_type decl (add (Ident.name id) acc)) summary
644644- | Env.Env_extension(summary, id, _) ->
645645- loop (add (Ident.name id) acc) summary
646646-#if OCAML_VERSION >= (4, 08, 0)
647647- | Env.Env_module(summary, id, _, _) ->
648648-#else
649649- | Env.Env_module(summary, id, _) ->
650650-#endif
651651- loop (add (Ident.name id) acc) summary
652652- | Env.Env_functor_arg(summary, id) ->
653653- loop (add (Ident.name id) acc) summary
654654- | Env.Env_modtype(summary, id, _) ->
655655- loop (add (Ident.name id) acc) summary
656656- | Env.Env_class(summary, id, _) ->
657657- loop (add (Ident.name id) acc) summary
658658- | Env.Env_cltype(summary, id, _) ->
659659- loop (add (Ident.name id) acc) summary
660660-#if OCAML_VERSION >= (4, 08, 0)
661661- | Env.Env_persistent (summary, id) ->
662662- loop (add (Ident.name id) acc) summary
663663-#endif
664664-#if OCAML_VERSION >= (4, 04, 0)
665665- | Env.Env_constraints (summary, _) ->
666666- loop acc summary
667667-#endif
668668-#if OCAML_VERSION >= (4, 10, 0)
669669- | Env.Env_copy_types summary ->
670670- loop acc summary
671671-#elif OCAML_VERSION >= (4, 06, 0)
672672- | Env.Env_copy_types (summary, _) ->
673673- loop acc summary
674674-#endif
675675-#if OCAML_VERSION >= (4, 07, 0)
676676- #if OCAML_VERSION >= (4, 08, 0)
677677- | Env.Env_open(summary, path) ->
678678- #else
679679- | Env.Env_open(summary, _, path) ->
680680- #endif
681681-#else
682682- | Env.Env_open(summary, path) ->
683683-#endif
684684- match try Some (Path_map.find path !local_fields_by_path) with Not_found -> None with
685685- | Some fields ->
686686- loop (String_set.union acc fields) summary
687687- | None ->
688688- match lookup_env find_module path !Toploop.toplevel_env with
689689- | Some module_type ->
690690- let fields = fields_of_module_type module_type in
691691- local_fields_by_path := Path_map.add path fields !local_fields_by_path;
692692- loop (String_set.union acc fields) summary
693693- | None ->
694694- local_fields_by_path := Path_map.add path String_set.empty !local_fields_by_path;
695695- loop acc summary
696696- in
697697- (* Add fields of the environment: *)
698698- let acc = loop String_set.empty (Env.summary !Toploop.toplevel_env) in
699699- (* Add accessible modules: *)
700700- String_set.union acc (visible_modules ())
701701-702702-let global_fields () = get_cached global_fields list_global_fields
703703-704704-(* +-----------------------------------------------------------------+
705705- | Listing methods |
706706- +-----------------------------------------------------------------+ *)
707707-708708-let rec find_method meth type_expr =
709709- match get_desc type_expr with
710710- | Tlink type_expr ->
711711- find_method meth type_expr
712712- | Tobject (type_expr, _) ->
713713- find_method meth type_expr
714714- | Tfield (name, _, type_expr, rest) ->
715715- if name = meth then
716716- Some type_expr
717717- else
718718- find_method meth rest
719719- | Tpoly (type_expr, _) ->
720720- find_method meth type_expr
721721- | Tconstr (path, _, _) -> begin
722722- match lookup_env Env.find_type path !Toploop.toplevel_env with
723723- | None
724724- | Some { type_manifest = None } ->
725725- None
726726- | Some { type_manifest = Some type_expr } ->
727727- find_method meth type_expr
728728- end
729729- | _ ->
730730- None
731731-732732-let rec methods_of_type acc type_expr =
733733- match get_desc type_expr with
734734- | Tlink type_expr ->
735735- methods_of_type acc type_expr
736736- | Tobject (type_expr, _) ->
737737- methods_of_type acc type_expr
738738- | Tfield (name, _, _, rest) ->
739739- methods_of_type (add name acc) rest
740740- | Tpoly (type_expr, _) ->
741741- methods_of_type acc type_expr
742742- | Tconstr (path, _, _) -> begin
743743- match lookup_env Env.find_type path !Toploop.toplevel_env with
744744- | None
745745- | Some { type_manifest = None } ->
746746- acc
747747- | Some { type_manifest = Some type_expr } ->
748748- methods_of_type acc type_expr
749749- end
750750- | _ ->
751751- acc
752752-753753-let rec find_object meths type_expr =
754754- match meths with
755755- | [] ->
756756- Some type_expr
757757- | meth :: meths ->
758758- match find_method meth type_expr with
759759- | Some type_expr ->
760760- find_object meths type_expr
761761- | None ->
762762- None
763763-764764-let methods_of_object longident meths =
765765- let lookup_value=
766766-#if OCAML_VERSION >= (4, 10, 0)
767767- Env.find_value_by_name
768768-#else
769769- Env.lookup_value
770770-#endif
771771- in
772772- match lookup_env lookup_value longident !Toploop.toplevel_env with
773773- | None ->
774774- []
775775- | Some (path, { val_type = type_expr }) ->
776776- match find_object meths type_expr with
777777- | None ->
778778- []
779779- | Some type_expr ->
780780- String_set.elements (methods_of_type String_set.empty type_expr)
781781-782782-(* +-----------------------------------------------------------------+
783783- | Listing labels |
784784- +-----------------------------------------------------------------+ *)
785785-786786-let rec labels_of_type acc type_expr =
787787- match get_desc type_expr with
788788- | Tlink te ->
789789- labels_of_type acc te
790790- | Tpoly (te, _) ->
791791- labels_of_type acc te
792792- | Tarrow(label, _, te, _) ->
793793-#if OCAML_VERSION < (4, 03, 0)
794794- if label = "" then
795795- labels_of_type acc te
796796- else if label.[0] = '?' then
797797- labels_of_type (String_map.add (String.sub label 1 (String.length label - 1)) Optional acc) te
798798- else
799799- labels_of_type (String_map.add label Required acc) te
800800-#else
801801- (match label with
802802- | Nolabel ->
803803- labels_of_type acc te
804804- | Optional label ->
805805- labels_of_type (String_map.add label Optional acc) te
806806- | Labelled label ->
807807- labels_of_type (String_map.add label Required acc) te)
808808-#endif
809809- | Tconstr(path, _, _) -> begin
810810- match lookup_env Env.find_type path !Toploop.toplevel_env with
811811- | None
812812- | Some { type_manifest = None } ->
813813- String_map.bindings acc
814814- | Some { type_manifest = Some type_expr } ->
815815- labels_of_type acc type_expr
816816- end
817817- | _ ->
818818- String_map.bindings acc
819819-820820-let labels_of_function longident meths =
821821- let lookup_value=
822822-#if OCAML_VERSION >= (4, 10, 0)
823823- Env.find_value_by_name
824824-#else
825825- Env.lookup_value
826826-#endif
827827- in
828828- match lookup_env lookup_value longident !Toploop.toplevel_env with
829829- | None ->
830830- []
831831- | Some (path, { val_type = type_expr }) ->
832832- match find_object meths type_expr with
833833- | None ->
834834- []
835835- | Some type_expr ->
836836- labels_of_type String_map.empty type_expr
837837-838838-let labels_of_newclass longident =
839839- let lookup_class=
840840-#if OCAML_VERSION >= (4, 10, 0)
841841- Env.find_class_by_name
842842-#else
843843- Env.lookup_class
844844-#endif
845845- in
846846- match lookup_env lookup_class longident !Toploop.toplevel_env with
847847- | None ->
848848- []
849849- | Some (path, { cty_new = None }) ->
850850- []
851851- | Some (path, { cty_new = Some type_expr }) ->
852852- labels_of_type String_map.empty type_expr
853853-854854-(* +-----------------------------------------------------------------+
855855- | Tokens processing |
856856- +-----------------------------------------------------------------+ *)
857857-858858-(* Filter blanks and comments except for the last token. *)
859859-let filter tokens =
860860- let rec aux acc = function
861861- | [] -> acc
862862- | [((Blanks | Comment (_, true)), loc)] -> (Blanks, loc) :: acc
863863- | ((Blanks | Comment (_, true)), _) :: rest -> aux acc rest
864864- | x :: rest -> aux (x :: acc) rest
865865- in
866866- List.rev (aux [] tokens)
867867-868868-(* Reverse and filter blanks and comments except for the last
869869- token. *)
870870-let rec rev_filter acc tokens =
871871- match tokens with
872872- | [] -> acc
873873- | [((Blanks | Comment (_, true)), loc)] -> (Blanks, loc) :: acc
874874- | ((Blanks | Comment (_, true)), _) :: rest -> rev_filter acc rest
875875- | x :: rest -> rev_filter (x :: acc) rest
876876-877877-(* Find the current context. *)
878878-let rec find_context tokens = function
879879- | [] ->
880880- Some (rev_filter [] tokens)
881881- | [(Quotation (items, false), _)] ->
882882- find_context_in_quotation items
883883- | _ :: rest ->
884884- find_context tokens rest
885885-886886-and find_context_in_quotation = function
887887- | [] ->
888888- None
889889- | [(Quot_anti { a_closing = None; a_contents = tokens }, _)] ->
890890- find_context tokens tokens
891891- | _ :: rest ->
892892- find_context_in_quotation rest
893893-894894-(* +-----------------------------------------------------------------+
895895- | Completion |
896896- +-----------------------------------------------------------------+ *)
897897-898898-#if OCAML_VERSION < (4, 11, 0)
899899-let longident_parse= Longident.parse
900900-#else
901901-let longident_parse str=
902902- let lexbuf= Lexing.from_string str in
903903- Parse.longident lexbuf
904904-#endif
905905-906906-let complete ~phrase_terminator ~input =
907907- let true_name, false_name = ("true", "false") in
908908- let tokens = UTop_lexer.lex_string input in
909909- (* Filter blanks and comments. *)
910910- let tokens = filter tokens in
911911- match tokens with
912912-913913- (* Completion on directive names. *)
914914- | [(Symbol "#", { idx2 = stop })]
915915- | [(Symbol "#", _); (Blanks, { idx2 = stop })] ->
916916- (stop, list_directives phrase_terminator)
917917- | [(Symbol "#", _); ((Lident src | Uident src), { idx1 = start })] ->
918918- (start, lookup_assoc src (list_directives phrase_terminator))
919919-920920- (* Complete with ";;" when possible. *)
921921- | [(Symbol "#", _); ((Lident _ | Uident _), _); (String (_, true), { idx2 = stop })]
922922- | [(Symbol "#", _); ((Lident _ | Uident _), _); (String (_, true), _); (Blanks, { idx2 = stop })] ->
923923- (stop, [(phrase_terminator, "")])
924924- | [(Symbol "#", _); ((Lident _ | Uident _), _); (String (_, true), _); (Symbol sym, { idx1 = start })] ->
925925- if Astring.String.is_prefix phrase_terminator ~affix:sym then
926926- (start, [(phrase_terminator, "")])
927927- else
928928- (0, [])
929929-930930- (* Completion on #require. *)
931931- | [(Symbol "#", _); (Lident "require", _); (String (tlen, false), loc)] ->
932932- let pkg = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in
933933- let pkgs = lookup pkg [] in
934934- (loc.idx1 + 1, List.map (fun pkg -> (pkg, "\"" ^ phrase_terminator)) (List.sort compare pkgs))
935935-936936- | [(Symbol "#", _); (Lident "typeof", _); (String (tlen, false), loc)] ->
937937- let prefix = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in
938938- begin match longident_parse prefix with
939939- | Longident.Ldot (lident, last_prefix) ->
940940- let set = names_of_module lident in
941941- let compls = lookup last_prefix (String_set.elements set) in
942942- let start = loc.idx1 + 1 + (String.length prefix - String.length last_prefix) in
943943- (start, List.map (fun w -> (w, "")) compls)
944944- | _ ->
945945- let set = global_names () in
946946- let compls = lookup prefix (String_set.elements set) in
947947- (loc.idx1 + 1, List.map (fun w -> (w, "")) compls)
948948- end
949949-950950- (* Completion on #load. *)
951951- | [(Symbol "#", _); (Lident ("load" | "load_rec"), _); (String (tlen, false), loc)] ->
952952- let file = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in
953953- let filter name = Filename.check_suffix name ".cma" || Filename.check_suffix name ".cmo" in
954954- let map =
955955- if Filename.is_relative file then
956956- let dir = Filename.dirname file in
957957- List.fold_left
958958- (fun acc d -> add_files filter acc (Filename.concat d dir))
959959- String_map.empty
960960- (Filename.current_dir_name ::
961961-#if OCAML_VERSION >= (4, 08, 0)
962962- (UTop_compat.get_load_path ())
963963-#else
964964- !Config.load_path
965965-#endif
966966- )
967967-968968- else
969969- add_files filter String_map.empty (Filename.dirname file)
970970- in
971971- let list = String_map.bindings map in
972972- let name = basename file in
973973- let result = lookup_assoc name list in
974974- (loc.idx2 - String.length name,
975975- List.map (function (w, Directory) -> (w, "") | (w, File) -> (w, "\"" ^ phrase_terminator)) result)
976976-977977- (* Completion on #use and #mod_use *)
978978- | [(Symbol "#", _); (Lident "use", _); (String (tlen, false), loc)]
979979- | [(Symbol "#", _); (Lident "mod_use", _); (String (tlen, false), loc)] ->
980980- let file = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in
981981- let filter name =
982982- match try Some (String.rindex name '.') with Not_found -> None with
983983- | None ->
984984- true
985985- | Some idx ->
986986- let ext = String.sub name (idx + 1) (String.length name - (idx + 1)) in
987987- ext = "ml"
988988- in
989989- let map =
990990- if Filename.is_relative file then
991991- let dir = Filename.dirname file in
992992- List.fold_left
993993- (fun acc d -> add_files filter acc (Filename.concat d dir))
994994- String_map.empty
995995- (Filename.current_dir_name ::
996996-#if OCAML_VERSION >= (4, 08, 0)
997997- UTop_compat.get_load_path ()
998998-#else
999999- !Config.load_path
10001000-#endif
10011001- )
10021002- else
10031003- add_files filter String_map.empty (Filename.dirname file)
10041004- in
10051005- let list = String_map.bindings map in
10061006- let name = basename file in
10071007- let result = lookup_assoc name list in
10081008- (loc.idx2 - String.length name,
10091009- List.map (function (w, Directory) -> (w, "") | (w, File) -> (w, "\"" ^ phrase_terminator)) result)
10101010-10111011- (* Completion on #directory and #cd. *)
10121012- | [(Symbol "#", _); (Lident ("cd" | "directory"), _); (String (tlen, false), loc)] ->
10131013- let file = String.sub input (loc.ofs1 + tlen) (String.length input - loc.ofs1 - tlen) in
10141014- let list = list_directories (Filename.dirname file) in
10151015- let name = basename file in
10161016- let result = lookup name list in
10171017- (loc.idx2 - String.length name, List.map (function dir -> (dir, "")) result)
10181018-10191019- (* Generic completion on directives. *)
10201020- | [(Symbol "#", _); ((Lident dir | Uident dir), _); (Blanks, { idx2 = stop })] ->
10211021- (stop,
10221022- match[@alert "-deprecated"] try Some (Hashtbl.find Toploop.directive_table dir) with Not_found -> None with
10231023- | Some (Toploop.Directive_none _) -> [(phrase_terminator, "")]
10241024- | Some (Toploop.Directive_string _) -> [(" \"", "")]
10251025- | Some (Toploop.Directive_bool _) -> [(true_name, phrase_terminator); (false_name, phrase_terminator)]
10261026- | Some (Toploop.Directive_int _) -> []
10271027- | Some (Toploop.Directive_ident _) -> List.map (fun w -> (w, "")) (String_set.elements (global_names ()))
10281028- | None -> [])
10291029- | (Symbol "#", _) :: ((Lident dir | Uident dir), _) :: tokens -> begin
10301030- match[@alert "-deprecated"] try Some (Hashtbl.find Toploop.directive_table dir) with Not_found -> None with
10311031- | Some (Toploop.Directive_none _) ->
10321032- (0, [])
10331033- | Some (Toploop.Directive_string _) ->
10341034- (0, [])
10351035- | Some (Toploop.Directive_bool _) -> begin
10361036- match tokens with
10371037- | [(Lident id, { idx1 = start })] ->
10381038- (start, lookup_assoc id [(true_name, phrase_terminator); (false_name, phrase_terminator)])
10391039- | _ ->
10401040- (0, [])
10411041- end
10421042- | Some (Toploop.Directive_int _) ->
10431043- (0, [])
10441044- | Some (Toploop.Directive_ident _) -> begin
10451045- match parse_longident (List.rev tokens) with
10461046- | Some (Value, None, start, id) ->
10471047- (start, List.map (fun w -> (w, "")) (lookup id (String_set.elements (global_names ()))))
10481048- | Some (Value, Some longident, start, id) ->
10491049- (start, List.map (fun w -> (w, "")) (lookup id (String_set.elements (names_of_module longident))))
10501050- | _ ->
10511051- (0, [])
10521052- end
10531053- | None ->
10541054- (0, [])
10551055- end
10561056-10571057- (* Completion on identifiers. *)
10581058- | _ ->
10591059- match find_context tokens tokens with
10601060- | None ->
10611061- (0, [])
10621062- | Some [] ->
10631063- (0, List.map (fun w -> (w, "")) (String_set.elements (String_set.union !UTop.keywords (global_names ()))))
10641064- | Some tokens ->
10651065- match parse_method tokens with
10661066- | Some (longident, meths, start, meth) ->
10671067- (start, List.map (fun w -> (w, "")) (lookup meth (methods_of_object longident meths)))
10681068- | None ->
10691069- match parse_label tokens with
10701070- | Some (Fun, longident, meths, Optional, start, label) ->
10711071- (start, List.map (fun (w, kind) -> (w, ":")) (lookup_assoc label (List.filter (function (w, Optional) -> true | (w, Required) -> false) (labels_of_function longident meths))))
10721072- | Some (Fun, longident, meths, Required, start, label) ->
10731073- (start, List.map (fun (w, kind) -> (w, ":")) (lookup_assoc label (labels_of_function longident meths)))
10741074- | Some (New, longident, meths, Optional, start, label) ->
10751075- (start, List.map (fun (w, kind) -> (w, ":")) (lookup_assoc label (List.filter (function (w, Optional) -> true | (w, Required) -> false) (labels_of_newclass longident))))
10761076- | Some (New, longident, meths, Required, start, label) ->
10771077- (start, List.map (fun (w, kind) -> (w, ":")) (lookup_assoc label (labels_of_newclass longident)))
10781078- | None ->
10791079- match parse_longident tokens with
10801080- | None ->
10811081- (0, [])
10821082- | Some (Value, None, start, id) ->
10831083- (start, List.map (fun w -> (w, "")) (lookup id (String_set.elements (String_set.union !UTop.keywords (global_names ())))))
10841084- | Some (Value, Some longident, start, id) ->
10851085- (start, List.map (fun w -> (w, "")) (lookup id (String_set.elements (names_of_module longident))))
10861086- | Some (Field, None, start, id) ->
10871087- (start, List.map (fun w -> (w, "")) (lookup id (String_set.elements (global_fields ()))))
10881088- | Some (Field, Some longident, start, id) ->
10891089- (start, List.map (fun w -> (w, "")) (lookup id (String_set.elements (fields_of_module longident))))
10901090-10911091-let complete ~phrase_terminator ~input =
10921092- try
10931093- (complete ~phrase_terminator ~input : int * (string * string) list)
10941094- with Cmi_format.Error _ ->
10951095- (0, [])
-18
lib/uTop_complete.mli
···11-(*
22- * uTop_complete.mli
33- * -----------------
44- * Copyright : (c) 2011, Jeremie Dimino <jeremie@dimino.org>
55- * Licence : BSD3
66- *
77- * This file is a part of utop.
88- *)
99-1010-(** OCaml completion. *)
1111-1212-val complete :
1313- phrase_terminator:string -> input:string -> int * (string * string) list
1414-(** [complete ~phrase_terminator ~input] returns the start of the completed word
1515- in [input] and the list of possible completions with their suffixes. *)
1616-1717-val reset : unit -> unit
1818-(** Reset global cache. It must be called before each interactive read line. *)
-11
lib/uTop_lexer.mli
···11-(*
22- * uTop_lexer.mli
33- * --------------
44- * Copyright : (c) 2012, Jeremie Dimino <jeremie@dimino.org>
55- * Licence : BSD3
66- *
77- * This file is a part of utop.
88- *)
99-1010-val lex_string : string -> (UTop_token.t * UTop_token.location) list
1111-(** [lex_string str] returns all the tokens contained in [str]. *)
-230
lib/uTop_lexer.mll
···11-(*
22- * uTop_lexer.mll
33- * --------------
44- * Copyright : (c) 2011, Jeremie Dimino <jeremie@dimino.org>
55- * Licence : BSD3
66- *
77- * This file is a part of utop.
88- *)
99-1010-(* Lexer for the OCaml language. *)
1111-1212-{
1313- open Lexing
1414- open UTop_token
1515-1616- let mkloc idx1 idx2 ofs1 ofs2 = {
1717- idx1 = idx1;
1818- idx2 = idx2;
1919- ofs1 = ofs1;
2020- ofs2 = ofs2;
2121- }
2222-2323- (* Only for ascii-only lexemes. *)
2424- let lexeme_loc idx lexbuf =
2525- let ofs1 = lexeme_start lexbuf and ofs2 = lexeme_end lexbuf in
2626- {
2727- idx1 = idx;
2828- idx2 = idx + (ofs2 - ofs1);
2929- ofs1 = ofs1;
3030- ofs2 = ofs2;
3131- }
3232-3333- let _merge_loc l1 l2 = {
3434- idx1 = l1.idx1;
3535- idx2 = l2.idx2;
3636- ofs1 = l1.ofs1;
3737- ofs2 = l2.ofs2;
3838- }
3939-4040-}
4141-4242-let uchar = ['\x00' - '\x7f'] | _ [ '\x80' - '\xbf' ]*
4343-4444-let blank = [' ' '\009' '\012']
4545-let lowercase = ['a'-'z' '_']
4646-let uppercase = ['A'-'Z']
4747-let identchar = ['A'-'Z' 'a'-'z' '_' '\'' '0'-'9']
4848-let lident = lowercase identchar*
4949-let uident = uppercase identchar*
5050-let ident = (lowercase|uppercase) identchar*
5151-5252-let hexa_char = ['0'-'9' 'A'-'F' 'a'-'f']
5353-let decimal_literal =
5454- ['0'-'9'] ['0'-'9' '_']*
5555-let hex_literal =
5656- '0' ['x' 'X'] hexa_char ['0'-'9' 'A'-'F' 'a'-'f' '_']*
5757-let oct_literal =
5858- '0' ['o' 'O'] ['0'-'7'] ['0'-'7' '_']*
5959-let bin_literal =
6060- '0' ['b' 'B'] ['0'-'1'] ['0'-'1' '_']*
6161-let int_literal =
6262- decimal_literal | hex_literal | oct_literal | bin_literal
6363-let float_literal =
6464- ['0'-'9'] ['0'-'9' '_']*
6565- ('.' ['0'-'9' '_']* )?
6666- (['e' 'E'] ['+' '-']? ['0'-'9'] ['0'-'9' '_']*)?
6767-6868-let symbolchar =
6969- ['!' '$' '%' '&' '*' '+' '-' '.' '/' ':' '<' '=' '>' '?' '@' '^' '|' '~']
7070-7171-rule tokens idx acc = parse
7272- | eof
7373- { (idx, None, List.rev acc) }
7474- | ('\n' | blank)+
7575- { let loc = lexeme_loc idx lexbuf in
7676- tokens loc.idx2 ((Blanks, loc) :: acc) lexbuf }
7777- | lident
7878- { let src = lexeme lexbuf in
7979- let loc = lexeme_loc idx lexbuf in
8080- let tok =
8181- match src with
8282- | ("true" | "false") ->
8383- Constant src
8484- | _ ->
8585- Lident src
8686- in
8787- tokens loc.idx2 ((tok, loc) :: acc) lexbuf }
8888- | uident
8989- { let src = lexeme lexbuf in
9090- let loc = lexeme_loc idx lexbuf in
9191- let tok = Uident src in
9292- tokens loc.idx2 ((tok, loc) :: acc) lexbuf }
9393- | int_literal "l"
9494- | int_literal "L"
9595- | int_literal "n"
9696- | int_literal
9797- | float_literal
9898- { let loc = lexeme_loc idx lexbuf in
9999- let tok = Constant (lexeme lexbuf) in
100100- tokens loc.idx2 ((tok, loc) :: acc) lexbuf }
101101- | '"'
102102- { let ofs = lexeme_start lexbuf in
103103- let item, idx2= cm_string (idx + 1) lexbuf in
104104- let loc = mkloc idx idx2 ofs (lexeme_end lexbuf) in
105105- tokens idx2 ((item, loc) :: acc) lexbuf }
106106- | '{' (lowercase* as tag) '|'
107107- { let ofs = lexeme_start lexbuf in
108108- let delim_len = String.length tag + 2 in
109109- let idx2, terminated = quoted_string (idx + delim_len) tag lexbuf in
110110- let loc = mkloc idx idx2 ofs (lexeme_end lexbuf) in
111111- tokens idx2 ((String (delim_len, terminated), loc) :: acc) lexbuf }
112112- | "'" [^'\'' '\\'] "'"
113113- | "'\\" ['\\' '"' 'n' 't' 'b' 'r' ' ' '\'' 'x' '0'-'9'] eof
114114- | "'\\" ['\\' '"' 'n' 't' 'b' 'r' ' ' '\''] "'"
115115- | "'\\" (['0'-'9'] ['0'-'9'] | 'x' hexa_char) eof
116116- | "'\\" (['0'-'9'] ['0'-'9'] ['0'-'9'] | 'x' hexa_char hexa_char) eof
117117- | "'\\" (['0'-'9'] ['0'-'9'] ['0'-'9'] | 'x' hexa_char hexa_char) "'"
118118- { let loc = lexeme_loc idx lexbuf in
119119- tokens loc.idx2 ((Char, loc) :: acc) lexbuf }
120120- | "'\\" uchar
121121- { let loc = mkloc idx (idx + 3) (lexeme_start lexbuf) (lexeme_end lexbuf) in
122122- tokens loc.idx2 ((Error, loc) :: acc) lexbuf }
123123- | "(*)"
124124- { let loc = lexeme_loc idx lexbuf in
125125- tokens loc.idx2 ((Comment (Comment_reg, true), loc) :: acc) lexbuf }
126126- | "(**)"
127127- { let loc = lexeme_loc idx lexbuf in
128128- tokens loc.idx2 ((Comment (Comment_doc, true), loc) :: acc) lexbuf }
129129- | "(**"
130130- { let ofs = lexeme_start lexbuf in
131131- let idx2, terminated = comment (idx + 3) 0 lexbuf in
132132- let loc = mkloc idx idx2 ofs (lexeme_end lexbuf) in
133133- tokens idx2 ((Comment (Comment_doc, terminated), loc) :: acc) lexbuf }
134134- | "(*"
135135- { let ofs = lexeme_start lexbuf in
136136- let idx2, terminated = comment (idx + 2) 0 lexbuf in
137137- let loc = mkloc idx idx2 ofs (lexeme_end lexbuf) in
138138- tokens idx2 ((Comment (Comment_reg, terminated), loc) :: acc) lexbuf }
139139- | ""
140140- { symbol idx acc lexbuf }
141141-142142-and symbol idx acc = parse
143143- | "(" | ")"
144144- | "[" | "]"
145145- | "{" | "}"
146146- | "`"
147147- | "#"
148148- | ","
149149- | ";" | ";;"
150150- | symbolchar+
151151- { let loc = lexeme_loc idx lexbuf in
152152- let tok = Symbol (lexeme lexbuf) in
153153- tokens loc.idx2 ((tok, loc) :: acc) lexbuf }
154154- | uchar
155155- {
156156- let loc = mkloc idx (idx + 1) (lexeme_start lexbuf) (lexeme_end lexbuf) in
157157- tokens loc.idx2 ((Error, loc) :: acc) lexbuf
158158- }
159159-160160-and cm_string idx= parse
161161- | '"'
162162- { (String (1, true), idx+1) }
163163- | "\\\""
164164- { let idx2, terminated= string (idx + 2) lexbuf in
165165- (String (1, terminated), idx2)
166166- }
167167- | uchar
168168- {
169169-170170- let idx2, terminated= string (idx + 1) lexbuf in
171171- (String (1, terminated), idx2)
172172- }
173173- | eof
174174- { (String (1, false), idx) }
175175-176176-and comment idx depth = parse
177177- | "(*"
178178- { comment (idx + 2) (depth + 1) lexbuf }
179179- | "*)"
180180- { if depth = 0 then
181181- (idx + 2, true)
182182- else
183183- comment (idx + 2) (depth - 1) lexbuf }
184184- | '"'
185185- { let idx, terminated = string (idx + 1) lexbuf in
186186- if terminated then
187187- comment idx depth lexbuf
188188- else
189189- (idx, false) }
190190- | uchar
191191- {
192192- comment (idx + 1) depth lexbuf
193193-194194- }
195195- | eof
196196- { (idx, false) }
197197-198198-and string idx = parse
199199- | '"'
200200- { (idx + 1, true) }
201201- | "\\\""
202202- { string (idx + 2) lexbuf }
203203- | uchar
204204- {
205205- string (idx + 1) lexbuf
206206-207207- }
208208- | eof
209209- { (idx, false) }
210210-211211-and quoted_string idx tag = parse
212212- | '|' (lowercase* as tag2) '}'
213213- { let idx = idx + 2 + String.length tag2 in
214214- if tag = tag2 then
215215- (idx, true)
216216- else
217217- quoted_string idx tag lexbuf }
218218- | eof
219219- { (idx, false) }
220220- | uchar
221221- {
222222- quoted_string (idx + 1) tag lexbuf
223223-224224- }
225225-226226-{
227227- let lex_string str =
228228- let _, _, items = tokens 0 [] (Lexing.from_string str) in
229229- items
230230-}
-48
lib/uTop_token.ml
···11-(*
22- * uTop_token.ml
33- * -------------
44- * Copyright : (c) 2011, Jeremie Dimino <jeremie@dimino.org>
55- * Licence : BSD3
66- *
77- * This file is a part of utop.
88- *)
99-1010-(** Tokens.
1111-1212- The type of tokens is semi-structured: parentheses construct and quotations
1313- are nested and others tokens are flat list. *)
1414-1515-type location = {
1616- idx1 : int; (** Start position in unicode characters. *)
1717- idx2 : int; (** Stop position in unicode characters. *)
1818- ofs1 : int; (** Start position in bytes. *)
1919- ofs2 : int; (** Stop position in bytes. *)
2020-}
2121-(** Locations in the source string, which is encoded in UTF-8. *)
2222-2323-type t =
2424- | Symbol of string
2525- | Lident of string
2626- | Uident of string
2727- | Constant of string
2828- | Char
2929- | String of int * bool (** [String (quote_size, terminated)]. *)
3030- | Comment of comment_kind * bool (** [Comment (kind, terminated)]. *)
3131- | Blanks
3232- | Error
3333- | Quotation of (quotation_item * location) list * bool
3434- (** [Quotation (items, terminated)]. *)
3535-3636-and comment_kind =
3737- | Comment_reg (** Regular comment. *)
3838- | Comment_doc (** Documentation comment. *)
3939-4040-and quotation_item = Quot_data | Quot_anti of antiquotation
4141-4242-and antiquotation = {
4343- a_opening : location; (** Location of the opening [$]. *)
4444- a_closing : location option; (** Location of the closing [$]. *)
4545- a_name : (location * location) option;
4646- (** Location of the name and colon if any. *)
4747- a_contents : (t * location) list; (** Contents of the location. *)
4848-}