Initial commit: Klammertext source distribution
Curated source subset assembled by klammertext-dev's doc/make_dist.sh: the Klammermachine (mac), the Standard Klammer Set (sks), the commands (com), editor plugins and install guides (doc), a test subset (tst), and lib/bin placeholders. Builds with 'make -C com'. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
155
mac/argtype_set.cpp
Normal file
155
mac/argtype_set.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
#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()
|
||||
{
|
||||
static Parameter_set instance("name | desc :pattern .* :python_cast str");
|
||||
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) {
|
||||
add(name, desc, pattern, python_cast, python_format, loc);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void Argtype_set::add(const std::string& name, const std::string& desc,
|
||||
const std::string& pattern,
|
||||
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());
|
||||
m_types[name] = Argtype(name, desc, pattern, expanded_pattern, python_cast, python_format, loc);
|
||||
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);
|
||||
//Argument_set parameters("name | desc :pattern .* :python_cast str");
|
||||
|
||||
auto [positional, optional, rest] =
|
||||
argument_split(begin + 1, end); //, Argtype_set::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);
|
||||
|
||||
// std::for_each(begin, end+1, [](Katom& k) { k.m_type = katom_t::replaced; });
|
||||
|
||||
modify_string_f pyformat {};
|
||||
std::string pycast {};
|
||||
|
||||
add(values["name"], values["desc"], values["pattern"],
|
||||
pycast, pyformat,
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
// result << abbrev(m_types.at(name).m_desc) << "\n";
|
||||
result << regex_split(m_types.at(name).m_desc, std::regex("\\n"), true)[0] << "\n";
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
Reference in New Issue
Block a user