Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'commandline_2'

  • Loading branch information...
commit 91d12c8123d7e1726a7ef395baece1f5b857d983 2 parents 2233933 + 98fd0a9
Andrew Whitworth authored
Showing with 1,929 additions and 613 deletions.
  1. +6 −0 setup.winxed
  2. +267 −0 src/commandline/ArgumentDef.winxed
  3. +204 −250 src/commandline/Arguments.winxed
  4. +200 −0 src/commandline/ModeCondition.winxed
  5. +86 −37 src/commandline/Program.winxed
  6. +118 −107 src/commandline/ProgramMode.winxed
  7. +8 −1 src/core/Hash.winxed
  8. +21 −7 src/core/Parrot.winxed
  9. +2 −0  src/include/Builtins.winxed
  10. +95 −0 src/utilities/dump_pbc.winxed
  11. +20 −33 src/utilities/test_all_lib.winxed
  12. +25 −11 src/utilities/test_template.winxed
  13. +50 −0 t/commandline/ArgumentDef.t
  14. +36 −0 t/commandline/ArgumentDef/NewStyleHash.t
  15. +36 −0 t/commandline/ArgumentDef/OldStyleArray.t
  16. +32 −0 t/commandline/ArgumentDef/Rosella.CommandLine.ArgumentDef.t
  17. +311 −102 t/commandline/Arguments.t
  18. +24 −0 t/commandline/ModeCondition.t
  19. +41 −0 t/commandline/ModeCondition/FlagSet.t
  20. +41 −0 t/commandline/ModeCondition/GenericFunc.t
  21. +41 −0 t/commandline/ModeCondition/NumPositionals.t
  22. +41 −0 t/commandline/ModeCondition/ScalarExists.t
  23. +41 −0 t/commandline/ModeCondition/ScalarValue.t
  24. +102 −65 t/commandline/ProgramMode.t
  25. +81 −0 t/commandline/ProgramMode/Default.t
