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

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

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

View File

@@ -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

View File

@@ -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)));
}

View File

@@ -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");

View File

@@ -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));

View File

@@ -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

View File

@@ -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))

View File

@@ -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)

View File

@@ -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<std::string> value, size_t name_size);

View File

@@ -3,7 +3,7 @@
#include <algorithm>
#include <numeric>
#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<Katom>::iterator begin, std::vector<Katom>::iterator end, std::vector<Katom>& katoms)
void Argtype_registry::add(std::vector<Katom>::iterator begin, std::vector<Katom>::iterator end, std::vector<Katom>& 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<Katom>::iterator begin, std::vector<Katom>::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(

View File

@@ -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<std::string> m_names {};

View File

@@ -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)

View File

@@ -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 {};

View File

@@ -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<Katom>& 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<Katom>& katoms, const Argtype_set& argtypes)
Parameter_set::Parameter_set(const std::vector<Katom>& katoms, const Argtype_registry& argtypes)
: m_katoms(katoms)
{
(void)K::log(3);
@@ -82,7 +82,7 @@ Parameter_set::Parameter_set(const std::vector<Katom>& 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<std::vector<Katom>> positional,
std::vector<std::vector<Katom>> optional,
std::vector<Katom> rest)
const std::string& label,
const std::vector<std::vector<Katom>>& positional,
const std::vector<std::vector<Katom>>& optional,
const std::vector<Katom>& rest)
{
std::cout << label << ":\n"
<< " positional: " << positional << "\n"

View File

@@ -7,7 +7,7 @@
#include "argument.h"
#include "locator.h"
class Argtype_set;
class Argtype_registry;
std::tuple<std::vector<std::vector<Katom>>,std::vector<std::vector<Katom>>,std::vector<Katom>>
argument_split(std::vector<Katom>::const_iterator kbegin, std::vector<Katom>::const_iterator kend,
@@ -20,9 +20,9 @@ public:
~Parameter_set() = default;
Parameter_set(const std::string parameter_string);
Parameter_set(const std::vector<Katom>& katoms);
Parameter_set(const std::vector<Katom>& katoms, const Argtype_set& argtypes);
Parameter_set(const std::vector<Katom>& katoms, const Argtype_registry& argtypes);
void parse_parameters(const std::vector<Katom>& katoms, const Argtype_set& argtypes);
void parse_parameters(const std::vector<Katom>& 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<Katom> m_katoms {};
//Argtype_set m_argtypes {};
//Argtype_registry m_argtypes {};
std::vector<Parameter> m_positional {};
std::vector<Parameter> m_optional {};
std::vector<std::string> 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<std::vector<Katom>> positional,
std::vector<std::vector<Katom>> optional,
std::vector<Katom> rest);
const std::string& label,
const std::vector<std::vector<Katom>>& positional,
const std::vector<std::vector<Katom>>& optional,
const std::vector<Katom>& rest);
std::string replace_arguments(
const std::map<std::string, std::string>& values,

View File

@@ -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<std::string> 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) {

View File

@@ -62,7 +62,7 @@ public:
void update_width(Arg arg);
void check_flags_and_options(std::string command, std::vector<std::string>& words);
void check_flags_and_options(const std::string& command, std::vector<std::string>& words);
void parse_flags(std::vector<std::string>& words, std::map<std::string, std::string>& named_args);
void parse_optional(std::vector<std::string>& words, std::map<std::string, std::string>& named_args);
void parse_vars(std::vector<std::string>& words, std::map<std::string, std::string>& 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<std::string> words,
const std::string& command, // std::vector<std::string> words,
std::string pos_args, std::map<std::string, std::string>& named_args);
std::map<std::string, std::string> 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;
}

View File

@@ -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

View File

@@ -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(

View File

@@ -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)
{};

View File

@@ -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";

View File

@@ -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;

View File

@@ -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);

View File

@@ -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<std::string> 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(

View File

@@ -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

View File

@@ -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<std::string> sks_dirs();
std::vector<std::string> 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<fs::path> 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<std::string> filenames, std::string output_directory, std::string link_directory);
const std::vector<std::string>& 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());

View File

@@ -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 {};

View File

@@ -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<std::string> installed_font_dirs();
@@ -27,7 +27,7 @@ std::vector<std::string> installed_font_dirs();
std::string default_font_dir();
// Every installable font family found across those directories.
std::vector<std::string> 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).

