Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Argparse #648

Merged
merged 1 commit into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 42 additions & 6 deletions docs/docs/standard-lib/argparse.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,16 @@ To make use of the Argparse module an import is required.
from Argparse import Parser;
```

### New Parser(String, String, String) -> Parser
### New Parser(String, String, String -> Optional) -> Parser

To create a new parser instance, call the `Parser` class with the 3 required string arguments; name, description, and user provided usage.
To create a new parser instance, call the `Parser` class with the 2 required string arguments; name, description.

You can optionally pass in a user generated usage for the Parser

```cs
var parser = Parser("prog_name", "Program to do all the things", "");
const parser = Parser("prog_name", "Program to do all the things");
//
const parser = Parser("prog_name", "Program to do all the things", "User defined usage string");
```

### Parse.addString(String, String, Bool, string -> Optional)
Expand Down Expand Up @@ -64,7 +68,24 @@ To add a new list argument, call the method below with at least the 3 required a
parser.addList("-u", "active users", true, "users");
```

### Parser.parse() -> Result\<Dict>
### Parser.usage() -> String

The Parser class will create a helpful output based on the arguments added to the parser class for you, this can be used to populate a `--help` argument.

```cs
const parser = Parser("Code!", "Some code");
parser.addBool("--myOption", "Some useful boolean option", false);
print(parser.usage());

// Output
usage: Code!
Some code

--myOption Some useful boolean option

```

### Parser.parse() -> Result\<Args>

The `parse` method needs to be called to process the given flags against the configured flags. `parse` returns a `Result` value that, on success, will need to be unwrapped to access an instance of the `Args` class.

Expand All @@ -78,8 +99,23 @@ const args = parser.parse().match(
);
```

The value of type `Args` will be instantiated with fields matching the configured flags or the given metavar names. Below is an example using the list argument example from above.
The value of type `Args` will be instantiated with fields matching the configured flags or the given metavar names.

If the option was not marked as required and a value for that given argument was not passed then it will have a `nil` value.

```cs
print("Users: {}".format(args.users));
const parser = Parser("Code!", "Some code");
parser.addString("--option", "Some useful string option", false);
parser.addString("--option1", "Some useful string option", false);
const args = parser.parse().unwrap();

print(args.option, args.option1);
```

CLI Input / Output:

```
$ dictu argparse.du --option "Hello"
hello
nil
```
39 changes: 31 additions & 8 deletions src/optionals/argparse/argparse-source.h
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
#define DICTU_ARGPARSE_SOURCE "import Argparse;\n" \
"import System;\n" \
#define DICTU_ARGPARSE_SOURCE "import System;\n" \
"\n" \
"class Args {\n" \
" init(private name, private desc) {}\n" \
"}\n" \
"\n" \
"class Parser {\n" \
" private args;\n" \
" private preArgs;\n" \
" private required;\n" \
"\n" \
" var preArgs = [];\n" \
" var required = [];\n" \
"\n" \
" init(private name, private desc, private userUsage) {\n" \
" init(private name, private desc, private userUsage = '') {\n" \
" this.args = Args(name, desc);\n" \
" this.preArgs = [];\n" \
" this.required = [];\n" \
" }\n" \
"\n" \
" private flagExists(flag) {\n" \
Expand Down Expand Up @@ -67,7 +67,11 @@
" var u = 'usage: {}\n {}\n\n'.format(this.name, this.desc);\n" \
"\n" \
" for (var i = 0; i < this.preArgs.len(); i+=1) {\n" \
" u += ' {} {}\n'.format(this.preArgs[i]['flag'], this.preArgs[i]['desc']);\n" \
" u += ' {} {}{}\n'.format(\n" \
" this.preArgs[i]['flag'],\n" \
" this.preArgs[i]['desc'],\n" \
" this.preArgs[i]['required'] ? ' Required' : ''\n" \
" );\n" \
" }\n" \
"\n" \
" return u;\n" \
Expand All @@ -93,6 +97,23 @@
" return false;\n" \
" }\n" \
"\n" \
" private fillEmpty() {\n" \
" for (var i = 0; i < this.preArgs.len(); i += 1) {\n" \
" const arg = this.preArgs[i];\n" \
"\n" \
" if (arg.get('metavar') and not this.args.getAttribute(arg['metavar'])) {\n" \
" this.args.setAttribute(arg['metavar'], nil);\n" \
"\n" \
" continue;\n" \
" }\n" \
"\n" \
" const flag = arg['flag'].replace('-', '');\n" \
" if (not this.args.getAttribute(flag)) {\n" \
" this.args.setAttribute(flag, nil);\n" \
" }\n" \
" }\n" \
" }\n" \
"\n" \
" parse() {\n" \
" for (var i = 0; i < System.argv.len(); i+=1) {\n" \
" for (var j = 0; j < this.preArgs.len(); j+=1) {\n" \
Expand All @@ -115,7 +136,7 @@
" this.args.setAttribute(this.preArgs[j]['flag'].replace('-', ''), System.argv[i+1].split(','));\n" \
" }\n" \
" } else if (this.preArgs[j]['type'] == 'number') {\n" \
" if (i == (System.argv.len() - 1) or System.argv[i+1][0] == '-') {\n" \
" if (i == (System.argv.len() - 1)) {\n" \
" return Error('{} requires an argument'.format(System.argv[i]));\n" \
" }\n" \
"\n" \
Expand Down Expand Up @@ -149,6 +170,8 @@
" return Error('1 or more required flags missing');\n" \
" }\n" \
"\n" \
" this.fillEmpty();\n" \
"\n" \
" return Success(this.args);\n" \
" }\n" \
"}\n" \
Expand Down
3 changes: 0 additions & 3 deletions src/optionals/argparse/argparse.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,5 @@ Value createArgParseModule(DictuVM *vm) {
return EMPTY_VAL;
}

push(vm, OBJ_VAL(closure));
pop(vm);

return OBJ_VAL(closure);
}
37 changes: 30 additions & 7 deletions src/optionals/argparse/argparse.du
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Argparse;
import System;

class Args {
Expand All @@ -7,12 +6,13 @@ class Args {

class Parser {
private args;
private preArgs;
private required;

var preArgs = [];
var required = [];

init(private name, private desc, private userUsage) {
init(private name, private desc, private userUsage = '') {
this.args = Args(name, desc);
this.preArgs = [];
this.required = [];
}

private flagExists(flag) {
Expand Down Expand Up @@ -67,7 +67,11 @@ class Parser {
var u = 'usage: {}\n {}\n\n'.format(this.name, this.desc);

for (var i = 0; i < this.preArgs.len(); i+=1) {
u += ' {} {}\n'.format(this.preArgs[i]['flag'], this.preArgs[i]['desc']);
u += ' {} {}{}\n'.format(
this.preArgs[i]['flag'],
this.preArgs[i]['desc'],
this.preArgs[i]['required'] ? ' Required' : ''
);
}

return u;
Expand All @@ -93,6 +97,23 @@ class Parser {
return false;
}

private fillEmpty() {
for (var i = 0; i < this.preArgs.len(); i += 1) {
const arg = this.preArgs[i];

if (arg.get('metavar') and not this.args.getAttribute(arg['metavar'])) {
this.args.setAttribute(arg['metavar'], nil);

continue;
}

const flag = arg['flag'].replace('-', '');
if (not this.args.getAttribute(flag)) {
this.args.setAttribute(flag, nil);
}
}
}

parse() {
for (var i = 0; i < System.argv.len(); i+=1) {
for (var j = 0; j < this.preArgs.len(); j+=1) {
Expand All @@ -115,7 +136,7 @@ class Parser {
this.args.setAttribute(this.preArgs[j]['flag'].replace('-', ''), System.argv[i+1].split(','));
}
} else if (this.preArgs[j]['type'] == 'number') {
if (i == (System.argv.len() - 1) or System.argv[i+1][0] == '-') {
if (i == (System.argv.len() - 1)) {
return Error('{} requires an argument'.format(System.argv[i]));
}

Expand Down Expand Up @@ -149,6 +170,8 @@ class Parser {
return Error('1 or more required flags missing');
}

this.fillEmpty();

return Success(this.args);
}
}