Skip to content

Commit b70c321

Browse files
authored
Merge pull request #594 from bloomberg/bs-main
add an option `-bs-main`
2 parents a4aaf4c + 6591077 commit b70c321

32 files changed

+435
-165
lines changed

jscomp/common/bs_exception.ml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
type error =
2727
| Cmj_not_found of string
2828
| Bs_cyclic_depends of string list
29-
29+
| Bs_duplicated_module of string * string
3030
exception Error of error
3131

3232
let error err = raise (Error err)
@@ -39,7 +39,10 @@ let report_error ppf = function
3939
Format.fprintf ppf "Cyclic depends : @[%a@]"
4040
(Format.pp_print_list ~pp_sep:Format.pp_print_space
4141
Format.pp_print_string)
42-
str
42+
str
43+
| Bs_duplicated_module (a,b)
44+
->
45+
Format.fprintf ppf "The build system does not support two files with same names yet %s, %s" a b
4346

4447
let () =
4548
Location.register_error_of_exn

jscomp/common/bs_exception.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@
2525
type error =
2626
| Cmj_not_found of string
2727
| Bs_cyclic_depends of string list
28-
28+
| Bs_duplicated_module of string * string
2929
val error : error -> 'a

jscomp/ext/ext_array.ml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,12 @@ let map2i f a b =
8989
else
9090
Array.mapi (fun i a -> f i a ( Array.unsafe_get b i )) a
9191

92+
let to_list_f f a =
93+
let rec tolist i res =
94+
if i < 0 then res else
95+
let v = Array.unsafe_get a i in
96+
tolist (i - 1)
97+
(match f v with
98+
| Some v -> v :: res
99+
| None -> res) in
100+
tolist (Array.length a - 1) []

jscomp/ext/ext_array.mli

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,4 @@ val range : int -> int -> int array
3939

