Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[CommandLine] Redo Arguments and ArgumentDef to option aliasing and m…

…ore of the argument types supported by GetOpt::Obj. More cleanup and error detection/handling.
  • Loading branch information...
commit fdd62c3bbaead8906a0a7a16a111f0242e4e1315 1 parent f8a619f
awhitworth authored
View
108 src/commandline/ArgumentDef.winxed
@@ -9,10 +9,9 @@ class Rosella.CommandLine.ArgumentDef
// depending on raw_defs format, and adding a factory to choose between
// them
- // TODO: We need to support "foo|f" and "foo|f=X" (where --foo is an alias for -f)
-
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
// Constructor
function ArgumentDef(var raw_defs)
@@ -23,6 +22,18 @@ class Rosella.CommandLine.ArgumentDef
/* Public Methods
*/
+ function get_definition(string arg_name)
+ {
+ :(var arg_defs, var aliases) = self.__get_definitions();
+ 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];
+ }
+ Rosella.Error.error("Unknown argument '%s'", arg_name);
+ }
+
// Get a description or help message. This message will show all argument
// definitions and the description message associated with each
function get_description(var sb = new 'StringBuilder')
@@ -39,21 +50,25 @@ class Rosella.CommandLine.ArgumentDef
// Process the input definitions format into a format suitable to use for
// argument processing.
- function get_definitions()
+ function __get_definitions()
{
if (self.prepared_defs != null)
- return self.prepared_defs;
+ return self.prepared_defs, self.aliases;
var arg_defs = Rosella.get_string_string_hash();
+ var aliases = Rosella.get_string_string_hash();
var raw_defs = self.raw_defs;
+
if (does(raw_defs, "hash"))
- self.__prepare_arg_defs_hash(raw_defs, arg_defs);
+ self.__prepare_arg_defs_hash(raw_defs, arg_defs, aliases);
else if (does(raw_defs, "array"))
- self.__prepare_arg_defs_array(raw_defs, arg_defs);
+ self.__prepare_arg_defs_array(raw_defs, arg_defs, aliases);
else
Rosella.Error.error("Unknown argument definition type '%s'", typeof(raw_defs));
+
self.prepared_defs = arg_defs;
- return arg_defs;
+ self.aliases = aliases;
+ return arg_defs, aliases;
}
/* Private Helper Methods
@@ -96,47 +111,74 @@ class Rosella.CommandLine.ArgumentDef
}
/* We can handle defs of the following types:
+ foo|f f|foo|foobar, etc
foo f
- foo=s f=s
+ foo=s f=s (b, i, f, @ or % too)
foo=[] f=[]
foo={} f={}
*/
// Get a processed definition hash for a new-style hash
- function __prepare_arg_defs_hash(var defs, var arg_defs)
+ function __prepare_arg_defs_hash(var defs, var arg_defs, var aliases)
{
for (string arg_def in defs) {
- var parts = split("=", arg_def);
-
- // Get the name of the argument
- string raw_arg_name = parts[0];
string arg_name;
- if (length(raw_arg_name) == 1)
- arg_name = "-" + raw_arg_name;
- else
- arg_name = "--" + raw_arg_name;
-
- // Now get a flag that tells us how to work with it.
- string flag = "f";
- if (elements(parts) == 2) {
- string second_part = parts[1];
- switch(second_part) {
- case "s":
- case "[]":
- case "{}":
- flag = parts[1];
- break;
- default:
- Rosella.Error.error("Unknown argument type for '%s': '%s'", raw_arg_name, second_part);
- }
+ string arg_type = "b"; // Default is a boolean flag
+ var raw_aliases = null;
+
+ // Separate on the '=' the name(s) from the type
+ int eql_idx = index_of_substr(arg_def, "=");
+ if (eql_idx != -1) {
+ arg_type = substr(arg_def, eql_idx + 1);
+ arg_def = substr(arg_def, 0, eql_idx);
}
- arg_defs[arg_name] = flag;
+ // Different aliases for the same option are separated by '|'.
+ // Get the list of them and take one of them to be the canonical
+ // arg_name.
+ if (index_of_substr(arg_def, "|") != -1) {
+ raw_aliases = split("|", arg_def);
+ arg_name = raw_aliases.pop();
+ } else
+ arg_name = arg_def;
+
+ // Verify that the type is acceptable
+ arg_type = 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;
+ }
}
}
// Get a processed definition hash for an old-style array of arrays
- function __prepare_arg_defs_array(var defs, var arg_defs)
+ function __prepare_arg_defs_array(var defs, var arg_defs, var aliases)
{
// TODO
}
+
+ function __verify_arg_type(string arg_name, string arg_type)
+ {
+ switch (arg_type) {
+ case "b": // Boolean Flag
+ case "s": // String
+ case "i": // Integer
+ case "f": // Float
+ case "[]": // Array
+ case "{}": // Hash
+ // These are OK
+ break;
+ case "@": // Old-style Array
+ arg_type = "[]";
+ break;
+ case "%": // Old-style Hash
+ arg_type = "{}";
+ break;
+ default:
+ Rosella.Error.error("Unknown argument type for '%s': '%s'", arg_name, arg_type);
+ }
+ return arg_type;
+ }
}
View
57 src/commandline/Arguments.winxed
@@ -25,9 +25,8 @@ class Rosella.CommandLine.Arguments
return self.program;
}
- function parse(var args, var arg_defs_obj)
+ function parse(var args, var arg_defs)
{
- var arg_defs = arg_defs_obj.get_definitions();
string lookahead[] = [];
var named_cache = {};
string remainders[];
@@ -52,18 +51,18 @@ class Rosella.CommandLine.Arguments
// An arg of the form "--foo", "--foo bar", "--foo:bar",
// "--foo bar=baz", "--foo:bar=baz"
if (substr(arg, 0, 2) == "--")
- arg_name = arg;
+ arg_name = substr(arg, 2);
// An arg of the form "-X", "-Xfoo", "-X foo", "-f:bar", "-Xfoo=bar",
// "-X foo=bar", "-X:foo=bar" or "-XYZ" (where -X, -Y, -Z are flags)
else if (substr(arg, 0, 1) == "-") {
if (length(arg) > 2) {
- arg_name = substr(arg, 0, 2);
+ arg_name = substr(arg, 1, 1);
string extra = substr(arg, 2);
unshift(lookahead, extra);
has_extra = true;
} else if (length(arg) == 2)
- arg_name = arg;
+ arg_name = substr(arg, 1, 1);
else
Rosella.Error.error("Unknown argument format '%s'", arg);
}
@@ -74,9 +73,9 @@ class Rosella.CommandLine.Arguments
continue;
}
- string def = self.__get_def(arg_name, arg_defs);
+ :(arg_name, string def) = arg_defs.get_definition(arg_name);
switch(def) {
- case "f":
+ case "b":
if (single == false)
Rosella.Error.error("Unexpected scalar value for flag '%s'", arg_name);
named_cache[arg_name] = true;
@@ -93,6 +92,10 @@ class Rosella.CommandLine.Arguments
}
}
break;
+ case "i":
+ Rosella.Error.unimplemented(__FUNCTION__ + " 'i'");
+ case "f":
+ Rosella.Error.unimplemented(__FUNCTION__ + " 'f'");
case "s":
:(arg, i, single) = self.__get_next(args, i, lookahead);
if (single == false)
@@ -126,15 +129,6 @@ class Rosella.CommandLine.Arguments
}
}
- // Loop over the arg_defs, adding false values for any missing flags
- for (string arg_name in arg_defs) {
- string arg_flag = arg_defs[arg_name];
- if (arg_flag == "f") {
- if (!(exists named_cache[arg_name]))
- named_cache[arg_name] = false;
- }
- }
-
// Finally, store values into object fields
self.named_cache = named_cache;
self.pos_cache = positionals;
@@ -159,6 +153,9 @@ class Rosella.CommandLine.Arguments
function get_integer_keyed[vtable](string name)
{
+ :(name, string def) = self.program.arg_defs.get_definition(name);
+ if (def != "b" && def != "i")
+ Rosella.Error.error("Argument '%s' is not an integer or boolean", name);
if (exists self.named_cache[name])
return self.named_cache[name];
return false;
@@ -166,15 +163,27 @@ class Rosella.CommandLine.Arguments
function get_string_keyed[vtable](string name)
{
+ :(name, string def) = self.program.arg_defs.get_definition(name);
+ if (def != "s")
+ Rosella.Error.error("Argument '%s' is not a string", name);
if (exists self.named_cache[name])
- // TODO: Check if it's a string. Lists and hashes shouldn't be
- // accessed like this
return self.named_cache[name];
return "";
}
+ function get_number_keyed[vtable](string name)
+ {
+ :(name, string def) = self.program.arg_defs.get_definition(name);
+ if (def != "f")
+ Rosella.Error.error("Argument '%s' is not a floating point number", name);
+ if (exists self.named_cache[name])
+ return self.named_cache[name];
+ return 0.0;
+ }
+
function get_pmc_keyed[vtable](string name)
{
+ :(name, string def) = self.program.arg_defs.get_definition(name);
if (exists self.named_cache[name])
return self.named_cache[name];
return null;
@@ -197,23 +206,17 @@ class Rosella.CommandLine.Arguments
/* Private Helper Methods
*/
- function __get_def(string name, var defs)
- {
- if (exists defs[name])
- return defs[name];
- Rosella.Error.error("Unknown argument '%s'", name);
- }
-
function __get_next(var args, int i, var lookahead)
{
int single = true;
string arg;
if (elements(lookahead) > 0)
arg = lookahead.shift();
- else {
+ else if (i < elements(args)){
arg = args[i];
i++;
- }
+ } else
+ Rosella.Error.error("Additional arg expected");
int idx = indexof(arg, ":");
if (idx != -1) {
View
2  src/include/Builtins.winxed
@@ -199,6 +199,8 @@ inline repeat_string(string s, int c) return string
return value;
}
+// TODO: The needle/haystack argument ordering of index is opposite for what it
+// is with split. Consider standardizing
inline index_of_substr(string s, string n) return int
{
int value;

0 comments on commit fdd62c3

Please sign in to comment.
Something went wrong with that request. Please try again.