Target coverage: a klammer states the targets it serves
kdesc gains --coverage, which reports for every klammer the set of targets it can render to, and — the point of it — which klammers' coverage cannot be derived and must therefore be declared. Three rules: coverage is DERIVED where the definitions determine it (a general body of klammer calls covers the intersection of what those klammers cover, by a greatest fixpoint after loading), DECLARED where the engine cannot interpret what decides it (an @eval body, whose targets are undecidable), and UNKNOWN where nothing is written — which never means "deliberately unavailable". Two new spellings in a definition's name. A comma-separated target list, "@@table.html,tex :: ...", gives one body several targets; it is surface syntax, expanded at registration, and each member goes through the redefinition rules on its own. And "@@date.* :: ..." writes the general target out, asserting that the klammer works for EVERY target including ones not yet defined — a stronger claim than a list of the targets defined today, and the one target declaration that could be mechanically falsified. The Standard Klammer Set was swept accordingly: it now has no general definitions at all, every klammer names the targets it serves, six use ".*", and tex and pdf are at zero undecided. kdesc's flags are reorganised on two rules: a flag reached for often gets a single letter (-k klammers, -t targets, -c characters, -i input), a more specialised topic a multi-letter name (--argtypes, --katoms, --rewrite, --optionsets, --coverage, --klammerset, --font); and -v says how much to show about PROCESSING, never what the RESULT contains — so the katom regex column is "--katoms full" and the coverage detail "--coverage all". NOTE: "-k" now lists klammers (optionally filtered by a name/description search); the katom table moved to "--katoms". Fixes carried along: an option written with no value crashed the command with SIGSEGV instead of reporting the mistake; two required positional arguments never parsed; kdesc and kdiag printed an error and exited 0; and definition diagnostics counted registrations rather than what was written, so one line could be reported as two definitions and then printed twice. Four new test suites: target_list, coverage, command_option, kdesc. (from dev 46f54080bd9a)
This commit is contained in:
60
mac/argv.cpp
60
mac/argv.cpp
@@ -145,7 +145,8 @@ void Argv::opt(const std::string& name, const std::string& desc, const std::stri
|
||||
update_width(arg);
|
||||
}
|
||||
|
||||
void Argv::var(const std::string& name, const std::string& desc)
|
||||
void Argv::var(const std::string& name, const std::string& desc,
|
||||
const std::string& parameter)
|
||||
{
|
||||
(void)K::log(2, name, desc);
|
||||
Arg arg {};
|
||||
@@ -153,6 +154,9 @@ void Argv::var(const std::string& name, const std::string& desc)
|
||||
arg.m_name = name;
|
||||
arg.m_desc = get_regex_desc(desc);
|
||||
arg.m_syntax = arg.symbol();
|
||||
if (!parameter.empty()) {
|
||||
arg.m_syntax += " [<" + parameter + ">]";
|
||||
}
|
||||
m_args[name] = arg;
|
||||
m_names.push_back(name);
|
||||
m_var_names.push_back(name);
|
||||
@@ -291,18 +295,23 @@ void Argv::parse_optional(strings_t& words, string_map& named_args)
|
||||
// std::cout << " Found: " << words[index] << "\n";
|
||||
//std::vector<std::string> opt_args = {};
|
||||
index++;
|
||||
/*
|
||||
// An option declared with opt() takes a value, so the word after
|
||||
// the flag must exist. Written last with nothing after it -- a
|
||||
// bare "kdesc -v", or "ktext doc.kt -t" -- this read past the end
|
||||
// of the vector and the command died with SIGSEGV, naming
|
||||
// nothing. (Two bounds checks used to sit here, commented out;
|
||||
// they would have returned a HALF-PARSED option rather than
|
||||
// reporting the mistake, so this reports it instead.) A valueless
|
||||
// option is declared with flag(), not opt().
|
||||
if (index >= words.size()) {
|
||||
break;
|
||||
throw Argument_error(
|
||||
"The option " + flag_name(opt) + " needs a value: " +
|
||||
m_args[opt].m_syntax + ". Enter \"" +
|
||||
file_basename(command_name) + "\" for the list of arguments.",
|
||||
Locator(), false);
|
||||
}
|
||||
*/
|
||||
std::string opt_arg = words[index] + " ";
|
||||
index++;
|
||||
/*
|
||||
if (index >= words.size()) {
|
||||
break;
|
||||
}
|
||||
*/
|
||||
std::regex opt_regex = m_args[opt].m_rgx;
|
||||
|
||||
// std::cout << "Regex match? " << std::regex_match(trim(opt_arg), opt_regex) << "\n";
|
||||
@@ -346,7 +355,19 @@ void Argv::parse_positional(const std::string& command, //strings_t words,
|
||||
throw Argument_error(ss.str(), Locator(), false);
|
||||
}
|
||||
named_args[req] = substring;
|
||||
pos_args = rest;
|
||||
// Drop the whitespace that separated this positional from the next.
|
||||
// regex_split_prefix() requires its match at position 0 and returns
|
||||
// the remainder verbatim, so without this the SECOND required
|
||||
// argument is always "not found": its pattern is offered " second"
|
||||
// and cannot match a leading space.
|
||||
//
|
||||
// Trimming here rather than at the top of the loop is deliberate: the
|
||||
// first positional still receives pos_args exactly as before, so a
|
||||
// command with ONE required argument -- which is every command that
|
||||
// ships (ktext's `filenames`, kdiag's `input`) -- parses
|
||||
// bit-identically. Only the case that never worked changes.
|
||||
size_t next = rest.find_first_not_of(" \t");
|
||||
pos_args = (next == std::string::npos) ? "" : rest.substr(next);
|
||||
}
|
||||
// std::cout << "Remaining words: " << words << "\n" << pos_args << "\n";
|
||||
}
|
||||
@@ -436,7 +457,13 @@ void Argv::parse(int argc, char* argv[], bool full_parse)
|
||||
{
|
||||
(void)K::log(2);
|
||||
command_name = argv[0];
|
||||
describe();
|
||||
// No describe() here. A call sat at this point, before any value has
|
||||
// been assigned, so it could only ever print a table of "<none>" -- and
|
||||
// because set_verbose_level() parses a throwaway Argv before the real
|
||||
// one, EVERY command would print that table on every run. Silencing
|
||||
// Argv::describe() itself was the wrong half of the fix: it also silenced
|
||||
// the callers that legitimately want it (kdesc -v, argv_test). The
|
||||
// caller decides; parse() does not print.
|
||||
auto input_args = classify_arguments(argc, argv, full_parse);
|
||||
// std::cout << "parse() classify:\n" << input_args << "\n";
|
||||
|
||||
@@ -610,10 +637,11 @@ void Argv::describe()
|
||||
std::stringstream ss {};
|
||||
ss << " "<< std::setfill(' ') << std::setw(width)
|
||||
<< m_args[name].symbol() << " : " << value;
|
||||
// The line was built and then dropped, so this printed nothing at
|
||||
// all -- which is why "kdesc -v 1" showed no arguments and argv_test,
|
||||
// whose whole job is to display what Argv parsed, was silent. The
|
||||
// callers already decide whether to call it (the commands gate it on
|
||||
// verbose_level > 0), so it prints unconditionally here.
|
||||
std::cout << ss.str() << "\n";
|
||||
}
|
||||
/*
|
||||
if (verbose_level == 1) {
|
||||
std::cout << "\n";
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user