Files
klammertext/mac/katom.cpp

398 lines
12 KiB
C++
Raw Normal View History

#include <iostream>
#include <fstream>
#include <ranges>
#include <algorithm>
#include "katom.h"
#include "ktype.h"
#include "error.h"
#include "log.h"
#include "show.h"
#include "util.h"
#include "file.h"
bool dbg = false;
size_t Katom::index = 0;
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)
{
if (m_type == katom_t::special && m_text[0] == '^') {
m_text.erase(0, 1);
}
}
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;
}
std::string expand_compound_katom(const std::string& s, std::regex rgx, const std::string& expanded)
{
if (s.find('-') != std::string::npos) { // Hyphen shortcut for arguments that allow it
const std::regex shortcut_rgx(R"((@\w+)(-\w+)+)");
std::smatch match {};
if (std::regex_match(s, match, shortcut_rgx)) {
std::string modified = string_replace(s, "-", " | ") + " @";
return std::regex_replace(modified, std::regex(R"((@\w+) \|)"), "$1");
}
}
return std::regex_replace(s, rgx, expanded);
}
katom_list make_katoms_from_word(std::string s, const std::string& source_desc, int line, int chr)
{
if (dbg) msg() << " make word: " << broken_bar << s << broken_bar << " [" << chr << "]\n";
auto ktyp = std::find_if(katom_types.begin(), katom_types.end(), [&](const auto& ktype) { return ktype.match(s); });
if (ktyp != katom_types.end()) {
return { Katom(s, ktyp->m_type, Locator(source_desc, line, chr)) };
} else {
if (dbg) {
std::cout << "\nBREAK: |" << s << "|\n";
}
for (const auto& [desc, rgx, expanded] : katom_rewrite_rules) {
std::string modified = expand_compound_katom(s, rgx.m_regex, expanded);
if (dbg) {
msg() << "Rewrite: " << desc << " " << rgx.m_pattern << " " << expanded << "\n";
}
if (modified != s) {
auto parts = word_split(modified);
if (dbg) std::cout << " Parts: " << parts << "\n";
if (show_rewrite_rules) {
Locator loc(source_desc, line, chr);
std::cout << loc << " Rewrite (" << desc << "): " << rgx.m_pattern
<< " " << right_arrow << " " << expanded << "\n";
}
katom_list klist {};
for (const std::string& p : parts) {
if (!p.empty()) {
auto ks = make_katoms_from_word(p, source_desc, line, chr);
std::copy(ks.begin(), ks.end(), std::back_inserter(klist));
}
}
return klist;
}
}
if (verbose_level > 0) {
std::cerr << command_name
<< " [warning]: Word not parsed in "
<< source_desc << ", line " << line+1 << ":\n"
<< " " << s << "\n"
<< "To include a special character (@, |, #, and ^), put \"^\" before it.\n";
//return std::vector{ std::make_shared<Katom>(s, Locator(), katom_t::word) };
//return std::vector{ std::make_shared<Katom>(s, katom_t::word, Locator(source_desc, line, chr)) };
}
return std::vector{ Katom(s, katom_t::word, Locator(source_desc, line, chr)) };
}
}
katom_list split_into_katoms(std::string s, const std::string& source, int source_line)
{
if (dbg) {
msg() << "Make katoms: " << s << "<\n";
}
// const std::string middle_dot { "\u00B7" };
s = string_replace(s, "\r", "");
s = string_replace(s, "\t", " ");
//std::regex words_regex("^\||[ ]|[\\n]|[^\\s]+|.+");
//std::regex words_regex(R"((?:[^][|])|[ ]|[\n]|[^\s]+|.+)");
std::regex words_regex(R"([ ]|[\n]|[^\s]+|.+)");
auto words_begin = std::sregex_iterator(s.begin(), s.end(), words_regex);
auto words_end = std::sregex_iterator();
if (dbg) {
std::cout << "Found " << std::distance(words_begin, words_end) << " words:\n";
}
strings_t atoms {};
for (std::sregex_iterator iter = words_begin; iter != words_end; ++iter) {
if (dbg) {
std::cout << middle_dot << iter->str();
}
atoms.push_back(iter->str());
}
if (dbg) std::cout << middle_dot << "\n";
//std::cout << kall << ktype;
katom_list result {};
int cpos = 0;
for (const auto& a : atoms) {
auto k = make_katoms_from_word(a, source, source_line, cpos);
for (auto& kk : k) {
Locator loc(source, source_line, cpos);
//kk->m_loc = loc;
kk.m_loc = loc;
//m_katoms.push_back(kk);
result.push_back(kk);
if (dbg) {
//std::cout << "LOOP: " << kk.m_text << " - " << cpos << "\n";
}
cpos += kk.m_src.size();
}
}
return result;
}
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);
}
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);
}
strings_t line_split(std::string s)
{
std::istringstream is(s);
strings_t result {};
std::string line;
while (std::getline(is, line)) {
result.push_back(line);
}
result.push_back("\n");
return result;
}
std::pair<std::string, strings_t> line_split(fs::path pathname)
{
std::string source {};
strings_t lines {};
std::ifstream infile(pathname);
std::string line;
while (std::getline(infile, line)) {
source += line + "\n";
lines.push_back(line);
}
if (!source.empty()) {
source.pop_back();
}
return {source, lines};
}
// I'm, like, this is
// some weird shit;
// what the fuck?
katom_list katomize(const strings_t& lines, const std::string& source_desc)
{
(void)K::log(3);
katom_list katoms {};
int i = 0;
for (std::string line : lines) {
(void)K::log(4, line);
katom_list ks = split_into_katoms(line + "\n", source_desc, ++i);
katoms.insert(katoms.end(), ks.begin(), ks.end());
}
katoms.pop_back();
return katoms;
}
// 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});
}