1 (***********************************************************************)
5 (* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
7 (* Copyright 1996 Institut National de Recherche en Informatique et *)
8 (* en Automatique. All rights reserved. This file is distributed *)
9 (* under the terms of the Q Public License version 1.0. *)
11 (***********************************************************************)
17 type t
= { loc_start
: position
; loc_end
: position
; loc_ghost
: bool };;
19 let none = { loc_start
= dummy_pos
; loc_end
= dummy_pos
; loc_ghost
= true };;
28 { loc_start
= loc; loc_end
= loc; loc_ghost
= true }
32 loc_start
= lexbuf
.lex_start_p
;
33 loc_end
= lexbuf
.lex_curr_p
;
37 let init lexbuf fname
=
38 lexbuf
.lex_curr_p
<- {
46 let symbol_rloc () = {
47 loc_start
= Parsing.symbol_start_pos
();
48 loc_end
= Parsing.symbol_end_pos
();
52 let symbol_gloc () = {
53 loc_start
= Parsing.symbol_start_pos
();
54 loc_end
= Parsing.symbol_end_pos
();
59 loc_start
= Parsing.rhs_start_pos n
;
60 loc_end
= Parsing.rhs_end_pos n
;
64 let input_name = ref ""
65 let input_lexbuf = ref (None
: lexbuf
option)
69 let status = ref Terminfo.Uninitialised
71 let num_loc_lines = ref 0 (* number of lines already printed after input *)
73 (* Highlight the locations using standout mode. *)
75 let highlight_terminfo ppf num_lines lb loc1 loc2
=
76 Format.pp_print_flush ppf
(); (* avoid mixing Format and normal output *)
77 (* Char 0 is at offset -lb.lex_abs_pos in lb.lex_buffer. *)
78 let pos0 = -lb
.lex_abs_pos
in
79 (* Do nothing if the buffer does not contain the whole phrase. *)
80 if pos0 < 0 then raise Exit
;
81 (* Count number of lines in phrase *)
82 let lines = ref !num_loc_lines in
83 for i
= pos0 to lb
.lex_buffer_len
- 1 do
84 if lb
.lex_buffer
.[i
] = '
\n'
then incr
lines
86 (* If too many lines, give up *)
87 if !lines >= num_lines
- 2 then raise Exit
;
88 (* Move cursor up that number of lines *)
89 flush stdout
; Terminfo.backup
!lines;
90 (* Print the input, switching to standout for the location *)
91 let bol = ref false in
93 for pos
= 0 to lb
.lex_buffer_len
- pos0 - 1 do
94 if !bol then (print_string
" "; bol := false);
95 if pos
= loc1
.loc_start
.pos_cnum
|| pos
= loc2
.loc_start
.pos_cnum
then
96 Terminfo.standout
true;
97 if pos
= loc1
.loc_end
.pos_cnum
|| pos
= loc2
.loc_end
.pos_cnum
then
98 Terminfo.standout
false;
99 let c = lb
.lex_buffer
.[pos
+ pos0] in
103 (* Make sure standout mode is over *)
104 Terminfo.standout
false;
105 (* Position cursor back to original location *)
106 Terminfo.resume
!num_loc_lines;
109 (* Highlight the location by printing it again. *)
111 let highlight_dumb ppf lb
loc =
112 (* Char 0 is at offset -lb.lex_abs_pos in lb.lex_buffer. *)
113 let pos0 = -lb
.lex_abs_pos
in
114 (* Do nothing if the buffer does not contain the whole phrase. *)
115 if pos0 < 0 then raise Exit
;
116 let end_pos = lb
.lex_buffer_len
- pos0 - 1 in
117 (* Determine line numbers for the start and end points *)
118 let line_start = ref 0 and line_end
= ref 0 in
119 for pos
= 0 to end_pos do
120 if lb
.lex_buffer
.[pos
+ pos0] = '
\n'
then begin
121 if loc.loc_start
.pos_cnum
> pos
then incr
line_start;
122 if loc.loc_end
.pos_cnum
> pos
then incr line_end
;
125 (* Print character location (useful for Emacs) *)
126 Format.fprintf ppf
"Characters %i-%i:@."
127 loc.loc_start
.pos_cnum
loc.loc_end
.pos_cnum
;
128 (* Print the input, underlining the location *)
129 Format.pp_print_string ppf
" ";
131 let pos_at_bol = ref 0 in
132 for pos
= 0 to end_pos do
133 let c = lb
.lex_buffer
.[pos
+ pos0] in
134 if c <> '
\n'
then begin
135 if !line = !line_start && !line = !line_end
then
136 (* loc is on one line: print whole line *)
137 Format.pp_print_char ppf
c
138 else if !line = !line_start then
139 (* first line of multiline loc: print ... before loc_start *)
140 if pos
< loc.loc_start
.pos_cnum
141 then Format.pp_print_char ppf '
.'
142 else Format.pp_print_char ppf
c
143 else if !line = !line_end
then
144 (* last line of multiline loc: print ... after loc_end *)
145 if pos
< loc.loc_end
.pos_cnum
146 then Format.pp_print_char ppf
c
147 else Format.pp_print_char ppf '
.'
148 else if !line > !line_start && !line < !line_end
then
149 (* intermediate line of multiline loc: print whole line *)
150 Format.pp_print_char ppf
c
152 if !line = !line_start && !line = !line_end
then begin
153 (* loc is on one line: underline location *)
154 Format.fprintf ppf
"@. ";
155 for i
= !pos_at_bol to loc.loc_start
.pos_cnum
- 1 do
156 Format.pp_print_char ppf ' '
158 for i
= loc.loc_start
.pos_cnum
to loc.loc_end
.pos_cnum
- 1 do
159 Format.pp_print_char ppf '^'
162 if !line >= !line_start && !line <= !line_end
then begin
163 Format.fprintf ppf
"@.";
164 if pos
< loc.loc_end
.pos_cnum
then Format.pp_print_string ppf
" "
167 pos_at_bol := pos
+ 1;
171 (* Highlight the location using one of the supported modes. *)
173 let rec highlight_locations ppf loc1 loc2
=
175 Terminfo.Uninitialised
->
176 status := Terminfo.setup stdout
; highlight_locations ppf loc1 loc2
177 | Terminfo.Bad_term
->
178 begin match !input_lexbuf with
182 try Sys.getenv
"TERM" = "norepeat" with Not_found
-> false in
183 if norepeat then false else
184 try highlight_dumb ppf lb loc1
; true
187 | Terminfo.Good_term num_lines
->
188 begin match !input_lexbuf with
191 try highlight_terminfo ppf num_lines lb loc1 loc2
; true
195 (* Print the location in some way or another *)
202 let (msg_file
, msg_line
, msg_chars
, msg_to
, msg_colon
, msg_head
) =
203 ("File \"", "\", line ", ", characters ", "-", ":", "")
205 (* return file, line, char from the given position *)
206 let get_pos_info pos
=
207 let (filename
, linenum
, linebeg
) =
208 if pos
.pos_fname
= "" && !input_name = "" then
210 else if pos
.pos_fname
= "" then
211 Linenum.for_position
!input_name pos
.pos_cnum
213 (pos
.pos_fname
, pos
.pos_lnum
, pos
.pos_bol
)
215 (filename
, linenum
, pos
.pos_cnum
- linebeg
)
219 let (file
, line, startchar
) = get_pos_info loc.loc_start
in
220 let endchar = loc.loc_end
.pos_cnum
- loc.loc_start
.pos_cnum
+ startchar
in
221 let (startchar
, endchar) =
222 if startchar
< 0 then (0, 1) else (startchar
, endchar)
224 if file
= "" then begin
225 if highlight_locations ppf
loc none then () else
226 fprintf ppf
"Characters %i-%i:@."
227 loc.loc_start
.pos_cnum
loc.loc_end
.pos_cnum
229 fprintf ppf
"%s%s%s%i" msg_file file msg_line
line;
230 fprintf ppf
"%s%i" msg_chars startchar
;
231 fprintf ppf
"%s%i%s@.%s" msg_to
endchar msg_colon msg_head
;
234 let print_warning loc ppf w
=
235 if Warnings.is_active w
then begin
237 let n = Warnings.print ppf w
in
238 num_loc_lines := !num_loc_lines + n
240 fprintf ppf
"%a" print loc;
241 fprintf ppf
"Warning %a@." printw w
;
242 pp_print_flush ppf
();
247 let prerr_warning loc w
= print_warning loc err_formatter w
;;