Permalink
Browse files

[CommandLine] Rewrite mode dispatch to use a new ModeCondition object…

…. Remove lots of old crufty code. Several misc cleanups
  • Loading branch information...
1 parent e69e868 commit 0631b953d40efb2666bd7c40f34bd00ab65ec358 @Whiteknight committed Aug 28, 2012
Showing with 96 additions and 127 deletions.
  1. +1 −0 setup.winxed
  2. +62 −0 src/commandline/ModeCondition.winxed
  3. +9 −9 src/commandline/Program.winxed
  4. +24 −118 src/commandline/ProgramMode.winxed
View
@@ -284,6 +284,7 @@ function setup_stable_libraries(var rosella)
setup_winxed_lib(rosella, "commandline", ["Core", "String"],
"commandline/Arguments",
"commandline/ArgumentDef",
+ "commandline/ModeCondition",
"commandline/Program",
"commandline/ProgramMode"
);
@@ -0,0 +1,62 @@
+class Rosella.CommandLine.ModeCondition
+{
+ function is_satisfied(var args)
+ {
+ return false;
+ }
+}
+
+class Rosella.CommandLine.ModeCondition.FlagSet : Rosella.CommandLine.ModeCondition
+{
+ var flagname;
+
+ function FlagSet(string flagname)
+ {
+ self.flagname = flagname;
+ }
+
+ function is_satisfied(var args)
+ {
+ string flagname = string(self.flagname);
+ int value = args[flagname];
+ return value;
+ }
+}
+
+class Rosella.CommandLine.ModeCondition.ScalarValue : Rosella.CommandLine.ModeCondition
+{
+ var name;
+ var value;
+
+ function ScalarValue(string name, string value)
+ {
+ self.name = name;
+ self.value = value;
+ }
+
+ function is_satisfied(var args)
+ {
+ string name = self.name;
+ string expectedvalue = self.value;
+ string actualvalue = args[name];
+ if (expectedvalue == actualvalue)
+ return true;
+ return false;
+ }
+}
+
+class Rosella.CommandLine.ModeCondition.GenericFunc : Rosella.CommandLine.ModeCondition
+{
+ var func;
+
+ function GenericFunc(var f)
+ {
+ self.func = f;
+ }
+
+ function is_satisfied(var args)
+ {
+ var f = self.func;
+ return f(args);
+ }
+}
@@ -18,7 +18,7 @@ class Rosella.CommandLine.Program
function Program(string program_name)
{
self.program_name = program_name;
- self.modes = [];
+ self.modes = {};
self.default_mode = new Rosella.CommandLine.ProgramMode("default");
self.on_error = function(var e) {
say("Error parsing arguments");
@@ -29,7 +29,7 @@ class Rosella.CommandLine.Program
function arguments(var raw_defs)
{
- self.arg_defs = new Rosella.CommandLine.ArgumentDefs(raw_defs);
+ self.arg_defs = new Rosella.CommandLine.ArgumentDef(raw_defs);
}
// Set a function to execute on errors
@@ -42,7 +42,7 @@ class Rosella.CommandLine.Program
function add_mode(string name)
{
var mode = new Rosella.CommandLine.ProgramMode(name);
- push(self.modes, mode);
+ self.modes[name] = mode;
return mode;
}
@@ -55,11 +55,12 @@ class Rosella.CommandLine.Program
// Execute the program with the given args
function run(var raw_args)
{
+ // TODO: Take some optional parameters, such as handles to use for
+ // overriding standard handles, other options.
var args = new Rosella.CommandLine.Arguments(self);
args.parse(raw_args, self.arg_defs);
var mode = self.__find_mode(args);
- mode.fetch_all_args(args);
var main_func = mode.main_function();
if (main_func == null) {
self.try_handle_error(null);
@@ -79,12 +80,12 @@ class Rosella.CommandLine.Program
function __find_mode(var args)
{
- for (var mode in self.modes)
- {
+ for (string modename in self.modes) {
+ var mode = self.modes[modename];
if (mode.can_accept(args))
return mode;
}
- return self.defaule_mode;
+ return self.default_mode;
}
// On error, try to execute the error handler, if any.
@@ -93,11 +94,10 @@ class Rosella.CommandLine.Program
var on_error = self.on_error;
if (on_error == null) {
if (e == null)
- Rosella.Error.invalid(__FUNCTION__, "Invalid parameter combination");
+ Rosella.Error.error("Unknown error during dispatch");
else
throw e;
}
on_error(e);
}
}
-
@@ -15,16 +15,12 @@ class Rosella.CommandLine.ProgramMode
var name; // The name of the mode
var func; // The function to call
- var condition; // The condition that determines if we use this mode
- var required_positionals; // The required positionals
- var required_args; // The required arguments
- var optional_args; // The optional arguments
+ var conditions; // The conditions that determine if we use this mode
// Constructor. Each ProgramMode has a name
function ProgramMode(string name)
{
self.name = name;
- self.required_positionals = {};
}
// Set the main function to call when this mode is activated
@@ -34,137 +30,47 @@ class Rosella.CommandLine.ProgramMode
return self;
}
- // Set a flag that must be present on the commandline for this mode to be
- // selected
- function set_flag(string name)
- {
- self.condition = [name, ""];
- return self;
- }
-
- // Set a name/value pair that must be present for this program mode to be
- // selected
- function set_flag(string name, string value)
- {
- self.condition = [name, value];
- return self;
- }
-
- // Require a positional argument at the given position. All positional
- // arguments must appear before all named and slurpy arguments
- function require_positional(string name, int position)
- {
- self.required_positionals[name] = position;
- return self;
- }
-
- function require_positional(string name)
- {
- self.required_positionals[name] = -1;
- return self;
- }
-
- // Take a hash of arguments and the type of values that they require. This
- // hash represents arguments that must appear on the command-line for this
- // program mode to be satisfied
- function require_args(var args)
- {
- self.required_args = args;
- return self;
- }
-
- // Take a hash of arguments and the value types that they require. This hash
- // represents a series of arguments which are optional and do not need to be
- // provided.
- function optional_args(var args)
- {
- self.optional_args = args;
- return self;
- }
-
// Called by the Program class internally. This function determines if the
// given list of arguments satisfies the list of required arguments for this
// ProgramMode. If so, the mode will be activated and executed
function can_accept(var args)
{
- if (self.condition == null)
+ if (self.conditions == null)
return true;
-
- string c_name = self.condition[0];
- string c_value = self.condition[1];
- if (c_value == "") {
- int have_flag = args.fetch_flag(c_name, 0);
- return have_flag;
- } else {
- string flag_value = args.fetch_scalar(c_name, 0);
- return flag_value == c_value;
+ for (var condition in self.conditions) {
+ if (!condition.is_satisfied(args))
+ return false;
}
+ return true;
}
- // Attempt to match the positionals. If the keep argument is true, the
- // arguments will be parsed completely and values will be extracted.
- // Otherwise, we will just look and not parse. Notice that some subtle
- // errors during parsing may not be found during simple matching.
- function match_positionals(var args, int keep)
+ // Get the main function to dispatch to.
+ function main_function()
{
- for (string key in self.required_positionals) {
- int idx = int(self.required_positionals[key]);
- string arg;
- if (idx < 0)
- arg = args.fetch_positional(key, keep);
- else
- arg = args.fetch_positional(key, keep, idx);
- if (arg == "")
- Rosella.Error.invalid(__FUNCTION__, "Can not find positional argument '%s' (%d)", key, idx);
- }
+ return self.func;
}
- // Attempt to match the named args. If the keep argument is true the
- // arguments will be parsed completely and values will be extracted. Once
- // extracted, we cannot go back and attempt to match other ProgramModes
- function match_args(var args, var arg_defs, int keep)
+ function require_flag(string name)
{
- if (arg_defs == null || elements(arg_defs) == 0)
- return true;
-
- for (string key in arg_defs) {
- string def = arg_defs[key];
-
- if (def == "f")
- args.fetch_flag(key, keep);
- else if (def == "s")
- args.fetch_scalar(key, keep);
- else if (def == "l")
- args.fetch_scalar_list(key, keep);
- else if (def == "p")
- args.fetch_pair(key, keep);
- else if (def == "h")
- args.fetch_pair_hash(key, keep);
- else if (def == "*")
- args.fetch_unparsed(key, keep);
- }
+ if (self.conditions == null)
+ self.conditions = [];
+ var condition = new Rosella.CommandLine.ModeCondition.FlagSet(name);
+ push(self.conditions, condition);
}
- // This ProgramMode has been activated. Fully-parse all arguments and
- // extract values
- function fetch_all_args(var args)
+ function require_value(string name, string value)
{
- if (args == null)
- return;
- if (self.condition != null) {
- string c_name = self.condition[0];
- args.fetch_flag(c_name, 1);
- }
- self.match_args(args, self.required_args, 1);
- self.match_args(args, self.optional_args, 1);
- self.match_positionals(args, 1);
- if (args.has_unparsed_args())
- Rosella.Error.invalid(__FUNCTION__, "Unrecognized arguments: %s", join(" ", args.fetch_unparsed("args", 0)));
+ if (self.conditions == null)
+ self.conditions = [];
+ var condition = new Rosella.CommandLine.ModeCondition.ScalarValue(name, value);
+ push(self.conditions, condition);
}
- // Get the main function to dispatch to.
- function main_function()
+ function require_condition(var f)
{
- return self.func;
+ if (self.conditions == null)
+ self.conditions = [];
+ var condition = new Rosella.CommandLine.ModeCondition.GenericFunc(f);
+ push(self.conditions, condition);
}
}

0 comments on commit 0631b95

Please sign in to comment.