syntax: prepare stmts following loops to be unreachable
[nit.git] / lib / opts.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2008 Floréal Morandat <morandat@lirmm.fr>
4 # Copyright 2008 Jean Privat <jean@pryen.org>
5 #
6 # This file is free software, which comes along with NIT. This software is
7 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
9 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
10 # is kept unaltered, and a notification of the changes is added.
11 # You are allowed to redistribute it and sell it, alone or is a part of
12 # another product.
13
14 # Super class of all option's class
15 class Option
16 # Names for the option (including long and short ones)
17 readable var _names: Array[String]
18
19 # Type of the value of the option
20 type VALUE: nullable Object
21
22 # Human readable description of the option
23 readable var _helptext: String
24
25 # Is this option mandatory?
26 readable writable var _mandatory: Bool
27
28 # Current value of this option
29 writable var _value: nullable VALUE
30
31 # Current value of this option
32 fun value: VALUE do return _value.as(VALUE)
33
34 # Default value of this option
35 readable writable var _default_value: nullable VALUE
36
37 # Create a new option
38 init init_opt(help: String, default: nullable VALUE, names: nullable Array[String])
39 do
40 if names == null then
41 _names = new Array[String]
42 else
43 _names = names.to_a
44 end
45 _helptext = help
46 _mandatory = false
47 _default_value = default
48 _value = default
49 end
50
51 # Add new aliases for this option
52 fun add_aliases(names: String...) do _names.add_all(names)
53
54 # An help text for this option with default settings
55 redef fun to_s do return pretty(2)
56
57 # A pretty print for this help
58 fun pretty(off: Int): String
59 do
60 var text = new Buffer.from(" ")
61 text.append(_names.join(", "))
62 text.append(" ")
63 var rest = off - text.length
64 if rest > 0 then text.append(" " * rest)
65 text.append(helptext)
66 #text.append(pretty_default)
67 return text.to_s
68 end
69
70 fun pretty_default: String
71 do
72 if default_value != null then
73 return " ({default_value})"
74 end
75 return ""
76 end
77
78 # Consume parameters for this option
79 protected fun read_param(it: Iterator[String]) is abstract
80 end
81
82 class OptionText
83 special Option
84 init(text: String) do init_opt(text, null, null)
85
86 redef fun pretty(off) do return to_s
87
88 redef fun to_s do return helptext
89 end
90
91 class OptionBool
92 special Option
93 redef type VALUE: Bool
94
95 init(help: String, names: String...) do init_opt(help, false, names)
96
97 redef fun read_param(it) do value = true
98 end
99
100 class OptionCount
101 special Option
102 redef type VALUE: Int
103
104 init(help: String, names: String...) do init_opt(help, 0, names)
105
106 redef fun read_param(it) do value += 1
107 end
108
109 # Option with one mandatory parameter
110 class OptionParameter
111 special Option
112 protected fun convert(str: String): VALUE is abstract
113
114 redef fun read_param(it)
115 do
116 if it.is_ok then
117 value = convert(it.item)
118 it.next
119 else
120 # TODO: What to do?
121 end
122 end
123
124 init init_opt(h, d, n) do super
125 end
126
127 class OptionString
128 special OptionParameter
129 redef type VALUE: nullable String
130
131 init(help: String, names: String...) do init_opt(help, null, names)
132
133 redef fun convert(str) do return str
134 end
135
136 class OptionEnum
137 special OptionParameter
138 redef type VALUE: Int
139 var _enum: Array[String]
140
141 init(enum: Array[String], help: String, default: Int, names: String...)
142 do
143 assert enum.length > 0
144 _enum = enum.to_a
145 init_opt("{help} <{enum.join(", ")}>", default, names)
146 end
147
148 redef fun convert(str)
149 do
150 var id = _enum.index_of(str)
151 return id
152 end
153
154 fun value_name: String = _enum[value]
155
156 redef fun pretty_default
157 do
158 if default_value != null then
159 return " ({_enum[default_value.as(not null)]})"
160 else
161 return ""
162 end
163 end
164 end
165
166 class OptionInt
167 special OptionParameter
168 redef type VALUE: Int
169
170 init(help: String, default: Int, names: String...) do init_opt(help, default, names)
171
172 redef fun convert(str) do return str.to_i
173 end
174
175 class OptionArray
176 special OptionParameter
177 redef type VALUE: Array[String]
178
179 init(help: String, names: String...)
180 do
181 _values = new Array[String]
182 init_opt(help, _values, names)
183 end
184
185 var _values: Array[String]
186 redef fun convert(str)
187 do
188 _values.add(str)
189 return _values
190 end
191 end
192
193 class OptionContext
194 readable var _options: Array[Option]
195 readable var _rest: Array[String]
196
197 var _optmap: Map[String, Option]
198
199 fun usage
200 do
201 var lmax = 1
202 for i in _options do
203 var l = 3
204 for n in i.names do
205 l += n.length + 2
206 end
207 if lmax < l then lmax = l
208 end
209
210 for i in _options do
211 print(i.pretty(lmax))
212 end
213 end
214
215 # Parse ans assign options everywhere is the argument list
216 fun parse(argv: Collection[String])
217 do
218 var it = argv.iterator
219 parse_intern(it)
220 end
221
222 protected fun parse_intern(it: Iterator[String])
223 do
224 var parseargs = true
225 build
226 var rest = _rest
227
228 while parseargs and it.is_ok do
229 var str = it.item
230 if str == "--" then
231 it.next
232 rest.add_all(it.to_a)
233 parseargs = false
234 else
235 if _optmap.has_key(str) then
236 var opt = _optmap[str]
237 it.next
238 opt.read_param(it)
239 else
240 rest.add(it.item)
241 it.next
242 end
243 end
244 end
245 end
246
247 fun add_option(opts: Option...)
248 do
249 for opt in opts do
250 _options.add(opt)
251 end
252 end
253
254 init
255 do
256 _options = new Array[Option]
257 _optmap = new HashMap[String, Option]
258 _rest = new Array[String]
259 end
260
261 private fun build
262 do
263 for o in _options do
264 for n in o.names do
265 _optmap[n] = o
266 end
267 end
268 end
269 end