Initial commit: Klammertext source distribution

Curated source subset assembled by klammertext-dev's doc/make_dist.sh: the Klammermachine (mac), the Standard Klammer Set (sks), the commands (com), editor plugins and install guides (doc), a test subset (tst), and lib/bin placeholders. Builds with 'make -C com'.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-18 18:48:23 +02:00
commit 2ba7ceee7a
272 changed files with 27634 additions and 0 deletions

12
tst/Makefile Normal file
View File

@@ -0,0 +1,12 @@
# Klammertext distribution test suite (subset).
#
# Runs the two shell regression suites:
# cond_test.sh — @cond argument delimitation
# deftype_test.sh — the four klammer definition modes + redefinition table
#
# Requires KLAMMERTEXT_HOME set and `ktext` on PATH (build it with `make -C com`).
.PHONY: test
test:
./cond_test.sh
./deftype_test.sh

17
tst/cond_test.kt Normal file
View File

@@ -0,0 +1,17 @@
Top level cond: @cond true | is true | is false @
@@cond_test bool :
Using cond in klammer: @cond *bool* | is true | is false @
@@
@cond_test true @
@@frac a | b : *a*/*b* @@
A fraction: @frac 2 | 3 @
@@cond_klammer_test bool :
@cond *bool* | @frac 1 | 2 @ | @frac 2 | 1 @ @
@@
# @cond_klammer_test true @

182
tst/cond_test.sh Executable file
View File

@@ -0,0 +1,182 @@
#!/bin/bash
#
# cond_test.sh — Regression tests for @cond argument delimitation.
#
# These tests pin down the fix for the bug witnessed by tst/cond_test.kt:
# a defined klammer that contains its own bar separators (e.g. @frac a | b @)
# nested inside a @cond branch caused @cond to miscount bars and reject the
# input with "There should only be one or two bar characters".
#
# Root cause: @cond delimited its arguments by counting EVERY bar in its flat
# katom range, conflating the inner klammer's bars (which belong to the inner
# klammer's arity) with @cond's own separators. The fix counts only the bars
# at nesting depth 0 within the @cond span (cond_separator_bars() in
# mac/machine.cpp), so argument boundaries follow the span tree.
#
# See doc/cond_evaluation_order.md for the full description and the
# theoretical basis (operadic arity, the precedence-order proposition, and
# @cond as a non-strict special form).
#
# Usage: ./cond_test.sh (LSan suppressions come from mac/env/runtime.env.*)
# Exit code: 0 if all tests pass, 1 otherwise.
PASS=0
FAIL=0
KTEXT=ktext
K=${KLAMMERTEXT_HOME:?KLAMMERTEXT_HOME must be set}
red=$'\033[31m'
green=$'\033[32m'
bold=$'\033[1m'
reset=$'\033[0m'
# strip leading/trailing blank lines and surrounding whitespace
trim() { sed -e 's/[[:space:]]*$//' | sed -e '/./,$!d' | tac | sed -e '/./,$!d' | tac; }
# check_eq TEST_NAME EXPECTED KTEXT_ARGS...
# Runs ktext, expects exit status 0, and compares trimmed stdout to EXPECTED.
check_eq() {
local test_name="$1"
local expected="$2"
shift 2
local output status
output=$("$KTEXT" "$@" 2>/tmp/cond_test_err.$$)
status=$?
output=$(printf '%s' "$output" | trim)
if [ $status -ne 0 ]; then
echo "${red}FAIL${reset} $test_name — ktext exited $status"
echo " stderr: $(head -3 /tmp/cond_test_err.$$)"
FAIL=$((FAIL + 1))
return
fi
if [ "$output" = "$expected" ]; then
echo "${green}PASS${reset} $test_name"
PASS=$((PASS + 1))
else
echo "${red}FAIL${reset} $test_name"
echo " expected: [$expected]"
echo " got: [$output]"
FAIL=$((FAIL + 1))
fi
}
# check_contains TEST_NAME SUBSTRING KTEXT_ARGS...
# Runs ktext, expects exit status 0, and checks that stdout contains SUBSTRING.
check_contains() {
local test_name="$1"
local needle="$2"
shift 2
local output status
output=$("$KTEXT" "$@" 2>&1)
status=$?
if [ $status -ne 0 ]; then
echo "${red}FAIL${reset} $test_name — ktext exited $status"
echo " output: $(echo "$output" | head -3)"
FAIL=$((FAIL + 1))
return
fi
if echo "$output" | grep -qF "$needle"; then
echo "${green}PASS${reset} $test_name"
PASS=$((PASS + 1))
else
echo "${red}FAIL${reset} $test_name — expected to contain [$needle]"
echo " output: $(echo "$output" | head -3)"
FAIL=$((FAIL + 1))
fi
}
# check_error TEST_NAME PATTERN KTEXT_ARGS...
# Runs ktext, expects a NONZERO exit status and PATTERN in the message.
check_error() {
local test_name="$1"
local pattern="$2"
shift 2
local output status
output=$("$KTEXT" "$@" 2>&1)
status=$?
if [ $status -eq 0 ]; then
echo "${red}FAIL${reset} $test_name — expected an error but ktext succeeded"
FAIL=$((FAIL + 1))
return
fi
if echo "$output" | grep -qF "$pattern"; then
echo "${green}PASS${reset} $test_name"
PASS=$((PASS + 1))
else
echo "${red}FAIL${reset} $test_name — expected error to contain [$pattern]"
echo " output: $(echo "$output" | head -3)"
FAIL=$((FAIL + 1))
fi
}
FRAC='@@frac a | b : *a*/*b* @@'
echo "${bold}@cond argument delimitation tests${reset}"
echo "================================="
echo
# --- The reported regression (defined klammer with bars inside a branch) ---
check_eq \
" 1. inner klammer with bars, true branch" \
"1/2" \
-s "$FRAC @cond true | @frac 1 | 2 @ | @frac 2 | 1 @ @" -d
check_eq \
" 2. inner klammer with bars, false branch" \
"2/1" \
-s "$FRAC @cond false | @frac 1 | 2 @ | @frac 2 | 1 @ @" -d
# --- The exact witness file from the bug report ---
check_contains \
" 3. tst/cond_test.kt @cond_klammer_test true" \
"1/2" \
"$K/tst/cond_test.kt" -d -s '@cond_klammer_test true @'
check_contains \
" 4. tst/cond_test.kt @cond_klammer_test false" \
"2/1" \
"$K/tst/cond_test.kt" -d -s '@cond_klammer_test false @'
# --- Plain @cond unaffected by the change ---
check_eq " 5. plain two-bar, true" "yes" -s '@cond true | yes | no @' -d
check_eq " 6. plain two-bar, false" "no" -s '@cond false | yes | no @' -d
check_eq " 7. one-bar, true" "shown" -s '@cond true | shown @' -d
check_eq " 8. one-bar, false (empty)" "" -s '@cond false | shown @' -d
# --- Primitives and nesting inside @cond ---
check_eq " 9. @eval in a branch" "42" -s '@cond true | @eval 6*7 @ | no @' -d
check_eq "10. @eval as the predicate" "yes" -s '@cond @eval 1==1 @ | yes | no @' -d
check_eq "11. nested @cond in a branch" "B" -s '@cond true | @cond false | A | B @ | C @' -d
# --- A klammer with its own bars (double-bar / cells) inside a branch ---
check_eq "12. klammer with internal bar in a branch" \
"x+y" \
-s '@@two a | b : *a*+*b* @@ @cond true | @two x | y @ | z @' -d
# --- Genuine arity errors must still be rejected ---
check_error "13. three top-level bars is still an error" \
"one or two bar characters" \
-s '@cond true | a | b | c @' -d
check_error "14. zero bars is still an error" \
"one or two bar characters" \
-s '@cond true @' -d
rm -f /tmp/cond_test_err.$$
echo
echo "================================="
echo "Results: ${green}$PASS passed${reset}, ${red}$FAIL failed${reset}"
[ $FAIL -eq 0 ]

