File: splitter.mll

package info (click to toggle)
herdtools7 7.58-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 19,732 kB
  • sloc: ml: 128,583; ansic: 3,827; makefile: 670; python: 407; sh: 212; awk: 14
file content (285 lines) | stat: -rw-r--r-- 8,797 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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
(****************************************************************************)
(*                           the diy toolsuite                              *)
(*                                                                          *)
(* Jade Alglave, University College London, UK.                             *)
(* Luc Maranget, INRIA Paris-Rocquencourt, France.                          *)
(*                                                                          *)
(* Copyright 2010-present Institut National de Recherche en Informatique et *)
(* en Automatique and the authors. All rights reserved.                     *)
(*                                                                          *)
(* This software is governed by the CeCILL-B license under French law and   *)
(* abiding by the rules of distribution of free software. You can use,      *)
(* modify and/ or redistribute the software under the terms of the CeCILL-B *)
(* license as circulated by CEA, CNRS and INRIA at the following URL        *)
(* "http://www.cecill.info". We also give a copy in LICENSE.txt.            *)
(****************************************************************************)

{
  open Lexing
  open LexMisc


(*  Result of splitter *)
type info = string * string

type result =
  {
    arch : Archs.t ;
    name : Name.t ;
    info : info list ;
    locs : Pos.pos2 * Pos.pos2 * Pos.pos2 *Pos.pos2 ;
    start : Lexing.position ;
  }

module type Config = sig
  include LexUtils.Config
  val check_rename : string -> string option
end

module Default = struct
  include LexUtils.Default
  let check_rename _ = None
end

let add_info buff k v =
  Buffer.add_string buff k ;
  Buffer.add_char buff '=' ;
  Buffer.add_string buff v ;
  Buffer.add_char buff '\n'

module Make(O:Config) = struct
  module LU = LexUtils.Make(O)
  open LU
}

let digit = [ '0'-'9' ]
let alpha = [ 'a'-'z' 'A'-'Z']
let blank = [' ' '\t' '\r']
let bool = "true" | "false"
let name  = alpha (alpha|digit|'_' | '/' | '.' | '-')*
 (* yes some test names are such *)
let testname  = (alpha|digit|'_' | '/' | '.' | '-' | '+'|'['|']')+
let num = digit+


rule main_pos = parse
| ""
    {
     let start = lexeme_start_p lexbuf  in
     main start lexbuf
    }

