diff --git a/CLAUDE.md b/CLAUDE.md index 60898b2..78125cf 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -572,8 +572,15 @@ Wiring a new bundling step: | `current/CHECKPOINT-LANG.md` | **Active** LANG progress tracker. Update after every step. | | `current/PLAN-ERR.md` | **Active** ERR implementation plan (`!` errors, `try` / `catch` / `or` / `onfail`, return traces). | | `current/CHECKPOINT-ERR.md` | **Active** ERR progress tracker. Update after every step. | +| `current/PLAN-STDLIB.md` | **Active** STDLIB restructure plan (alias carry rule + std/ffi/math layout). Progress tracked in its `## Status` section — no separate checkpoint file. | | `implementation_plan.md` | Archive of completed work (closures, protocols, etc.). Do not pick up tasks from here. | | `readme.md` | User-facing language overview — **maintained**. Update it whenever a user-facing sx change lands (new/changed syntax, semantics, gating diagnostics, language behavior), per the docs-track-changes rule. | | `CLAUDE.md` | This file. Session instructions. | +| `library/modules/std.sx` | The prelude (print/format/List/string ops/Context/Allocator) + the namespace tail (`mem`/`xml`/`log` carried to flat importers). | +| `library/modules/std/` | Stdlib modules: mem (allocators), fs, process, socket, json, cli, hash, xml, log, trace, test. Import directly until they join the tail. | +| `library/modules/ffi/` | FFI bindings: objc, objc_block, sdl3, opengl, raylib, stb, stb_truetype, wasm. | +| `library/modules/math/` | scalar / vector2 / matrix44 — one spelling: `#import "modules/math"` (directory import). | +| `library/modules/build.sx` | `BuildOptions` compile-time build DSL. See "Bundling lives in sx" above. | | `library/modules/platform/bundle.sx` | sx-side `.app` / `.apk` bundler. See "Bundling lives in sx" above. | | `library/modules/std/fs.sx`, `library/modules/std/process.sx` | POSIX stdlib for the bundler + general consumer use. | +| `tests/fixtures/` | Test-only import fixtures (testpkg/, test_c.sx) — resolve CWD-relative from the repo root, not via the stdlib search path. | diff --git a/readme.md b/readme.md index b5d7146..c37185c 100644 --- a/readme.md +++ b/readme.md @@ -441,6 +441,26 @@ struct / pack fn / protocol body is instantiated in the module that defines it, e.g. `List(T).append`'s `alloc: Allocator` is visible there regardless of the call site.) +**Namespace aliases carry one level.** A namespaced import is an ordinary +declaration, and flat-importing the module that declares it makes the alias +usable in the importer — there is no `pub` keyword. The stdlib prelude uses +exactly this: `#import "modules/std.sx"` gives every bare prelude name +(`print`, `List`, `Context`, …) plus the carried namespaces of std's tail: + +```sx +#import "modules/std.sx"; + +main :: () { + gpa := mem.GPA.init(); // mem :: #import — carried from std.sx + log.warn("count = {}", 3); + s := xml.escape(""); +} +``` + +Carried aliases follow declaration rules: an own declaration shadows a carried +alias, two flat imports carrying the same alias make its use ambiguous, and +carry does not chain through a second flat hop. + ### Implicit Context Every program gets an implicit `context` with a default allocator: diff --git a/specs.md b/specs.md index c9b5963..4f30931 100644 --- a/specs.md +++ b/specs.md @@ -2479,7 +2479,7 @@ The `#import` directive brings declarations from another `.sx` file or directory **Flat import** — splices all declarations from the imported file into the current scope: ```sx -#import "modules/std/math.sx"; +#import "modules/std/fs.sx"; ``` **Namespaced import** — wraps all declarations under a namespace name: @@ -2502,10 +2502,58 @@ Namespaced declarations are accessed with dot notation: std.print("hello"); ``` +### Namespace Alias Carry + +A namespaced import is an ordinary declaration of the alias name. There is no +`pub` keyword: flat-importing a module carries the module's namespace aliases +**one level** — a file's aliases are usable by its DIRECT flat importers, with +declaration-like collision semantics. + +```sx +// facade.sx +r :: #import "rich.sx"; // an ordinary declaration of `r` + +// main.sx +#import "facade.sx"; // flat import carries facade's aliases + +main :: () { + r.helper(); // plain fn through the carried alias + t := r.Thing.init(); // static method + x : r.Thing = t; // type annotation + n := r.LIMIT; // module const + c := r.Color.green; // enum variant + b := r.Box(s64).{ item = 3 }; // generic struct head +} +``` + +Every qualified shape resolves through a carried alias exactly as through a +directly-declared one: function calls, `alias.Type.method()`, type +annotations, enum variants, module constants, and generic struct heads. + +Collision rules mirror ordinary declarations: + +- **Own wins** — a file's own declaration of a name (including its own + `ns :: #import`) shadows any same-named alias carried from a flat import. +- **Ambiguity** — two direct flat imports each carrying a distinct alias of + the same name make a bare use of that alias an error; declare the alias + locally to disambiguate. +- **One level only** — carry does not chain: a flat import of a flat import + does not surface the inner file's aliases. (The bare `alias.fn()` call path + does not yet enforce this gate — issue 0114 tracks the tightening.) + +`#import c { ... }` aliases (`tc :: #import c { ... }`) carry the same way. + ### Import Resolution - Imports are resolved after parsing and before code generation. -- Paths are first resolved relative to the directory of the file containing the `#import`. If not found, they fall back to the working directory (cwd). This allows modules in subdirectories to import shared modules using the same paths as the root file. +- Paths are resolved in three tiers, first hit wins: + 1. relative to the directory of the file containing the `#import`; + 2. relative to the working directory (cwd); + 3. relative to each stdlib search path — the `library/` directory discovered + from the compiler binary's location (dev: `zig-out/bin/sx` → + `/library`; install: `/library`), overridable with the + `SX_STDLIB_PATH` environment variable. This is how + `#import "modules/std.sx"` resolves from any project. - If the path resolves to a file, it is imported directly. If it resolves to a directory, all `.sx` files in that directory are aggregated. - Nested imports are supported (imported files may themselves contain `#import`). - Circular imports are detected and silently skipped (each file is imported at most once). @@ -2529,22 +2577,45 @@ Functions within a namespaced import can call each other without the namespace p ### Example ```sx -// modules/std/math.sx -mul :: (base: $T, exp: T) -> T { base * exp; } - -// modules/std/std.sx -out :: (str: string) -> void #builtin; +// modules/std/json.sx +parse :: (text: string) -> ?JsonValue { ... } // main.sx std :: #import "modules/std.sx"; -#import "modules/std/math.sx"; +#import "modules/std/json.sx"; main :: () -> s32 { - std.out("hello there"); - mul(5, 2); + std.print("hello there\n"); + v := parse("{}"); + 0 } ``` +### Standard Library Layout + +``` +modules/std.sx the prelude — print/format, string ops (concat, substr, + path_join, ...), List(T), Context + push, the Allocator + protocol; plus the namespace tail: + mem / xml / log :: #import "modules/std/.sx" +modules/std/ mem.sx (CAllocator, GPA, Arena, TrackingAllocator), + fs.sx, process.sx, socket.sx, json.sx, cli.sx, hash.sx, + xml.sx, log.sx, trace.sx, test.sx +modules/ffi/ objc.sx, objc_block.sx, sdl3.sx, opengl.sx, raylib.sx, + stb.sx, stb_truetype.sx, wasm.sx +modules/math/ scalar.sx, vector2.sx, matrix44.sx — import the + directory: #import "modules/math" +modules/build.sx BuildOptions — compile-time build configuration (§10.5) +modules/platform/ bundle.sx, uikit.sx, android.sx, sdl3.sx, ... — + windowing/bundling backends +modules/gpu/, modules/ui/ GPU protocol + retained UI toolkit +``` + +`#import "modules/std.sx"` gives every prelude name bare, plus `mem.GPA`, +`xml.escape`, `log.warn`, ... through the carried namespace tail (see +Namespace Alias Carry). The remaining `std/` modules are imported directly +(`#import "modules/std/json.sx"`) until they join the tail. + --- ## 10. CLI & Cross-Compilation