docs: alias carry semantics + stdlib layout (step 4)

- specs §9: Namespace Alias Carry section (one level, own-wins, ambiguity,
  no chaining — 0114 noted for the still-ungated bare-call path), the
  three-tier import resolution (file dir -> cwd -> stdlib search path /
  SX_STDLIB_PATH), a Standard Library Layout section, real-layout examples
  replacing the stale modules/std/std.sx ones.
- readme: carry-rule teaser with the std namespace-tail example (verified
  to compile and run as written).
- CLAUDE.md: file-roles rows for std.sx/std//ffi//math//build.sx,
  tests/fixtures, and the PLAN-STDLIB tracker.
This commit is contained in:
agra
2026-06-11 08:46:17 +03:00
parent 698f75d79a
commit b8748aee16
3 changed files with 108 additions and 10 deletions

View File

@@ -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. |

View File

@@ -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("<a & b>");
}
```
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:

View File

@@ -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` →
`<repo>/library`; install: `<prefix>/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/<m>.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