Files
klammertext/mac/argtype.cpp
Andy Kopra ef77f03584 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)
2026-07-30 23:50:07 +02:00

123 lines
3.6 KiB
C++

#include <set>
#include <regex>
#include <sstream>
#include "argtype.h"
#include "error.h"
#include "util.h"
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)
, m_symbolic_pattern(symbolic_pattern)
, m_pattern(pattern)
, m_default(default_value)
, m_alone(alone_value)
, m_python_cast(python_cast)
, m_python_format(python_format)
, m_regex(std::regex(pattern))
, m_loc(loc)
{
}
static bool empty_value(const strings_t& v)
{
return v.empty() || (v.size() == 1 && v[0].empty());
}
std::string pyformat_string(const strings_t& v)
{
std::string p = v.empty() ? "" : v[0];
p = string_replace(p, "\\", "\\\\");
p = string_replace(p, "\"", "\\\"");
p = string_replace(p, "\n", "\\n");
return "\"" + p + "\"";
}
std::string pyformat_bool(const strings_t& v)
{
if (empty_value(v)) {
return "None";
}
std::string value = v[0];
std::set<std::string> true_values { "1", "true", "True", "yes" };
std::set<std::string> false_values { "0", "false", "False", "no" };
if (true_values.contains(value)) {
return "True";
} else if (false_values.contains(value)) {
return "False";
} else {
throw Argument_error("The argument\"" + value + "\" is not a Boolean value");
}
}
std::string pyformat_number(const strings_t& value)
{
if (empty_value(value)) {
return "None";
}
return value[0];
}
std::string pylist(strings_t words)
{
std::transform(words.begin(), words.end(), words.begin(),
[](const std::string& s) { return pyformat_string({s}); });
return "[" + join(words, ", ") + "]";
}
std::string pyformat_list(const strings_t& value)
{
strings_t words {};
for (const std::string& v : value) {
for (const std::string& word : word_split(v)) {
if (!word.empty()) {
words.push_back(word);
}
}
}
return pylist(words);
}
std::string pyformat_dlist(const strings_t& value)
{
strings_t items {};
for (const std::string& v : value) {
if (v.empty()) {
continue;
}
for (const std::string& item : dlist_split(v)) {
items.push_back(item);
}
}
return pylist(items);
}
std::string Argtype::python_value(const std::string& var_name, std::vector<std::string> value, size_t name_size)
{
std::stringstream ss {};
ss << " " << std::left << std::setw(name_size) << var_name << " = ";
if (m_python_format) {
ss << m_python_format(value);
} else if (m_python_cast.empty() || m_python_cast == "str") {
// String-family types (and untyped variables): plain quoted string.
ss << pyformat_string(value);
} else if (!m_parameter.empty()) {
// Parameterized type: bind the type parameter as N around the
// cast, e.g. (lambda N: <cast>)(2)("A | B || C | D").
ss << "(lambda N: " << m_python_cast << ")(" << m_parameter << ")("
<< pyformat_string(value) << ")";
} else {
// User-defined :python_cast expression, applied to the raw value.
// The cast is applied to an empty value too, so e.g. a split lambda
// yields [] for an unsupplied argument.
ss << m_python_cast << "(" << pyformat_string(value) << ")";
}
return ss.str();
}