View File

@@ -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<std::string, strings_t> line_split(fs::path pathname)
std::pair<std::string, strings_t> line_split(const fs::path& pathname)
{
std::string source {};
strings_t lines {};

View File

@@ -99,8 +99,8 @@ std::vector<Katom> trim(const std::vector<Katom>& katoms, bool trim_inactive = f
std::vector<std::vector<Katom>> bar_split(std::vector<Katom>::iterator kbegin, std::vector<Katom>::iterator kend);
std::vector<std::string> line_split(std::string s);
std::pair<std::string, std::vector<std::string>> line_split(fs::path pathname);
std::vector<std::string> line_split(const std::string& s);
std::pair<std::string, std::vector<std::string>> line_split(const fs::path& pathname);
std::vector<Katom> katomize(const std::vector<std::string>& lines, const std::string& source_desc);
void warn_unparsed_katoms(std::vector<Katom>& katoms, bool warn = true);

View File

@@ -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<bool(const Katom&)> level_inc,
std::function<bool(const Katom&)> level_dec,
const std::function<bool(const Katom&)>& level_inc,
const std::function<bool(const Katom&)>& 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<bool(const Katom&)> level_inc,
std::function<bool(const Katom&)> level_dec,
const std::function<bool(const Katom&)>& level_inc,
const std::function<bool(const Katom&)>& 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);
}

View File

@@ -23,17 +23,17 @@ find_katom(const std::vector<Katom>::iterator begin, const std::vector<Katom>::i
std::vector<std::pair<Katom, Katom>>
find_spans(std::vector<Katom>::iterator begin, std::vector<Katom>::iterator end,
std::function<bool(const Katom&)> level_inc,
std::function<bool(const Katom&)> level_dec,
const std::function<bool(const Katom&)>& level_inc,
const std::function<bool(const Katom&)>& level_dec,
bool error_exit,
std::string name);
const std::string& name);
std::vector<std::pair<Katom, Katom>>
find_spans(std::vector<Katom>& katoms,
std::function<bool(const Katom&)> level_inc,
std::function<bool(const Katom&)> level_dec,
const std::function<bool(const Katom&)>& level_inc,
const std::function<bool(const Katom&)>& level_dec,
bool error_exit=true,
std::string name="all");
const std::string& name="all");
void describe_spans(const std::vector<Katom>& katoms);

View File

