mirror of
https://github.com/fluffos/fluffos
synced 2026-08-12 18:26:06 -04:00
* Add inherit_program / include_file master applies; auto hot-reload demo
New compile-time master applies, consulted for every inherit statement
and #include directive:
* mixed inherit_program(string from, string path, int priv)
Called while compiling `from` for `inherit "path";` (priv nonzero for
private inherits). A string return is an alternate path for the
inherited file; an array-of-strings return is the inherited program's
source itself (compiled via load_object_from_source under the inherit
statement's name, through the existing load_object retry loop); any
other return prevents the inheritance.
* mixed include_file(string compiled, string from, string path)
Called when `from` is about to include `path` while compiling
`compiled`. A string return is the translated path (resolved absolute
from the mudlib root or relative to the includer; returning `path`
unchanged keeps the "..."-vs-<...> search semantics); an
array-of-strings return is the included text itself (pushed as an
in-memory include buffer with the usual file-identity bookkeeping);
any other return prevents the inclusion.
Both follow the valid_override/get_include_path precedent for calling
master LPC mid-compile (skipped without a VM context or master object),
and a missing apply keeps stock behavior.
The applies expose the full compile-time dependency graph, which the
testsuite uses to demonstrate mudlib auto hot-reload on file changes:
/single/hot_reload.lpc registers as the master's compile hooks, records
which source files each program's bytecode was built from (own source,
includes, inherited programs, transitively), and its call_out poller
destructs+reloads watched blueprints whose dependency closure changed
on disk - including reloading a stale parent when only the parent's
include changed.
Testsuite: single/tests/compiler/{inherit_program,include_file}.lpc pin
the apply semantics (redirect, inline source, deny, priv flag, argument
shapes on nested includes) via the scriptable /clone/compile_hook;
single/tests/applies/hot_reload.lpc demonstrates end-to-end hot reload
over a runtime-written inherit+include fixture chain. Docs added for
both applies.
Validated: full LPC suite (532 files) x2 on RelWithDebInfo, x2 on
Debug+ASan/UBSan, plus the 297 GTest unit tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018DGhzJfPhDGJA94EPh1gEK
* docs: add hot reload guide for the new compile-time master applies
New concepts page (concepts/general/hot_reload.md) explaining why
"file changed -> reload" needs the compile-time dependency graph, how
the inherit_program / include_file master applies expose it, and a
step-by-step mudlib implementation with examples: master delegation,
dependency recording, closure computation, change detection with
size+mtime snapshots, parent-first reload ordering, and the call_out
poller. Documents blueprint-reload semantics and caveats (clones keep
the old program, no compiles inside the applies, records only complete
for compiles observed by the daemon), pointing at the testsuite
reference implementation. Cross-linked from both apply reference pages
and the concepts indices.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018DGhzJfPhDGJA94EPh1gEK
* docs/testsuite: say "master copy", not "blueprint"
Align the hot-reload guide, apply reference, daemon, and test comments
with the project's terminology for the object loaded from a file (see
clonep(3): "the master copy").
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018DGhzJfPhDGJA94EPh1gEK
* testsuite: edge cases for the compile-time applies; docs review fixes
compile_hooks_edge.lpc pins that unusual inherit_program/include_file
return values produce clean LPC errors or the documented behavior,
never a driver crash: empty array, non-string elements, redirect to
self, empty-string redirect, inline source vs already-loaded object,
multiline inline content, the apply itself throwing mid-compile
(safe_apply falls back to default resolution), extension-spelled
redirects, and denying the auto-included global include file.
Fixtures in /clone/adv_*; /clone/adv_hook wraps the scriptable hook
with a throwing include_file.
Docs fixes from review: the apply-page examples now look the daemon up
with find_object() instead of a path call_other (which would load the
target and trigger a compile mid-compile -- the exact pattern the same
pages forbid), and the hot-reload guide's ancestors() snippet carries
the seen-mapping argument to match the reference daemon.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018DGhzJfPhDGJA94EPh1gEK
* hot_reload: fix multi-watch and failed-reload handling; harden tests
Three defects from the LPC review round, each now pinned by the
demonstration test:
* check_now() collected and reloaded in one pass, so the first reload's
snapshot refresh erased the change evidence for every other watched
program sharing the dependency (a common header, or a watched parent
iterating before its watched child - which then stayed bound to the
destructed old parent forever). The stale set is now collected before
any reload runs.
* A reload whose recompile throws (a syntax error mid-edit - the most
common event in a hot-reload workflow) unwound poll() before the
re-arm, killing the poller forever and leaving the watched master
copy destructed. poll() re-arms first, check_now() catches per
program, reload_count only counts successes, and closure_changed()
treats a watched-but-not-loaded program as stale so the retry
self-heals once the file compiles again.
* The three apply tests registered master compile hooks (and the
hot-reload test armed the poller and wrote /data/hot) with cleanup on
the success path only; a thrown check would leave the hook routing
every remaining compile of the randomized run. Each test now runs its
checks under catch and unhooks/tears down unconditionally, re-raising
the error afterward.
The demo test now also covers the shared-dependency pass (watch parent
and child, change the common include, both reload in one pass) and the
broken-edit recovery cycle. The hot-reload guide's snippets are updated
to match the daemon.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018DGhzJfPhDGJA94EPh1gEK
* simulate: let inline inherit source resolve its own unloaded inherits
From the C++ review round: master::inherit_program returning inline
source whose text itself inherits a not-yet-loaded program failed the
whole load with "#inherit is not supported when compiling from
in-memory source" -- reachable in the feature's primary use case, since
synthesized programs routinely inherit ordinary on-disk library files.
load_object_from_source() now runs the same iterative dance as
load_object(): when the compile aborts on an unloaded parent, load that
parent (from disk, or from further master-supplied inline source, so
synthesized-inheriting-synthesized chains work), then recompile the
same source string -- which is in hand, unlike the historical
no-filename rationale for rejecting #inherit here. Mirrors
load_object()'s guards: illegal-to-inherit-self, the duplicate-name
check after the parent's arbitrary LPC ran, and an inherit-chain bound
on the retry loop as a backstop against a master that redirects to a
fresh unloaded name on every recompile.
The inherit_program test now covers both new shapes (inline inheriting
unloaded on-disk, and two levels of inline source); the apply doc drops
the already-loaded-only caveat.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018DGhzJfPhDGJA94EPh1gEK
---------
Co-authored-by: Claude <noreply@anthropic.com>
5 lines
179 B
Text
5 lines
179 B
Text
// Fixture: "if_synth.h" does not exist; the test's compile hook
|
|
// supplies the included text inline (array-of-strings return).
|
|
#include "if_synth.h"
|
|
|
|
int fn() { return SYNTH; }
|