Klammerset: the @@@klammerset construct, its search path, and const correctness

The @@@klammerset system command formally declares a klammerset — a
named, logically related group of klammer definitions — with an
operative, idempotent declaration (:requires and :files load in order
at the declaration point, relative to the declaring file). A bare
symbol given to ktext -k, kdesc --input, or :requires resolves to
x/x.k on the search path: the document's directory, then
KLAMMERTEXT_KLAMMERSETS, then KLAMMERTEXT_HOME; kdesc --klammerset
lists the available sets. sks/sks.k is the first declared klammerset,
so `-k sks` loads the SKS by name. The engine's lookup classes were
renamed *_set → *_registry to keep the two concepts apart, and the
whole C++ tree now follows standard const-correctness conventions.
tst/ gains klammerset_test.sh (18 cases).

(from dev 64b1abf23e56)
This commit is contained in:
2026-07-30 23:50:07 +02:00
parent c42981f7e2
commit ef77f03584
83 changed files with 1429 additions and 594 deletions

View File

@@ -9,10 +9,10 @@
#include "eval.h"
Machine::Machine()
: m_argtypes(Argtype_set())
: m_argtypes(Argtype_registry())
, m_state(State())
, m_targets(Target_set())
, m_klammers(Klammer_set())
, m_targets(Target_registry())
, m_klammers(Klammer_registry())
{
(void)K::log(3);
m_state.add_environment_frame();
@@ -352,20 +352,80 @@ void Machine::extract_machine_definitions()
if (m_katoms.empty()) {
return;
}
for (const auto& [op, cl] : find_spans(m_katoms, begin_machine_def, end_machine_def, true, command_name)) {
auto [begin, end] = find_span_katoms(m_katoms, op, cl);
//std::string name = trim_char(begin->m_text, '@');
std::string name = begin->m_text;
if (name == "@@@target") {
m_targets.add(begin, end, m_katoms);
} else if (name == "@@@argtype") {
m_argtypes.add(begin, end, m_katoms);
} else if (name == "@@@state") {
m_state.parse_state_katoms(begin, end, m_katoms);
// A @@@klammerset declaration inserts its files' katoms into the stream
// at the declaration point, invalidating the span list, so the scan
// restarts. Processed spans are marked replaced and are never found
// again, which also bounds the restarts.
bool rescan = true;
while (rescan) {
rescan = false;
for (const auto& [op, cl] : find_spans(m_katoms, begin_machine_def, end_machine_def, true, command_name)) {
auto [begin, end] = find_span_katoms(m_katoms, op, cl);
//std::string name = trim_char(begin->m_text, '@');
std::string name = begin->m_text;
if (name == "@@@target") {
m_targets.add(begin, end, m_katoms);
} else if (name == "@@@argtype") {
m_argtypes.add(begin, end, m_katoms);
} else if (name == "@@@state") {
m_state.parse_state_katoms(begin, end, m_katoms);
} else if (name == "@@@klammerset") {
if (auto klammerset = m_klammersets.add(begin, end, m_katoms)) {
load_klammerset_files(*klammerset, end);
rescan = true;
break;
}
}
}
}
}
void Machine::load_klammerset_files(const Klammerset& klammerset, katom_iter insert_at)
{
(void)K::log(2, "Loading klammerset \"" + klammerset.m_symbol + "\"");
// Relative names resolve against the declaring file's directory, never
// the cwd. :requires files are read before the set's own files; each
// holds its own @@@klammerset declaration, whose already-loaded guard
// makes repeated requirements a no-op.
fs::path declaring(klammerset.m_loc.m_filename);
fs::path base = fs::exists(declaring) ? declaring : fs::current_path();
std::string base_dir = (is_directory(base) ? base : base.parent_path()).string();
// A :requires entry may be a bare symbol, resolved on the klammerset
// search path with the declaring directory as the local stage; :files
// entries are always filenames (this set's own definition files).
std::vector<std::string> filenames {};
for (const auto& required : klammerset.m_requires) {
if (is_klammerset_symbol(required)) {
filenames.push_back(
resolve_klammerset_symbol(required, base_dir, klammerset.m_loc).string());
} else {
filenames.push_back(required);
}
}
filenames.insert(filenames.end(), klammerset.m_files.begin(), klammerset.m_files.end());
// Collect all files into one list and insert once: insert_at is
// invalidated by the first insertion into m_katoms.
katom_list loaded {};
for (const auto& filename : filenames) {
fs::path pathname = resolve_relative_to(filename, base);
if (!fs::exists(pathname)) {
throw Klammerset_error(
"Klammerset \"" + klammerset.m_symbol + "\" lists the file \"" + filename
+ "\", which does not exist (resolved to \"" + pathname.string() + "\")",
klammerset.m_loc);
}
pathname = fs::canonical(pathname);
m_state.add_search_dir(pathname.parent_path().string());
std::string text = trim_right(string_from_file(pathname.string()));
katom_list ks = katomize(line_split(text), pathname);
process_katoms(ks, pathname);
loaded.insert(loaded.end(), ks.begin(), ks.end());
}
m_katoms.insert(insert_at, loaded.begin(), loaded.end());
}
void Machine::extract_klammer_definitions(katom_list katoms)
{
fmsg() << katoms << "\n";
@@ -489,12 +549,12 @@ katom_list Machine::apply_klammer(
return result;
}
void Machine::apply_klammer_set(
Klammer_set& klammer_set, katom_list& katoms, const std::string& target, katom_iter begin, katom_iter end)
void Machine::apply_klammer_registry(
Klammer_registry& klammer_registry, katom_list& katoms, const std::string& target, katom_iter begin, katom_iter end)
{
(void)K::log(3, "Klammer");
std::string name = trim_char(begin->m_text, '@');
katom_list applied_katoms = apply_klammer(klammer_set.m_klammers[name], target, begin, end);
katom_list applied_katoms = apply_klammer(klammer_registry.m_klammers[name], target, begin, end);
for (auto& k : applied_katoms) {
if (k.m_type == katom_t::bar || k.m_type == katom_t::double_bar || k.m_type == katom_t::option_name) {
k.m_type = katom_t::text;
@@ -504,16 +564,16 @@ void Machine::apply_klammer_set(
}
void Machine::apply(
Klammer_set& klammer_set, katom_list& katoms, const std::string& target)
Klammer_registry& klammer_registry, katom_list& katoms, const std::string& target)
{
(void)K::log(3, "Klammer_set");
(void)K::log(3, "Klammer_registry");
for (const auto& [op, cl] : find_spans(
katoms, begin_klammer_apply, end_klammer_apply, true, command_name)) {
auto [begin, end] = find_span_katoms(katoms, op, cl);
klammer_set.check_klammer(
klammer_registry.check_klammer(
klammer_name_from_katom(begin->m_text, begin->m_loc),
target, begin->m_loc);
apply_klammer_set(klammer_set, katoms, target, begin, end);
apply_klammer_registry(klammer_registry, katoms, target, begin, end);
}
}