@@ -13,7 +13,7 @@ using namespace std::literals;
std::regex Klammer::name_re = std::regex(R"((\w+)(?:\.(\w+))?)");
std::tuple<std::string, std::string>
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<Katom, Parameter_set, katom_list, Locator>
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<std::string> target_names)
auto Klammer::target_defs(const std::vector<std::string>& target_names)
{
std::vector<Klammer::components> 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<Klammer::components> cs, Target_set targets)
const Parameter_set& parameters, const std::vector<Klammer::components>& 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<Klammer::components> 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<std::string> target_names = targets.applicable();
std::vector<Parameter_set> 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<Klammer::components> declares)
void Klammer::many_declarations(const std::vector<Klammer::components>& declares)
{
(void)K::log(4);
// std::cout << boldblack << "Many declarations\n" << black;
@@ -353,10 +354,10 @@ void Klammer::many_declarations(std::vector<Klammer::components> 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<Argument> arguments)
void show_args(const std::string& label_text, const std::vector<Argument>& 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<Argument> 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();

View File

@@ -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<Katom>::iterator begin, std::vector<Katom>::iterator end);
void remove_target_definition(const std::string& target_name);
auto target_defs(std::vector<std::string> target_names);
auto target_defs(const std::vector<std::string>& 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<Klammer::components> cs, Target_set targets);
const Parameter_set& parameters, const std::vector<Klammer::components>& 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<Klammer::components> 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<Klammer::components>& 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<std::string, bool> 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<std::string,std::string>
parse_name(Target_set targets, Katom name_katom);
parse_name(const Target_registry& targets, const Katom& name_katom);
std::tuple<Katom, Parameter_set, std::vector<Katom>, Locator>
parse_definition_katoms(Argtype_set argtypes, //Target_set targets,
parse_definition_katoms(const std::string& klammer_name, const Argtype_registry& argtypes,
std::vector<Katom>::iterator& begin, std::vector<Katom>::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);

View File

@@ -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<Katom>* Klammer_set::constant_body(const std::string& name) const
const std::vector<Katom>* 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<Katom>* 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<std::string, Klammer> ss)
int max_length(const std::map<std::string, Klammer>& ss)
{
size_t result = 0;
for_each(ss.begin(), ss.end(),
@@ -141,19 +141,19 @@ int max_length(std::map<std::string, Klammer> 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);

View File

@@ -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<Katom>::iterator begin, std::vector<Katom>::iterator end, std::vector<Katom>& 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<Katom>* constant_body(const std::string& name) const;
std::string instance_list(int margin) const;
std::string describe(int margin=0) const;

8
mac/klammerset.cpp Normal file
View File

@@ -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)
{
}

28
mac/klammerset.h Normal file
View File

@@ -0,0 +1,28 @@
#pragma once
#include <string>
#include <vector>
#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<std::string> m_requires {}; // klammerset declaration files, loaded first
std::vector<std::string> m_files {}; // definition files, loaded in list order
Locator m_loc {}; // the declaring file; relative names resolve against it
};

225
mac/klammerset_registry.cpp Normal file
View File

@@ -0,0 +1,225 @@
#include <cctype>
#include <cstdlib>
#include <iomanip>
#include <sstream>
#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> Klammerset_registry::add(
std::vector<Katom>::iterator begin, std::vector<Katom>::iterator end, std::vector<Katom>& 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<unsigned char>(symbol[0]));
for (char c : symbol) {
if (!std::isalnum(static_cast<unsigned char>(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<unsigned char>(name[0]))) {
return false;
}
for (char c : name) {
if (!std::isalnum(static_cast<unsigned char>(c)) && c != '_') {
return false;
}
}
return true;
}
std::vector<std::string> klammerset_search_dirs(const std::string& local_dir)
{
std::vector<std::string> 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<std::string> 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<std::string, std::string> 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<std::string> 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();
}

63
mac/klammerset_registry.h Normal file
View File

@@ -0,0 +1,63 @@
#pragma once
#include <map>
#include <optional>
#include <string>
#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<Klammerset> add(std::vector<Katom>::iterator begin, std::vector<Katom>::iterator end, std::vector<Katom>& 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<std::string, Klammerset> m_klammersets {};
std::vector<std::string> 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 <dir>/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<std::string> 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);

View File

@@ -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)

View File

@@ -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;

View File

@@ -9,10 +9,10 @@
#include "eval.h"
Machine::Machine()
: m_argtypes(Argtype_set())
: m_argtypes(Argtype_registry())
, m_state(State())
, m_targets(Target_set())
, m_klammers(Klammer_set())
, m_targets(Target_registry())
, m_klammers(Klammer_registry())
{
(void)K::log(3);
m_state.add_environment_frame();
@@ -352,6 +352,13 @@ void Machine::extract_machine_definitions()
if (m_katoms.empty()) {
return;
}
// 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, '@');
@@ -362,8 +369,61 @@ void Machine::extract_machine_definitions()
m_argtypes.add(begin, end, m_katoms);
} else if (name == "@@@state") {
m_state.parse_state_katoms(begin, end, m_katoms);
} else if (name == "@@@klammerset") {
if (auto klammerset = m_klammersets.add(begin, end, m_katoms)) {
load_klammerset_files(*klammerset, end);
rescan = true;
break;
}
}
}
}
}
void Machine::load_klammerset_files(const Klammerset& klammerset, katom_iter insert_at)
{
(void)K::log(2, "Loading klammerset \"" + klammerset.m_symbol + "\"");
// Relative names resolve against the declaring file's directory, never
// the cwd. :requires files are read before the set's own files; each
// holds its own @@@klammerset declaration, whose already-loaded guard
// makes repeated requirements a no-op.
fs::path declaring(klammerset.m_loc.m_filename);
fs::path base = fs::exists(declaring) ? declaring : fs::current_path();
std::string base_dir = (is_directory(base) ? base : base.parent_path()).string();
// A :requires entry may be a bare symbol, resolved on the klammerset
// search path with the declaring directory as the local stage; :files
// entries are always filenames (this set's own definition files).
std::vector<std::string> filenames {};
for (const auto& required : klammerset.m_requires) {
if (is_klammerset_symbol(required)) {
filenames.push_back(
resolve_klammerset_symbol(required, base_dir, klammerset.m_loc).string());
} else {
filenames.push_back(required);
}
}
filenames.insert(filenames.end(), klammerset.m_files.begin(), klammerset.m_files.end());
// Collect all files into one list and insert once: insert_at is
// invalidated by the first insertion into m_katoms.
katom_list loaded {};
for (const auto& filename : filenames) {
fs::path pathname = resolve_relative_to(filename, base);
if (!fs::exists(pathname)) {
throw Klammerset_error(
"Klammerset \"" + klammerset.m_symbol + "\" lists the file \"" + filename
+ "\", which does not exist (resolved to \"" + pathname.string() + "\")",
klammerset.m_loc);
}
pathname = fs::canonical(pathname);
m_state.add_search_dir(pathname.parent_path().string());
std::string text = trim_right(string_from_file(pathname.string()));
katom_list ks = katomize(line_split(text), pathname);
process_katoms(ks, pathname);
loaded.insert(loaded.end(), ks.begin(), ks.end());
}
m_katoms.insert(insert_at, loaded.begin(), loaded.end());
}
void Machine::extract_klammer_definitions(katom_list katoms)
@@ -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);
}
}