6 setup.winxed
View
@@ -283,6 +283,8 @@ function setup_stable_libraries(var rosella)
// Working with commandline arguments
setup_winxed_lib(rosella, "commandline", ["Core", "String"],
"commandline/Arguments",
+ "commandline/ArgumentDef",
+ "commandline/ModeCondition",
"commandline/Program",
"commandline/ProgramMode"
);
@@ -471,6 +473,10 @@ function setup_utilities(var rosella)
"rosella_doc" : {
"install_name" : "rosella_doc",
"includes" : ["Core", "CommandLine", "FileSystem", "Query", "Reflect"]
+ },
+ "dump_pbc" : {
+ "install_name" : "rosella_dump_pbc",
+ "includes" : ["Core", "FileSystem", "String", "CommandLine", "Query", "Reflect"]
}
};
string src_prefix = "src/utilities/";
267 src/commandline/ArgumentDef.winxed
View
@@ -0,0 +1,267 @@
+namespace Rosella.CommandLine.ArgumentDef
+{
+ function get_argument_definition(var raw_defs)
+ {
+ var arg_defs;
+ if (does(raw_defs, "hash"))
+ arg_defs = new Rosella.CommandLine.ArgumentDef.NewStyleHash();
+ else if (does(raw_defs, "array"))
+ arg_defs = new Rosella.CommandLine.ArgumentDef.OldStyleArray();
+ else
+ Rosella.Error.error("Unknown argument type %s", typeof(raw_defs));
+
+ arg_defs.set_definitions(raw_defs);
+ return arg_defs;
+ }
+}
+
+/* Argument Definitions.
+ Represents the forward declarations of the different arguments. These
+ definitions are used during argument processing to parse out expected
+ arguments.
+*/
+class Rosella.CommandLine.ArgumentDef
+{
+ // TODO: Give a way to slurp up all positionals after position X with a
+ // single alias name.
+
+ 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() { }
+
+ /* Public Methods
+ */
+
+ function set_definitions(var raw_defs)
+ {
+ self.raw_defs = raw_defs;
+ }
+
+ function get_definition(var args, string arg_name)
+ {
+ :(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];
+
+ 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')
+ {
+ self.__get_description_internal(self.raw_defs, sb);
+ 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, 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, pos_aliases);
+
+ self.prepared_defs = arg_defs;
+ self.aliases = 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
+ 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, idx;
+ }
+
+ function __prepare_arg_defs(var defs, var arg_defs, var aliases, var pos_aliases)
+ {
+ Rosella.Error.must_subclass(__FUNCTION__);
+ }
+
+ function __get_description_internal(var sb)
+ {
+ Rosella.Error.must_subclass(__FUNCTION__);
+ }
+}
+
+class Rosella.CommandLine.ArgumentDef.NewStyleHash : Rosella.CommandLine.ArgumentDef
+{
+ function NewStyleHash() { }
+
+ /* We can handle defs of the following types:
+ 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, 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
+ 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);
+ }
+
+ // 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, 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;
+ }
+ }
+
+ function __get_description_internal(var raw_defs, var sb)
+ {
+ int max = 0;
+ var fixed_defs = {};
+ for (string arg in raw_defs) {
+ var parts = split("=", arg);
+ string arg_name = parts[0];
+ string prefix = (length(arg_name) == 1) ? "-" : "--";
+ arg_name = prefix + arg;
+ fixed_defs[arg_name] = raw_defs[arg];
+
+ int len = length(arg_name);
+ if (len > max)
+ max = len;
+ }
+ max += 4;
+
+ for (string arg in fixed_defs) {
+ string desc = fixed_defs[arg];
+ push(sb, " ");
+
+ push(sb, arg);
+ push(sb, repeat_string(" ", max - length(arg)));
+ push(sb, desc);
+ push(sb, "\n");
+ }
+ }
+}
+
+// An array of simple text definitions, like GetOpt::Obj uses
+class Rosella.CommandLine.ArgumentDef.OldStyleArray : Rosella.CommandLine.ArgumentDef
+{
+ function OldStyleArray() { }
+
+ function __get_description_internal(var raw_defs, var sb)
+ {
+ for (int i = 0; i < elements(raw_defs); i++) {
+ string arg = raw_defs[i];
+ push(sb, " ");
+ push(sb, arg);
+ push(sb, "\n");
+ }
+ }
+
+ // Get a processed definition hash for an old-style array of arrays
+ function __prepare_arg_defs(var defs, var arg_defs, var aliases)
+ {
+ for (int i = i; i < elements(defs); i++) {
+ string arg_def = defs[i];
+ string arg_name;
+ 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);
+ }
+
+ // 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, 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;
+ }
+ }
+ }
+}
454 src/commandline/Arguments.winxed
View
@@ -4,309 +4,263 @@
*/
class Rosella.CommandLine.Arguments
{
- var program; // The Program object
- var args; // The list of pre-sorted arguments
- var remainder; // The list of all arguments after -- which are not parsed
- var cache; // The cache of already-parsed args
+ var program; // The Program object
+ var remainder; // The list of all arguments after -- which are not parsed
+ var named_cache; // The cache of already-parsed args
+ var pos_cache; // All positional arguments
+ var raw_args; // The raw argument list
+ var arg_defs; // The ArgumentDef object
// Constructor. Take the list of arguments and do a fast presort on them.
- function Arguments(var program, var args)
+ function Arguments(var program)
{
self.program = program;
- var a = [];
- for (var arg in args)
- push(a, arg);
- self.cache = {};
- self.presort(a);
}
+ /* Public API Functions
+ */
+
// Get the program name
- function program_name()
+ function program()
{
- return self.program.program_name;
+ return self.program;
}
- // Pre-sort the list of arguments to break up compound arguments into a
- // common form. For instance the pattern "--foo=bar" is broken up into
- // "--foo bar". Having all arguments in a common form helps with parsing
- // later.
- function presort(var args)
+ function parse(var args, var arg_defs)
{
- self.remainder = [];
- var sorted = [];
- int do_process = true;
- for (string a in args) {
- if (do_process && length(a) >= 2 && substr(a, 0, 1) == "-" && substr(a, 1, 1) != "-") {
- if (length(a) >= 4 && substr(a, 2, 1) == '=') {
- push(sorted, substr(a, 0, 2));
- push(sorted, substr(a, 3));
- continue;
- }
- for (int i = 1; i < length(a); i++)
- push(sorted, "-" + substr(a, i, 1));
- continue;
- }
- if (do_process && length(a) >= 3 && substr(a, 0, 2) == "--" && substr(a, 2, 1) != "-") {
- int eq_idx = indexof(a, "=");
- if (eq_idx != -1) {
- var parts = split("=", a);
- for (string b in parts)
- push(sorted, b);
- } else
- push(sorted, a);
- continue;
- }
- if (indexof(a, "=") != -1) {
- var parts = split("=", a);
- for (string b in parts)
- push(sorted, b);
- continue;
- }
- if (do_process && length(a) == 2 && a == "--") {
- do_process = false;
- continue;
- }
- if (do_process)
- push(sorted, a);
- else
- push(self.remainder, a);
- }
- self.args = sorted;
- }
+ string lookahead[] = [];
+ var named_cache = {};
+ string remainders[];
+ string positionals[] = [];
+ var pos_aliases = arg_defs.get_positional_aliases();
- // Fetch a flag. A flag is a named argument like "--help" or "-V"
- // which may be specified or not, but does not take a value. Flags are
- // boolean (int)
- function fetch_flag(string name, int keep)
- {
- int found = false;
- for (int i = 0; i < elements(self.args); i++) {
- string a = self.args[i];
- if (a == "")
- continue;
- if (a == name) {
- if (!found) {
- found = true;
- if (keep)
- self.args[i] = "";
- } else
- Rosella.Error.invalid(__FUNCTION__, "Argument '%s' specified more than once", name);
+ int i = 0;
+ while (self.__has_more(args, i, lookahead)) {
+ :(string arg, i, int single) = self.__get_next(args, i, lookahead);
+
+ // All arguments after "--" are not parsed. Add them all to the
+ // remainders list
+ if (arg == "--") {
+ remainders = [];
+ for (; i < elements(args); i++)
+ push(remainders, args[i]);
+ break;
}
- }
- self.cache[name] = found;
- return found;
- }
- // Fetch a scalar value, such as "--foo=bar" or "--foo bar"
- function fetch_scalar(string name, int keep)
- {
- int found = false;
- string value = "";
- for (int i = 0; i < elements(self.args) - 1; i++) {
- string a = self.args[i];
- if (a == "")
- continue;
- if (a == name) {
- if (!found)
- found = true;
+ string arg_name = "";
+ int has_extra = false;
+
+ // An arg of the form "--foo", "--foo bar", "--foo:bar",
+ // "--foo bar=baz", "--foo:bar=baz"
+ if (substr(arg, 0, 2) == "--")
+ 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, 1, 1);
+ string extra = substr(arg, 2);
+ unshift(lookahead, extra);
+ has_extra = true;
+ } else if (length(arg) == 2)
+ arg_name = substr(arg, 1, 1);
else
- Rosella.Error.invalid(__FUNCTION__, "Argument '%s' specified more than once", name);
- value = self.args[i + 1];
- if (keep) {
- self.args[i] = "";
- self.args[i + 1] = "";
- }
- i++;
+ Rosella.Error.error("Unknown argument format '%s'", arg);
}
- }
- self.cache[name] = value;
- return value;
- }
- // Fetch a scalar list such as "--foo=bar --foo=baz", returns all values
- // together in an array
- function fetch_scalar_list(string name, int keep)
- {
- var value = [];
- for (int i = 0; i < elements(self.args) - 1; i++) {
- string a = self.args[i];
- if (a == "")
- continue;
- if (a == name && self.args[i + 1] != "") {
- push(value, self.args[i + 1]);
- if (keep) {
- self.args[i] = "";
- self.args[i + 1] = "";
+ // A positional arg
+ else {
+ int idx = elements(positionals);
+ push(positionals, arg);
+
+ // 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);
}
- i++;
+ else
+ continue;
}
- }
- self.cache[name] = value;
- return value;
- }
- // Fetch a pair such as "--foo=bar=baz" or "--foo bar=baz" or "--foo bar baz"
- // Returns a 1-element hash with the name and the value
- function fetch_pair(string name, int keep)
- {
- int found = false;
- string key = "";
- string value = "";
- for (int i = 0; i < elements(self.args) - 2; i++) {
- string a = self.args[i];
- if (a == "")
- continue;
- if (a == name && self.args[i + 1] != "" && self.args[i + 2] != "") {
- if (!found) {
- found = true;
- key = self.args[i + 1];
- value = self.args[i + 2];
- if (keep) {
- self.args[i] = "";
- self.args[i + 1] = "";
- self.args[i + 2] = "";
+ :(arg_name, string def) = arg_defs.get_definition(null, arg_name);
+ switch(def) {
+ case "b":
+ if (single == false)
+ Rosella.Error.error("Unexpected scalar value for flag '%s'", arg_name);
+ named_cache[arg_name] = true;
+ if (has_extra) {
+ // If we have an arg of the form -xyz, and all of them
+ // are flags, break them apart and set them each
+ // individually -x -y -z
+ :(arg, i, single) = self.__get_next(args, i, lookahead);
+ if (!single)
+ Rosella.Error.error("Unknown syntax for flag '%s'", arg_name);
+ for (int i = 0; i < length(arg); i++) {
+ string extra_arg = substr(arg, i, 1);
+ unshift(lookahead, "-" + extra_arg);
+ }
}
- i += 2;
- } else
- Rosella.Error.invalid(__FUNCTION__, "Argument '%s' specified more than once", name);
+ 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)
+ Rosella.Error.error("Unknown syntax for argument '%s'", arg_name);
+ named_cache[arg_name] = var(arg);
+ break;
+ case "[]":
+ :(arg, i, single) = self.__get_next(args, i, lookahead);
+ if (single == false)
+ Rosella.Error.error("Unexpected pair value for list '%s'", arg_name);
+ if (!(exists named_cache[arg_name]))
+ named_cache[arg_name] = new 'ResizableStringArray';
+ push(named_cache[arg_name], arg);
+ break;
+ case "{}":
+ :(arg, i, single) = self.__get_next(args, i, lookahead);
+ if (single == false)
+ Rosella.Error.error("Unexpected pair value for list '%s'", arg_name);
+ if (!(exists named_cache[arg_name]))
+ named_cache[arg_name] = Rosella.get_string_string_hash();
+ var h = named_cache[arg_name];
+ var parts = split("=", arg);
+ if (elements(parts) != 2)
+ Rosella.Error.error("Unexpected syntax for pair '%s': '%s'", arg_name, arg);
+ string val_name = parts[0];
+ string value = parts[1];
+ h[val_name] = value;
+ break;
+ default:
+ Rosella.Error.error("Unknown argument '%s'", arg_name);
}
}
- var ret = { };
- ret[key] = value;
- self.cache[name] = ret;
- return ret;
+
+ // Finally, store values into object fields
+ self.named_cache = named_cache;
+ self.pos_cache = positionals;
+ self.remainder = remainders;
+ self.raw_args = args;
+ self.arg_defs = arg_defs;
}
- // Fetch all pairs of the form "--foo=bar=baz" or "--foo bar=baz" or
- // "--foo bar baz". Returns them all as a hash
- function fetch_pair_hash(string name, int keep)
+ // Get the remaining args
+ function remainder()
{
- var values = {};
- for (int i = 0; i < elements(self.args) - 2; i++) {
- string a = self.args[i];
- if (a == "")
- continue;
- if (a == name && self.args[i + 1] != "" && self.args[i + 2] != "") {
- string key = self.args[i + 1];
- string value = self.args[i + 2];
- if (keep) {
- self.args[i] = "";
- self.args[i + 1] = "";
- self.args[i + 2] = "";
- }
- values[key] = value;
- i += 2;
- }
- }
- self.cache[name] = values;
- return values;
+ return self.remainder;
}
- // Fetch a list of all remaining args which have not yet been parsed
- function fetch_unparsed(string name, int keep)
+ // Get the raw list of args.
+ function raw_args()
{
- var args = [];
- for (int i = 0; i < elements(self.args); i++) {
- string a = self.args[i];
- if (a == "")
- continue;
- push(args, a);
- if (keep)
- self.args[i] = "";
- }
- self.cache[name] = args;
- return args;
+ return self.raw_args;
}
- // Fetch the first of the remaining arguments, and store it as a string.
- // Does not fetch flags such as -V or --foo
- function fetch_value(string name)
+ function is_set(string name)
{
- string value = "";
- for (int i = 0; i < elements(self.args); i++) {
- string a = self.args[i];
- if (a == "" || (length(a) >= 2 && substr(a, 0, 1) == "-") || (length(a) >= 3 && substr(a, 0, 2) == "--"))
- continue;
- value = a;
- break;
- }
- self.cache[name] = value;
- return value;
+ :(name, string def) = self.arg_defs.get_definition(self.named_cache, name);
+ if (exists self.named_cache[name])
+ return true;
+ return false;
}
- // Fetch a positional argument, which may be a flag or anything else.
- function fetch_positional(string name, int keep, int idx = -1)
+ function get_positionals(int start = -1)
{
- string arg = "";
- if (idx >= 0) {
- if (idx >= elements(self.args)) {
- self.cache[name] = "";
- return "";
- }
- arg = self.args[idx];
- if (keep)
- self.args[idx] = "";
- } else {
- for (int i = 0; i < elements(self.args); i++) {
- string a = self.args[i];
- if (a != "") {
- arg = a;
- if (keep)
- self.args[i] = "";
- break;
- }
- }
- }
- self.cache[name] = arg;
- return arg;
+ if (start == -1)
+ return self.pos_cache;
+ string pos_from[] = [];
+ for (int i = start; i < elements(self.pos_cache); i++)
+ push(pos_from, string(self.pos_cache[i]));
+ return pos_from;
}
- // Get the remaining args
- function remainder()
+ /* VTABLEs
+ */
+
+ function get_integer_keyed[vtable](string name)
{
- return self.remainder;
+ :(name, string def) = self.arg_defs.get_definition(self.named_cache, 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;
}
- // Get the raw list of args. Notice that this list is destroyed during
- // parsing
- function raw_args()
+ function get_string_keyed[vtable](string name)
{
- return self.args;
+ :(name, string def) = self.arg_defs.get_definition(self.named_cache, name);
+ if (def != "s")
+ Rosella.Error.error("Argument '%s' is not a string", name);
+ if (exists self.named_cache[name])
+ return self.named_cache[name];
+ return "";
}
- // Return true if there are arguments remaining which have not been parsed.
- function has_unparsed_args()
+ function get_number_keyed[vtable](string name)
{
- for (int i = 0; i < elements(self.args); i++) {
- string a = self.args[i];
- if (a != "")
- return true;
- }
- return false;
+ :(name, string def) = self.arg_defs.get_definition(self.named_cache, 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_integer_keyed[vtable](string name)
+ function get_pmc_keyed[vtable](string name)
{
- if (exists self.cache[name])
- return self.cache[name];
- return [];
+ :(name, string def) = self.arg_defs.get_definition(self.named_cache, name);
+ if (exists self.named_cache[name])
+ return self.named_cache[name];
+ return null;
}
- // Once parsed, provide keyed access to the cache
- function get_string_keyed[vtable](string name)
+ function get_string_keyed_int[vtable](int idx)
{
- if (exists self.cache[name])
- // TODO: Check if it's a string. Lists and hashes shouldn't be
- // accessed like this
- return self.cache[name];
+ if (elements(self.pos_cache) > idx)
+ return self.pos_cache[idx];
return "";
}
- // Once parsed, provide keyed access to the cache
- function get_pmc_keyed[vtable](string name)
+ function get_pmc_keyed_int[vtable](int idx)
+ {
+ if (elements(self.pos_cache) > idx)
+ return self.pos_cache[idx];
+ return "";
+ }
+
+ /* Private Helper Methods
+ */
+
+ function __get_next(var args, int i, var lookahead)
+ {
+ int single = true;
+ string arg;
+ if (elements(lookahead) > 0)
+ arg = lookahead.shift();
+ else if (i < elements(args)){
+ arg = args[i];
+ i++;
+ } else
+ Rosella.Error.error("Additional arg expected");
+
+ int idx = indexof(arg, ":");
+ if (idx != -1) {
+ var parts = split(":", arg);
+ arg = parts[0];
+ unshift(lookahead, parts[1]);
+ single = false;
+ }
+ return arg, i, single;
+ }
+
+ function __has_more(var args, int i, var lookahead)
{
- if (exists self.cache[name])
- return self.cache[name];
- return [];
+ return elements(lookahead) > 0 || i < elements(args);
}
}
200 src/commandline/ModeCondition.winxed
View
@@ -0,0 +1,200 @@
+/* A condition for a ProgramMode
+ Each ProgramMode besides the default mode may have one or more conditions
+ that must be met before that ProgramMode can be activated. This is the
+ abstract parent class of specialized conditions.
+*/
+class Rosella.CommandLine.ModeCondition
+{
+ // Determine if this condition is satisifed by the given list of parsed
+ // arguments
+ function is_satisfied(var args)
+ {
+ return false;
+ }
+
+ // Get a description of this condition, for use in a help/usage message
+ function get_description(var sb)
+ {
+ }
+
+ function __get_flag_name(string name)
+ {
+ if (length(name) == 1)
+ return "-" + name;
+ return "--" + name;
+ }
+}
+
+// Condition that requires the presence of a given flag
+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;
+ }
+
+ function get_description(var sb)
+ {
+ string flagname = self.flagname;
+ push(sb, " ");
+ push(sb, self.__get_flag_name(flagname));
+ }
+}
+
+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)
+ {
+ string name = self.scalarname;
+ push(sb, " ");
+ push(sb, self.__get_flag_name(name));
+ }
+}
+
+
+// Condition that requires a given scalar-valued flag
+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;
+ }
+
+ function get_description(var sb)
+ {
+ string name = self.name;
+ string value = self.value;
+ push(sb, " ");
+ push(sb, self.__get_flag_name(name));
+ push(sb, "=");
+ push(sb, value);
+ }
+}
+
+// Condition that uses a user-specified predicate function
+class Rosella.CommandLine.ModeCondition.GenericFunc : Rosella.CommandLine.ModeCondition
+{
+ var func;
+ var desc;
+
+ function GenericFunc(var f, string desc)
+ {
+ self.func = f;
+ self.desc = desc;
+ }
+
+ function is_satisfied(var args)
+ {
+ var f = self.func;
+ return f(args);
+ }
+
+ function get_description(var sb)
+ {
+ string desc = self.desc;
+ push(sb, " ");
+ push(sb, desc);
+ }
+}
+
+/*
+class Rosella.CommandLine.ModeCondition.RequiredPositionals : Rosella.CommandLine.ModeCondition
+{
+ var required_args;
+ var can_have_more;
+
+ function RequiredPositionals(int can_have_more, var args)
+ {
+ self.required_args = args;
+ self.can_have_more = can_have_more;
+ }
+
+ function is_satisfied(var args)
+ {
+ if (self.can_have_more) {
+ return elements(args.pos_cache) >= elements(self.required_args);
+ } else {
+ return elements(args.pos_cache) == elements(self.required_args);
+ }
+ }
+
+ function get_description(var sb)
+ {
+ for (string arg in self.required_args) {
+ push(sb, " <");
+ push(sb, arg);
+ push(sb, ">");
+ }
+ if (self.can_have_more)
+ push(sb, " ...");
+ }
+}
+*/
+
+class Rosella.CommandLine.ModeCondition.NumPositionals : Rosella.CommandLine.ModeCondition
+{
+ var min_positionals;
+ var max_positionals;
+
+ function NumPositionals(int min, int max)
+ {
+ self.min_positionals = min;
+ self.max_positionals = max;
+ }
+
+ function is_satisfied(var args)
+ {
+ int min = int(self.min_positionals);
+ int max = int(self.max_positionals);
+ int n = elements(args.pos_cache);
+
+ if (min != -1 && n < min)
+ return false;
+ if (max != -1 && n > max)
+ return false;
+ return true;
+ }
+
+ function get_description(var sb)
+ {
+ // TODO: This!
+ //push(sb, " ...");
+ }
+}
123 src/commandline/Program.winxed
View
@@ -10,33 +10,59 @@ class Rosella.CommandLine.Program
{
var program_name; // The string name of the program
var default_mode; // The default ProgramMode
+ var arg_defs; // Hash of all argument definitions
var on_error; // The error handler callback
var modes; // A hash of named program modes
+ var description; // Program help description
+ var handles; // Standard IO handles to use for program execution
// Constructor
function Program(string program_name)
{
self.program_name = program_name;
- self.modes = [];
- self.default_mode = new Rosella.CommandLine.ProgramMode("default");
- self.on_error = function(var e) {
- say("Error parsing arguments");
- if (e != null)
- say(e.message);
- };
+ self.modes = {};
+ self.default_mode = new Rosella.CommandLine.ProgramMode.Default();
+ }
+
+ /* Public Methods
+ */
+
+ function define_arguments(var raw_defs)
+ {
+ self.arg_defs = Rosella.CommandLine.ArgumentDef.get_argument_definition(raw_defs);
+ return self;
+ }
+
+ function set_description(string desc)
+ {
+ self.description = desc;
+ return self;
+ }
+
+ function set_handles(var stdin, var stdout, var stderr)
+ {
+ var handles = {};
+ if (stdin != null)
+ handles["stdin"] = stdin;
+ if (stdout != null)
+ handles["stdout"] = stdout;
+ if (stderr != null)
+ handles["stderr"] = stderr;
+ self.handles = handles;
}
// Set a function to execute on errors
function on_error(var e)
{
self.on_error = e;
+ return self;
}
// Add a new ProgramMode with the given name
function add_mode(string name)
{
var mode = new Rosella.CommandLine.ProgramMode(name);
- push(self.modes, mode);
+ self.modes[name] = mode;
return mode;
}
@@ -49,28 +75,16 @@ class Rosella.CommandLine.Program
// Execute the program with the given args
function run(var raw_args)
{
- var args = new Rosella.CommandLine.Arguments(self, raw_args);
- var main_func = null;
+ var args = new Rosella.CommandLine.Arguments(self);
+ var main_func;
try {
- for (var mode in self.modes)
- {
- if (mode.can_accept(args)) {
- mode.fetch_all_args(args);
- main_func = mode.main_function();
- break;
- }
- }
- if (main_func == null) {
- main_func = self.default_mode.main_function();
- if (main_func != null)
- self.default_mode.fetch_all_args(args);
- }
+ args.parse(raw_args, self.arg_defs);
+
+ var mode = self.__find_mode(args);
+ main_func = mode.main_function();
} catch (e) {
- self.try_handle_error(e);
- return;
- }
- if (main_func == null) {
- self.try_handle_error(null);
+ say(e);
+ self.try_handle_error(args);
return;
}
@@ -80,22 +94,57 @@ class Rosella.CommandLine.Program
:(int ec [optional], int hec [opt_flag]) = main_func(args);
exit_code = ec;
has_ec = hec;
- });
+ }, self.handles);
if (has_ec)
exit(exit_code);
}
+ function get_usage_text(var sb = new 'StringBuilder')
+ {
+ string name = self.program_name;
+
+ self.default_mode.get_usage(name, sb);
+ for (string modename in self.modes) {
+ var mode = self.modes[modename];
+ mode.get_usage(name, sb);
+ }
+ return sb;
+ }
+
+ function get_help_text()
+ {
+ var sb = new 'StringBuilder';
+ self.get_usage_text(sb);
+ push(sb, "\n");
+ if (self.description != null) {
+ string desc = self.description;
+ push(sb, desc);
+ push(sb, "\n");
+ }
+ push(sb, "\n");
+ return self.arg_defs.get_description(sb);
+ }
+
+ /* Private Methods
+ */
+
+ function __find_mode(var args)
+ {
+ for (string modename in self.modes) {
+ var mode = self.modes[modename];
+ if (mode.can_accept(args))
+ return mode;
+ }
+ return self.default_mode;
+ }
+
// On error, try to execute the error handler, if any.
- function try_handle_error(var e)
+ function try_handle_error(var args)
{
var on_error = self.on_error;
if (on_error == null) {
- if (e == null)
- Rosella.Error.invalid(__FUNCTION__, "Invalid parameter combination");
- else
- throw e;
- }
- on_error(e);
+ say(self.get_usage_text());
+ } else
+ on_error(args);
}
}
-
225 src/commandline/ProgramMode.winxed
View
@@ -5,26 +5,16 @@
*/
class Rosella.CommandLine.ProgramMode
{
- // TODO: Provide an automated help feature where each named argument can
- // take a short description which can be printed
-
- // TODO: Take an integer to use as the default exit code
-
- // TODO: Take a list of handles to use as the interpreter default during
- // execution
-
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
+ var usage; // Usage string for this mode
+ var required_positionals; // Required positionsl
// 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 +24,158 @@ 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)
+ // Set a custom usage message
+ function set_usage(string usage)
{
- self.condition = [name, ""];
+ self.usage = usage;
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)
+ // Get the complete usage message, as a combination of the Program usage
+ // message, usage messages for the different modes, and usage messages
+ // for all argument definitions.
+ function get_usage(string program_name, var sb = new 'StringBuilder')
{
- self.condition = [name, value];
- return self;
+ var usage = self.usage;
+ if (usage != null) {
+ push(sb, " ");
+ push(sb, program_name);
+ push(sb, " ");
+ push(sb, string(usage));
+ push(sb, "\n");
+ }
+ else if (self.conditions != null) {
+ push(sb, " ");
+ push(sb, program_name);
+ for (var condition in self.conditions)
+ condition.get_description(sb);
+ push(sb, " <OPTIONS>\n");
+ }
+ return sb;
+ }
+
+ // 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.conditions == null)
+ return true;
+ for (var condition in self.conditions) {
+ if (!condition.is_satisfied(args))
+ return false;
+ }
+ return true;
}
- // 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)
+ // Get the main function to dispatch to.
+ function main_function()
{
- self.required_positionals[name] = position;
+ var main_func = self.func;
+ if (main_func == null)
+ Rosella.Error.error("Main function for mode %s not set", self.name);
+ return self.func;
+ }
+
+ // Require the existence of a flag
+ function require_flag(string name)
+ {
+ if (self.conditions == null)
+ self.conditions = [];
+ var condition = new Rosella.CommandLine.ModeCondition.FlagSet(name);
+ push(self.conditions, condition);
return self;
}
- function require_positional(string name)
+ // Require a specific scalar value
+ function require_value(string name, string value)
{
- self.required_positionals[name] = -1;
+ if (self.conditions == null)
+ self.conditions = [];
+ var condition = new Rosella.CommandLine.ModeCondition.ScalarValue(name, value);
+ push(self.conditions, condition);
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)
+ // Require a predicate function to return true
+ function require_condition(var f)
{
- self.required_args = args;
+ if (self.conditions == null)
+ self.conditions = [];
+ var condition = new Rosella.CommandLine.ModeCondition.GenericFunc(f);
+ push(self.conditions, condition);
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)
+ // Require that a scalar value be provided with any value
+ function require_scalar(string name)
{
- self.optional_args = args;
+ if (self.conditions == null)
+ self.conditions = [];
+ var condition = new Rosella.CommandLine.ModeCondition.ScalarExists(name);
+ push(self.conditions, condition);
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)
+ // Require that a scalar value be provided with any value
+ function require_positionals(int min, int max = min)
{
- if (self.condition == null)
- return true;
+ if (self.conditions == null)
+ self.conditions = [];
+ var condition = new Rosella.CommandLine.ModeCondition.NumPositionals(min, max);
+ push(self.conditions, condition);
+ return self;
+ }
+}
+
+// Default program mode, similar to a normal mode but with no preconditions
+// and a more generic usage message
+class Rosella.CommandLine.ProgramMode.Default : Rosella.CommandLine.ProgramMode
+{
+ function Default() { self.name = ""; }
- 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;
+ function get_usage(string program_name, var sb = new 'StringBuilder')
+ {
+ var usage = self.usage;
+ if (usage != null) {
+ push(sb, "Usage: ");
+ push(sb, program_name);
+ push(sb, " ");
+ push(sb, string(usage));
+ push(sb, "\n");
+ }
+ else if (self.conditions != null) {
+ push(sb, "Usage: ");
+ push(sb, program_name);
+ for (var condition in self.conditions)
+ condition.get_description(sb);
+ push(sb, " <OPTIONS>\n");
}
+ return sb;
}
- // 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)
- {
- 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);
- }
+ function require_flag(string name)
+ {
+ Rosella.Error.error("May not add prerequisite conditions to the default program mode");
}
- // 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_value(string name, string value)
{
- if (arg_defs == null || elements(arg_defs) == 0)
- return true;
+ Rosella.Error.error("May not add prerequisite conditions to the default program mode");
+ }
- 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);
- }
+ function require_condition(var f)
+ {
+ Rosella.Error.error("May not add prerequisite conditions to the default program mode");
}
- // This ProgramMode has been activated. Fully-parse all arguments and
- // extract values
- function fetch_all_args(var args)
+ function require_positionals(int a, int b = a)
{
- 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)));
+ Rosella.Error.error("May not add prerequisite conditions to the default program mode");
}
- // Get the main function to dispatch to.
- function main_function()
+ function can_accept(var args)
{
- return self.func;
+ return true;
}
}
9 src/core/Hash.winxed
View
@@ -23,10 +23,17 @@ 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);
return h;
}
+
+ function get_string_int_hash()
+ {
+ var h = {};
+ h.set_value_type(DATATYPE_INT);
+ return h;
+ }
}
28 src/core/Parrot.winxed
View
@@ -45,18 +45,32 @@ namespace Rosella.Parrot
}
// Execute a function. Catch any exceptions and print the message and
- // backtrace out to a specified handle. If no handle is specified,
- // use stdout.
- function try_report(var sub, var handle = null)
+ // backtrace out to a specified handle. Swap out the standard handles,
+ // if alternatives are provided. Return whatever values the function
+ // returns
+ function try_report(var sub, var handles = null)
{
- if (handle == null)
- handle = getstdout();
+ var out = null;
+ if (handles != null && exists handles["stderr"])
+ out = handles["stderr"];
+ else
+ out = getstdout();
+ if (handles != null)
+ handles = Rosella.IO.swap_handles(handles);
+
+ var p;
+ var n;
try {
- sub();
+ /*:(p [slurpy], n [slurpy,named]) = */sub();
} catch (e) {
var fmt = Rosella.Parrot.exception_formatter();
- handle.print(fmt.format_default(e));
+ out.print(fmt.format_default(e));
}
+
+ if (handles != null)
+ Rosella.IO.swap_handles(handles);
+
+ /*return p:[flat], n:[flat,named];*/
}
// private routine. Format backtrace information into an array of
2  src/include/Builtins.winxed
View
@@ -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;
95 src/utilities/dump_pbc.winxed
View
@@ -0,0 +1,95 @@
+// Main entry point. Parse arguments and dispatch to the main handler
+function main[main](var args)
+{
+ Rosella.Query.install_to_parrot_types();
+ var p = new Rosella.CommandLine.Program(args.shift());
+ p.define_arguments({
+ "help|h" : "Show help message",
+ "class|c" : "Dump classes",
+ "namespace|n" : "Dump namespaces",
+ "function|f" : "Dump functions (implies -n)",
+ "all|a" : "Dump everything",
+ "quiet|q" : "Print only requested items",
+ "header|e" : "Dump module header"
+ });
+ p.default_mode().set_function(dump_pbc_main);
+ p.add_mode("help").require_flag("h").set_function(usage_and_exit);
+ p.on_error(usage_and_exit);
+ p.run(args);
+}
+
+function usage_and_exit(var args)
+{
+ say(args.program.get_help_text());
+}
+
+function dump_pbc_main(var args)
+{
+ string libpath = args[0];
+ int dump_all = args["all"];
+ int dump_classes = dump_all || int(args["class"]);
+ int dump_namespaces = dump_all || int(args["namespace"]);
+ int dump_functions = dump_all || int(args["function"]);
+ int quiet = int(args["quiet"]); // TODO
+ int dump_header = dump_all || int(args["header"]);
+
+ // We should be able to do something like:
+ // rosella_dump_pbc foo.pbc --quiet --classes | xargs rosella_test_template test lang foo.pbc
+ // rosella_dump_pbc foo.pbc --quiet --ns | xargs rosella_test_template test lang foo.pbc
+
+ var module = Rosella.Reflect.Module.load(libpath);
+
+ if (dump_header) {
+ // TODO: What other info can we put here?
+ Rosella.IO.sayf("%s", module);
+ }
+
+ if (dump_namespaces) {
+ say("Namespaces:");
+ if (dump_functions) {
+ dump_functions = false;
+ module.functions_by_ns()
+ .iterable()
+ .filter(function(kvp) { return elements(kvp.value()) > 0; })
+ .foreach(function(kvp) {
+ string nsname = kvp.key();
+ Rosella.IO.sayf("\t%s", nsname);
+ kvp.value().iterable().foreach(function(sub) {
+ Rosella.IO.sayf("\t\t%s", string(sub));
+ });
+ });
+ } else {
+ module.functions_by_ns()
+ .iterable()
+ .filter(function(kvp) { return elements(kvp.value()) > 0; })
+ .foreach(function(kvp) {
+ var subs = kvp.value();
+ string nsname = kvp.key();
+ Rosella.IO.sayf("\t%s", nsname);
+ });
+ }
+ }
+
+ if (dump_functions) {
+ say("Functions: ");
+ module.functions_by_ns()
+ .iterable()
+ .filter(function(kvp) { return elements(kvp.value()) > 0; })
+ .foreach(function(kvp) {
+ string nsname = kvp.key();
+ kvp.value().iterable().foreach(function(sub) {
+ Rosella.IO.sayf("\t\t%s.%s", nsname, string(sub));
+ });
+ });
+ }
+
+ if (dump_classes) {
+ say("Classes:");
+ module.classes()
+ .iterable()
+ .foreach(function(kvp) {
+ string classname = kvp.key();
+ Rosella.IO.sayf("\t%s", classname);
+ });
+ }
+}
53 src/utilities/test_all_lib.winxed
View
@@ -3,21 +3,32 @@ function main[main](var args)
{
Rosella.Query.install_to_parrot_types();
var p = new Rosella.CommandLine.Program(args.shift());
- p.default_mode().set_function(test_all_main)
- .require_positional("language", 0)
- .require_positional("libpath", 1)
- .require_positional("folder", 2);
- p.add_mode("help").set_flag("--help").set_function(usage_and_exit);
- p.on_error(usage_and_exit);
+ p
+ .define_arguments({
+ "help|h" : "Show the help message",
+ "lang=s0" : "The language to use",
+ "library=s1" : "The library to read",
+ "folder=s2" : "Folder to generate tests in"
+ })
+ .set_description("Create tests for all classes and namespaces in <library>. Output all tests\n" +
+ "to <folder>. Tests will be in language <lang>. <lang> is probably one of\n" +
+ "'winxed' or 'nqp' or others if you have suitable templates installed.");
+ p.default_mode().set_function(function(var a) { say(a.program.get_help_text()); });
+ p.add_mode("test_all")
+ .set_function(test_all_main)
+ .require_positionals(3, 3);
+ p.add_mode("help")
+ .require_flag("help")
+ .set_function(function(var args) { say(p.get_help_text()); });
p.run(args);
}
// Main handler. Pull out the arguments by name and run the program.
function test_all_main(var args)
{
- string libpath = args["libpath"];
- string lang = args["language"];
- string folder = args["folder"];
+ string libpath = args[1];
+ string lang = args[0];
+ string folder = args[2];
var module = Rosella.Reflect.Module.load(libpath);
var engine = new Rosella.Template.Engine();
@@ -53,30 +64,6 @@ function test_all_main(var args)
});
}
-// Help handler. Show usage information on --help or error
-function usage_and_exit(var args)
-{
- if (__DEBUG__ && args instanceof 'Exception') {
- say(args.message);
- for (string bt in args.backtrace_strings())
- say(bt);
- }
- string prog_name;
- if (args == null || args instanceof 'Exception')
- prog_name = "rosella_test_all_lib";
- else
- prog_name = (new Rosella.FileSystem.FilePath(args.program_name())).short_name();
- string fmt = <<:
-Usage: %s <lang> <library> <folder>
-
-Create tests for all classes and namespaces in <library>. Output all tests
-to <folder>. Tests will be in language <lang>. <lang> is probably one of
-'winxed' or 'nqp' or others if you have suitable templates installed.
-:>>
-;
- Rosella.IO.sayf(fmt, prog_name);
-}
-
// Get the Directory object for the given namespace
function get_namespace_directory(var dir, string ns)
{
36 src/utilities/test_template.winxed
View
@@ -5,16 +5,30 @@ function main[main](var args)
{
Rosella.Query.install_to_parrot_types();
var program = new Rosella.CommandLine.Program(args.shift());
- program.add_mode("help").set_flag("--help").set_function(show_help);
- program.add_mode("version").set_flag("--version").set_function(show_version);
- program.add_mode("harness").set_flag("harness").set_function(harness_main)
- .require_positional("language", 1)
- .require_args({ "dirs" : "*" });
- program.add_mode("test").set_flag("test").set_function(test_main)
- .require_positional("language", 1)
- .require_positional("libname", 2)
- .require_positional("classname", 3);
- program.on_error(show_help);
+ program
+ .define_arguments({
+ "help" : "Show the help message",
+ "version" : "Display version information",
+ "harness" : "Generate a test harness",
+ "test" : "Generate test classes",
+ "language=s0" : "Language to use",
+ "libname=s1" : ".pbc library to read",
+ "classname=s3" : "Class to generate tests for"
+ });
+
+ program.add_mode("help").require_flag("help").set_function(show_help);
+ program.add_mode("version").require_flag("version").set_function(show_version);
+
+ program.add_mode("harness")
+ .require_flag("harness")
+ .require_positionals(1)
+ .set_function(harness_main);
+
+ program.add_mode("test")
+ .require_flag("test")
+ .require_positionals(3)
+ .set_function(test_main);
+
program.run(args);
}
@@ -36,7 +50,7 @@ function harness_main(var args)
{
string mode = args["mode"];
string language = args["language"];
- var dirs = args["dirs"];
+ var dirs = args.get_positionals(3);
string template = get_template_text("test_harness", language);
var context = harness_template_context(template, dirs);
var engine = new Rosella.Template.Engine();
50 t/commandline/ArgumentDef.t
View
@@ -0,0 +1,50 @@
+// Automatically generated test for Class Rosella.CommandLine.ArgumentDef
+function create_new(var p_args [slurpy], var n_args [slurpy,named])
+{
+ return new Rosella.CommandLine.ArgumentDef.NewStyleHash(p_args:[flat], n_args:[flat,named]);
+}
+
+class Test_Rosella_CommandLine_ArgumentDef
+{
+ function set_definitions()
+ {
+ self.status.verify("Test Rosella.CommandLine.ArgumentDef.set_definitions()");
+ var obj = create_new();
+
+ var arg_0 = {};
+ var result = obj.set_definitions(arg_0);
+ }
+
+ function get_positional_aliases()
+ {
+ self.status.verify("Test Rosella.CommandLine.ArgumentDef.get_positional_aliases()");
+ var obj = create_new();
+
+ var result = obj.get_positional_aliases();
+ self.assert.equal(elements(result), 0);
+ }
+
+ function get_description()
+ {
+ self.status.verify("Test Rosella.CommandLine.ArgumentDef.get_description()");
+ self.status.unimplemented("Need tests for description generation");
+ var obj = create_new();
+
+ var result = obj.get_description();
+ }
+}
+
+function initialize_test[anon](var context)
+{
+ // Set up the test suite here. Set options on the Suite, set up matchers
+ // in the matcher factory, load prerequisites, and do other things.
+ var(Rosella.load_bytecode_file)("rosella/commandline.pbc", "load");
+}
+
+function main[main]()
+{
+ var core = load_packfile("rosella/core.pbc");
+ var(Rosella.initialize_rosella)("test");
+ using initialize_test;
+ var(Rosella.Test.test)(class Test_Rosella_CommandLine_ArgumentDef, initialize_test:[named("initialize")]);
+}
36 t/commandline/ArgumentDef/NewStyleHash.t
View
@@ -0,0 +1,36 @@
+// Automatically generated test for Class Rosella.CommandLine.ArgumentDef.NewStyleHash
+function create_new(var p_args [slurpy], var n_args [slurpy,named])
+{
+ return new Rosella.CommandLine.ArgumentDef.NewStyleHash(p_args:[flat], n_args:[flat,named]);
+}
+
+class Test_Rosella_CommandLine_ArgumentDef_NewStyleHash
+{
+ function test_sanity()
+ {
+ self.assert.is_true(1);
+ }
+
+ function test_new()
+ {
+ // Test simple constructor. For most individual method tests, use create_new() above
+ var obj = new Rosella.CommandLine.ArgumentDef.NewStyleHash();
+ self.assert.not_null(obj);
+ self.assert.instance_of(obj, class Rosella.CommandLine.ArgumentDef.NewStyleHash);
+ }
+}
+
+function initialize_test[anon](var context)
+{
+ // Set up the test suite here. Set options on the Suite, set up matchers
+ // in the matcher factory, load prerequisites, and do other things.
+ var(Rosella.load_bytecode_file)("rosella/commandline.pbc", "load");
+}
+
+function main[main]()
+{
+ var core = load_packfile("rosella/core.pbc");
+ var(Rosella.initialize_rosella)("test");
+ using initialize_test;
+ var(Rosella.Test.test)(class Test_Rosella_CommandLine_ArgumentDef_NewStyleHash, initialize_test:[named("initialize")]);
+}
36 t/commandline/ArgumentDef/OldStyleArray.t
View
@@ -0,0 +1,36 @@
+// Automatically generated test for Class Rosella.CommandLine.ArgumentDef.OldStyleArray
+function create_new(var p_args [slurpy], var n_args [slurpy,named])
+{
+ return new Rosella.CommandLine.ArgumentDef.OldStyleArray(p_args:[flat], n_args:[flat,named]);
+}
+
+class Test_Rosella_CommandLine_ArgumentDef_OldStyleArray
+{
+ function test_sanity()
+ {
+ self.assert.is_true(1);
+ }
+
+ function test_new()
+ {
+ // Test simple constructor. For most individual method tests, use create_new() above
+ var obj = new Rosella.CommandLine.ArgumentDef.OldStyleArray();
+ self.assert.not_null(obj);
+ self.assert.instance_of(obj, class Rosella.CommandLine.ArgumentDef.OldStyleArray);
+ }
+}
+
+function initialize_test[anon](var context)
+{
+ // Set up the test suite here. Set options on the Suite, set up matchers
+ // in the matcher factory, load prerequisites, and do other things.
+ var(Rosella.load_bytecode_file)("rosella/commandline.pbc", "load");
+}
+
+function main[main]()
+{
+ var core = load_packfile("rosella/core.pbc");
+ var(Rosella.initialize_rosella)("test");
+ using initialize_test;
+ var(Rosella.Test.test)(class Test_Rosella_CommandLine_ArgumentDef_OldStyleArray, initialize_test:[named("initialize")]);
+}
32 t/commandline/ArgumentDef/Rosella.CommandLine.ArgumentDef.t
View
@@ -0,0 +1,32 @@
+// Automatically generated test for NameSpace Rosella.CommandLine.ArgumentDef
+class Test_Rosella_CommandLine_ArgumentDef
+{
+ function get_argument_definition()
+ {
+ self.status.verify("Test Rosella.CommandLine.ArgumentDef.get_argument_definition()");
+ using Rosella.CommandLine.ArgumentDef.get_argument_definition;
+
+ var arg_0 = {};
+ var result = get_argument_definition(arg_0);
+ self.assert.instance_of(result, class Rosella.CommandLine.ArgumentDef.NewStyleHash);
+
+ arg_0 = [];
+ result = get_argument_definition(arg_0);
+ self.assert.instance_of(result, class Rosella.CommandLine.ArgumentDef.OldStyleArray);
+ }
+}
+
+function initialize_test[anon](var context)
+{
+ // Set up the test suite here. Initialize the context, set up matchers
+ // in the matcher factory, load prerequisites, and do other things.
+ var(Rosella.load_bytecode_file)("rosella/commandline.pbc", "load");
+}
+
+function main[main]()
+{
+ var core = load_packfile("rosella/core.pbc");
+ var(Rosella.initialize_rosella)("test");
+ using initialize_test;
+ var(Rosella.Test.test)(class Test_Rosella_CommandLine_ArgumentDef, initialize_test:[named("initialize")]);
+}
413 t/commandline/Arguments.t
View
@@ -1,7 +1,24 @@
// Automatically generated test for Class Rosella.CommandLine.Arguments
function create_new(var p_args [slurpy])
{
- return new Rosella.CommandLine.Arguments(null, p_args);
+ return new Rosella.CommandLine.Arguments(null);
+}
+
+function create_arg_defs(var raw_arg_defs = null)
+{
+ if (raw_arg_defs == null) {
+ raw_arg_defs = {
+ "A" : "The A flag",
+ "B=s" : "The B scalar",
+ "C=[]" : "The C list",
+ "D={}" : "The D hash",
+ "fff" : "The F flag",
+ "ggg=s" : "The G scalar",
+ "hhh=[]" : "The H list",
+ "iii={}" : "The I hash"
+ };
+ }
+ return Rosella.CommandLine.ArgumentDef.get_argument_definition(raw_arg_defs);
}
class Test_Rosella_CommandLine_Arguments
@@ -9,171 +26,363 @@ class Test_Rosella_CommandLine_Arguments
function test_new()
{
// Test simple constructor. For most individual method tests, use create_new() above
- var obj = new Rosella.CommandLine.Arguments(null, []);
+ var obj = new Rosella.CommandLine.Arguments(null);
self.assert.not_null(obj);
self.assert.instance_of(obj, class Rosella.CommandLine.Arguments);
}
- function program_name()
+ function program()
{
- self.status.verify("Test Rosella.CommandLine.Arguments.program_name()");
+ self.status.verify("Test Rosella.CommandLine.Arguments.program()");
var p = new Rosella.CommandLine.Program("foo");
- var obj = new Rosella.CommandLine.Arguments(p, []);
+ var obj = new Rosella.CommandLine.Arguments(p);
- string result = obj.program_name();
- self.assert.equal(result, "foo");
+ var result = obj.program();
+ self.assert.same(result, p);
}
- function presort()
+ function parse()
{
- self.status.verify("Test Rosella.CommandLine.Arguments.presort()");
+ self.status.verify("Test Rosella.CommandLine.Arguments.parse()");
var obj = create_new();
-
- var arg_0 = null;
- obj.presort(arg_0);
+ var arg_defs = create_arg_defs();
+
+ string raw_args[] = [
+ "-A",
+ "--",
+ "Aye", "Bee", "Cee"
+ ];
+
+ // We test parsed results in other methods. Here, just prove that it
+ // doesn't error out.
+ self.assert.throws_nothing(function() {
+ obj.parse(raw_args, arg_defs);
+ });
}
- function fetch_flag()
+ function remainder()
{
- self.status.verify("Test Rosella.CommandLine.Arguments.fetch_flag()");
- var obj = create_new("-x", "-y", "--foo");
-
- string arg_0 = "-x";
- int arg_1 = 0;
- int result = obj.fetch_flag(arg_0, arg_1);
- self.assert.equal(result, 1);
-
- arg_0 = "-z";
- result = obj.fetch_flag(arg_0, arg_1);
- self.assert.equal(result, 0);
+ self.status.verify("Test Rosella.CommandLine.Arguments.remainder()");
+ var obj = create_new();
+ var arg_defs = create_arg_defs();
- arg_0 = "--foo";
- result = obj.fetch_flag(arg_0, arg_1);
- self.assert.equal(result, 1);
+ string raw_args[] = [
+ "-A",
+ "--",
+ "Aye", "Bee", "Cee"
+ ];
- arg_0 = "--bar";
- result = obj.fetch_flag(arg_0, arg_1);
- self.assert.equal(result, 0);
+ obj.parse(raw_args, arg_defs);
+ self.assert.is_match(obj.remainder(), ["Aye", "Bee", "Cee"]);
}
- function fetch_scalar()
+ function raw_args()
{
- self.status.verify("Test Rosella.CommandLine.Arguments.fetch_scalar()");
- var obj = create_new("--foo", "bar", "--baz=fie");
-
- string arg_0 = "--foo";
- int arg_1 = 0;
- string result = obj.fetch_scalar(arg_0, arg_1);
- self.assert.equal(result, "bar");
+ self.status.verify("Test Rosella.CommandLine.Arguments.get_argument_string()");
+ var obj = create_new();
+ var arg_defs = create_arg_defs();
- arg_0 = "--baz";
- result = obj.fetch_scalar(arg_0, arg_1);
- self.assert.equal(result, "fie");
+ string raw_args[] = [
+ "-A",
+ "--",
+ "Aye", "Bee", "Cee"
+ ];
- arg_0 = "--whatever";
- result = obj.fetch_scalar(arg_0, arg_1);
- self.assert.equal(result, "");
+ obj.parse(raw_args, arg_defs);
+ self.assert.same(obj.raw_args(), raw_args);
}
- function fetch_scalar_list()
+ function get_integer_keyed()
{
- self.status.verify("Test Rosella.CommandLine.Arguments.fetch_scalar_list()");
- var obj = create_new("-x", "a", "-x", "b", "-x", "c", "-y", "d");
-
- string arg_0 = "-x";
- int arg_1 = 0;
- var result = obj.fetch_scalar_list(arg_0, arg_1);
- self.assert.equal(elements(result), 3);
- self.assert.equal(result[0], "a");
- self.assert.equal(result[1], "b");
- self.assert.equal(result[2], "c");
+ var obj = create_new();
+ var arg_defs = create_arg_defs();
- arg_0 = "-y";
- result = obj.fetch_scalar_list(arg_0, arg_1);
- self.assert.equal(elements(result), 1);
- self.assert.equal(result[0], "d");
+ string raw_args[] = [
+ "-A"
+ ];
- arg_0 = "-z";
- result = obj.fetch_scalar_list(arg_0, arg_1);
- self.assert.equal(elements(result), 0);
+ obj.parse(raw_args, arg_defs);
+ self.assert.equal(int(obj["A"]), true);
+ self.assert.equal(int(obj["A"]), true);
+ self.assert.equal(int(obj["fff"]), false);
}
- function fetch_pair()
+ function get_string_keyed()
{
- self.status.verify("Test Rosella.CommandLine.Arguments.fetch_pair()");
- var obj = create_new("--foo", "a", "b");
+ var obj = create_new();
+ var arg_defs = create_arg_defs();
+
+ string raw_args[] = [
+ "-B",
+ "foo",
+ "--ggg",
+ "bar"
+ ];
+
+ obj.parse(raw_args, arg_defs);
+ self.assert.equal(string(obj["B"]), "foo");
+ self.assert.equal(string(obj["ggg"]), "bar");
+ }
- string arg_0 = "--foo";
- int arg_1 = 0;
- var result = obj.fetch_pair(arg_0, arg_1);
- self.assert.equal(elements(result), 1);
- self.assert.equal(result["a"], "b");
+ function get_pmc_keyed()
+ {
+ var obj = create_new();
+ var arg_defs = create_arg_defs();
+
+ string raw_args[] = [
+ "-C", "foo",
+ "-C", "bar",
+ "--hhh", "baz",
+ "--hhh", "fie"
+ ];
+
+ obj.parse(raw_args, arg_defs);
+ self.assert.is_match(obj["C"], ["foo", "bar"]);
+ self.assert.is_match(obj["hhh"], ["baz", "fie"]);
}
- function fetch_pair_hash()
+ function get_string_keyed_int()
{
- self.status.verify("Test Rosella.CommandLine.Arguments.fetch_pair_hash()");
- var obj = create_new("--foo=a=b", "--foo=c=d");
+ var obj = create_new();
+ var arg_defs = create_arg_defs();
- string arg_0 = "--foo";
- int arg_1 = 0;
- var result = obj.fetch_pair_hash(arg_0, arg_1);
- self.assert.equal(elements(result), 2);
- self.assert.equal(result["a"], "b");
- self.assert.equal(result["c"], "d");
+ string raw_args[] = [
+ "foo", "bar", "baz"
+ ];
+
+ obj.parse(raw_args, arg_defs);
+ self.assert.equal(string(obj[0]), "foo");
+ self.assert.equal(string(obj[1]), "bar");
+ self.assert.equal(string(obj[2]), "baz");
}
- function fetch_unparsed()
+ function get_pmc_keyed_int()
{
- self.status.verify("Test Rosella.CommandLine.Arguments.fetch_unparsed()");
var obj = create_new();
+ var arg_defs = create_arg_defs();
+
+ string raw_args[] = [
+ "foo", "bar", "baz"
+ ];
- string arg_0 = "";
- var arg_1 = 0;
- var result = obj.fetch_unparsed(arg_0, arg_1);
+ obj.parse(raw_args, arg_defs);
+ self.assert.equal(obj[0], "foo");
+ self.assert.equal(obj[1], "bar");
+ self.assert.equal(obj[2], "baz");
}
- function fetch_value()
+ function get_flag()
{
- self.status.verify("Test Rosella.CommandLine.Arguments.fetch_value()");
var obj = create_new();
+ var arg_defs = create_arg_defs();
+
+ string raw_args[] = [
+ "-A"
+ ];
- string arg_0 = "";
- var result = obj.fetch_value(arg_0);
+ obj.parse(raw_args, arg_defs);
+ self.assert.equal(int(obj["A"]), true);
+ self.assert.equal(int(obj["fff"]), false);
}
- function fetch_positional()
+ function get_scalar()
{
- self.status.verify("Test Rosella.CommandLine.Arguments.fetch_positional()");
var obj = create_new();
+ var arg_defs = create_arg_defs();
+
+ //"-B foo" and "--ggg bar"
+ string raw_args[] = [
+ "-B", "foo",
+ "--ggg", "bar"
+ ];
+ obj.parse(raw_args, arg_defs);
+ self.assert.equal(obj["B"], "foo");
+ self.assert.equal(obj["ggg"], "bar");
+
+ // "-Bfoo"
+ raw_args = [
+ "-Bfoo"
+ ];
+ obj = create_new();
+ obj.parse(raw_args, arg_defs);
+ self.assert.equal(obj["B"], "foo");
+
+ // "-B:foo" and "--ggg:bar"
+ raw_args = [
+ "-B:foo",
+ "--ggg:bar"
+ ];
+ obj = create_new();
+ obj.parse(raw_args, arg_defs);
+ self.assert.equal(obj["B"], "foo");
+ self.assert.equal(obj["ggg"], "bar");
+ }
- string arg_0 = "";
- int arg_1 = 0;
- var result = obj.fetch_positional(arg_0, arg_1);
+ function get_list()
+ {
+ var obj = create_new();
+ var arg_defs = create_arg_defs();
+
+ string raw_args[] = [
+ "-C", "foo",
+ "-Cbar",
+ "-C:baz",
+ "--hhh", "FOO",
+ "--hhh:BAR"
+ ];
+
+ obj.parse(raw_args, arg_defs);
+ self.assert.is_match(obj["C"], ["foo", "bar", "baz"]);
+ self.assert.is_match(obj["hhh"], ["FOO", "BAR"]);
}
- function remainder()
+ function get_hash()
{
- self.status.verify("Test Rosella.CommandLine.Arguments.remainder()");
var obj = create_new();
+ var arg_defs = create_arg_defs();
+
+ string raw_args[] = [
+ "-D", "foo=A",
+ "-Dbar=B",
+ "-D:baz=C",
+ "--iii", "FOO=A",
+ "--iii:BAR=B"
+ ];
+ obj.parse(raw_args, arg_defs);
+ self.assert.is_match(obj["D"], {"foo":"A", "bar":"B", "baz":"C"});
+ self.assert.equal(obj["iii"], {"FOO":"A", "BAR":"B"});
+ }
- var result = obj.remainder();
+ function argument_order()
+ {
+ self.status.verify("Parse flags and positionals in any order");
+ var obj = create_new();
+ var arg_defs = create_arg_defs();
+
+ string raw_args[] = [
+ "-A",
+ "foo"
+ ];
+ obj.parse(raw_args, arg_defs);
+ self.assert.equal(int(obj["A"]), true);
+ self.assert.equal(int(obj["fff"]), false);
+ self.assert.equal(obj[0], "foo");
+
+ raw_args = [
+ "foo",
+ "-A",
+ "--fff",
+ "bar"
+ ];
+ obj = create_new();
+ obj.parse(raw_args, arg_defs);
+ self.assert.equal(int(obj["A"]), true);
+ self.assert.equal(int(obj["fff"]), true);
+ self.assert.equal(obj[0], "foo");
+ self.assert.equal(obj[1], "bar");
+
+ raw_args = [
+ "foo",
+ "bar",
+ "-A",
+ "--fff"
+ ];
+ obj = create_new();
+ obj.parse(raw_args, arg_defs);
+ self.assert.equal(int(obj["A"]), true);
+ self.assert.equal(int(obj["fff"]), true);
+ self.assert.equal(obj[0], "foo");
+ self.assert.equal(obj[1], "bar");
}
- function raw_args()
+ function combination_args()
{
- self.status.verify("Test Rosella.CommandLine.Arguments.raw_args()");
var obj = create_new();
+ var arg_defs = create_arg_defs({
+ "A" : "A",
+ "B" : "B",
+ "C" : "C",
+ "D" : "D"
+ });
+
+ obj.parse(["-A", "-BC"], arg_defs);
+ self.assert.equal(int(obj["A"]), true);
+ self.assert.equal(int(obj["B"]), true);
+ self.assert.equal(int(obj["C"]), true);
+ self.assert.equal(int(obj["D"]), false);
+
+ obj = create_new();
+ obj.parse(["-ABCD"], arg_defs);
+ self.assert.equal(int(obj["A"]), true);
+ self.assert.equal(int(obj["B"]), true);
+ self.assert.equal(int(obj["C"]), true);
+ self.assert.equal(int(obj["D"]), true);
+
+ obj = create_new();
+ obj.parse(["-AD"], arg_defs);
+ self.assert.equal(int(obj["A"]), true);
+ self.assert.equal(int(obj["B"]), false);
+ self.assert.equal(int(obj["C"]), false);
+ self.assert.equal(int(obj["D"]), true);
+
+ obj = create_new();
+ obj.parse(["-BCD"], arg_defs);
+ self.assert.equal(int(obj["A"]), false);
+ self.assert.equal(int(obj["B"]), true);
+ self.assert.equal(int(obj["C"]), true);
+ self.assert.equal(int(obj["D"]), true);
+ }
- var result = obj.raw_args();
+ function arg_does_not_exist()
+ {
+ var obj = create_new();
+ var arg_defs = create_arg_defs({
+ "A" : "A"
+ });
+
+ obj.parse(["-A"], arg_defs);
+ self.assert.throws(function() {
+ int a = obj["does-not-exist"];
+ });
}
- function has_unparsed_args()
+ function unknown_args()
{
- self.status.verify("Test Rosella.CommandLine.Arguments.has_unparsed_args()");
var obj = create_new();
+ var arg_defs = create_arg_defs({
+ "A" : "A",
+ "B" : "B",
+ "C" : "C",
+ "D" : "D"
+ });
+
+ self.assert.throws(function() {
+ obj.parse(["-A", "-BC", "-X"], arg_defs);
+ });
+ }
+
+ function aliased_positionals()
+ {
+ var arg_defs = create_arg_defs({
+ "A=s" : "A",
+ "B=s0" : "B"
+ });
- var result = obj.has_unparsed_args();
+ // 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], "");
}
}
24 t/commandline/ModeCondition.t
View
@@ -0,0 +1,24 @@
+// Automatically generated test for Class Rosella.CommandLine.ModeCondition
+function create_new(var p_args [slurpy], var n_args [slurpy,named])
+{
+ return new Rosella.CommandLine.ModeCondition(p_args:[flat], n_args:[flat,named]);
+}
+
+class Test_Rosella_CommandLine_ModeCondition
+{
+}
+
+function initialize_test[anon](var context)
+{
+ // Set up the test suite here. Set options on the Suite, set up matchers
+ // in the matcher factory, load prerequisites, and do other things.
+ var(Rosella.load_bytecode_file)("rosella/commandline.pbc", "load");
+}
+
+function main[main]()
+{
+ var core = load_packfile("rosella/core.pbc");
+ var(Rosella.initialize_rosella)("test");
+ using initialize_test;
+ var(Rosella.Test.test)(class Test_Rosella_CommandLine_ModeCondition, initialize_test:[named("initialize")]);
+}
41 t/commandline/ModeCondition/FlagSet.t
View
@@ -0,0 +1,41 @@
+// Automatically generated test for Class Rosella.CommandLine.ModeCondition.FlagSet
+function create_new(var p_args [slurpy], var n_args [slurpy,named])
+{
+ return new Rosella.CommandLine.ModeCondition.FlagSet(p_args:[flat], n_args:[flat,named]);
+}
+
+class Test_Rosella_CommandLine_ModeCondition_FlagSet
+{
+ function test_new()
+ {
+ // Test simple constructor. For most individual method tests, use create_new() above
+ var obj = new Rosella.CommandLine.ModeCondition.FlagSet("foo");
+ self.assert.not_null(obj);
+ self.assert.instance_of(obj, class Rosella.CommandLine.ModeCondition.FlagSet);
+ }
+
+ function is_satisfied()
+ {
+ self.status.verify("Test Rosella.CommandLine.ModeCondition.FlagSet.is_satisfied()");
+ self.status.unimplemented("Need testing strategy for ModeConditions");
+ var obj = create_new("foo");
+
+ var arg_0 = null;
+ var result = obj.is_satisfied(arg_0);
+ }
+}
+
+function initialize_test[anon](var context)
+{
+ // Set up the test suite here. Set options on the Suite, set up matchers
+ // in the matcher factory, load prerequisites, and do other things.
+ var(Rosella.load_bytecode_file)("rosella/commandline.pbc", "load");
+}
+
+function main[main]()
+{
+ var core = load_packfile("rosella/core.pbc");
+ var(Rosella.initialize_rosella)("test");
+ using initialize_test;
+ var(Rosella.Test.test)(class Test_Rosella_CommandLine_ModeCondition_FlagSet, initialize_test:[named("initialize")]);
+}
41 t/commandline/ModeCondition/GenericFunc.t
View
@@ -0,0 +1,41 @@
+// Automatically generated test for Class Rosella.CommandLine.ModeCondition.GenericFunc
+function create_new(var p_args [slurpy], var n_args [slurpy,named])
+{
+ return new Rosella.CommandLine.ModeCondition.GenericFunc(p_args:[flat], n_args:[flat,named]);
+}
+
+class Test_Rosella_CommandLine_ModeCondition_GenericFunc
+{
+ function test_new()
+ {
+ // Test simple constructor. For most individual method tests, use create_new() above
+ var obj = new Rosella.CommandLine.ModeCondition.GenericFunc(null, "");
+ self.assert.not_null(obj);
+ self.assert.instance_of(obj, class Rosella.CommandLine.ModeCondition.GenericFunc);
+ }
+
+ function is_satisfied()
+ {
+ self.status.verify("Test Rosella.CommandLine.ModeCondition.GenericFunc.is_satisfied()");
+ self.status.unimplemented("Need testing strategy for ModeConditions");
+ var obj = create_new();
+
+ var arg_0 = null;
+ var result = obj.is_satisfied(arg_0);
+ }
+}
+
+function initialize_test[anon](var context)
+{
+ // Set up the test suite here. Set options on the Suite, set up matchers
+ // in the matcher factory, load prerequisites, and do other things.
+ var(Rosella.load_bytecode_file)("rosella/commandline.pbc", "load");
+}
+
+function main[main]()
+{
+ var core = load_packfile("rosella/core.pbc");
+ var(Rosella.initialize_rosella)("test");
+ using initialize_test;
+ var(Rosella.Test.test)(class Test_Rosella_CommandLine_ModeCondition_GenericFunc, initialize_test:[named("initialize")]);
+}
41 t/commandline/ModeCondition/NumPositionals.t
View
@@ -0,0 +1,41 @@
+// Automatically generated test for Class Rosella.CommandLine.ModeCondition.NumPositionals
+function create_new(var p_args [slurpy], var n_args [slurpy,named])
+{
+ return new Rosella.CommandLine.ModeCondition.NumPositionals(p_args:[flat], n_args:[flat,named]);
+}
+
+class Test_Rosella_CommandLine_ModeCondition_NumPositionals
+{
+ function test_new()
+ {
+ // Test simple constructor. For most individual method tests, use create_new() above
+ var obj = new Rosella.CommandLine.ModeCondition.NumPositionals(1, 2);
+ self.assert.not_null(obj);
+ self.assert.instance_of(obj, class Rosella.CommandLine.ModeCondition.NumPositionals);
+ }
+
+ function is_satisfied()
+ {
+ self.status.verify("Test Rosella.CommandLine.ModeCondition.NumPositionals.is_satisfied()");
+ self.status.unimplemented("Need testing strategy for ModeConditions");
+ var obj = create_new();
+
+ var arg_0 = null;
+ var result = obj.is_satisfied(arg_0);
+ }
+}
+
+function initialize_test[anon](var context)
+{
+ // Set up the test suite here. Set options on the Suite, set up matchers
+ // in the matcher factory, load prerequisites, and do other things.
+ var(Rosella.load_bytecode_file)("rosella/commandline.pbc", "load");
+}
+
+function main[main]()
+{
+ var core = load_packfile("rosella/core.pbc");
+ var(Rosella.initialize_rosella)("test");
+ using initialize_test;
+ var(Rosella.Test.test)(class Test_Rosella_CommandLine_ModeCondition_NumPositionals, initialize_test:[named("initialize")]);
+}
41 t/commandline/ModeCondition/ScalarExists.t
View
@@ -0,0 +1,41 @@
+// Automatically generated test for Class Rosella.CommandLine.ModeCondition.ScalarExists
+function create_new(var p_args [slurpy], var n_args [slurpy,named])
+{
+ return new Rosella.CommandLine.ModeCondition.ScalarExists(p_args:[flat], n_args:[flat,named]);
+}
+
+class Test_Rosella_CommandLine_ModeCondition_ScalarExists
+{
+ function test_new()
+ {
+ // Test simple constructor. For most individual method tests, use create_new() above
+ var obj = new Rosella.CommandLine.ModeCondition.ScalarExists("foo");
+ self.assert.not_null(obj);
+ self.assert.instance_of(obj, class Rosella.CommandLine.ModeCondition.ScalarExists);
+ }
+
+ function is_satisfied()
+ {
+ self.status.verify("Test Rosella.CommandLine.ModeCondition.ScalarExists.is_satisfied()");
+ self.status.unimplemented("Need testing strategy for ModeConditions");
+ var obj = create_new();
+
+ var arg_0 = null;
+ var result = obj.is_satisfied(arg_0);
+ }
+}
+
+function initialize_test[anon](var context)
+{
+ // Set up the test suite here. Set options on the Suite, set up matchers
+ // in the matcher factory, load prerequisites, and do other things.
+ var(Rosella.load_bytecode_file)("rosella/commandline.pbc", "load");
+}
+
+function main[main]()
+{
+ var core = load_packfile("rosella/core.pbc");
+ var(Rosella.initialize_rosella)("test");
+ using initialize_test;
+ var(Rosella.Test.test)(class Test_Rosella_CommandLine_ModeCondition_ScalarExists, initialize_test:[named("initialize")]);
+}
41 t/commandline/ModeCondition/ScalarValue.t
View
@@ -0,0 +1,41 @@
+// Automatically generated test for Class Rosella.CommandLine.ModeCondition.ScalarValue
+function create_new(var p_args [slurpy], var n_args [slurpy,named])
+{
+ return new Rosella.CommandLine.ModeCondition.ScalarValue(p_args:[flat], n_args:[flat,named]);
+}
+
+class Test_Rosella_CommandLine_ModeCondition_ScalarValue
+{
+ function test_new()
+ {
+ // Test simple constructor. For most individual method tests, use create_new() above
+ var obj = new Rosella.CommandLine.ModeCondition.ScalarValue("foo", "bar");
+ self.assert.not_null(obj);
+ self.assert.instance_of(obj, class Rosella.CommandLine.ModeCondition.ScalarValue);
+ }
+
+ function is_satisfied()
+ {
+ self.status.verify("Test Rosella.CommandLine.ModeCondition.ScalarValue.is_satisfied()");
+ self.status.unimplemented("Need testing strategy for ModeConditions");
+ var obj = create_new();
+
+ var arg_0 = null;
+ var result = obj.is_satisfied(arg_0);
+ }
+}
+
+function initialize_test[anon](var context)
+{
+ // Set up the test suite here. Set options on the Suite, set up matchers
+ // in the matcher factory, load prerequisites, and do other things.
+ var(Rosella.load_bytecode_file)("rosella/commandline.pbc", "load");
+}
+
+function main[main]()
+{
+ var core = load_packfile("rosella/core.pbc");
+ var(Rosella.initialize_rosella)("test");
+ using initialize_test;
+ var(Rosella.Test.test)(class Test_Rosella_CommandLine_ModeCondition_ScalarValue, initialize_test:[named("initialize")]);
+}
167 t/commandline/ProgramMode.t
View
@@ -1,114 +1,151 @@
+function setup_arguments(var defs, var raw_args)
+{
+ var arg_defs = Rosella.CommandLine.ArgumentDef.get_argument_definition(defs);
+ var args = new Rosella.CommandLine.Arguments(null);
+ args.parse(raw_args, arg_defs);
+ return args;
+}
+
// Automatically generated test for Class Rosella.CommandLine.ProgramMode
class Test_Rosella_CommandLine_ProgramMode
{
- function test_new()
- {
- var obj = new Rosella.CommandLine.ProgramMode("");
- self.assert.not_null(obj);
- self.assert.instance_of(obj, class Rosella.CommandLine.ProgramMode);
- }
-
function set_function()
{
self.status.verify("Test Rosella.CommandLine.ProgramMode.set_function()");
var obj = new Rosella.CommandLine.ProgramMode("");
var arg_0 = function(var args) { };
- var result = obj.set_function(arg_0);
- }
-
- function set_flag_1()
- {
- self.status.verify("Test Rosella.CommandLine.ProgramMode.set_flag()");
- var obj = new Rosella.CommandLine.ProgramMode("");
-
- string arg_0 = "";
- var result = obj.set_flag(arg_0);
+ obj.set_function(arg_0);
}
- function set_flag_2()
+ function set_usage()
{
- self.status.verify("Test Rosella.CommandLine.ProgramMode.set_flag()");
- var obj = new Rosella.CommandLine.ProgramMode("");
-
- string arg_0 = "";
- string arg_1 = "";
- var result = obj.set_flag(arg_0, arg_1);
+ // TODO: This is very fragile, I don't like matching exact strings, especially
+ // when there's whitespace involved.
+ var obj = new Rosella.CommandLine.ProgramMode("foo");
+ obj.set_usage("This is a test");
+ string usage = obj.get_usage("foo");
+ self.assert.str_equal(usage, " foo This is a test\n");
}
- function require_positional()
+ function get_usage()
{
- self.status.verify("Test Rosella.CommandLine.ProgramMode.require_positional()");
- var obj = new Rosella.CommandLine.ProgramMode("");
-
- string arg_0 = "";
- int arg_1 = 0;
- var result = obj.require_positional(arg_0, arg_1);
+ self.status.unimplemented("Need to set up some conditions to test with");
}
- function require_args()
+ function can_accept()
{
- self.status.verify("Test Rosella.CommandLine.ProgramMode.require_args()");
+ self.status.verify("Test Rosella.CommandLine.ProgramMode.can_accept()");
var obj = new Rosella.CommandLine.ProgramMode("");
var arg_0 = null;
- var result = obj.require_args(arg_0);
+ var result = obj.can_accept(arg_0);
}
- function optional_args()
+ function main_function()
{
- self.status.verify("Test Rosella.CommandLine.ProgramMode.optional_args()");
+ self.status.verify("Test Rosella.CommandLine.ProgramMode.main_function()");
var obj = new Rosella.CommandLine.ProgramMode("");
- var arg_0 = null;
- var result = obj.optional_args(arg_0);
+ // If we haven't set a function, this should throw an exception
+ self.assert.throws(function() {
+ var result = obj.main_function();
+ });
+
+ var arg_0 = function(var args) { };
+ obj.set_function(arg_0);
+ var result = obj.main_function();
+ self.assert.same(result, arg_0);
}
- function can_accept()
+ function require_flag()
{
- self.status.verify("Test Rosella.CommandLine.ProgramMode.can_accept()");
var obj = new Rosella.CommandLine.ProgramMode("");
-
- var arg_0 = null;
- var result = obj.can_accept(arg_0);
+ var args = setup_arguments({"foo":"foo","bar":"bar"}, ["--foo"]);
+ obj.require_flag("foo");
+ int result = obj.can_accept(args);
+ self.assert.is_true(result);
+
+ obj = new Rosella.CommandLine.ProgramMode("");
+ args = setup_arguments({"foo":"foo", "bar":"bar"}, ["--bar"]);
+ obj.require_flag("foo");
+ result = obj.can_accept(args);
+ self.assert.is_false(result);
+
+ obj = new Rosella.CommandLine.ProgramMode("");
+ args = setup_arguments({"foo":"foo", "bar":"bar"}, ["--bar", "--foo"]);
+ obj.require_flag("foo");
+ result = obj.can_accept(args);
+ self.assert.is_true(result);
}
- function match_positionals()
+ function require_value()
{
- self.status.verify("Test Rosella.CommandLine.ProgramMode.match_positionals()");
var obj = new Rosella.CommandLine.ProgramMode("");
-
- var arg_0 = null;
- int arg_1 = 0;
- var result = obj.match_positionals(arg_0, arg_1);
+ var args = setup_arguments({"foo=s":"foo","bar=s":"bar"}, ["--foo:baz"]);
+ obj.require_value("foo", "baz");
+ int result = obj.can_accept(args);
+ self.assert.is_true(result);
+
+ obj = new Rosella.CommandLine.ProgramMode("");
+ args = setup_arguments({"foo=s":"foo", "bar=s":"bar"}, ["--foo:fie"]);
+ obj.require_value("foo", "ba