4040
val map2i : (int -> 'a -> 'b -> 'c ) -> 'a array -> 'b array -> 'c array
4141

42+
val to_list_f : ('a -> 'b option) -> 'a array -> 'b list

jscomp/js_main.ml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,13 @@ let intf filename =
3838
Compenv.readenv ppf Before_compile; process_interface_file ppf filename;;
3939

4040
let batch_files = ref []
41-
41+
let main_file = ref ""
42+
4243
let collect_file name =
4344
batch_files := name :: !batch_files
4445

45-
46+
let set_main_entry name =
47+
main_file := name
4648

4749

4850

@@ -108,6 +110,10 @@ let buckle_script_flags =
108110
Arg.Unit set_noassert,
109111
" no code containing any assertion"
110112
)
113+
::
114+
("-bs-main",
115+
Arg.String set_main_entry,
116+
" set the Main entry file")
111117
::
112118
("-bs-files",
113119
Arg.Rest collect_file,
@@ -128,8 +134,7 @@ let _ =
128134
try
129135
Compenv.readenv ppf Before_args;
130136
Arg.parse buckle_script_flags anonymous usage;
131-
Ocaml_batch_compile.batch_compile ppf !batch_files;
132-
exit 0
137+
exit (Ocaml_batch_compile.batch_compile ppf !batch_files !main_file)
133138
with x ->
134139
Location.report_exception ppf x;
135140
exit 2

jscomp/ocaml_batch_compile.ml

Lines changed: 181 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -23,62 +23,187 @@
2323
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
2424

2525

26-
let batch_compile ppf files =
26+
let module_name_of_file file =
27+
String.capitalize
28+
(Filename.chop_extension @@ Filename.basename file)
29+
30+
let build_queue ppf queue (ast_table : _ Ast_extract.t String_map.t) =
31+
queue |> Queue.iter (fun modname ->
32+
match String_map.find modname ast_table with
33+
| {ast_info = Ml(source_file,ast, opref)}
34+
->
35+
Js_implementation.after_parsing_impl ppf source_file
36+
opref ast
37+
| {ast_info = Mli (source_file,ast,opref) ; }
38+
->
39+
Js_implementation.after_parsing_sig ppf source_file
40+
opref ast
41+
| {ast_info = Ml_mli(source_file1,impl,opref1,source_file2,intf,opref2)}
42+
->
43+
Js_implementation.after_parsing_sig ppf source_file1 opref1 intf ;
44+
Js_implementation.after_parsing_impl ppf source_file2 opref2 impl
45+
| exception Not_found -> assert false
46+
)
47+
48+
let build_lazy_queue ppf queue (ast_table : _ Ast_extract.t String_map.t) =
49+
queue |> Queue.iter (fun modname ->
50+
match String_map.find modname ast_table with
51+
| {ast_info = Ml(source_file,lazy ast, opref)}
52+
->
53+
Js_implementation.after_parsing_impl ppf source_file
54+
opref ast
55+
| {ast_info = Mli (source_file,lazy ast,opref) ; }
56+
->
57+
Js_implementation.after_parsing_sig ppf source_file
58+
opref ast
59+
| {ast_info = Ml_mli(source_file1,lazy impl,opref1,source_file2,lazy intf,opref2)}
60+
->
61+
Js_implementation.after_parsing_sig ppf source_file1 opref1 intf ;
62+
Js_implementation.after_parsing_impl ppf source_file2 opref2 impl
63+
| exception Not_found -> assert false
64+
)
65+
66+
let build_ast_table ppf files parse_implementation parse_interface =
67+
List.fold_left
68+
(fun (acc : _ Ast_extract.t String_map.t)
69+
source_file ->
70+
match Ocaml_parse.check_suffix source_file with
71+
| `Ml, opref ->
72+
let module_name = module_name_of_file source_file in
73+
begin match String_map.find module_name acc with
74+
| exception Not_found ->
75+
String_map.add module_name
76+
{Ast_extract.ast_info =
77+
(Ml (source_file, parse_implementation
78+
ppf source_file, opref));
79+
module_name ;
80+
} acc
81+
| {ast_info = (Ml (source_file2, _, _)
82+
| Ml_mli(source_file2, _, _,_,_,_))} ->
83+
Bs_exception.error
84+
(Bs_duplicated_module (source_file, source_file2))
85+
| {ast_info = Mli (source_file2, intf, opref2)}
86+
->
87+
String_map.add module_name
88+
{Ast_extract.ast_info =
89+
Ml_mli (source_file,
90+
parse_implementation ppf source_file,
91+
opref,
92+
source_file2,
93+
intf,
94+
opref2
95+
);
96+
module_name} acc
97+
end
98+
| `Mli, opref ->
99+
let module_name = module_name_of_file source_file in
100+
begin match String_map.find module_name acc with
101+
| exception Not_found ->
102+
String_map.add module_name
103+
{Ast_extract.ast_info = (Mli (source_file, parse_interface
104+
ppf source_file, opref));
105+
module_name } acc
106+
| {ast_info =
107+
(Mli (source_file2, _, _) |
108+
Ml_mli(_,_,_,source_file2,_,_)) } ->
109+
Bs_exception.error
110+
(Bs_duplicated_module (source_file, source_file2))
111+
| {ast_info = Ml (source_file2, impl, opref2)}
112+
->
113+
String_map.add module_name
114+
{Ast_extract.ast_info =
115+
Ml_mli
116+
(source_file2,
117+
impl,
118+
opref2,
119+
source_file,
120+
parse_interface ppf source_file,
121+
opref
122+
);
123+
module_name} acc
124+
end
125+
) String_map.empty files
126+
127+
128+
module String_set = Depend.StringSet
129+
130+
131+
let handle_main_file ppf main_file =
132+
let dirname = Filename.dirname main_file in
133+
let files =
134+
Sys.readdir dirname
135+
|> Ext_array.to_list_f
136+
(fun source_file ->
137+
if Ext_string.ends_with source_file ".ml" ||
138+
Ext_string.ends_with source_file ".mli" then
139+
Some (Filename.concat dirname source_file)
140+
else None
141+
) in
142+
let ast_table =
143+
build_ast_table ppf files
144+
Ocaml_parse.lazy_parse_implementation
145+
Ocaml_parse.lazy_parse_interface in
146+
147+
let visited = Hashtbl.create 31 in
148+
let result = Queue.create () in
149+
let next module_name =
150+
match String_map.find module_name ast_table with
151+
| exception _ -> String_set.empty
152+
| {ast_info = Ml (_, lazy impl, _)} ->
153+
Ast_extract.read_parse_and_extract Ml_kind impl
154+
| {ast_info = Mli (_, lazy intf,_)} ->
155+
Ast_extract.read_parse_and_extract Mli_kind intf
156+
| {ast_info = Ml_mli(_,lazy impl, _, _, lazy intf, _)}
157+
->
158+
String_set.union
159+
(Ast_extract.read_parse_and_extract Ml_kind impl)
160+
(Ast_extract.read_parse_and_extract Mli_kind intf)
161+
in
162+
let rec visit visiting path current =
163+
if String_set.mem current visiting then
164+
Bs_exception.error (Bs_cyclic_depends (current::path))
165+
else
166+
if not (Hashtbl.mem visited current)
167+
&& String_map.mem current ast_table then
168+
begin
169+
String_set.iter
170+
(visit
171+
(String_set.add current visiting)
172+
(current::path))
173+
(next current) ;
174+
Queue.push current result;
175+
Hashtbl.add visited current ();
176+
end in
177+
visit (String_set.empty) [] (module_name_of_file main_file) ;
178+
if Js_config.get_diagnose () then
179+
Format.fprintf Format.err_formatter
180+
"Order: @[%a@]@."
181+
(Ext_format.pp_print_queue
182+
~pp_sep:Format.pp_print_space
183+
Format.pp_print_string)
184+
result ;
185+
build_lazy_queue ppf result ast_table;
186+
if not (!Clflags.compile_only) then
187+
Sys.command
188+
("node " ^ Filename.chop_extension main_file ^ ".js")
189+
else 0
190+
191+
let batch_compile ppf files main_file =
192+
Compenv.readenv ppf Before_compile;
193+
Compmisc.init_path false;
27194
if files <> [] then
28-
begin
29-
Compenv.readenv ppf Before_compile;
30-
Compmisc.init_path false;
31-
let batch_files : (string, Ast_extract.ast) Hashtbl.t =
32-
Hashtbl.create 31 in
33-
files |> List.iter begin fun name ->
34-
match Ocaml_parse.check_suffix name with
35-
| `Ml, opref ->
36-
Hashtbl.add batch_files
37-
name
38-
(Ml (Ocaml_parse.parse_implementation ppf name, opref) )
39-
| `Mli, opref ->
40-
Hashtbl.add batch_files name
41-
(Mli (Ocaml_parse.parse_interface ppf name, opref))
195+
begin
196+
let ast_table =
197+
build_ast_table ppf files
198+
Ocaml_parse.parse_implementation
199+
Ocaml_parse.parse_interface in
200+
build_queue ppf (Ast_extract.sort ast_table) ast_table
201+
end
202+
;
203+
if String.length main_file <> 0 then
204+
handle_main_file ppf main_file
205+
else 0
206+
42207

43-
end;
44-
let stack, mapping = Ast_extract.prepare batch_files in
45-
stack |> Queue.iter (fun modname ->
46-
match Hashtbl.find_all mapping modname with
47-
| [] -> ()
48-
| [sourcefile] ->
49-
begin match Hashtbl.find batch_files sourcefile with
50-
| exception _ -> assert false
51-
| Ml (ast,opref)
52-
->
53-
Js_implementation.after_parsing_impl ppf sourcefile
54-
opref ast
55-
| Mli (ast,opref)
56-
->
57-
Js_implementation.after_parsing_sig ppf sourcefile
58-
opref ast
59-
end
60-
| [sourcefile1;sourcefile2]
61-
-> (* TODO: check duplicated names *)
62-
begin match Hashtbl.find batch_files sourcefile1 with
63-
| exception _ -> assert false
64-
| Mli (ast,opref) ->
65-
Js_implementation.after_parsing_sig ppf sourcefile1 opref ast ;
66-
begin match Hashtbl.find batch_files sourcefile2 with
67-
| Ml (ast,opref) ->
68-
Js_implementation.after_parsing_impl ppf sourcefile2
69-
opref ast ;
70-
| _ -> assert false
71-
end
72-
| Ml (ast0,opref0) ->
73-
begin match Hashtbl.find batch_files sourcefile2 with
74-
| Mli (ast,opref) ->
75-
Js_implementation.after_parsing_sig ppf sourcefile2 opref ast ;
76-
Js_implementation.after_parsing_impl ppf sourcefile1
77-
opref0 ast0 ;
78208

79-
| _ -> assert false
80-
end
81-
end
82-
| _ -> assert false
83-
)
84-
end
209+

jscomp/ocaml_batch_compile.mli

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@
2222
* along with this program; if not, write to the Free Software
2323
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
2424

25-
val batch_compile : Format.formatter -> string list -> unit
25+
(** reutrn value is the error code *)
26+
val batch_compile : Format.formatter -> string list -> string -> int

jscomp/ocaml_parse.ml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,18 @@ let parse_interface ppf sourcefile =
2626
let ast = Pparse.parse_interface ~tool_name:Js_config.tool_name ppf sourcefile in
2727
if !Js_config.no_builtin_ppx_mli then ast else !Ppx_entry.rewrite_signature ast
2828

29+
let lazy_parse_interface ppf sourcefile =
30+
lazy (parse_interface ppf sourcefile)
31+
2932
let parse_implementation ppf sourcefile =
3033
let ast =
3134
Pparse.parse_implementation ~tool_name:Js_config.tool_name ppf sourcefile in
3235
if !Js_config.no_builtin_ppx_ml then ast else
3336
!Ppx_entry.rewrite_implementation ast
3437

38+
let lazy_parse_implementation ppf sourcefile =
39+
lazy (parse_implementation ppf sourcefile)
40+
3541
let check_suffix name =
3642
if Filename.check_suffix name ".ml"
3743
|| Filename.check_suffix name ".mlt" then

jscomp/ocaml_parse.mli

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,8 @@ val parse_interface : Format.formatter -> string -> Parsetree.signature
2626

2727
val parse_implementation : Format.formatter -> string -> Parsetree.structure
2828

29+
val lazy_parse_interface : Format.formatter -> string -> Parsetree.signature lazy_t
30+
31+
val lazy_parse_implementation : Format.formatter -> string -> Parsetree.structure lazy_t
32+
2933
val check_suffix : string -> [> `Ml | `Mli ] * string

0 commit comments

Comments
 (0)