Blame browser/typecheck.ml

Packit bd2e5d
(*************************************************************************)
Packit bd2e5d
(*                                                                       *)
Packit bd2e5d
(*                         OCaml LablTk library                          *)
Packit bd2e5d
(*                                                                       *)
Packit bd2e5d
(*            Jacques Garrigue, Kyoto University RIMS                    *)
Packit bd2e5d
(*                                                                       *)
Packit bd2e5d
(*   Copyright 1999 Institut National de Recherche en Informatique et    *)
Packit bd2e5d
(*   en Automatique and Kyoto University.  All rights reserved.          *)
Packit bd2e5d
(*   This file is distributed under the terms of the GNU Library         *)
Packit bd2e5d
(*   General Public License, with the special exception on linking       *)
Packit bd2e5d
(*   described in file ../../../LICENSE.                                 *)
Packit bd2e5d
(*                                                                       *)
Packit bd2e5d
(*************************************************************************)
Packit bd2e5d
Packit bd2e5d
(* $Id$ *)
Packit bd2e5d
Packit bd2e5d
open StdLabels
Packit bd2e5d
open Tk
Packit bd2e5d
open Parsetree
Packit bd2e5d
open Typedtree
Packit bd2e5d
open Location
Packit bd2e5d
open Jg_tk
Packit bd2e5d
open Mytypes
Packit bd2e5d
Packit bd2e5d
(* Optionally preprocess a source file *)
Packit bd2e5d
Packit bd2e5d
let preprocess ~pp ~ext text =
Packit bd2e5d
  let sourcefile = Filename.temp_file "caml" ext in
Packit bd2e5d
  begin try
Packit bd2e5d
    let oc = open_out_bin sourcefile in
Packit bd2e5d
    output_string oc text;
Packit bd2e5d
    flush oc;
Packit bd2e5d
    close_out oc
Packit bd2e5d
  with _ ->
Packit bd2e5d
    failwith "Preprocessing error"
Packit bd2e5d
  end;
Packit bd2e5d
  let tmpfile = Filename.temp_file "camlpp" ext in
Packit bd2e5d
  let comm = Printf.sprintf "%s %s > %s" pp sourcefile tmpfile in
Packit bd2e5d
  if Ccomp.command comm <> 0 then begin
Packit bd2e5d
    Sys.remove sourcefile;
Packit bd2e5d
    Sys.remove tmpfile;
Packit bd2e5d
    failwith "Preprocessing error"
Packit bd2e5d
  end;
Packit bd2e5d
  Sys.remove sourcefile;
Packit bd2e5d
  tmpfile
Packit bd2e5d
Packit bd2e5d
exception Outdated_version
Packit bd2e5d
Packit bd2e5d
let parse_pp ~parse ~wrap ~ext text =
Packit bd2e5d
  Location.input_name := "";
Packit bd2e5d
  match !Clflags.preprocessor with
Packit bd2e5d
    None ->
Packit bd2e5d
      let buffer = Lexing.from_string text in
Packit bd2e5d
      Location.init buffer "";
Packit bd2e5d
      parse buffer
Packit bd2e5d
  | Some pp ->
Packit bd2e5d
      let tmpfile = preprocess ~pp ~ext text in
Packit bd2e5d
      let ast_magic =
Packit bd2e5d
        if ext = ".ml" then Config.ast_impl_magic_number
Packit bd2e5d
        else Config.ast_intf_magic_number in
Packit bd2e5d
      let ic = open_in_bin tmpfile in
Packit bd2e5d
      let ast =
Packit bd2e5d
        try
Packit bd2e5d
          let buffer = really_input_string ic (String.length ast_magic) in
Packit bd2e5d
          if buffer = ast_magic then begin
Packit bd2e5d
            ignore (input_value ic);
Packit bd2e5d
            wrap (input_value ic)
Packit bd2e5d
          end else if String.sub buffer 0 9 = String.sub ast_magic 0 9 then
