Also: the klammertext argtype (descriptions kept as source), txt table wrapping and :hpos/:offset, @c between ‹ ›, txt section headings, the ktext newline-only trim, capitalize(), and the argtype test suite. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
278 lines
7.8 KiB
C++
278 lines
7.8 KiB
C++
#include <iostream>
|
|
#include <fstream>
|
|
#include <ranges>
|
|
#include <algorithm>
|
|
|
|
#include "katom.h"
|
|
#include "ktype.h"
|
|
#include "katomize.h"
|
|
#include "error.h"
|
|
#include "log.h"
|
|
#include "show.h"
|
|
#include "util.h"
|
|
#include "file.h"
|
|
|
|
bool dbg = false;
|
|
|
|
// KATOMIZATION IS NOT HERE. Turning text into katoms moved to
|
|
// katomize.{h,cpp} (2026-09-02), leaving this file the KATOM: what it is,
|
|
// what its type means, and the operations on a list of them. The test that
|
|
// decided the split is in katomize.h -- does a character stream enter?
|
|
// Everything below answers no.
|
|
|
|
size_t Katom::index = 0;
|
|
|
|
// A katom holds its source text and its text, and decides nothing about
|
|
// either. It used to strip the "^" from a quoted special here -- knowledge
|
|
// of what a construct looks like IN SOURCE, inside the datum, which is the
|
|
// one thing the katom/katomization split says does not belong here. That
|
|
// moved to source_katom() in katomize.{h,cpp} on 2026-09-02, the one place
|
|
// a katom is made from matched source text.
|
|
Katom::Katom(const std::string& src, katom_t type, Locator loc)
|
|
: m_index(Katom::index++)
|
|
, m_text(src)
|
|
, m_src(src)
|
|
, m_loc(loc)
|
|
, m_type(type)
|
|
, m_initial_type(type)
|
|
{
|
|
}
|
|
|
|
int active_count(const katom_list& katoms)
|
|
{
|
|
return std::ranges::count_if(
|
|
katoms,
|
|
[] (const Katom& k) {
|
|
return k.m_type != katom_t::replaced
|
|
&& k.m_type != katom_t::ignored
|
|
&& k.m_type != katom_t::space
|
|
&& k.m_type != katom_t::newline;
|
|
});
|
|
}
|
|
|
|
bool active(const katom_list& katoms)
|
|
{
|
|
return active_count(katoms) > 0;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void restore_initial_type(katom_iter begin, katom_iter end)
|
|
{
|
|
std::for_each(
|
|
begin, end, [](Katom& k) { k.m_type = k.m_initial_type; });
|
|
}
|
|
|
|
void modify_type(katom_t new_type, katom_iter begin, katom_iter end)
|
|
{
|
|
std::for_each(
|
|
begin, end, [&new_type](Katom& k) { k.m_type = new_type; });
|
|
}
|
|
|
|
void modify_type(katom_t old_type, katom_t new_type, katom_iter begin, katom_iter end)
|
|
{
|
|
std::for_each(
|
|
begin, end, [&](Katom& k) { if (k.m_type == old_type) k.m_type = new_type; });
|
|
}
|
|
|
|
void ignore_whitespace(katom_iter& begin, katom_list& katoms)
|
|
{
|
|
constexpr bool _dbg = false;
|
|
if (begin < katoms.end()) {
|
|
katom_iter ki = begin;
|
|
if (_dbg) std::cout << "IGNORE_WHITESPACE: ";
|
|
auto end = katoms.end();
|
|
while (ki < end && ki->is_whitespace()) {
|
|
if (_dbg) std::cout << kall << ktype << *ki << sp_arrow;
|
|
ki->m_type = katom_t::ignored;
|
|
if (_dbg) std::cout << kignored << kall << ktype << *ki << " " << "\n";
|
|
++ki;
|
|
}
|
|
if (_dbg) std::cout << black << kreset;
|
|
}
|
|
}
|
|
|
|
katom_iter after_whitespace(katom_iter begin)
|
|
{
|
|
katom_iter result = begin;
|
|
while (result->is_whitespace()) {
|
|
result++;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::vector<Katom> text_katoms(katom_iter& begin, katom_iter& end)
|
|
{
|
|
katom_list result {};
|
|
for (auto ki = begin; ki < end; ki++) {
|
|
if (!ki->is_whitespace()) {
|
|
auto k = *ki;
|
|
//msg() << " push: " << kindex << ktype << kall << kws << k << "\n";
|
|
result.push_back(k);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
std::string as_string(std::vector<Katom>::const_iterator begin, std::vector<Katom>::const_iterator end, bool strip_whitespace)
|
|
{
|
|
auto include =
|
|
[&](katom_t t)
|
|
{ return t != katom_t::replaced and t != katom_t::ignored; };
|
|
std::string result {};
|
|
for (auto ki = begin; ki < end; ki++) {
|
|
katom_t t = ki->m_type;
|
|
if (include(t)) {
|
|
std::string text = !ki->m_display.empty() ? ki->m_display : ki->m_text;
|
|
result += text;
|
|
}
|
|
}
|
|
if (strip_whitespace)
|
|
result = trim(result);
|
|
return result;
|
|
}
|
|
|
|
std::string as_string(const katom_list& ks, bool strip_whitespace)
|
|
{
|
|
return as_string(ks.begin(), ks.end(), strip_whitespace);
|
|
}
|
|
|
|
std::string as_source(std::vector<Katom>::const_iterator begin, std::vector<Katom>::const_iterator end, bool strip_whitespace)
|
|
{
|
|
std::string result {};
|
|
for (auto ki = begin; ki < end; ki++) {
|
|
if (ki->m_type != katom_t::replaced && ki->m_type != katom_t::ignored)
|
|
result += ki->m_src;
|
|
}
|
|
if (strip_whitespace)
|
|
result = trim(result);
|
|
return result;
|
|
}
|
|
|
|
katom_list trim(katom_list& katoms, std::set<katom_t> trim_types)
|
|
{
|
|
katom_iter begin =
|
|
std::find_if(katoms.begin(), katoms.end(),
|
|
[&trim_types](const Katom& k) { return !trim_types.contains(k.m_type); });
|
|
if (begin == katoms.end()) {
|
|
return katom_list{};
|
|
}
|
|
katom_iter end = katoms.end() - 1;
|
|
while (trim_types.contains(end->m_type)) {
|
|
--end;
|
|
}
|
|
return katom_list(begin, end+1);
|
|
}
|
|
|
|
katom_list trim(const katom_list& katoms, bool trim_inactive)
|
|
{
|
|
katom_list result = katoms;
|
|
std::set<katom_t> trim_types {katom_t::space, katom_t::newline};
|
|
if (trim_inactive) {
|
|
trim_types.insert(katom_t::replaced);
|
|
trim_types.insert(katom_t::ignored);
|
|
}
|
|
return trim(result, trim_types);
|
|
}
|
|
|
|
|
|
// I'm, like, this is
|
|
// some weird shit;
|
|
// what the fuck?
|
|
|
|
|
|
// Whitespace
|
|
|
|
std::pair<katom_iter,katom_iter> whitespace_span(const katom_list& katoms, const katom_iter& start, katom_t start_type)
|
|
{
|
|
katom_iter ki = start;
|
|
if (ki != katoms.begin()) {
|
|
--ki;
|
|
while (ki != katoms.begin() && ki->is_whitespace()) {
|
|
--ki;
|
|
}
|
|
if (!ki->is_whitespace()) {
|
|
++ki;
|
|
}
|
|
}
|
|
katom_iter begin = ki;
|
|
while (ki != katoms.end() && (ki->is_whitespace() || ki->m_type == start_type
|
|
|| ki->m_type == katom_t::ignored || ki->m_type == katom_t::replaced)) {
|
|
++ki;
|
|
}
|
|
//katom_iter end = ki;
|
|
return {begin, ki}; //end};
|
|
}
|
|
|
|
std::vector<Katom> find_katoms_of_type(const katom_list& katoms, katom_t type)
|
|
{
|
|
auto result = katoms | std::views::filter([type](const Katom& k) { return k.m_type == type; });
|
|
return std::vector(result.begin(), result.end());
|
|
}
|
|
|
|
katom_iter find_katom_of_type(katom_iter begin, katom_iter end, katom_t type)
|
|
{
|
|
return std::find_if(begin, end, [&](const Katom& k) { return k.m_type == type; });
|
|
}
|
|
|
|
// #-
|
|
|
|
void remove_whitespace(katom_list& katoms) // Lint error
|
|
{
|
|
(void)K::log(3);
|
|
auto begin = katoms.begin();
|
|
while (begin < katoms.end()) {
|
|
auto ki = find_katom_of_type(begin, katoms.end(), katom_t::ws_remove);
|
|
if (ki == katoms.end()) break;
|
|
auto [b, e] = whitespace_span(katoms, ki, katom_t::ws_remove);
|
|
std::for_each(b, e, [](Katom& k) { k.m_type = katom_t::ignored; });
|
|
begin = e;
|
|
}
|
|
}
|
|
|
|
// #+n and #/n
|
|
|
|
int whitespace_arg(Katom& k)
|
|
{
|
|
int result = 1;
|
|
std::smatch match{};
|
|
if (std::regex_match(k.m_text, match, std::regex(R"(#[+/](\d*))"))) {
|
|
if (!match[1].str().empty()) {
|
|
result = stoi(match[1]);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void insert_whitespace(katom_list& katoms, katom_t type, const std::string& c)
|
|
{
|
|
(void)K::log(3);
|
|
for (Katom k : find_katoms_of_type(katoms, type)) {
|
|
katom_iter ki = find_katom(katoms.begin(), katoms.end(), k.m_index);
|
|
auto count = whitespace_arg(k);
|
|
auto [b, e] = whitespace_span(katoms, ki, type);
|
|
std::for_each(b, e, [](Katom& ka) { ka.m_type = katom_t::ignored; });
|
|
katom_list inserted = std::vector<Katom>{};
|
|
for (int i = 0; i < count; ++i) {
|
|
inserted.push_back(Katom(c, katom_t::ws_added, k.m_loc));
|
|
}
|
|
katoms.insert(e, inserted.begin(), inserted.end());
|
|
}
|
|
}
|
|
|
|
void process_whitespace_modifiers(katom_list& katoms)
|
|
{
|
|
(void)K::log(4);
|
|
remove_whitespace(katoms);
|
|
insert_whitespace(katoms, katom_t::ws_space, " ");
|
|
insert_whitespace(katoms, katom_t::ws_newline, "\n");
|
|
}
|
|
|
|
katom_list trim_whitespace(katom_list katoms)
|
|
{
|
|
return trim(katoms, {katom_t::space, katom_t::newline});
|
|
}
|