Skip to content

Commit 9e7c4be

Browse files
committed
Clean up logic interface and add way to parse stdin in full mode
1 parent dbdf4df commit 9e7c4be

File tree

7 files changed

+103
-39
lines changed

7 files changed

+103
-39
lines changed

src/classes/logic.ml

+26-14
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,11 @@ module type S = sig
2424
val parse_file :
2525
?language:language ->
2626
string -> language * file * statement list
27-
val parse_file_lazy :
27+
val parse_all :
2828
?language:language ->
29-
string -> language * file * statement list Lazy.t
30-
val parse_raw_lazy :
31-
?language:language ->
32-
filename:string -> string -> language * file * statement list Lazy.t
29+
[< `File of string | `Stdin of language
30+
| `Raw of string * language * string ] ->
31+
language * file * statement list Lazy.t
3332
val parse_input :
3433
?language:language ->
3534
[< `File of string | `Stdin of language
@@ -156,15 +155,6 @@ module Make
156155
let locfile, res = P.parse_file file in
157156
l, locfile, res
158157

159-
let parse_file_lazy ?language file =
160-
let l, _, (module P : S) =
161-
match language with
162-
| None -> of_filename file
163-
| Some l -> of_language l
164-
in
165-
let locfile, res = P.parse_file_lazy file in
166-
l, locfile, res
167-
168158
let parse_raw_lazy ?language ~filename contents =
169159
let l, _, (module P : S) =
170160
match language with
@@ -174,6 +164,28 @@ module Make
174164
let locfile, res = P.parse_raw_lazy ~filename contents in
175165
l, locfile, res
176166

167+
let parse_all ?language = function
168+
| `File file ->
169+
let l, _, (module P : S) =
170+
match language with
171+
| None -> of_filename file
172+
| Some l -> of_language l
173+
in
174+
let locfile, res = P.parse_file_lazy file in
175+
l, locfile, res
176+
| `Raw (filename, l, s) ->
177+
let language =
178+
match language with Some _ -> language | None -> Some l
179+
in
180+
parse_raw_lazy ?language ~filename s
181+
| `Stdin l ->
182+
let filename = "<stdin>" in
183+
let s = Dolmen_std.Misc.read_all ~size:1024 stdin in
184+
let language =
185+
match language with Some _ -> language | None -> Some l
186+
in
187+
parse_raw_lazy ?language ~filename s
188+
177189
let parse_input ?language = function
178190
| `File file ->
179191
let l, _, (module P : S) =

src/classes/logic.mli

+30-14
Original file line numberDiff line numberDiff line change
@@ -51,21 +51,34 @@ module type S = sig
5151
string -> language * file * statement list
5252
(** Given a filename, parse the file, and return the detected language
5353
together with the list of statements parsed.
54-
@param language specify a language; overrides auto-detection. *)
5554
56-
val parse_file_lazy :
57-
?language:language ->
58-
string -> language * file * statement list Lazy.t
59-
(** Given a filename, parse the file, and return the detected language
60-
together with the list of statements parsed.
55+
WARNING: please note that this function makes it difficult to report
56+
error locations, since exceptions might be raised during parsing
57+
and any caller of this function will not have access to the [file]
58+
return value of the function, which is necessary to correctly
59+
interpret the locations in error exceptions. Instead, please use
60+
either {parse_all} or {parse_input}.
61+
6162
@param language specify a language; overrides auto-detection. *)
6263

63-
val parse_raw_lazy :
64+
val parse_all :
6465
?language:language ->
65-
filename:string -> string -> language * file * statement list Lazy.t
66-
(** Given a filename and a string, parse the string, and return the detected
67-
language together with the list of statements parsed.
68-
@param language specify a language; overrides auto-detection. *)
66+
[< `File of string
67+
| `Stdin of language
68+
| `Raw of string * language * string ] ->
69+
language * file * statement list Lazy.t
70+
(** Full (but lazy) parsing of either a file (see {!parse_file}), stdin
71+
(with given language), or some arbitrary contents, of the form
72+
[`Raw (filename, language, contents)].
73+
Returns a triplet [(lan, file, stmts)], containing:
74+
- the language [lan] detected
75+
- a [file] value that stores the metadata about file locations
76+
- a lazy list of statements [stmts]; forcing this list will run the actual
77+
parsing of the whole input given as argument, and may raise errors, if
78+
any arises during the parsing (such as lexical errors, etc..)
79+
80+
@param language specify a language for parsing, overrides auto-detection
81+
and stdin specification. *)
6982

7083
val parse_input :
7184
?language:language ->
@@ -76,9 +89,12 @@ module type S = sig
7689
(** Incremental parsing of either a file (see {!parse_file}), stdin
7790
(with given language), or some arbitrary contents, of the form
7891
[`Raw (filename, language, contents)].
79-
Returns a triplet [(lan, gen, cl)], containing
80-
the language detexted [lan], a genratro function [gen] for parsing the input,
81-
and a cleanup function [cl] to call in order to cleanup the file descriptors.
92+
Returns a quadruplet [(lan, file, gen, cl)], containing:
93+
- the language [lan] detected
94+
- a [file] value that stores the metadata about file locations
95+
- a genrator function [gen] for parsing the input,
96+
- a cleanup function [cl] to call in order to cleanup the file descriptors
97+
8298
@param language specify a language for parsing, overrides auto-detection
8399
and stdin specification. *)
84100