Packit bd2e5d
            raise Outdated_version
Packit bd2e5d
          else
Packit bd2e5d
            raise Exit
Packit bd2e5d
        with
Packit bd2e5d
          Outdated_version ->
Packit bd2e5d
            close_in ic;
Packit bd2e5d
            Sys.remove tmpfile;
Packit bd2e5d
            failwith "OCaml and preprocessor have incompatible versions"
Packit bd2e5d
        | _ ->
Packit bd2e5d
            seek_in ic 0;
Packit bd2e5d
            let buffer = Lexing.from_channel ic in
Packit bd2e5d
            Location.init buffer "";
Packit bd2e5d
            parse buffer
Packit bd2e5d
      in
Packit bd2e5d
      close_in ic;
Packit bd2e5d
      Sys.remove tmpfile;
Packit bd2e5d
      ast
Packit bd2e5d
Packit bd2e5d
let nowarnings = ref false
Packit bd2e5d
Packit bd2e5d
let f txt =
Packit bd2e5d
  let error_messages = ref [] in
Packit bd2e5d
  let text = Jg_text.get_all txt.tw
Packit bd2e5d
  and env = ref (Compmisc.initial_env ()) in
Packit bd2e5d
  let tl, ew, end_message =
Packit bd2e5d
    Jg_message.formatted ~title:"Warnings" ~ppf:Format.err_formatter () in
Packit bd2e5d
  Text.tag_remove txt.tw ~tag:"error" ~start:tstart ~stop:tend;
Packit bd2e5d
  txt.structure <- [];
Packit bd2e5d
  txt.type_info <- [];
Packit bd2e5d
  txt.signature <- [];
Packit bd2e5d
  txt.psignature <- [];
Packit bd2e5d
  ignore (Stypes.get_info ());
Packit bd2e5d
  Clflags.annotations := true;
Packit bd2e5d
Packit bd2e5d
  begin try
Packit bd2e5d
Packit bd2e5d
    if Filename.check_suffix txt.name ".mli" then
Packit bd2e5d
    let psign = parse_pp text ~ext:".mli"
Packit bd2e5d
        ~parse:Parse.interface ~wrap:(fun x -> x) in
Packit bd2e5d
    txt.psignature <- psign;
Packit bd2e5d
    txt.signature <- (Typemod.transl_signature !env psign).sig_type;
Packit bd2e5d
Packit bd2e5d
    else (* others are interpreted as .ml *)
Packit bd2e5d
Packit bd2e5d
    let psl = parse_pp text ~ext:".ml"
Packit bd2e5d
        ~parse:Parse.use_file ~wrap:(fun x -> [Parsetree.Ptop_def x]) in
Packit bd2e5d
    List.iter psl ~f:
Packit bd2e5d
    begin function
Packit bd2e5d
      Ptop_def pstr ->
Packit bd2e5d
        let str, sign, env' = Typemod.type_structure !env pstr Location.none in
Packit bd2e5d
        txt.structure <- txt.structure @ str.str_items;
Packit bd2e5d
        txt.signature <- txt.signature @ sign;
Packit bd2e5d
        env := env'
Packit bd2e5d
    | Ptop_dir _ -> ()
Packit bd2e5d
    end;
Packit bd2e5d
    txt.type_info <- Stypes.get_info ();
Packit bd2e5d
Packit bd2e5d
  with
Packit bd2e5d
    Lexer.Error _ | Syntaxerr.Error _
Packit bd2e5d
  | Typecore.Error _ | Typemod.Error _
Packit bd2e5d
  | Typeclass.Error _ | Typedecl.Error _
Packit bd2e5d
  | Typetexp.Error _ | Includemod.Error _
Packit bd2e5d
  | Env.Error _ | Ctype.Tags _ | Failure _ as exn ->
Packit bd2e5d
      txt.type_info <- Stypes.get_info ();
