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

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

Issue 12545013: Added the continueParsing option to ArgParser. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Style + commentary. Created 7 years, 8 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 /**
14 * The actual parsing class. Unlike [ArgParser] which is really more an "arg 14 * The actual parsing class. Unlike [ArgParser] which is really more an "arg
15 * 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
16 * state required during a parse. 16 * state required during a parse.
17 *
18 * If [continueParsing] is set, the parser will continue parsing even after it
19 * finds an argument that is not an option. This allows you to specify options
20 * after your command parameters.
17 */ 21 */
18 class Parser { 22 class Parser {
19 /** 23 /**
20 * If parser is parsing a command's options, this will be the name of the 24 * If parser is parsing a command's options, this will be the name of the
21 * command. For top-level results, this returns `null`. 25 * command. For top-level results, this returns `null`.
22 */ 26 */
23 final String commandName; 27 final String commandName;
24 28
25 /** 29 /**
26 * The parser for the supercommand of this command parser, or `null` if this 30 * The parser for the supercommand of this command parser, or `null` if this
27 * is the top-level parser. 31 * is the top-level parser.
28 */ 32 */
29 final Parser parent; 33 final Parser parent;
30 34
35 /** If `true`, parser will continue after it sees a non-option argument. */
36 final boolean continueParsing;
37
31 /** The grammar being parsed. */ 38 /** The grammar being parsed. */
32 final ArgParser grammar; 39 final ArgParser grammar;
33 40
34 /** The arguments being parsed. */ 41 /** The arguments being parsed. */
35 final List<String> args; 42 final List<String> args;
36 43
44 /**
45 * The remaining unparsed arguments.
46 *
47 * This will be passed onto commands so only the last command will use the
48 * arguments.
49 */
50 List<String> rest;
51
37 /** The accumulated parsed options. */ 52 /** The accumulated parsed options. */
38 final Map results = {}; 53 final Map results = {};
39 54
40 Parser(this.commandName, this.grammar, this.args, [this.parent]); 55 Parser(this.commandName, this.grammar, this.args,
56 [this.continueParsing = false, this.parent, rest])
57 : this.rest = rest == null ? [] : rest;
41 58
42 /** The current argument being parsed. */ 59 /** The current argument being parsed. */
43 String get current => args[0]; 60 String get current => args[0];
44 61
45 /** Parses the arguments. This can only be called once. */ 62 /**
63 * Parses the arguments. This can only be called once.
64 */
46 ArgResults parse() { 65 ArgResults parse() {
47 var commandResults = null; 66 var commandResults = null;
48 67
49 // Initialize flags to their defaults. 68 // Initialize flags to their defaults.
50 grammar.options.forEach((name, option) { 69 grammar.options.forEach((name, option) {
51 if (option.allowMultiple) { 70 if (option.allowMultiple) {
52 results[name] = []; 71 results[name] = [];
53 } else { 72 } else {
54 results[name] = option.defaultValue; 73 results[name] = option.defaultValue;
55 } 74 }
56 }); 75 });
57 76
58 // Parse the args. 77 // Parse the args.
59 while (args.length > 0) { 78 while (args.length > 0) {
60 if (current == '--') { 79 if (current == '--') {
61 // Reached the argument terminator, so stop here. 80 // Reached the argument terminator, so stop here.
62 args.removeAt(0); 81 args.removeAt(0);
63 break; 82 break;
64 } 83 }
65 84
66 // Try to parse the current argument as a command. This happens before 85 // Try to parse the current argument as a command. This happens before
67 // options so that commands can have option-like names. 86 // options so that commands can have option-like names.
68 var command = grammar.commands[current]; 87 var command = grammar.commands[current];
69 if (command != null) { 88 if (command != null) {
70 var commandName = args.removeAt(0); 89 var commandName = args.removeAt(0);
71 var commandParser = new Parser(commandName, command, args, this); 90 var commandParser = new Parser(commandName, command, args,
91 continueParsing, this, rest.toList());
72 commandResults = commandParser.parse(); 92 commandResults = commandParser.parse();
73 continue; 93
94 // All remaining arguments were passed to command so clear them here.
95 rest.clear();
96
97 break;
74 } 98 }
75 99
76 // Try to parse the current argument as an option. Note that the order 100 // Try to parse the current argument as an option. Note that the order
77 // here matters. 101 // here matters.
78 if (parseSoloOption()) continue; 102 if (parseSoloOption()) continue;
79 if (parseAbbreviation(this)) continue; 103 if (parseAbbreviation(this)) continue;
80 if (parseLongOption()) continue; 104 if (parseLongOption()) continue;
81 105
82 // If we got here, the argument doesn't look like an option, so stop. 106 if (!continueParsing) {
83 break; 107 // If we got here, the argument doesn't look like an option, so stop.
108 break;
109 } else {
110 rest.add(args.removeAt(0));
111 }
84 } 112 }
85 113
86 // Set unspecified multivalued arguments to their default value, 114 // Set unspecified multivalued arguments to their default value,
87 // if any, and invoke the callbacks. 115 // if any, and invoke the callbacks.
88 grammar.options.forEach((name, option) { 116 grammar.options.forEach((name, option) {
89 if (option.allowMultiple && 117 if (option.allowMultiple &&
90 results[name].length == 0 && 118 results[name].length == 0 &&
91 option.defaultValue != null) { 119 option.defaultValue != null) {
92 results[name].add(option.defaultValue); 120 results[name].add(option.defaultValue);
93 } 121 }
94 if (option.callback != null) option.callback(results[name]); 122 if (option.callback != null) option.callback(results[name]);
95 }); 123 });
96 124
97 // Add in the leftover arguments we didn't parse to the innermost command. 125 // Add in the leftover arguments we didn't parse to the innermost command.
98 var rest = args.toList(); 126 rest.addAll(args.toList());
99 args.clear(); 127 args.clear();
100 return new ArgResults(results, commandName, commandResults, rest); 128 return new ArgResults(results, commandName, commandResults, rest);
101 } 129 }
102 130
103 /** 131 /**
104 * Pulls the value for [option] from the second argument in [args]. Validates 132 * Pulls the value for [option] from the second argument in [args]. Validates
105 * that there is a valid value there. 133 * that there is a valid value there.
106 */ 134 */
107 void readNextArgAsValue(Option option) { 135 void readNextArgAsValue(Option option) {
108 // Take the option argument from the next command line arg. 136 // Take the option argument from the next command line arg.
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
272 '"$value" is not an allowed value for option "${option.name}".'); 300 '"$value" is not an allowed value for option "${option.name}".');
273 } 301 }
274 302
275 if (option.allowMultiple) { 303 if (option.allowMultiple) {
276 results[option.name].add(value); 304 results[option.name].add(value);
277 } else { 305 } else {
278 results[option.name] = value; 306 results[option.name] = value;
279 } 307 }
280 } 308 }
281 } 309 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698