and main start = parse
| blank* (alpha|digit|'_')+ as arch
  blank+
  (testname as tname)
  blank*
  ('(' (name as texname) ')' blank*) ?
  ( ('\n'? as line) blank*'"'([^'"']* as doc) '"' blank*) ? (* '"' *)
  ';' ?
  { begin match line with Some _ -> incr_lineno lexbuf | None -> () end ;
    let arch =
      match Archs.parse arch with
      | Some a -> a
      | None ->
        Warn.user_error "%s is not an implemented architecture" arch in
    let (info,init1,(init2,prog1)) = find_init [] lexbuf in
    let do_skip_comments = match arch with
    | `C|`CPP -> false (* We can't skip comments in C, because "(*" is legal and frequent syntax *)
    | _ -> true in
    let is_empty,prog2 = inside_prog do_skip_comments lexbuf in
    let constr2 =
      if is_empty then prog2 else inside_constr lexbuf in
    let loc_eof = find_eof lexbuf in
    let tname =
      if tname = "--" then
        Filename.chop_extension
          (Filename.basename init1.pos_fname)
      else
 (* GRR follow litmus here *)
        Misc.clean_name tname in
    let tname = match O.check_rename tname with
    | None -> tname
    | Some n -> n in
    let names =
      { Name.name = tname ;
        file = init1.pos_fname ;
        texname = Misc.proj_opt tname texname ;
        doc = Misc.proj_opt "" doc ; } in
    { arch = arch ;
      name = names ;
      info = info ;
      locs = ((init1,init2),(prog1,prog2),(prog2,constr2),(constr2,loc_eof)) ;
      start = start ;
    }
  }
| "" { error "first line" lexbuf }

and find_init info = parse
| '\n'  { incr_lineno lexbuf ;  find_init info lexbuf }
| "(*" { skip_comment lexbuf ;  find_init info lexbuf }
| '{'
    { let loc1 = lexeme_end_p lexbuf in
      let loc2 = inside_init (Buffer.create 16) 0 lexbuf in
      List.rev info,loc1,loc2 }
| (name as key) blank* '=' blank* ([^'\n''\r']* as value) '\r'?'\n'
  { incr_lineno lexbuf ; find_init ((key,value)::info) lexbuf }
| [^'\n''{']+  { find_init info lexbuf }
| "" { error "find init section" lexbuf }

(* Courtesy of Luc - remove this comment when upstreaming *)
and inside_init buff depth = parse
| '{'   { Buffer.add_char buff '{'; inside_init buff (depth+1) lexbuf }
| '\n'  { incr_lineno lexbuf ;  inside_init buff depth lexbuf }
| '}'   { if depth > 0 then begin
            Buffer.add_char buff '}';
            inside_init buff (depth -1) lexbuf
          end else
            lexeme_start_p lexbuf,lexeme_end_p lexbuf
          }
| "" { error "inside init section" lexbuf }
| _ as c { Buffer.add_char buff c; inside_init buff depth lexbuf }

and inside_prog do_skip_comments = parse
| '\n'  { incr_lineno lexbuf ;  inside_prog do_skip_comments lexbuf }
(* Had to erase comments to handle C-code *)
| "(*"
    { if  do_skip_comments then  begin
      skip_comment lexbuf
    end ;
    inside_prog do_skip_comments lexbuf }
| "\""  { skip_string lexbuf ; inside_prog do_skip_comments lexbuf }
(* | "<<" *)  (* Had to erase this to handle C-code *)
|eof
    { true,lexeme_start_p lexbuf } (* boolean -> empty constraint *)
(* | "+" *) (* Had to erase this to handle C-code, why here ?? *)
| "final"
| "forall"
| ('~' blank* "exists" )
| "exists"
| "cases" (* not sure if this line should still be here *)
| "observed"|"Observed"
| "locations"
| "filter"
   { false,lexeme_start_p lexbuf }
 (* name is for longest match to avoid confusion, in case of eg. forallx *)
| (name | _)  { inside_prog do_skip_comments lexbuf }
| "" { error "inside_prog" lexbuf }

and inside_constr  = parse
| '\n'  { incr_lineno lexbuf ;  inside_constr lexbuf }
| "(*"  { skip_comment lexbuf ; inside_constr lexbuf }
| "<<"| eof  { lexeme_start_p lexbuf }
| _  { inside_constr lexbuf }
| "" { error "inside_constr" lexbuf }

and find_eof = parse
| '\n' { incr_lineno lexbuf ; find_eof lexbuf }
| [^'\n']+ { find_eof lexbuf }
| eof {  lexeme_start_p lexbuf }

(* Change info in the init section *)
and change_main buff p = parse
| blank* (alpha|digit|'_')+
  blank+
  testname
  blank*
  ('(' name ')' blank*) ?
  ( ('\n'? as line) blank*'"'[^'"']* '"' blank*) ? (* '"' *)
  [^'\n']* '\n' as lexed
  { begin match line with Some _ -> incr_lineno lexbuf | None -> () end ;
    incr_lineno lexbuf ;
    Buffer.add_string buff lexed ;
    change_info false p buff lexbuf }

and change_info found p buff = parse
| eof
    { () }
| '\n'
    { incr_lineno lexbuf ;
      Buffer.add_char buff '\n' ;
      change_info found p buff lexbuf }
| '\n'* '{' as lexed
    { incr_lineno lexbuf ;
      if not found then begin
        let k,v = p in
        add_info buff k v
      end ;
      Buffer.add_string buff lexed ;
      change_info found p buff lexbuf }
| (name as key) blank* '=' blank* [^'\n']* '\n' as line
  { incr_lineno lexbuf ;
    let k,v = p in
    if O.debug then Printf.eprintf "Found key: %s\n%!" key ;
    let found =
      if k = key then begin
        if not found then add_info buff k v ;
        true
      end else begin
        Buffer.add_string buff line ;
        found
      end in
    change_info found p buff lexbuf }
| [^'\n''{']+  as lexed
    { Buffer.add_string buff lexed ;
      change_info found p buff lexbuf }
| "" { error "change info" lexbuf }


{

(* Useful for debug *)
(*
 let pp_opt chan = function
   | None -> ()
   | Some s -> output_string chan s
*)

let pp_loc chan (i1,i2) =
  Printf.fprintf chan "%i-%i" i1.pos_cnum i2.pos_cnum

let show r =
  let loc_init,loc_prog,loc_constr,loc_cfgs = r.locs in
  Printf.eprintf
    "Test (arch=%s, name=%s, texname=%s, doc=%s)\nSplited as: init=%a, prog=%a, constr=%a, cfgs=%a\n"
    (Archs.pp r.arch)
    r.name.Name.name
    r.name.Name.texname
    r.name.Name.doc
    pp_loc loc_init
    pp_loc loc_prog
    pp_loc loc_constr
    pp_loc loc_cfgs

let split_lexbuf name lexbuf =
  lexbuf.lex_curr_p <-
    {pos_fname = name; pos_lnum = 1;
     pos_bol = 0; pos_cnum = 0};
  let r =
    try main_pos lexbuf
    with
    | LexMisc.Error (msg,loc) ->
       failwith (Printf.sprintf "%s: splitter error in sublexer %s" (Pos.str_pos loc) msg)
    | Assert_failure _ as e ->  raise e
    | e ->
       failwith (Printf.sprintf "%s: Uncaught exception in splitter %s" (Pos.str_pos lexbuf.lex_curr_p) (Printexc.to_string e))
  in
  if O.debug then show r ;
  r

let reinfo p lexbuf =
  let buff = Buffer.create 32 in
  change_main buff p lexbuf ;
  Buffer.contents buff

let rehash v lexbuf = reinfo (MiscParser.hash_key,v) lexbuf

let split name chan =
  let lexbuf = from_channel chan in
  split_lexbuf name lexbuf

let split_string name s =
  let lexbuf = from_string s in
  split_lexbuf name lexbuf
end
}