Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(367)

Side by Side Diff: pkg/args/lib/src/parser.dart

Issue 271183002: Modernize the docs for args. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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]+)(.*)$');
11 final _LONG_OPT = new RegExp(r'^--([a-zA-Z\-_0-9]+)(=(.*))?$'); 11 final _LONG_OPT = new RegExp(r'^--([a-zA-Z\-_0-9]+)(=(.*))?$');
12 12
13 /** 13 /// The actual parsing class. Unlike [ArgParser] which is really more an "arg
nweiz 2014/05/12 20:15:30 It would be nice to convert this to use single-sen
Bob Nystrom 2014/05/12 21:29:26 Done.
14 * The actual parsing class. Unlike [ArgParser] which is really more an "arg 14 /// grammar", this is the class that does the parsing and holds the mutable
15 * grammar", this is the class that does the parsing and holds the mutable 15 /// state required during a parse.
16 * state required during a parse.
17 */
18 class Parser { 16 class Parser {
19 /** 17 /// If parser is parsing a command's options, this will be the name of the
20 * If parser is parsing a command's options, this will be the name of the 18 /// command. For top-level results, this returns `null`.
21 * command. For top-level results, this returns `null`.
22 */
23 final String commandName; 19 final String commandName;
24 20
25 /** 21 /// The parser for the supercommand of this command parser, or `null` if this
26 * The parser for the supercommand of this command parser, or `null` if this 22 /// is the top-level parser.
27 * is the top-level parser.
28 */
29 final Parser parent; 23 final Parser parent;
30 24
31 /** The grammar being parsed. */ 25 /// The grammar being parsed.
32 final ArgParser grammar; 26 final ArgParser grammar;
33 27
34 /** The arguments being parsed. */ 28 /// The arguments being parsed.
35 final List<String> args; 29 final List<String> args;
36 30
37 /** The remaining non-option, non-command arguments. */ 31 /// The remaining non-option, non-command arguments.
38 final rest = <String>[]; 32 final rest = <String>[];
39 33
40 /** The accumulated parsed options. */ 34 /// The accumulated parsed options.
41 final Map<String, dynamic> results = <String, dynamic>{}; 35 final Map<String, dynamic> results = <String, dynamic>{};
42 36
43 Parser(this.commandName, this.grammar, this.args, this.parent, rest) { 37 Parser(this.commandName, this.grammar, this.args, this.parent, rest) {
44 if (rest != null) this.rest.addAll(rest); 38 if (rest != null) this.rest.addAll(rest);
45 } 39 }
46 40
47 41
48 /** The current argument being parsed. */ 42 /// The current argument being parsed.
49 String get current => args[0]; 43 String get current => args[0];
50 44
51 /** Parses the arguments. This can only be called once. */ 45 /// Parses the arguments. This can only be called once.
52 ArgResults parse() { 46 ArgResults parse() {
53 var commandResults = null; 47 var commandResults = null;
54 48
55 // Initialize flags to their defaults. 49 // Initialize flags to their defaults.
56 grammar.options.forEach((name, option) { 50 grammar.options.forEach((name, option) {
57 if (option.allowMultiple) { 51 if (option.allowMultiple) {
58 results[name] = []; 52 results[name] = [];
59 } else { 53 } else {
60 results[name] = option.defaultValue; 54 results[name] = option.defaultValue;
61 } 55 }
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
105 } 99 }
106 if (option.callback != null) option.callback(results[name]); 100 if (option.callback != null) option.callback(results[name]);
107 }); 101 });
108 102
109 // Add in the leftover arguments we didn't parse to the innermost command. 103 // Add in the leftover arguments we didn't parse to the innermost command.
110 rest.addAll(args); 104 rest.addAll(args);
111 args.clear(); 105 args.clear();
112 return new ArgResults(results, commandName, commandResults, rest); 106 return new ArgResults(results, commandName, commandResults, rest);
113 } 107 }
114 108
115 /** 109 /// Pulls the value for [option] from the second argument in [args]. Validates
116 * Pulls the value for [option] from the second argument in [args]. Validates 110 /// that there is a valid value there.
117 * that there is a valid value there.
118 */
119 void readNextArgAsValue(Option option) { 111 void readNextArgAsValue(Option option) {
120 // Take the option argument from the next command line arg. 112 // Take the option argument from the next command line arg.
121 validate(args.length > 0, 113 validate(args.length > 0,
122 'Missing argument for "${option.name}".'); 114 'Missing argument for "${option.name}".');
123 115
124 // Make sure it isn't an option itself. 116 // Make sure it isn't an option itself.
125 validate(!_ABBR_OPT.hasMatch(current) && !_LONG_OPT.hasMatch(current), 117 validate(!_ABBR_OPT.hasMatch(current) && !_LONG_OPT.hasMatch(current),
126 'Missing argument for "${option.name}".'); 118 'Missing argument for "${option.name}".');
127 119
128 setOption(results, option, current); 120 setOption(results, option, current);
129 args.removeAt(0); 121 args.removeAt(0);
130 } 122 }
131 123
132 /** 124 /// Tries to parse the current argument as a "solo" option, which is a single
133 * Tries to parse the current argument as a "solo" option, which is a single 125 /// hyphen followed by a single letter. We treat this differently than
134 * hyphen followed by a single letter. We treat this differently than 126 /// collapsed abbreviations (like "-abc") to handle the possible value that
135 * collapsed abbreviations (like "-abc") to handle the possible value that 127 /// may follow it.
136 * may follow it.
137 */
138 bool parseSoloOption() { 128 bool parseSoloOption() {
139 var soloOpt = _SOLO_OPT.firstMatch(current); 129 var soloOpt = _SOLO_OPT.firstMatch(current);
140 if (soloOpt == null) return false; 130 if (soloOpt == null) return false;
141 131
142 var option = grammar.findByAbbreviation(soloOpt[1]); 132 var option = grammar.findByAbbreviation(soloOpt[1]);
143 if (option == null) { 133 if (option == null) {
144 // Walk up to the parent command if possible. 134 // Walk up to the parent command if possible.
145 validate(parent != null, 135 validate(parent != null,
146 'Could not find an option or flag "-${soloOpt[1]}".'); 136 'Could not find an option or flag "-${soloOpt[1]}".');
147 return parent.parseSoloOption(); 137 return parent.parseSoloOption();
148 } 138 }
149 139
150 args.removeAt(0); 140 args.removeAt(0);
151 141
152 if (option.isFlag) { 142 if (option.isFlag) {
153 setOption(results, option, true); 143 setOption(results, option, true);
154 } else { 144 } else {
155 readNextArgAsValue(option); 145 readNextArgAsValue(option);
156 } 146 }
157 147
158 return true; 148 return true;
159 } 149 }
160 150
161 /** 151 /// Tries to parse the current argument as a series of collapsed abbreviations
162 * Tries to parse the current argument as a series of collapsed abbreviations 152 /// (like "-abc") or a single abbreviation with the value directly attached
163 * (like "-abc") or a single abbreviation with the value directly attached 153 /// to it (like "-mrelease").
164 * to it (like "-mrelease").
165 */
166 bool parseAbbreviation(Parser innermostCommand) { 154 bool parseAbbreviation(Parser innermostCommand) {
167 var abbrOpt = _ABBR_OPT.firstMatch(current); 155 var abbrOpt = _ABBR_OPT.firstMatch(current);
168 if (abbrOpt == null) return false; 156 if (abbrOpt == null) return false;
169 157
170 // If the first character is the abbreviation for a non-flag option, then 158 // If the first character is the abbreviation for a non-flag option, then
171 // the rest is the value. 159 // the rest is the value.
172 var c = abbrOpt[1].substring(0, 1); 160 var c = abbrOpt[1].substring(0, 1);
173 var first = grammar.findByAbbreviation(c); 161 var first = grammar.findByAbbreviation(c);
174 if (first == null) { 162 if (first == null) {
175 // Walk up to the parent command if possible. 163 // Walk up to the parent command if possible.
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
213 } 201 }
214 202
215 // 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
216 // we get here we've checked that already. 204 // we get here we've checked that already.
217 validate(option.isFlag, 205 validate(option.isFlag,
218 'Option "-$c" must be a flag to be in a collapsed "-".'); 206 'Option "-$c" must be a flag to be in a collapsed "-".');
219 207
220 setOption(results, option, true); 208 setOption(results, option, true);
221 } 209 }
222 210
223 /** 211 /// Tries to parse the current argument as a long-form named option, which
224 * Tries to parse the current argument as a long-form named option, which 212 /// may include a value like "--mode=release" or "--mode release".
225 * may include a value like "--mode=release" or "--mode release".
226 */
227 bool parseLongOption() { 213 bool parseLongOption() {
228 var longOpt = _LONG_OPT.firstMatch(current); 214 var longOpt = _LONG_OPT.firstMatch(current);
229 if (longOpt == null) return false; 215 if (longOpt == null) return false;
230 216
231 var name = longOpt[1]; 217 var name = longOpt[1];
232 var option = grammar.options[name]; 218 var option = grammar.options[name];
233 if (option != null) { 219 if (option != null) {
234 args.removeAt(0); 220 args.removeAt(0);
235 if (option.isFlag) { 221 if (option.isFlag) {
236 validate(longOpt[3] == null, 222 validate(longOpt[3] == null,
(...skipping 24 matching lines...) Expand all
261 setOption(results, option, false); 247 setOption(results, option, false);
262 } else { 248 } else {
263 // Walk up to the parent command if possible. 249 // Walk up to the parent command if possible.
264 validate(parent != null, 'Could not find an option named "$name".'); 250 validate(parent != null, 'Could not find an option named "$name".');
265 return parent.parseLongOption(); 251 return parent.parseLongOption();
266 } 252 }
267 253
268 return true; 254 return true;
269 } 255 }
270 256
271 /** 257 /// Called during parsing to validate the arguments. Throws a
272 * Called during parsing to validate the arguments. Throws a 258 /// [FormatException] if [condition] is `false`.
273 * [FormatException] if [condition] is `false`.
274 */
275 void validate(bool condition, String message) { 259 void validate(bool condition, String message) {
276 if (!condition) throw new FormatException(message); 260 if (!condition) throw new FormatException(message);
277 } 261 }
278 262
279 /** Validates and stores [value] as the value for [option]. */ 263 /// Validates and stores [value] as the value for [option].
280 void setOption(Map results, Option option, value) { 264 void setOption(Map results, Option option, value) {
281 // See if it's one of the allowed values. 265 // See if it's one of the allowed values.
282 if (option.allowed != null) { 266 if (option.allowed != null) {
283 validate(option.allowed.any((allow) => allow == value), 267 validate(option.allowed.any((allow) => allow == value),
284 '"$value" is not an allowed value for option "${option.name}".'); 268 '"$value" is not an allowed value for option "${option.name}".');
285 } 269 }
286 270
287 if (option.allowMultiple) { 271 if (option.allowMultiple) {
288 results[option.name].add(value); 272 results[option.name].add(value);
289 } else { 273 } else {
290 results[option.name] = value; 274 results[option.name] = value;
291 } 275 }
292 } 276 }
293 } 277 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698