OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library args.src.parser; | 5 library args.src.parser; |
6 | 6 |
7 import '../args.dart'; | 7 import '../args.dart'; |
8 | 8 |
9 final _SOLO_OPT = new RegExp(r'^-([a-zA-Z0-9])$'); | 9 final _SOLO_OPT = new RegExp(r'^-([a-zA-Z0-9])$'); |
10 final _ABBR_OPT = new RegExp(r'^-([a-zA-Z0-9]+)(.*)$'); | 10 final _ABBR_OPT = new RegExp(r'^-([a-zA-Z0-9]+)(.*)$'); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
99 args.clear(); | 99 args.clear(); |
100 return new ArgResults(results, commandName, commandResults, rest); | 100 return new ArgResults(results, commandName, commandResults, rest); |
101 } | 101 } |
102 | 102 |
103 /** | 103 /** |
104 * Pulls the value for [option] from the second argument in [args]. Validates | 104 * Pulls the value for [option] from the second argument in [args]. Validates |
105 * that there is a valid value there. | 105 * that there is a valid value there. |
106 */ | 106 */ |
107 void readNextArgAsValue(Option option) { | 107 void readNextArgAsValue(Option option) { |
108 // Take the option argument from the next command line arg. | 108 // Take the option argument from the next command line arg. |
109 validate(args.length > 0, | 109 validate(args.length > 0, 'Missing argument for "${option.name}".'); |
110 'Missing argument for "${option.name}".'); | |
111 | 110 |
112 // Make sure it isn't an option itself. | 111 // Make sure it isn't an option itself. |
113 validate(!_ABBR_OPT.hasMatch(current) && !_LONG_OPT.hasMatch(current), | 112 validate(!_ABBR_OPT.hasMatch(current) && !_LONG_OPT.hasMatch(current), |
114 'Missing argument for "${option.name}".'); | 113 'Missing argument for "${option.name}".'); |
115 | 114 |
116 setOption(results, option, current); | 115 setOption(results, option, current); |
117 args.removeAt(0); | 116 args.removeAt(0); |
118 } | 117 } |
119 | 118 |
120 /** | 119 /** |
121 * Tries to parse the current argument as a "solo" option, which is a single | 120 * Tries to parse the current argument as a "solo" option, which is a single |
122 * hyphen followed by a single letter. We treat this differently than | 121 * hyphen followed by a single letter. We treat this differently than |
123 * collapsed abbreviations (like "-abc") to handle the possible value that | 122 * collapsed abbreviations (like "-abc") to handle the possible value that |
124 * may follow it. | 123 * may follow it. |
125 */ | 124 */ |
126 bool parseSoloOption() { | 125 bool parseSoloOption() { |
127 var soloOpt = _SOLO_OPT.firstMatch(current); | 126 var soloOpt = _SOLO_OPT.firstMatch(current); |
128 if (soloOpt == null) return false; | 127 if (soloOpt == null) return false; |
129 | 128 |
130 var option = grammar.findByAbbreviation(soloOpt[1]); | 129 var option = grammar.findByAbbreviation(soloOpt[1]); |
131 if (option == null) { | 130 if (option == null) { |
132 // Walk up to the parent command if possible. | 131 // Walk up to the parent command if possible. |
133 validate(parent != null, | 132 validate( |
134 'Could not find an option or flag "-${soloOpt[1]}".'); | 133 parent != null, 'Could not find an option or flag "-${soloOpt[1]}".'); |
135 return parent.parseSoloOption(); | 134 return parent.parseSoloOption(); |
136 } | 135 } |
137 | 136 |
138 args.removeAt(0); | 137 args.removeAt(0); |
139 | 138 |
140 if (option.isFlag) { | 139 if (option.isFlag) { |
141 setOption(results, option, true); | 140 setOption(results, option, true); |
142 } else { | 141 } else { |
143 readNextArgAsValue(option); | 142 readNextArgAsValue(option); |
144 } | 143 } |
145 | 144 |
146 return true; | 145 return true; |
147 } | 146 } |
148 | 147 |
149 /** | 148 /** |
150 * Tries to parse the current argument as a series of collapsed abbreviations | 149 * Tries to parse the current argument as a series of collapsed abbreviations |
151 * (like "-abc") or a single abbreviation with the value directly attached | 150 * (like "-abc") or a single abbreviation with the value directly attached |
152 * to it (like "-mrelease"). | 151 * to it (like "-mrelease"). |
153 */ | 152 */ |
154 bool parseAbbreviation(Parser innermostCommand) { | 153 bool parseAbbreviation(Parser innermostCommand) { |
155 var abbrOpt = _ABBR_OPT.firstMatch(current); | 154 var abbrOpt = _ABBR_OPT.firstMatch(current); |
156 if (abbrOpt == null) return false; | 155 if (abbrOpt == null) return false; |
157 | 156 |
158 // If the first character is the abbreviation for a non-flag option, then | 157 // If the first character is the abbreviation for a non-flag option, then |
159 // the rest is the value. | 158 // the rest is the value. |
160 var c = abbrOpt[1].substring(0, 1); | 159 var c = abbrOpt[1].substring(0, 1); |
161 var first = grammar.findByAbbreviation(c); | 160 var first = grammar.findByAbbreviation(c); |
162 if (first == null) { | 161 if (first == null) { |
163 // Walk up to the parent command if possible. | 162 // Walk up to the parent command if possible. |
164 validate(parent != null, | 163 validate( |
165 'Could not find an option with short name "-$c".'); | 164 parent != null, 'Could not find an option with short name "-$c".'); |
166 return parent.parseAbbreviation(innermostCommand); | 165 return parent.parseAbbreviation(innermostCommand); |
167 } else if (!first.isFlag) { | 166 } else if (!first.isFlag) { |
168 // The first character is a non-flag option, so the rest must be the | 167 // The first character is a non-flag option, so the rest must be the |
169 // value. | 168 // value. |
170 var value = '${abbrOpt[1].substring(1)}${abbrOpt[2]}'; | 169 var value = '${abbrOpt[1].substring(1)}${abbrOpt[2]}'; |
171 setOption(results, first, value); | 170 setOption(results, first, value); |
172 } else { | 171 } else { |
173 // If we got some non-flag characters, then it must be a value, but | 172 // If we got some non-flag characters, then it must be a value, but |
174 // if we got here, it's a flag, which is wrong. | 173 // if we got here, it's a flag, which is wrong. |
175 validate(abbrOpt[2] == '', | 174 validate( |
176 'Option "-$c" is a flag and cannot handle value ' | 175 abbrOpt[2] == '', |
177 '"${abbrOpt[1].substring(1)}${abbrOpt[2]}".'); | 176 'Option "-$c" is a flag and cannot handle value ' |
| 177 '"${abbrOpt[1].substring(1)}${abbrOpt[2]}".'); |
178 | 178 |
179 // Not an option, so all characters should be flags. | 179 // Not an option, so all characters should be flags. |
180 // We use "innermostCommand" here so that if a parent command parses the | 180 // We use "innermostCommand" here so that if a parent command parses the |
181 // *first* letter, subcommands can still be found to parse the other | 181 // *first* letter, subcommands can still be found to parse the other |
182 // letters. | 182 // letters. |
183 for (var i = 0; i < abbrOpt[1].length; i++) { | 183 for (var i = 0; i < abbrOpt[1].length; i++) { |
184 var c = abbrOpt[1].substring(i, i + 1); | 184 var c = abbrOpt[1].substring(i, i + 1); |
185 innermostCommand.parseShortFlag(c); | 185 innermostCommand.parseShortFlag(c); |
186 } | 186 } |
187 } | 187 } |
188 | 188 |
189 args.removeAt(0); | 189 args.removeAt(0); |
190 return true; | 190 return true; |
191 } | 191 } |
192 | 192 |
193 void parseShortFlag(String c) { | 193 void parseShortFlag(String c) { |
194 var option = grammar.findByAbbreviation(c); | 194 var option = grammar.findByAbbreviation(c); |
195 if (option == null) { | 195 if (option == null) { |
196 // Walk up to the parent command if possible. | 196 // Walk up to the parent command if possible. |
197 validate(parent != null, | 197 validate( |
198 'Could not find an option with short name "-$c".'); | 198 parent != null, 'Could not find an option with short name "-$c".'); |
199 parent.parseShortFlag(c); | 199 parent.parseShortFlag(c); |
200 return; | 200 return; |
201 } | 201 } |
202 | 202 |
203 // In a list of short options, only the first can be a non-flag. If | 203 // In a list of short options, only the first can be a non-flag. If |
204 // we get here we've checked that already. | 204 // we get here we've checked that already. |
205 validate(option.isFlag, | 205 validate( |
206 'Option "-$c" must be a flag to be in a collapsed "-".'); | 206 option.isFlag, 'Option "-$c" must be a flag to be in a collapsed "-".'); |
207 | 207 |
208 setOption(results, option, true); | 208 setOption(results, option, true); |
209 } | 209 } |
210 | 210 |
211 /** | 211 /** |
212 * Tries to parse the current argument as a long-form named option, which | 212 * Tries to parse the current argument as a long-form named option, which |
213 * may include a value like "--mode=release" or "--mode release". | 213 * may include a value like "--mode=release" or "--mode release". |
214 */ | 214 */ |
215 bool parseLongOption() { | 215 bool parseLongOption() { |
216 var longOpt = _LONG_OPT.firstMatch(current); | 216 var longOpt = _LONG_OPT.firstMatch(current); |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
272 '"$value" is not an allowed value for option "${option.name}".'); | 272 '"$value" is not an allowed value for option "${option.name}".'); |
273 } | 273 } |
274 | 274 |
275 if (option.allowMultiple) { | 275 if (option.allowMultiple) { |
276 results[option.name].add(value); | 276 results[option.name].add(value); |
277 } else { | 277 } else { |
278 results[option.name] = value; | 278 results[option.name] = value; |
279 } | 279 } |
280 } | 280 } |
281 } | 281 } |
OLD | NEW |