Width and height argtypes, kdesc --argtypes from ref/, txt @define/@left_right/@columns, kdiag --check value validation (from dev d6993110e9b3)
Also: the klammertext argtype (descriptions kept as source), txt table wrapping and :hpos/:offset, @c between ‹ ›, txt section headings, the ktext newline-only trim, capitalize(), and the argtype test suite. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
9b0d0d7897
commit
0ead40f272
39 files changed
+734
-158
No files matched your search
@@ -4,6 +4,7 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "check.h"
|
||||
#include "error.h"
|
||||
#include "machine.h"
|
||||
#include "katom.h"
|
||||
#include "katom_process.h"
|
||||
@@ -23,12 +24,32 @@ namespace {
|
||||
// check time nothing has been reduced, so the nesting is still present and
|
||||
// must be tracked. (The depth-0 rule is the same one cond_separator_bars()
|
||||
// applies for @cond; see doc/cond_evaluation_order.md.)
|
||||
// A value as written, and whether it is LITERAL: made of nothing but text
|
||||
// and whitespace at depth 0, so that what the writer typed is what the
|
||||
// argument type will see. A value holding a nested klammer, a *variable*,
|
||||
// a quoted special or a caret form is computed at run time and cannot be
|
||||
// judged here -- the static-structure rule: check what is fixed, skip what
|
||||
// is computed.
|
||||
struct Argument_value
|
||||
{
|
||||
std::string m_text {};
|
||||
bool m_literal { true };
|
||||
};
|
||||
|
||||
struct Application_shape
|
||||
{
|
||||
int m_positional { 0 };
|
||||
std::vector<std::string> m_options {};
|
||||
std::vector<Argument_value> m_positional_values {};
|
||||
std::vector<std::pair<std::string, Argument_value>> m_option_values {};
|
||||
};
|
||||
|
||||
bool is_literal_katom(const Katom& k)
|
||||
{
|
||||
return k.m_type == katom_t::text || k.m_type == katom_t::word
|
||||
|| k.m_type == katom_t::space || k.m_type == katom_t::newline;
|
||||
}
|
||||
|
||||
bool is_boundary_katom(const Katom& k)
|
||||
{
|
||||
return k.m_type == katom_t::bar || k.m_type == katom_t::option_name;
|
||||
@@ -49,14 +70,36 @@ Application_shape application_shape(katom_list::const_iterator begin, katom_list
|
||||
bool in_positional = first->m_type != katom_t::option_name;
|
||||
if (in_positional) shape.m_positional = 1;
|
||||
|
||||
// The value being accumulated: a positional part, or the option named
|
||||
// last. Closed at each depth-0 boundary and at the end.
|
||||
Argument_value current {};
|
||||
bool current_is_option = !in_positional;
|
||||
std::string current_option {};
|
||||
auto close = [&]() {
|
||||
current.m_text = trim(current.m_text);
|
||||
if (current_is_option) {
|
||||
shape.m_option_values.emplace_back(current_option, current);
|
||||
} else {
|
||||
shape.m_positional_values.push_back(current);
|
||||
}
|
||||
current = Argument_value {};
|
||||
};
|
||||
|
||||
int depth = 0;
|
||||
for (auto k = first; k != end; ++k) {
|
||||
if (depth == 0 && is_boundary_katom(*k)) {
|
||||
close();
|
||||
if (k->m_type == katom_t::bar) {
|
||||
++shape.m_positional;
|
||||
current_is_option = false;
|
||||
} else {
|
||||
shape.m_options.push_back(k->m_text.substr(1));
|
||||
current_is_option = true;
|
||||
current_option = k->m_text.substr(1);
|
||||
}
|
||||
} else {
|
||||
if (depth > 0 || !is_literal_katom(*k)) current.m_literal = false;
|
||||
current.m_text += k->m_text;
|
||||
}
|
||||
if (level_increase(*k)) {
|
||||
++depth;
|
||||
@@ -64,6 +107,7 @@ Application_shape application_shape(katom_list::const_iterator begin, katom_list
|
||||
--depth;
|
||||
}
|
||||
}
|
||||
close();
|
||||
return shape;
|
||||
}
|
||||
|
||||
@@ -159,6 +203,28 @@ void Checker::check_application(
|
||||
error(ss.str(), context, begin->m_loc);
|
||||
}
|
||||
|
||||
// Argument VALUES against their argument types -- the check that finds
|
||||
// a height unit on a width, a word where a number is wanted -- for every
|
||||
// value that is literal (see Argument_value). The same test the engine
|
||||
// applies when the klammer is applied, Parameter_set::validate(), so the
|
||||
// two can never disagree; its exception becomes a diagnostic here.
|
||||
auto validate = [&](const Parameter& parameter, const Argument_value& value) {
|
||||
if (!value.m_literal || value.m_text.empty()) return;
|
||||
try {
|
||||
Parameter_set::validate(parameter, value.m_text, begin->m_loc);
|
||||
} catch (const Argument_error& e) {
|
||||
error("@" + name + ": " + collapse_whitespace(e.m_desc), context, begin->m_loc);
|
||||
}
|
||||
};
|
||||
for (size_t i = 0; i < shape.m_positional_values.size() && i < parameters.m_positional.size(); i++) {
|
||||
validate(parameters.m_positional[i], shape.m_positional_values[i]);
|
||||
}
|
||||
for (const auto& [option, value] : shape.m_option_values) {
|
||||
if (const Parameter* parameter = parameters.find(option)) {
|
||||
validate(*parameter, value);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> seen {};
|
||||
for (const auto& option : shape.m_options) {
|
||||
if (std::ranges::count(parameters.m_optional_names, option) == 0) {
|
||||
|
||||
Reference in new issue
Block a user