Packit bd2e5d
      let et, ew, end_message = Jg_message.formatted ~title:"Error !" () in
Packit bd2e5d
      error_messages := et :: !error_messages;
Packit bd2e5d
      let range = match exn with
Packit bd2e5d
        Lexer.Error (err, l) ->
Packit bd2e5d
          Lexer.report_error Format.std_formatter err; l
Packit bd2e5d
      | Syntaxerr.Error err ->
Packit bd2e5d
          Syntaxerr.report_error Format.std_formatter err;
Packit bd2e5d
          Syntaxerr.location_of_error err
Packit bd2e5d
      | Typecore.Error (l, env, err) ->
Packit bd2e5d
          Typecore.report_error env Format.std_formatter err; l
Packit bd2e5d
      | Typeclass.Error (l, env, err) ->
Packit bd2e5d
          Typeclass.report_error env Format.std_formatter err; l
Packit bd2e5d
      | Typedecl.Error (l, err) ->
Packit bd2e5d
          Typedecl.report_error Format.std_formatter err; l
Packit bd2e5d
      | Typemod.Error (l, env, err) ->
Packit bd2e5d
          Typemod.report_error env Format.std_formatter err; l
Packit bd2e5d
      | Typetexp.Error (l, env, err) ->
Packit bd2e5d
          Typetexp.report_error env Format.std_formatter err; l
Packit bd2e5d
      | Includemod.Error errl ->
Packit bd2e5d
          Includemod.report_error Format.std_formatter errl; Location.none
Packit bd2e5d
      | Env.Error err ->
Packit bd2e5d
          Env.report_error Format.std_formatter err; Location.none
Packit bd2e5d
      | Cmi_format.Error err ->
Packit bd2e5d
          Cmi_format.report_error Format.std_formatter err; Location.none
Packit bd2e5d
      | Ctype.Tags(l, l') ->
Packit bd2e5d
          Format.printf "In this program,@ variant constructors@ `%s and `%s@ have same hash value.@." l l';
Packit bd2e5d
          Location.none
Packit bd2e5d
      | Failure s ->
Packit bd2e5d
          Format.printf "%s.@." s; Location.none
Packit bd2e5d
      | _ -> assert false
Packit bd2e5d
      in
Packit bd2e5d
      end_message ();
Packit bd2e5d
      let s = range.loc_start.Lexing.pos_cnum in
Packit bd2e5d
      let e = range.loc_end.Lexing.pos_cnum in
Packit bd2e5d
      if s < e then
Packit bd2e5d
        Jg_text.tag_and_see txt.tw ~start:(tpos s) ~stop:(tpos e) ~tag:"error"
Packit bd2e5d
  end;
Packit bd2e5d
  end_message ();
Packit bd2e5d
  if !nowarnings || Text.index ew ~index:tend = `Linechar (2,0)
Packit bd2e5d
  then destroy tl
Packit bd2e5d
  else begin
Packit bd2e5d
    error_messages := tl :: !error_messages;
Packit bd2e5d
    Text.configure ew ~state:`Disabled;
Packit bd2e5d
    bind ew ~events:[`Modified([`Double], `ButtonReleaseDetail 1)]
Packit bd2e5d
      ~action:(fun _ ->
Packit bd2e5d
        try
Packit bd2e5d
          let start, ende = Text.tag_nextrange ew ~tag:"sel" ~start:(tpos 0) in
Packit bd2e5d
          let s = Text.get ew ~start:(start,[]) ~stop:(ende,[]) in
Packit bd2e5d
          let n = int_of_string s in
Packit bd2e5d
          Text.mark_set txt.tw ~index:(tpos n) ~mark:"insert";
Packit bd2e5d
          Text.see txt.tw ~index:(`Mark "insert", [])
Packit bd2e5d
        with _ -> ())
Packit bd2e5d
  end;
Packit bd2e5d
  !error_messages