Order-independent imports (#181) on top of #203 - #205
Conversation
…dent imports Fix issue #181 on top of PR #203. A definition referencing a not-yet-registered function compiles the reference as inert data, so cross-file meaning depended on import order. Scanning imports upfront cannot work: files fetched by git-import! or generated at runtime are invisible to a scan on a fresh machine but visible once a previous run created them, making program behavior depend on leftover on-disk state. Instead, when a function name registers after stored definitions already compiled it as plain data, those definitions are recompiled from their source terms. Definitions then mean the same thing on every machine regardless of import order, including for libraries that only become loadable at runtime. Expressions that already executed cannot be recompiled retroactively and keep the warning.
5c21b45 to
8c143dc
Compare
A (git-dependency url rev [build [basedir]]) form declares a repository the file needs at an exact commit. Declarations are collected after parsing and satisfied before any form runs, the way cargo fetches its locked dependency graph before compiling: checkouts are staged, verified against the pinned commit, retargeted when the pin changes, and refused when locally modified, so a fresh clone and a machine with a leftover checkout behave identically. A checkout may declare its own dependencies in deps.metta at its repository root, which are acquired transitively; the same url pinned to two commits in one run is an error. The machinery lives in src/gitimport.pl; the runnable git-import! in lib_import.pl remains for dynamic acquisition.
|
The prescan approach this PR originally used had the machine-dependence problem @rTreutlein raised: a signature scan can only see files that already exist, while The PR now takes the inverse approach, and the prescan is gone. #203 already records which names were compiled as plain data ( The second commit picks up the other half of the discussion, including moving git-import to the core. Cargo's handling of git dependencies is the model: declarations are data, every git dependency is locked to a concrete commit, the graph is fetched before anything compiles, and checkouts are verified rather than trusted. PeTTa has no versions or registry, so with exact pins none of the resolver machinery is needed. A file can now declare
|
Stacks on #203 (
import-overhaul). It adds the one import requirement #203 does not cover: import order independence (#181). #203 detects the bad-order case and warns; this makes the order actually not matter, so the four semantics from the tracking discussion (duplicate is a no-op, cycles are fine, order does not matter, relative paths resolve) are all covered once this lands on top of it.Why order matters today
PeTTa freezes the function-vs-data decision at compile time from the
fun/1registry. Within a single file that is fine, because the first pass registers every head before any body compiles. Across files it is not:import!runs during the second pass one file at a time in textual order, so a definition in an earlier-loaded file that calls a function defined in a later-loaded file compiles that call as inert data. This is the #181 repro: importingc(which has(= (bar) (foo))) beforeb(which has(= (foo) ...)) leaves(bar)returning an unreduced(foo).Approach
A name-collection pre-pass in
process_metta_string/3runs once per outer load, walks the static import closure, and parses each file so every function name is registered infun/1before any body compiles. It:import_signature_scan_active, so nested real imports never re-scan their subtree,(library ...)forms, reusing Overhaul import loading semantics #203'sresolve_existing_import_path/3,current_working_dir/1, andensure_metta_ext/2so relative resolution stays identical,import!.The prescan in #201 was pulled as "more trouble than it's worth". This avoids the three things that made that costly: it scans once instead of per file, it parses only instead of compiling, and it never evaluates an import expression to compute a path. After the change, #203's late-registration warning correctly stays quiet for the fixed cases and fires only for genuinely dynamic import paths, so the warning test now uses a computed path.
Verification
examples/imports/import_order/using thetestbuiltin.test.shpasses across the exercised examples and the Python tests pass.The change is one commit and touches
src/filereader.plplus the example and test fixtures.