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:
@@ -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. |
|
||||
|
||||
20
readme.md
20
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("<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:
|
||||
|
||||
91
specs.md
91
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` →
|
||||
`<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
|
||||
|
||||
Reference in New Issue
Block a user