2026-07-18 18:48:23 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <limits>
|
|
|
|
|
#include <memory>
|
|
|
|
|
|
|
|
|
|
#include "ktype.h"
|
|
|
|
|
#include "locator.h"
|
|
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
|
|
inline bool show_rewrite_rules = false;
|
|
|
|
|
|
|
|
|
|
class Katom
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
static size_t index;
|
|
|
|
|
Katom(const std::string& src, katom_t type, Locator loc);
|
|
|
|
|
|
|
|
|
|
// Copy constructor
|
2026-07-26 23:22:59 +02:00
|
|
|
Katom(const Katom& other)
|
2026-07-18 18:48:23 +02:00
|
|
|
: m_index(other.m_index)
|
|
|
|
|
, m_text(other.m_text)
|
|
|
|
|
, m_src(other.m_src)
|
|
|
|
|
, m_loc(other.m_loc)
|
|
|
|
|
, m_type(other.m_type)
|
|
|
|
|
, m_initial_type(other.m_initial_type)
|
|
|
|
|
, m_display(other.m_display)
|
2026-07-26 23:22:59 +02:00
|
|
|
, m_unparsed(other.m_unparsed)
|
2026-07-18 18:48:23 +02:00
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
// Copy assignment operator
|
|
|
|
|
Katom& operator=(const Katom& other) {
|
|
|
|
|
if (this != &other) {
|
|
|
|
|
m_index = other.m_index;
|
|
|
|
|
m_text = other.m_text;
|
|
|
|
|
m_src = other.m_src;
|
|
|
|
|
m_loc = other.m_loc;
|
|
|
|
|
m_type = other.m_type;
|
|
|
|
|
m_initial_type = other.m_initial_type;
|
|
|
|
|
m_display = other.m_display;
|
2026-07-26 23:22:59 +02:00
|
|
|
m_unparsed = other.m_unparsed;
|
2026-07-18 18:48:23 +02:00
|
|
|
}
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline bool show_index;
|
|
|
|
|
static inline bool show_type;
|
|
|
|
|
static inline bool show_id;
|
|
|
|
|
static inline bool show_whitespace;
|
|
|
|
|
static inline bool show_all;
|
|
|
|
|
static inline bool show_replaced;
|
|
|
|
|
static inline bool show_ignored;
|
|
|
|
|
|
|
|
|
|
bool is_whitespace() const {
|
|
|
|
|
return m_initial_type == katom_t::space
|
|
|
|
|
|| m_initial_type == katom_t::newline
|
|
|
|
|
|| m_type == katom_t::ws_added; }
|
|
|
|
|
bool is_word() const { return m_initial_type == katom_t::word; }
|
|
|
|
|
bool is_text() const { return m_initial_type == katom_t::text; }
|
|
|
|
|
//bool is_text() { return m_initial_type == katom_t::text; }
|
|
|
|
|
bool is_literal() const { return m_type == katom_t::literal; }
|
|
|
|
|
bool is_active() const {
|
|
|
|
|
return m_type != katom_t::ignored
|
|
|
|
|
&& m_type != katom_t::replaced; };
|
|
|
|
|
bool is_nonascii() const {
|
|
|
|
|
return m_type == katom_t::nonascii; };
|
|
|
|
|
size_t m_index;
|
|
|
|
|
std::string m_text{};
|
|
|
|
|
std::string m_src{};
|
|
|
|
|
Locator m_loc;
|
|
|
|
|
katom_t m_type;
|
|
|
|
|
katom_t m_initial_type;
|
|
|
|
|
std::string m_display {};
|
2026-07-26 23:22:59 +02:00
|
|
|
// Set when the word matched no katom type and fell back to katom_t::word.
|
|
|
|
|
// The warning is deferred to warn_unparsed_katoms(), after removal and
|
|
|
|
|
// literal marking, so removed text (comments, #[...]# blocks) never warns.
|
|
|
|
|
bool m_unparsed {};
|
2026-07-18 18:48:23 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool active(const std::vector<Katom>& katoms);
|
|
|
|
|
int active_count(const std::vector<Katom>& katoms);
|
|
|
|
|
std::vector<Katom> split_into_katoms(std::string s, const std::string& source, int source_line);
|
|
|
|
|
void restore_initial_type(std::vector<Katom>::iterator begin, std::vector<Katom>::iterator end);
|
|
|
|
|
void modify_type(katom_t new_type, std::vector<Katom>::iterator begin, std::vector<Katom>::iterator end);
|
|
|
|
|
void modify_type(katom_t old_type, katom_t new_type,
|
|
|
|
|
std::vector<Katom>::iterator begin, std::vector<Katom>::iterator end);
|
|
|
|
|
void ignore_whitespace(std::vector<Katom>::iterator& begin, std::vector<Katom>& katoms);
|
|
|
|
|
std::vector<Katom>::iterator after_whitespace(std::vector<Katom>::iterator begin);
|
|
|
|
|
std::vector<Katom> text_katoms(
|
|
|
|
|
std::vector<Katom>::iterator& begin, std::vector<Katom>::iterator& end);
|
|
|
|
|
|
|
|
|
|
std::string as_string(std::vector<Katom>::const_iterator begin, std::vector<Katom>::const_iterator end, bool strip_whitespace);
|
|
|
|
|
|
|
|
|
|
std::string as_string(const std::vector<Katom>& katoms, bool strip_whitespace);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<Katom> trim(std::vector<Katom>& katoms, std::set<katom_t> trim_types = {katom_t::space, katom_t::newline});
|
|
|
|
|
std::vector<Katom> trim(const std::vector<Katom>& katoms, bool trim_inactive = false);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::vector<Katom>> bar_split(std::vector<Katom>::iterator kbegin, std::vector<Katom>::iterator kend);
|
|
|
|
|
|
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
|
|
|
std::vector<std::string> line_split(const std::string& s);
|
|
|
|
|
std::pair<std::string, std::vector<std::string>> line_split(const fs::path& pathname);
|
2026-07-18 18:48:23 +02:00
|
|
|
std::vector<Katom> katomize(const std::vector<std::string>& lines, const std::string& source_desc);
|
|
|
|
|
|
2026-07-26 23:22:59 +02:00
|
|
|
void warn_unparsed_katoms(std::vector<Katom>& katoms, bool warn = true);
|
2026-07-18 18:48:23 +02:00
|
|
|
void process_whitespace_modifiers(std::vector<Katom>& katoms);
|
|
|
|
|
std::vector<Katom> trim_whitespace(std::vector<Katom> katoms);
|
|
|
|
|
|
|
|
|
|
// escape_backslash() and unescape_backslash() (the ___BS___ hack) were
|
|
|
|
|
// removed. Backslash is now handled by the general target escape mechanism
|
|
|
|
|
// via the :escape parameter on @@@target.
|
|
|
|
|
|
|
|
|
|
inline bool is_bar(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::bar;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool is_nonascii(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::nonascii;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool is_newline(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::newline;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool is_ignore_rest(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::ignore_rest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool is_ignore_line(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::ignore_line;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void mark_as_replaced(Katom& k) {
|
|
|
|
|
k.m_type = katom_t::replaced;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void mark_as_literal(Katom& k) {
|
|
|
|
|
k.m_type = katom_t::literal;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void mark_as_ignored(Katom& k) {
|
|
|
|
|
k.m_type = katom_t::ignored;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool begin_read(Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::read_begin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool begin_ignore(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::ignore_begin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool end_ignore(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::ignore_end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool begin_literal(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::literal_begin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool end_literal(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::literal_end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool begin_eval(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::eval_begin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool begin_cond(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::cond_begin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool begin_klammer_def(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::define_begin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool end_klammer_def(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::define_end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool begin_klammer_apply(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::apply_begin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool end_klammer_apply(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::apply_end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool begin_machine_def(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::machine_begin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool end_machine_def(const Katom& k) {
|
|
|
|
|
return k.m_type == katom_t::machine_end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inline bool begin_apply(const Katom& k)
|
|
|
|
|
{
|
|
|
|
|
const std::set<katom_t> opens {
|
|
|
|
|
katom_t::read_begin,
|
|
|
|
|
katom_t::eval_begin,
|
|
|
|
|
katom_t::cond_begin,
|
|
|
|
|
katom_t::apply_begin};
|
|
|
|
|
return opens.contains(k.m_type);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline bool end_apply(const Katom& k)
|
|
|
|
|
{
|
|
|
|
|
return k.m_type == katom_t::apply_end;
|
|
|
|
|
}
|