(**************************************************************************) (* Lem *) (* *) (* Dominic Mulligan, University of Cambridge *) (* Francesco Zappa Nardelli, INRIA Paris-Rocquencourt *) (* Gabriel Kerneis, University of Cambridge *) (* Kathy Gray, University of Cambridge *) (* Peter Boehm, University of Cambridge (while working on Lem) *) (* Peter Sewell, University of Cambridge *) (* Scott Owens, University of Kent *) (* Thomas Tuerk, University of Cambridge *) (* *) (* The Lem sources are copyright 2010-2013 *) (* by the UK authors above and Institut National de Recherche en *) (* Informatique et en Automatique (INRIA). *) (* *) (* All files except ocaml-lib/pmap.{ml,mli} and ocaml-libpset.{ml,mli} *) (* are distributed under the license below. The former are distributed *) (* under the LGPLv2, as in the LICENSE file. *) (* *) (* *) (* Redistribution and use in source and binary forms, with or without *) (* modification, are permitted provided that the following conditions *) (* are met: *) (* 1. Redistributions of source code must retain the above copyright *) (* notice, this list of conditions and the following disclaimer. *) (* 2. Redistributions in binary form must reproduce the above copyright *) (* notice, this list of conditions and the following disclaimer in the *) (* documentation and/or other materials provided with the distribution. *) (* 3. The names of the authors may not be used to endorse or promote *) (* products derived from this software without specific prior written *) (* permission. *) (* *) (* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS *) (* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED *) (* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE *) (* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY *) (* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL *) (* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE *) (* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *) (* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER *) (* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR *) (* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN *) (* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *) (**************************************************************************) let format_pos ff p = ( Format.fprintf ff "File \"%s\", line %d, character %d:\n" p.Lexing.pos_fname p.Lexing.pos_lnum (p.Lexing.pos_cnum - p.Lexing.pos_bol); Format.pp_print_flush ff ()) let format_pos2 ff p1 p2 = ( Format.fprintf ff "File \"%s\", line %d, character %d to line %d, character %d" p1.Lexing.pos_fname p1.Lexing.pos_lnum (p1.Lexing.pos_cnum - p1.Lexing.pos_bol + 1) p2.Lexing.pos_lnum (p2.Lexing.pos_cnum - p2.Lexing.pos_bol); Format.pp_print_flush ff () ) (* reads the part between p1 and p2 from the file *) let read_from_file_pos2 p1 p2 = let (s, e, multi) = if p1.Lexing.pos_lnum = p2.Lexing.pos_lnum then (* everything in the same line, so really only read this small part*) (p1.Lexing.pos_cnum, p2.Lexing.pos_cnum, None) else (*multiline, so start reading at beginning of line *) (p1.Lexing.pos_bol, p2.Lexing.pos_cnum, Some (p1.Lexing.pos_cnum - p1.Lexing.pos_bol)) in let ic = open_in p1.Lexing.pos_fname in let _ = seek_in ic s in let l = (e - s) in let buf = String.create l in let _ = input ic buf 0 l in let _ = match multi with None -> () | Some sk -> String.fill buf 0 sk ' ' in let _ = close_in ic in (buf, not (multi = None)) (* Destruct a location by splitting all the Internal strings except possibly the last one into a string list and keeping only the last location *) let dest_loc (l : Parse_ast.l) : (Parse_ast.l * string list) = let rec aux acc l = match l with | Parse_ast.Int(s, Some l') -> aux (s::acc) l' | _ -> (l, acc) in aux [] l let rec format_loc_aux ff l = let (l_org, mod_s) = dest_loc l in let _ = match l_org with | Parse_ast.Unknown -> Format.fprintf ff "no location information available" | Parse_ast.Range(p1,p2) -> format_pos2 ff p1 p2 | Parse_ast.Int(s,_) -> Format.fprintf ff "code generated by: %s" s in () let format_loc_source ff l = match dest_loc l with | (Parse_ast.Range (p1, p2), _) -> begin let (s, multi_line) = read_from_file_pos2 p1 p2 in if multi_line then Format.fprintf ff " original input:\n%s\n" s else Format.fprintf ff " original input: \"%s\"\n" s end | _ -> () let format_loc ff l = (format_loc_aux ff l; Format.pp_print_newline ff (); Format.pp_print_flush ff () );; let print_err_loc l = (format_loc Format.err_formatter l) let print_pos p = format_pos Format.std_formatter p let print_err_pos p = format_pos Format.err_formatter p let loc_to_string l = let _ = Format.flush_str_formatter () in let _ = format_loc_aux Format.str_formatter l in let s = Format.flush_str_formatter () in s type pos_or_loc = Loc of Parse_ast.l | Pos of Lexing.position let print_err_internal fatal verb_loc p_l m1 m2 = let _ = (match p_l with Pos p -> print_err_pos p | Loc l -> print_err_loc l) in let m12 = if String.length m2 = 0 then "" else ": " in Format.eprintf " %s%s%s\n" m1 m12 m2; if verb_loc then (match p_l with Loc l -> format_loc_source Format.err_formatter l; Format.pp_print_newline Format.err_formatter (); | _ -> ()); Format.pp_print_flush Format.err_formatter (); if fatal then (exit 1) else () let print_err fatal verb_loc l m1 m2 = print_err_internal fatal verb_loc (Loc l) m1 m2 type error = | Err_general of Parse_ast.l * string | Err_unreachable of Parse_ast.l * string | Err_todo of Parse_ast.l * string | Err_syntax of Lexing.position * string | Err_syntax_locn of Parse_ast.l * string | Err_lex of Lexing.position * string | Err_type of Parse_ast.l * string let dest_err = function | Err_general (l, m) -> ("Error", false, Loc l, m) | Err_unreachable (l, m) -> ("Internal error: Unreachable code", false, Loc l, m) | Err_todo (l, m) -> ("Todo" ^ m, false, Loc l, "") | Err_syntax (p, m) -> ("Syntax error", false, Pos p, m) | Err_syntax_locn (l, m) -> ("Syntax error", false, Loc l, m) | Err_lex (p, s) -> ("Lexical error", false, Pos p, s) | Err_type (l, m) -> ("Type error", false, Loc l, m) exception Fatal_error of error (* Abbreviations for the very common cases *) let err_todo l m = Fatal_error (Err_todo (l, m)) let err_unreachable l m = Fatal_error (Err_unreachable (l, m)) let err_general l m = Fatal_error (Err_general (l, m)) let err_typ l m = Fatal_error (Err_type (l,m)) let report_error e = let (m1, verb_pos, pos_l, m2) = dest_err e in (print_err_internal verb_pos false pos_l m1 m2; exit 1)