src/loop/parser.ml

+17-8
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,20 @@ module Make(State : State.S) = struct
193193
st, None
194194

195195
let parse_stdin st (file : Logic.language file) =
196-
let lang, file_loc, gen, _ = Logic.parse_input
197-
?language:file.lang (`Stdin (Logic.Smtlib2 `Latest))
198-
in
199-
let file = { file with loc = file_loc; lang = Some lang; } in
200-
st, file, gen
196+
match file.mode with
197+
| None
198+
| Some `Incremental ->
199+
let lang, file_loc, gen, _ = Logic.parse_input
200+
?language:file.lang (`Stdin (Logic.Smtlib2 `Latest))
201+
in
202+
let file = { file with loc = file_loc; lang = Some lang; } in
203+
st, file, gen
204+
| Some `Full ->
205+
let lang, file_loc, l = Logic.parse_all
206+
?language:file.lang (`Stdin (Logic.Smtlib2 `Latest))
207+
in
208+
let file = { file with loc = file_loc; lang = Some lang; } in
209+
st, file, gen_of_llist l
201210

202211
let parse_file st source (file : Logic.language file) lang =
203212
(* Parse the input *)
@@ -211,8 +220,8 @@ module Make(State : State.S) = struct
211220
let file = { file with loc = file_loc; lang = Some lang; } in
212221
st, file, gen_finally gen cl
213222
| Some `Full ->
214-
let lang, file_loc, l = Logic.parse_raw_lazy ~language:lang
215-
~filename contents
223+
let lang, file_loc, l = Logic.parse_all
224+
~language:lang (`Raw (filename, lang, contents))
216225
in
217226
let file = { file with loc = file_loc; lang = Some lang; } in
218227
st, file, gen_of_llist l
@@ -402,7 +411,7 @@ module Make(State : State.S) = struct
402411
let st = set_logic_file st new_logic_file in
403412
st, `Gen (merge, wrap_parser ~file:new_logic_file (gen_finally gen cl))
404413
| Some `Full ->
405-
let lang, file_loc, l = Logic.parse_file_lazy ?language file in
414+
let lang, file_loc, l = Logic.parse_all ?language (`File file) in
406415
let new_logic_file = { logic_file with loc = file_loc; lang = Some lang; } in
407416
let st = set_logic_file st new_logic_file in
408417
st, `Gen (merge, wrap_parser ~file:new_logic_file (gen_of_llist l))

src/standard/misc.ml

+22
Original file line numberDiff line numberDiff line change
@@ -234,3 +234,25 @@ let mk_lexbuf i =
234234
set_file buf filename;
235235
buf, cl
236236

237+
(* Read everything from stdin *)
238+
(* ************************************************************************* *)
239+
(* Implementations mostly taken from containers, see
240+
https://github.com/c-cube/ocaml-containers/blob/master/src/core/CCIO.ml *)
241+
242+
let read_all ~size ic =
243+
let buf = ref (Bytes.create size) in
244+
let len = ref 0 in
245+
try
246+
while true do
247+
(* resize *)
248+
if !len = Bytes.length !buf then buf := Bytes.extend !buf 0 !len;
249+
assert (Bytes.length !buf > !len);
250+
let n = input ic !buf !len (Bytes.length !buf - !len) in
251+
len := !len + n;
252+
if n = 0 then raise Exit
253+
(* exhausted *)
254+
done;
255+
assert false (* never reached*)
256+
with Exit ->
257+
Bytes.sub_string !buf 0 !len
258+

src/standard/misc.mli

+5
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,8 @@ val mk_lexbuf :
9797
contents to be parsed. *)
9898

9999

100+
(** {2 In_channel helpers} *)
101+
102+
val read_all : size:int -> in_channel -> string
103+
(** Read all the contents of an in_channel into a string. *)
104+

tests/qcheck/maps.ml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ module M = Map.Make(String)
55
module T = Dolmen_std.Maps.String
66

77
let add_find =
8-
QCheck2.Test.make ~count:1_000 ~long_factor:100
8+
QCheck2.Test.make ~count:500 ~long_factor:100
99
~name:"Maps.add_find"
1010
QCheck2.Gen.(list (pair string int))
1111
(fun l ->

tests/qcheck/print.ml

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ module L = Dolmen.Class.Logic.Make
1717
let identifier
1818
~print ~template ~name ~is_print_exn ~language ~gen =
1919
QCheck2.Test.make
20-
~count:1_000 ~long_factor:1_000
20+
~count:50 ~max_gen:500 ~long_factor:100
2121
~print:(fun name -> Format.asprintf template print name)
2222
~name gen
2323
(fun name ->
@@ -26,7 +26,7 @@ let identifier
2626
with exn when is_print_exn exn ->
2727
QCheck2.assume_fail ()
2828
in
29-
let _, _, l = L.parse_raw_lazy ~language ~filename:"test" test in
29+
let _, _, l = L.parse_all ~language (`Raw ("test", language, test)) in
3030
try
3131
let _ = Lazy.force l in
3232
true

0 commit comments

Comments
 (0)