aboutsummaryrefslogtreecommitdiffstats
path: root/Makefile
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-14 23:53:53 +0200
committeruser <user@clank>2026-08-14 23:53:53 +0200
commite16834a81a7111a4d954369af7e42601e0190a7f (patch)
tree1326d53e05cf7cbe1bb1fd898b82bd9b72e11bfb /Makefile
parentsl0ppty: the graphics stream gives the cursor back (diff)
downloadslosh-e16834a81a7111a4d954369af7e42601e0190a7f.tar.gz
slosh-e16834a81a7111a4d954369af7e42601e0190a7f.tar.xz
slosh-e16834a81a7111a4d954369af7e42601e0190a7f.zip
contrib: a shadertoy for shader expressions
You cannot see an expression by reading it. `(y % 2) * 40` is scanlines and `(x > cols - 10) * 120` is a right margin, and neither is obvious until it is on a screen -- so here is a screen. One HTML file, no build and no server: open it and it works, offline, including from a checkout on a machine that has never run sl0ppty. It draws a fake pane with plausible contents, applies a chain of passes to every cell, and prints the config line to paste. The mouse moves the cursor, so `dist(x, y, curx, cury)` behaves the way it will in a pane rather than the way it does at coordinates you imagined. Anything reading `t` animates. The presets are every built-in written as an expression, which is the equivalence the whole design rests on: `vignette` and `spotlight` are not special, they are `dim` with an argument. It also reports what each expression *reads* and whether that makes it cacheable, because the dependency analysis is the interesting half of the implementation and is otherwise invisible. The hazard is that this is a second implementation of the language, in another language, and it would disagree with the compiler quietly -- in the third digit of a colour, on one preset, at one cursor position. So tests/test_shadertoy.py lifts the evaluator straight out of the page (not a copy of it, the page itself) and runs a few hundred expression/environment pairs through both it and src/expr.c, including the corners: division by zero, the ternary's untaken branch, `dist` counting a row double, and six expressions that both sides must refuse. build/expr_eval is the real compiler as a filter, which is what makes that comparison possible at all. It found a bug on its first run, in the page: unary `-` and `!` did not thread the environment through their closures, so `!x` threw instead of evaluating. Which is the argument for the test, made better than I could have made it. Skipped with a message when node is missing -- a checker for a contrib toy is not a reason the suite cannot run.
Diffstat (limited to 'Makefile')
-rw-r--r--Makefile11
1 files changed, 10 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index d6204fd..1b95a57 100644
--- a/Makefile
+++ b/Makefile
@@ -71,6 +71,13 @@ EXPR_TEST := build/expr_test
$(EXPR_TEST): tests/expr_test.c src/expr.c | build
$(CC) $(CFLAGS) tests/expr_test.c src/expr.c -o $@
+# The real expression evaluator as a filter, so test_shadertoy.py can hold
+# contrib/shadertoy.html's JavaScript to what the compiler actually does.
+EXPR_EVAL := build/expr_eval
+
+$(EXPR_EVAL): tests/expr_eval.c src/expr.c | build
+ $(CC) $(CFLAGS) tests/expr_eval.c src/expr.c -o $@
+
SHADER_TEST := build/shader_test
$(SHADER_TEST): tests/shader_test.c src/shader.c src/screen.c src/json.c src/expr.c $(VT_LIB) | build
@@ -93,13 +100,15 @@ build/exampleshader.so: contrib/shader-plugin/example.c src/shader_abi.h | build
build/.pass-test_shader_plugin: build/testshader.so build/badshader.so \
build/exampleshader.so
+build/.pass-test_shadertoy: $(EXPR_EVAL) contrib/shadertoy.html
+
build/.pass-%: tests/%.py tests/harness.py $(BIN) | build
@cd tests && timeout 300 python3 $(notdir $<) > ../build/.log-$* 2>&1 \
|| { echo "FAIL $(notdir $<)"; tail -25 ../build/.log-$*; exit 1; }
@printf ' ok %-24s %s\n' "$(notdir $<)" "$$(grep -c '^ok' build/.log-$* 2>/dev/null || echo ?) checks"
@touch $@
-test: $(BIN) $(TEST_BIN) $(KDL_TEST) $(SHADER_TEST) $(EXPR_TEST) ## unit + headless checks (fast)
+test: $(BIN) $(TEST_BIN) $(KDL_TEST) $(SHADER_TEST) $(EXPR_TEST) $(EXPR_EVAL) ## unit + headless checks (fast)
@./$(TEST_BIN) >/dev/null && ./$(KDL_TEST) >/dev/null && ./$(SHADER_TEST) >/dev/null \
&& ./$(EXPR_TEST) >/dev/null \
&& printf ' ok %-24s %s\n' "C unit tests" "4 binaries"