summaryrefslogtreecommitdiffstats
path: root/tools/ocaml299to3.ml
blob: fb66c7616c440d975501627e3e8eccf18a065630 (plain)
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
(***********************************************************************)
(*                                                                     *)
(*                                OCaml                                *)
(*                                                                     *)
(*              Jacques Garrigue, Kyoto University RIMS                *)
(*                                                                     *)
(*  Copyright 1996 Institut National de Recherche en Informatique et   *)
(*  en Automatique.  All rights reserved.  This file is distributed    *)
(*  under the terms of the Q Public License version 1.0.               *)
(*                                                                     *)
(***********************************************************************)

(* $Id$ *)

open Lexer299

let input_buffer = Buffer.create 16383
let input_function ic buf len =
  let len = input ic buf 0 len in
  Buffer.add_substring input_buffer buf 0 len;
  len

let output_buffer = Buffer.create 16383

let modified = ref false

let convert buffer =
  let input_pos = ref 0 in
  let copy_input stop =
    Buffer.add_substring output_buffer (Buffer.contents input_buffer)
      !input_pos (stop - !input_pos);
    input_pos := stop
  in
  let last = ref (EOF, 0, 0) in
  try while true do
    let token = Lexer299.token buffer
    and start = Lexing.lexeme_start buffer
    and stop = Lexing.lexeme_end buffer
    and last_token, last_start, last_stop = !last in
    begin match token with
    | LABEL l0 ->
        let l = if l0 = "fun" then "f" else l0 in
        begin match last_token with
        | PREFIXOP "?(" ->
            modified := true;
            copy_input last_start;
            Buffer.add_char output_buffer '?';
            Buffer.add_string output_buffer l;
            Buffer.add_string output_buffer ":(";
            input_pos := stop
        | QUESTION | LPAREN | LBRACE | SEMI | MINUSGREATER
        | EQUAL | COLON | COLONGREATER
        | VAL | MUTABLE | EXTERNAL | METHOD | OF ->
            if l0 = "fun" then begin
              modified := true;
              copy_input start;
              Buffer.add_string output_buffer l;
              Buffer.add_char output_buffer ':';
              input_pos := stop
            end
        | _ ->
            modified := true;
            copy_input start;
            Buffer.add_char output_buffer '~';
            Buffer.add_string output_buffer l;
            Buffer.add_char output_buffer ':';
            input_pos := stop
        end
    | LABELID l ->
        modified := true;
        begin match last_token with
        | PREFIXOP "?(" ->
            copy_input last_start;
            Buffer.add_string output_buffer "?(";
            Buffer.add_string output_buffer l;
            input_pos := stop
        | LPAREN ->
            copy_input last_start;
            Buffer.add_string output_buffer "~(";
            Buffer.add_string output_buffer l;
            input_pos := stop
        | QUESTION ->
            copy_input last_stop;
            Buffer.add_string output_buffer l;
            input_pos := stop
        | _ ->
            copy_input start;
            Buffer.add_char output_buffer '~';
            Buffer.add_string output_buffer l;
            input_pos := stop
       end
    | EOF -> raise End_of_file
    | _ -> ()
    end;
    if last_token = QUESTION && token = LPAREN then
      last := (PREFIXOP "?(", last_start, stop)
    else
      last := (token, start, stop)
  done with
    End_of_file ->
      copy_input (Buffer.length input_buffer)

let convert_file name =
  let ic = open_in name in
  Buffer.clear input_buffer;
  Buffer.clear output_buffer;
  modified := false;
  begin
    try convert (Lexing.from_function (input_function ic)); close_in ic
    with exn -> close_in ic; raise exn
  end;
  if !modified then begin
    let backup = name ^ ".bak" in
    if Sys.file_exists backup then Sys.remove name
    else Sys.rename name backup;
    let oc = open_out name in
    Buffer.output_buffer oc output_buffer;
    close_out oc
  end

let _ =
  if Array.length Sys.argv < 2 || Sys.argv.(1) = "-h" || Sys.argv.(1) = "-help"
  then begin
    print_endline "Usage: ocaml299to3 <source file> ...";
    print_endline "Description:";
    print_endline
      "Convert OCaml 2.99 O'Labl-style labels in implementation files to";
    print_endline
      "a syntax compatible with version 3. Also `fun:' labels are replaced by `f:'.";
    print_endline "Other syntactic changes are not handled.";
    print_endline "Old files are renamed to <file>.bak.";
    print_endline "Interface files do not need label syntax conversion.";
    exit 0
  end;
  for i = 1 to Array.length Sys.argv - 1 do
    let name = Sys.argv.(i) in
    prerr_endline ("Converting " ^ name);
    Printexc.catch convert_file name
  done