-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrun_example.sh
More file actions
executable file
·74 lines (69 loc) · 4.5 KB
/
Copy pathrun_example.sh
File metadata and controls
executable file
·74 lines (69 loc) · 4.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#!/usr/bin/env bash
# Прогон .nol-программы: разбор → проверка → выполнение → показ → ВЕРДИКТ КОДОМ ВОЗВРАТА.
#
# Использование:
# ./run_example.sh ФАЙЛ.nol [--prelude ФАЙЛ.nolp] [--require ИМЯ_ДЕЙСТВИЯ]
#
# Коды возврата (единственный ответ машине; печать адресована человеку):
# 0 допущено · 1 отклонено · 2 сбой сбора · 3 суда не было · 4 не допущено · 5 с пороком
#
# 🔴 --require ИМЯ. Без него программа, ничего не делающая, даёт «ничему не воспрепятствовало»
# = 0 = «можно». Спрашивающий про необратимое обязан НАЗВАТЬ действие: тогда молчание
# программы становится отказом, а не разрешением.
#
# 🔴 Путь и имя действия уходят в Лисп ПЕРЕМЕННЫМИ ОКРУЖЕНИЯ, а не подстановкой в исходник.
# Раньше «$F» вклеивался в текст программы — имя файла с кавычкой исполняло что угодно.
# Это тот же впрыск, который мы закрываем в цитатах разрешения, и лечится он так же:
# передавать адрес, а не текст.
set -u
cd "$(dirname "$0")" || exit 2
F="${1:?укажите файл .nol}"
shift || true
REQ=""
PRELUDE=""
while [ $# -gt 0 ]; do
case "$1" in
--require) REQ="${2:?--require требует имя действия}"; shift 2 ;;
# 🔴 Путь к прелюдии приходит СНАРУЖИ, от того, кто запускает суд, — и никогда из самой
# программы. Дай программе указывать свою линейку, и разделение мест станет украшением.
--prelude) PRELUDE="${2:?--prelude требует файл}"; shift 2 ;;
*) printf 'неизвестный ключ: %s\n' "$1" >&2; exit 2 ;;
esac
done
if [ ! -r "$F" ]; then
printf '⛔ файл не читается: %s\n⟦NOLANG-VERDICT code=2 kind=СБОЙ⟧ нет файла\n' "$F" >&2
exit 2
fi
RUNNER=/tmp/_nol_run.lisp
cat > "$RUNNER" <<'LISP'
(load (merge-pathnames "src/verdict.lisp" (or (sb-ext:posix-getenv "NOL_HOME") "")))
(let ((path (sb-ext:posix-getenv "NOL_PROGRAM"))
(req (sb-ext:posix-getenv "NOL_REQUIRE"))
(pre (sb-ext:posix-getenv "NOL_PRELUDE")))
(judge-and-exit path
:require (and req (string/= req "") req)
:prelude (and pre (string/= pre "") pre)))
LISP
OUT=$(mktemp /tmp/_nol_out.XXXXXX)
if [ -n "$PRELUDE" ] && [ ! -r "$PRELUDE" ]; then
printf '⛔ прелюдия не читается: %s\n' "$PRELUDE" >&2
exit 2
fi
NOL_HOME="$(pwd)/" NOL_PROGRAM="$F" NOL_REQUIRE="$REQ" NOL_PRELUDE="$PRELUDE" \
sbcl --script "$RUNNER" > "$OUT" 2>&1
RC=$?
cat "$OUT"
# ── 🔴 СВЕРКА КОДА И МАРКЕРА ─────────────────────────────────────────────────────
# Судья — код возврата; маркер нужен ровно для одного: понять, высказался ли судья ВООБЩЕ.
# `sbcl --script`, упав, сам выходит с 1 — то есть с нашим «отклонено»: сломанный инструмент
# неотличим от строгого. Умер до вердикта → маркера нет → это СБОЙ (2), а не ответ языка.
# Маркер ищется ЯКОРЕМ В НАЧАЛЕ СТРОКИ и сравнивается с кодом: подделать его изнутри
# программы (через `says "…"`) можно, но подделка кода возврата процесса ей недоступна —
# поэтому расхождение маркера с кодом тоже читается как сбой, а не как вердикт.
MARK=$(grep -c "^⟦NOLANG-VERDICT code=$RC " "$OUT")
rm -f "$OUT"
if [ "$MARK" -eq 0 ]; then
printf '\n⚠️ вердикт не высказан (маркер отсутствует или не сходится с кодом %s) — считаю сбоем\n' "$RC" >&2
exit 2
fi
exit "$RC"