View File

@@ -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"
@@ -25,6 +26,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)
{}
@@ -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<Katom> m_katoms {};

View File

@@ -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<std::string,std::string> 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;
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;

View File

@@ -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);

View File

@@ -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<std::string> 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<Var, bool> Frame::get(std::string name)
std::pair<Var, bool> Frame::get(const std::string& name) const
{
std::pair<Var, bool> 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<Var, bool> 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<std::string, std::string> varmap)
void State::set(const std::map<std::string, std::string>& 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<std::string, std::string>& 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<std::string> State::all_names()
std::vector<std::string> State::all_names() const
{
std::vector<std::string> 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 = "<no-value>";

View File

@@ -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<std::string> names() const;
void set(std::string name, std::string value,
std::string delim=":", std::string desc="", Locator loc=Locator(),
Argtype argtype=Argtype());
std::pair<Var, bool> 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<Var, bool> get(const std::string& name) const;
std::string m_name {};
std::map<std::string, Var> 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<std::string, std::string> 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<std::string, std::string>& varmap);
void set(const std::map<std::string, std::string>& 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<Katom>::iterator begin, std::vector<Katom>::iterator end);
void parse_state_katoms(std::vector<Katom>::iterator begin, std::vector<Katom>::iterator end, katom_list katoms);
std::vector<std::string> all_names();
void parse_state_katoms(std::vector<Katom>::iterator begin, std::vector<Katom>::iterator end, katom_list& katoms);
std::vector<std::string> 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;

View File

@@ -7,24 +7,24 @@
//#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(
@@ -32,7 +32,7 @@ void Target::transform(katom_list& katoms)
[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<std::pair<std::string, std::string>>
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);
}

View File

