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 'arg_parser.dart'; |
| 8 import 'arg_results.dart'; |
| 9 import 'option.dart'; |
8 | 10 |
9 final _SOLO_OPT = new RegExp(r'^-([a-zA-Z0-9])$'); | 11 final _SOLO_OPT = new RegExp(r'^-([a-zA-Z0-9])$'); |
10 final _ABBR_OPT = new RegExp(r'^-([a-zA-Z0-9]+)(.*)$'); | 12 final _ABBR_OPT = new RegExp(r'^-([a-zA-Z0-9]+)(.*)$'); |
11 final _LONG_OPT = new RegExp(r'^--([a-zA-Z\-_0-9]+)(=(.*))?$'); | 13 final _LONG_OPT = new RegExp(r'^--([a-zA-Z\-_0-9]+)(=(.*))?$'); |
12 | 14 |
13 /// The actual argument parsing class. | 15 /// The actual argument parsing class. |
14 /// | 16 /// |
15 /// Unlike [ArgParser] which is really more an "arg grammar", this is the class | 17 /// Unlike [ArgParser] which is really more an "arg grammar", this is the class |
16 /// that does the parsing and holds the mutable state required during a parse. | 18 /// that does the parsing and holds the mutable state required during a parse. |
17 class Parser { | 19 class Parser { |
(...skipping 21 matching lines...) Expand all Loading... |
39 if (rest != null) this.rest.addAll(rest); | 41 if (rest != null) this.rest.addAll(rest); |
40 } | 42 } |
41 | 43 |
42 /// The current argument being parsed. | 44 /// The current argument being parsed. |
43 String get current => args[0]; | 45 String get current => args[0]; |
44 | 46 |
45 /// Parses the arguments. This can only be called once. | 47 /// Parses the arguments. This can only be called once. |
46 ArgResults parse() { | 48 ArgResults parse() { |
47 var commandResults = null; | 49 var commandResults = null; |
48 | 50 |
49 // Initialize flags to their defaults. | |
50 grammar.options.forEach((name, option) { | |
51 if (option.allowMultiple) { | |
52 results[name] = []; | |
53 } else { | |
54 results[name] = option.defaultValue; | |
55 } | |
56 }); | |
57 | |
58 // Parse the args. | 51 // Parse the args. |
59 while (args.length > 0) { | 52 while (args.length > 0) { |
60 if (current == '--') { | 53 if (current == '--') { |
61 // Reached the argument terminator, so stop here. | 54 // Reached the argument terminator, so stop here. |
62 args.removeAt(0); | 55 args.removeAt(0); |
63 break; | 56 break; |
64 } | 57 } |
65 | 58 |
66 // Try to parse the current argument as a command. This happens before | 59 // Try to parse the current argument as a command. This happens before |
67 // options so that commands can have option-like names. | 60 // options so that commands can have option-like names. |
(...skipping 14 matching lines...) Expand all Loading... |
82 if (parseSoloOption()) continue; | 75 if (parseSoloOption()) continue; |
83 if (parseAbbreviation(this)) continue; | 76 if (parseAbbreviation(this)) continue; |
84 if (parseLongOption()) continue; | 77 if (parseLongOption()) continue; |
85 | 78 |
86 // This argument is neither option nor command, so stop parsing unless | 79 // This argument is neither option nor command, so stop parsing unless |
87 // the [allowTrailingOptions] option is set. | 80 // the [allowTrailingOptions] option is set. |
88 if (!grammar.allowTrailingOptions) break; | 81 if (!grammar.allowTrailingOptions) break; |
89 rest.add(args.removeAt(0)); | 82 rest.add(args.removeAt(0)); |
90 } | 83 } |
91 | 84 |
92 // Set unspecified multivalued arguments to their default value, | 85 // Invoke the callbacks. |
93 // if any, and invoke the callbacks. | |
94 grammar.options.forEach((name, option) { | 86 grammar.options.forEach((name, option) { |
95 if (option.allowMultiple && | 87 if (option.callback == null) return; |
96 results[name].length == 0 && | 88 option.callback(option.getOrDefault(results[name])); |
97 option.defaultValue != null) { | |
98 results[name].add(option.defaultValue); | |
99 } | |
100 if (option.callback != null) option.callback(results[name]); | |
101 }); | 89 }); |
102 | 90 |
103 // Add in the leftover arguments we didn't parse to the innermost command. | 91 // Add in the leftover arguments we didn't parse to the innermost command. |
104 rest.addAll(args); | 92 rest.addAll(args); |
105 args.clear(); | 93 args.clear(); |
106 return new ArgResults(results, commandName, commandResults, rest); | 94 return newArgResults(grammar, results, commandName, commandResults, rest); |
107 } | 95 } |
108 | 96 |
109 /// Pulls the value for [option] from the second argument in [args]. | 97 /// Pulls the value for [option] from the second argument in [args]. |
110 /// | 98 /// |
111 /// Validates that there is a valid value there. | 99 /// Validates that there is a valid value there. |
112 void readNextArgAsValue(Option option) { | 100 void readNextArgAsValue(Option option) { |
113 // Take the option argument from the next command line arg. | 101 // Take the option argument from the next command line arg. |
114 validate(args.length > 0, | 102 validate(args.length > 0, |
115 'Missing argument for "${option.name}".'); | 103 'Missing argument for "${option.name}".'); |
116 | 104 |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 } | 252 } |
265 | 253 |
266 /// Validates and stores [value] as the value for [option]. | 254 /// Validates and stores [value] as the value for [option]. |
267 void setOption(Map results, Option option, value) { | 255 void setOption(Map results, Option option, value) { |
268 // See if it's one of the allowed values. | 256 // See if it's one of the allowed values. |
269 if (option.allowed != null) { | 257 if (option.allowed != null) { |
270 validate(option.allowed.any((allow) => allow == value), | 258 validate(option.allowed.any((allow) => allow == value), |
271 '"$value" is not an allowed value for option "${option.name}".'); | 259 '"$value" is not an allowed value for option "${option.name}".'); |
272 } | 260 } |
273 | 261 |
274 if (option.allowMultiple) { | 262 if (option.isMultiple) { |
275 results[option.name].add(value); | 263 var list = results.putIfAbsent(option.name, () => []); |
| 264 list.add(value); |
276 } else { | 265 } else { |
277 results[option.name] = value; | 266 results[option.name] = value; |
278 } | 267 } |
279 } | 268 } |
280 } | 269 } |
OLD | NEW |