summaryrefslogtreecommitdiff
path: root/ocamltest/translate.ml
blob: 2554d64a4d5c2931ab32f5e2ad3f45b8eb129662 (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
(**************************************************************************)
(*                                                                        *)
(*                                 OCaml                                  *)
(*                                                                        *)
(*               Damien Doligez, projet Cambium, INRIA Paris              *)
(*                                                                        *)
(*   Copyright 2023 Institut National de Recherche en Informatique et     *)
(*     en Automatique.                                                    *)
(*                                                                        *)
(*   All rights reserved.  This file is distributed under the terms of    *)
(*   the GNU Lesser General Public License version 2.1, with the          *)
(*   special exception on linking described in the file LICENSE.          *)
(*                                                                        *)
(**************************************************************************)

(* Translate a test file from old to new syntax. *)

open Stdlib
open Printf

let copy ic oc up_to =
  try
    while pos_in ic < up_to do
      output_char oc (input_char ic)
    done
  with End_of_file -> ()

let text =
  "Filler_text_added_to_preserve_locations_while_translating_from_old_syntax__"
let len = String.length text
let index = ref (-1)
let lorem () = incr index; text.[!index mod len]

type mode =
| Keep_chars of int (* how many chars to skip before keeping chars *)
| Keep_lines

let copy_newlines ~mode ic oc up_to =
  let skip, insert =
    match mode with
    | Keep_lines ->
      ref max_int, ref "(* Blank lines added here to preserve locations. *)"
    | Keep_chars n -> ref n, ref ""
  in
  try
    while pos_in ic < up_to do
      let c = input_char ic in
      if c = '\n' || c = '\r' then begin
        output_char oc c;
        output_string oc !insert;
        insert := "";
      end else if !skip <= 0 then
        output_char oc (lorem ())
      else
        decr skip
    done
  with End_of_file -> ()

let tsl_block_of_file test_filename =
  let input_channel = open_in test_filename in
  let lexbuf = Lexing.from_channel input_channel in
  Location.init lexbuf test_filename;
  try
    let block = Tsl_parser.tsl_block Tsl_lexer.token lexbuf in
    close_in input_channel;
    if !Tsl_lexer.has_comments then
      eprintf "%s:1.0: warning: test script has comments\n" test_filename;
    block
  with
  | Parsing.Parse_error ->
    let open Lexing in
    let p = lexbuf.lex_start_p in
    Printf.eprintf "%s:%d.%d: syntax error in test script\n%!"
      test_filename p.pos_lnum (p.pos_cnum - p.pos_bol);
    raise Parsing.Parse_error

(* In what style to output the translated test file *)
type style =
| Plain
| Lines
| Chars

(* What kind of comments are used in the test file *)
type kind = { opening : string; closing : string }
let c_kind = { opening = "/*"; closing = "*/" }
let ocaml_kind = { opening = "(*"; closing = "*)" }

let file ~style ~compact f =
  let tsl_block = tsl_block_of_file f in
  let (rootenv_statements, test_trees) =
    Tsl_semantics.test_trees_of_tsl_block tsl_block
  in
  let ast =
    Tsl_semantics.tsl_ast_of_test_trees (rootenv_statements, test_trees)
  in
  let lex_ic = open_in f in
  let copy_ic = open_in f in
  let lexbuf = Lexing.from_channel lex_ic in
  Location.init lexbuf f;
  let rec seek_to_begin () =
    match Tsl_lexer.token lexbuf with
    | Tsl_parser.TSL_BEGIN_C_STYLE position -> (c_kind, position)
    | Tsl_parser.TSL_BEGIN_OCAML_STYLE position -> (ocaml_kind, position)
    | _ -> seek_to_begin ()
  in
  let rec seek_to_end () =
    match Tsl_lexer.token lexbuf with
    | Tsl_parser.TSL_END_C_STYLE -> ()
    | Tsl_parser.TSL_END_OCAML_STYLE -> ()
    | _ -> seek_to_end ()
  in
  let (kind, position) = seek_to_begin () in
  copy copy_ic stdout Lexing.(lexbuf.lex_curr_p.pos_cnum);
  if position = `Below || style = Plain then begin
    print_string (if ast = Tsl_ast.Ast ([], []) then " " else "\n");
    Tsl_semantics.print_tsl_ast ~compact stdout ast;
    seek_to_end ();
    seek_in copy_ic Lexing.(lexbuf.lex_start_p.pos_cnum);
    copy copy_ic stdout max_int;
  end else begin
    printf "_BELOW";
    seek_to_end ();
    let limit = Lexing.(lexbuf.lex_start_p.pos_cnum) in
    let mode =
      match style with
      | Lines -> Keep_lines
      | Chars -> Keep_chars 6
      | Plain -> assert false
    in
    copy_newlines ~mode copy_ic stdout limit;
    copy copy_ic stdout max_int;
    printf "\n%s TEST\n" kind.opening;
    Tsl_semantics.print_tsl_ast ~compact stdout ast;
    printf "%s\n" kind.closing;
  end;
  flush stdout;
  close_in lex_ic;
  close_in copy_ic;