Option sets: a .o target for shared parameters

A named group of optional parameters, declared once and used by several
klammers, so a writer learns one vocabulary instead of a spelling per
klammer.  The "o" target is a pseudo-target beside "k": "k" declares a
klammer's interface and documents it, "o" declares an option interface and
documents it, and neither produces output for any target.

    @@caption_args.o :caption :number.bool true :caption_side.side
    : Arguments that define a caption for a block element @@

    @@code.k :filename @hpos_args :hpos left @ @caption_args :caption_side top @
    | text.literal : A source file displayed verbatim @@

A set is used only in the parameter list of a ".k" declaration -- the one
place a klammer's interface is declared once for all of its targets -- and
is resolved as that list is read.  Names and types come from the set; a
default may be overridden where it is used.  A klammer application in a
parameter list is now a definition-time error.

The SKS gains the sets caption_args and hpos_args (:hpos and :offset), and
@table, @image, @image_grid, @reference and @show gain .k declarations.  A
distance is no longer written as a position: :hpos 4em is rejected, and the
same layout is :hpos left :offset 4em.  Code listings are numbered by
default, like tables and figures.

New engine sources mac/option_set{,_registry}.{h,cpp}; tst/ ships two more
suites, option_set_test.sh and signature_test.sh (twelve in all).

 (from dev 34e536cb0329)
This commit is contained in:
2026-08-06 13:11:37 +02:00
parent 4306dcd490
commit 6e7596ab2e
37 changed files with 2198 additions and 267 deletions

View File

@@ -207,12 +207,27 @@ void Machine::process_cond_katoms(katom_list& katoms)
}
// Expand the constant klammers written in a definition's BODY. A constant is
// expanded at definition time, which is what makes it a constant; the body is
// where that is meaningful.
//
// The parameter list is deliberately excluded. A klammer application there
// is an error (see expand_option_sets): parameters shared between klammers
// are declared by an option set, whose ".o" declaration is resolved as the
// parameter list is read. Expanding a constant into a parameter list used to
// be the way to share parameters, and it silently destroyed the parameter
// list of a ".k" declaration -- the spliced options AND the declared
// positionals -- surfacing only as an argument error at the first
// application, in the document rather than the declaration.
void Machine::expand_constant_klammers(katom_list& katoms, const Katom& op, const Katom& cl)
{
auto [begin, end] = find_span_katoms(katoms, op, cl);
restore_initial_type(begin + 1, end - 1);
if (std::find_if(begin + 1, end - 1, begin_klammer_apply) == end - 1) return;
for (const auto& [app_op, app_cl] : find_spans(begin + 1, end - 1, begin_apply, end_apply, false, "def-time")) {
auto body_begin = std::find_if(
begin + 1, end - 1, [](const Katom& k) { return is_deftype(k.m_type); });
if (body_begin == end - 1) return;
if (std::find_if(body_begin, end - 1, begin_klammer_apply) == end - 1) return;
for (const auto& [app_op, app_cl] : find_spans(body_begin, end - 1, begin_apply, end_apply, false, "def-time")) {
auto [app_begin, app_end] = find_span_katoms(katoms, app_op, app_cl);
if (app_begin->m_type == katom_t::apply_begin) {
std::string name = trim_char(app_begin->m_text, '@');
@@ -506,14 +521,27 @@ void Machine::load_klammerset_files(const Klammerset& klammerset, katom_iter ins
m_katoms.insert(insert_at, loaded.begin(), loaded.end());
}
// Register one "@@...@@" definition. An ".o" target declares an option set
// -- parameters shared by klammers -- and goes to its own registry: it
// defines no klammer and produces no output for any target.
void Machine::add_definition(katom_list& katoms, const Katom& op, const Katom& cl)
{
expand_constant_klammers(katoms, op, cl);
auto [begin, end] = find_span_katoms(katoms, op, cl);
auto [name, target] = parse_name(m_targets, *begin);
if (target == Target_registry::optionset_name) {
m_option_sets.add(m_argtypes, name, begin, end, katoms);
} else {
m_klammers.add(m_argtypes, m_targets, m_option_sets, begin, end, katoms);
}
}
void Machine::extract_klammer_definitions(katom_list katoms)
{
fmsg() << katoms << "\n";
(void)K::log(3);
for (const auto& [op, cl] : find_spans(katoms, begin_klammer_def, end_klammer_def, true, command_name)) {
expand_constant_klammers(katoms, op, cl);
auto [begin, end] = find_span_katoms(katoms, op, cl);
m_klammers.add(m_argtypes, m_targets, begin, end, katoms);
add_definition(katoms, op, cl);
}
m_klammers.rationalize(m_targets);
}
@@ -522,9 +550,7 @@ void Machine::extract_klammer_definitions()
{
(void)K::log(3);
for (const auto& [op, cl] : find_spans(m_katoms, begin_klammer_def, end_klammer_def, true, command_name)) {
expand_constant_klammers(m_katoms, op, cl);
auto [begin, end] = find_span_katoms(m_katoms, op, cl);
m_klammers.add(m_argtypes, m_targets, begin, end, m_katoms);
add_definition(m_katoms, op, cl);
}
m_klammers.rationalize(m_targets);
}