#!/usr/bin/env bash # arity.sh — check call arity against the runtime's OWN declarations. # # codegen.el carried builtin_arity(): 344 lines, 300 entries, of which 243 were # an exact duplicate of el_runtime.h. Measured drift between them was zero -- # the duplicate had been maintained correctly -- but 199 functions the runtime # declares had NO entry, so calling them with the wrong argument count produced # no El-level diagnostic at all. The table was not wrong, it was 40% incomplete. # # Deriving from the header fixes the coverage and makes drift impossible. set -uo pipefail REL="${1:?usage: arity.sh [runtime-header]}" HDR="${2:-$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)/runtime/el_runtime.h}" [ -f "$REL" ] || exit 0 [ -f "$HDR" ] || { echo "no header: $HDR" >&2; exit 0; } SIG=$(mktemp); trap 'rm -f "$SIG"' EXIT # Declarations may span lines, so join continuations before parsing. Reading # only the first line silently yields 0 params, and a checker that reports the # wrong expected count is worse than no checker at all. sed 's://.*::' "$HDR" | tr '\n' ' ' | sed 's:/\*[^*]*\*/: :g; s/;/;\n/g' | awk ' /el_val_t[[:space:]]+[a-z0-9_]+[[:space:]]*\(/ { line=$0 match(line, /el_val_t[[:space:]]+[a-z0-9_]+/); name=substr(line,RSTART,RLENGTH) sub(/el_val_t[[:space:]]+/,"",name) match(line, /\(.*\)/); params=substr(line,RSTART+1,RLENGTH-2) gsub(/^[[:space:]]+|[[:space:]]+$/,"",params) if (params=="void" || params=="") n=0 else { n=1; for(i=1;i<=length(params);i++) if(substr(params,i,1)==",") n++ } if (line ~ /\.\.\./) n=-1 print name, n }' | sort -u > "$SIG" V=0 while read -r callee _ rest; do [ "${rest#arity:}" = "$rest" ] && continue actual="${rest#arity:}" expected=$(awk -v n="$callee" '$1==n {print $2; exit}' "$SIG") # 60 of 500 runtime decls carry a __ prefix: El's `println` is C's # `__println`. codegen owns that mapping and its table carried BOTH keys. # One rule covers every one of them. [ -n "$expected" ] || expected=$(awk -v n="__$callee" '$1==n {print $2; exit}' "$SIG") [ -n "$expected" ] || continue # not a runtime builtin [ "$expected" = "-1" ] && continue # variadic if [ "$actual" != "$expected" ]; then printf "arity error: '%s' takes %s arguments, called with %s\n" "$callee" "$expected" "$actual" V=$((V+1)) fi done < <(sort -u "$REL") [ "$V" -eq 0 ] && echo "arity: clean ($(wc -l < "$SIG" | tr -d ' ') signatures from the header)" exit "$V"