Skip to content

Layering is convention, not structure: no per-layer headers, eigenscript.h is a 1253-line umbrella, eigenscript.c carries two dead extension includes, vm.c has 32 stale externs #744

Description

@InauguralPhysicist

Found in a modularity review of main @ 8e8970a. Tracking issue, ordered cheapest-fix-first. The pipeline (lexer → parser → compiler → chunk → vm → builtins → ext) is a real and defensible design; nothing enforces it.

1. eigenscript.c includes two extension private headers and uses zero symbols from them — trivially removable

eigenscript.c:13 includes ext_db_internal.h and :16 includes model_internal.h. Verified usage in that TU:

Symbol Uses in eigenscript.c
TransformerModel 0
PGconn 0
g_db_conn 0
ne_matmul_buf 0
quantize_ternary 0
json_obj_get 0
ObserverBuffer 0

ext_db_internal.h:4 states "Only included by ext_db.c" and pulls <libpq-fe.h>. So in the full variant the core TU cannot compile without PostgreSQL headers on the include path, for a dead include. Deleting both lines is safe and removes the only core→ext include edge in the tree.

2. vm.c:242-278 carries 32 stale extern re-declarations of already-public symbols

All are declared in eigenscript.h. One is commented "declared in eval.c" (vm.c:266-268) — a TU deleted when the bytecode VM replaced the tree-walker. val_incref there (vm.c:242) is inert, because eigenscript.h:903 defines it static inline. Harmless today, a silent divergence hazard the moment any of those signatures changes.

3. No per-layer headers; eigenscript.h is a 1253-line umbrella every TU includes

There is no lexer.h, parser.h, compiler.h, chunk.h, or builtins.h — only vm.h, jit.h, trace.h, state.h. eigenscript.h spans tokenizer (:114), AST (:159), values (:217), arena (:418), EigsThread (:442), env (:927), parser (:1054), registration (:1082), MODEL tensor kernels (:1194), handle table (:1204), store (:1214), step (:1217), fmt+lint (:1222) — 26 structs with every field visible, 167 declarations, included by 29 of ~30 TUs.

Measured consequences:

The header graph itself is clean and acyclic (eigenscript.h → value_slot.h, vm.h → value_slot.h, everything else → eigenscript.h), so this is a hub problem, not a tangle. The external API discipline is notably better: eigs_embed.h plus six *_internal.h headers.

4. Filesystem utilities live in the builtins leaf and are consumed upward

read_file_util (builtins.c:2806) and resolve_eigenscript_file_from (:2880/2886) are used by vm.c:5034-5036 (the import opcode re-declares both extern at block scope inside the dispatch loop), main.c:298, lint.c:2157,2622,2691, and fmt.c:383.

So nothing can link file reading without the whole 7407-line builtins TU — visibly why LSP_SOURCES (Makefile:39) and FUZZ_SOURCES (:296) link the entire runtime after hand-picked subsets bitrotted. The VM's import handler additionally performs path resolution, realpath, and module-cache canonicalization inline (vm.c:5028-5083), so the dispatch loop owns filesystem policy.

5. Two TUs carry several responsibilities each

  • vm.c (6224): dispatch (vm_run_ex, :2365-5496 — a single 3131-line function covering 85 opcodes), the JIT helper runtime ABI (jit_helper_*, :759-2255, ~1500 lines), the cooperative task scheduler (:5502-6190, self-contained TaskScheduler), and the SIGUSR1 observer dump (:33-240).
  • builtins.c (7407): at least ten groups — bitwise (:396), dict (:700), regex (:1636), string (:1785), argv/path/fs (:2070), corpus/JSON (:2285), file+module loading (:2800), stdio/exec/proc (:3099), eval + bytecode assembly (:4068), channels/tasks (:5032), buffers/DSP (:5938), DEFLATE (:6135).

Worth noting what the size metric doesn't say: builtins.c has 248 functions averaging 29 lines and jit.c 180 averaging 22 — both are well-decomposed files that are merely long. vm.c (101 functions, 61-line average, one at 3131) is the genuine cohesion outlier.

Mechanical splits available now: vm.c's task scheduler → task.c (own struct, own statics); builtins.c's buffer/DSP kernels and DEFLATE → builtins_buf.c (no shared statics). Entangled: jit_helper_* must stay with vm.c because it consumes static inline vm_push/vm_pop/vm_slot_lift (vm.c:582-645); moving it needs those promoted to a private header first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions