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:
ackandClaude Fable 5.1 committed 2026-09-16 16:59:49 +02:00
1 parent 9b0d0d7897
commit 0ead40f272
39 files changed
+734 -158

No files matched your search

+66
View File
@@ -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) {