t = next_token();
if (t == TOK_CLOSE_PAREN)
break;
+
+ while (next_pos < num_args && !(adefs[next_pos].type & AT_POSITIONAL))
+ next_pos++;
+
uint argi = 0;
bool has_value = false;
+
if (t == TOK_IDENT)
{
while (adefs[argi].name && token != adefs[argi].name)
argi++;
- if (!adefs[argi].name)
- err("Command %s has no argument %s", cdef->name, token.c_str());
- if (c->args.count(token))
- err("Argument %s given multiple times", token.c_str());
- t = next_token();
- if (t == TOK_EQUAL)
- has_value = true;
+ if (adefs[argi].name)
+ {
+ if (c->args.count(token))
+ err("Argument %s given multiple times", token.c_str());
+ t = next_token();
+ if (t == TOK_EQUAL)
+ has_value = true;
+ else
+ return_token();
+ saw_named = true;
+ }
+ else if (next_pos < num_args && (adefs[next_pos].type & AT_TYPE_MASK) == AT_STRING)
+ {
+ // Shortcut syntax: positional arguments of string type can be specified
+ // as bare identifiers if they do not collide with names or other arguments.
+ return_token();
+ argi = next_pos++;
+ has_value = true;
+ }
else
- return_token();
- saw_named = true;
+ err("Command %s has no argument %s", cdef->name, token.c_str());
}
else if (saw_named)
err("Positional arguments must precede named ones");
- else
+ else if (next_pos < num_args)
{
return_token();
- while (next_pos < num_args && !(adefs[next_pos].type & AT_POSITIONAL))
- next_pos++;
- if (next_pos >= num_args)
- err("Too many positional arguments for command %s", cdef->name);
argi = next_pos++;
has_value = true;
}
+ else
+ err("Too many positional arguments for command %s", cdef->name);
const arg_def *adef = &adefs[argi];
uint type = adef->type & AT_TYPE_MASK;
{
case AT_STRING:
t = next_token();
- if (t != TOK_STRING)
- err("Argument %s must be a string", adef->name);
+ if (t != TOK_STRING && t != TOK_IDENT)
+ err("Argument %s must be a string or identifier", adef->name);
val = new arg_string(token);
break;
case AT_INT: