diff --git a/README.md b/README.md index a4b2a16..61b44aa 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ are regenerated on each release — patches cannot be merged directly. Report problems (or send patches) to the author; accepted changes are applied to the development tree and appear in a following snapshot. -This snapshot was assembled from development commit `15b822f06ee0`. +This snapshot was assembled from development commit `64b1abf23e56`. ## License diff --git a/com/kdesc.cpp b/com/kdesc.cpp index 0168177..9ee660b 100644 --- a/com/kdesc.cpp +++ b/com/kdesc.cpp @@ -5,7 +5,8 @@ #include "font_store.h" #include "ktype.h" #include "log.h" -#include "argtype_set.h" +#include "argtype_registry.h" +#include "klammerset_registry.h" #include "character.h" #include "show.h" #include "util.h" @@ -32,6 +33,37 @@ static void font_usage() "and then in the default font set.\n"; } +static void klammerset_usage() +{ + std::cout << + "Klammerset commands:\n" + " --klammerset List the klammersets on the search path\n" + " --klammerset list The same\n" + " --klammerset help This description\n" + "\n" + "A klammerset symbol x names the declaration file x/x.k, searched for in:\n" + "the current directory (for ktext, the input document's directory), the\n" + "KLAMMERTEXT_KLAMMERSETS directories (colon-separated; default\n" + "$HOME/.klammertext/klammersets), and $KLAMMERTEXT_HOME. The first hit\n" + "wins, so a document-local klammerset shadows an installed one, which\n" + "shadows a distributed one.\n"; +} + +static void klammerset_command(const strings_t& words) +{ + std::string verb = words.empty() ? "list" : words[0]; + if (verb == "list") { + std::cout << boldblack << "Klammersets\n" << black + << describe_klammerset_search(fs::current_path().string()); + } else if (verb == "help") { + klammerset_usage(); + } else { + std::cout << "Unrecognized klammerset command: --klammerset " + << join(words, " ") << "\n\n"; + klammerset_usage(); + } +} + static void font_command(const strings_t& words) { std::string verb = words.empty() ? "list" : words[0]; @@ -70,13 +102,14 @@ int main(int argc, char* argv[]) args.flag("targets", "Show targets defined by the input file"); args.flag("klammers", "Show klammers defined by the input file"); args.var("font", "List installed fonts. Enter \"--font help\" for font maintenance commands."); + args.var("klammerset", "List the klammersets on the search path. Enter \"--klammerset help\" for details."); args.opt("v", "'verbosity'", "n", "0", "'verbosity'"); if (show_usage(argc, argv)) { args.usage(file_basename(argv[0])); exit(1); } - auto p = [&](std::string name) { return args.get(name) == "true"; }; + auto p = [&](const std::string& name) { return args.get(name) == "true"; }; args.parse(argc, argv); verbose_level = stoi(args.get("v")); @@ -90,7 +123,7 @@ int main(int argc, char* argv[]) } if (p("a")) { - Argtype_set argtypes; + Argtype_registry argtypes; std::cout << boldblack << "\nStandard klammer argument types\n" << black; std::cout << argtypes.describe() << "\n"; } @@ -116,6 +149,19 @@ int main(int argc, char* argv[]) return 0; } + // The --klammerset subcommands operate on the search path + // (filesystem enumeration) and load no klammer set. + if (args.given("klammerset")) { + strings_t words {}; + for (const std::string& w : args.as_vector("klammerset")) { + if (!w.empty()) { + words.push_back(w); + } + } + klammerset_command(words); + return 0; + } + Machine M; strings_t input_filenames = resolve_filename_list(args.get("input")); @@ -124,6 +170,13 @@ int main(int argc, char* argv[]) M.read(fs::path(M.m_state.value("KLAMMERTEXT_HOME") + "/sks/sks.k")); } else { for (auto fname : input_filenames) { + if (is_klammerset_symbol(fname)) { + // A bare symbol resolves on the klammerset search + // path; kdesc has no input document, so the local + // stage is the cwd. + fname = resolve_klammerset_symbol( + fname, fs::current_path().string(), Locator()).string(); + } std::cout << "Read " << fname << "\n"; M.read(fs::path(absolute_pathname(fname))); } diff --git a/com/kdiag.cpp b/com/kdiag.cpp index 6c87a83..5642380 100644 --- a/com/kdiag.cpp +++ b/com/kdiag.cpp @@ -45,7 +45,7 @@ int main(int argc, char* argv[]) args.usage(file_basename(argv[0])); exit(1); } - auto p = [&](std::string name) { return args.get(name) == "true"; }; + auto p = [&](const std::string& name) { return args.get(name) == "true"; }; args.parse(argc, argv); verbose_level = args.as_int("v"); diff --git a/com/ktext.cpp b/com/ktext.cpp index c361865..62e81bd 100644 --- a/com/ktext.cpp +++ b/com/ktext.cpp @@ -7,7 +7,8 @@ #include "util.h" #include "machine.h" #include "show.h" -#include "target_set.h" +#include "target_registry.h" +#include "klammerset_registry.h" int main(int argc, char* argv[]) { @@ -17,10 +18,10 @@ int main(int argc, char* argv[]) args.req("filenames", "Input files in Klammertext format. ", "'list'"); args.opt("s", "Text processed before input files.", "input-string", "", "'text'"); args.opt("t","Output target; default is general (unspecified)", "target", - Target_set::general_name, "'word'"); + Target_registry::general_name, "'word'"); args.opt("o", "Output basename; meaning and default defined by target.", "basename", "", "'word'"); - args.opt("k", "File containing the klammerset definition; default is the Standard Klammer Set. With a value of \"none\", no klammerset is loaded.", + args.opt("k", "Klammerset symbol (resolved on the klammerset search path) or the pathname of a klammerset definition file; default is the Standard Klammer Set. With a value of \"none\", no klammerset is loaded.", "pathname", "", "'word'"); args.flag("d", "Display the output to the screen, rather than writing files."); args.flag("m", "Show the Klammermachine state at the beginning of processing."); @@ -83,6 +84,12 @@ int main(int argc, char* argv[]) if (klammerset_filename != "none") { if (klammerset_filename.empty()) { klammerset_filename = M.m_state.value("KLAMMERTEXT_HOME") + "/sks/sks.k"; + } else if (is_klammerset_symbol(klammerset_filename)) { + // A bare symbol resolves on the klammerset search path; + // the local stage is the input document's directory (the + // cwd when the input is a string). + klammerset_filename = resolve_klammerset_symbol( + klammerset_filename, M.m_state.value("K_input_dir"), Locator()).string(); } K::log(1, "Reading klammerset filename: " + klammerset_filename); M.read(fs::path(klammerset_filename)); diff --git a/doc/edit/sublime/README.md b/doc/edit/sublime/README.md index ef6b26c..72f8217 100644 --- a/doc/edit/sublime/README.md +++ b/doc/edit/sublime/README.md @@ -151,6 +151,35 @@ in the package folder (its name is shown at **Preferences → Settings** under `color_scheme`), choosing a light or dark source file to match the ground. The exact values are in each file's header comment. +## Sublime Merge + +Sublime Merge reads the same `Packages` directory as Sublime Text, so the +package installed above needs no separate installation: `.kt` and `.k` files +are syntax-highlighted in Merge's diffs, and an edit to the syntax file is +picked up live, exactly as in the editor. + +Only the syntax file crosses over. Merge has no Python plugin host — it +ships no `plugin_host` binary — so none of this package's code runs there: + +| File | In Sublime Merge | +|------|------------------| +| `Klammertext.sublime-syntax` | Works. Delimiters and removed text are colored in diffs. | +| `Klammertext.py`, `Klammertext_indent.py`, `Klammertext_align.py` | Do not run: no plugin host. | +| `Default.sublime-keymap` | Inactive — it binds plugin commands. | +| `Comments.tmPreferences` | Inactive — Merge does not edit text. | +| `Breakers` / `Celeste` / `Mariana` / `Monokai` / `Sixteen` `.sublime-color-scheme` | Not used. They override Sublime Text's built-in schemes by name; Merge has its own. | + +So delimiter matching — **Ctrl+M** and the live highlight of the matching +delimiter — is a Sublime Text feature only. Merge colors the delimiters but +cannot match them: matching is context-sensitive code, not a syntax rule +(which is why it is a plugin in the first place). Merge's built-in bracket +matching does not stand in for it either; that matches literal `(`, `[`, `{` +characters, not `@name ... name@` runs. + +Merge colors the Klammertext scopes with its own scheme, so the hues differ +from the editor's — the token classes are distinguished, but the package's +five color schemes do not apply. + ## Keeping literal klammers in sync Klammers whose content is verbatim (`@code ... code@`) are listed in the diff --git a/mac/Makefile b/mac/Makefile index 59ec1fa..7c93fa4 100644 --- a/mac/Makefile +++ b/mac/Makefile @@ -8,9 +8,9 @@ include $(K)/env/makefile.env # Source files BASENAMES := util error locator file argv character ktype katom katom_list \ - log show command argument argument_set argtype argtype_set \ - state eval eval_python eval_cpp klammer klammer_set deftype \ - target target_set machine font_store + log show command argument argument_set argtype argtype_registry \ + state eval eval_python eval_cpp klammer klammer_registry klammerset klammerset_registry deftype \ + target target_registry machine font_store SOURCES := $(addsuffix .cpp,$(BASENAMES)) OBJECTS := $(addsuffix .o,$(BASENAMES)) diff --git a/mac/argtype.cpp b/mac/argtype.cpp index 877e373..632480b 100644 --- a/mac/argtype.cpp +++ b/mac/argtype.cpp @@ -6,9 +6,10 @@ #include "error.h" #include "util.h" -Argtype::Argtype(std::string name, std::string desc, std::string symbolic_pattern, std::string pattern, - std::string default_value, std::string alone_value, - std::string python_cast, modify_string_f python_format, +Argtype::Argtype(const std::string& name, const std::string& desc, const std::string& symbolic_pattern, + const std::string& pattern, + const std::string& default_value, const std::string& alone_value, + const std::string& python_cast, const modify_string_f& python_format, const Locator& loc) : m_name(name) , m_desc(desc) diff --git a/mac/argtype.h b/mac/argtype.h index 00e5913..9f850fd 100644 --- a/mac/argtype.h +++ b/mac/argtype.h @@ -25,9 +25,10 @@ public: , m_loc() {}; - Argtype(std::string name, std::string desc, std::string symbolic_pattern, std::string pattern, - std::string default_value, std::string alone_value, - std::string python_cast, modify_string_f python_format, + Argtype(const std::string& name, const std::string& desc, const std::string& symbolic_pattern, + const std::string& pattern, + const std::string& default_value, const std::string& alone_value, + const std::string& python_cast, const modify_string_f& python_format, const Locator& loc); std::string python_value(const std::string& var_name, std::vector value, size_t name_size); diff --git a/mac/argtype_set.cpp b/mac/argtype_registry.cpp similarity index 90% rename from mac/argtype_set.cpp rename to mac/argtype_registry.cpp index 71d0afd..d90ec39 100644 --- a/mac/argtype_set.cpp +++ b/mac/argtype_registry.cpp @@ -3,7 +3,7 @@ #include #include -#include "argtype_set.h" +#include "argtype_registry.h" #include "error.h" #include "show.h" #include "log.h" @@ -11,13 +11,13 @@ #include "character.h" #include "katom.h" -Parameter_set& Argtype_set::parameters() +Parameter_set& Argtype_registry::parameters() { static Parameter_set instance("name | desc :pattern .* :python_cast str :default :alone"); return instance; } -Argtype_set::Argtype_set() +Argtype_registry::Argtype_registry() { (void)(void)K::log(2); Locator loc = current_locator(); @@ -33,7 +33,7 @@ Argtype_set::Argtype_set() m_types["bool"].m_alone = "true"; } -std::string Argtype_set::replace_symbols(const std::string& pattern, const Locator& loc) +std::string Argtype_registry::replace_symbols(const std::string& pattern, const Locator& loc) { std::smatch match {}; std::regex symbol_pat(R"('(\w+)')"); @@ -54,7 +54,7 @@ std::string Argtype_set::replace_symbols(const std::string& pattern, const Locat return expanded; } -void Argtype_set::check_for_existing_definition( +void Argtype_registry::check_for_existing_definition( const std::string& name, const Locator& loc) { if (count(m_names.begin(), m_names.end(), name) > 0) { @@ -65,7 +65,7 @@ void Argtype_set::check_for_existing_definition( } } -void Argtype_set::add(const std::string& name, const std::string& desc, +void Argtype_registry::add(const std::string& name, const std::string& desc, const std::string& pattern, const std::string& default_value, const std::string& alone_value, const std::string& python_cast, modify_string_f python_format, @@ -130,15 +130,15 @@ void Argtype_set::add(const std::string& name, const std::string& desc, m_names.push_back(name); } -void Argtype_set::add(std::vector::iterator begin, std::vector::iterator end, std::vector& katoms) +void Argtype_registry::add(std::vector::iterator begin, std::vector::iterator end, std::vector& katoms) { (void)K::log(3); auto [positional, optional, rest] = - argument_split(begin + 1, end - 1); //, Argtype_set::parameters.m_positional.size()); + argument_split(begin + 1, end - 1); //, Argtype_registry::parameters.m_positional.size()); check_for_existing_definition(positional[0][0].m_text, begin->m_loc); - auto values = Argtype_set::parameters().value_map(positional, optional, rest, begin->m_loc); + auto values = Argtype_registry::parameters().value_map(positional, optional, rest, begin->m_loc); // std::for_each(begin, end+1, [](Katom& k) { k.m_type = katom_t::replaced; }); @@ -151,7 +151,7 @@ void Argtype_set::add(std::vector::iterator begin, std::vector::it ignore_whitespace(next_iter, katoms); } -Argtype Argtype_set::get(const std::string& name, const Locator& loc) const +Argtype Argtype_registry::get(const std::string& name, const Locator& loc) const { if (is_not_in(name, m_names)) { std::stringstream msg {}; @@ -162,7 +162,7 @@ Argtype Argtype_set::get(const std::string& name, const Locator& loc) const } -std::string Argtype_set::eval( +std::string Argtype_registry::eval( const std::string& value, const std::string& type_name, const Locator& loc) { std::regex re = m_types[type_name].m_regex; @@ -193,7 +193,7 @@ static std::string values_note(const Argtype& type) return note.str(); } -std::string Argtype_set::describe(bool long_form, int indent_width) const +std::string Argtype_registry::describe(bool long_form, int indent_width) const { std::string indent(' ', indent_width); std::size_t name_width = std::accumulate( diff --git a/mac/argtype_set.h b/mac/argtype_registry.h similarity index 96% rename from mac/argtype_set.h rename to mac/argtype_registry.h index 95954e9..777f28e 100644 --- a/mac/argtype_set.h +++ b/mac/argtype_registry.h @@ -8,12 +8,12 @@ #include "katom.h" #include "argument_set.h" -class Argtype_set +class Argtype_registry { public: static Parameter_set& parameters(); - Argtype_set(); + Argtype_registry(); std::string replace_symbols(const std::string& pattern, const Locator& loc); void check_for_existing_definition(const std::string& name, const Locator& loc); @@ -29,7 +29,7 @@ public: std::string eval(const std::string& value, const std::string& type_name, const Locator& loc); std::string describe(bool long_form=false, int indent_width=4) const; - inline bool is_defined(std::string name) { + inline bool is_defined(const std::string& name) const { return count(m_names.begin(), m_names.end(), name) > 0; } std::vector m_names {}; diff --git a/mac/argument.cpp b/mac/argument.cpp index 6d964ed..3f730e6 100644 --- a/mac/argument.cpp +++ b/mac/argument.cpp @@ -1,8 +1,8 @@ #include "argument.h" #include "argtype.h" -Parameter::Parameter(const std::string& name, Argtype argtype, const Locator& loc, - bool optional, std::string default_value) +Parameter::Parameter(const std::string& name, const Argtype& argtype, const Locator& loc, + bool optional, const std::string& default_value) : m_name(name) , m_argtype(argtype) , m_optional(optional) diff --git a/mac/argument.h b/mac/argument.h index 2fb5b9c..335f409 100644 --- a/mac/argument.h +++ b/mac/argument.h @@ -19,11 +19,10 @@ public: , m_target() {}; - Parameter(const std::string& name, Argtype argtype, const Locator& loc, - bool optional=false, std::string default_value = ""); + Parameter(const std::string& name, const Argtype& argtype, const Locator& loc, + bool optional=false, const std::string& default_value = ""); ~Parameter() = default; - std::string python_value(std::string value); bool undefined() const { return m_name == "_default"; }; std::string m_name {}; diff --git a/mac/argument_set.cpp b/mac/argument_set.cpp index 7d39234..a20a3b9 100644 --- a/mac/argument_set.cpp +++ b/mac/argument_set.cpp @@ -5,7 +5,7 @@ #include "show.h" #include "log.h" #include "katom.h" -#include "argtype_set.h" +#include "argtype_registry.h" #include "argument_set.h" #include "util.h" @@ -36,7 +36,7 @@ std::regex parameter_regex(bool optional=false) // rest(2): the base type is copied, its type parameter set, and its // display name extended, so kdesc signatures show rows.rest(2). static Argtype resolve_argtype( - const std::string& type_text, const Argtype_set& argtypes, const Locator& loc) + const std::string& type_text, const Argtype_registry& argtypes, const Locator& loc) { static const std::regex parameterized(R"((\w+)\((\d+)\))"); std::smatch match {}; @@ -58,7 +58,7 @@ static bool is_rest(const Argtype& argtype) Parameter_set::Parameter_set(const std::string parameter_string) { (void)K::log(3); - Argtype_set argtypes {}; + Argtype_registry argtypes {}; parse_parameters( katomize(line_split(parameter_string), Locator().str()), argtypes); @@ -69,11 +69,11 @@ Parameter_set::Parameter_set(const std::vector& katoms) : m_katoms(katoms) { (void)K::log(3); - Argtype_set argtypes {}; + Argtype_registry argtypes {}; parse_parameters(m_katoms, argtypes); } -Parameter_set::Parameter_set(const std::vector& katoms, const Argtype_set& argtypes) +Parameter_set::Parameter_set(const std::vector& katoms, const Argtype_registry& argtypes) : m_katoms(katoms) { (void)K::log(3); @@ -82,7 +82,7 @@ Parameter_set::Parameter_set(const std::vector& katoms, const Argtype_set // Parameter parsing -Parameter parse_positional_parameter(const katom_list& katoms, const Argtype_set& argtypes) +Parameter parse_positional_parameter(const katom_list& katoms, const Argtype_registry& argtypes) { // (void)K::log(3, katoms); if (katoms.size() > 1) { @@ -110,7 +110,7 @@ Parameter parse_positional_parameter(const katom_list& katoms, const Argtype_set } -Parameter parse_optional_parameter(const katom_list& katoms, const Argtype_set& argtypes) +Parameter parse_optional_parameter(const katom_list& katoms, const Argtype_registry& argtypes) { //(void)K::log(3); Katom k = katoms[0]; @@ -242,7 +242,7 @@ parameter_split(katom_list::const_iterator kbegin, katom_list::const_iterator ke return {positional, optional}; } -void Parameter_set::parse_parameters(const katom_list& katoms, const Argtype_set& argtypes) +void Parameter_set::parse_parameters(const katom_list& katoms, const Argtype_registry& argtypes) { (void)K::log(3, trim(katoms)); if (katoms.empty()) { @@ -274,10 +274,10 @@ void Parameter_set::parse_parameters(const katom_list& katoms, const Argtype_set } void describe_arguments( - std::string label, - std::vector> positional, - std::vector> optional, - std::vector rest) + const std::string& label, + const std::vector>& positional, + const std::vector>& optional, + const std::vector& rest) { std::cout << label << ":\n" << " positional: " << positional << "\n" diff --git a/mac/argument_set.h b/mac/argument_set.h index 4b424bf..7bbf4e7 100644 --- a/mac/argument_set.h +++ b/mac/argument_set.h @@ -7,7 +7,7 @@ #include "argument.h" #include "locator.h" -class Argtype_set; +class Argtype_registry; std::tuple>,std::vector>,std::vector> argument_split(std::vector::const_iterator kbegin, std::vector::const_iterator kend, @@ -20,9 +20,9 @@ public: ~Parameter_set() = default; Parameter_set(const std::string parameter_string); Parameter_set(const std::vector& katoms); - Parameter_set(const std::vector& katoms, const Argtype_set& argtypes); + Parameter_set(const std::vector& katoms, const Argtype_registry& argtypes); - void parse_parameters(const std::vector& katoms, const Argtype_set& argtypes); + void parse_parameters(const std::vector& katoms, const Argtype_registry& argtypes); void describe_parameters(); void check_positional( @@ -40,7 +40,7 @@ public: bool empty() const { return m_katoms.size() == 0; }; std::vector m_katoms {}; - //Argtype_set m_argtypes {}; + //Argtype_registry m_argtypes {}; std::vector m_positional {}; std::vector m_optional {}; std::vector m_optional_names {}; @@ -56,10 +56,10 @@ bool operator==(Parameter_set lhs, Parameter_set rhs); using Argument_set = Parameter_set; void describe_arguments( - std::string label, - std::vector> positional, - std::vector> optional, - std::vector rest); + const std::string& label, + const std::vector>& positional, + const std::vector>& optional, + const std::vector& rest); std::string replace_arguments( const std::map& values, diff --git a/mac/argv.cpp b/mac/argv.cpp index 43cfa32..cb13ea8 100644 --- a/mac/argv.cpp +++ b/mac/argv.cpp @@ -227,7 +227,7 @@ void Argv::usage(const std::string& command) } -void Argv::check_flags_and_options(std::string command, strings_t& words) +void Argv::check_flags_and_options(const std::string& command, strings_t& words) { std::vector not_defined {}; for (auto word : words) { @@ -334,10 +334,10 @@ void Argv::parse_optional(strings_t& words, string_map& named_args) // std::cout << "\n"; } -void Argv::parse_positional(std::string command, //strings_t words, +void Argv::parse_positional(const std::string& command, //strings_t words, std::string pos_args, string_map& named_args) { - for (std::string req : m_req_names) { + for (const std::string& req : m_req_names) { auto arg = m_args[req]; auto [substring, rest, found] = regex_split_prefix(arg.m_rgx, pos_args); if (!found) { diff --git a/mac/argv.h b/mac/argv.h index bfa5103..ba135ce 100644 --- a/mac/argv.h +++ b/mac/argv.h @@ -62,7 +62,7 @@ public: void update_width(Arg arg); - void check_flags_and_options(std::string command, std::vector& words); + void check_flags_and_options(const std::string& command, std::vector& words); void parse_flags(std::vector& words, std::map& named_args); void parse_optional(std::vector& words, std::map& named_args); void parse_vars(std::vector& words, std::map& named_args); @@ -72,7 +72,7 @@ public: bool given(const std::string& name) { return m_given.contains(name); }; void parse_positional( - std::string command, // std::vector words, + const std::string& command, // std::vector words, std::string pos_args, std::map& named_args); std::map classify_arguments(int argc, char* argv[], bool full_parse=true); @@ -96,11 +96,11 @@ public: void describe(); // void describe(Argv original); - bool is_flag(std::string name) { + bool is_flag(const std::string& name) const { return std::ranges::count(m_flag_names, name) > 0; } - bool is_opt(std::string name) { + bool is_opt(const std::string& name) const { return std::ranges::count(m_opt_names, name) > 0; } diff --git a/mac/basenames.mk b/mac/basenames.mk index a6347df..3132381 100644 --- a/mac/basenames.mk +++ b/mac/basenames.mk @@ -1 +1 @@ -BASENAMES := util error locator file argv character ktype katom katom_list log show command argument argument_set argtype argtype_set state eval eval_python eval_cpp klammer klammer_set target target_set machine +BASENAMES := util error locator file argv character ktype katom katom_list log show command argument argument_set argtype argtype_registry state eval eval_python eval_cpp klammer klammer_registry klammerset klammerset_registry target target_registry machine diff --git a/mac/error.h b/mac/error.h index 8b5147b..f15cf6c 100644 --- a/mac/error.h +++ b/mac/error.h @@ -10,8 +10,8 @@ inline std::string command_pathname { "Pathname of command executed on the comma class Error : std::exception { public: - Error(std::string error_type, std::string description, - Locator locator = Locator(), bool do_justify = true) + Error(const std::string& error_type, const std::string& description, + const Locator& locator = Locator(), bool do_justify = true) : m_type(error_type) , m_desc(description) , m_loc(locator) @@ -48,6 +48,13 @@ public: : Error("target", description, locator, do_justify) {}; }; +class Klammerset_error : public Error { +public: + explicit Klammerset_error( + const std::string& description, const Locator& locator=Locator(), bool do_justify=true) + : Error("klammerset", description, locator, do_justify) {}; +}; + class Definition_error : public Error { public: explicit Definition_error( diff --git a/mac/eval.h b/mac/eval.h index 454881b..87be4c6 100644 --- a/mac/eval.h +++ b/mac/eval.h @@ -14,7 +14,7 @@ enum class eval_t { class Eval { public: - explicit Eval(Machine& machine, Locator loc) + explicit Eval(Machine& machine, const Locator& loc) : m_machine(machine), m_loc(loc) {}; diff --git a/mac/eval_cpp.cpp b/mac/eval_cpp.cpp index ee20c26..9181a40 100644 --- a/mac/eval_cpp.cpp +++ b/mac/eval_cpp.cpp @@ -7,14 +7,14 @@ #include "file.h" #include "show.h" -Eval_cpp::Eval_cpp(Machine& machine, Locator loc) +Eval_cpp::Eval_cpp(Machine& machine, const Locator& loc) : m_machine(machine) , m_loc(loc) { (void)K::log(3); } -std::string Eval_cpp::eval(fs::path library_path, std::string function_name) +std::string Eval_cpp::eval(const fs::path& library_path, const std::string& function_name) { (void)K::log(3, library_path, function_name); // msg() << "library path: " << library_path.string().c_str() << "\n"; diff --git a/mac/eval_cpp.h b/mac/eval_cpp.h index 76943e1..e2d503e 100644 --- a/mac/eval_cpp.h +++ b/mac/eval_cpp.h @@ -7,12 +7,12 @@ class Eval_cpp { public: - explicit Eval_cpp(Machine& machine, Locator loc); + explicit Eval_cpp(Machine& machine, const Locator& loc); Eval_cpp(const Eval_cpp&) = delete; Eval_cpp& operator=(const Eval_cpp&) = delete; //~Eval_cpp(); - std::string eval(fs::path library_path, std::string function_name); + std::string eval(const fs::path& library_path, const std::string& function_name); Machine m_machine {}; Locator m_loc; diff --git a/mac/eval_python.cpp b/mac/eval_python.cpp index 0dcfea6..10564a2 100644 --- a/mac/eval_python.cpp +++ b/mac/eval_python.cpp @@ -5,7 +5,7 @@ std::regex Eval_python::statement_delimiter("\\s*;\\s*"); -Eval_python::Eval_python(Machine& machine, Locator loc) +Eval_python::Eval_python(Machine& machine, const Locator& loc) : m_machine(machine) , m_loc(loc) , m_globals(nullptr) @@ -93,7 +93,7 @@ strings_t Eval_python::parse_modules(std::string code) return modules; } -void Eval_python::import_module(std::string module_name, bool verify) +void Eval_python::import_module(const std::string& module_name, bool verify) { (void)K::log(3, module_name); @@ -176,12 +176,12 @@ std::string Eval_python::get_result(PyObject* result_object) return result; } -std::string Eval_python::eval_expression(std::string expression, bool import_modules) +std::string Eval_python::eval_expression(const std::string& expression, bool import_modules) { (void)K::log(3, expression); // msg() << "expression: " << expression << "\n"; if (import_modules && expression.find('.') != std::string::npos) { - for (auto m : parse_modules(expression)) { + for (const auto& m : parse_modules(expression)) { import_module(m); } } @@ -191,7 +191,7 @@ std::string Eval_python::eval_expression(std::string expression, bool import_mod Py_eval_input, m_globals, m_locals)); } -std::string Eval_python::eval_statements(std::string script) +std::string Eval_python::eval_statements(const std::string& script) { (void)K::log(3); strings_t statements = regex_split(script, statement_delimiter); diff --git a/mac/eval_python.h b/mac/eval_python.h index 292cd32..ad00f7d 100644 --- a/mac/eval_python.h +++ b/mac/eval_python.h @@ -9,16 +9,16 @@ class Eval_python { public: static std::regex statement_delimiter; - explicit Eval_python(Machine& machine, Locator loc); + explicit Eval_python(Machine& machine, const Locator& loc); Eval_python(const Eval_python&) = delete; Eval_python& operator=(const Eval_python&) = delete; ~Eval_python(); void add_module_path(const std::string& path); std::vector parse_modules(std::string code); - void import_module(std::string module_name, bool verify = true); + void import_module(const std::string& module_name, bool verify = true); std::string get_result(PyObject* result_object); - std::string eval_expression(std::string expression, bool import_modules = true); - std::string eval_statements(std::string script); + std::string eval_expression(const std::string& expression, bool import_modules = true); + std::string eval_statements(const std::string& script); std::string eval(std::string code); //std::string eval_katom_list(const katom_iter& begin, const katom_iter& end); std::string eval_katom_list( diff --git a/mac/file.cpp b/mac/file.cpp index c0972ec..420d1b6 100644 --- a/mac/file.cpp +++ b/mac/file.cpp @@ -440,7 +440,7 @@ strings_t get_sks_directories(const std::string& s, bool include_argument) return result; } -std::string cache_directory(std::string subdirectory, std::string parent_directory) +std::string cache_directory(const std::string& subdirectory, std::string parent_directory) { if (parent_directory.empty()) { // /dev/shm is a fast RAM-backed tmpfs on Linux; it does not exist on @@ -475,7 +475,7 @@ bool in_modification_order(std::string filename1, std::string filename2) } } -void write_to_cache(std::string cache_dir, std::string basename, std::string text) +void write_to_cache(const std::string& cache_dir, const std::string& basename, const std::string& text) { if (!file_exists(cache_dir)) { //std::cout << "Creating cache directory: " << cache_dir << "\n"; @@ -486,14 +486,14 @@ void write_to_cache(std::string cache_dir, std::string basename, std::string tex string_to_file(output_filename, text); } -std::string read_from_cache(std::string cache_dir, std::string basename) +std::string read_from_cache(const std::string& cache_dir, const std::string& basename) { std::string input_filename = cache_dir + "/" + basename; // msg() << "Reading file from cache: " << input_filename << "\n"; return string_from_file(input_filename); } -bool cache_requires_update(std::string cache_dir, std::string file_to_cache, std::string basename) +bool cache_requires_update(const std::string& cache_dir, const std::string& file_to_cache, const std::string& basename) { std::string cache_filename = cache_dir + "/" + basename; return !in_modification_order(file_to_cache, cache_filename); @@ -662,11 +662,12 @@ void copy_file_stream(const fs::path& src, const fs::path& dst) } void copy_preserving_basename( - strings_t filenames, std::string output_directory, std::string link_directory) + const strings_t& filenames, const std::string& output_directory, + const std::string& link_directory) { fs::path outdir(output_directory + "/" + link_directory); fs::create_directories(outdir); - for (std::string filename : filenames) { + for (const std::string& filename : filenames) { fs::path pname(filename); auto out_path = outdir / pname.filename(); // Preserve the previous copy_options::update_existing behavior: skip diff --git a/mac/file.h b/mac/file.h index d69666d..888e4bb 100644 --- a/mac/file.h +++ b/mac/file.h @@ -45,12 +45,12 @@ fs::path klammertext_filename( const std::string& basename, bool error_if_missing=true, bool make_directory_if_missing=false); std::vector sks_dirs(); std::vector get_sks_directories(const std::string& s, bool include_argument=true); -std::string cache_directory(std::string subdirectory, std::string parent_directory=""); +std::string cache_directory(const std::string& subdirectory, std::string parent_directory=""); std::time_t to_time_t(const fs::file_time_type& ftime); bool in_modification_order(std::string filename1, std::string filename2); -void write_to_cache(std::string cache_dir, std::string basename, std::string text); -std::string read_from_cache(std::string cache_dir, std::string basename); -bool cache_requires_update(std::string cache_dir, std::string file_to_cache, std::string basename); +void write_to_cache(const std::string& cache_dir, const std::string& basename, const std::string& text); +std::string read_from_cache(const std::string& cache_dir, const std::string& basename); +bool cache_requires_update(const std::string& cache_dir, const std::string& file_to_cache, const std::string& basename); std::vector pathnames_with_extension( const fs::path& dir, const std::string extension @@ -73,6 +73,7 @@ bool files_differ(const fs::path& p1, void copy_file_stream(const fs::path& src, const fs::path& dst); void copy_preserving_basename( - std::vector filenames, std::string output_directory, std::string link_directory); + const std::vector& filenames, const std::string& output_directory, + const std::string& link_directory); fs::path resolve_relative_to(const fs::path& relative, const fs::path& base=std::filesystem::current_path()); diff --git a/mac/font_store.cpp b/mac/font_store.cpp index 3326aef..97a9b18 100644 --- a/mac/font_store.cpp +++ b/mac/font_store.cpp @@ -36,7 +36,7 @@ static std::string lower_extension(const fs::path& path) } -std::string name_to_dirname(std::string name) +std::string name_to_dirname(const std::string& name) { std::string result {}; for (char c : name) { @@ -206,7 +206,7 @@ static void extract_font_metrics(Resolved_font& font) } } -Resolved_font resolve_font(std::string family_name) +Resolved_font resolve_font(const std::string& family_name) { if (family_name.empty()) return {}; diff --git a/mac/font_store.h b/mac/font_store.h index 73269a8..5e4ee49 100644 --- a/mac/font_store.h +++ b/mac/font_store.h @@ -19,7 +19,7 @@ struct Resolved_font { float capheight_ratio = 0.0f; // cap-height / unitsPerEm from OS/2 table }; -std::string name_to_dirname(std::string name); +std::string name_to_dirname(const std::string& name); // Directories searched for installed fonts (KLAMMERTEXT_FONTS, default // ~/.klammertext/fonts); the default font set is searched after them. std::vector installed_font_dirs(); @@ -27,7 +27,7 @@ std::vector installed_font_dirs(); std::string default_font_dir(); // Every installable font family found across those directories. std::vector available_font_families(); -Resolved_font resolve_font(std::string family_name); +Resolved_font resolve_font(const std::string& family_name); void install_resolved_font(const Resolved_font& font, std::string output_dir); // One font file classified by its internal metadata (name table, OS/2). diff --git a/mac/katom.cpp b/mac/katom.cpp index 5599021..9f869cd 100644 --- a/mac/katom.cpp +++ b/mac/katom.cpp @@ -281,7 +281,7 @@ katom_list trim(const katom_list& katoms, bool trim_inactive) return trim(result, trim_types); } -strings_t line_split(std::string s) +strings_t line_split(const std::string& s) { std::istringstream is(s); strings_t result {}; @@ -293,7 +293,7 @@ strings_t line_split(std::string s) return result; } -std::pair line_split(fs::path pathname) +std::pair line_split(const fs::path& pathname) { std::string source {}; strings_t lines {}; diff --git a/mac/katom.h b/mac/katom.h index 2e1d8f2..6de9c09 100644 --- a/mac/katom.h +++ b/mac/katom.h @@ -99,8 +99,8 @@ std::vector trim(const std::vector& katoms, bool trim_inactive = f std::vector> bar_split(std::vector::iterator kbegin, std::vector::iterator kend); -std::vector line_split(std::string s); -std::pair> line_split(fs::path pathname); +std::vector line_split(const std::string& s); +std::pair> line_split(const fs::path& pathname); std::vector katomize(const std::vector& lines, const std::string& source_desc); void warn_unparsed_katoms(std::vector& katoms, bool warn = true); diff --git a/mac/katom_list.cpp b/mac/katom_list.cpp index e204555..e822149 100644 --- a/mac/katom_list.cpp +++ b/mac/katom_list.cpp @@ -181,10 +181,10 @@ void check_named_katom_span(const Katom& begin, const Katom& end) spans_t find_spans( katom_iter begin, katom_iter end, - std::function level_inc, - std::function level_dec, + const std::function& level_inc, + const std::function& level_dec, bool error_exit, - std::string name) + const std::string& name) { (void)K::log(4, name); bool _dbg = false; @@ -245,10 +245,10 @@ spans_t find_spans( spans_t find_spans( katom_list& katoms, - std::function level_inc, - std::function level_dec, + const std::function& level_inc, + const std::function& level_dec, bool error_exit, - std::string name) + const std::string& name) { return find_spans(katoms.begin(), katoms.end(), level_inc, level_dec, error_exit, name); } diff --git a/mac/katom_list.h b/mac/katom_list.h index 06b5d47..7b4f2cd 100644 --- a/mac/katom_list.h +++ b/mac/katom_list.h @@ -23,17 +23,17 @@ find_katom(const std::vector::iterator begin, const std::vector::i std::vector> find_spans(std::vector::iterator begin, std::vector::iterator end, - std::function level_inc, - std::function level_dec, + const std::function& level_inc, + const std::function& level_dec, bool error_exit, - std::string name); + const std::string& name); std::vector> find_spans(std::vector& katoms, - std::function level_inc, - std::function level_dec, + const std::function& level_inc, + const std::function& level_dec, bool error_exit=true, - std::string name="all"); + const std::string& name="all"); void describe_spans(const std::vector& katoms); diff --git a/mac/klammer.cpp b/mac/klammer.cpp index 76352e5..60176f6 100644 --- a/mac/klammer.cpp +++ b/mac/klammer.cpp @@ -13,7 +13,7 @@ using namespace std::literals; std::regex Klammer::name_re = std::regex(R"((\w+)(?:\.(\w+))?)"); std::tuple -parse_name(Target_set targets, Katom name_katom) +parse_name(const Target_registry& targets, const Katom& name_katom) { std::string name_with_target = trim_char(name_katom.m_text, '@'); std::smatch match {}; @@ -29,7 +29,7 @@ parse_name(Target_set targets, Katom name_katom) std::string klammer_name = match[1]; std::string target_name = match[2]; if (target_name.empty()) { - target_name = Target_set::general_name; + target_name = Target_registry::general_name; } if (!targets.has(target_name)) { throw Target_error( @@ -41,7 +41,7 @@ parse_name(Target_set targets, Katom name_katom) } std::tuple -parse_definition_katoms(std::string klammer_name, Argtype_set argtypes, katom_iter& begin, katom_iter& end) +parse_definition_katoms(const std::string& klammer_name, const Argtype_registry& argtypes, katom_iter& begin, katom_iter& end) { (void)K::log(3, *begin, *(end - 1)); katom_iter deftype = std::find_if( @@ -84,7 +84,7 @@ parse_definition_katoms(std::string klammer_name, Argtype_set argtypes, katom_it } void Klammer::add_target_definition( - std::string target_name, Argtype_set argtypes, katom_iter begin, katom_iter end) + const std::string& target_name, const Argtype_registry& argtypes, katom_iter begin, katom_iter end) { (void)K::log(3, *begin, *(end-1)); auto [deftype, parameters, body, loc] = @@ -95,7 +95,7 @@ void Klammer::add_target_definition( std::regex variable_re(R"(\*(\w+)\*)"); int i = 0; variable_map_t varmap {}; - for (auto k : body) { + for (const auto& k : body) { std::smatch match {}; std::string txt = k.m_text; while (std::regex_search(txt, match, variable_re) && @@ -127,23 +127,23 @@ void Klammer::remove_target_definition(const std::string& target_name) // Rationalize multiple definitions -std::string error_list(std::string label, auto components, std::string after="") +std::string error_list(const std::string& label, const auto& components, const std::string& after="") { std::stringstream ss {}; ss << label << ":\n"; - for (auto c : components) { + for (const auto& c : components) { ss << " " << c.loc.desc() << "\n"; } ss << after; return ss.str(); } -auto Klammer::target_defs(std::vector target_names) +auto Klammer::target_defs(const std::vector& target_names) { std::vector defs {}; - for (auto target : target_names) { + for (const auto& target : target_names) { auto target_defs = collect_if( - m_defs, [target](const auto& def) { return def.target == target; }); + m_defs, [&target](const auto& def) { return def.target == target; }); defs.insert(defs.end(), target_defs.begin(), target_defs.end()); } return defs; @@ -173,7 +173,7 @@ void Klammer::disallow_instances() //Klammer::components declaration) } } -bool Klammer::copy_to_instances(Target_set targets) +bool Klammer::copy_to_instances(const Target_registry& targets) { auto instances = instance_defs(); if (!instances.empty()) { @@ -202,19 +202,20 @@ bool Klammer::copy_to_instances(Target_set targets) } void Klammer::copy_components( - Parameter_set parameters, std::vector cs, Target_set targets) + const Parameter_set& parameters, const std::vector& cs, + const Target_registry& targets) { (void)K::log(4); - for (auto target_name : targets.m_names) { - if (target_name == Target_set::declare_name || - target_name == Target_set::general_name) { + for (const auto& target_name : targets.m_names) { + if (target_name == Target_registry::declare_name || + target_name == Target_registry::general_name) { continue; } m_parameters = parameters; } - for (auto c : cs) { + for (const auto& c : cs) { m_body[c.target] = c.body; - m_body_generic[c.target] = (c.target == Target_set::general_name); + m_body_generic[c.target] = (c.target == Target_registry::general_name); m_varmap[c.target] = c.varmap; } } @@ -223,7 +224,7 @@ void Klammer::copy_components( void Klammer::check_for_multiple_general_klammers() { - auto general_klammers = target_defs({Target_set::general_name}); + auto general_klammers = target_defs({Target_registry::general_name}); if (general_klammers.size() > 1) { throw Definition_error( error_list( @@ -235,11 +236,11 @@ void Klammer::check_for_multiple_general_klammers() void Klammer::check_for_declaration_and_definitions() { - auto declares = target_defs({Target_set::declare_name}); + auto declares = target_defs({Target_registry::declare_name}); if (!declares.empty()) { std::vector definitions {}; - for (auto def : m_defs) { - if (def.target != Target_set::declare_name) { + for (const auto& def : m_defs) { + if (def.target != Target_registry::declare_name) { if (def.deftype == katom_t::klammer_definition || def.deftype == katom_t::klammer_default) { msg() << def << "\n"; @@ -261,11 +262,11 @@ void Klammer::check_for_declaration_and_definitions() // If a general definition exists, use it for targets not defined, but check signatures -void Klammer::copy_general_klammer_to_undefined(Target_set targets) +void Klammer::copy_general_klammer_to_undefined(const Target_registry& targets) { (void)K::log(4); - auto general_klammers = target_defs({Target_set::general_name}); - auto declares = target_defs({Target_set::declare_name}); + auto general_klammers = target_defs({Target_registry::general_name}); + auto declares = target_defs({Target_registry::declare_name}); // Check matching signatures (though this case already handled) if (general_klammers.size() == 1) { @@ -279,13 +280,13 @@ void Klammer::copy_general_klammer_to_undefined(Target_set targets) m_parameters.m_katoms[0].m_loc, false); } } - auto [target, deftype, parameters, body, varmap, loc] = general_klammers[0]; + const auto& [target, deftype, parameters, body, varmap, loc] = general_klammers[0]; if (m_parameters.m_katoms.empty()) { m_parameters = parameters; } - for (auto target_name : targets.m_names) { + for (const auto& target_name : targets.m_names) { // std::cout << "General copy, considering " << target_name << "\n"; - if (m_body.count(target_name) == 0 && target_name != Target_set::declare_name) { + if (m_body.count(target_name) == 0 && target_name != Target_registry::declare_name) { // std::cout << " Copying to " << target_name << "\n"; m_body[target_name] = body; m_body_generic[target_name] = true; // general body -> writer content @@ -298,7 +299,7 @@ void Klammer::copy_general_klammer_to_undefined(Target_set targets) // Three declaration cases: none, one, many -void Klammer::no_declarations(Target_set targets) +void Klammer::no_declarations(const Target_registry& targets) { (void)K::log(4); // std::cout << boldblack << "No declarations\n" << black; @@ -308,7 +309,7 @@ void Klammer::no_declarations(Target_set targets) std::vector target_names = targets.applicable(); std::vector all_parameter_sets {}; // Are all parameters the same? - for (auto def : m_defs) { + for (const auto& def : m_defs) { if (std::ranges::find(target_names, def.target) != target_names.end()) { // std::cout << " Found: " << def.target << "\n"; all_parameter_sets.push_back(def.parameters); @@ -332,7 +333,7 @@ void Klammer::no_declarations(Target_set targets) copy_general_klammer_to_undefined(targets); } -void Klammer::one_declaration(Target_set targets, Klammer::components declare) +void Klammer::one_declaration(const Target_registry& targets, const Klammer::components& declare) { (void)K::log(4); // std::cout << boldblack << "One declaration\n" << black; @@ -342,7 +343,7 @@ void Klammer::one_declaration(Target_set targets, Klammer::components declare) copy_general_klammer_to_undefined(targets); } -void Klammer::many_declarations(std::vector declares) +void Klammer::many_declarations(const std::vector& declares) { (void)K::log(4); // std::cout << boldblack << "Many declarations\n" << black; @@ -353,10 +354,10 @@ void Klammer::many_declarations(std::vector declares) -void Klammer::rationalize(Target_set targets) +void Klammer::rationalize(const Target_registry& targets) { (void)K::log(3, m_name); - auto declares = target_defs({Target_set::declare_name}); + auto declares = target_defs({Target_registry::declare_name}); auto declare_count = declares.size(); if (declare_count == 0) { disallow_instances(); @@ -371,7 +372,7 @@ void Klammer::rationalize(Target_set targets) } -std::string klammer_name_from_katom(std::string s, Locator loc) +std::string klammer_name_from_katom(const std::string& s, const Locator& loc) { std::regex rgx(R"(@(\w+).*)"); std::smatch match {}; @@ -389,11 +390,11 @@ void label(const std::string& s) std::cout << std::right << std::setw(w) << std::setfill(' ') << s << ": "; } -void show_args(const std::string& label_text, std::vector arguments) +void show_args(const std::string& label_text, const std::vector& arguments) { if (!arguments.empty()) { label(label_text); - for (auto a : arguments) { + for (const auto& a : arguments) { std::cout << a << " "; } std::cout << '\n'; @@ -403,7 +404,7 @@ void show_args(const std::string& label_text, std::vector arguments) strings_t Klammer::get_target_names() const { strings_t names {}; - for (auto [target, body] : m_body) { + for (const auto& [target, body] : m_body) { std::stringstream ss {}; // ss << name << target.m_loc.m_line; ss << target; @@ -422,12 +423,12 @@ strings_t Klammer::get_locations() return {}; } -std::string Klammer::signature_text() +std::string Klammer::signature_text() const { std::string result {}; bool has_pos = false; bool has_opt = false; - for (auto pos : m_parameters.m_positional) { + for (const auto& pos : m_parameters.m_positional) { result += pos.m_name; std::string type = pos.m_argtype.m_name; if (type != default_argtype) { @@ -442,7 +443,7 @@ std::string Klammer::signature_text() if (opt_count <= 3 && !has_pos) { result += " "; } - for (auto opt : m_parameters.m_optional) { + for (const auto& opt : m_parameters.m_optional) { if (opt_count > 3) { result += "\n :" + opt.m_name; } else { @@ -473,18 +474,18 @@ std::string Klammer::signature_text() } -std::string Klammer::description_text() +std::string Klammer::description_text() const { std::string result = " [" + m_name + ": no description]"; if (m_body.contains("k")) { - result = to_string(m_body["k"], true); + result = to_string(m_body.at("k"), true); result = justify(result, 80, 1); } return result; } -std::string Klammer::describe(int margin) +std::string Klammer::describe(int margin) const { std::string result {}; result += "@" + m_name + signature_text() + description_text(); diff --git a/mac/klammer.h b/mac/klammer.h index e6e4628..1e17987 100644 --- a/mac/klammer.h +++ b/mac/klammer.h @@ -4,7 +4,7 @@ #include "deftype.h" #include "argument_set.h" -#include "target_set.h" +#include "target_registry.h" #include "locator.h" class Klammer @@ -31,37 +31,38 @@ public: // target-name -> [variable -> index] void add_target_definition( - std::string target_name, Argtype_set argtypes, + const std::string& target_name, const Argtype_registry& argtypes, std::vector::iterator begin, std::vector::iterator end); void remove_target_definition(const std::string& target_name); - auto target_defs(std::vector target_names); + auto target_defs(const std::vector& target_names); auto instance_defs(); void disallow_instances(); //Klammer::components declaration); - bool copy_to_instances(Target_set targets); + bool copy_to_instances(const Target_registry& targets); void copy_components( - Parameter_set parameters, std::vector cs, Target_set targets); + const Parameter_set& parameters, const std::vector& cs, + const Target_registry& targets); void check_for_multiple_general_klammers(); void check_for_declaration_and_definitions(); - void copy_general_klammer_to_undefined(Target_set targets); - void no_declarations(Target_set targets); - void one_declaration(Target_set targets, Klammer::components declare); - void many_declarations(std::vector declares); - void rationalize(Target_set target); + void copy_general_klammer_to_undefined(const Target_registry& targets); + void no_declarations(const Target_registry& targets); + void one_declaration(const Target_registry& targets, const Klammer::components& declare); + void many_declarations(const std::vector& declares); + void rationalize(const Target_registry& targets); /* void add_description(const std::string& desc, Katom definition_type); auto user_defs(); auto klammer_defines_parameters(); auto klammer_uses_parameters(); - void check_for_target_errors(Target_set targets); + void check_for_target_errors(Target_registry targets); bool explicit_parameters_match(); - void copy_components(Klammer::components cs, Target_set targets); + void copy_components(Klammer::components cs, Target_registry targets); */ - std::string signature_text(); - std::string description_text(); - std::string describe(int margin=0); + std::string signature_text() const; + std::string description_text() const; + std::string describe(int margin=0) const; bool has_literal_param() const { for (const auto& p : m_parameters.m_positional) @@ -91,18 +92,18 @@ public: std::map m_body_generic {}; }; -std::string klammer_name_from_katom(std::string s, Locator loc); +std::string klammer_name_from_katom(const std::string& s, const Locator& loc); std::tuple -parse_name(Target_set targets, Katom name_katom); +parse_name(const Target_registry& targets, const Katom& name_katom); std::tuple, Locator> -parse_definition_katoms(Argtype_set argtypes, //Target_set targets, +parse_definition_katoms(const std::string& klammer_name, const Argtype_registry& argtypes, std::vector::iterator& begin, std::vector::iterator& end); /* klammer_definition_args parse_klammer_definition_katoms( - katom_list& katoms, Argtype_set& argtypes); + katom_list& katoms, Argtype_registry& argtypes); void check_for_undefined_arguments( std::string name, Parameters parameters, katom_list body_katoms, Locator loc); diff --git a/mac/klammer_set.cpp b/mac/klammer_registry.cpp similarity index 80% rename from mac/klammer_set.cpp rename to mac/klammer_registry.cpp index 0e7c51f..bf50cfd 100644 --- a/mac/klammer_set.cpp +++ b/mac/klammer_registry.cpp @@ -1,18 +1,18 @@ #include "klammer.h" -#include "klammer_set.h" +#include "klammer_registry.h" #include "show.h" #include "util.h" #include "log.h" #include "error.h" /* -bool Klammer_set::has(std::string name, std::string target) +bool Klammer_registry::has(std::string name, std::string target) { return m_klammers.count(name) > 0; } */ -void Klammer_set::add(Argtype_set argtypes, Target_set& targets, katom_iter begin, katom_iter end, katom_list& katoms) +void Klammer_registry::add(const Argtype_registry& argtypes, const Target_registry& targets, katom_iter begin, katom_iter end, katom_list& katoms) { (void)K::log(3, *begin, *(end - 1)); restore_initial_type(begin, end); @@ -62,7 +62,7 @@ void Klammer_set::add(Argtype_set argtypes, Target_set& targets, katom_iter begi // This add's target: Target target = targets.get(target_name, begin->m_loc); if (!target.m_provides.empty()) { - for (auto provide_name : target.m_provides) { + for (const auto& provide_name : target.m_provides) { if (m_klammers[klammer_name].m_defloc.count(provide_name) > 0) { m_klammers[klammer_name].remove_target_definition(provide_name); } @@ -80,30 +80,30 @@ void Klammer_set::add(Argtype_set argtypes, Target_set& targets, katom_iter begi ignore_whitespace(next_iter, katoms); } -void Klammer_set::rationalize(Target_set targets) +void Klammer_registry::rationalize(const Target_registry& targets) { (void)K::log(3); - for (auto k : m_klammers) { - m_klammers[k.first].rationalize(targets); + for (auto& [name, klammer] : m_klammers) { + klammer.rationalize(targets); } } /* -bool Klammer_set::has(std::string name, std::string target) +bool Klammer_registry::has(std::string name, std::string target) { return m_klammers.count(name) > 0; } */ -void Klammer_set::check_klammer(std::string name, std::string target, Locator loc) +void Klammer_registry::check_klammer(const std::string& name, const std::string& target, const Locator& loc) const { if (m_klammers.count(name) == 0) { throw Definition_error("The klammer " + q_(name) + " is not defined for an unspecified target", loc); } - Klammer k = m_klammers[name]; + const Klammer& k = m_klammers.at(name); if (k.m_defloc.count(target) == 0) { std::string desc; - if (target == Target_set::general_name) { + if (target == Target_registry::general_name) { desc = "an unspecified target"; } else { desc = "target " + q_(target); @@ -113,7 +113,7 @@ void Klammer_set::check_klammer(std::string name, std::string target, Locator lo } -const std::vector* Klammer_set::constant_body(const std::string& name) const +const std::vector* Klammer_registry::constant_body(const std::string& name) const { auto it = m_klammers.find(name); if (it == m_klammers.end()) return nullptr; @@ -126,14 +126,14 @@ const std::vector* Klammer_set::constant_body(const std::string& name) co if (!d.parameters.empty()) return nullptr; } for (const auto& d : k.m_defs) { - if (d.target == Target_set::general_name && d.parameters.empty()) { + if (d.target == Target_registry::general_name && d.parameters.empty()) { return &d.body; } } return nullptr; } -int max_length(std::map ss) +int max_length(const std::map& ss) { size_t result = 0; for_each(ss.begin(), ss.end(), @@ -141,19 +141,19 @@ int max_length(std::map ss) return result; } -std::string Klammer_set::instance_list(int margin) const +std::string Klammer_registry::instance_list(int margin) const { std::stringstream ss {}; std::string tab(margin, ' '); auto name_width = max_length(m_klammers); - for (auto [name, k] : m_klammers) { + for (const auto& [name, k] : m_klammers) { ss << tab << std::setfill(' ') << std::setw(name_width) << name << sp_arrow << k << "\n"; } return ss.str(); } -std::string Klammer_set::describe(int margin) const +std::string Klammer_registry::describe(int margin) const { /* strings_t names {}; @@ -161,7 +161,7 @@ std::string Klammer_set::describe(int margin) const strings_t locations {}; */ std::string result; - for (auto [name, k] : m_klammers) { + for (const auto& [name, k] : m_klammers) { result += k.describe(margin) + "\n"; /* names.push_back(name); diff --git a/mac/klammer_set.h b/mac/klammer_registry.h similarity index 54% rename from mac/klammer_set.h rename to mac/klammer_registry.h index 5b6f829..75c6f2e 100644 --- a/mac/klammer_set.h +++ b/mac/klammer_registry.h @@ -1,16 +1,16 @@ #pragma once #include "klammer.h" -#include "target_set.h" +#include "target_registry.h" -class Klammer_set +class Klammer_registry { public: - Klammer_set() = default; - void add(Argtype_set argtypes, Target_set& targets, + Klammer_registry() = default; + void add(const Argtype_registry& argtypes, const Target_registry& targets, std::vector::iterator begin, std::vector::iterator end, std::vector& katoms); - void rationalize(Target_set targets); - void check_klammer(std::string name, std::string target, Locator loc); + void rationalize(const Target_registry& targets); + void check_klammer(const std::string& name, const std::string& target, const Locator& loc) const; const std::vector* constant_body(const std::string& name) const; std::string instance_list(int margin) const; std::string describe(int margin=0) const; diff --git a/mac/klammerset.cpp b/mac/klammerset.cpp new file mode 100644 index 0000000..933ad80 --- /dev/null +++ b/mac/klammerset.cpp @@ -0,0 +1,8 @@ +#include "klammerset.h" + +Klammerset::Klammerset(const std::string& symbol, const std::string& desc, const Locator& loc) + : m_symbol(symbol) + , m_desc(desc) + , m_loc(loc) +{ +} diff --git a/mac/klammerset.h b/mac/klammerset.h new file mode 100644 index 0000000..c971d16 --- /dev/null +++ b/mac/klammerset.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#include "locator.h" + +// A Klammerset is the formal construct declared by the @@@klammerset system +// command: a named, logically related group of klammer definitions loaded +// together. The instance holds metadata and the file list only -- the +// klammers themselves live in the Machine's Klammer_registry (one flat, +// additive namespace; the definition modes govern collisions). Membership +// is provenance, not containment. +class Klammerset +{ +public: + Klammerset() = default; + Klammerset(const std::string& symbol, const std::string& desc, const Locator& loc); + + std::string m_symbol {}; // registry key and command-line name (e.g. "sks") + std::string m_desc {}; // the logical relationship that makes this a set + std::string m_name {}; // display name (e.g. "Standard Klammer Set") + std::string m_author {}; + std::string m_date {}; // last update; a date serves as the version + std::vector m_requires {}; // klammerset declaration files, loaded first + std::vector m_files {}; // definition files, loaded in list order + Locator m_loc {}; // the declaring file; relative names resolve against it +}; diff --git a/mac/klammerset_registry.cpp b/mac/klammerset_registry.cpp new file mode 100644 index 0000000..da5e007 --- /dev/null +++ b/mac/klammerset_registry.cpp @@ -0,0 +1,225 @@ +#include +#include +#include +#include + +#include "klammerset_registry.h" +#include "error.h" +#include "file.h" +#include "log.h" +#include "util.h" +#include "show.h" +#include "katom.h" + +Klammerset_registry::Klammerset_registry() + : m_parameters(Parameter_set("symbol | desc :name :author :date :requires :files")) +{ +} + +void Klammerset_registry::add(Klammerset klammerset) +{ + (void)K::log(3, klammerset.m_symbol); + m_klammersets[klammerset.m_symbol] = klammerset; + m_symbols.push_back(klammerset.m_symbol); +} + +std::optional Klammerset_registry::add( + std::vector::iterator begin, std::vector::iterator end, std::vector& katoms) +{ + (void)K::log(3, *begin, *(end - 1)); + auto [positional, optional, rest] = + argument_split(begin + 1, end - 1, m_parameters.m_positional.size()); + auto values = m_parameters.value_map(positional, optional, rest, begin->m_loc); + + modify_type(katom_t::replaced, begin, end); + auto next_iter = end; + ignore_whitespace(next_iter, katoms); + + std::string symbol = values["symbol"]; + check_symbol(symbol, begin->m_loc); + if (has(symbol)) { + (void)K::log(2, "Klammerset \"" + symbol + "\" is already loaded; declaration skipped"); + return std::nullopt; + } + + // The filename lists follow the standard conventions (spaces allowed, + // standalone "/" separator). The existence rescue tests names against + // the declaring file's directory, where relative names are later + // resolved by Machine::load_klammerset_files. + fs::path declaring(begin->m_loc.m_filename); + std::string base_dir = + fs::exists(declaring) ? declaring.parent_path().string() : ""; + + Klammerset klammerset(symbol, values["desc"], begin->m_loc); + klammerset.m_name = values["name"]; + klammerset.m_author = values["author"]; + klammerset.m_date = values["date"]; + klammerset.m_requires = resolve_filename_list(values["requires"], base_dir); + klammerset.m_files = resolve_filename_list(values["files"], base_dir); + add(klammerset); + return klammerset; +} + +void Klammerset_registry::check_symbol(const std::string& symbol, const Locator& loc) const +{ + bool valid = !symbol.empty() && std::isalpha(static_cast(symbol[0])); + for (char c : symbol) { + if (!std::isalnum(static_cast(c)) && c != '_') { + valid = false; + } + } + if (!valid) { + throw Klammerset_error( + "The klammerset symbol \"" + symbol + "\" is not valid. A symbol begins " + "with a letter and contains only letters, digits, and underscores.", + loc); + } +} + +bool Klammerset_registry::has(const std::string& symbol) const +{ + return m_klammersets.count(symbol) > 0; +} + +Klammerset Klammerset_registry::get(const std::string& symbol, const Locator& loc) const +{ + if (has(symbol)) { + return m_klammersets.at(symbol); + } else { + throw Klammerset_error("Klammerset " + symbol + " does not exist", loc); + } +} + +// --- The klammerset search path --- + +bool is_klammerset_symbol(const std::string& name) +{ + if (name.empty() || !std::isalpha(static_cast(name[0]))) { + return false; + } + for (char c : name) { + if (!std::isalnum(static_cast(c)) && c != '_') { + return false; + } + } + return true; +} + +std::vector klammerset_search_dirs(const std::string& local_dir) +{ + std::vector result {}; + // A repeated directory (e.g. the local stage already IS + // $KLAMMERTEXT_HOME) adds nothing and clutters error messages. + auto push_unique = [&result](const std::string& dir) { + std::string canonical = fs::weakly_canonical(dir).string(); + if (!is_in(canonical, result)) { + result.push_back(canonical); + } + }; + if (!local_dir.empty()) { + push_unique(local_dir); + } + std::string paths {}; + const char* env = std::getenv("KLAMMERTEXT_KLAMMERSETS"); + if (env && *env) { + paths = env; + } else if (const char* home = std::getenv("HOME"); home && *home) { + paths = std::string(home) + "/.klammertext/klammersets"; + } + std::stringstream ss(paths); + std::string dir; + while (std::getline(ss, dir, ':')) { + if (!dir.empty()) { + push_unique(dir); + } + } + if (const char* kthome = std::getenv(klammertext_home_var.c_str()); kthome && *kthome) { + push_unique(kthome); + } + return result; +} + +fs::path resolve_klammerset_symbol( + const std::string& symbol, const std::string& local_dir, const Locator& loc) +{ + std::vector dirs = klammerset_search_dirs(local_dir); + for (const std::string& dir : dirs) { + fs::path candidate = fs::path(dir) / symbol / (symbol + ".k"); + if (fs::exists(candidate) && fs::is_regular_file(candidate)) { + return fs::weakly_canonical(candidate); + } + } + throw Klammerset_error( + "The klammerset \"" + symbol + "\" was not found. A symbol x names the " + "declaration file x/x.k in one of the search directories: " + + join(dirs, ", ") + + ". Enter \"kdesc --klammerset\" to list the available klammersets.", + loc); +} + +std::string describe_klammerset_search(const std::string& local_dir, int margin) +{ + std::string tab(margin, ' '); + std::stringstream ss {}; + std::map first_hit {}; + for (const std::string& dir : klammerset_search_dirs(local_dir)) { + if (!fs::is_directory(dir)) { + continue; + } + for (const auto& entry : fs::directory_iterator(dir)) { + if (!entry.is_directory()) { + continue; + } + std::string symbol = entry.path().filename().string(); + fs::path declaration = entry.path() / (symbol + ".k"); + if (!is_klammerset_symbol(symbol) || !fs::is_regular_file(declaration)) { + continue; + } + ss << tab << symbol << sp_arrow << declaration.string(); + if (first_hit.count(symbol)) { + ss << " (shadowed by " << first_hit[symbol] << ")"; + } else { + first_hit[symbol] = declaration.string(); + } + ss << "\n"; + } + } + if (first_hit.empty()) { + ss << tab << "(no klammersets found)\n"; + } + return ss.str(); +} + +std::string Klammerset_registry::describe(int margin, bool long_format) const +{ + std::string tab(margin, ' '); + std::stringstream ss {}; + std::vector descs {}; + for (const std::string& symbol : m_symbols) { + descs.push_back(m_klammersets.at(symbol).m_desc); + } + auto symbol_width = max_length(m_symbols); + auto desc_width = max_length(descs); + for (const std::string& symbol : m_symbols) { + const Klammerset& ks = m_klammersets.at(symbol); + if (long_format) { + ss << tab << std::setfill(' ') << std::setw(symbol_width) << std::left << symbol << " " + << std::setw(desc_width) << std::left << ks.m_desc << " " + << ks.m_loc.str() << "\n"; + if (!ks.m_name.empty()) + ss << tab << std::string(symbol_width, ' ') << " name: " << ks.m_name << "\n"; + if (!ks.m_author.empty()) + ss << tab << std::string(symbol_width, ' ') << " author: " << ks.m_author << "\n"; + if (!ks.m_date.empty()) + ss << tab << std::string(symbol_width, ' ') << " date: " << ks.m_date << "\n"; + if (!ks.m_requires.empty()) + ss << tab << std::string(symbol_width, ' ') << " requires: " << join(ks.m_requires, " / ") << "\n"; + if (!ks.m_files.empty()) + ss << tab << std::string(symbol_width, ' ') << " files: " << join(ks.m_files, " / ") << "\n"; + } else { + ss << tab << std::setfill(' ') << std::setw(symbol_width) << std::left << symbol + << sp_arrow << ks << "\n"; + } + } + return ss.str(); +} diff --git a/mac/klammerset_registry.h b/mac/klammerset_registry.h new file mode 100644 index 0000000..e59dfe6 --- /dev/null +++ b/mac/klammerset_registry.h @@ -0,0 +1,63 @@ +#pragma once +#include +#include +#include + +#include "klammerset.h" +#include "argument_set.h" +#include "katom.h" + +class Klammerset_registry +{ +public: + Klammerset_registry(); + + void add(Klammerset klammerset); + // Parse a @@@klammerset span. Returns the new Klammerset so the + // Machine can load its files, or nullopt when the symbol is already + // registered: a klammerset is loaded once, and a repeated declaration + // (typically reached through :requires) is skipped, not an error. + std::optional add(std::vector::iterator begin, std::vector::iterator end, std::vector& katoms); + void check_symbol(const std::string& symbol, const Locator& loc) const; + + bool has(const std::string& symbol) const; + Klammerset get(const std::string& symbol, const Locator& loc) const; + + std::string describe(int margin=2, bool long_format=false) const; + + std::map m_klammersets {}; + std::vector m_symbols {}; + Parameter_set m_parameters {}; +}; + +// --- The klammerset search path (symbol -> declaration file) --- + +// A bare identifier (letters, digits, underscores; starts with a letter) +// names a klammerset symbol; anything else -- a path component, an +// extension, a space -- is a filename used as given. +bool is_klammerset_symbol(const std::string& name); + +// The directories searched for a klammerset symbol, most specific first: +// 1. local_dir -- the directory of whatever names the symbol: the input +// document's directory (ktext -k), the declaring file's directory +// (:requires), or the cwd when there is no document +// 2. the KLAMMERTEXT_KLAMMERSETS directories (colon-separated; default +// ~/.klammertext/klammersets), in listed order +// 3. $KLAMMERTEXT_HOME (the distribution's sets, e.g. sks/sks.k) +// A symbol x resolves to the first /x/x.k found, so a document-local +// set shadows an installed one, which shadows a distributed one. (This is +// deliberately the OPPOSITE order from the @eval module path, which puts +// the SKS directories first: a stray util.py next to a document shadowing +// an SKS module is an everyday accident, while a directory named sks/ +// holding an sks.k next to a manuscript is not.) +std::vector klammerset_search_dirs(const std::string& local_dir); + +// Resolve a symbol to its declaration file; first hit wins. Throws a +// Klammerset_error naming the searched directories when nothing matches. +fs::path resolve_klammerset_symbol( + const std::string& symbol, const std::string& local_dir, const Locator& loc); + +// The symbols available on the search path, with provenance; a symbol +// found again in a later directory is marked as shadowed. For +// kdesc --klammerset. +std::string describe_klammerset_search(const std::string& local_dir, int margin=2); diff --git a/mac/locator.cpp b/mac/locator.cpp index 1aeaed8..01a98c4 100644 --- a/mac/locator.cpp +++ b/mac/locator.cpp @@ -28,7 +28,7 @@ std::string abbreviate_location( } -Locator::Locator(fs::path filename, int line, int chr) +Locator::Locator(const fs::path& filename, int line, int chr) : m_filename(filename) , m_line(line) , m_chr(chr) diff --git a/mac/locator.h b/mac/locator.h index 78b8659..95b6589 100644 --- a/mac/locator.h +++ b/mac/locator.h @@ -23,7 +23,7 @@ public: , m_line(int(location.line())) , m_chr(int(location.column())) {}; - Locator(fs::path filename, int line, int chr); + Locator(const fs::path& filename, int line, int chr); std::string str(bool relative = false) const; std::string desc(bool relative = false) const; std::string abbrev(bool include_chr=true) const; diff --git a/mac/machine.cpp b/mac/machine.cpp index 9434dc1..7beb73c 100644 --- a/mac/machine.cpp +++ b/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 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); } } diff --git a/mac/machine.h b/mac/machine.h index 3e938d2..e26d8ad 100644 --- a/mac/machine.h +++ b/mac/machine.h @@ -4,9 +4,10 @@ // #include "source.h" #include "katom_list.h" -#include "klammer_set.h" -#include "target_set.h" -#include "argtype_set.h" +#include "klammer_registry.h" +#include "klammerset_registry.h" +#include "target_registry.h" +#include "argtype_registry.h" #include "state.h" #include "error.h" @@ -20,11 +21,12 @@ public: Machine(); // Copy constructor - Machine(const Machine& other) + Machine(const Machine& other) : m_argtypes(other.m_argtypes) , m_state(other.m_state) , m_targets(other.m_targets) , m_klammers(other.m_klammers) + , m_klammersets(other.m_klammersets) , m_result(other.m_result) {} @@ -35,6 +37,7 @@ public: m_state = other.m_state; m_targets = other.m_targets; m_klammers = other.m_klammers; + m_klammersets = other.m_klammersets; m_result = other.m_result; } return *this; @@ -65,6 +68,7 @@ public: bool klammers=true, bool eval=true, bool cond=true, bool read=true); void expand_constant_klammers(katom_list& katoms, const Katom& op, const Katom& cl); + void load_klammerset_files(const Klammerset& klammerset, katom_iter insert_at); void extract_machine_definitions(); void extract_klammer_definitions(); void extract_klammer_definitions(katom_list katoms); @@ -72,18 +76,19 @@ public: katom_list apply_klammer(Klammer& klammer, const std::string& target, katom_iter arguments_begin, katom_iter arguments_end); - void apply_klammer_set(Klammer_set& klammer_set, + void apply_klammer_registry(Klammer_registry& klammer_registry, katom_list& katoms, const std::string& target, katom_iter begin, katom_iter end); - void apply(Klammer_set& klammer_set, katom_list& katoms, const std::string& target); + void apply(Klammer_registry& klammer_registry, katom_list& katoms, const std::string& target); std::string run_phase_functions(); std::string apply(const std::string& target_name, bool final_processing=true, bool escape_characters=true); - Argtype_set m_argtypes {}; + Argtype_registry m_argtypes {}; State m_state {}; - Target_set m_targets {}; - Klammer_set m_klammers {}; + Target_registry m_targets {}; + Klammer_registry m_klammers {}; + Klammerset_registry m_klammersets {}; input_sources_t m_sources {}; std::string m_result {}; std::vector m_katoms {}; diff --git a/mac/show.cpp b/mac/show.cpp index ab27a16..2b6e405 100644 --- a/mac/show.cpp +++ b/mac/show.cpp @@ -461,12 +461,12 @@ std::ostream& operator<<(std::ostream& os, const Klammer::components& kc) } -// Klammer_set +// Klammer_registry -std::ostream& operator<<(std::ostream& os, const Klammer_set& ks) +std::ostream& operator<<(std::ostream& os, const Klammer_registry& ks) { - for (auto klam : ks.m_klammers) { - for (auto [k,v] : klam.second.m_defloc) { + for (const auto& klam : ks.m_klammers) { + for (const auto& [k,v] : klam.second.m_defloc) { os << " " << k << sp_arrow << v << "\n"; } //klam.second.m_defloc.str() << "\n"; @@ -485,30 +485,62 @@ void show_arrow_pair(std::ostream& os, std::pair transf std::ostream& operator<<(std::ostream& os, const Target& t) { os << "<\U0001D517" << broken_bar << t.m_name << broken_bar << t.m_desc << broken_bar; - for (auto i : t.m_includes) { + for (const auto& i : t.m_includes) { os << i << right_arrow << t.m_name << broken_bar; } - for (auto p : t.m_provides) { + for (const auto& p : t.m_provides) { os << t.m_name << right_arrow << p << broken_bar; } os << ">"; return os; } -// Target_set +// Target_registry -std::ostream& operator<<(std::ostream& os, const Target_set& ts) +std::ostream& operator<<(std::ostream& os, const Target_registry& ts) { size_t width = 0; - for (auto t : ts.m_targets) { + for (const auto& t : ts.m_targets) { width = std::max(width, t.first.size()); } - for (auto [name, target] : ts.m_targets) { + for (const auto& [name, target] : ts.m_targets) { os << std::setw(width) << name << sp_arrow << target << "\n"; } return os; } +// Klammerset + +std::ostream& operator<<(std::ostream& os, const Klammerset& ks) +{ + os << "<\U0001D516" << broken_bar << ks.m_symbol << broken_bar << ks.m_desc; + if (!ks.m_date.empty()) { + os << broken_bar << ks.m_date; + } + if (!ks.m_requires.empty()) { + os << broken_bar << "requires " << join(ks.m_requires, " / "); + } + if (!ks.m_files.empty()) { + os << broken_bar << join(ks.m_files, " / "); + } + os << ">"; + return os; +} + +// Klammerset_registry + +std::ostream& operator<<(std::ostream& os, const Klammerset_registry& kr) +{ + size_t width = 0; + for (const auto& k : kr.m_klammersets) { + width = std::max(width, k.first.size()); + } + for (const auto& [symbol, klammerset] : kr.m_klammersets) { + os << std::setw(width) << symbol << sp_arrow << klammerset << "\n"; + } + return os; +} + // Machine @@ -537,6 +569,7 @@ std::ostream& operator<<(std::ostream& os, const Machine& m) std::string argtypes_desc = m.m_argtypes.describe(false, 8); std::string state_desc = m.m_state.describe(false, 3); std::string targets_desc = m.m_targets.describe(4); + std::string klammersets_desc = m.m_klammersets.describe(4); std::string klammer_desc = m.m_klammers.describe(2); std::string source_desc = describe_sources(m); @@ -544,12 +577,13 @@ std::ostream& operator<<(std::ostream& os, const Machine& m) << label("Sources", m.m_sources.size()) << source_desc << "\n" << label("Argtypes", m.m_argtypes.m_names.size()) << argtypes_desc << "\n" << label("Targets", m.m_targets.m_names.size()) << targets_desc << "\n" + << label("Klammersets", m.m_klammersets.m_symbols.size()) << klammersets_desc << "\n" << label("Klammers", m.m_klammers.m_klammers.size()) << klammer_desc << "\n" - << label("State", m.m_state.m_frames.size()) << state_desc; + << label("State", m.m_state.m_frames.size()) << state_desc; return os; } -void modify_stream(std::string name) +void modify_stream(const std::string& name) { if (name == "all") std::cout << kall; if (name == "type") std::cout << ktype; diff --git a/mac/show.h b/mac/show.h index c1e01c1..d5cbee5 100644 --- a/mac/show.h +++ b/mac/show.h @@ -8,9 +8,10 @@ #include "argtype.h" #include "argument.h" #include "klammer.h" -#include "klammer_set.h" +#include "klammer_registry.h" +#include "klammerset_registry.h" #include "state.h" -#include "target_set.h" +#include "target_registry.h" #include "machine.h" #include "file.h" @@ -143,16 +144,22 @@ std::ostream& operator<<(std::ostream& os, const Klammer::variable_map_t& vm); // Klammer::components std::ostream& operator<<(std::ostream& os, const Klammer::components& kc); -// Klammer_set -std::ostream& operator<<(std::ostream& os, const Klammer_set& ks); +// Klammer_registry +std::ostream& operator<<(std::ostream& os, const Klammer_registry& ks); // Target std::ostream& operator<<(std::ostream& os, const Target& t); -// Target_set -std::ostream& operator<<(std::ostream& os, const Target_set& ts); +// Target_registry +std::ostream& operator<<(std::ostream& os, const Target_registry& ts); + +// Klammerset +std::ostream& operator<<(std::ostream& os, const Klammerset& ks); + +// Klammerset_registry +std::ostream& operator<<(std::ostream& os, const Klammerset_registry& kr); // Machine std::ostream& operator<<(std::ostream& os, const Machine& m); -void modify_stream(std::string name); +void modify_stream(const std::string& name); diff --git a/mac/state.cpp b/mac/state.cpp index 6023567..c8e2be6 100644 --- a/mac/state.cpp +++ b/mac/state.cpp @@ -10,7 +10,7 @@ int State::class_id = 0; -bool Var::defined() +bool Var::defined() const { return !m_name.empty(); } @@ -24,18 +24,19 @@ std::vector Frame::names() const return result; } -void Frame::set(std::string name, std::string value, - std::string delim, std::string desc, Locator loc, Argtype argtype) +void Frame::set(const std::string& name, const std::string& value, + const std::string& delim, const std::string& desc, const Locator& loc, + const Argtype& argtype) { Var v(name, value, delim, desc, loc, argtype); m_vars[name] = v; } -std::pair Frame::get(std::string name) +std::pair Frame::get(const std::string& name) const { std::pair result {Var(), false}; if (m_vars.contains(name)) { - result = {m_vars[name], true}; + result = {m_vars.at(name), true}; } return result; } @@ -43,7 +44,7 @@ std::pair Frame::get(std::string name) // State -void State::open_frame(std::string name) +void State::open_frame(const std::string& name) { Frame f(name); // m_frames.push_back(f); @@ -58,19 +59,20 @@ void State::close_frame() } // Preserve altered machine state: string_map machine_state {}; - for (auto [name, var] : m_frames[0].m_vars) { + for (const auto& [name, var] : m_frames[0].m_vars) { if (contains(name, "K_")) { machine_state[name] = var.m_value; } } m_frames.erase(m_frames.begin()); - for (auto [name, value] : machine_state) { + for (const auto& [name, value] : machine_state) { set(name, value, true); } } -void State::set(std::string name, std::string value, bool update, - std::string delim, std::string desc, Locator loc, Argtype argtype) +void State::set(const std::string& name, const std::string& value, bool update, + const std::string& delim, const std::string& desc, const Locator& loc, + const Argtype& argtype) { if (m_frames.empty()) { std::stringstream ss {}; @@ -89,9 +91,9 @@ void State::set(std::string name, std::string value, bool update, m_frames[0].set(name, value, delim, desc, loc, argtype); } -void State::set(std::map varmap) +void State::set(const std::map& varmap) { - for (auto [k, v] : varmap) { + for (const auto& [k, v] : varmap) { set(k, v); } } @@ -107,7 +109,7 @@ void State::set(const std::map& varmap, } -void State::replace(std::string name, std::string value, bool error_if_not_defined) +void State::replace(const std::string& name, const std::string& value, bool error_if_not_defined) { if (error_if_not_defined && !get(name).defined()) { std::stringstream ss {}; @@ -120,14 +122,14 @@ void State::replace(std::string name, std::string value, bool error_if_not_defin void State::add_environment_frame() { open_frame(klammerstate::shell_environment_name); - for (auto [name, value] : environment_variables()) { + for (const auto& [name, value] : environment_variables()) { set(name, value); } } -Var State::get(std::string name, bool error_if_not_defined, Locator loc) +Var State::get(const std::string& name, bool error_if_not_defined, const Locator& loc) const { - for (auto f : m_frames) { + for (const auto& f : m_frames) { auto [result, found] = f.get(name); if (found) { return result; @@ -141,12 +143,12 @@ Var State::get(std::string name, bool error_if_not_defined, Locator loc) } } -std::string State::value(std::string name, bool error_if_not_defined, Locator loc) +std::string State::value(const std::string& name, bool error_if_not_defined, const Locator& loc) const { return get(name, error_if_not_defined, loc).m_value; } -std::string State::subst(std::string text, bool quote_values) +std::string State::subst(const std::string& text, bool quote_values) const { (void)K::log(3); std::string result = text; @@ -198,7 +200,8 @@ void State::subst(katom_iter begin, katom_iter end) } void prohibit_change_of_description( - std::string name, bool defined, std::string old_desc, std::string new_desc, Locator old_loc, Locator loc) + const std::string& name, bool defined, const std::string& old_desc, + const std::string& new_desc, const Locator& old_loc, const Locator& loc) { if (defined && !old_desc.empty() && !new_desc.empty()) { std::stringstream ss {}; @@ -216,7 +219,7 @@ void prohibit_change_of_description( // Parameter_set m_parameters = Parameter_set("name :value :append :replace :delim :desc"); -void State::parse_state_katoms(katom_iter begin, katom_iter end, katom_list katoms) +void State::parse_state_katoms(katom_iter begin, katom_iter end, katom_list& katoms) { (void)K::log(3, *begin, *(end-1)); // std::cout << "parse_katoms: " << std::pair(begin + 1, end - 1) << "\n"; @@ -246,11 +249,11 @@ void State::parse_state_katoms(katom_iter begin, katom_iter end, katom_list kato ignore_whitespace(next_iter, katoms); } -std::vector State::all_names() +std::vector State::all_names() const { std::vector result {}; - for (Frame f : m_frames) { - for (auto [name, var] : f.m_vars) { + for (const Frame& f : m_frames) { + for (const auto& [name, var] : f.m_vars) { // std::cout << "Name: " << name << "\n"; result.push_back(name); } @@ -282,7 +285,7 @@ std::string State::python_code() // the file whose @eval names it is found regardless of the cwd. python_dirs.insert(python_dirs.end(), m_search_dirs.begin(), m_search_dirs.end()); - for (auto d : python_dirs) { + for (const auto& d : python_dirs) { auto python_files = pathnames_with_extension(d, "py"); if (!python_files.empty()) { ss << "sys.path.append('" << d << "')\n"; @@ -308,12 +311,12 @@ std::string State::describe(bool show_environment, int margin_size) const std::string margin(margin_size, ' '); int i = m_frames.size() - 1; std::stringstream ss {}; - for (auto f : m_frames) { + for (const auto& f : m_frames) { int width = max_key_length(f.m_vars); ss << margin << "Frame " << i-- << ": " << f.m_name << "\n"; if ((f.m_name != klammerstate::shell_environment_name) || (show_environment && f.m_name == klammerstate::shell_environment_name)) { - for (auto [key, value] : f.m_vars) { + for (const auto& [key, value] : f.m_vars) { std::string print_value = value.m_value; if (print_value == klammerstate::no_value) { print_value = ""; diff --git a/mac/state.h b/mac/state.h index 2d17e0c..cf0ebdb 100644 --- a/mac/state.h +++ b/mac/state.h @@ -14,9 +14,9 @@ class Var { public: Var() = default; - Var(std::string name, std::string value=klammerstate::no_value, - std::string delim=":", std::string desc="", Locator loc=Locator(), - Argtype argtype=Argtype()) + Var(const std::string& name, const std::string& value=klammerstate::no_value, + const std::string& delim=":", const std::string& desc="", const Locator& loc=Locator(), + const Argtype& argtype=Argtype()) : m_name(name) , m_value(value) , m_delim(delim) @@ -24,7 +24,7 @@ public: , m_loc(loc) , m_argtype(argtype) {}; - bool defined(); + bool defined() const; std::string m_name {}; std::string m_value {}; @@ -41,15 +41,15 @@ inline std::string shell_environment_name = "Shell environment"; class Frame { public: - Frame(std::string name) + Frame(const std::string& name) : m_name(name) {}; std::vector names() const; - void set(std::string name, std::string value, - std::string delim=":", std::string desc="", Locator loc=Locator(), - Argtype argtype=Argtype()); - std::pair get(std::string name); + void set(const std::string& name, const std::string& value, + const std::string& delim=":", const std::string& desc="", const Locator& loc=Locator(), + const Argtype& argtype=Argtype()); + std::pair get(const std::string& name) const; std::string m_name {}; std::map m_vars {}; @@ -59,24 +59,24 @@ class State { public: static int class_id; - void open_frame(std::string name); + void open_frame(const std::string& name); void close_frame(); - void set(std::string name, std::string value, bool update=false, - std::string delim=" ", std::string desc="", Locator loc=Locator(), - Argtype argtype=Argtype()); - void set(std::map varmap); + void set(const std::string& name, const std::string& value, bool update=false, + const std::string& delim=" ", const std::string& desc="", const Locator& loc=Locator(), + const Argtype& argtype=Argtype()); + void set(const std::map& varmap); void set(const std::map& varmap, const Parameter_set& parameters); - void replace(std::string name, std::string value, bool error_if_not_defined=true); + void replace(const std::string& name, const std::string& value, bool error_if_not_defined=true); void add_environment_frame(); - Var get(std::string name, bool error_if_not_defined=false, Locator loc=Locator()); - std::string value(std::string name, bool error_if_not_defined=true, Locator loc=Locator()); + Var get(const std::string& name, bool error_if_not_defined=false, const Locator& loc=Locator()) const; + std::string value(const std::string& name, bool error_if_not_defined=true, const Locator& loc=Locator()) const; - std::string subst(std::string text, bool quote_values=false); + std::string subst(const std::string& text, bool quote_values=false) const; void subst(std::vector::iterator begin, std::vector::iterator end); - void parse_state_katoms(std::vector::iterator begin, std::vector::iterator end, katom_list katoms); - std::vector all_names(); + void parse_state_katoms(std::vector::iterator begin, std::vector::iterator end, katom_list& katoms); + std::vector all_names() const; void add_search_dir(const std::string& dir); std::string python_code(); std::string describe(bool show_environment=false, int margin_size=2) const; diff --git a/mac/target.cpp b/mac/target.cpp index ea70a49..959c555 100644 --- a/mac/target.cpp +++ b/mac/target.cpp @@ -7,32 +7,32 @@ //#include "text.h" #include "util.h" -void Target::add_transform(std::string original, std::string transformed) +void Target::add_transform(const std::string& original, const std::string& transformed) { m_transforms.push_back({original, transformed}); } -void Target::add_transforms(std::string transforms) +void Target::add_transforms(const std::string& transforms) { add_transforms(parse_transforms(transforms)); } -void Target::add_transforms(string_pairs transforms) +void Target::add_transforms(const string_pairs& transforms) { - for (auto [old_str, new_str] : transforms) { + for (const auto& [old_str, new_str] : transforms) { add_transform(old_str, new_str); } } -void Target::transform(katom_list& katoms) +void Target::transform(katom_list& katoms) const { (void)K::log(3); std::for_each( - katoms.begin(), katoms.end(), - [this] (Katom& k) { + katoms.begin(), katoms.end(), + [this] (Katom& k) { // std::cout << "transform: " << k << "\n"; if (k.m_type != katom_t::literal) { - for (auto [a, b] : this->m_transforms) { + for (const auto& [a, b] : this->m_transforms) { // std::cout << " " << a << right_arrow << b << "\n"; k.m_text = string_replace(k.m_text, a, b); } @@ -41,7 +41,7 @@ void Target::transform(katom_list& katoms) } std::vector> -parse_transforms(std::string transform_string) +parse_transforms(const std::string& transform_string) { (void)K::log(3); if (trim(transform_string).empty()) return {}; @@ -59,7 +59,7 @@ parse_transforms(std::string transform_string) return result; } -void Target::add_escapes(std::string escape_spec) +void Target::add_escapes(const std::string& escape_spec) { auto words = word_split(escape_spec); for (size_t i = 0; i + 1 < words.size(); i += 2) { @@ -142,9 +142,9 @@ std::string hide_structural_characters(const std::string& s) return result; } -void Target::add_after_apply(std::string function_specs) +void Target::add_after_apply(const std::string& function_specs) { - for (auto f : regex_split(function_specs, std::regex(R"(\s+;\s+)"), true)) { + for (const auto& f : regex_split(function_specs, std::regex(R"(\s+;\s+)"), true)) { // msg() << "Add " << m_name << " after-apply: " << f << "\n"; m_after_apply.push_back(f); } diff --git a/mac/target.h b/mac/target.h index 3d1e4fe..f91041b 100644 --- a/mac/target.h +++ b/mac/target.h @@ -11,25 +11,25 @@ class Target { public: Target() = default; -// Target(std::vector::iterator begin, std::vector::iterator end, Argtype_set argtypes); - Target(std::string name, std::string desc, Locator loc) +// Target(std::vector::iterator begin, std::vector::iterator end, Argtype_registry argtypes); + Target(const std::string& name, const std::string& desc, const Locator& loc) : m_name(name) , m_desc(desc) , m_loc(loc) {}; - void add_transform(std::string original, std::string transformed); - void add_transforms(std::string transforms); - void add_transforms(std::vector> transforms); - void transform(std::vector& katoms); + void add_transform(const std::string& original, const std::string& transformed); + void add_transforms(const std::string& transforms); + void add_transforms(const std::vector>& transforms); + void transform(std::vector& katoms) const; - void add_escapes(std::string escape_spec); + void add_escapes(const std::string& escape_spec); std::string escape_text(std::string text) const; std::string unescape_text(std::string text) const; std::string resolve_escapes(std::string text) const; static std::string escape_marker(const std::string& ch); - void add_after_apply(std::string function_specs); + void add_after_apply(const std::string& function_specs); std::string m_name {}; std::string m_desc {}; @@ -40,13 +40,13 @@ public: Locator m_loc {}; std::vector> m_transforms {}; std::vector> m_escapes {}; -// Argtype_set m_argtypes {}; +// Argtype_registry m_argtypes {}; }; std::vector> -parse_transforms(std::string transform_string); +parse_transforms(const std::string& transform_string); // Decode every KTESCKTESC marker in text back to its original // characters. Used for the final output (after target-declared escapes have diff --git a/mac/target_set.cpp b/mac/target_registry.cpp similarity index 67% rename from mac/target_set.cpp rename to mac/target_registry.cpp index 25b8753..093c22c 100644 --- a/mac/target_set.cpp +++ b/mac/target_registry.cpp @@ -1,8 +1,7 @@ #include #include -#include -#include "target_set.h" +#include "target_registry.h" #include "error.h" #include "log.h" #include "util.h" @@ -10,10 +9,10 @@ #include "log.h" #include "katom.h" -std::string Target_set::declare_name = "k"; -std::string Target_set::general_name = "*"; +std::string Target_registry::declare_name = "k"; +std::string Target_registry::general_name = "*"; -Target_set::Target_set() +Target_registry::Target_registry() : m_parameters(Parameter_set("name | desc :after_apply :after_write :includes :escape | transforms.rest")) { Target k(declare_name, "Description of parameters and klammer result", Locator()); @@ -22,16 +21,15 @@ Target_set::Target_set() add(general); } -void Target_set::add(Target target) +void Target_registry::add(Target target) { (void)K::log(3, target); check_for_previous_definition(target.m_name, target.m_loc); m_targets[target.m_name] = target; m_names.push_back(target.m_name); - m_descs.push_back(target.m_desc); } -void Target_set::add(std::vector::iterator begin, std::vector::iterator end, std::vector& katoms) +void Target_registry::add(std::vector::iterator begin, std::vector::iterator end, std::vector& katoms) { (void)K::log(3, *begin, *(end - 1)); auto [positional, optional, rest] = @@ -40,14 +38,10 @@ void Target_set::add(std::vector::iterator begin, std::vector::ite //std::cout << ktype << "Transformed: " << kreplaced << std::pair(begin, end) << "\n"; //std::cout << values << "\n"; - check_for_previous_definition(values["name"], begin->m_loc); Target target(values["name"], values["desc"], begin->m_loc); target.add_transforms(values["transforms"]); target.add_escapes(values["escape"]); target.add_after_apply(values["after_apply"]); - // for (auto included_target : word_split(values["includes"])) { - // msg() << "Include: " << included_target << "\n"; - // } target.m_includes = word_split(values["includes"]); // Inherit escapes from included targets for (const auto& included : target.m_includes) { @@ -57,15 +51,13 @@ void Target_set::add(std::vector::iterator begin, std::vector::ite } } } - m_targets[target.m_name] = target; - m_names.push_back(target.m_name); + // Registration (and the previous-definition check) goes through + // add(Target) -- the single registration path. + add(target); - for (auto [name, defined_target] : m_targets) { - // msg() << name << sp_arrow << defined_target << "\n"; + for (auto& [name, defined_target] : m_targets) { if (is_in(name, target.m_includes)) { defined_target.m_provides.push_back(target.m_name); - // msg() << " " << name << " provides " << target.m_name << "\n " << defined_target.m_provides << "\n"; - m_targets[name] = defined_target; } } @@ -76,56 +68,62 @@ void Target_set::add(std::vector::iterator begin, std::vector::ite } -void Target_set::check_for_previous_definition(std::string name, Locator loc) +void Target_registry::check_for_previous_definition(const std::string& name, const Locator& loc) const { if (has(name)) { - Target current = m_targets[name]; + const Target& current = m_targets.at(name); throw Target_error("Target \"" + name + "\" is already defined:\n " + current.m_loc.desc(), loc, false); } } -bool Target_set::has(std::string target_name) +bool Target_registry::has(const std::string& target_name) const { - return std::ranges::find(m_names, target_name) != m_names.end(); + // Membership comes from the map; m_names exists only to preserve + // definition order for describe(). + return m_targets.count(target_name) > 0; } -Target Target_set::get(std::string target_name, Locator loc) +Target Target_registry::get(const std::string& target_name, const Locator& loc) const { - if (has(target_name) || target_name == Target_set::general_name) { + if (has(target_name) || target_name == Target_registry::general_name) { return m_targets.at(target_name); } else { throw Target_error("Target " + target_name + " does not exist", loc); } } -void Target_set::transform(std::string target_name, katom_list& katoms) +void Target_registry::transform(const std::string& target_name, katom_list& katoms) const { (void)K::log(3); - m_targets[target_name].transform(katoms); + m_targets.at(target_name).transform(katoms); } -std::vector Target_set::user_defined() +std::vector Target_registry::user_defined() const { return collect_if( - m_names, [](auto name) { - return name != Target_set::declare_name && name != Target_set::general_name; }); + m_names, [](const auto& name) { + return name != Target_registry::declare_name && name != Target_registry::general_name; }); } -std::vector Target_set::applicable() +std::vector Target_registry::applicable() const { return collect_if( - m_names, [](auto name) { - return name != Target_set::declare_name; }); + m_names, [](const auto& name) { + return name != Target_registry::declare_name; }); } -std::string Target_set::describe(int margin, bool long_format) const +std::string Target_registry::describe(int margin, bool long_format) const { std::string tab(margin, ' '); std::stringstream ss {}; + std::vector descs {}; + for (const std::string& name : m_names) { + descs.push_back(m_targets.at(name).m_desc); + } auto name_width = max_length(m_names); - auto desc_width = max_length(m_descs); + auto desc_width = max_length(descs); for (const std::string& name : m_names) { const Target& t = m_targets.at(name); if (long_format) { diff --git a/mac/target_set.h b/mac/target_registry.h similarity index 77% rename from mac/target_set.h rename to mac/target_registry.h index 364ba9e..58c3ba4 100644 --- a/mac/target_set.h +++ b/mac/target_registry.h @@ -6,17 +6,17 @@ #include "argument_set.h" #include "katom.h" -class Target_set +class Target_registry { public: static std::string declare_name; static std::string general_name; - Target_set(); + Target_registry(); void add(Target target); void add(std::vector::iterator begin, std::vector::iterator end, std::vector& katoms); - void check_for_previous_definition(std::string name, Locator loc); + void check_for_previous_definition(const std::string& name, const Locator& loc) const; /* @@ -27,19 +27,18 @@ public: */ - bool has(std::string target_name); - Target get(std::string target_name, Locator loc); - void transform(std::string target_name, std::vector& katoms); + bool has(const std::string& target_name) const; + Target get(const std::string& target_name, const Locator& loc) const; + void transform(const std::string& target_name, std::vector& katoms) const; - std::vector user_defined(); - std::vector applicable(); + std::vector user_defined() const; + std::vector applicable() const; std::string describe(int margin=2, bool long_format=false) const; - //Argtype_set m_argtypes {}; + //Argtype_registry m_argtypes {}; std::map m_targets {}; std::vector m_names {}; - std::vector m_descs {}; Parameter_set m_parameters {}; @@ -51,7 +50,7 @@ public: //Parameter_set m_parameters = - // Parameter_set(katomize({"name :desc | transforms.rest"}, "target_set")); + // Parameter_set(katomize({"name :desc | transforms.rest"}, "target_registry")); /* // Targets(Statevar_set& statevars); diff --git a/mac/util.cpp b/mac/util.cpp index 15f1065..aa515e2 100644 --- a/mac/util.cpp +++ b/mac/util.cpp @@ -111,7 +111,7 @@ std::string regex_escape(const std::string& s) return result; } -strings_t regex_split(std::string s, std::regex re, bool trim_parts) +strings_t regex_split(const std::string& s, const std::regex& re, bool trim_parts) { strings_t result = {}; if (s.size() == 0) { @@ -134,17 +134,17 @@ strings_t word_split(const std::string& s) return regex_split(s, std::regex("\\s+")); } -bool is_in(std::string s, strings_t v) +bool is_in(const std::string& s, const strings_t& v) { return find(v.begin(), v.end(), s) != v.end(); } -bool is_not_in(std::string s, strings_t v) +bool is_not_in(const std::string& s, const strings_t& v) { return find(v.begin(), v.end(), s) == v.end(); } -strings_t find_all(std::string str, std::regex pattern, int match_group) +strings_t find_all(const std::string& str, const std::regex& pattern, int match_group) { std::sregex_iterator end {}; strings_t result; @@ -153,7 +153,7 @@ strings_t find_all(std::string str, std::regex pattern, int match_group) return result; } -strings_t find_all(std::string str, std::string pattern, int match_group) +strings_t find_all(const std::string& str, const std::string& pattern, int match_group) { return find_all(str, std::regex(pattern), match_group); } @@ -168,7 +168,7 @@ strings_t split_into_paragraphs(const std::string& s) } -std::string add_margin(std::string s, unsigned int margin_size) +std::string add_margin(const std::string& s, unsigned int margin_size) { auto margin = std::string(margin_size, ' '); return trim_right( @@ -297,7 +297,7 @@ std::string to_be(int count, bool present) return result; } -int max_length(strings_t ss) +int max_length(const strings_t& ss) { size_t result = 0; for_each(ss.begin(), ss.end(), @@ -349,7 +349,7 @@ std::vector> environment_variables(bool allo return result; } -std::string replace_environment_variables(std::string str) +std::string replace_environment_variables(const std::string& str) { if (str.find('{') == std::string::npos || str.find('}') == std::string::npos) { return str; @@ -398,10 +398,10 @@ std::string abbrev(const std::string& s, unsigned int max_length, bool remove_ne return result; } -void remove_element(std::vector& ss, std::string removed) +void remove_element(std::vector& ss, const std::string& removed) { ss.erase(std::remove_if(ss.begin(), ss.end(), - [&removed](std::string s) { return s == removed; }), + [&removed](const std::string& s) { return s == removed; }), ss.end()); } @@ -428,7 +428,7 @@ std::string display_string(const std::string& s, unsigned int width, bool replac return result; } -std::pair extract_parameter_type(std::string parameter_name) +std::pair extract_parameter_type(const std::string& parameter_name) { std::regex name_pat { R"((\w+)\.(\w+))" }; std::smatch match {}; @@ -487,7 +487,8 @@ std::string get_env_var(const std::string& var) { return val ? std::string(val) : ""; } -std::string freplace(const std::string src, std::regex pattern, std::function func) +std::string freplace(const std::string& src, const std::regex& pattern, + const std::function& func) { std::string result {}; std::smatch match; diff --git a/mac/util.h b/mac/util.h index 00bdc9c..9cb263c 100644 --- a/mac/util.h +++ b/mac/util.h @@ -36,13 +36,13 @@ std::string string_replace(const std::string& source, const std::string& old_str std::string regex_escape(const std::string& s); bool contains(const std::string& str, const std::string& substr); bool contains(const std::vector& strings, const std::string& element); -std::vector regex_split(std::string s, std::regex re, bool trim_parts=true); +std::vector regex_split(const std::string& s, const std::regex& re, bool trim_parts=true); std::vector word_split(const std::string& s); -bool is_in(std::string s, std::vector v); -bool is_not_in(std::string s, std::vector v); -std::vector find_all(std::string str, std::regex pattern, int match_group=0); -std::vector find_all(std::string str, std::string pattern, int match_group=0); -std::string add_margin(std::string s, unsigned int margin_size); +bool is_in(const std::string& s, const std::vector& v); +bool is_not_in(const std::string& s, const std::vector& v); +std::vector find_all(const std::string& str, const std::regex& pattern, int match_group=0); +std::vector find_all(const std::string& str, const std::string& pattern, int match_group=0); +std::string add_margin(const std::string& s, unsigned int margin_size); std::string justify(const std::string& input_text, unsigned int text_width=80, unsigned int margin_width=0); std::string join(const std::vector& ss, const std::string& separator = " "); std::string join(int argc, char* array[], const std::string& separator = " "); @@ -50,26 +50,27 @@ std::string argv_to_string(int argc, char* argv[]); std::string plural(const std::string& word, int count); std::string plural(const std::string& word, const std::vector& things); std::string to_be(int count, bool present = true); -int max_length(std::vector ss); +int max_length(const std::vector& ss); std::vector> environment_variables(bool allow_empty_definitions=true); -std::string replace_environment_variables(std::string str); +std::string replace_environment_variables(const std::string& str); std::string abbrev(const std::string& s, unsigned int max_length=65, bool remove_newlines=true); -void remove_element(std::vector& ss, std::string removed); +void remove_element(std::vector& ss, const std::string& removed); void remove_duplicates(std::vector& ss); std::string display_string(const std::string& s, unsigned int width=40, bool replace_newlines=true); -std::pair extract_parameter_type(std::string parameter_name); +std::pair extract_parameter_type(const std::string& parameter_name); std::tuple regex_split_prefix(const std::regex& pattern, const std::string& text); std::vector dlist_split(const std::string& s); std::string get_env_var(const std::string& var); -std::string freplace(const std::string src, std::regex pattern, std::function func); +std::string freplace(const std::string& src, const std::regex& pattern, + const std::function& func); std::string exec(const char* cmd); -inline std::string q_(std::string s) +inline std::string q_(const std::string& s) { return "\"" + s + "\""; } -inline std::string qq_(std::string s) +inline std::string qq_(const std::string& s) { if (s.find('\n') == std::string::npos) { return "\"" + s + "\""; @@ -97,7 +98,7 @@ bool all_equal(const std::vector& v) { } template -int max_key_length(std::map map) +int max_key_length(const std::map& map) { size_t result = 0; for_each(map.begin(), map.end(), diff --git a/sks/document/document_class.cpp b/sks/document/document_class.cpp index aed9cad..29561cc 100644 --- a/sks/document/document_class.cpp +++ b/sks/document/document_class.cpp @@ -11,7 +11,7 @@ #include "log.h" #include "file.h" -bool strbool(std::string s, Locator loc) +bool strbool(const std::string& s, const Locator& loc) { std::vector values = {"false", "False", "0", "true", "True", "1"}; if (is_not_in(s, values)) { @@ -136,7 +136,7 @@ void Document_class::save_string_input_as_file() } -fs::path parse_input_filename(std::string s, std::string input_dir) +fs::path parse_input_filename(const std::string& s, const std::string& input_dir) { fs::path p(s); if (p.extension() != ".kt") { @@ -160,13 +160,13 @@ fs::path parse_input_filename(std::string s, std::string input_dir) return p; } -void Document_class::write(std::string filename, std::string contents) +void Document_class::write(const std::string& filename, const std::string& contents) { write_file(filename, contents, write_files); } -void write_file(std::string filename, std::string contents, bool write_p) +void write_file(const std::string& filename, const std::string& contents, bool write_p) { if (write_p) { string_to_file(filename, contents); @@ -177,14 +177,14 @@ void write_file(std::string filename, std::string contents, bool write_p) /* -void output_msg(std::string msg) +void output_msg(const std::string& msg) { std::cout << red; (void)K::log(1, msg); std::cout << black; } -void Document_class::create_directory(std::string directory) +void Document_class::create_directory(const std::string& directory) { if (write_files) { fs::create_directories(directory); diff --git a/sks/document/document_class.h b/sks/document/document_class.h index a163e18..3d795fa 100644 --- a/sks/document/document_class.h +++ b/sks/document/document_class.h @@ -16,7 +16,7 @@ inline std::map html_tags { using string_pairs_t = std::vector>; -std::string unescape_newlines(std::string s); +std::string unescape_newlines(const std::string& s); enum class docstruct_t { plain, @@ -24,7 +24,7 @@ enum class docstruct_t { book }; -inline docstruct_t docstruct(std::string name) +inline docstruct_t docstruct(const std::string& name) { if (name == "plain") { return docstruct_t::plain; @@ -43,41 +43,41 @@ public: void save_string_input_as_file(); //void create_directory(std::string directory); - void write(std::string filename, std::string contents); + void write(const std::string& filename, const std::string& contents); /* strings_t get_css_files( - std::string output_dir, - std::string css_text, strings_t css_files, bool write_file); + const std::string& output_dir, + const std::string& css_text, const strings_t& css_files, bool write_file); */ strings_t get_js_files( bool nav, bool include_sks_js, - std::string pages_basenames_filename); // , std::string output_dir, bool write_file); + const std::string& pages_basenames_filename); // , const std::string& output_dir, bool write_file); argmap m_args {}; - void write_basenames_js_file(std::string filename, std::vector basenames); + void write_basenames_js_file(const std::string& filename, const std::vector& basenames); std::string create_html_output_directories(); std::string create_tex_output_directories(); std::pair, std::vector> - html_auxiliary_files(std::string output_directory, std::string pages_basename_filename, - std::vector custom_css_files); + html_auxiliary_files(const std::string& output_directory, const std::string& pages_basename_filename, + const std::vector& custom_css_files); void process_input_files(); - std::vector insert_section_numbers(std::string marker="___NUM___", bool add_to_toc=true); + std::vector insert_section_numbers(const std::string& marker="___NUM___", bool add_to_toc=true); void insert_html_caption_numbers(); - std::vector> reference_list(std::string target_marker); + std::vector> reference_list(const std::string& target_marker); std::map id_to_caption_number(); std::map>> html_references(); void resolve_html_references(); std::string single_page_toc(); - elements_t page(std::string body, std::string output_dir, int max_level); + elements_t page(const std::string& body, const std::string& output_dir, int max_level); - std::string make_single_html_page(std::string output_directory); + std::string make_single_html_page(const std::string& output_directory); std::string make_html_navigation_structure( - std::string output_directory, std::vector headings); + const std::string& output_directory, std::vector headings); std::string html(); std::string tex(); std::string make_help_page(); @@ -167,13 +167,13 @@ public: std::string m_cache_dir {}; }; -fs::path parse_input_filename(std::string s, std::string input_dir); -void write_file(std::string filename, std::string contents, bool write_files); +fs::path parse_input_filename(const std::string& s, const std::string& input_dir); +void write_file(const std::string& filename, const std::string& contents, bool write_files); /* std::vector combine_files( - std::vector filenames, std::string output_filename, - std::string prolog="", std::string epilog="", + const std::vector& filenames, const std::string& output_filename, + const std::string& prolog="", const std::string& epilog="", bool write_file_p=true, std::function processor=nullptr); */ diff --git a/sks/document/document_html.cpp b/sks/document/document_html.cpp index 62d9155..3525038 100644 --- a/sks/document/document_html.cpp +++ b/sks/document/document_html.cpp @@ -10,7 +10,7 @@ #include "show.h" #include "file.h" -std::string unescape_newlines(std::string s) +std::string unescape_newlines(const std::string& s) { return string_replace(s, " ___NL___ ", "\n"); @@ -44,7 +44,7 @@ std::string insert_missing_ids(std::smatch match) return result; } -std::string insert_ids(std::string html_text) +std::string insert_ids(const std::string& html_text) { (void)K::log(3); std::string result = html_text; @@ -154,7 +154,7 @@ std::string Document_class::font_definitions() return ss.str(); } -void Document_class::write_basenames_js_file(std::string filename, std::vector basenames) +void Document_class::write_basenames_js_file(const std::string& filename, const std::vector& basenames) { (void)K::log(3); std::string tab(" "); @@ -202,7 +202,7 @@ std::string Document_class::create_html_output_directories() return output_directory; } -strings_t get_css_files(strings_t custom_css_files) +strings_t get_css_files(const strings_t& custom_css_files) { (void)K::log(3); strings_t result = sks_files_of_type("css"); @@ -223,7 +223,7 @@ std::vector js_basenames(bool nav) strings_t Document_class::get_js_files( bool nav, bool include_sks_js, - std::string pages_basenames_filename) + const std::string& pages_basenames_filename) { (void)K::log(3); strings_t result {}; @@ -244,13 +244,13 @@ strings_t Document_class::get_js_files( } -strings_t link_filenames(strings_t& full_filenames, std::string page_dir) +strings_t link_filenames(strings_t& full_filenames, const std::string& page_dir) { strings_t result {}; fs::path page_dir_path(page_dir); // int i = 0; std::transform(full_filenames.begin(), full_filenames.end(), std::back_inserter(result), - [&](std::string f) { + [&](const std::string& f) { fs::path full(f); //msg() << i << full << " " << full.filename() << "\n"; fs::path path(page_dir_path / full.filename()); @@ -260,8 +260,8 @@ strings_t link_filenames(strings_t& full_filenames, std::string page_dir) } std::pair, std::vector> -Document_class::html_auxiliary_files(std::string output_directory, std::string pages_basenames_filename, - std::vector custom_css_files) +Document_class::html_auxiliary_files(const std::string& output_directory, const std::string& pages_basenames_filename, + const std::vector& custom_css_files) { (void)K::log(3); strings_t all_css_files = custom_css_files; @@ -352,7 +352,7 @@ std::string increment_level(int level, std::vector &levels) } -std::string extract_id(std::string attr) +std::string extract_id(const std::string& attr) { std::smatch match {}; if (!std::regex_match(attr, match, id_attr_rgx)) { @@ -362,7 +362,7 @@ std::string extract_id(std::string attr) } std::vector -Document_class::insert_section_numbers(std::string marker, bool add_to_toc) +Document_class::insert_section_numbers(const std::string& marker, bool add_to_toc) { std::vector levels(9, 0); std::smatch match {}; @@ -407,7 +407,7 @@ Document_class::insert_section_numbers(std::string marker, bool add_to_toc) return headings; } -int get_caption_number(std::map& numbers, std::string label) +int get_caption_number(std::map& numbers, const std::string& label) { int result; if (numbers.count(label) == 0) { @@ -470,7 +470,7 @@ void Document_class::insert_html_caption_numbers() std::vector> -Document_class::reference_list(std::string target_marker) +Document_class::reference_list(const std::string& target_marker) { std::regex reference_rgx("__REF__"); std::regex target_rgx("
Document_class::id_to_caption_number() } -std::pair offset_spec_to_count(std::string spec) +std::pair offset_spec_to_count(const std::string& spec) { std::regex rgx(R"((\w+)\s*(\d*))"); std::smatch match {}; @@ -637,7 +637,7 @@ std::string Document_class::single_page_toc() } -elements_t Document_class::page(std::string body_text, std::string output_dir, int max_level) +elements_t Document_class::page(const std::string& body_text, const std::string& output_dir, int max_level) { (void)K::log(3); std::string toc {}; // Calculate @@ -674,7 +674,7 @@ elements_t Document_class::page(std::string body_text, std::string output_dir, i return page; } -std::string Document_class::make_single_html_page(std::string output_directory) +std::string Document_class::make_single_html_page(const std::string& output_directory) { (void)K::log(3); std::stringstream ss {};; @@ -694,7 +694,7 @@ std::string Document_class::make_single_html_page(std::string output_directory) } std::string Document_class::make_html_navigation_structure( - std::string output_directory, std::vector headings) + const std::string& output_directory, std::vector headings) { msg() << "Navigation format\n"; std::vector pages_basenames {}; diff --git a/sks/document/heading.cpp b/sks/document/heading.cpp index 0e9dfd3..79507d7 100644 --- a/sks/document/heading.cpp +++ b/sks/document/heading.cpp @@ -40,7 +40,7 @@ int unnumbered_id = 0; /* std::tuple, std::vector, unsigned int> -add_section_numbers(std::string s, std::string basename, std::vector levels, unsigned int initial_id, +add_section_numbers(const std::string& s, const std::string& basename, std::vector levels, unsigned int initial_id, std::map& section_id_map) { (void)K::log(3); @@ -155,7 +155,7 @@ std::string make_html_table_of_contents(std::vector headings) } std::string toc_link_attrs( - std::string section, std::string title, std::string filename, std::string target, int level) + const std::string& section, const std::string& title, const std::string& filename, const std::string& target, int level) { std::string basename = file_basename(filename); std::stringstream ss {}; @@ -259,7 +259,7 @@ make_navigation_table_of_contents(std::vector headings) } void show_table_of_contents( - std::string kt_root_filename, std::string title, std::vector headings) + const std::string& kt_root_filename, const std::string& title, std::vector headings) { long unsigned int width = kt_root_filename.size(); for (Heading h : headings) { @@ -285,7 +285,7 @@ void show_table_of_contents( } std::string cache_table_of_contents( - std::string kt_root_filename, std::string title, std::vector headings) + const std::string& kt_root_filename, const std::string& title, std::vector headings) { long unsigned int width = kt_root_filename.size(); for (Heading h : headings) { diff --git a/sks/document/heading.h b/sks/document/heading.h index ee61376..fe64338 100644 --- a/sks/document/heading.h +++ b/sks/document/heading.h @@ -8,8 +8,8 @@ const std::string link_delimiter { "%" }; class Heading { public: - Heading(int level, std::string filename, std::string section, std::string id, - std::string number, std::string title) + Heading(int level, const std::string& filename, const std::string& section, const std::string& id, + const std::string& number, const std::string& title) : m_level(level), m_filename(filename), m_section(section), m_id(id), m_number(number), m_title(title) {}; @@ -25,7 +25,7 @@ std::ostream& operator<<(std::ostream& os, const Heading h); /* std::tuple, std::vector, unsigned int> -add_section_numbers(std::string s, std::string basename, std::vector levels, unsigned int initial_id, +add_section_numbers(const std::string& s, const std::string& basename, std::vector levels, unsigned int initial_id, std::map& section_id_map); */ @@ -35,7 +35,7 @@ std::pair make_navigation_table_of_contents(std::vector headings); void show_table_of_contents( - std::string kt_filename, std::string title, std::vector headings); + const std::string& kt_filename, const std::string& title, std::vector headings); std::string cache_table_of_contents( - std::string kt_root_filename, std::string title, std::vector headings); + const std::string& kt_root_filename, const std::string& title, std::vector headings); diff --git a/sks/document/reference.cpp b/sks/document/reference.cpp index 5eb8008..2147112 100644 --- a/sks/document/reference.cpp +++ b/sks/document/reference.cpp @@ -29,7 +29,7 @@ std::ostream& operator<<(std::ostream& os, const numbered_elements& line_states) return os; } -std::string add_latex_caption_numbers(std::string latex_text) +std::string add_latex_caption_numbers(const std::string& latex_text) { std::string caption_delimiter { "__CAPTION__" }; // But also in kutil.py std::regex caption_delimiter_rgx(caption_delimiter); @@ -74,7 +74,7 @@ std::string add_latex_caption_numbers(std::string latex_text) return result; } -numbered_elements latex_line_states(std::vector lines) +numbered_elements latex_line_states(const std::vector& lines) { // \hypertarget{Reference-Figure-0}{}\label{Label-Reference-Figure-0} std::regex element_container_rgx(BS + R"(hypertarget\{(Reference-(\w+)-\d+)\}.*)"); @@ -96,9 +96,9 @@ numbered_elements latex_line_states(std::vector lines) return states; } -std::string find_target(std::string target, - std::vector& lines, int start, numbered_elements states, - std::string target_type, int target_count, std::string direction) +std::string find_target(const std::string& target, + const std::vector& lines, int start, const numbered_elements& states, + const std::string& target_type, int target_count, const std::string& direction) { // msg() << "find_target: " << target_type << " target_count: " << target_count // << " direction: " << direction << "\n"; @@ -137,7 +137,7 @@ std::string find_target(std::string target, } std::string resolve_caption_references( - std::string target, std::vector lines, numbered_elements states) + const std::string& target, const std::vector& lines, numbered_elements states) { //auto lines = regex_split(text, std::regex(R"(\n)"), false); // numbered_elements states = line_states(lines); diff --git a/sks/document/reference.h b/sks/document/reference.h index 524b857..06b68a1 100644 --- a/sks/document/reference.h +++ b/sks/document/reference.h @@ -11,12 +11,12 @@ using numbered_element_spec = std::tuple; //using numbered_elements = std::vector>; using numbered_elements = std::vector; -numbered_elements html_line_states(std::vector lines); -numbered_elements latex_line_states(std::vector lines); +numbered_elements html_line_states(const std::vector& lines); +numbered_elements latex_line_states(const std::vector& lines); -std::pair add_html_caption_numbers(std::string html_text, int& chapter_number); -std::string add_latex_caption_numbers(std::string text); +std::pair add_html_caption_numbers(const std::string& html_text, int& chapter_number); +std::string add_latex_caption_numbers(const std::string& text); std::string resolve_caption_references( - std::string target, std::vector lines, numbered_elements states); + const std::string& target, const std::vector& lines, numbered_elements states); diff --git a/sks/kutil/klammer_base.cpp b/sks/kutil/klammer_base.cpp index efed78b..4d7eacc 100644 --- a/sks/kutil/klammer_base.cpp +++ b/sks/kutil/klammer_base.cpp @@ -5,7 +5,7 @@ #include "klammer_base.h" #include "show.h" -std::string Klammer_base::get(std::string name) +std::string Klammer_base::get(const std::string& name) { //std::cout << "GET " << name << "\n"; std::string result = m_machine.m_state.value(name); @@ -49,7 +49,7 @@ std::string Klammer_base::result() throw Target_error("Unknown target: " + target); } -void Klammer_base::show(std::string klammer_name) +void Klammer_base::show(const std::string& klammer_name) { std::cout << "Arguments of klammer \"" << klammer_name << "\"\n" << m_machine.m_state.describe() << "\n"; diff --git a/sks/kutil/klammer_base.h b/sks/kutil/klammer_base.h index 5315059..f96ad37 100644 --- a/sks/kutil/klammer_base.h +++ b/sks/kutil/klammer_base.h @@ -18,14 +18,14 @@ public: {}; virtual ~Klammer_base() {}; - std::string get(std::string); + std::string get(const std::string& name); std::string get(const char* name); virtual std::string html(); virtual std::string tex(); virtual std::string txt(); std::string result(); - void show(std::string klammer_name); + void show(const std::string& klammer_name); Machine m_machine; }; diff --git a/sks/kutil/kutil.cpp b/sks/kutil/kutil.cpp index 379d440..7d98e33 100644 --- a/sks/kutil/kutil.cpp +++ b/sks/kutil/kutil.cpp @@ -10,7 +10,7 @@ #include -std::string read_file(std::string filename) +std::string read_file(const std::string& filename) { std::ifstream stream {}; std::ostringstream buffer {}; @@ -36,7 +36,7 @@ std::string klammertext_dir() return kdir; } -bool in_subset(std::string base, std::vector subset) +bool in_subset(const std::string& base, const std::vector& subset) { return subset.empty() || (std::find(subset.begin(), subset.end(), base) != subset.end()); @@ -44,7 +44,7 @@ bool in_subset(std::string base, std::vector subset) -std::vector sks_files_of_type(std::string extension, std::vector subset) +std::vector sks_files_of_type(const std::string& extension, const std::vector& subset) { bool dbg = false; std::string kdir = klammertext_dir(); @@ -85,7 +85,7 @@ std::vector sks_files_of_type(std::string extension, std::vector prefix {"", "kt/"}; @@ -117,7 +117,7 @@ std::string find_kt_file(std::string filename) } -std::string caption_marker(std::string name, std::string caption, std::string delimiter) +std::string caption_marker(const std::string& name, const std::string& caption, const std::string& delimiter) { std::string result {caption}; if (caption.size() > 0) { @@ -128,7 +128,7 @@ std::string caption_marker(std::string name, std::string caption, std::string de } /* -std::string process(Machine& M, std::string target, fs::path source_filename, +std::string process(Machine& M, const std::string& target, const fs::path& source_filename, bool post_process, bool unescape_chars) { // Text text(source_filename, false, false); @@ -144,7 +144,7 @@ std::string process(Machine& M, std::string target, fs::path source_filename, return processed; } -std::string process(Machine& M, std::string target, std::string source_text, +std::string process(Machine& M, const std::string& target, const std::string& source_text, bool post_process, bool unescape_chars) { Text text(source_text, false, false); @@ -157,8 +157,8 @@ std::string process(Machine& M, std::string target, std::string source_text, return processed; } -std::string process(Machine& M, std::string target, - std::string source_text, fs::path source_filename, +std::string process(Machine& M, const std::string& target, + const std::string& source_text, const fs::path& source_filename, bool post_process, bool unescape_chars) { Text text({source_text}, {source_filename}, false, false); diff --git a/sks/kutil/kutil.h b/sks/kutil/kutil.h index 1babd7d..f2457a6 100644 --- a/sks/kutil/kutil.h +++ b/sks/kutil/kutil.h @@ -12,24 +12,24 @@ std::vector sks_basenames { // removed "book" const std::string caption_delimiter = "__CAPTION__"; -std::string read_file(std::string filename); +std::string read_file(const std::string& filename); std::string klammertext_dir(); -std::vector old_sks_files_of_type(std::string extension); -std::vector sks_files_of_type(std::string extension, std::vector subset={}); +std::vector old_sks_files_of_type(const std::string& extension); +std::vector sks_files_of_type(const std::string& extension, const std::vector& subset={}); -std::string caption_marker(std::string name, std::string caption, std::string delimiter=" – "); +std::string caption_marker(const std::string& name, const std::string& caption, const std::string& delimiter=" – "); -std::string find_kt_file(std::string filename); +std::string find_kt_file(const std::string& filename); -std::string process(Machine& M, std::string target, std::string source_text, +std::string process(Machine& M, const std::string& target, const std::string& source_text, bool post_process=false, bool unescape_chars=false); -std::string process(Machine& M, std::string target, fs::path source_filename, +std::string process(Machine& M, const std::string& target, const fs::path& source_filename, bool post_process=false, bool unescape_chars=false); -std::string process(Machine& M, std::string target, - std::string source_text, fs::path source_filename, +std::string process(Machine& M, const std::string& target, + const std::string& source_text, const fs::path& source_filename, bool post_process, bool unescape_chars); diff --git a/sks/sks.k b/sks/sks.k index c5f432b..7307f80 100644 --- a/sks/sks.k +++ b/sks/sks.k @@ -1,15 +1,10 @@ # Standard Klammer Set -@read kutil/kutil.k @ -@read target/target.k @ -@read font/font.k @ -@read section/section.k @ -@read image/image.k @ -@read code/code.k @ -@read list/list.k @ -@read link/link.k @ -@read table/table.k @ -@read date/date.k @ -@read block/block.k @ -@read color/color.k @ -@read document/document.k @ -@read book/book.k @ +@@@klammerset sks | Document production: formatting, structure, and layout for the html, tex, pdf, and txt targets + :name Standard Klammer Set + :author Andy Kopra + :date 2026-07-30 + :files kutil/kutil.k target/target.k font/font.k section/section.k + image/image.k code/code.k list/list.k link/link.k + table/table.k date/date.k block/block.k color/color.k + document/document.k book/book.k +@@@ diff --git a/sks/target/html_util.cpp b/sks/target/html_util.cpp index 604e5da..fa01db8 100644 --- a/sks/target/html_util.cpp +++ b/sks/target/html_util.cpp @@ -132,7 +132,7 @@ std::string to_string(elements_t e) -bool HTML::void_element(std::string tag) const +bool HTML::void_element(const std::string& tag) const { if (tag == "!DOCTYPE") return true; @@ -141,7 +141,7 @@ bool HTML::void_element(std::string tag) const (m_void_tags.begin(), m_void_tags.end(), tag) != m_void_tags.end(); } -bool HTML::empty_element(std::string tag) const +bool HTML::empty_element(const std::string& tag) const { if (tag == preamble_tag) return true; @@ -151,13 +151,13 @@ bool HTML::empty_element(std::string tag) const } //HTML& HTML::attr(std::string name, std::variant value) -HTML& HTML::attr(std::string name, attr_t value) +HTML& HTML::attr(const std::string& name, attr_t value) { m_attrs.push_back({name, value}); return *this; } -HTML& HTML::attrs(std::string s) +HTML& HTML::attrs(const std::string& s) { static const std::regex attr_rgx(R"((\w+)\s*=\s*\"(.*?)\")"); auto attrs_begin = std::sregex_iterator(s.begin(), s.end(), attr_rgx); @@ -177,25 +177,25 @@ HTML& HTML::attrs(std::string s) namespace html { - HTML elt(std::string tag) + HTML elt(const std::string& tag) { HTML h(tag); return h; } - HTML elt(std::string tag, std::string text) + HTML elt(const std::string& tag, const std::string& text) { HTML h(tag, trim(text)); return h; } - HTML elt(std::string tag, elements_t elements) + HTML elt(const std::string& tag, elements_t elements) { HTML h(tag, elements); return h; } - HTML elt(std::string tag, HTML e, elements_t elts) + HTML elt(const std::string& tag, HTML e, elements_t elts) { elements_t elements = {e}; elements.insert(elements.end(), elts.begin(), elts.end()); @@ -242,7 +242,7 @@ namespace html { return result; } - elements_t local_font_elements(strings_t fontnames) + elements_t local_font_elements(const strings_t& fontnames) { elements_t result {}; for (auto name : fontnames) { @@ -254,7 +254,7 @@ namespace html { return result; } - elements_t javascript(std::string output_dir, strings_t js_filenames) + elements_t javascript(const std::string& output_dir, const strings_t& js_filenames) { //elements_t result { jquery_elements() }; elements_t result {}; @@ -276,10 +276,10 @@ namespace html { return result; } - HTML head(std::string title, - std::string css, - strings_t css_filenames, - strings_t local_fonts) + HTML head(const std::string& title, + const std::string& css, + const strings_t& css_filenames, + const strings_t& local_fonts) { elements_t elts = meta_elements(); // msg() << "ELTS sks: " << elts << "\n"; @@ -317,8 +317,8 @@ namespace html { } - HTML button(std::string id, std::string name, - std::string attrib="", std::string value="") + HTML button(const std::string& id, const std::string& name, + const std::string& attrib="", const std::string& value="") { std::vector hidden = {"Clear", "Back"}; HTML result = elt("span", string_replace(name, " ", " ")).id(id).cls("navb"); @@ -449,7 +449,7 @@ namespace html { return result; } - elements_t status(std::string date, std::string version, std::string copyright) + elements_t status(const std::string& date, const std::string& version, const std::string& copyright) { elements_t result {}; if (!date.empty()) { @@ -465,21 +465,21 @@ namespace html { } elements_t page( - std::string title, + const std::string& title, std::string page_title, - std::string output_dir, - std::string nav, + const std::string& output_dir, + const std::string& nav, int max_level, - std::string toc, - std::string text, - std::string date, - std::string version, - std::string copyright, - std::string css, - strings_t css_filenames, - strings_t js_filenames, - strings_t local_fonts, - std::string logo) + const std::string& toc, + const std::string& text, + const std::string& date, + const std::string& version, + const std::string& copyright, + const std::string& css, + const strings_t& css_filenames, + const strings_t& js_filenames, + const strings_t& local_fonts, + const std::string& logo) { if (page_title.empty()) page_title = title; @@ -540,7 +540,7 @@ namespace html { } - void add_title(elements_t& body, std::string title, std::string logo) + void add_title(elements_t& body, const std::string& title, const std::string& logo) { // No title bar at all when there is nothing to put in it (an // untitled document); a logo alone still gets the bar. @@ -561,7 +561,7 @@ namespace html { body.push_back(navigation(max_level)); } - void add_text(elements_t& body, std::string text, std::string toc, bool text_only) + void add_text(elements_t& body, const std::string& text, const std::string& toc, bool text_only) { if (text_only) { elements_t content {}; @@ -580,7 +580,7 @@ namespace html { } void add_status_bar( - elements_t& body, std::string date, std::string version, std::string copyright) + elements_t& body, const std::string& date, const std::string& version, const std::string& copyright) { elements_t status_elements = status(date, version, copyright); if (!empty(status_elements)) { @@ -593,7 +593,7 @@ namespace html { body.push_back(elt("div", "").attr("id", "pagecache")); } - void add_js_links(elements_t& body, strings_t js_filenames, std::string output_dir) + void add_js_links(elements_t& body, const strings_t& js_filenames, const std::string& output_dir) { if (!js_filenames.empty()) { auto js_elements { javascript(output_dir, js_filenames) }; @@ -603,8 +603,8 @@ namespace html { elements_t make_page( elements_t body, - std::string page_title, std::string css, - strings_t css_filenames, strings_t local_fonts) + std::string page_title, const std::string& css, + const strings_t& css_filenames, const strings_t& local_fonts) { elements_t page { preamble() }; page.push_back( @@ -615,7 +615,7 @@ namespace html { return page; } - bool tag_is_block_element(std::string tag) + bool tag_is_block_element(const std::string& tag) { auto location = std::find(block_elements.begin(), block_elements.end(), tag); return location != block_elements.end(); @@ -635,7 +635,7 @@ namespace html { return result; } - std::string make_paragraphs(std::string html_text) + std::string make_paragraphs(const std::string& html_text) { (void)K::log(3); std::string result {}; @@ -654,7 +654,7 @@ namespace html { return result; } - std::string minimize_css(std::string src) + std::string minimize_css(const std::string& src) { (void)K::log(3); std::string result = src; @@ -668,7 +668,7 @@ namespace html { return result; } - std::string minimize_js(std::string src) + std::string minimize_js(const std::string& src) { (void)K::log(3); return src; diff --git a/sks/target/html_util.h b/sks/target/html_util.h index d71b17e..34c57d0 100644 --- a/sks/target/html_util.h +++ b/sks/target/html_util.h @@ -32,24 +32,24 @@ public: operator std::string() { std::stringstream ss {}; ss << *this; return ss.str(); }; - HTML(std::string tag) : + HTML(const std::string& tag) : m_tag(tag) {}; - HTML(std::string tag, std::string text) : + HTML(const std::string& tag, const std::string& text) : m_tag(tag), m_text({text}) {}; - HTML(std::string tag, elements_t elements) : + HTML(const std::string& tag, elements_t elements) : m_tag(tag), m_elements(elements) {}; - HTML& attr(std::string name, attr_t value); - HTML& attrs(std::string s); + HTML& attr(const std::string& name, attr_t value); + HTML& attrs(const std::string& s); - HTML& cls(std::string name) { return attr("class", name); }; - HTML& sty(std::string css) { return attr("style", css); }; - HTML& id(std::string id) { return attr("id", id); }; + HTML& cls(const std::string& name) { return attr("class", name); }; + HTML& sty(const std::string& css) { return attr("style", css); }; + HTML& id(const std::string& id) { return attr("id", id); }; - bool void_element(std::string tag) const; - bool empty_element(std::string tag) const; + bool void_element(const std::string& tag) const; + bool empty_element(const std::string& tag) const; friend std::ostream& operator<<(std::ostream& os, const HTML& h); friend std::ostream& operator<<(std::ostream& os, const std::vector& hv); @@ -68,48 +68,48 @@ private: }; namespace html { - HTML elt(std::string tag); - HTML elt(std::string tag, std::string text); - HTML elt(std::string tag, elements_t elements); - HTML elt(std::string tag, HTML e, elements_t elts); + HTML elt(const std::string& tag); + HTML elt(const std::string& tag, const std::string& text); + HTML elt(const std::string& tag, elements_t elements); + HTML elt(const std::string& tag, HTML e, elements_t elts); //HTML preamble(); //HTML head(strings_t css_filenames, strings_t js_filenames); elements_t page( - std::string title, + const std::string& title, std::string page_title, - std::string output_dir, - std::string nav, + const std::string& output_dir, + const std::string& nav, int max_level, - std::string toc, - std::string text, - std::string date, - std::string version, - std::string copyright, - std::string css, + const std::string& toc, + const std::string& text, + const std::string& date, + const std::string& version, + const std::string& copyright, + const std::string& css, strings_t css_filenames = {}, strings_t js_filenames = {}, strings_t local_fonts = {}, std::string logo = {}); - void add_title(elements_t& body, std::string title, std::string logo=""); - void add_title(elements_t& body, std::string title, std::string logo); + void add_title(elements_t& body, const std::string& title, const std::string& logo=""); + void add_title(elements_t& body, const std::string& title, const std::string& logo); void add_nav(elements_t& body, int max_level); - void add_text(elements_t& body, std::string text, std::string toc_text, bool text_only); + void add_text(elements_t& body, const std::string& text, const std::string& toc_text, bool text_only); void add_bottom_spacer(elements_t& body); - void add_status_bar(elements_t& body, std::string date, std::string version, std::string copyright); + void add_status_bar(elements_t& body, const std::string& date, const std::string& version, const std::string& copyright); void add_page_cache(elements_t& body); - void add_js_links(elements_t& body, std::vector js_filenames, std::string output_dir); + void add_js_links(elements_t& body, const std::vector& js_filenames, const std::string& output_dir); elements_t make_page( elements_t body, - std::string page_title, std::string css, - std::vector css_filenames, - std::vector local_fonts); + std::string page_title, const std::string& css, + const std::vector& css_filenames, + const std::vector& local_fonts); - bool tag_is_block_element(std::string tag); - std::string make_paragraphs(std::string html_text); - std::string minimize_css(std::string src); - std::string minimize_js(std::string src); + bool tag_is_block_element(const std::string& tag); + std::string make_paragraphs(const std::string& html_text); + std::string minimize_css(const std::string& src); + std::string minimize_js(const std::string& src); } diff --git a/sks/target/latex_util.cpp b/sks/target/latex_util.cpp index 42a0a54..94e2c05 100644 --- a/sks/target/latex_util.cpp +++ b/sks/target/latex_util.cpp @@ -33,7 +33,7 @@ namespace latex { std::string title_line( - std::string text, std::string font="1.3", std::string vskip="4pt", + const std::string& text, const std::string& font="1.3", const std::string& vskip="4pt", bool vskip_if_missing=false) { std::stringstream ss {}; @@ -48,8 +48,8 @@ namespace latex { } std::string default_cover( - std::string title, std::string subtitle, - std::string author, std::string date, std::string version) + const std::string& title, const std::string& subtitle, + const std::string& author, const std::string& date, const std::string& version) { std::string test = trim(title + subtitle + author + date + version); std::stringstream ss {}; @@ -65,8 +65,8 @@ namespace latex { } std::string nonbook_title( - std::string title, std::string subtitle, - std::string author, std::string date, std::string version) + const std::string& title, const std::string& subtitle, + const std::string& author, const std::string& date, const std::string& version) { std::string test = trim(title + subtitle + author + date + version); std::stringstream ss {}; @@ -86,7 +86,7 @@ namespace latex { return ss.str(); } - std::string pagenumber(int n, std::string style="arabic") + std::string pagenumber(int n, const std::string& style="arabic") { (void)K::log(3); std::stringstream ss {}; @@ -94,7 +94,7 @@ namespace latex { return ss.str(); } - std::string book_verso_page(std::string copyright) + std::string book_verso_page(const std::string& copyright) { (void)K::log(3); std::stringstream ss {}; @@ -111,7 +111,7 @@ namespace latex { return ss.str(); } - std::string font_command(std::string command, const Resolved_font& font, float scale) + std::string font_command(const std::string& command, const Resolved_font& font, float scale) { std::stringstream ss {}; if (font.family_name.empty()) @@ -150,23 +150,23 @@ namespace latex { return ss.str(); } - std::string page(std::string structure, - std::string title, - std::string subtitle, - std::string authors, - std::string date, - std::string version, - std::string copyright, - std::string bottom, - std::string prolog, - std::string paper_size, + std::string page(const std::string& structure, + const std::string& title, + const std::string& subtitle, + const std::string& authors, + const std::string& date, + const std::string& version, + const std::string& copyright, + const std::string& bottom, + const std::string& prolog, + const std::string& paper_size, bool two_column, float leading, int pointsize, bool ragged_right, - std::string cover, + const std::string& cover, bool landscape, - std::string body, + const std::string& body, Resolved_font serif_font, Resolved_font sans_font, Resolved_font mono_font, diff --git a/sks/target/latex_util.h b/sks/target/latex_util.h index 358769c..1380ece 100644 --- a/sks/target/latex_util.h +++ b/sks/target/latex_util.h @@ -6,23 +6,23 @@ namespace latex { -std::string page(std::string structure, - std::string title, - std::string subtitle, - std::string authors, - std::string date, - std::string version, - std::string copyright, - std::string bottom, - std::string prolog, - std::string paper_size, +std::string page(const std::string& structure, + const std::string& title, + const std::string& subtitle, + const std::string& authors, + const std::string& date, + const std::string& version, + const std::string& copyright, + const std::string& bottom, + const std::string& prolog, + const std::string& paper_size, bool two_column, float leading, int pointsize, bool ragged_right, - std::string cover, + const std::string& cover, bool landscape, - std::string body, + const std::string& body, Resolved_font serif_font = {}, Resolved_font sans_font = {}, Resolved_font mono_font = {}, diff --git a/sks/target/target.k b/sks/target/target.k index f771ebf..b923701 100644 --- a/sks/target/target.k +++ b/sks/target/target.k @@ -3,7 +3,7 @@ The targets in the SKS use the LaTeX convention for converting ASCII characters into standard typographical characters. This is done by LaTeX by default; other targets must use the transforms parameter of Parameter_set, as defined for the m_parameters variable of the -Target_set class. (See file target_set.cpp.) +Target_registry class. (See file target_registry.cpp.) The LaTeX transformations supported by the SKS are: diff --git a/tst/Makefile b/tst/Makefile index 2e12c6c..1063458 100644 --- a/tst/Makefile +++ b/tst/Makefile @@ -1,6 +1,6 @@ # Klammertext distribution test suite (subset). # -# Runs the seven shell regression suites: +# Runs the eight shell regression suites: # cond_test.sh — @cond argument delimitation # deftype_test.sh — the four klammer definition modes + redefinition table # escape_test.sh — target character escaping and quoted specials @@ -8,6 +8,7 @@ # alone_test.sh — an optional argument's three values (default, the # argument type's :alone value, a written value) # modulepath_test.sh — @eval finds modules beside the file that names them +# klammerset_test.sh — the @@@klammerset system command and its search path # editor_test.sh — editor support (doc/edit): indentation and table # alignment; needs python3, uses Emacs when installed # @@ -21,4 +22,5 @@ test: ./filename_test.sh ./alone_test.sh ./modulepath_test.sh + ./klammerset_test.sh ./editor_test.sh diff --git a/tst/deftype_test.sh b/tst/deftype_test.sh index a16dd22..575d802 100755 --- a/tst/deftype_test.sh +++ b/tst/deftype_test.sh @@ -17,7 +17,7 @@ # combinations. This test pins down every entry of that table plus the basic # behavior of each mode, none of which tst/klammer_test.cpp currently covers. # -# {replace,warn,message} semantics (mac/klammer_set.cpp): +# {replace,warn,message} semantics (mac/klammer_registry.cpp): # !replace && message -> Definition_error (nonzero exit) # !replace && empty -> silently keep the existing definition # replace && warn -> emit a warning, then replace diff --git a/tst/klammerset/bad_file.k b/tst/klammerset/bad_file.k new file mode 100644 index 0000000..1df398e --- /dev/null +++ b/tst/klammerset/bad_file.k @@ -0,0 +1 @@ +@@@klammerset broken | Lists a file that does not exist :files missing.k @@@ diff --git a/tst/klammerset/base.k b/tst/klammerset/base.k new file mode 100644 index 0000000..1b68c14 --- /dev/null +++ b/tst/klammerset/base.k @@ -0,0 +1 @@ +@@@target fix | Fixture target @@@ diff --git a/tst/klammerset/decl.k b/tst/klammerset/decl.k new file mode 100644 index 0000000..57f5b51 --- /dev/null +++ b/tst/klammerset/decl.k @@ -0,0 +1,11 @@ +# Engine-tier fixture: a klammerset with metadata, a dependency, an ordered +# file list (klammers.k uses the target defined in base.k), and a trailing +# definition that must load after the files (program order). +@@@klammerset kit | Engine-test klammerset + :name Klammerset Integration Test + :author Klammertext tests + :date 2026-07-30 + :requires util.k + :files base.k / klammers.k +@@@ +@@after : AFTER @@ diff --git a/tst/klammerset/decl2.k b/tst/klammerset/decl2.k new file mode 100644 index 0000000..41c9e42 --- /dev/null +++ b/tst/klammerset/decl2.k @@ -0,0 +1 @@ +@@@klammerset kit | Duplicate declaration of kit :files dup_only.k @@@ diff --git a/tst/klammerset/dup_only.k b/tst/klammerset/dup_only.k new file mode 100644 index 0000000..1d6bcdc --- /dev/null +++ b/tst/klammerset/dup_only.k @@ -0,0 +1 @@ +@@only_dup : DUP @@ diff --git a/tst/klammerset/klammers.k b/tst/klammerset/klammers.k new file mode 100644 index 0000000..3e7992c --- /dev/null +++ b/tst/klammerset/klammers.k @@ -0,0 +1 @@ +@@greet.fix name : Hello *name* @@ diff --git a/tst/klammerset/space name.k b/tst/klammerset/space name.k new file mode 100644 index 0000000..b006dbf --- /dev/null +++ b/tst/klammerset/space name.k @@ -0,0 +1 @@ +@@spacey.fix : SPACEY @@ diff --git a/tst/klammerset/spacey.k b/tst/klammerset/spacey.k new file mode 100644 index 0000000..4e63bf2 --- /dev/null +++ b/tst/klammerset/spacey.k @@ -0,0 +1 @@ +@@@klammerset sp | Spacey filename in the list :files base.k / space name.k @@@ diff --git a/tst/klammerset/util.k b/tst/klammerset/util.k new file mode 100644 index 0000000..53b87fc --- /dev/null +++ b/tst/klammerset/util.k @@ -0,0 +1,2 @@ +@@@klammerset util | Utility klammers for engine tests :date 2026-07-30 @@@ +@@dash : -- @@ diff --git a/tst/klammerset/wrapper.k b/tst/klammerset/wrapper.k new file mode 100644 index 0000000..cbfb1e4 --- /dev/null +++ b/tst/klammerset/wrapper.k @@ -0,0 +1 @@ +@@@klammerset wrap | Wrapper requiring kit twice :requires decl.k / decl2.k @@@ diff --git a/tst/klammerset_test.sh b/tst/klammerset_test.sh new file mode 100755 index 0000000..c17ff45 --- /dev/null +++ b/tst/klammerset_test.sh @@ -0,0 +1,284 @@ +#!/bin/bash +# +# klammerset_test.sh — Regression tests for the @@@klammerset system command. +# +# @@@klammerset declares a Klammerset: a named, logically related group of +# klammer definitions. The declaration is operative — processing it reads +# the :requires files and then the :files, in list order, at the point of the +# declaration; relative names resolve against the declaring file's directory, +# never the cwd. A repeated declaration of an already-registered symbol is +# skipped (loaded once), which is what makes :requires idempotent. The +# klammers themselves live in the Machine's flat Klammer_registry; the +# Klammerset holds metadata and the file list only. +# +# Engine tier: no SKS. Fixtures live in tst/klammerset/ and define their own +# target ("fix") inline. +# +# Usage: ./klammerset_test.sh +# Exit code: 0 if all tests pass, 1 otherwise. + +PASS=0 +FAIL=0 +KTEXT=ktext +K=${KLAMMERTEXT_HOME:?KLAMMERTEXT_HOME must be set} +FIX=$K/tst/klammerset + +red=$'\033[31m' +green=$'\033[32m' +bold=$'\033[1m' +reset=$'\033[0m' + +# strip leading/trailing blank lines and surrounding whitespace +trim() { awk '{ sub(/[ \t\r]+$/, "") } { line[NR]=$0 } END { f=1; while (f<=NR && line[f]=="") f++; l=NR; while (l>=1 && line[l]=="") l--; for (i=f;i<=l;i++) print line[i] }'; } + +# check_eq TEST_NAME EXPECTED KTEXT_ARGS... +# Runs ktext, expects exit status 0, and compares trimmed stdout to EXPECTED. +check_eq() { + local test_name="$1" + local expected="$2" + shift 2 + + local output status + output=$("$KTEXT" "$@" 2>/tmp/klammerset_test_err.$$) + status=$? + output=$(printf '%s' "$output" | trim) + + if [ $status -ne 0 ]; then + echo "${red}FAIL${reset} $test_name — ktext exited $status" + echo " stderr: $(head -3 /tmp/klammerset_test_err.$$)" + FAIL=$((FAIL + 1)) + return + fi + if [ "$output" = "$expected" ]; then + echo "${green}PASS${reset} $test_name" + PASS=$((PASS + 1)) + else + echo "${red}FAIL${reset} $test_name" + echo " expected: [$expected]" + echo " got: [$output]" + FAIL=$((FAIL + 1)) + fi +} + +# check_contains TEST_NAME SUBSTRING KTEXT_ARGS... +# Runs ktext, expects exit status 0, and checks that the combined output +# contains SUBSTRING. +check_contains() { + local test_name="$1" + local needle="$2" + shift 2 + + local output status + output=$("$KTEXT" "$@" 2>&1) + status=$? + + if [ $status -ne 0 ]; then + echo "${red}FAIL${reset} $test_name — ktext exited $status" + echo " output: $(echo "$output" | head -3)" + FAIL=$((FAIL + 1)) + return + fi + if printf '%s' "$output" | grep -qF "$needle"; then + echo "${green}PASS${reset} $test_name" + PASS=$((PASS + 1)) + else + echo "${red}FAIL${reset} $test_name" + echo " expected output to contain: [$needle]" + echo " got: $(echo "$output" | head -5)" + FAIL=$((FAIL + 1)) + fi +} + +# check_fails TEST_NAME SUBSTRING KTEXT_ARGS... +# Runs ktext, expects a NONZERO exit status, and checks that the combined +# output contains SUBSTRING. +check_fails() { + local test_name="$1" + local needle="$2" + shift 2 + + local output status + output=$("$KTEXT" "$@" 2>&1) + status=$? + + if [ $status -eq 0 ]; then + echo "${red}FAIL${reset} $test_name — expected an error, ktext exited 0" + FAIL=$((FAIL + 1)) + return + fi + if printf '%s' "$output" | grep -qF "$needle"; then + echo "${green}PASS${reset} $test_name" + PASS=$((PASS + 1)) + else + echo "${red}FAIL${reset} $test_name" + echo " expected error output to contain: [$needle]" + echo " got: $(echo "$output" | head -5)" + FAIL=$((FAIL + 1)) + fi +} + +echo "${bold}@@@klammerset tests${reset}" +echo "=======================" +echo + +# --- Loading --------------------------------------------------------------- + +# 1. :files load in list order: klammers.k defines @greet for the target +# that base.k declares, so base.k must have been read first. +check_eq "1. :files load in order (target before klammer)" \ + "Hello World" \ + -k "$FIX/decl.k" -s '@greet World @' -t fix + +# 2. :requires loads the dependency before the set's own files. +check_eq "2. :requires loads the dependency" \ + "--" \ + -k "$FIX/decl.k" -s '@dash@' -t fix + +# 3. Program order: a definition AFTER the declaration in the declaring file +# is available (there is no :text argument; the declaring file's own +# content plays that role). +check_eq "3. trailing definition in the declaring file" \ + "AFTER" \ + -k "$FIX/decl.k" -s '@after@' -t fix + +# 4. Relative :files names resolve against the DECLARING file's directory, +# not the cwd (run from an unrelated directory). +output=$( (cd /tmp && "$KTEXT" -k "$FIX/decl.k" -s '@greet Elsewhere @' -t fix) 2>/dev/null | trim ) +if [ "$output" = "Hello Elsewhere" ]; then + echo "${green}PASS${reset} 4. :files resolve against the declaring file's directory" + PASS=$((PASS + 1)) +else + echo "${red}FAIL${reset} 4. :files resolve against the declaring file's directory" + echo " expected: [Hello Elsewhere]" + echo " got: [$output]" + FAIL=$((FAIL + 1)) +fi + +# 5. A filename with a space in the :files list (standalone "/" separator). +check_eq "5. spacey filename in :files" \ + "SPACEY" \ + -k "$FIX/spacey.k" -s '@spacey@' -t fix + +# --- The already-loaded guard ------------------------------------------------ + +# 6. A second declaration of an already-registered symbol is skipped, not an +# error: wrapper.k requires decl.k (registers "kit") and then decl2.k +# (re-declares "kit"); the wrapper still loads and kit's klammers work. +check_eq "6. duplicate declaration is skipped, not an error" \ + "Hello Again" \ + -k "$FIX/wrapper.k" -s '@greet Again @' -t fix + +# 7. ...and the skipped declaration's files are NOT loaded. +check_fails "7. skipped declaration loads none of its files" \ + "only_dup" \ + -k "$FIX/wrapper.k" -s '@only_dup@' -t fix + +# --- Introspection ----------------------------------------------------------- + +# 8. -m lists the registered klammersets. +check_contains "8. -m shows the klammerset symbol" \ + "kit" \ + -k "$FIX/decl.k" -s 'x' -t fix -m + +check_contains "9. -m shows the required klammerset too" \ + "Utility klammers for engine tests" \ + -k "$FIX/decl.k" -s 'x' -t fix -m + +# --- Errors -------------------------------------------------------------------- + +# 10. A listed file that does not exist is a clean klammerset error. +check_fails "10. missing file in :files" \ + "missing.k" \ + -k "$FIX/bad_file.k" -s 'x' -t fix + +# 11. A symbol must be an identifier (starts with a letter; letters, digits, +# underscores). +check_fails "11. invalid symbol rejected" \ + "not valid" \ + -k none -s '@@@klammerset 9bad | Bad symbol @@@' -d + +# --- The search path (symbol -> //.k) ------------------- + +# Runtime fixtures: a document directory holding a local klammerset, and a +# separate directory serving as a KLAMMERTEXT_KLAMMERSETS stage. +DOCDIR=$(mktemp -d /tmp/klammerset_doc.XXXXXX) +ENVDIR=$(mktemp -d /tmp/klammerset_env.XXXXXX) +trap 'rm -rf "$DOCDIR" "$ENVDIR" /tmp/klammerset_test_err.$$' EXIT + +mkdir -p "$DOCDIR/locset" "$ENVDIR/envset" "$ENVDIR/locset" +printf '@@@klammerset locset | Document-local set @@@\n@@@target fixL | Fixture @@@\n@@local_k.fixL : LOCAL @@\n' \ + > "$DOCDIR/locset/locset.k" +printf '@local_k@\n' > "$DOCDIR/doc.kt" +printf '@@@klammerset envset | Installed set @@@\n@@@target fixE | Fixture @@@\n@@env_k.fixE : ENV @@\n' \ + > "$ENVDIR/envset/envset.k" +printf '@@@klammerset locset | Shadow candidate @@@\n@@@target fixL | Fixture @@@\n@@local_k.fixL : ENV-SHADOWED @@\n' \ + > "$ENVDIR/locset/locset.k" + +# 12. Stage 1 for a file input: the document's directory. +check_eq "12. symbol resolves in the document's directory" \ + "LOCAL" \ + "$DOCDIR/doc.kt" -k locset -t fixL -d + +# 13. Stage 1 for string input: the cwd stands in for the document. +output=$( (cd "$DOCDIR" && "$KTEXT" -s '@local_k@' -k locset -t fixL) 2>/dev/null | trim ) +if [ "$output" = "LOCAL" ]; then + echo "${green}PASS${reset} 13. cwd stands in for the document (string input)" + PASS=$((PASS + 1)) +else + echo "${red}FAIL${reset} 13. cwd stands in for the document (string input)" + echo " expected: [LOCAL] got: [$output]" + FAIL=$((FAIL + 1)) +fi + +# 14. Stage 2: the KLAMMERTEXT_KLAMMERSETS directories. +output=$(KLAMMERTEXT_KLAMMERSETS=$ENVDIR "$KTEXT" -s '@env_k@' -k envset -t fixE 2>/dev/null | trim) +if [ "$output" = "ENV" ]; then + echo "${green}PASS${reset} 14. symbol resolves in KLAMMERTEXT_KLAMMERSETS" + PASS=$((PASS + 1)) +else + echo "${red}FAIL${reset} 14. symbol resolves in KLAMMERTEXT_KLAMMERSETS" + echo " expected: [ENV] got: [$output]" + FAIL=$((FAIL + 1)) +fi + +# 15. Shadowing: the document-local set wins over the installed one. +output=$(KLAMMERTEXT_KLAMMERSETS=$ENVDIR "$KTEXT" "$DOCDIR/doc.kt" -k locset -t fixL -d 2>/dev/null | trim) +if [ "$output" = "LOCAL" ]; then + echo "${green}PASS${reset} 15. document-local set shadows the installed one" + PASS=$((PASS + 1)) +else + echo "${red}FAIL${reset} 15. document-local set shadows the installed one" + echo " expected: [LOCAL] got: [$output]" + FAIL=$((FAIL + 1)) +fi + +# 16. :requires by symbol, resolved with the declaring directory as the +# local stage (the required set sits inside the declaring set's dir). +mkdir -p "$DOCDIR/kit2/locset" +cp "$DOCDIR/locset/locset.k" "$DOCDIR/kit2/locset/locset.k" +printf '@@@klammerset kit2 | Requires by symbol :requires locset @@@\n' > "$DOCDIR/kit2/kit2.k" +check_eq "16. :requires accepts a symbol (declaring-dir stage)" \ + "LOCAL" \ + -k "$DOCDIR/kit2/kit2.k" -s '@local_k@' -t fixL + +# 17. Stage 3: $KLAMMERTEXT_HOME — the kdesc listing enumerates sks +# (sks/sks.k already satisfies the /.k convention). +output=$(kdesc --klammerset 2>/dev/null) +if printf '%s' "$output" | grep -q 'sks/sks\.k'; then + echo "${green}PASS${reset} 17. kdesc --klammerset lists sks from KLAMMERTEXT_HOME" + PASS=$((PASS + 1)) +else + echo "${red}FAIL${reset} 17. kdesc --klammerset lists sks from KLAMMERTEXT_HOME" + echo " got: $(echo "$output" | head -3)" + FAIL=$((FAIL + 1)) +fi + +# 18. An unknown symbol is a clean error naming the search directories. +check_fails "18. unknown symbol names the search path" \ + "was not found" \ + -s 'x' -k nosuchset -d + +echo +echo "=======================" +echo "Results: ${green}$PASS passed${reset}, $([ $FAIL -gt 0 ] && echo "${red}$FAIL failed${reset}" || echo "0 failed")" +[ $FAIL -eq 0 ]