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 'arg_parser.dart'; | 7 import 'arg_parser.dart'; |
8 import 'arg_results.dart'; | 8 import 'arg_results.dart'; |
9 import 'option.dart'; | 9 import 'option.dart'; |
10 | 10 |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 | 85 |
86 // Invoke the callbacks. | 86 // Invoke the callbacks. |
87 grammar.options.forEach((name, option) { | 87 grammar.options.forEach((name, option) { |
88 if (option.callback == null) return; | 88 if (option.callback == null) return; |
89 option.callback(option.getOrDefault(results[name])); | 89 option.callback(option.getOrDefault(results[name])); |
90 }); | 90 }); |
91 | 91 |
92 // Add in the leftover arguments we didn't parse to the innermost command. | 92 // Add in the leftover arguments we didn't parse to the innermost command. |
93 rest.addAll(args); | 93 rest.addAll(args); |
94 args.clear(); | 94 args.clear(); |
95 return newArgResults(grammar, results, commandName, commandResults, rest, | 95 return newArgResults( |
96 arguments); | 96 grammar, results, commandName, commandResults, rest, arguments); |
97 } | 97 } |
98 | 98 |
99 /// Pulls the value for [option] from the second argument in [args]. | 99 /// Pulls the value for [option] from the second argument in [args]. |
100 /// | 100 /// |
101 /// Validates that there is a valid value there. | 101 /// Validates that there is a valid value there. |
102 void readNextArgAsValue(Option option) { | 102 void readNextArgAsValue(Option option) { |
103 // Take the option argument from the next command line arg. | 103 // Take the option argument from the next command line arg. |
104 validate(args.length > 0, | 104 validate(args.length > 0, 'Missing argument for "${option.name}".'); |
105 'Missing argument for "${option.name}".'); | |
106 | 105 |
107 // Make sure it isn't an option itself. | 106 // Make sure it isn't an option itself. |
108 validate(!_ABBR_OPT.hasMatch(current) && !_LONG_OPT.hasMatch(current), | 107 validate(!_ABBR_OPT.hasMatch(current) && !_LONG_OPT.hasMatch(current), |
109 'Missing argument for "${option.name}".'); | 108 'Missing argument for "${option.name}".'); |
110 | 109 |
111 setOption(results, option, current); | 110 setOption(results, option, current); |
112 args.removeAt(0); | 111 args.removeAt(0); |
113 } | 112 } |
114 | 113 |
115 /// Tries to parse the current argument as a "solo" option, which is a single | 114 /// Tries to parse the current argument as a "solo" option, which is a single |
116 /// hyphen followed by a single letter. | 115 /// hyphen followed by a single letter. |
117 /// | 116 /// |
118 /// We treat this differently than collapsed abbreviations (like "-abc") to | 117 /// We treat this differently than collapsed abbreviations (like "-abc") to |
119 /// handle the possible value that may follow it. | 118 /// handle the possible value that may follow it. |
120 bool parseSoloOption() { | 119 bool parseSoloOption() { |
121 var soloOpt = _SOLO_OPT.firstMatch(current); | 120 var soloOpt = _SOLO_OPT.firstMatch(current); |
122 if (soloOpt == null) return false; | 121 if (soloOpt == null) return false; |
123 | 122 |
124 var option = grammar.findByAbbreviation(soloOpt[1]); | 123 var option = grammar.findByAbbreviation(soloOpt[1]); |
125 if (option == null) { | 124 if (option == null) { |
126 // Walk up to the parent command if possible. | 125 // Walk up to the parent command if possible. |
127 validate(parent != null, | 126 validate( |
128 'Could not find an option or flag "-${soloOpt[1]}".'); | 127 parent != null, 'Could not find an option or flag "-${soloOpt[1]}".'); |
129 return parent.parseSoloOption(); | 128 return parent.parseSoloOption(); |
130 } | 129 } |
131 | 130 |
132 args.removeAt(0); | 131 args.removeAt(0); |
133 | 132 |
134 if (option.isFlag) { | 133 if (option.isFlag) { |
135 setOption(results, option, true); | 134 setOption(results, option, true); |
136 } else { | 135 } else { |
137 readNextArgAsValue(option); | 136 readNextArgAsValue(option); |
138 } | 137 } |
139 | 138 |
140 return true; | 139 return true; |
141 } | 140 } |
142 | 141 |
143 /// Tries to parse the current argument as a series of collapsed abbreviations | 142 /// Tries to parse the current argument as a series of collapsed abbreviations |
144 /// (like "-abc") or a single abbreviation with the value directly attached | 143 /// (like "-abc") or a single abbreviation with the value directly attached |
145 /// to it (like "-mrelease"). | 144 /// to it (like "-mrelease"). |
146 bool parseAbbreviation(Parser innermostCommand) { | 145 bool parseAbbreviation(Parser innermostCommand) { |
147 var abbrOpt = _ABBR_OPT.firstMatch(current); | 146 var abbrOpt = _ABBR_OPT.firstMatch(current); |
148 if (abbrOpt == null) return false; | 147 if (abbrOpt == null) return false; |
149 | 148 |
150 // If the first character is the abbreviation for a non-flag option, then | 149 // If the first character is the abbreviation for a non-flag option, then |
151 // the rest is the value. | 150 // the rest is the value. |
152 var c = abbrOpt[1].substring(0, 1); | 151 var c = abbrOpt[1].substring(0, 1); |
153 var first = grammar.findByAbbreviation(c); | 152 var first = grammar.findByAbbreviation(c); |
154 if (first == null) { | 153 if (first == null) { |
155 // Walk up to the parent command if possible. | 154 // Walk up to the parent command if possible. |
156 validate(parent != null, | 155 validate( |
157 'Could not find an option with short name "-$c".'); | 156 parent != null, 'Could not find an option with short name "-$c".'); |
158 return parent.parseAbbreviation(innermostCommand); | 157 return parent.parseAbbreviation(innermostCommand); |
159 } else if (!first.isFlag) { | 158 } else if (!first.isFlag) { |
160 // The first character is a non-flag option, so the rest must be the | 159 // The first character is a non-flag option, so the rest must be the |
161 // value. | 160 // value. |
162 var value = '${abbrOpt[1].substring(1)}${abbrOpt[2]}'; | 161 var value = '${abbrOpt[1].substring(1)}${abbrOpt[2]}'; |
163 setOption(results, first, value); | 162 setOption(results, first, value); |
164 } else { | 163 } else { |
165 // If we got some non-flag characters, then it must be a value, but | 164 // If we got some non-flag characters, then it must be a value, but |
166 // if we got here, it's a flag, which is wrong. | 165 // if we got here, it's a flag, which is wrong. |
167 validate(abbrOpt[2] == '', | 166 validate(abbrOpt[2] == '', |
168 'Option "-$c" is a flag and cannot handle value ' | 167 'Option "-$c" is a flag and cannot handle value ' |
169 '"${abbrOpt[1].substring(1)}${abbrOpt[2]}".'); | 168 '"${abbrOpt[1].substring(1)}${abbrOpt[2]}".'); |
170 | 169 |
171 // Not an option, so all characters should be flags. | 170 // Not an option, so all characters should be flags. |
172 // We use "innermostCommand" here so that if a parent command parses the | 171 // We use "innermostCommand" here so that if a parent command parses the |
173 // *first* letter, subcommands can still be found to parse the other | 172 // *first* letter, subcommands can still be found to parse the other |
174 // letters. | 173 // letters. |
175 for (var i = 0; i < abbrOpt[1].length; i++) { | 174 for (var i = 0; i < abbrOpt[1].length; i++) { |
176 var c = abbrOpt[1].substring(i, i + 1); | 175 var c = abbrOpt[1].substring(i, i + 1); |
177 innermostCommand.parseShortFlag(c); | 176 innermostCommand.parseShortFlag(c); |
178 } | 177 } |
179 } | 178 } |
180 | 179 |
181 args.removeAt(0); | 180 args.removeAt(0); |
182 return true; | 181 return true; |
183 } | 182 } |
184 | 183 |
185 void parseShortFlag(String c) { | 184 void parseShortFlag(String c) { |
186 var option = grammar.findByAbbreviation(c); | 185 var option = grammar.findByAbbreviation(c); |
187 if (option == null) { | 186 if (option == null) { |
188 // Walk up to the parent command if possible. | 187 // Walk up to the parent command if possible. |
189 validate(parent != null, | 188 validate( |
190 'Could not find an option with short name "-$c".'); | 189 parent != null, 'Could not find an option with short name "-$c".'); |
191 parent.parseShortFlag(c); | 190 parent.parseShortFlag(c); |
192 return; | 191 return; |
193 } | 192 } |
194 | 193 |
195 // In a list of short options, only the first can be a non-flag. If | 194 // In a list of short options, only the first can be a non-flag. If |
196 // we get here we've checked that already. | 195 // we get here we've checked that already. |
197 validate(option.isFlag, | 196 validate( |
198 'Option "-$c" must be a flag to be in a collapsed "-".'); | 197 option.isFlag, 'Option "-$c" must be a flag to be in a collapsed "-".'); |
199 | 198 |
200 setOption(results, option, true); | 199 setOption(results, option, true); |
201 } | 200 } |
202 | 201 |
203 /// Tries to parse the current argument as a long-form named option, which | 202 /// Tries to parse the current argument as a long-form named option, which |
204 /// may include a value like "--mode=release" or "--mode release". | 203 /// may include a value like "--mode=release" or "--mode release". |
205 bool parseLongOption() { | 204 bool parseLongOption() { |
206 var longOpt = _LONG_OPT.firstMatch(current); | 205 var longOpt = _LONG_OPT.firstMatch(current); |
207 if (longOpt == null) return false; | 206 if (longOpt == null) return false; |
208 | 207 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
262 } | 261 } |
263 | 262 |
264 if (option.isMultiple) { | 263 if (option.isMultiple) { |
265 var list = results.putIfAbsent(option.name, () => []); | 264 var list = results.putIfAbsent(option.name, () => []); |
266 list.add(value); | 265 list.add(value); |
267 } else { | 266 } else { |
268 results[option.name] = value; | 267 results[option.name] = value; |
269 } | 268 } |
270 } | 269 } |
271 } | 270 } |
OLD | NEW |