EXPERIMENT: invocation control resolves at runtime

ISHIKAWA: why did wraps_body need compile-time knowledge? Because the wrapper
called the target directly. If the wrapper calls through the seam instead, the
seam can call the body itself, and a construct bound after the build decides
how and whether to invoke it.

PREDICTIONS AND RESULTS
  P1 wrap becomes runtime-bindable                  TRUE   body x3 -> 21,
                                                           never invoked -> 111
  P2 codegen shrinks                                TRUE   5042 -> 4977
  P3 cost 5-10% from an indirect call on every fn   TRUE   0.36s -> 0.39s, ~8%
  P4 zero-param fns break on the empty struct       TRUE   empty struct is a GNU
                                                           extension, empty init
                                                           is C23. Fixed with a
                                                           char field.
  P5 fixpoint holds                                 TRUE

PROCESS FAILURE worth recording: my first patch silently did not apply because
I dropped the assert on the string replacement. The build then failed with
"undeclared identifier __thunk_noargs", which I nearly attributed to the
empty-struct prediction. The guard that would have caught it existed and I
removed it -- the same shape as every other defect found tonight.

Removed: declare_wrap, decorator_wrap, cg_wrap_target, cg_wrap_construct,
params_to_call_args, and the wraps_body scanner branch.

prohibits_outside is now the ONLY construct kind left at compile time, and it
cannot move: a #error has no runtime.
This commit is contained in:
bigmerge
2026-08-17 09:06:05 -05:00
parent b40754f07b
commit bc2f26ddfc
5 changed files with 70 additions and 89 deletions
+6 -1
View File
@@ -83,10 +83,15 @@ check "two constructs compose on one crossing" \
SEEN work/b
7" "$(cd "$WORK" && EL_CONSTRUCTS=two.txt ./prog 2>&1)"
cat >> "$WORK/targets.c" <<'TGT'
el_val_t thrice(el_val_t fn, el_val_t con, el_val_t (*b)(void*), void* e){
(void)fn; (void)con; return b(e) + b(e) + b(e); /* wrap: invoke N times */
}
TGT
printf 'work doubler exit double_result\n' > "$WORK/exit.txt"
check "an EXIT construct declared after the build replaces the result" \
"14" "$(cd "$WORK" && EL_CONSTRUCTS=exit.txt ./prog 2>&1)"
echo
echo " 7 assertions, $((6-FAILS)) passed, $FAILS failed"
echo " 7 assertions, $((7-FAILS)) passed, $FAILS failed"
exit $FAILS