@@ -11,25 +11,25 @@ class Target
{
public:
Target() = default;
// Target(std::vector<Katom>::iterator begin, std::vector<Katom>::iterator end, Argtype_set argtypes);
Target(std::string name, std::string desc, Locator loc)
// Target(std::vector<Katom>::iterator begin, std::vector<Katom>::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<std::pair<std::string, std::string>> transforms);
void transform(std::vector<Katom>& 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<std::pair<std::string, std::string>>& transforms);
void transform(std::vector<Katom>& 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<std::pair<std::string, std::string>> m_transforms {};
std::vector<std::pair<std::string, std::string>> m_escapes {};
// Argtype_set m_argtypes {};
// Argtype_registry m_argtypes {};
};
std::vector<std::pair<std::string, std::string>>
parse_transforms(std::string transform_string);
parse_transforms(const std::string& transform_string);
// Decode every KTESC<hex>KTESC marker in text back to its original
// characters. Used for the final output (after target-declared escapes have

View File

@@ -1,8 +1,7 @@
#include <sstream>
#include <iterator>
#include <algorithm>
#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<Katom>::iterator begin, std::vector<Katom>::iterator end, std::vector<Katom>& katoms)
void Target_registry::add(std::vector<Katom>::iterator begin, std::vector<Katom>::iterator end, std::vector<Katom>& katoms)
{
(void)K::log(3, *begin, *(end - 1));
auto [positional, optional, rest] =
@@ -40,14 +38,10 @@ void Target_set::add(std::vector<Katom>::iterator begin, std::vector<Katom>::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<Katom>::iterator begin, std::vector<Katom>::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<Katom>::iterator begin, std::vector<Katom>::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<std::string> Target_set::user_defined()
std::vector<std::string> 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<std::string> Target_set::applicable()
std::vector<std::string> 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<std::string> 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) {

View File

@@ -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<Katom>::iterator begin, std::vector<Katom>::iterator end, std::vector<Katom>& 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<Katom>& 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<Katom>& katoms) const;
std::vector<std::string> user_defined();
std::vector<std::string> applicable();
std::vector<std::string> user_defined() const;
std::vector<std::string> applicable() const;
std::string describe(int margin=2, bool long_format=false) const;
//Argtype_set m_argtypes {};
//Argtype_registry m_argtypes {};
std::map<std::string, Target> m_targets {};
std::vector<std::string> m_names {};
std::vector<std::string> 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);

View File

@@ -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<std::pair<std::string, std::string>> 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<std::string>& ss, std::string removed)
void remove_element(std::vector<std::string>& 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<std::string,std::string> extract_parameter_type(std::string parameter_name)
std::pair<std::string,std::string> 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<std::string(std::smatch)> func)
std::string freplace(const std::string& src, const std::regex& pattern,
const std::function<std::string(std::smatch)>& func)
{
std::string result {};
std::smatch match;

View File

@@ -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<std::string>& strings, const std::string& element);
std::vector<std::string> regex_split(std::string s, std::regex re, bool trim_parts=true);
std::vector<std::string> regex_split(const std::string& s, const std::regex& re, bool trim_parts=true);
std::vector<std::string> word_split(const std::string& s);
bool is_in(std::string s, std::vector<std::string> v);
bool is_not_in(std::string s, std::vector<std::string> v);
std::vector<std::string> find_all(std::string str, std::regex pattern, int match_group=0);
std::vector<std::string> 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<std::string>& v);
bool is_not_in(const std::string& s, const std::vector<std::string>& v);
std::vector<std::string> find_all(const std::string& str, const std::regex& pattern, int match_group=0);
std::vector<std::string> 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<std::string>& 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<std::string>& things);
std::string to_be(int count, bool present = true);
int max_length(std::vector<std::string> ss);
int max_length(const std::vector<std::string>& ss);
std::vector<std::pair<std::string, std::string>> 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<std::string>& ss, std::string removed);
void remove_element(std::vector<std::string>& ss, const std::string& removed);
void remove_duplicates(std::vector<std::string>& ss);
std::string display_string(const std::string& s, unsigned int width=40, bool replace_newlines=true);
std::pair<std::string,std::string> extract_parameter_type(std::string parameter_name);
std::pair<std::string,std::string> extract_parameter_type(const std::string& parameter_name);
std::tuple<std::string, std::string, bool> regex_split_prefix(const std::regex& pattern, const std::string& text);
std::vector<std::string> 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<std::string(std::smatch)> func);
std::string freplace(const std::string& src, const std::regex& pattern,
const std::function<std::string(std::smatch)>& 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<T>& v) {
}
template <typename T>
int max_key_length(std::map<std::string, T> map)
int max_key_length(const std::map<std::string, T>& map)
{
size_t result = 0;
for_each(map.begin(), map.end(),

View File

@@ -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<std::string> 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);

View File

@@ -16,7 +16,7 @@ inline std::map<std::string, int> html_tags {
using string_pairs_t = std::vector<std::pair<std::string,std::string>>;
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<std::string> basenames);
void write_basenames_js_file(const std::string& filename, const std::vector<std::string>& basenames);
std::string create_html_output_directories();
std::string create_tex_output_directories();
std::pair<std::vector<std::string>, std::vector<std::string>>
html_auxiliary_files(std::string output_directory, std::string pages_basename_filename,
std::vector<std::string> custom_css_files);
html_auxiliary_files(const std::string& output_directory, const std::string& pages_basename_filename,
const std::vector<std::string>& custom_css_files);
void process_input_files();
std::vector<Heading> insert_section_numbers(std::string marker="___NUM___", bool add_to_toc=true);
std::vector<Heading> insert_section_numbers(const std::string& marker="___NUM___", bool add_to_toc=true);
void insert_html_caption_numbers();
std::vector<std::tuple<std::string, std::string, std::string>> reference_list(std::string target_marker);
std::vector<std::tuple<std::string, std::string, std::string>> reference_list(const std::string& target_marker);
std::map<std::string, std::string> id_to_caption_number();
std::map<std::string, std::vector<std::pair<std::string, std::string>>> 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<Heading> headings);
const std::string& output_directory, std::vector<Heading> 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<std::string> combine_files(
std::vector<std::string> filenames, std::string output_filename,
std::string prolog="", std::string epilog="",
const std::vector<std::string>& filenames, const std::string& output_filename,
const std::string& prolog="", const std::string& epilog="",
bool write_file_p=true,
std::function <std::string(std::string)> processor=nullptr);
*/

