feat(pkg): package manager — fetch + MVS resolve + namespace registration (#63)
Implements the v1 direction decided in the RFC as a set of `x` subcommands
plus a small, contained compiler change.
* URL-as-identity, no registry — a dependency is named by its git import
path and a `git tag vX.Y.Z` publishes a version.
* Minimum Version Selection — a `require` is a minimum; the resolver picks
the greatest required minimum per module, then the reachable closure at
those versions. Deterministic, no SAT solver (tools/x/pkg.ludic).
* Content-addressed global store + per-project links — packages live once in
~/.ludic/store keyed by a content hash; each project links them under
ludic_modules/. package.ludic (manifest) + package.lock.ludic (lock).
* Namespace registration for source packages via a module-root import
fallback in the compiler: do_import resolves a non-local, non-absolute
import under $LUDIC_MODULES (default ludic_modules/), so a fetched
package's Ludic compiles into the consumer the way the built-in stdlib
does. Collisions and missing prebuilt targets are hard errors.
Commands: x add / x get / x update / x verify / x vendor. New hermetic suite
`x test-pkg` (stands up throwaway git repos, offline) is gated inside `x test`.
Existing programs compile byte-for-byte identically (the import fallback only
fires when the local path is absent); the C-free bootstrap fixpoint holds and
the seed is regenerated. Full suite: 87 passed, package suite: 12 passed.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
237e13c95e
commit
2c44bae496
10 changed files with 17409 additions and 16387 deletions
|
|
@ -573,12 +573,26 @@ function parse_test() -> Node {
|
|||
return n
|
||||
}
|
||||
|
||||
# lex and parse an imported fragment into `prog`, saving/restoring lexer state
|
||||
# lex and parse an imported fragment into `prog`, saving/restoring lexer state.
|
||||
#
|
||||
# An import is resolved first relative to the importing file (the historical
|
||||
# behaviour). When that fails and the spec is not absolute, it is looked up
|
||||
# under the package module root — $LUDIC_MODULES, default "ludic_modules" — so a
|
||||
# fetched source package resolves by its import path, e.g.
|
||||
# import "git.workshopsoft.io/user/pkg/foo.ludic"
|
||||
# materialised by `x get` at ludic_modules/git.workshopsoft.io/user/pkg/foo.ludic.
|
||||
# The fallback only fires when the local path does not exist, so every existing
|
||||
# import resolves exactly as before (the emitted IR is byte-identical).
|
||||
function do_import(rel: pointer) -> void {
|
||||
let full = path_join(cur_dir, rel)
|
||||
var full = path_join(cur_dir, rel)
|
||||
var src = read_file(full)
|
||||
if (src == null) and (rel[0] != 47) {
|
||||
let cand = ensure_slash(getenv_or("LUDIC_MODULES", "ludic_modules")) + rel
|
||||
let s2 = read_file(cand)
|
||||
if (s2 != null) { full = cand; src = s2 }
|
||||
}
|
||||
if already_loaded(full) { return }
|
||||
push(loaded_paths, full)
|
||||
let src = read_file(full)
|
||||
if (src == null) { perr(`cannot open import {full}`) }
|
||||
let saved_toks = toks; let saved_pi = pi; let saved_dir = cur_dir
|
||||
cur_dir = dir_of(full)
|
||||
|
|
|
|||
32818
selfhost/ludicc.seed.ll
32818
selfhost/ludicc.seed.ll
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue