Can only be used for functions that are templated, on runtime parameters.
A UDA on the argument, will be stored with the argument position.
After symbol lookup is completed, and it is time to determine if a template instantiation is required, the UDA's from all arguments will be used as an extra criteria for the template instantion.
This will affect the name mangling of a template instance, by including the UDA's to make the unique.
The storage of the call site UDA will be upon the parameter position, and for alias sequence, will be with respect to the elements index also.
To access a UDA on a parameter, use __traits(getAttributes, parameter)
.
Do not use the parameter type, this does not identify the parameter.
The trait getAttributes
will be extended to support an optional filter parameter for the type to prevent the need for templates.
A new trait hasAttribute
with a filter parameter that specifies a type is added determine if a given attribute type is available on a symbol.
CLI access ala std.getopt
has a common need for providing extra meta data with a value.
string username, password;
getopt(
@description("My program")
@description("Second line")
commandsInfo,
@description("My programs help info")
@flag("help") @flag("h") helpInfo,
@description("The username to connect with")
@flag("username") @flag("u") username,
@description("The password to connect with")
@flag("password") @flag("p") password
);
shared CommandsInfo commandsInfo;
shared HelpInfo helpInfo;
void getopt(Args...)(ref string[] cli, ref Args args) {
void printHeader() {
static foreach(i; 0 .. Args.length) {
static if (is(args[i] : typeof(commandsInfo))) {
foreach(programDescription; __traits(getAttributes, args[i], description))) {
// TODO: writeln programDescription
}
}
}
}
void printHelpEntry(string flag, string description) {
if (flag is null) {
// TODO: write fill flag
} else {
// TODO: write flag
}
if (description !is null) {
// TODO: write fill between flag and description
// TODO: write description
}
// TODO: writeln
}
void printHelp() {
static foreach(i; 0 .. Args.length) {
static if (is(args[i] : typeof(commandsInfo))) {
} else {
flag[] flags = [__traits(getAttributes, args[i], flag)];
description[] descriptions = [__traits(getAttributes, args[i], description)];
if (flags.length < descriptions.length) {
foreach(i; 0 .. flags.length) {
printHelpEntry(flags[i], descriptions[i]);
}
foreach(i; flags.length .. descriptions.length) {
printHelpEntry(null, descriptions[i]);
}
} else {
foreach(i; 0 .. descriptions.length) {
printHelpEntry(flags[i], descriptions[i]);
}
foreach(i; descriptions.length .. flags.length) {
printHelpEntry(flags[i], null);
}
}
foreach(programDescription; )) {
// TODO: writeln programDescription
}
}
}
}
foreach(str; cli) {
switch(str) {
static foreach(i; 0 .. Args.length) {
static foreach(f; __traits(getAttributes, args[i], flag)) {
case "--" ~ f.value:
str = str[1 .. $];
goto case "-" ~ f;
case "-" ~ f.value:
str = str[1 .. $];
// TODO: remove from cli array
static if (is(Args[i] : typeof(commandsInfo)) {
} else static if (is(Args[i] : typeof(helpInfo)) {
foreach(help; __traits(getAttributes, args[i], typeof(helpInfo))) {
// TODO: writeln help.value
}
printHelp;
} else {
printHeader;
str.formattedRead(args[i]);
}
return;
}
}
default:
// TODO: unrecognized option
return;
}
}
}
This has the same capability of 1036e, except it does not rely on templates to convey the additional information.
i"prefix$(expr)suffix"
Becomes:
@IPrefix("prefix")
@ISuffix("suffix")
@IExpression("expr")
expr
This can be extended to support a single identifier, positional arguments, as well as formatting.
i"$ident$(expr)$(ident:format)${1:format}"
Becomes:
@IExpression("ident")
ident,
@IExpression("expr")
expr,
@IExpression("ident")
@IFormat("format")
ident,
@IFormat("format")
@IPosition(1)
IPosition(1)
db.execi(i"SELECT * FROM items WHERE id = $desiredId");
Becomes:
db.execi(@IPrefix("SELECT * FROM items WHERE id = ") desiredId);
For the function:
auto execi(Args...)(Sqlite db, Args args) {
enum query = () {
string ret;
static foreach(i; 0 .. Args.length) {
foreach(prefix; __traits(getAttributes, args[i], IPrefix)) {
ret ~= prefix.value;
}
ret ~= "?";
ret ~= i.text;
}
return ret;
}();
auto statement = Statement(db, query);
static foreach (i, arg; args)
statement.bind(i + 1, arg);
return statement.execute();
}