View File

@@ -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<std::string> basenames)
void Document_class::write_basenames_js_file(const std::string& filename, const std::vector<std::string>& 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<std::string> 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<std::string>, std::vector<std::string>>
Document_class::html_auxiliary_files(std::string output_directory, std::string pages_basenames_filename,
std::vector<std::string> custom_css_files)
Document_class::html_auxiliary_files(const std::string& output_directory, const std::string& pages_basenames_filename,
const std::vector<std::string>& 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<int> &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<Heading>
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<int> 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<std::string, int>& numbers, std::string label)
int get_caption_number(std::map<std::string, int>& 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<std::tuple<std::string, std::string, std::string>>
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("<div id=\"(.*?)\" data-label=\"(.*?)\" class=\"caption_");
@@ -519,7 +519,7 @@ std::map<std::string, std::string> Document_class::id_to_caption_number()
}
std::pair<int, int> offset_spec_to_count(std::string spec)
std::pair<int, int> 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<Heading> headings)
const std::string& output_directory, std::vector<Heading> headings)
{
msg() << "Navigation format\n";
std::vector<std::string> pages_basenames {};

View File

@@ -40,7 +40,7 @@ int unnumbered_id = 0;
/*
std::tuple<std::string, std::vector<Heading>, std::vector<unsigned int>, unsigned int>
add_section_numbers(std::string s, std::string basename, std::vector<unsigned int> levels, unsigned int initial_id,
add_section_numbers(const std::string& s, const std::string& basename, std::vector<unsigned int> levels, unsigned int initial_id,
std::map<std::string, std::string>& section_id_map)
{
(void)K::log(3);
@@ -155,7 +155,7 @@ std::string make_html_table_of_contents(std::vector<Heading> 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<Heading> headings)
}
void show_table_of_contents(
std::string kt_root_filename, std::string title, std::vector<Heading> headings)
const std::string& kt_root_filename, const std::string& title, std::vector<Heading> 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<Heading> headings)
const std::string& kt_root_filename, const std::string& title, std::vector<Heading> headings)
{
long unsigned int width = kt_root_filename.size();
for (Heading h : headings) {

View File

@@ -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::string, std::vector<Heading>, std::vector<unsigned int>, unsigned int>
add_section_numbers(std::string s, std::string basename, std::vector<unsigned int> levels, unsigned int initial_id,
add_section_numbers(const std::string& s, const std::string& basename, std::vector<unsigned int> levels, unsigned int initial_id,
std::map<std::string, std::string>& section_id_map);
*/
@@ -35,7 +35,7 @@ std::pair<int, std::string>
make_navigation_table_of_contents(std::vector<Heading> headings);
void show_table_of_contents(
std::string kt_filename, std::string title, std::vector<Heading> headings);
const std::string& kt_filename, const std::string& title, std::vector<Heading> headings);
std::string cache_table_of_contents(
std::string kt_root_filename, std::string title, std::vector<Heading> headings);
const std::string& kt_root_filename, const std::string& title, std::vector<Heading> headings);

View File

