Skip to content

Commit 2e49780

Browse files
Remove Unix Dependency (rescript-lang#45)
* Revert "Prevent race conditions in Reason -> Res printing." This reverts commit e78c841. We do not want to rely on the unix module. * Document usage of temp file in refmt conversion
1 parent 6a14360 commit 2e49780

File tree

4 files changed

+66
-49
lines changed

4 files changed

+66
-49
lines changed

syntax/Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ FILES = \
3434
src/napkin_reason_binary_driver.cmx \
3535
src/napkin_binary_driver.cmx \
3636
src/napkin_ast_debugger.cmx \
37-
src/napkin_outcome_printer.cmx
37+
src/napkin_outcome_printer.cmx \
38+
src/napkin_multi_printer.cmx
3839

3940
.DEFAULT_GOAL := build-native
4041
build-native: lib/refmt.exe $(FILES) src/napkin_main.cmx depend
@@ -59,7 +60,7 @@ benchmarks/refmt_main3b.cmx: benchmarks/refmt_main3b.ml
5960
$(OCAMLOPT) -c -O2 -I +compiler-libs ocamlcommon.cmxa benchmarks/refmt_main3b.ml
6061

6162
lib/test.exe: tests/napkin_test.cmx
62-
$(OCAMLOPT) $(OCAMLFLAGS) -O2 -o ./lib/test.exe -bin-annot -I +compiler-libs ocamlcommon.cmxa unix.cmxa -I src $(FILES) src/napkin_multi_printer.cmx tests/napkin_test.ml
63+
$(OCAMLOPT) $(OCAMLFLAGS) -O2 -o ./lib/test.exe -bin-annot -I +compiler-libs ocamlcommon.cmxa -I src $(FILES) tests/napkin_test.ml
6364

6465
test: build-native lib/test.exe
6566
./node_modules/.bin/jest

syntax/src/napkin_io.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,9 @@ let readStdin () =
3131
)
3232
in
3333
loop ()
34+
35+
let writeFile ~filename ~content =
36+
let chan = open_out_bin filename in
37+
output_string chan content;
38+
close_out chan
39+
[@@raises Sys_error]

syntax/src/napkin_io.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,6 @@ val readFile: filename: string -> string
55

66
(* read the contents of stdin into a string*)
77
val readStdin: unit -> string
8+
9+
(* writes "content" into file with name "filename" *)
10+
val writeFile: filename: string -> content: string -> unit

syntax/src/napkin_multi_printer.ml

Lines changed: 54 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -54,60 +54,67 @@ let printMl ~isInterface ~filename =
5454
parseResult.parsetree
5555

