Permalink
Browse files

[CommandLine] Add in a mechanism for adding a name alias for position…

…al arguments, which can then be accessed by name instead of raw idx. Several other cleanups and changes.
  • Loading branch information...
1 parent 9b59086 commit f3db1a18b1e86d21f49bf6b53a0a1d95e5920060 @Whiteknight committed Sep 4, 2012
@@ -28,6 +28,7 @@ class Rosella.CommandLine.ArgumentDef
var raw_defs; // The raw argument definitions from the user
var prepared_defs; // The prepared/processed argument definitions
var aliases; // Map of aliased argument names
+ var pos_aliases; // Map of idx->name for positionals
// Constructor
function ArgumentDef() { }
@@ -42,18 +43,12 @@ class Rosella.CommandLine.ArgumentDef
function get_definition(var args, string arg_name)
{
- :(var arg_defs, var aliases) = self.__get_definitions();
+ :(var arg_defs, var aliases, var pos_aliases) = self.__get_definitions();
+ if (exists aliases[arg_name])
+ arg_name = aliases[arg_name];
if (exists arg_defs[arg_name])
return arg_name, arg_defs[arg_name];
- if (exists aliases[arg_name]) {
- string alias = aliases[arg_name];
- return alias, arg_defs[alias];
- }
- // If we have a parsed arg in the cache, but no def, just assume it
- // was added by some other means.
- if (args != null && exists args[arg_name])
- return arg_name, "s";
Rosella.Error.error("Unknown argument '%s'", arg_name);
}
@@ -66,29 +61,46 @@ class Rosella.CommandLine.ArgumentDef
return sb;
}
+ function get_positional_aliases()
+ {
+ :(var arg_defs, var aliases, var pos_aliases) = self.__get_definitions();
+ return pos_aliases;
+ }
+
// Process the input definitions format into a format suitable to use for
// argument processing.
function __get_definitions()
{
if (self.prepared_defs != null)
- return self.prepared_defs, self.aliases;
+ return self.prepared_defs, self.aliases, self.pos_aliases;
var arg_defs = Rosella.get_string_string_hash();
var aliases = Rosella.get_string_string_hash();
+ var pos_aliases = Rosella.get_int_string_hash();
var raw_defs = self.raw_defs;
- self.__prepare_arg_defs(raw_defs, arg_defs, aliases);
+ self.__prepare_arg_defs(raw_defs, arg_defs, aliases, pos_aliases);
self.prepared_defs = arg_defs;
self.aliases = aliases;
- return arg_defs, aliases;
+ self.pos_aliases = pos_aliases;
+ return arg_defs, aliases, pos_aliases;
}
/* Private Helper Methods
*/
function __verify_arg_type(string arg_name, string arg_type)
{
+ if (arg_type == "[]" || arg_type == "{}")
+ return arg_type, -1;
+
+ int idx = -1;
+ if (length(arg_type) >= 2) {
+ arg_type = substr(arg_type, 0, 1);
+ idx = int(substr(arg_type, 1));
+ }
+
switch (arg_type) {
case "b": // Boolean Flag
case "s": // String
@@ -107,10 +119,10 @@ class Rosella.CommandLine.ArgumentDef
default:
Rosella.Error.error("Unknown argument type for '%s': '%s'", arg_name, arg_type);
}
- return arg_type;
+ return arg_type, idx;
}
- function __prepare_arg_defs(var defs, var arg_defs, var aliases)
+ function __prepare_arg_defs(var defs, var arg_defs, var aliases, var pos_aliases)
{
Rosella.Error.must_subclass(__FUNCTION__);
}
@@ -129,15 +141,17 @@ class Rosella.CommandLine.ArgumentDef.NewStyleHash : Rosella.CommandLine.Argumen
foo|f f|foo|foobar, etc
foo f
foo=s f=s (b, i, f, @ or % too)
+ foo=sX f=sX (s, b, i, f. X = 0, 1, 2, ...)
foo=[] f=[]
foo={} f={}
*/
- function __prepare_arg_defs(var defs, var arg_defs, var aliases)
+ function __prepare_arg_defs(var defs, var arg_defs, var aliases, var pos_aliases)
{
for (string arg_def in defs) {
string arg_name;
string arg_type = "b"; // Default is a boolean flag
+ int arg_idx = -1; // Index for positionals
var raw_aliases = null;
// Separate on the '=' the name(s) from the type
@@ -157,14 +171,17 @@ class Rosella.CommandLine.ArgumentDef.NewStyleHash : Rosella.CommandLine.Argumen
arg_name = arg_def;
// Verify that the type is acceptable
- arg_type = self.__verify_arg_type(arg_name, arg_type);
+ :(arg_type, int idx) = self.__verify_arg_type(arg_name, arg_type);
// Add all aliases to the list of aliases
arg_defs[arg_name] = arg_type;
if (raw_aliases != null) {
for (string alias in raw_aliases)
aliases[alias] = arg_name;
}
+
+ if (idx != -1)
+ pos_aliases[idx] = arg_name;
}
}
@@ -238,7 +255,7 @@ class Rosella.CommandLine.ArgumentDef.OldStyleArray : Rosella.CommandLine.Argume
arg_name = arg_def;
// Verify that the type is acceptable
- arg_type = self.__verify_arg_type(arg_name, arg_type);
+ :(arg_type, int idx) = self.__verify_arg_type(arg_name, arg_type);
// Add all aliases to the list of aliases
arg_defs[arg_name] = arg_type;
@@ -32,6 +32,7 @@ class Rosella.CommandLine.Arguments
var named_cache = {};
string remainders[];
string positionals[] = [];
+ var pos_aliases = arg_defs.get_positional_aliases();
int i = 0;
while (self.__has_more(args, i, lookahead)) {
@@ -70,8 +71,18 @@ class Rosella.CommandLine.Arguments
// A positional arg
else {
+ int idx = elements(positionals);
push(positionals, arg);
- continue;
+
+ // If we have an alias name for this positional, set the arg_name
+ // and push the value back to the lookahead so we can process it
+ // like normal.
+ if (exists pos_aliases[idx]) {
+ arg_name = pos_aliases[idx];
+ unshift(lookahead, arg);
+ }
+ else
+ continue;
}
:(arg_name, string def) = arg_defs.get_definition(null, arg_name);
@@ -138,17 +149,6 @@ class Rosella.CommandLine.Arguments
self.arg_defs = arg_defs;
}
- function alias_positionals(req_pos)
- {
- int num_req = elements(req_pos);
- if (elements(self.pos_cache) < num_req)
- Rosella.Error.error("Expected %d positionals to alias. Have %d instead", num_req, elements(self.pos_cache));
- for (int i = 0; i < elements(req_pos); i++) {
- string name = req_pos[i];
- self.named_cache[name] = self.pos_cache[i];
- }
- }
-
// Get the remaining args
function remainder()
{
@@ -161,6 +161,14 @@ class Rosella.CommandLine.Arguments
return self.raw_args;
}
+ function is_set(string name)
+ {
+ :(name, string def) = self.arg_defs.get_definition(self.named_cache, name);
+ if (exists self.named_cache[name])
+ return true;
+ return false;
+ }
+
/* VTABLEs
*/
@@ -50,6 +50,29 @@ class Rosella.CommandLine.ModeCondition.FlagSet : Rosella.CommandLine.ModeCondit
}
}
+class Rosella.CommandLine.ModeCondition.ScalarExists : Rosella.CommandLine.ModeCondition
+{
+ var scalarname;
+
+ function ScalarExists(string scalarname)
+ {
+ self.scalarname = scalarname;
+ }
+
+ function is_satisfied(var args)
+ {
+ if (args.is_set(self.scalarname))
+ return true;
+ return false;
+ }
+
+ function get_description(var sb)
+ {
+ // TODO: This!
+ }
+}
+
+
// Condition that requires a given scalar-valued flag
class Rosella.CommandLine.ModeCondition.ScalarValue : Rosella.CommandLine.ModeCondition
{
@@ -109,6 +132,7 @@ class Rosella.CommandLine.ModeCondition.GenericFunc : Rosella.CommandLine.ModeCo
}
}
+/*
class Rosella.CommandLine.ModeCondition.RequiredPositionals : Rosella.CommandLine.ModeCondition
{
var required_args;
@@ -140,3 +164,15 @@ class Rosella.CommandLine.ModeCondition.RequiredPositionals : Rosella.CommandLin
push(sb, " ...");
}
}
+*/
+
+class Rosella.CommandLine.ModeCondition.NumPositionals : Rosella.CommandLine.ModeCondition
+{
+ var min_positionals;
+ var max_positionals;
+
+ function NumPositionals(int min, int max)
+ {
+ // TODO: This
+ }
+}
@@ -72,8 +72,6 @@ class Rosella.CommandLine.Program
var mode = self.__find_mode(args);
main_func = mode.main_function();
-
- mode.alias_positionals(args);
} catch (e) {
say(e);
self.try_handle_error(args);
@@ -107,24 +107,15 @@ class Rosella.CommandLine.ProgramMode
return self;
}
- function require_positionals(int can_have_more, var args [slurpy])
+ // Require that a scalar value be provided with any value
+ function require_scalar(string name)
{
- if (self.required_positionals != null)
- Rosella.Error.error("Cannot specify more than one list of required positionals");
if (self.conditions == null)
self.conditions = [];
- var condition = new Rosella.CommandLine.ModeCondition.RequiredPositionals(can_have_more, args);
+ var condition = new Rosella.CommandLine.ModeCondition.ScalarExists(name);
push(self.conditions, condition);
- self.required_positionals = args;
return self;
}
-
- function alias_positionals(var args)
- {
- var req_pos = self.required_positionals;
- if (req_pos != null)
- args.alias_positionals(self.required_positionals);
- }
}
// Default program mode, similar to a normal mode but with no preconditions
View
@@ -23,7 +23,7 @@ namespace Rosella
return h;
}
- function get_integer_string_hash()
+ function get_int_string_hash()
{
var h = int_keyed_hash();
h.set_value_type(DATATYPE_STRING);
View
@@ -360,6 +360,30 @@ class Test_Rosella_CommandLine_Arguments
obj.parse(["-A", "-BC", "-X"], arg_defs);
});
}
+
+ function aliased_positionals()
+ {
+ var arg_defs = create_arg_defs({
+ "A=s" : "A",
+ "B=s0" : "B"
+ });
+
+ // Test that an aliased positional, passed as a positional, can be accessed
+ // by name or idx
+ var obj = create_new();
+ obj.parse(["foo", "-Abar"], arg_defs);
+ self.assert.str_equal(obj["A"], "bar");
+ self.assert.str_equal(obj["B"], "foo");
+ self.assert.str_equal(obj[0], "foo");
+
+ // Next, test that an aliased positional, passed by name, can only be
+ // accessed by name
+ obj = create_new();
+ obj.parse(["-Bfoo", "-Abar"], arg_defs);
+ self.assert.str_equal(obj["A"], "bar");
+ self.assert.str_equal(obj["B"], "foo");
+ self.assert.str_equal(obj[0], "");
+ }
}
function main[main]()
@@ -46,7 +46,12 @@ class Test_Rosella_CommandLine_ProgramMode
self.status.verify("Test Rosella.CommandLine.ProgramMode.main_function()");
var obj = new Rosella.CommandLine.ProgramMode("");
- var result = obj.main_function();
+ // If we haven't set a function, this should throw an exception
+ self.assert.throws(function() {
+ var result = obj.main_function();
+ });
+
+ // TODO: test it when we set a function
}
function require_flag()

0 comments on commit f3db1a1

Please sign in to comment.