| 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; | |
| 6 | |
| 7 import 'arg_parser.dart'; | 5 import 'arg_parser.dart'; |
| 6 import 'arg_parser_exception.dart'; |
| 8 import 'arg_results.dart'; | 7 import 'arg_results.dart'; |
| 9 import 'option.dart'; | 8 import 'option.dart'; |
| 10 | 9 |
| 11 final _SOLO_OPT = new RegExp(r'^-([a-zA-Z0-9])$'); | 10 final _SOLO_OPT = new RegExp(r'^-([a-zA-Z0-9])$'); |
| 12 final _ABBR_OPT = new RegExp(r'^-([a-zA-Z0-9]+)(.*)$'); | 11 final _ABBR_OPT = new RegExp(r'^-([a-zA-Z0-9]+)(.*)$'); |
| 13 final _LONG_OPT = new RegExp(r'^--([a-zA-Z\-_0-9]+)(=(.*))?$'); | 12 final _LONG_OPT = new RegExp(r'^--([a-zA-Z\-_0-9]+)(=(.*))?$'); |
| 14 | 13 |
| 15 /// The actual argument parsing class. | 14 /// The actual argument parsing class. |
| 16 /// | 15 /// |
| 17 /// Unlike [ArgParser] which is really more an "arg grammar", this is the class | 16 /// Unlike [ArgParser] which is really more an "arg grammar", this is the class |
| (...skipping 12 matching lines...) Expand all Loading... |
| 30 | 29 |
| 31 /// The arguments being parsed. | 30 /// The arguments being parsed. |
| 32 final List<String> args; | 31 final List<String> args; |
| 33 | 32 |
| 34 /// The remaining non-option, non-command arguments. | 33 /// The remaining non-option, non-command arguments. |
| 35 final rest = <String>[]; | 34 final rest = <String>[]; |
| 36 | 35 |
| 37 /// The accumulated parsed options. | 36 /// The accumulated parsed options. |
| 38 final Map<String, dynamic> results = <String, dynamic>{}; | 37 final Map<String, dynamic> results = <String, dynamic>{}; |
| 39 | 38 |
| 40 Parser(this.commandName, this.grammar, this.args, this.parent, rest) { | 39 Parser(this.commandName, this.grammar, this.args, |
| 40 [this.parent, List<String> rest]) { |
| 41 if (rest != null) this.rest.addAll(rest); | 41 if (rest != null) this.rest.addAll(rest); |
| 42 } | 42 } |
| 43 | 43 |
| 44 /// The current argument being parsed. | 44 /// The current argument being parsed. |
| 45 String get current => args[0]; | 45 String get current => args[0]; |
| 46 | 46 |
| 47 /// Parses the arguments. This can only be called once. | 47 /// Parses the arguments. This can only be called once. |
| 48 ArgResults parse() { | 48 ArgResults parse() { |
| 49 var arguments = args.toList(); | 49 var arguments = args.toList(); |
| 50 var commandResults = null; | 50 var commandResults = null; |
| 51 | 51 |
| 52 // Parse the args. | 52 // Parse the args. |
| 53 while (args.length > 0) { | 53 while (args.length > 0) { |
| 54 if (current == '--') { | 54 if (current == '--') { |
| 55 // Reached the argument terminator, so stop here. | 55 // Reached the argument terminator, so stop here. |
| 56 args.removeAt(0); | 56 args.removeAt(0); |
| 57 break; | 57 break; |
| 58 } | 58 } |
| 59 | 59 |
| 60 // Try to parse the current argument as a command. This happens before | 60 // Try to parse the current argument as a command. This happens before |
| 61 // options so that commands can have option-like names. | 61 // options so that commands can have option-like names. |
| 62 var command = grammar.commands[current]; | 62 var command = grammar.commands[current]; |
| 63 if (command != null) { | 63 if (command != null) { |
| 64 validate(rest.isEmpty, 'Cannot specify arguments before a command.'); | 64 validate(rest.isEmpty, 'Cannot specify arguments before a command.'); |
| 65 var commandName = args.removeAt(0); | 65 var commandName = args.removeAt(0); |
| 66 var commandParser = new Parser(commandName, command, args, this, rest); | 66 var commandParser = new Parser(commandName, command, args, this, rest); |
| 67 commandResults = commandParser.parse(); | 67 |
| 68 try { |
| 69 commandResults = commandParser.parse(); |
| 70 } on ArgParserException catch (error) { |
| 71 if (commandName == null) rethrow; |
| 72 throw new ArgParserException( |
| 73 error.message, |
| 74 [commandName]..addAll(error.commands)); |
| 75 } |
| 68 | 76 |
| 69 // All remaining arguments were passed to command so clear them here. | 77 // All remaining arguments were passed to command so clear them here. |
| 70 rest.clear(); | 78 rest.clear(); |
| 71 break; | 79 break; |
| 72 } | 80 } |
| 73 | 81 |
| 74 // Try to parse the current argument as an option. Note that the order | 82 // Try to parse the current argument as an option. Note that the order |
| 75 // here matters. | 83 // here matters. |
| 76 if (parseSoloOption()) continue; | 84 if (parseSoloOption()) continue; |
| 77 if (parseAbbreviation(this)) continue; | 85 if (parseAbbreviation(this)) continue; |
| (...skipping 158 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 // Walk up to the parent command if possible. | 244 // Walk up to the parent command if possible. |
| 237 validate(parent != null, 'Could not find an option named "$name".'); | 245 validate(parent != null, 'Could not find an option named "$name".'); |
| 238 return parent.parseLongOption(); | 246 return parent.parseLongOption(); |
| 239 } | 247 } |
| 240 | 248 |
| 241 return true; | 249 return true; |
| 242 } | 250 } |
| 243 | 251 |
| 244 /// Called during parsing to validate the arguments. | 252 /// Called during parsing to validate the arguments. |
| 245 /// | 253 /// |
| 246 /// Throws a [FormatException] if [condition] is `false`. | 254 /// Throws an [ArgParserException] if [condition] is `false`. |
| 247 void validate(bool condition, String message) { | 255 void validate(bool condition, String message) { |
| 248 if (!condition) throw new FormatException(message); | 256 if (!condition) throw new ArgParserException(message); |
| 249 } | 257 } |
| 250 | 258 |
| 251 /// Validates and stores [value] as the value for [option], which must not be | 259 /// Validates and stores [value] as the value for [option], which must not be |
| 252 /// a flag. | 260 /// a flag. |
| 253 void setOption(Map results, Option option, String value) { | 261 void setOption(Map results, Option option, String value) { |
| 254 assert(!option.isFlag); | 262 assert(!option.isFlag); |
| 255 | 263 |
| 256 if (!option.isMultiple) { | 264 if (!option.isMultiple) { |
| 257 _validateAllowed(option, value); | 265 _validateAllowed(option, value); |
| 258 results[option.name] = value; | 266 results[option.name] = value; |
| 259 return; | 267 return; |
| 260 } | 268 } |
| 261 | 269 |
| 262 var list = results.putIfAbsent(option.name, () => []); | 270 var list = results.putIfAbsent(option.name, () => <String>[]); |
| 263 | 271 |
| 264 if (option.splitCommas) { | 272 if (option.splitCommas) { |
| 265 for (var element in value.split(",")) { | 273 for (var element in value.split(",")) { |
| 266 _validateAllowed(option, element); | 274 _validateAllowed(option, element); |
| 267 list.add(element); | 275 list.add(element); |
| 268 } | 276 } |
| 269 } else { | 277 } else { |
| 270 _validateAllowed(option, value); | 278 _validateAllowed(option, value); |
| 271 list.add(value); | 279 list.add(value); |
| 272 } | 280 } |
| 273 } | 281 } |
| 274 | 282 |
| 275 /// Validates and stores [value] as the value for [option], which must be a | 283 /// Validates and stores [value] as the value for [option], which must be a |
| 276 /// flag. | 284 /// flag. |
| 277 void setFlag(Map results, Option option, bool value) { | 285 void setFlag(Map results, Option option, bool value) { |
| 278 assert(option.isFlag); | 286 assert(option.isFlag); |
| 279 results[option.name] = value; | 287 results[option.name] = value; |
| 280 } | 288 } |
| 281 | 289 |
| 282 /// Validates that [value] is allowed as a value of [option]. | 290 /// Validates that [value] is allowed as a value of [option]. |
| 283 void _validateAllowed(Option option, String value) { | 291 void _validateAllowed(Option option, String value) { |
| 284 if (option.allowed == null) return; | 292 if (option.allowed == null) return; |
| 285 | 293 |
| 286 validate(option.allowed.contains(value), | 294 validate(option.allowed.contains(value), |
| 287 '"$value" is not an allowed value for option "${option.name}".'); | 295 '"$value" is not an allowed value for option "${option.name}".'); |
| 288 } | 296 } |
| 289 } | 297 } |
| OLD | NEW |