132
tst/deftype_test.sh Executable file
View File

@@ -0,0 +1,132 @@
#!/bin/bash
#
# deftype_test.sh — Regression tests for the four klammer definition modes
# and the 9-combination redefinition transition table.
#
# The four syntactic definition modes (increasing colon count = decreasing
# binding strength, the "conservation of syntax" ladder):
#
# : create, defines its own parameters — error if already defined
# :: create, inherits parameters from `.k` — error if already defined
# ::: override, inherits parameters from `.k` — replaces existing (warns)
# :::: default, defines its own parameters — silently replaced by create
#
# At the transition level (mac/deftype.cpp) `:` and `::` are both `def_create`;
# the three redefinition modes are create / override (`:::`) / default (`::::`).
# `defmode_transition(existing, incoming)` governs all 9 (existing x incoming)
# combinations. This test pins down every entry of that table plus the basic
# behavior of each mode, none of which tst/klammer_test.cpp currently covers.
#
# {replace,warn,message} semantics (mac/klammer_set.cpp):
# !replace && message -> Definition_error (nonzero exit)
# !replace && empty -> silently keep the existing definition
# replace && warn -> emit a warning, then replace
# replace && !warn -> replace silently
#
# Usage: ./deftype_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/deftype_test_err.$$
red=$'\033[31m'
green=$'\033[32m'
bold=$'\033[1m'
reset=$'\033[0m'
# strip leading/trailing blank lines and trailing whitespace
trim() { sed -e 's/[[:space:]]*$//' | sed -e '/./,$!d' | tac | sed -e '/./,$!d' | tac; }
# check_eq NAME EXPECTED KTEXT_ARGS... — exit 0, stdout==EXPECTED, and NO warning.
check_eq() {
local name="$1" expected="$2"; shift 2
local out status err
out=$("$KTEXT" "$@" 2>"$ERR"); status=$?
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"; 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
}
# check_warn NAME EXPECTED KTEXT_ARGS... — exit 0, stdout==EXPECTED, AND a warning on stderr.
check_warn() {
local name="$1" expected="$2"; shift 2
local out status err
out=$("$KTEXT" "$@" 2>"$ERR"); status=$?
err=$(cat "$ERR")
out=$(printf '%s' "$out" | trim)
if [ $status -ne 0 ]; then
echo "${red}FAIL${reset} $name — ktext exited $status"; FAIL=$((FAIL+1)); return
fi
if ! printf '%s' "$err" | grep -qiF "warning"; then
echo "${red}FAIL${reset} $name — expected a warning, got none"; 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
}
# check_error NAME PATTERN KTEXT_ARGS... — nonzero exit and PATTERN in the message.
check_error() {
local name="$1" pattern="$2"; shift 2
local out status
out=$("$KTEXT" "$@" 2>&1); status=$?
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 -2)"; FAIL=$((FAIL+1))
fi
}
echo "${bold}Klammer definition-mode tests${reset}"
echo "============================="
echo
# --- Each mode defines and applies in isolation ---
echo "-- isolated modes --"
check_eq " 1. : create defines + applies" "cq" -s '@@x s : c*s* @@ @x q @' -d
check_eq " 2. :: instance inherits from .k" "iq" -s '@@x.k s : d @@ @@x :: i*s* @@ @x q @' -d
check_error " 3. :: without a .k declaration is an error" "no declarations" -s '@@x :: i*s* @@ @x q @' -d
check_eq " 4. :::: default defines + applies" "eq" -s '@@x s :::: e*s* @@ @x q @' -d
check_eq " 5. ::: override alone becomes the def" "oq" -s '@@x.k s : d @@ @@x ::: o*s* @@ @x q @' -d
# --- The 9-entry transition table: (existing x incoming) ---
echo
echo "-- transition table (existing + incoming) --"
check_error " 6. create + create = error" "already defined" -s '@@x s : one*s* @@ @@x s : two*s* @@ @x q @' -d
check_warn " 7. create + override = warn+repl" "twoq" -s '@@x.k s : d @@ @@x :: one*s* @@ @@x ::: two*s* @@ @x q @' -d
check_eq " 8. create + default = keep exist" "oneq" -s '@@x s : one*s* @@ @@x s :::: two*s* @@ @x q @' -d
check_error " 9. override + create = error" "already overridden" -s '@@x.k s : d @@ @@x ::: one*s* @@ @@x :: two*s* @@ @x q @' -d
check_warn "10. override + override = warn+repl" "twoq" -s '@@x.k s : d @@ @@x ::: one*s* @@ @@x ::: two*s* @@ @x q @' -d
check_eq "11. override + default = keep exist" "oneq" -s '@@x.k s : d @@ @@x ::: one*s* @@ @@x :::: two*s* @@ @x q @' -d
check_eq "12. default + create = replace (silent)" "twoq" -s '@@x s :::: one*s* @@ @@x s : two*s* @@ @x q @' -d
check_warn "13. default + override = warn+repl" "twoq" -s '@@x.k s : d @@ @@x :::: one*s* @@ @@x ::: two*s* @@ @x q @' -d
check_error "14. default + default = error" "already defined" -s '@@x s :::: one*s* @@ @@x s :::: two*s* @@ @x q @' -d
rm -f "$ERR"
echo
echo "============================="
echo "Results: ${green}$PASS passed${reset}, ${red}$FAIL failed${reset}"
[ $FAIL -eq 0 ]