Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 library fasta.command_line; | |
| 6 | |
| 7 import 'errors.dart' show | |
| 8 inputError, | |
| 9 internalError; | |
| 10 | |
| 11 argumentError(String usage, String message) { | |
| 12 if (usage != null) print(usage); | |
| 13 inputError(null, null, message); | |
| 14 } | |
| 15 | |
| 16 class ParsedArguments { | |
| 17 final Map<String, dynamic> options = <String, dynamic>{}; | |
| 18 final List<String> arguments = <String>[]; | |
| 19 | |
| 20 toString() => "ParsedArguments($options, $arguments)"; | |
| 21 } | |
| 22 | |
| 23 class CommandLine { | |
| 24 final Map<String, dynamic> options; | |
| 25 | |
| 26 final List<String> arguments; | |
| 27 | |
| 28 final String usage; | |
| 29 | |
| 30 CommandLine.parsed(ParsedArguments p, this.usage) | |
| 31 : this.options = p.options, | |
| 32 this.arguments = p.arguments { | |
| 33 validate(); | |
| 34 if (verbose) { | |
| 35 print(p); | |
| 36 } | |
| 37 } | |
| 38 | |
| 39 CommandLine(List<String> arguments, | |
| 40 {Map<String, dynamic> specification, String usage}) | |
| 41 : this.parsed(parse(arguments, specification, usage), usage); | |
| 42 | |
| 43 bool get verbose { | |
| 44 return options.containsKey("-v") || options.containsKey("--verbose"); | |
| 45 } | |
| 46 | |
| 47 /// Override to validate arguments and options. | |
| 48 void validate() { | |
| 49 } | |
| 50 | |
| 51 static ParsedArguments parse(List<String> arguments, | |
|
Johnni Winther
2017/01/16 09:47:46
Add doc, especially for the semantics of [specific
ahe
2017/01/16 12:07:03
Done.
| |
| 52 Map<String, dynamic> specification, String usage) { | |
| 53 specification ??= const <String, dynamic>{}; | |
| 54 ParsedArguments result = new ParsedArguments(); | |
| 55 int index = arguments.indexOf("--"); | |
| 56 Iterable<String> nonOptions = const <String>[]; | |
| 57 Iterator<String> iterator = arguments.iterator; | |
| 58 if (index != -1) { | |
| 59 nonOptions = arguments.skip(index + 1); | |
| 60 iterator = arguments.take(index).iterator; | |
| 61 } | |
| 62 while (iterator.moveNext()) { | |
| 63 String argument = iterator.current; | |
| 64 if (argument.startsWith("-")) { | |
| 65 var valueSpecification = specification[argument]; | |
| 66 String value; | |
| 67 if (valueSpecification != null) { | |
| 68 if (!iterator.moveNext()) { | |
| 69 return argumentError(usage, "Expected value after '$argument'."); | |
| 70 } | |
| 71 value = iterator.current; | |
| 72 } else { | |
| 73 index = argument.indexOf("="); | |
| 74 if (index != -1) { | |
| 75 value = argument.substring(index + 1); | |
| 76 argument = argument.substring(0, index); | |
| 77 valueSpecification = specification[argument]; | |
| 78 } | |
| 79 } | |
| 80 if (valueSpecification == null) { | |
| 81 if (value != null) { | |
| 82 return argumentError(usage, | |
| 83 "Argument '$argument' doesn't take a value: '$value'."); | |
| 84 } | |
| 85 result.options[argument] = true; | |
| 86 } else { | |
| 87 if (valueSpecification is! String && valueSpecification is! Type) { | |
| 88 return argumentError(usage, "Unrecognized type of value " | |
| 89 "specification: ${valueSpecification.runtimeType}."); | |
| 90 } | |
| 91 switch ("$valueSpecification") { | |
| 92 case ",": | |
| 93 result.options.putIfAbsent(argument, () => <String>[]) | |
| 94 .addAll(value.split(",")); | |
| 95 break; | |
| 96 | |
| 97 case "int": | |
| 98 case "bool": | |
| 99 case "String": | |
| 100 case "Uri": | |
| 101 if (result.options.containsKey(argument)) { | |
| 102 return argumentError(usage, "Multiple values for '$argument': " | |
| 103 "'${result.options[argument]}' and '$value'."); | |
| 104 } | |
| 105 var parsedValue; | |
| 106 if (valueSpecification == int) { | |
| 107 parsedValue = int.parse(value, onError: (_) { | |
| 108 return argumentError(usage, | |
| 109 "Value for '$argument', '$value', isn't an int."); | |
| 110 }); | |
| 111 } else if (valueSpecification == bool) { | |
| 112 if (value == "true" || value == "yes") { | |
| 113 parsedValue = true; | |
| 114 } else if (value == "false" || value == "no") { | |
| 115 parsedValue = false; | |
| 116 } else { | |
| 117 return argumentError(usage, | |
| 118 "Value for '$argument' is '$value', " | |
| 119 "but expected one of: 'true', 'false', 'yes', or 'no'."); | |
| 120 } | |
| 121 } else if (valueSpecification == Uri) { | |
| 122 parsedValue = Uri.base.resolve(value); | |
| 123 } else if (valueSpecification == String) { | |
| 124 parsedValue = value; | |
| 125 } else if (valueSpecification is String) { | |
| 126 return argumentError(usage, "Unrecognized value specification: " | |
| 127 "'$valueSpecification', try using a type literal instead."); | |
| 128 } else { | |
| 129 // All possible cases should have been handled above. | |
| 130 return internalError("assertion failure"); | |
| 131 } | |
| 132 result.options[argument] = parsedValue; | |
| 133 break; | |
| 134 | |
| 135 default: | |
| 136 return argumentError(usage, | |
| 137 "Unrecognized value specification: '$valueSpecification'."); | |
| 138 } | |
| 139 } | |
| 140 } else if (argument == "/?" || argument == "/h") { | |
| 141 result.options[argument] = true; | |
| 142 } else { | |
| 143 result.arguments.add(argument); | |
| 144 } | |
| 145 } | |
| 146 result.arguments.addAll(nonOptions); | |
| 147 return result; | |
| 148 } | |
| 149 } | |
| OLD | NEW |