Skip to content

Commit 894f3ae

Browse files
committed
specialized argument parsing for the main compiler
1 parent 5b576ea commit 894f3ae

File tree

2 files changed

+337
-148
lines changed

2 files changed

+337
-148
lines changed

jscomp/core/bsc_args.ml

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
(* Copyright (C) 2020- Authors of BuckleScript
2+
*
3+
* This program is free software: you can redistribute it and/or modify
4+
* it under the terms of the GNU Lesser General Public License as published by
5+
* the Free Software Foundation, either version 3 of the License, or
6+
* (at your option) any later version.
7+
*
8+
* In addition to the permissions granted to you by the LGPL, you may combine
9+
* or link a "work that uses the Library" with a publicly distributed version
10+
* of this file to produce a combined library or application, then distribute
11+
* that combined work under the terms of your choosing, with no requirement
12+
* to comply with the obligations normally placed on you by section 4 of the
13+
* LGPL version 3 (or the corresponding section of a later version of the LGPL
14+
* should you choose to use a later version).
15+
*
16+
* This program is distributed in the hope that it will be useful,
17+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
* GNU Lesser General Public License for more details.
20+
*
21+
* You should have received a copy of the GNU Lesser General Public License
22+
* along with this program; if not, write to the Free Software
23+
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *)
24+
25+
26+
27+
28+
type key = string
29+
type doc = string
30+
type anon_fun = rev_args:string list -> unit
31+
32+
type string_action =
33+
| String_call of (string -> unit)
34+
| String_set of string ref
35+
| String_optional_set of string option ref
36+
| String_list_add of string list ref
37+
38+
type unit_action =
39+
| Unit_call of (unit -> unit)
40+
| Unit_lazy of unit lazy_t
41+
| Unit_set of bool ref
42+
| Unit_clear of bool ref
43+
44+
type spec =
45+
| Unit of unit_action
46+
| String of string_action
47+
48+
49+
exception Bsc_bad_arg of string
50+
51+
52+
type error =
53+
| Unknown of string
54+
| Missing of string
55+
56+
type t = (string * spec * string) array
57+
58+
let rec unsafe_loop i (l : t) n x =
59+
if i = n then None
60+
else
61+
let (y1,y2,_) = Array.unsafe_get l i in
62+
if y1 = x then Some y2
63+
else unsafe_loop (i + 1) l n x
64+
65+
let assoc3 (x : string) (l : t) =
66+
let n = Array.length l in
67+
unsafe_loop 0 l n x
68+
;;
69+
70+
71+
let (+>) = Ext_buffer.add_string
72+
73+
let usage_b (buf : Ext_buffer.t) ~usage (speclist : t) =
74+
buf +> usage;
75+
buf +> "\nOptions:\n";
76+
let max_col = ref 0 in
77+
Ext_array.iter speclist (fun (key,_,_) ->
78+
if String.length key > !max_col then
79+
max_col := String.length key
80+
);
81+
Ext_array.iter speclist (fun (key,_,doc) ->
82+
if not (Ext_string.starts_with doc "*internal*") then begin
83+
buf +> " ";
84+
buf +> key ;
85+
buf +> (String.make (!max_col - String.length key + 2 ) ' ');
86+
let cur = ref 0 in
87+
let doc_length = String.length doc in
88+
while !cur < doc_length do
89+
match String.index_from_opt doc !cur '\n' with
90+
| None ->
91+
if !cur <> 0 then begin
92+
buf +> "\n";
93+
buf +> String.make (!max_col + 4) ' ' ;
94+
end;
95+
buf +> String.sub doc !cur (String.length doc - !cur );
96+
cur := doc_length
97+
| Some new_line_pos ->
98+
if !cur <> 0 then begin
99+
buf +> "\n";
100+
buf +> String.make (!max_col + 4) ' ' ;
101+
end;
102+
buf +> String.sub doc !cur (new_line_pos - !cur );
103+
cur := new_line_pos + 1
104+
done ;
105+
buf +> "\n"
106+
end
107+
)
108+
;;
109+
110+
111+
112+
let stop_raise ~usage ~(error : error) (speclist : t ) =
113+
let b = Ext_buffer.create 200 in
114+
begin match error with
115+
| Unknown ("-help" | "--help" | "-h") ->
116+
usage_b b ~usage speclist ;
117+
Ext_buffer.output_buffer stdout b;
118+
exit 0
119+
| Unknown s ->
120+
b +> "unknown option: '";
121+
b +> s ;
122+
b +> "'.\n"
123+
| Missing s ->
124+
b +> "option '";
125+
b +> s;
126+
b +> "' needs an argument.\n"
127+
end;
128+
usage_b b ~usage speclist ;
129+
raise (Bsc_bad_arg (Ext_buffer.contents b))
130+
131+
132+
let parse_exn ~usage ~argv ?(start=1) ?(finish=Array.length argv) (speclist : t)
133+
(anonfun : rev_args:string list -> unit) =
134+
let current = ref start in
135+
let rev_list = ref [] in
136+
while !current < finish do
137+
let s = argv.(!current) in
138+
incr current;
139+
if s <> "" && s.[0] = '-' then begin
140+
match assoc3 s speclist with
141+
| Some action -> begin
142+
begin match action with
143+
| Unit r ->
144+
begin match r with
145+
| Unit_set r -> r := true
146+
| Unit_clear r -> r := false
147+
| Unit_call f -> f ()
148+
| Unit_lazy f -> Lazy.force f
149+
end
150+
| String f ->
151+
if !current >= finish then stop_raise ~usage ~error:(Missing s) speclist
152+
else begin
153+
let arg = argv.(!current) in
154+
incr current;
155+
match f with
156+
| String_call f ->
157+
f arg
158+
| String_set u -> u := arg
159+
| String_optional_set s -> s := Some arg
160+
| String_list_add s -> s := arg :: !s
161+
end
162+
end;
163+
end;
164+
| None -> stop_raise ~usage ~error:(Unknown s) speclist
165+
end else begin
166+
rev_list := s :: !rev_list;
167+
end;
168+
done;
169+
anonfun ~rev_args:!rev_list
170+
;;
171+
172+

0 commit comments

Comments
 (0)