@@ -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<std::string> lines)
numbered_elements latex_line_states(const std::vector<std::string>& 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<std::string> lines)
return states;
}
std::string find_target(std::string target,
std::vector<std::string>& 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<std::string>& 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<std::string> lines, numbered_elements states)
const std::string& target, const std::vector<std::string>& lines, numbered_elements states)
{
//auto lines = regex_split(text, std::regex(R"(\n)"), false);
// numbered_elements states = line_states(lines);

View File

@@ -11,12 +11,12 @@ using numbered_element_spec = std::tuple<std::string, std::string, std::string>;
//using numbered_elements = std::vector<std::vector<numbered_element_spec>>;
using numbered_elements = std::vector<numbered_element_spec>;
numbered_elements html_line_states(std::vector<std::string> lines);
numbered_elements latex_line_states(std::vector<std::string> lines);
numbered_elements html_line_states(const std::vector<std::string>& lines);
numbered_elements latex_line_states(const std::vector<std::string>& lines);
std::pair<std::string, int> add_html_caption_numbers(std::string html_text, int& chapter_number);
std::string add_latex_caption_numbers(std::string text);
std::pair<std::string, int> 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<std::string> lines, numbered_elements states);
const std::string& target, const std::vector<std::string>& lines, numbered_elements states);

View File

@@ -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";

View File

@@ -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;
};

View File

@@ -10,7 +10,7 @@
#include <filesystem>
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<std::string> subset)
bool in_subset(const std::string& base, const std::vector<std::string>& 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<std::string> subset)
std::vector<std::string> sks_files_of_type(std::string extension, std::vector<std::string> subset)
std::vector<std::string> sks_files_of_type(const std::string& extension, const std::vector<std::string>& subset)
{
bool dbg = false;
std::string kdir = klammertext_dir();
@@ -85,7 +85,7 @@ std::vector<std::string> sks_files_of_type(std::string extension, std::vector<st
return result;
}
std::string find_kt_file(std::string filename)
std::string find_kt_file(const std::string& filename)
{
std::string result {};
std::vector<std::string> 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);

View File

@@ -12,24 +12,24 @@ std::vector<std::string> 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<std::string> old_sks_files_of_type(std::string extension);
std::vector<std::string> sks_files_of_type(std::string extension, std::vector<std::string> subset={});
std::vector<std::string> old_sks_files_of_type(const std::string& extension);
std::vector<std::string> sks_files_of_type(const std::string& extension, const std::vector<std::string>& 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);

View File

@@ -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
@@@

View File

@@ -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<int, float, std::string> 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<std::string> hidden = {"Clear", "Back"};
HTML result = elt("span", string_replace(name, " ", "&#160;")).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;

View File

@@ -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<HTML>& 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<std::string> js_filenames, std::string output_dir);
void add_js_links(elements_t& body, const std::vector<std::string>& js_filenames, const std::string& output_dir);
elements_t make_page(
elements_t body,
std::string page_title, std::string css,
std::vector<std::string> css_filenames,
std::vector<std::string> local_fonts);
std::string page_title, const std::string& css,
const std::vector<std::string>& css_filenames,
const std::vector<std::string>& 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);
}

View File

@@ -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,

View File

@@ -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 = {},

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1 @@
@@@klammerset broken | Lists a file that does not exist :files missing.k @@@

1
tst/klammerset/base.k Normal file
View File

@@ -0,0 +1 @@
@@@target fix | Fixture target @@@

11
tst/klammerset/decl.k Normal file
View File

@@ -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 @@

1
tst/klammerset/decl2.k Normal file
View File

@@ -0,0 +1 @@
@@@klammerset kit | Duplicate declaration of kit :files dup_only.k @@@

View File

@@ -0,0 +1 @@
@@only_dup : DUP @@

View File

@@ -0,0 +1 @@
@@greet.fix name : Hello *name* @@

View File

@@ -0,0 +1 @@
@@spacey.fix : SPACEY @@

1
tst/klammerset/spacey.k Normal file
View File

@@ -0,0 +1 @@
@@@klammerset sp | Spacey filename in the list :files base.k / space name.k @@@

2
tst/klammerset/util.k Normal file
View File

@@ -0,0 +1,2 @@
@@@klammerset util | Utility klammers for engine tests :date 2026-07-30 @@@
@@dash : -- @@

1
tst/klammerset/wrapper.k Normal file
View File

@@ -0,0 +1 @@
@@@klammerset wrap | Wrapper requiring kit twice :requires decl.k / decl2.k @@@

284
tst/klammerset_test.sh Executable file
View File

@@ -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 -> <dir>/<symbol>/<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 <symbol>/<symbol>.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 ]