2026-07-18 18:48:23 +02:00
|
|
|
#include <regex>
|
|
|
|
|
#include <sstream>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <numeric>
|
|
|
|
|
|
|
|
|
|
#include "argtype_set.h"
|
|
|
|
|
#include "error.h"
|
|
|
|
|
#include "show.h"
|
|
|
|
|
#include "log.h"
|
|
|
|
|
#include "util.h"
|
|
|
|
|
#include "character.h"
|
|
|
|
|
#include "katom.h"
|
|
|
|
|
|
|
|
|
|
Parameter_set& Argtype_set::parameters()
|
|
|
|
|
{
|
2026-07-28 22:24:32 +02:00
|
|
|
static Parameter_set instance("name | desc :pattern .* :python_cast str :default :alone");
|
2026-07-18 18:48:23 +02:00
|
|
|
return instance;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Argtype_set::Argtype_set()
|
|
|
|
|
{
|
|
|
|
|
(void)(void)K::log(2);
|
|
|
|
|
Locator loc = current_locator();
|
|
|
|
|
for (auto [name, desc, pattern, python_cast, python_format] : base_argtypes) {
|
2026-07-28 22:24:32 +02:00
|
|
|
add(name, desc, pattern, "", "", python_cast, python_format, loc);
|
2026-07-18 18:48:23 +02:00
|
|
|
}
|
Typed arguments, calculated tables, spans, closed-world fonts, top-level fnt/ and env/
Sync with klammertext-dev through b90b0e09:
- Argument types end to end: :python_cast values are applied (Python
@eval receives real bools/numbers/lists), argument values are
validated against their argtype patterns with the argtype's
description as the error message, argtypes can declare :default
(overridable per declaration), and parameterized type families are
supported: rest(N) casts a rest argument to an N-dimensional list
(bar-count = dimension).
- Unified indexed_range syntax (selector with parenthesized subsets,
composable mnemonic names) for table lines and spans.
- Table klammer: caption fonts fixed in both targets, :column_width /
:leading / :colsep wired, :colspan and :rowspan render (HTML
attributes; \multicolumn / \multirow), calculated cell values (:calc)
with prefix operators, display-precision semantics, :calc_format and
:decimal period|comma.
- Fonts: closed-world resolution on the Klammertext font store
(infrastructure in mac/font_store; no Google Fonts links or fetch).
Default fonts live in the top-level fnt/; additional fonts install
into KLAMMERTEXT_FONTS directories via kdesc --font (list, samples,
preview, install — classification by font metadata). CSS font family
names are quoted (digit-initial families were silently lost).
- Environment files moved from mac/env/ to the top-level env/; shell
profiles source env/runtime.env. Dead per-host variants removed.
- Container: fnt/ ships in the image; curl removed (no network use).
2026-07-22 18:17:43 +02:00
|
|
|
// rest is a parameterized type (rest(N)); an unparameterized use is
|
|
|
|
|
// one-dimensional.
|
|
|
|
|
m_types["rest"].m_parameter = "1";
|
2026-07-28 22:24:32 +02:00
|
|
|
// A bool option written alone is true: :number means :number true.
|
|
|
|
|
// This is a declaration like any other type's :alone, not an engine
|
|
|
|
|
// special case for booleans.
|
|
|
|
|
m_types["bool"].m_alone = "true";
|
2026-07-18 18:48:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string Argtype_set::replace_symbols(const std::string& pattern, const Locator& loc)
|
|
|
|
|
{
|
|
|
|
|
std::smatch match {};
|
|
|
|
|
std::regex symbol_pat(R"('(\w+)')");
|
|
|
|
|
std::string expanded { pattern };
|
|
|
|
|
for (const std::string& symbol : find_all(pattern, symbol_pat, 0)) {
|
|
|
|
|
std::string name { symbol.begin()+1, symbol.end()-1 };
|
|
|
|
|
if (m_types.find(name) != m_types.end()) {
|
|
|
|
|
expanded = string_replace(
|
|
|
|
|
expanded, symbol, R"((?:)" + m_types[name].m_pattern + R"())");
|
|
|
|
|
} else {
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
ss << "Argtype symbol " << symbol << " not defined.\n\n"
|
|
|
|
|
<< "Defined argtypes:\n";
|
|
|
|
|
ss << describe();
|
|
|
|
|
throw Definition_error(ss.str(), loc, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return expanded;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Argtype_set::check_for_existing_definition(
|
|
|
|
|
const std::string& name, const Locator& loc)
|
|
|
|
|
{
|
|
|
|
|
if (count(m_names.begin(), m_names.end(), name) > 0) {
|
|
|
|
|
std::stringstream ss {};
|
|
|
|
|
ss << "Argument type '" << name << "' is already defined at "
|
|
|
|
|
<< m_types[name].m_loc;
|
|
|
|
|
throw Definition_error(ss.str(), loc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Typed arguments, calculated tables, spans, closed-world fonts, top-level fnt/ and env/
Sync with klammertext-dev through b90b0e09:
- Argument types end to end: :python_cast values are applied (Python
@eval receives real bools/numbers/lists), argument values are
validated against their argtype patterns with the argtype's
description as the error message, argtypes can declare :default
(overridable per declaration), and parameterized type families are
supported: rest(N) casts a rest argument to an N-dimensional list
(bar-count = dimension).
- Unified indexed_range syntax (selector with parenthesized subsets,
composable mnemonic names) for table lines and spans.
- Table klammer: caption fonts fixed in both targets, :column_width /
:leading / :colsep wired, :colspan and :rowspan render (HTML
attributes; \multicolumn / \multirow), calculated cell values (:calc)
with prefix operators, display-precision semantics, :calc_format and
:decimal period|comma.
- Fonts: closed-world resolution on the Klammertext font store
(infrastructure in mac/font_store; no Google Fonts links or fetch).
Default fonts live in the top-level fnt/; additional fonts install
into KLAMMERTEXT_FONTS directories via kdesc --font (list, samples,
preview, install — classification by font metadata). CSS font family
names are quoted (digit-initial families were silently lost).
- Environment files moved from mac/env/ to the top-level env/; shell
profiles source env/runtime.env. Dead per-host variants removed.
- Container: fnt/ ships in the image; curl removed (no network use).
2026-07-22 18:17:43 +02:00
|
|
|
void Argtype_set::add(const std::string& name, const std::string& desc,
|
|
|
|
|
const std::string& pattern, const std::string& default_value,
|
2026-07-28 22:24:32 +02:00
|
|
|
const std::string& alone_value,
|
2026-07-18 18:48:23 +02:00
|
|
|
const std::string& python_cast, modify_string_f python_format,
|
|
|
|
|
const Locator& loc)
|
|
|
|
|
{
|
|
|
|
|
// (void)K::log(3, name, ":", abbrev(string_replace(desc, "\n", "/"), 50), pattern);
|
|
|
|
|
check_for_existing_definition(name, loc);
|
|
|
|
|
std::string expanded_pattern = replace_symbols(pattern, loc);
|
|
|
|
|
m_name_size = std::max(m_name_size, name.size()); // For display
|
|
|
|
|
m_pattern_size = std::max(m_pattern_size, expanded_pattern.size());
|
Typed arguments, calculated tables, spans, closed-world fonts, top-level fnt/ and env/
Sync with klammertext-dev through b90b0e09:
- Argument types end to end: :python_cast values are applied (Python
@eval receives real bools/numbers/lists), argument values are
validated against their argtype patterns with the argtype's
description as the error message, argtypes can declare :default
(overridable per declaration), and parameterized type families are
supported: rest(N) casts a rest argument to an N-dimensional list
(bar-count = dimension).
- Unified indexed_range syntax (selector with parenthesized subsets,
composable mnemonic names) for table lines and spans.
- Table klammer: caption fonts fixed in both targets, :column_width /
:leading / :colsep wired, :colspan and :rowspan render (HTML
attributes; \multicolumn / \multirow), calculated cell values (:calc)
with prefix operators, display-precision semantics, :calc_format and
:decimal period|comma.
- Fonts: closed-world resolution on the Klammertext font store
(infrastructure in mac/font_store; no Google Fonts links or fetch).
Default fonts live in the top-level fnt/; additional fonts install
into KLAMMERTEXT_FONTS directories via kdesc --font (list, samples,
preview, install — classification by font metadata). CSS font family
names are quoted (digit-initial families were silently lost).
- Environment files moved from mac/env/ to the top-level env/; shell
profiles source env/runtime.env. Dead per-host variants removed.
- Container: fnt/ ships in the image; curl removed (no network use).
2026-07-22 18:17:43 +02:00
|
|
|
try {
|
|
|
|
|
m_types[name] = Argtype(name, desc, pattern, expanded_pattern,
|
2026-07-28 22:24:32 +02:00
|
|
|
default_value, alone_value,
|
|
|
|
|
python_cast, python_format, loc);
|
Typed arguments, calculated tables, spans, closed-world fonts, top-level fnt/ and env/
Sync with klammertext-dev through b90b0e09:
- Argument types end to end: :python_cast values are applied (Python
@eval receives real bools/numbers/lists), argument values are
validated against their argtype patterns with the argtype's
description as the error message, argtypes can declare :default
(overridable per declaration), and parameterized type families are
supported: rest(N) casts a rest argument to an N-dimensional list
(bar-count = dimension).
- Unified indexed_range syntax (selector with parenthesized subsets,
composable mnemonic names) for table lines and spans.
- Table klammer: caption fonts fixed in both targets, :column_width /
:leading / :colsep wired, :colspan and :rowspan render (HTML
attributes; \multicolumn / \multirow), calculated cell values (:calc)
with prefix operators, display-precision semantics, :calc_format and
:decimal period|comma.
- Fonts: closed-world resolution on the Klammertext font store
(infrastructure in mac/font_store; no Google Fonts links or fetch).
Default fonts live in the top-level fnt/; additional fonts install
into KLAMMERTEXT_FONTS directories via kdesc --font (list, samples,
preview, install — classification by font metadata). CSS font family
names are quoted (digit-initial families were silently lost).
- Environment files moved from mac/env/ to the top-level env/; shell
profiles source env/runtime.env. Dead per-host variants removed.
- Container: fnt/ ships in the image; curl removed (no network use).
2026-07-22 18:17:43 +02:00
|
|
|
} catch (const std::regex_error& e) {
|
|
|
|
|
std::stringstream ss {};
|
|
|
|
|
ss << "The pattern for argument type \"" << name
|
|
|
|
|
<< "\" is not a valid regular expression (" << e.what() << "):\n"
|
|
|
|
|
<< " " << pattern << "\n";
|
|
|
|
|
if (pattern != expanded_pattern) {
|
|
|
|
|
ss << "expanded to:\n " << expanded_pattern << "\n";
|
|
|
|
|
}
|
|
|
|
|
throw Definition_error(ss.str(), loc, false);
|
|
|
|
|
}
|
|
|
|
|
if (!default_value.empty() &&
|
|
|
|
|
!std::regex_match(default_value, m_types[name].m_regex)) {
|
|
|
|
|
std::stringstream ss {};
|
|
|
|
|
ss << "The default value \"" << default_value << "\" for argument type \""
|
|
|
|
|
<< name << "\" does not match its own pattern:\n"
|
|
|
|
|
<< " " << pattern << "\n";
|
|
|
|
|
throw Definition_error(ss.str(), loc, false);
|
|
|
|
|
}
|
2026-07-28 22:24:32 +02:00
|
|
|
if (!alone_value.empty()) {
|
|
|
|
|
// A pattern that matches running text cannot delimit a bare option
|
|
|
|
|
// name from the text after it: an option's value runs to the next
|
|
|
|
|
// bar or option name, so ":opt some words" would silently take
|
|
|
|
|
// "some words" as the value and the alone value would never be
|
|
|
|
|
// reached. A pattern that rejects multi-word text raises a clean
|
|
|
|
|
// argument error there instead. The test is behavioral rather
|
|
|
|
|
// than a comparison against matches_all()'s one literal pattern,
|
|
|
|
|
// because an @@@argtype written without a :pattern gets ".*",
|
|
|
|
|
// which is equally unable to delimit.
|
|
|
|
|
if (std::regex_match(std::string("one two"), m_types[name].m_regex)) {
|
|
|
|
|
std::stringstream ss {};
|
|
|
|
|
ss << "The argument type \"" << name << "\" cannot declare an :alone value "
|
|
|
|
|
<< "because its pattern matches running text:\n"
|
|
|
|
|
<< " " << pattern << "\n\n"
|
|
|
|
|
<< "An :alone value is used when an option name is written without a "
|
|
|
|
|
<< "value. A type that matches running text cannot tell a bare option "
|
|
|
|
|
<< "name from one whose value follows it, so the text after the name "
|
|
|
|
|
<< "would be taken as the value instead.\n";
|
|
|
|
|
throw Definition_error(ss.str(), loc, false);
|
|
|
|
|
}
|
|
|
|
|
if (!std::regex_match(alone_value, m_types[name].m_regex)) {
|
|
|
|
|
std::stringstream ss {};
|
|
|
|
|
ss << "The alone value \"" << alone_value << "\" for argument type \""
|
|
|
|
|
<< name << "\" does not match its own pattern:\n"
|
|
|
|
|
<< " " << pattern << "\n";
|
|
|
|
|
throw Definition_error(ss.str(), loc, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-07-18 18:48:23 +02:00
|
|
|
m_names.push_back(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Argtype_set::add(std::vector<Katom>::iterator begin, std::vector<Katom>::iterator end, std::vector<Katom>& katoms)
|
|
|
|
|
{
|
|
|
|
|
(void)K::log(3);
|
|
|
|
|
auto [positional, optional, rest] =
|
Typed arguments, calculated tables, spans, closed-world fonts, top-level fnt/ and env/
Sync with klammertext-dev through b90b0e09:
- Argument types end to end: :python_cast values are applied (Python
@eval receives real bools/numbers/lists), argument values are
validated against their argtype patterns with the argtype's
description as the error message, argtypes can declare :default
(overridable per declaration), and parameterized type families are
supported: rest(N) casts a rest argument to an N-dimensional list
(bar-count = dimension).
- Unified indexed_range syntax (selector with parenthesized subsets,
composable mnemonic names) for table lines and spans.
- Table klammer: caption fonts fixed in both targets, :column_width /
:leading / :colsep wired, :colspan and :rowspan render (HTML
attributes; \multicolumn / \multirow), calculated cell values (:calc)
with prefix operators, display-precision semantics, :calc_format and
:decimal period|comma.
- Fonts: closed-world resolution on the Klammertext font store
(infrastructure in mac/font_store; no Google Fonts links or fetch).
Default fonts live in the top-level fnt/; additional fonts install
into KLAMMERTEXT_FONTS directories via kdesc --font (list, samples,
preview, install — classification by font metadata). CSS font family
names are quoted (digit-initial families were silently lost).
- Environment files moved from mac/env/ to the top-level env/; shell
profiles source env/runtime.env. Dead per-host variants removed.
- Container: fnt/ ships in the image; curl removed (no network use).
2026-07-22 18:17:43 +02:00
|
|
|
argument_split(begin + 1, end - 1); //, Argtype_set::parameters.m_positional.size());
|
2026-07-18 18:48:23 +02:00
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
// std::for_each(begin, end+1, [](Katom& k) { k.m_type = katom_t::replaced; });
|
|
|
|
|
|
Typed arguments, calculated tables, spans, closed-world fonts, top-level fnt/ and env/
Sync with klammertext-dev through b90b0e09:
- Argument types end to end: :python_cast values are applied (Python
@eval receives real bools/numbers/lists), argument values are
validated against their argtype patterns with the argtype's
description as the error message, argtypes can declare :default
(overridable per declaration), and parameterized type families are
supported: rest(N) casts a rest argument to an N-dimensional list
(bar-count = dimension).
- Unified indexed_range syntax (selector with parenthesized subsets,
composable mnemonic names) for table lines and spans.
- Table klammer: caption fonts fixed in both targets, :column_width /
:leading / :colsep wired, :colspan and :rowspan render (HTML
attributes; \multicolumn / \multirow), calculated cell values (:calc)
with prefix operators, display-precision semantics, :calc_format and
:decimal period|comma.
- Fonts: closed-world resolution on the Klammertext font store
(infrastructure in mac/font_store; no Google Fonts links or fetch).
Default fonts live in the top-level fnt/; additional fonts install
into KLAMMERTEXT_FONTS directories via kdesc --font (list, samples,
preview, install — classification by font metadata). CSS font family
names are quoted (digit-initial families were silently lost).
- Environment files moved from mac/env/ to the top-level env/; shell
profiles source env/runtime.env. Dead per-host variants removed.
- Container: fnt/ ships in the image; curl removed (no network use).
2026-07-22 18:17:43 +02:00
|
|
|
add(values["name"], values["desc"], values["pattern"], values["default"],
|
2026-07-28 22:24:32 +02:00
|
|
|
values["alone"], values["python_cast"], modify_string_f{},
|
2026-07-18 18:48:23 +02:00
|
|
|
begin->m_loc);
|
|
|
|
|
|
|
|
|
|
modify_type(katom_t::replaced, begin, end);
|
|
|
|
|
auto next_iter = end;
|
|
|
|
|
ignore_whitespace(next_iter, katoms);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Argtype Argtype_set::get(const std::string& name, const Locator& loc) const
|
|
|
|
|
{
|
|
|
|
|
if (is_not_in(name, m_names)) {
|
|
|
|
|
std::stringstream msg {};
|
|
|
|
|
msg << "Type '" << name << "' is not an argument type";
|
|
|
|
|
throw Argument_error(msg.str(), loc);
|
|
|
|
|
}
|
|
|
|
|
return m_types.at(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::string Argtype_set::eval(
|
|
|
|
|
const std::string& value, const std::string& type_name, const Locator& loc)
|
|
|
|
|
{
|
|
|
|
|
std::regex re = m_types[type_name].m_regex;
|
|
|
|
|
std::smatch match {};
|
|
|
|
|
if (std::regex_match(value, match, re)) {
|
|
|
|
|
return value;
|
|
|
|
|
} else {
|
|
|
|
|
//return "NO MATCH";
|
|
|
|
|
std::stringstream ss {};
|
|
|
|
|
ss << "Argument \"" << value << "\" does not match the pattern for \""
|
|
|
|
|
<< type_name << "\"\n";
|
|
|
|
|
throw Definition_error(ss.str(), loc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-28 22:24:32 +02:00
|
|
|
// The values a type supplies when an argument does not give one: the
|
|
|
|
|
// default (the option was not written at all) and the alone value (the
|
|
|
|
|
// option name was written without a value). Shown only when declared.
|
|
|
|
|
static std::string values_note(const Argtype& type)
|
|
|
|
|
{
|
|
|
|
|
std::stringstream note {};
|
|
|
|
|
if (!type.m_default.empty()) {
|
|
|
|
|
note << " [default: " << type.m_default << "]";
|
|
|
|
|
}
|
|
|
|
|
if (!type.m_alone.empty()) {
|
|
|
|
|
note << " [alone: " << type.m_alone << "]";
|
|
|
|
|
}
|
|
|
|
|
return note.str();
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-18 18:48:23 +02:00
|
|
|
std::string Argtype_set::describe(bool long_form, int indent_width) const
|
|
|
|
|
{
|
|
|
|
|
std::string indent(' ', indent_width);
|
|
|
|
|
std::size_t name_width = std::accumulate(
|
|
|
|
|
m_names.begin(), m_names.end(), 0,
|
|
|
|
|
[&] (size_t w, const std::string& name) { return std::max(w, name.size()); });
|
|
|
|
|
std::stringstream result {};
|
|
|
|
|
for (const auto& name : m_names) {
|
|
|
|
|
std::string label { "Regex:" };
|
|
|
|
|
int pat_width = name_width + 2 + indent_width + label.size();
|
|
|
|
|
result << indent << std::setw(name_width) << name << sp_arrow;
|
|
|
|
|
if (long_form) {
|
|
|
|
|
result << m_types.at(name).m_desc << "\n";
|
|
|
|
|
result << std::setw(pat_width) << "regex: " << m_types.at(name).m_symbolic_pattern;
|
|
|
|
|
if (m_types.at(name).m_symbolic_pattern != m_types.at(name).m_pattern)
|
|
|
|
|
result << sp_arrow << m_types.at(name).m_pattern;
|
|
|
|
|
result << "\n";
|
|
|
|
|
} else {
|
2026-07-28 22:24:32 +02:00
|
|
|
// result << abbrev(m_types.at(name).m_desc) << "\n";
|
|
|
|
|
result << regex_split(m_types.at(name).m_desc, std::regex("\\n"), true)[0]
|
|
|
|
|
<< values_note(m_types.at(name)) << "\n";
|
2026-07-18 18:48:23 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (long_form) {
|
|
|
|
|
result << "\nA previously defined type can be included in the definition of a new type\n"
|
|
|
|
|
<< "by surrounding the name of the existing type in single quotation marks.\n";
|
|
|
|
|
}
|
|
|
|
|
return result.str();
|
|
|
|
|
}
|