Target coverage: a klammer states the targets it serves
kdesc gains --coverage, which reports for every klammer the set of targets it
can render to, and — the point of it — which klammers' coverage cannot be
derived and must therefore be declared. Three rules: coverage is DERIVED
where the definitions determine it (a general body of klammer calls covers
the intersection of what those klammers cover, by a greatest fixpoint after
loading), DECLARED where the engine cannot interpret what decides it (an
@eval body, whose targets are undecidable), and UNKNOWN where nothing is
written — which never means "deliberately unavailable".
Two new spellings in a definition's name. A comma-separated target list,
"@@table.html,tex :: ...", gives one body several targets; it is surface
syntax, expanded at registration, and each member goes through the
redefinition rules on its own. And "@@date.* :: ..." writes the general
target out, asserting that the klammer works for EVERY target including ones
not yet defined — a stronger claim than a list of the targets defined today,
and the one target declaration that could be mechanically falsified.
The Standard Klammer Set was swept accordingly: it now has no general
definitions at all, every klammer names the targets it serves, six use ".*",
and tex and pdf are at zero undecided.
kdesc's flags are reorganised on two rules: a flag reached for often gets a
single letter (-k klammers, -t targets, -c characters, -i input), a more
specialised topic a multi-letter name (--argtypes, --katoms, --rewrite,
--optionsets, --coverage, --klammerset, --font); and -v says how much to show
about PROCESSING, never what the RESULT contains — so the katom regex column
is "--katoms full" and the coverage detail "--coverage all". NOTE: "-k" now
lists klammers (optionally filtered by a name/description search); the katom
table moved to "--katoms".
Fixes carried along: an option written with no value crashed the command with
SIGSEGV instead of reporting the mistake; two required positional arguments
never parsed; kdesc and kdiag printed an error and exited 0; and definition
diagnostics counted registrations rather than what was written, so one line
could be reported as two definitions and then printed twice.
Four new test suites: target_list, coverage, command_option, kdesc.
(from dev 46f54080bd9a)
2026-08-12 17:20:23 +02:00
|
|
|
#!/bin/bash
|
|
|
|
|
#
|
|
|
|
|
# target_list_test.sh — A klammer definition may name several targets.
|
|
|
|
|
#
|
|
|
|
|
# @@table.html,tex :: <body> @@
|
|
|
|
|
#
|
|
|
|
|
# One body, several targets. The list is SURFACE SYNTAX: the registry makes
|
|
|
|
|
# one definition per target named, so nothing downstream of registration knows
|
|
|
|
|
# a list was written. That is what these tests pin down — in particular that
|
|
|
|
|
# each member goes through the redefinition transition table on its own, so a
|
|
|
|
|
# list overlapping an existing definition is decided per target rather than
|
|
|
|
|
# all-or-nothing.
|
|
|
|
|
#
|
|
|
|
|
# Why the feature exists: a klammer whose body is an `@eval` cannot have its
|
|
|
|
|
# coverage derived (deciding which targets a Python function answers for is
|
|
|
|
|
# undecidable), so its targets must be DECLARED. Writing one definition per
|
|
|
|
|
# target would then duplicate the body. See notes/target_coverage.md.
|
|
|
|
|
#
|
|
|
|
|
# Two patterns are involved and must not be confused (mac/ktype.h):
|
|
|
|
|
# definition_begin_name — runs through commas; used ONLY for "@@<name>"
|
|
|
|
|
# definition_name — no comma; klammer applications, option names,
|
|
|
|
|
# "*arg*" variables, and the closing delimiters
|
|
|
|
|
# Case 14 guards the second: a comma next to an application is writer text.
|
|
|
|
|
#
|
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
|
|
|
# These are engine tests, so they use --klammersets none and define their own targets
|
Target coverage: a klammer states the targets it serves
kdesc gains --coverage, which reports for every klammer the set of targets it
can render to, and — the point of it — which klammers' coverage cannot be
derived and must therefore be declared. Three rules: coverage is DERIVED
where the definitions determine it (a general body of klammer calls covers
the intersection of what those klammers cover, by a greatest fixpoint after
loading), DECLARED where the engine cannot interpret what decides it (an
@eval body, whose targets are undecidable), and UNKNOWN where nothing is
written — which never means "deliberately unavailable".
Two new spellings in a definition's name. A comma-separated target list,
"@@table.html,tex :: ...", gives one body several targets; it is surface
syntax, expanded at registration, and each member goes through the
redefinition rules on its own. And "@@date.* :: ..." writes the general
target out, asserting that the klammer works for EVERY target including ones
not yet defined — a stronger claim than a list of the targets defined today,
and the one target declaration that could be mechanically falsified.
The Standard Klammer Set was swept accordingly: it now has no general
definitions at all, every klammer names the targets it serves, six use ".*",
and tex and pdf are at zero undecided.
kdesc's flags are reorganised on two rules: a flag reached for often gets a
single letter (-k klammers, -t targets, -c characters, -i input), a more
specialised topic a multi-letter name (--argtypes, --katoms, --rewrite,
--optionsets, --coverage, --klammerset, --font); and -v says how much to show
about PROCESSING, never what the RESULT contains — so the katom regex column
is "--katoms full" and the coverage detail "--coverage all". NOTE: "-k" now
lists klammers (optionally filtered by a name/description search); the katom
table moved to "--katoms".
Fixes carried along: an option written with no value crashed the command with
SIGSEGV instead of reporting the mistake; two required positional arguments
never parsed; kdesc and kdiag printed an error and exited 0; and definition
diagnostics counted registrations rather than what was written, so one line
could be reported as two definitions and then printed twice.
Four new test suites: target_list, coverage, command_option, kdesc.
(from dev 46f54080bd9a)
2026-08-12 17:20:23 +02:00
|
|
|
# inline: a target is a Machine construct (@@@target), not owned by any
|
|
|
|
|
# klammer set.
|
|
|
|
|
#
|
|
|
|
|
# Usage: ./target_list_test.sh (needs KLAMMERTEXT_HOME set; ktext on PATH)
|
|
|
|
|
# Exit code: 0 if all tests pass, 1 otherwise.
|
|
|
|
|
|
|
|
|
|
PASS=0
|
|
|
|
|
FAIL=0
|
|
|
|
|
KTEXT=ktext
|
|
|
|
|
K=${KLAMMERTEXT_HOME:?KLAMMERTEXT_HOME must be set}
|
|
|
|
|
ERR=/tmp/target_list_test_err.$$
|
|
|
|
|
|
|
|
|
|
red=$'\033[31m'
|
|
|
|
|
green=$'\033[32m'
|
|
|
|
|
bold=$'\033[1m'
|
|
|
|
|
reset=$'\033[0m'
|
|
|
|
|
|
|
|
|
|
# ta, tb, tc are independent; td INCLUDES tc, so tc "provides" td and a
|
|
|
|
|
# definition for tc is copied to td (mac/klammer_registry.cpp).
|
|
|
|
|
TARGETS='@@@target ta | Target A @@@
|
|
|
|
|
@@@target tb | Target B @@@
|
|
|
|
|
@@@target tc | Target C @@@
|
|
|
|
|
@@@target td | Target D :includes tc @@@
|
|
|
|
|
'
|
|
|
|
|
|
|
|
|
|
trim() { awk '{ sub(/[ \t\r]+$/, "") } { line[NR]=$0 } END { f=1; while (f<=NR && line[f]=="") f++; l=NR; while (l>=1 && line[l]=="") l--; for (i=f;i<=l;i++) print line[i] }'; }
|
|
|
|
|
|
|
|
|
|
# check_eq NAME TARGET EXPECTED SRC — exit 0, stdout==EXPECTED, no warning.
|
|
|
|
|
check_eq() {
|
|
|
|
|
local name="$1" target="$2" expected="$3" src="$4"
|
|
|
|
|
local out status err
|
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
|
|
|
out=$("$KTEXT" --klammersets none -s "$TARGETS$src" -t "$target" -d 2>"$ERR"); status=$?
|
Target coverage: a klammer states the targets it serves
kdesc gains --coverage, which reports for every klammer the set of targets it
can render to, and — the point of it — which klammers' coverage cannot be
derived and must therefore be declared. Three rules: coverage is DERIVED
where the definitions determine it (a general body of klammer calls covers
the intersection of what those klammers cover, by a greatest fixpoint after
loading), DECLARED where the engine cannot interpret what decides it (an
@eval body, whose targets are undecidable), and UNKNOWN where nothing is
written — which never means "deliberately unavailable".
Two new spellings in a definition's name. A comma-separated target list,
"@@table.html,tex :: ...", gives one body several targets; it is surface
syntax, expanded at registration, and each member goes through the
redefinition rules on its own. And "@@date.* :: ..." writes the general
target out, asserting that the klammer works for EVERY target including ones
not yet defined — a stronger claim than a list of the targets defined today,
and the one target declaration that could be mechanically falsified.
The Standard Klammer Set was swept accordingly: it now has no general
definitions at all, every klammer names the targets it serves, six use ".*",
and tex and pdf are at zero undecided.
kdesc's flags are reorganised on two rules: a flag reached for often gets a
single letter (-k klammers, -t targets, -c characters, -i input), a more
specialised topic a multi-letter name (--argtypes, --katoms, --rewrite,
--optionsets, --coverage, --klammerset, --font); and -v says how much to show
about PROCESSING, never what the RESULT contains — so the katom regex column
is "--katoms full" and the coverage detail "--coverage all". NOTE: "-k" now
lists klammers (optionally filtered by a name/description search); the katom
table moved to "--katoms".
Fixes carried along: an option written with no value crashed the command with
SIGSEGV instead of reporting the mistake; two required positional arguments
never parsed; kdesc and kdiag printed an error and exited 0; and definition
diagnostics counted registrations rather than what was written, so one line
could be reported as two definitions and then printed twice.
Four new test suites: target_list, coverage, command_option, kdesc.
(from dev 46f54080bd9a)
2026-08-12 17:20:23 +02:00
|
|
|
err=$(cat "$ERR")
|
|
|
|
|
out=$(printf '%s' "$out" | trim)
|
|
|
|
|
if [ $status -ne 0 ]; then
|
|
|
|
|
echo "${red}FAIL${reset} $name — ktext exited $status"
|
|
|
|
|
echo " stderr: $(echo "$err" | head -2)"; FAIL=$((FAIL+1)); return
|
|
|
|
|
fi
|
|
|
|
|
if printf '%s' "$err" | grep -qiF "warning"; then
|
|
|
|
|
echo "${red}FAIL${reset} $name — unexpected warning"
|
|
|
|
|
echo " stderr: $(echo "$err" | head -2)"; FAIL=$((FAIL+1)); return
|
|
|
|
|
fi
|
|
|
|
|
if [ "$out" = "$expected" ]; then
|
|
|
|
|
echo "${green}PASS${reset} $name"; PASS=$((PASS+1))
|
|
|
|
|
else
|
|
|
|
|
echo "${red}FAIL${reset} $name"
|
|
|
|
|
echo " expected: [$expected]"; echo " got: [$out]"; FAIL=$((FAIL+1))
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
# check_warn NAME TARGET EXPECTED SRC — exit 0, stdout==EXPECTED, the override
|
|
|
|
|
# SILENT at the default verbosity and REPORTED at "-v 1" (2026-08-15; see
|
|
|
|
|
# tst/deftype_test.sh's check_warn for why it is no longer a warning).
|
Target coverage: a klammer states the targets it serves
kdesc gains --coverage, which reports for every klammer the set of targets it
can render to, and — the point of it — which klammers' coverage cannot be
derived and must therefore be declared. Three rules: coverage is DERIVED
where the definitions determine it (a general body of klammer calls covers
the intersection of what those klammers cover, by a greatest fixpoint after
loading), DECLARED where the engine cannot interpret what decides it (an
@eval body, whose targets are undecidable), and UNKNOWN where nothing is
written — which never means "deliberately unavailable".
Two new spellings in a definition's name. A comma-separated target list,
"@@table.html,tex :: ...", gives one body several targets; it is surface
syntax, expanded at registration, and each member goes through the
redefinition rules on its own. And "@@date.* :: ..." writes the general
target out, asserting that the klammer works for EVERY target including ones
not yet defined — a stronger claim than a list of the targets defined today,
and the one target declaration that could be mechanically falsified.
The Standard Klammer Set was swept accordingly: it now has no general
definitions at all, every klammer names the targets it serves, six use ".*",
and tex and pdf are at zero undecided.
kdesc's flags are reorganised on two rules: a flag reached for often gets a
single letter (-k klammers, -t targets, -c characters, -i input), a more
specialised topic a multi-letter name (--argtypes, --katoms, --rewrite,
--optionsets, --coverage, --klammerset, --font); and -v says how much to show
about PROCESSING, never what the RESULT contains — so the katom regex column
is "--katoms full" and the coverage detail "--coverage all". NOTE: "-k" now
lists klammers (optionally filtered by a name/description search); the katom
table moved to "--katoms".
Fixes carried along: an option written with no value crashed the command with
SIGSEGV instead of reporting the mistake; two required positional arguments
never parsed; kdesc and kdiag printed an error and exited 0; and definition
diagnostics counted registrations rather than what was written, so one line
could be reported as two definitions and then printed twice.
Four new test suites: target_list, coverage, command_option, kdesc.
(from dev 46f54080bd9a)
2026-08-12 17:20:23 +02:00
|
|
|
check_warn() {
|
|
|
|
|
local name="$1" target="$2" expected="$3" src="$4"
|
|
|
|
|
local out status err
|
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
|
|
|
out=$("$KTEXT" --klammersets none -s "$TARGETS$src" -t "$target" -d 2>"$ERR"); status=$?
|
Target coverage: a klammer states the targets it serves
kdesc gains --coverage, which reports for every klammer the set of targets it
can render to, and — the point of it — which klammers' coverage cannot be
derived and must therefore be declared. Three rules: coverage is DERIVED
where the definitions determine it (a general body of klammer calls covers
the intersection of what those klammers cover, by a greatest fixpoint after
loading), DECLARED where the engine cannot interpret what decides it (an
@eval body, whose targets are undecidable), and UNKNOWN where nothing is
written — which never means "deliberately unavailable".
Two new spellings in a definition's name. A comma-separated target list,
"@@table.html,tex :: ...", gives one body several targets; it is surface
syntax, expanded at registration, and each member goes through the
redefinition rules on its own. And "@@date.* :: ..." writes the general
target out, asserting that the klammer works for EVERY target including ones
not yet defined — a stronger claim than a list of the targets defined today,
and the one target declaration that could be mechanically falsified.
The Standard Klammer Set was swept accordingly: it now has no general
definitions at all, every klammer names the targets it serves, six use ".*",
and tex and pdf are at zero undecided.
kdesc's flags are reorganised on two rules: a flag reached for often gets a
single letter (-k klammers, -t targets, -c characters, -i input), a more
specialised topic a multi-letter name (--argtypes, --katoms, --rewrite,
--optionsets, --coverage, --klammerset, --font); and -v says how much to show
about PROCESSING, never what the RESULT contains — so the katom regex column
is "--katoms full" and the coverage detail "--coverage all". NOTE: "-k" now
lists klammers (optionally filtered by a name/description search); the katom
table moved to "--katoms".
Fixes carried along: an option written with no value crashed the command with
SIGSEGV instead of reporting the mistake; two required positional arguments
never parsed; kdesc and kdiag printed an error and exited 0; and definition
diagnostics counted registrations rather than what was written, so one line
could be reported as two definitions and then printed twice.
Four new test suites: target_list, coverage, command_option, kdesc.
(from dev 46f54080bd9a)
2026-08-12 17:20:23 +02:00
|
|
|
out=$(printf '%s' "$out" | trim)
|
|
|
|
|
if [ $status -ne 0 ]; then
|
|
|
|
|
echo "${red}FAIL${reset} $name — ktext exited $status"; FAIL=$((FAIL+1)); return
|
|
|
|
|
fi
|
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
|
|
|
if [ -s "$ERR" ]; then
|
|
|
|
|
echo "${red}FAIL${reset} $name — the default run was not silent: $(head -1 "$ERR")"
|
|
|
|
|
FAIL=$((FAIL+1)); return
|
|
|
|
|
fi
|
|
|
|
|
"$KTEXT" --klammersets none -s "$TARGETS$src" -t "$target" -d -v 1 >/dev/null 2>"$ERR"
|
|
|
|
|
err=$(cat "$ERR")
|
|
|
|
|
if ! printf '%s' "$err" | grep -qiF "overridden"; then
|
|
|
|
|
echo "${red}FAIL${reset} $name — no override reported at -v 1"; FAIL=$((FAIL+1)); return
|
Target coverage: a klammer states the targets it serves
kdesc gains --coverage, which reports for every klammer the set of targets it
can render to, and — the point of it — which klammers' coverage cannot be
derived and must therefore be declared. Three rules: coverage is DERIVED
where the definitions determine it (a general body of klammer calls covers
the intersection of what those klammers cover, by a greatest fixpoint after
loading), DECLARED where the engine cannot interpret what decides it (an
@eval body, whose targets are undecidable), and UNKNOWN where nothing is
written — which never means "deliberately unavailable".
Two new spellings in a definition's name. A comma-separated target list,
"@@table.html,tex :: ...", gives one body several targets; it is surface
syntax, expanded at registration, and each member goes through the
redefinition rules on its own. And "@@date.* :: ..." writes the general
target out, asserting that the klammer works for EVERY target including ones
not yet defined — a stronger claim than a list of the targets defined today,
and the one target declaration that could be mechanically falsified.
The Standard Klammer Set was swept accordingly: it now has no general
definitions at all, every klammer names the targets it serves, six use ".*",
and tex and pdf are at zero undecided.
kdesc's flags are reorganised on two rules: a flag reached for often gets a
single letter (-k klammers, -t targets, -c characters, -i input), a more
specialised topic a multi-letter name (--argtypes, --katoms, --rewrite,
--optionsets, --coverage, --klammerset, --font); and -v says how much to show
about PROCESSING, never what the RESULT contains — so the katom regex column
is "--katoms full" and the coverage detail "--coverage all". NOTE: "-k" now
lists klammers (optionally filtered by a name/description search); the katom
table moved to "--katoms".
Fixes carried along: an option written with no value crashed the command with
SIGSEGV instead of reporting the mistake; two required positional arguments
never parsed; kdesc and kdiag printed an error and exited 0; and definition
diagnostics counted registrations rather than what was written, so one line
could be reported as two definitions and then printed twice.
Four new test suites: target_list, coverage, command_option, kdesc.
(from dev 46f54080bd9a)
2026-08-12 17:20:23 +02:00
|
|
|
fi
|
|
|
|
|
if [ "$out" = "$expected" ]; then
|
|
|
|
|
echo "${green}PASS${reset} $name"; PASS=$((PASS+1))
|
|
|
|
|
else
|
|
|
|
|
echo "${red}FAIL${reset} $name"
|
|
|
|
|
echo " expected: [$expected]"; echo " got: [$out]"; FAIL=$((FAIL+1))
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# check_error NAME TARGET PATTERN SRC — nonzero exit and PATTERN in the message.
|
|
|
|
|
check_error() {
|
|
|
|
|
local name="$1" target="$2" pattern="$3" src="$4"
|
|
|
|
|
local out status
|
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
|
|
|
out=$("$KTEXT" --klammersets none -s "$TARGETS$src" -t "$target" -d 2>&1); status=$?
|
Target coverage: a klammer states the targets it serves
kdesc gains --coverage, which reports for every klammer the set of targets it
can render to, and — the point of it — which klammers' coverage cannot be
derived and must therefore be declared. Three rules: coverage is DERIVED
where the definitions determine it (a general body of klammer calls covers
the intersection of what those klammers cover, by a greatest fixpoint after
loading), DECLARED where the engine cannot interpret what decides it (an
@eval body, whose targets are undecidable), and UNKNOWN where nothing is
written — which never means "deliberately unavailable".
Two new spellings in a definition's name. A comma-separated target list,
"@@table.html,tex :: ...", gives one body several targets; it is surface
syntax, expanded at registration, and each member goes through the
redefinition rules on its own. And "@@date.* :: ..." writes the general
target out, asserting that the klammer works for EVERY target including ones
not yet defined — a stronger claim than a list of the targets defined today,
and the one target declaration that could be mechanically falsified.
The Standard Klammer Set was swept accordingly: it now has no general
definitions at all, every klammer names the targets it serves, six use ".*",
and tex and pdf are at zero undecided.
kdesc's flags are reorganised on two rules: a flag reached for often gets a
single letter (-k klammers, -t targets, -c characters, -i input), a more
specialised topic a multi-letter name (--argtypes, --katoms, --rewrite,
--optionsets, --coverage, --klammerset, --font); and -v says how much to show
about PROCESSING, never what the RESULT contains — so the katom regex column
is "--katoms full" and the coverage detail "--coverage all". NOTE: "-k" now
lists klammers (optionally filtered by a name/description search); the katom
table moved to "--katoms".
Fixes carried along: an option written with no value crashed the command with
SIGSEGV instead of reporting the mistake; two required positional arguments
never parsed; kdesc and kdiag printed an error and exited 0; and definition
diagnostics counted registrations rather than what was written, so one line
could be reported as two definitions and then printed twice.
Four new test suites: target_list, coverage, command_option, kdesc.
(from dev 46f54080bd9a)
2026-08-12 17:20:23 +02:00
|
|
|
if [ $status -eq 0 ]; then
|
|
|
|
|
echo "${red}FAIL${reset} $name — expected an error but ktext succeeded"; FAIL=$((FAIL+1)); return
|
|
|
|
|
fi
|
|
|
|
|
if echo "$out" | grep -qF "$pattern"; then
|
|
|
|
|
echo "${green}PASS${reset} $name"; PASS=$((PASS+1))
|
|
|
|
|
else
|
|
|
|
|
echo "${red}FAIL${reset} $name — expected error to contain [$pattern]"
|
|
|
|
|
echo " output: $(echo "$out" | head -3)"; FAIL=$((FAIL+1))
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo "${bold}Klammer definition target-list tests${reset}"
|
|
|
|
|
echo "===================================="
|
|
|
|
|
echo
|
|
|
|
|
|
|
|
|
|
# --- One body, several targets ---
|
|
|
|
|
echo "-- the list defines each target named --"
|
|
|
|
|
check_eq " 1. first member gets the body" ta "x B y" \
|
|
|
|
|
'@@f.k : a test @@ @@f.ta,tb :: B @@ x @f@ y'
|
|
|
|
|
check_eq " 2. second member gets the body" tb "x B y" \
|
|
|
|
|
'@@f.k : a test @@ @@f.ta,tb :: B @@ x @f@ y'
|
|
|
|
|
check_error " 3. a target NOT in the list is undefined" tc "not defined for target" \
|
|
|
|
|
'@@f.k : a test @@ @@f.ta,tb :: B @@ x @f@ y'
|
|
|
|
|
check_eq " 4. three members, last one" tc "x B y" \
|
|
|
|
|
'@@f.k : a test @@ @@f.ta,tb,tc :: B @@ x @f@ y'
|
|
|
|
|
check_eq " 5. parameters are inherited from .k for every member" tb "x [q] y" \
|
|
|
|
|
'@@f.k s : a test @@ @@f.ta,tb :: [*s*] @@ x @f q @ y'
|
|
|
|
|
check_eq " 6. a list member propagates to a target that includes it" td "x B y" \
|
|
|
|
|
'@@f.k : a test @@ @@f.ta,tc :: B @@ x @f@ y'
|
|
|
|
|
|
|
|
|
|
# --- Malformed lists ---
|
|
|
|
|
echo
|
|
|
|
|
echo "-- malformed lists --"
|
|
|
|
|
check_error " 7. an unknown target in the list" ta "is not defined" \
|
|
|
|
|
'@@f.ta,nosuch : B @@'
|
|
|
|
|
check_error " 8. a target named twice" ta "more than once" \
|
|
|
|
|
'@@f.ta,ta : B @@'
|
|
|
|
|
check_error " 9. \".k\" in a list" ta "in a list of targets" \
|
|
|
|
|
'@@f.k,ta : a test @@'
|
|
|
|
|
check_error "10. \".o\" in a list" ta "in a list of targets" \
|
|
|
|
|
'@@f.o,ta : an option set @@'
|
|
|
|
|
# "*" is the general target written out: an assertion that the klammer works
|
|
|
|
|
# for EVERY target, including ones not yet defined. In a list it is either
|
|
|
|
|
# redundant or a misunderstanding.
|
|
|
|
|
check_error "10a. \"*\" in a list" ta 'names "*" in a list of targets' \
|
|
|
|
|
'@@f.*,ta : b @@'
|
|
|
|
|
check_eq "10b. \"*\" alone defines every target" tb "x body" \
|
|
|
|
|
'@@f.* : body @@ x @f@'
|
|
|
|
|
check_eq "10c. ... including one it does not name" ta "x body" \
|
|
|
|
|
'@@f.* : body @@ x @f@'
|
|
|
|
|
check_error "11. a trailing comma" ta "is not correctly defined" \
|
|
|
|
|
'@@f.ta, : B @@'
|
|
|
|
|
check_error "12. an empty member" ta "is not correctly defined" \
|
|
|
|
|
'@@f.ta,,tb : B @@'
|
|
|
|
|
|
|
|
|
|
# --- The transition table applies per member, not to the list ---
|
|
|
|
|
echo
|
|
|
|
|
echo "-- redefinition, decided per member --"
|
|
|
|
|
check_error "13. create + list create collides on the shared member" ta "already defined" \
|
|
|
|
|
'@@f.ta : one @@ @@f.ta,tb : two @@ x @f@'
|
|
|
|
|
# The list's default is silently ignored for ta (which already has a create)
|
|
|
|
|
# and creates tb. This is the case a whole-list decision would get wrong.
|
|
|
|
|
check_eq "14. existing create + list default: existing kept" ta "x one" \
|
|
|
|
|
'@@f.ta : one @@ @@f.ta,tb :::: two @@ x @f@'
|
|
|
|
|
check_eq "15. existing create + list default: other member defined" tb "x two" \
|
|
|
|
|
'@@f.ta : one @@ @@f.ta,tb :::: two @@ x @f@'
|
|
|
|
|
check_eq "16. list default + create for one member: replaced" ta "x real" \
|
|
|
|
|
'@@f.ta,tb :::: def @@ @@f.ta : real @@ x @f@'
|
|
|
|
|
check_eq "17. list default + create for one member: other keeps default" tb "x def" \
|
|
|
|
|
'@@f.ta,tb :::: def @@ @@f.ta : real @@ x @f@'
|
|
|
|
|
check_warn "18. list override warns and replaces (first member)" ta "x over" \
|
|
|
|
|
'@@f.k : a test @@ @@f.ta :: one @@ @@f.tb :: two @@ @@f.ta,tb ::: over @@ x @f@'
|
|
|
|
|
check_warn "19. list override warns and replaces (second member)" tb "x over" \
|
|
|
|
|
'@@f.k : a test @@ @@f.ta :: one @@ @@f.tb :: two @@ @@f.ta,tb ::: over @@ x @f@'
|
|
|
|
|
|
|
|
|
|
# --- The comma is a target separator ONLY after "@@" ---
|
|
|
|
|
echo
|
|
|
|
|
echo "-- a comma elsewhere is writer text --"
|
|
|
|
|
check_eq "20. a comma in a body is text" ta "x a,b" \
|
|
|
|
|
'@@f.ta : a,b @@ x @f@'
|
|
|
|
|
check_eq "21. a comma after an argument substitution" ta "x q,tail" \
|
|
|
|
|
'@@f.ta s : *s*,tail @@ x @f q @'
|
|
|
|
|
check_eq "22. a comma after an application" ta "x q, y" \
|
|
|
|
|
'@@f.ta s : *s* @@ x @f q @, y'
|
|
|
|
|
check_eq "23. a general definition is unaffected" ta "x B" \
|
|
|
|
|
'@@f : B @@ x @f@'
|
|
|
|
|
|
|
|
|
|
# --- Diagnostics count what was WRITTEN, not how often it registered ---
|
|
|
|
|
echo
|
|
|
|
|
echo "-- one definition, several registrations --"
|
|
|
|
|
# tc provides td, so "@@f.tc : ..." registers twice from one line. Before
|
|
|
|
|
# this was grouped, the message said "2 definitions" and then printed the one
|
|
|
|
|
# line the author wrote twice, sending them to look for a second.
|
|
|
|
|
check_error "24. the count is of written definitions" ta \
|
|
|
|
|
"and a definition that declares its own parameters" \
|
|
|
|
|
'@@f.k s : d @@ @@f.tc : [*s*] @@'
|
|
|
|
|
check_error "25. ... and the location names its targets" ta "(targets tc, td)" \
|
|
|
|
|
'@@f.k s : d @@ @@f.tc : [*s*] @@'
|
|
|
|
|
# Two definitions in two places are still two.
|
|
|
|
|
check_error "26. distinct places still count separately" ta \
|
|
|
|
|
"2 definitions that declare their own parameters" \
|
|
|
|
|
'@@f.k s : d @@ @@f.ta : a*s* @@ @@f.tb : b*s* @@'
|
|
|
|
|
# The remedy, named in the message rather than implied.
|
|
|
|
|
check_error "27. the message says what to write instead" ta \
|
|
|
|
|
'Write "::" instead of ":"' \
|
|
|
|
|
'@@f.k s : d @@ @@f.tc : [*s*] @@'
|
|
|
|
|
|
|
|
|
|
rm -f "$ERR"
|
|
|
|
|
|
|
|
|
|
echo
|
|
|
|
|
echo "===================================="
|
|
|
|
|
echo "Results: ${PASS} passed, ${FAIL} failed"
|
|
|
|
|
[ "$FAIL" -eq 0 ] || exit 1
|
|
|
|
|
exit 0
|