2026-07-18 18:48:23 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
|
|
#include "locator.h"
|
|
|
|
|
#include "katom.h"
|
|
|
|
|
#include "argtype.h"
|
|
|
|
|
#include "argument.h"
|
|
|
|
|
#include "klammer.h"
|
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
|
|
|
#include "klammer_registry.h"
|
|
|
|
|
#include "klammerset_registry.h"
|
2026-07-18 18:48:23 +02:00
|
|
|
#include "state.h"
|
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
|
|
|
#include "target_registry.h"
|
2026-07-18 18:48:23 +02:00
|
|
|
#include "machine.h"
|
|
|
|
|
#include "file.h"
|
|
|
|
|
|
|
|
|
|
using namespace std::string_literals;
|
|
|
|
|
|
|
|
|
|
const std::string middle_dot { "\uFF65" };
|
|
|
|
|
const std::string broken_bar { "\u00A6" };
|
|
|
|
|
const std::string right_arrow { "\uFFEB" };
|
|
|
|
|
const std::string sp_arrow { " \u2192 " };
|
|
|
|
|
const std::string right_bracket { "\u27E9" };
|
|
|
|
|
const std::string left_bracket { "\u27E8" };
|
|
|
|
|
const std::string bbar { "¦" };
|
|
|
|
|
const std::string left_double_bracket { "\u27E6" };
|
|
|
|
|
const std::string right_double_bracket { "\u27E7" };
|
|
|
|
|
const std::string left_square_bracket { "\u2045" };
|
|
|
|
|
const std::string right_square_bracket { "\u2046" };
|
|
|
|
|
const std::string check { "\u2713" };
|
|
|
|
|
|
An output policy for the three commands, and @cond as a true special form
A snapshot of the development tree. The substantial changes since the last one:
COMMAND OUTPUT POLICY. The three commands display text in exactly three cases,
and each owns a stream: LOGGING under "-v" greater than 0 and an ERROR before
termination go to STDERR; OUTPUT THE USER ASKED FOR goes to STDOUT. For ktext
that output is a document, so "ktext doc.kt -d | ..." is now safe -- logging
used to share the stream and land inside the document. A bare command prints
its usage and succeeds rather than failing. Colour is emitted only to a
terminal, per stream, and NO_COLOR is honoured.
"-v 1" reports every decision whose outcome you could not have read off your own
input: the klammerset that was loaded and from which file, a font's directory, a
":files" name's file, how "-o" was expanded. Higher levels are the trace.
The commands no longer warn and continue: an anomaly is an error, described with
its location. Two exceptions remain, each for a stated reason -- a condition
that is expected and temporary by design, and a judgment that is a heuristic
rather than exact.
@cond IS NOW A TRUE SPECIAL FORM, resolved at APPLICATION time rather than when
the file is read. Two consequences for a writer:
* a state variable reaches the predicate. "@@@state Flag :value true @@@
@cond *Flag* | T | F @" renders "T"; it used to see the literal "*Flag*" and
silently take the false branch. The document now behaves like a klammer
body, whose arguments are bound before its conditionals are decided.
* nothing in a discarded branch happens -- it is not read, not evaluated, not
expanded. An @eval in the branch not taken used to run anyway.
Its predicate relation is total and strict: true, True, 1; false, False, 0, and
empty; anything else is an error at the @cond rather than silently false.
@eval REACHING OUTSIDE. ":shell" and ":haskell" now keep the command's standard
error out of the document (it appears under "-v 1") and treat a nonzero exit as
an error naming what the command reported. A command that exits nonzero on
purpose -- "grep" finding no match -- says so with "|| true".
KLAMMER SETS. Several combine: "--klammersets a b c" loads all three in the
order given, sharing one namespace, with the definition modes deciding
collisions. "none" means none and may not be combined with other symbols. A
klammerset with symbol X is declared in a file X/X.k, which is what lets two
sets require the same third set without loading it twice.
TESTS. Four new suites: the kdiag command's interface, the @eval primitive's
contract with the outside world, and verbosity at both tiers. Three suites
that could not run on macOS at all now do.
Assembled from dev commit 6c8ee6c22fca.
2026-08-16 01:37:59 +02:00
|
|
|
// A colour is a STREAM-AWARE object, not a string, because the same name is
|
|
|
|
|
// written to two streams whose destinations differ: "ktext -d > doc.txt" has a
|
|
|
|
|
// file on stdout and a terminal on stderr at the same time, so one global
|
|
|
|
|
// on/off cannot be right for both. Inserting a Color emits its escape
|
|
|
|
|
// sequence only when THAT stream is a terminal, so escape codes can never
|
|
|
|
|
// reach a redirected document, a pipe, or a captured log.
|
|
|
|
|
//
|
|
|
|
|
// Streams other than std::cout/std::cerr -- a stringstream building an error
|
|
|
|
|
// message, a file -- are never coloured. That is the conservative reading and
|
|
|
|
|
// it also stops escapes from being baked into strings whose length is then
|
|
|
|
|
// measured (abbreviate() in util.cpp counted them).
|
|
|
|
|
class Color {
|
|
|
|
|
public:
|
|
|
|
|
explicit Color(const std::string& code) : m_code(code) {}
|
|
|
|
|
// The raw sequence, for the rare place that needs a string rather than an
|
|
|
|
|
// insertion. Prefer inserting the Color: this form cannot be suppressed.
|
|
|
|
|
const std::string& code() const { return m_code; }
|
|
|
|
|
private:
|
|
|
|
|
std::string m_code {};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// True when colour should be emitted on this stream: it is a terminal and the
|
|
|
|
|
// NO_COLOR environment variable is unset. NO_COLOR (https://no-color.org) is
|
|
|
|
|
// honoured for ANY non-empty value, which is what the convention specifies; it
|
|
|
|
|
// is the escape hatch for the case isatty cannot see, such as a pager or a CI
|
|
|
|
|
// capture that does want, or does not want, colour.
|
|
|
|
|
bool color_enabled(const std::ostream& os);
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Color& color);
|
|
|
|
|
|
|
|
|
|
const Color black("\033[0;30m");
|
|
|
|
|
const Color boldblack("\033[1;30m");
|
|
|
|
|
const Color green("\033[0;32m");
|
|
|
|
|
const Color boldgreen("\033[1;32m");
|
|
|
|
|
const Color cyan("\033[0;36m");
|
|
|
|
|
const Color blue("\033[0;34m");
|
|
|
|
|
const Color boldblue("\033[1;34m");
|
|
|
|
|
const Color magenta("\033[0;35m");
|
|
|
|
|
const Color red("\033[31m");
|
|
|
|
|
const Color yellow("\033[0;33m");
|
|
|
|
|
const Color reset("\033[0m");
|
2026-07-18 18:48:23 +02:00
|
|
|
|
|
|
|
|
const auto seqout = [](auto x) { std::cout << "seq: " << x << "\n"; };
|
|
|
|
|
//const auto mapout = [](auto m) { auto const& key std::cout << m.first << sp_arrow << m.second << "\n"; };
|
|
|
|
|
|
|
|
|
|
const auto mapout = [](auto const& kv){
|
|
|
|
|
auto const& [k, v] = kv;
|
|
|
|
|
std::cout << k << sp_arrow << v << "\n";
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
inline const
|
|
|
|
|
std::set sks_commands = {
|
|
|
|
|
"ktext"s,
|
|
|
|
|
"kdesc"s,
|
|
|
|
|
"kdiag"s,
|
|
|
|
|
"argument_test"s,
|
|
|
|
|
"argtype_test"s
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
std::ostream& msg(Locator loc=Locator());
|
|
|
|
|
std::ostream& fmsg(Locator loc=Locator());
|
|
|
|
|
|
|
|
|
|
std::vector<Katom> abbrev(const std::vector<Katom>& ks, unsigned int max_length=16);
|
|
|
|
|
|
|
|
|
|
// std::vector<int>
|
|
|
|
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const std::vector<int>& ns);
|
|
|
|
|
|
|
|
|
|
// std::vector<std::string>
|
|
|
|
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const std::vector<std::string>& ss);
|
|
|
|
|
|
|
|
|
|
// std::vector<fs::path>
|
|
|
|
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const std::vector<fs::path>& pp);
|
|
|
|
|
|
|
|
|
|
// std::map<std::string,std::string>
|
|
|
|
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const std::map<std::string,std::string>& sm);
|
|
|
|
|
|
|
|
|
|
// Katom iterator pair
|
|
|
|
|
|
|
|
|
|
std::ostream& operator<<(
|
|
|
|
|
std::ostream& os,
|
|
|
|
|
const std::pair<std::vector<Katom>::iterator, std::vector<Katom>::iterator>& iters);
|
|
|
|
|
|
|
|
|
|
// Locator
|
|
|
|
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Locator& loc);
|
|
|
|
|
|
|
|
|
|
// Katom
|
|
|
|
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Katom& k);
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const std::vector<std::vector<Katom>>& ks);
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const std::shared_ptr<Katom>& k);
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const std::vector<Katom>::iterator& k);
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const std::vector<Katom>& ks);
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const std::vector<std::vector<Katom>::iterator>& ks);
|
|
|
|
|
|
|
|
|
|
std::ostream& kindex(std::ostream& os);
|
|
|
|
|
std::ostream& ktype(std::ostream& os);
|
|
|
|
|
std::ostream& klevel(std::ostream& os);
|
|
|
|
|
// std::ostream& kspans(std::ostream& os);
|
|
|
|
|
std::ostream& kws(std::ostream& os);
|
|
|
|
|
std::ostream& kall(std::ostream& os);
|
|
|
|
|
std::ostream& kreplaced(std::ostream& os);
|
|
|
|
|
std::ostream& kignored(std::ostream& os);
|
|
|
|
|
std::ostream& kreset(std::ostream& os);
|
|
|
|
|
|
|
|
|
|
inline static std::string newline_symbol = "/";
|
|
|
|
|
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const std::vector<Katom>& ks);
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const std::vector<Katom>& ks);
|
|
|
|
|
|
|
|
|
|
// Argtype
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Argtype& a);
|
|
|
|
|
|
|
|
|
|
// Parameter (aliased as Argument at application sites)
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Parameter& p);
|
|
|
|
|
|
|
|
|
|
// Parameter_set (aliased as Argument_set at application sites)
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Parameter_set& as);
|
|
|
|
|
|
|
|
|
|
// std::vector<Parameter>
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const std::vector<Parameter>& as);
|
|
|
|
|
|
|
|
|
|
// Var
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Var& v);
|
|
|
|
|
|
|
|
|
|
// Frame
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Frame& f);
|
|
|
|
|
|
|
|
|
|
// State
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const State& s);
|
|
|
|
|
|
|
|
|
|
// Klammer
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Klammer& k);
|
|
|
|
|
|
|
|
|
|
// Klammer::variable_map_t
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Klammer::variable_map_t& vm);
|
|
|
|
|
|
|
|
|
|
// Klammer::components
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Klammer::components& kc);
|
|
|
|
|
|
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
|
|
|
// Klammer_registry
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Klammer_registry& ks);
|
2026-07-18 18:48:23 +02:00
|
|
|
|
|
|
|
|
// Target
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Target& t);
|
|
|
|
|
|
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
|
|
|
// Target_registry
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Target_registry& ts);
|
|
|
|
|
|
|
|
|
|
// Klammerset
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Klammerset& ks);
|
|
|
|
|
|
|
|
|
|
// Klammerset_registry
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Klammerset_registry& kr);
|
2026-07-18 18:48:23 +02:00
|
|
|
|
|
|
|
|
// Machine
|
|
|
|
|
std::ostream& operator<<(std::ostream& os, const Machine& m);
|
|
|
|
|
|
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
|
|
|
void modify_stream(const std::string& name);
|