summaryrefslogtreecommitdiff
path: root/minijazz/src/global/location.ml
diff options
context:
space:
mode:
Diffstat (limited to 'minijazz/src/global/location.ml')
-rw-r--r--minijazz/src/global/location.ml130
1 files changed, 130 insertions, 0 deletions
diff --git a/minijazz/src/global/location.ml b/minijazz/src/global/location.ml
new file mode 100644
index 0000000..1837584
--- /dev/null
+++ b/minijazz/src/global/location.ml
@@ -0,0 +1,130 @@
+(* Printing a location in the source program *)
+(* inspired from the source of the Caml Light 0.73 compiler *)
+
+open Lexing
+open Parsing
+open Format
+
+(* two important global variables: [input_name] and [input_chan] *)
+type location =
+ Loc of position (* Position of the first character *)
+ * position (* Position of the next character following the last one *)
+
+
+let input_name = ref "" (* Input file name. *)
+
+let input_chan = ref stdin (* The channel opened on the input. *)
+
+let initialize iname ic =
+ input_name := iname;
+ input_chan := ic
+
+
+let no_location = Loc (dummy_pos, dummy_pos)
+
+let error_prompt = ">"
+
+
+(** Prints [n] times char [c] on [oc]. *)
+let prints_n_chars ff n c = for i = 1 to n do pp_print_char ff c done
+
+(** Prints out to [oc] a line designed to be printed under [line] from file [ic]
+ underlining from char [first] to char [last] with char [ch].
+ [line] is the index of the first char of line. *)
+let underline_line ic ff ch line first last =
+ let c = ref ' '
+ and f = ref first
+ and l = ref (last-first) in
+ ( try
+ seek_in ic line;
+ pp_print_string ff error_prompt;
+ while c := input_char ic; !c != '\n' do
+ if !f > 0 then begin
+ f := !f - 1;
+ pp_print_char ff (if !c == '\t' then !c else ' ')
+ end
+ else if !l > 0 then begin
+ l := !l - 1;
+ pp_print_char ff (if !c == '\t' then !c else ch)
+ end
+ else ()
+ done
+ with End_of_file ->
+ if !f = 0 && !l > 0 then prints_n_chars ff 5 ch )
+
+
+let copy_lines nl ic ff prompt =
+ for i = 1 to nl do
+ pp_print_string ff prompt;
+ (try pp_print_string ff (input_line ic)
+ with End_of_file -> pp_print_string ff "<EOF>");
+ fprintf ff "@\n"
+ done
+
+let copy_chunk p1 p2 ic ff =
+ try for i = p1 to p2 - 1 do pp_print_char ff (input_char ic) done
+ with End_of_file -> pp_print_string ff "<EOF>"
+
+
+
+let skip_lines n ic =
+ try for i = 1 to n do
+ let _ = input_line ic in ()
+ done
+ with End_of_file -> ()
+
+
+
+let print_location ff (Loc(p1,p2)) =
+ let n1 = p1.pos_cnum - p1.pos_bol in (* character number *)
+ let n2 = p2.pos_cnum - p2.pos_bol in
+ let np1 = p1.pos_cnum in (* character position *)
+ let np2 = p2.pos_cnum in
+ let l1 = p1.pos_lnum in (* line number *)
+ let l2 = p2.pos_lnum in
+ let lp1 = p1.pos_bol in (* line position *)
+ let lp2 = p2.pos_bol in
+ let f1 = p1.pos_fname in (* file name *)
+ let f2 = p2.pos_fname in
+
+ if f1 != f2 then (* Strange case *)
+ fprintf ff
+ "File \"%s\" line %d, character %d, to file \"%s\" line %d, character %d@."
+ f1 l1 n1 f2 l2 n2
+
+ else begin (* Same file *)
+ if l2 > l1 then
+ fprintf ff
+ "File \"%s\", line %d-%d, characters %d-%d:@\n" f1 l1 l2 n1 n2
+ else
+ fprintf ff "File \"%s\", line %d, characters %d-%d:@\n" f1 l1 n1 n2;
+ (* Output source code *)
+ try
+ let ic = open_in f1 in
+
+ if l1 == l2 then (
+ (* Only one line : copy full line and underline *)
+ seek_in ic lp1;
+ copy_lines 1 ic ff ">";
+ underline_line ic ff '^' lp1 n1 n2 )
+ else (
+ underline_line ic ff '.' lp1 0 n1; (* dots until n1 *)
+ seek_in ic np1;
+ (* copy the end of the line l1 after the dots *)
+ copy_lines 1 ic ff "";
+ if l2 - l1 <= 8 then
+ (* copy the 6 or less middle lines *)
+ copy_lines (l2-l1-1) ic ff ">"
+ else (
+ (* sum up the middle lines to 6 *)
+ copy_lines 3 ic ff ">";
+ fprintf ff "..........@\n";
+ skip_lines (l2-l1-7) ic; (* skip middle lines *)
+ copy_lines 3 ic ff ">"
+ );
+ fprintf ff ">";
+ copy_chunk lp2 np2 ic ff; (* copy interesting begining of l2 *)
+ )
+ with Sys_error _ -> ();
+ end;
+ fprintf ff "@."