File: typecheck.ml

package info (click to toggle)
labltk 8.06.15-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,972 kB
  • sloc: ml: 12,549; ansic: 1,005; makefile: 578; sh: 289; tcl: 2
file content (188 lines) | stat: -rw-r--r-- 6,575 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
(*************************************************************************)
(*                                                                       *)
(*                         OCaml LablTk library                          *)
(*                                                                       *)
(*            Jacques Garrigue, Kyoto University RIMS                    *)
(*                                                                       *)
(*   Copyright 1999 Institut National de Recherche en Informatique et    *)
(*   en Automatique and Kyoto University.  All rights reserved.          *)
(*   This file is distributed under the terms of the GNU Library         *)
(*   General Public License, with the special exception on linking       *)
(*   described in file ../../../LICENSE.                                 *)
(*                                                                       *)
(*************************************************************************)

(* $Id$ *)

open StdLabels
open Tk
open Parsetree
open Typedtree
open Location
open Jg_tk
open Mytypes

(* Optionally preprocess a source file *)

let preprocess ~pp ~ext text =
  let sourcefile = Filename.temp_file "caml" ext in
  begin try
    let oc = open_out_bin sourcefile in
    output_string oc text;
    flush oc;
    close_out oc
  with _ ->
    failwith "Preprocessing error"
  end;
  let tmpfile = Filename.temp_file "camlpp" ext in
  let comm = Printf.sprintf "%s %s > %s" pp sourcefile tmpfile in
  if Ccomp.command comm <> 0 then begin
    Sys.remove sourcefile;
    Sys.remove tmpfile;
    failwith "Preprocessing error"
  end;
  Sys.remove sourcefile;
  tmpfile

exception Outdated_version

let parse_pp ~parse ~wrap ~ext text =
  Location.input_name := "";
  match !Clflags.preprocessor with
    None ->
      let buffer = Lexing.from_string text in
      Location.init buffer "";
      parse buffer
  | Some pp ->
      let tmpfile = preprocess ~pp ~ext text in
      let ast_magic =
        if ext = ".ml" then Config.ast_impl_magic_number
        else Config.ast_intf_magic_number in
      let ic = open_in_bin tmpfile in
      let ast =
        try
          let buffer = really_input_string ic (String.length ast_magic) in
          if buffer = ast_magic then begin
            ignore (input_value ic);
            wrap (input_value ic)
          end else if String.sub buffer ~pos:0 ~len:9
                    = String.sub ast_magic ~pos:0 ~len:9
          then raise Outdated_version
          else raise Exit
        with
          Outdated_version ->
            close_in ic;
            Sys.remove tmpfile;
            failwith "OCaml and preprocessor have incompatible versions"
        | _ ->
            seek_in ic 0;
            let buffer = Lexing.from_channel ic in
            Location.init buffer "";
            parse buffer
      in
      close_in ic;
      Sys.remove tmpfile;
      ast

let update_type_info txt =
  let open Cmt2annot_raw in
  let iter = iterator true ~scope:(Location.in_file txt.name) in
  List.iter ~f:(binary_part iter) (Cmt_format.get_saved_types ());
  txt.type_info <- Stypes.get_info ()

let nowarnings = ref false

let f txt =
  let error_messages = ref [] in
  let text = Jg_text.get_all txt.tw
  and env = ref (Compmisc.initial_env ()) in
  let tl, ew, end_message =
    Jg_message.formatted ~title:"Warnings" ~ppf:Format.err_formatter () in
  Text.tag_remove txt.tw ~tag:"error" ~start:tstart ~stop:tend;
  txt.structure <- [];
  txt.type_info <- [];
  txt.signature <- [];
  txt.psignature <- [];
  ignore (Stypes.get_info ());
  Clflags.annotations := true;
  Clflags.color := Some Misc.Color.Never;

  begin try

    if Filename.check_suffix txt.name ".mli" then
    let psign = parse_pp text ~ext:".mli"
        ~parse:Parse.interface ~wrap:(fun x -> x) in
    txt.psignature <- psign;
    txt.signature <- (Typemod.type_interface !env psign).sig_type;

    else (* others are interpreted as .ml *)

    let psl = parse_pp text ~ext:".ml"
        ~parse:Parse.use_file ~wrap:(fun x -> [Parsetree.Ptop_def x]) in
    List.iter psl ~f:
    begin function
      Ptop_def pstr ->
        let str, sign, _names, _, env' = Typemod.type_structure !env pstr in
        txt.structure <- txt.structure @ str.str_items;
        txt.signature <- txt.signature @ sign;
        env := env'
    | Ptop_dir _ -> ()
    end;
    update_type_info txt

  with
    Lexer.Error _ | Syntaxerr.Error _
  | Typecore.Error _ | Typemod.Error _
  | Typeclass.Error _ | Typedecl.Error _
  | Typetexp.Error _ | Includemod.Error _
  | Persistent_env.Error _ | Env.Error _
  | Ctype.Tags _ | Failure _ as exn ->
      update_type_info txt;
      let et, ew, end_message = Jg_message.formatted ~title:"Error !" () in
      error_messages := et :: !error_messages;
      let range = match exn with
        Lexer.Error (err, l) -> l
      | Syntaxerr.Error err -> Syntaxerr.location_of_error err
      | Typecore.Error (l, env, err) -> l
      | Typeclass.Error (l, env, err) -> l
      | Typedecl.Error (l, err) -> l
      | Typemod.Error (l, env, err) -> l
      | Typetexp.Error (l, env, err) -> l
      | Env.Error (Missing_module (l, _, _) | Illegal_value_name (l, _) |
                   Lookup_error (l, _, _)) -> l
      | _ -> Location.none
      in
      begin match exn with
      | Cmi_format.Error err ->
          Cmi_format.report_error Format.std_formatter err
      | Ctype.Tags(l, l') ->
          Format.printf 
            "In this program,@ variant constructors@ `%s and `%s@ %s.@."
            l l' "have same hash value"
      | Failure s ->
          Format.printf "%s.@." s
      | _ -> Location.report_exception Format.std_formatter exn
      end;
      end_message ();
      let s = range.loc_start.Lexing.pos_cnum in
      let e = range.loc_end.Lexing.pos_cnum in
      if s < e then
        Jg_text.tag_and_see txt.tw ~start:(tpos s) ~stop:(tpos e) ~tag:"error"
  end;
  end_message ();
  if !nowarnings || Text.index ew ~index:tend = `Linechar (2,0)
  then destroy tl
  else begin
    error_messages := tl :: !error_messages;
    Text.configure ew ~state:`Disabled;
    bind ew ~events:[`Modified([`Double], `ButtonReleaseDetail 1)]
      ~action:(fun _ ->
        try
          let start, ende = Text.tag_nextrange ew ~tag:"sel" ~start:(tpos 0) in
          let s = Text.get ew ~start:(start,[]) ~stop:(ende,[]) in
          let n = int_of_string s in
          Text.mark_set txt.tw ~index:(tpos n) ~mark:"insert";
          Text.see txt.tw ~index:(`Mark "insert", [])
        with _ -> ())
  end;
  !error_messages