5656
(* How does printing Reason to Res work?
57-
* -> Run refmt in parallel with the program,
58-
* the standard input and standard output of the refmt command are redirected
59-
* to pipes connected to the two returned channels
60-
* -> Read the source code of "filename"
61-
* -> Write the source code to output channel (i.e. the input of refmt)
62-
* -> Read the marshalled ast from the input channel (i.e. the output of refmt)
57+
* -> open a tempfile
58+
* -> write the source code found in "filename" into the tempfile
59+
* -> run refmt in-place in binary mode on the tempfile,
60+
* mutates contents tempfile with marshalled AST.j
61+
* -> read the marshalled ast (from the binary output in the tempfile)
6362
* -> re-read the original "filename" and extract string + comment data
6463
* -> put the comment- and string data back into the unmarshalled parsetree
65-
* -> normalize the ast to conform to the napkin printer
6664
* -> pretty print to res
6765
* -> take a deep breath and exhale slowly *)
6866
let printReason ~refmtPath ~isInterface ~filename =
69-
(* Run refmt in parallel with the program *)
70-
let refmtCmd = Printf.sprintf "%s --print=binary --interface=%b" refmtPath isInterface in
71-
let (refmtOutput, refmtInput) = Unix.open_process refmtCmd in
72-
(* Read the source code of "filename" *)
73-
let source = IO.readFile ~filename in
74-
(* Write the source code to output channel (i.e. the input of refmt) *)
75-
output_string refmtInput source;
76-
close_out refmtInput;
77-
(* Read the marshalled ast from the input channel (i.e. the output of refmt) *)
78-
let magic = if isInterface then Config.ast_intf_magic_number else Config.ast_impl_magic_number in
79-
ignore ((really_input_string [@doesNotRaise]) refmtOutput (String.length magic));
80-
ignore (input_value refmtOutput);
81-
let ast = input_value refmtOutput in
82-
close_in refmtOutput;
83-
(* re-read the original "filename" and extract string + comment data *)
84-
let (comments, stringData) = Napkin_reason_binary_driver.extractConcreteSyntax filename in
85-
if isInterface then
86-
let ast = ast
67+
(* open a tempfile *)
68+
let (tempFilename, chan) =
69+
(* refmt is just a prefix, `open_temp_file` takes care of providing a random name
70+
* It tries 1000 times in the case of a name conflict.
71+
* In practise this means that we shouldn't worry too much about filesystem races *)
72+
Filename.open_temp_file "refmt" (if isInterface then ".rei" else ".re") in
73+
close_out chan;
74+
(* Write the source code found in "filename" into the tempfile *)
75+
IO.writeFile ~filename:tempFilename ~content:(IO.readFile ~filename);
76+
let cmd = Printf.sprintf "%s --print=binary --in-place --interface=%b %s" refmtPath isInterface tempFilename in
77+
(* run refmt in-place in binary mode on the tempfile *)
78+
ignore (Sys.command cmd);
79+
let result =
80+
if isInterface then
81+
let parseResult =
82+
(* read the marshalled ast (from the binary output in the tempfile) *)
83+
Napkin_reason_binary_driver.parsingEngine.parseInterface ~forPrinter:true ~filename:tempFilename in
84+
(* re-read the original "filename" and extract string + comment data *)
85+
let (comments, stringData) = Napkin_reason_binary_driver.extractConcreteSyntax filename in
8786
(* put the comment- and string data back into the unmarshalled parsetree *)
88-
|> Napkin_ast_conversion.replaceStringLiteralSignature stringData
89-
(* normalize the ast to conform to the napkin printer *)
90-
|> Napkin_ast_conversion.normalizeReasonAritySignature ~forPrinter:true
91-
|> Napkin_ast_conversion.signature
92-
in
93-
(* pretty print to res *)
94-
Napkin_printer.printInterface
95-
~width:defaultPrintWidth
96-
~comments:comments
97-
ast
98-
else
99-
let ast = ast
87+
let parseResult = {
88+
parseResult with
89+
parsetree =
90+
parseResult.parsetree |> Napkin_ast_conversion.replaceStringLiteralSignature stringData;
91+
comments = comments;
92+
} in
93+
(* pretty print to res *)
94+
Napkin_printer.printInterface
95+
~width:defaultPrintWidth
96+
~comments:parseResult.comments
97+
parseResult.parsetree
98+
else
99+
let parseResult =
100+
(* read the marshalled ast (from the binary output in the tempfile) *)
101+
Napkin_reason_binary_driver.parsingEngine.parseImplementation ~forPrinter:true ~filename:tempFilename in
102+
let (comments, stringData) = Napkin_reason_binary_driver.extractConcreteSyntax filename in
100103
(* put the comment- and string data back into the unmarshalled parsetree *)
101-
|> Napkin_ast_conversion.replaceStringLiteralStructure stringData
102-
(* normalize the ast to conform to the napkin printer *)
103-
|> Napkin_ast_conversion.normalizeReasonArityStructure ~forPrinter:true
104-
|> Napkin_ast_conversion.structure
105-
in
106-
(* pretty print to res *)
107-
Napkin_printer.printImplementation
108-
~width:defaultPrintWidth
109-
~comments:comments
110-
ast
104+
let parseResult = {
105+
parseResult with
106+
parsetree =
107+
parseResult.parsetree |> Napkin_ast_conversion.replaceStringLiteralStructure stringData;
108+
comments = comments;
109+
} in
110+
(* pretty print to res *)
111+
Napkin_printer.printImplementation
112+
~width:defaultPrintWidth
113+
~comments:parseResult.comments
114+
parseResult.parsetree
115+
in
116+
Sys.remove tempFilename;
117+
result
111118
[@@raises Sys_error]
112119

113120
(* print the given file named input to from "language" to res, general interface exposed by the compiler *)

0 commit comments

Comments
 (0)