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:
100
mac/machine.cpp
100
mac/machine.cpp
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user