452 lines
15 KiB
Markdown
452 lines
15 KiB
Markdown
# PBS Manifest, Module, Stdlib, and SDK Resolution Specification
|
|
|
|
Status: Draft v2 (Normative)
|
|
Applies to: `prometeu.json`, project and module terminology, workspace dependency resolution, stdlib selection, reserved stdlib projects, interface-module loading, and compile-time SDK metadata
|
|
|
|
## 1. Purpose
|
|
|
|
This document defines the normative compile-time model for:
|
|
|
|
- project manifests,
|
|
- project and module identity,
|
|
- import resolution,
|
|
- stdlib selection,
|
|
- reserved stdlib project spaces,
|
|
- stdlib interface modules,
|
|
- and the compile-time lifecycle of SDK host-binding metadata.
|
|
|
|
This document is the authority for how the compiler discovers and loads:
|
|
|
|
- ordinary project modules,
|
|
- reserved stdlib modules such as `@sdk:gfx`,
|
|
- and compile-time-only host-binding metadata attached to those reserved modules.
|
|
|
|
This document does not define runtime load behavior.
|
|
PBX host-binding emission and loader-side syscall resolution are defined by the Host ABI Binding and Loader Resolution Specification.
|
|
|
|
## 2. Scope
|
|
|
|
This document defines:
|
|
|
|
- the role of `language` in `prometeu.json`,
|
|
- the role of `stdlib` in `prometeu.json`,
|
|
- the distinction between projects, modules, and imports,
|
|
- the distinction between ordinary project dependencies and the stdlib environment,
|
|
- root-project ownership of the effective stdlib line of a build,
|
|
- reserved project spaces such as `@sdk:*` and `@core:*`,
|
|
- the source model for stdlib interface modules,
|
|
- the compile-time role of reserved attributes such as `[Host(...)]`.
|
|
|
|
This document does not define:
|
|
|
|
- PBX binary layout,
|
|
- loader-side syscall resolution,
|
|
- cartridge capability policy,
|
|
- package registry protocol details,
|
|
- runtime reflection over attributes.
|
|
|
|
## 3. Core Terms
|
|
|
|
### 3.1 Project
|
|
|
|
A project is the unit described by `prometeu.json`.
|
|
|
|
Rules:
|
|
|
|
- A project has a `name`, `version`, `language`, `stdlib`, and `dependencies`.
|
|
- A project is the unit resolved by the workspace dependency graph.
|
|
- A project is the unit selected by a dependency declaration.
|
|
- A project is the unit published and versioned by ordinary dependency resolution.
|
|
- A project contains one or more modules.
|
|
|
|
### 3.2 Module
|
|
|
|
A module is the unit of source import inside a project.
|
|
|
|
Rules:
|
|
|
|
- Every `.pbs` source file belongs to exactly one module.
|
|
- Every module belongs to exactly one project.
|
|
- Imports select modules, not whole projects.
|
|
- A module is addressed by a project name plus a module path.
|
|
|
|
### 3.3 Canonical module address
|
|
|
|
The canonical PBS module address format is:
|
|
|
|
```text
|
|
@project:path/to/module
|
|
```
|
|
|
|
Rules:
|
|
|
|
- `project` identifies the owning project space.
|
|
- `path/to/module` identifies the module path inside that project.
|
|
- Module path segments are directory-style segments separated by `/`.
|
|
- The syntax is Java-like in organization and JavaScript-like in import surface.
|
|
|
|
Examples:
|
|
|
|
- `@game:player/state`
|
|
- `@physics:collision/shapes`
|
|
- `@sdk:gfx`
|
|
- `@core:math/vector`
|
|
|
|
### 3.4 Reserved project spaces
|
|
|
|
The following project spaces are reserved:
|
|
|
|
- `@sdk:*`
|
|
- `@core:*`
|
|
|
|
Rules:
|
|
|
|
- Reserved project spaces belong to the selected stdlib environment.
|
|
- Ordinary user-authored projects MUST NOT publish modules into reserved project spaces.
|
|
- Ordinary dependency resolution MUST NOT satisfy `@sdk:*` or `@core:*` imports from user projects.
|
|
- Reserved project spaces are resolved only from the selected stdlib environment.
|
|
|
|
## 4. `prometeu.json`
|
|
|
|
### 4.1 Required fields
|
|
|
|
The manifest format relevant to this document is:
|
|
|
|
```json
|
|
{
|
|
"name": "main",
|
|
"version": "1.0.0",
|
|
"language": "pbs",
|
|
"stdlib": "1",
|
|
"dependencies": [
|
|
{ "name": "dep1", "version": "1.0.0" }
|
|
]
|
|
}
|
|
```
|
|
|
|
Rules:
|
|
|
|
- `name` identifies the project.
|
|
- `version` identifies the project version.
|
|
- `language` identifies the frontend language.
|
|
- `stdlib` identifies the selected stdlib major line.
|
|
- `dependencies` declare ordinary project dependencies only.
|
|
|
|
### 4.2 `language`
|
|
|
|
Rules:
|
|
|
|
- `language` selects the compiler frontend.
|
|
- All projects in one resolved workspace MUST use the same `language`.
|
|
- Unknown `language` values are compile-time errors.
|
|
|
|
### 4.3 `stdlib`
|
|
|
|
Rules:
|
|
|
|
- `stdlib` is required in every manifest.
|
|
- `stdlib` uses major-only version syntax in v1.
|
|
- The manifest surface for `stdlib` is a string containing a positive decimal integer.
|
|
- Examples of valid values: `"1"`, `"2"`.
|
|
- Examples of invalid values: `"0"`, `"01"`, `"1.0"`, `"v1"`, `""`.
|
|
- Implementations SHOULD normalize `stdlib` internally to an integer major version.
|
|
|
|
Diagnostics:
|
|
|
|
- Missing `stdlib` is a manifest error.
|
|
- Invalid major-only format is a manifest error.
|
|
|
|
## 5. Ordinary Dependencies vs Stdlib Environment
|
|
|
|
### 5.1 Ordinary dependencies
|
|
|
|
Rules:
|
|
|
|
- `dependencies` model ordinary project relationships only.
|
|
- A dependency may be local or registry-based according to the compiler's dependency resolver.
|
|
- Dependencies contribute source projects, modules, and project-graph edges.
|
|
- `dependencies` do not declare stdlib projects.
|
|
|
|
### 5.2 Stdlib environment
|
|
|
|
Rules:
|
|
|
|
- The stdlib environment is not declared through `dependencies`.
|
|
- The stdlib environment is selected through `stdlib`.
|
|
- `@sdk:*` and `@core:*` imports resolve against the stdlib environment selected for the build.
|
|
- The presence of stdlib modules does not imply automatic visibility in source.
|
|
- User code MUST still import stdlib modules explicitly through ordinary import syntax.
|
|
|
|
Example:
|
|
|
|
```pbs
|
|
import { Gfx, color } from @sdk:gfx;
|
|
|
|
let c: color = color.red;
|
|
Gfx.draw_pixel(1, 1, c);
|
|
```
|
|
|
|
Rules:
|
|
|
|
- `Gfx` is not implicitly in scope.
|
|
- `Gfx` becomes visible only through `import`.
|
|
- The compiler accepts that import because the selected stdlib environment exposes `@sdk:gfx`.
|
|
|
|
## 6. Effective Stdlib of the Build
|
|
|
|
The root project owns the effective stdlib line of the build.
|
|
|
|
Rules:
|
|
|
|
- The resolved workspace has exactly one effective stdlib major version.
|
|
- The effective stdlib major version is taken from the root project manifest.
|
|
- All projects in the workspace compile under that same effective stdlib line.
|
|
- Dependency projects do not activate separate stdlib environments for themselves.
|
|
|
|
This means:
|
|
|
|
- `stdlib` on a dependency is a compatibility declaration,
|
|
- not an instruction to switch the compiler into another stdlib mode for that dependency.
|
|
|
|
## 7. Stdlib Compatibility Across Dependency Projects
|
|
|
|
Let:
|
|
|
|
- `R` be the root project's `stdlib` major,
|
|
- `D` be a dependency project's `stdlib` major.
|
|
|
|
Rules:
|
|
|
|
- If `D > R`, dependency resolution MUST fail with a deterministic compile-time error.
|
|
- If `D <= R`, dependency resolution MAY proceed.
|
|
- `D <= R` does not guarantee semantic compatibility of all APIs used by the dependency; it only means the dependency is not asking for a newer stdlib line than the root selected.
|
|
|
|
Rationale:
|
|
|
|
- the build target is chosen by the root project,
|
|
- dependency projects may target the same or an older stdlib line,
|
|
- dependency projects must not force the build to silently adopt a newer stdlib than the root requested.
|
|
|
|
Example:
|
|
|
|
- root `stdlib = "1"`, dependency `stdlib = "2"`: error.
|
|
- root `stdlib = "2"`, dependency `stdlib = "1"`: allowed.
|
|
- root `stdlib = "1"`, dependency `stdlib = "1"`: allowed.
|
|
|
|
## 8. Import Resolution
|
|
|
|
### 8.1 Resolution sources
|
|
|
|
The compiler resolves imports against exactly two sources:
|
|
|
|
1. the selected stdlib environment,
|
|
2. the resolved ordinary project dependency graph.
|
|
|
|
Rules:
|
|
|
|
- `@sdk:*` and `@core:*` are resolved only against the stdlib environment,
|
|
- all other `@project:*` imports are resolved only against the ordinary dependency graph,
|
|
- there is no fallback from reserved stdlib resolution to ordinary dependencies,
|
|
- there is no fallback from ordinary dependency resolution to reserved stdlib spaces.
|
|
|
|
### 8.2 Resolution algorithm
|
|
|
|
For an import:
|
|
|
|
```pbs
|
|
import { X } from @project:path/to/module;
|
|
```
|
|
|
|
the compiler MUST:
|
|
|
|
1. parse the project space and module path,
|
|
2. determine whether the project space is reserved,
|
|
3. if reserved, resolve the module from the selected stdlib environment,
|
|
4. otherwise, resolve the module from the root project or its dependency graph,
|
|
5. load the target module,
|
|
6. resolve the requested exported names from that module.
|
|
|
|
Failure at any step is a deterministic compile-time error.
|
|
|
|
## 9. Stdlib Interface Modules
|
|
|
|
### 9.1 Interface-module model
|
|
|
|
The selected stdlib environment MUST provide its modules as PBS-like interface modules.
|
|
|
|
Rules:
|
|
|
|
- Stdlib modules are `.pbs` modules loaded by the compiler.
|
|
- Stdlib interface modules use the same parser surface as ordinary PBS modules.
|
|
- Stdlib interface modules are interpreted in interface-module mode.
|
|
- Interface-module mode is non-executable and compile-time only.
|
|
- Interface modules participate in import resolution and type checking.
|
|
- Interface modules do not emit executable bytecode by themselves.
|
|
|
|
### 9.2 Allowed role
|
|
|
|
At minimum, an interface module may provide:
|
|
|
|
- exported names,
|
|
- types,
|
|
- enums,
|
|
- host owners,
|
|
- method signatures,
|
|
- compile-time metadata such as canonical host-binding attributes.
|
|
|
|
This list fixes the currently required declarative role of interface modules, but does not by itself freeze the final complete declaration set allowed in interface-module mode.
|
|
|
|
An interface module is not runtime code.
|
|
|
|
### 9.3 Interface-module restrictions
|
|
|
|
At minimum, an interface module MUST remain declarative.
|
|
|
|
Rules:
|
|
|
|
- Interface modules MUST NOT contain top-level executable statements.
|
|
- Interface modules MUST NOT require runtime initialization.
|
|
- Interface modules MUST NOT introduce executable method bodies that would emit bytecode.
|
|
- `declare host` is permitted only in reserved stdlib/toolchain interface modules.
|
|
- Reserved attributes such as `[Host(...)]` are permitted only where another specification explicitly allows them.
|
|
|
|
### 9.4 Example interface module
|
|
|
|
Illustrative stdlib interface module:
|
|
|
|
```pbs
|
|
declare enum color(red, green, blue);
|
|
|
|
declare host Gfx {
|
|
[Host(module = "gfx", name = "draw_pixel", version = 1)]
|
|
fn draw_pixel(x: int, y: int, c: color);
|
|
}
|
|
```
|
|
|
|
Rules:
|
|
|
|
- This module is valid only in a reserved stdlib/interface-module context.
|
|
- It contributes compile-time symbols and metadata.
|
|
- It does not produce executable bytecode by itself.
|
|
|
|
## 10. Compiler Loading of the Stdlib Environment
|
|
|
|
The compiler loads the stdlib environment from the stdlib line selected by the root project.
|
|
|
|
Required model:
|
|
|
|
1. Read the root `prometeu.json`.
|
|
2. Determine the effective stdlib major line.
|
|
3. Mount or select the matching stdlib environment.
|
|
4. Expose its reserved project spaces such as `@sdk:*` and `@core:*`.
|
|
5. Load interface modules from that environment on demand during import resolution.
|
|
6. Parse those modules with the ordinary PBS parser.
|
|
7. Validate them under interface-module semantic rules.
|
|
8. Populate the compiler's symbol graph from their exported declarations and attributes.
|
|
|
|
Rules:
|
|
|
|
- The compiler MUST behave as if it were loading real modules, not hardcoded symbol tables.
|
|
- The physical storage format of the stdlib environment is an implementation detail.
|
|
- The compiler MAY load the stdlib environment from disk, embedded resources, a virtual filesystem, or another implementation-defined source with equivalent behavior.
|
|
- For the Studio PBS frontend, embedding stdlib interface modules under frontend `resources` is a valid implementation strategy.
|
|
|
|
## 11. Reserved Attributes and Metadata Lifecycle
|
|
|
|
### 11.1 General rule
|
|
|
|
Attributes are compile-time metadata, not runtime objects.
|
|
|
|
Rules:
|
|
|
|
- Attributes are parsed as part of the source module.
|
|
- Attributes participate in declaration validation and compiler metadata extraction.
|
|
- Attributes are not exported as ordinary values, types, or runtime-reflectable objects.
|
|
- Attributes do not automatically survive into bytecode, PBX, or runtime metadata.
|
|
|
|
### 11.2 `Host` attribute
|
|
|
|
The canonical reserved host-binding attribute is:
|
|
|
|
```pbs
|
|
[Host(module = "gfx", name = "draw_pixel", version = 1)]
|
|
```
|
|
|
|
Rules:
|
|
|
|
- `Host` is valid only on a host method signature declared directly inside a reserved stdlib/interface-module `declare host` body.
|
|
- `Host` provides the canonical host primitive identity used by compiler lowering.
|
|
- `module` and `name` are string literals.
|
|
- `version` is a positive integer literal.
|
|
- The attribute surface itself is compile-time only.
|
|
|
|
### 11.3 Lowering effect
|
|
|
|
Although the attribute syntax itself is compile-time only, its semantic effect may be lowered.
|
|
|
|
Rules:
|
|
|
|
- The compiler consumes `Host` metadata while resolving host-backed SDK members.
|
|
- The compiler uses that metadata to emit runtime-facing host-binding declarations as defined by the Host ABI Binding specification.
|
|
- The compiler does not export the raw `[Host(...)]` syntax into runtime as a source-level attribute object.
|
|
|
|
In other words:
|
|
|
|
- the attribute is compile-time metadata,
|
|
- the lowered host-binding declaration is runtime-facing artifact metadata,
|
|
- they are not the same thing.
|
|
|
|
## 12. Relationship to `declare host`
|
|
|
|
Rules:
|
|
|
|
- `declare host` remains reserved to SDK/toolchain-controlled modules.
|
|
- Ordinary user-authored project modules do not declare canonical host bindings directly.
|
|
- User code consumes SDK exports through normal imports.
|
|
- SDK-facing surfaces such as `Gfx.draw_pixel(...)` are resolved by the compiler against the selected stdlib environment.
|
|
- Canonical host identity comes from reserved host-binding metadata such as `[Host(...)]`, not from the source spelling of the imported owner.
|
|
|
|
## 13. Project Publication and Distribution
|
|
|
|
Rules:
|
|
|
|
- Ordinary publication and dependency resolution operate at project granularity.
|
|
- A published project version contains one or more modules.
|
|
- Imports consume modules from a resolved project.
|
|
- The stdlib environment is distributed separately from ordinary project dependencies.
|
|
- The stdlib environment is selected by `stdlib`, not by `dependencies`.
|
|
|
|
## 14. Non-Goals
|
|
|
|
- Making stdlib modules implicitly visible without `import`.
|
|
- Treating the stdlib as an ordinary dependency in the workspace graph.
|
|
- Allowing each dependency project to activate its own stdlib line.
|
|
- Hardcoding stdlib symbols directly into the compiler without a module model.
|
|
- Runtime reflection over source-level attributes.
|
|
|
|
## 15. Open Items Deferred
|
|
|
|
The following remain intentionally deferred:
|
|
|
|
1. Exact on-disk distribution format of stdlib environment packs.
|
|
2. Registry/publication protocol details for ordinary projects.
|
|
3. Final diagnostics catalog for all import-resolution failures.
|
|
4. Full list of declarations allowed inside interface modules beyond the already-fixed reserved host surfaces.
|
|
|
|
## 16. Current Decision Summary
|
|
|
|
The current PBS design direction is:
|
|
|
|
1. `prometeu.json` declares `language` and `stdlib` separately.
|
|
2. A project is the unit described by `prometeu.json` and selected by `dependencies`.
|
|
3. A module is the unit selected by `import`.
|
|
4. Canonical module addresses use `@project:path/to/module`.
|
|
5. `@sdk:*` and `@core:*` are reserved stdlib project spaces.
|
|
6. The root project selects the effective stdlib line for the whole build.
|
|
7. Dependency projects with a higher stdlib requirement than the root are rejected.
|
|
8. Stdlib modules are loaded as PBS-like interface modules, not as ordinary dependencies.
|
|
9. Interface modules are compile-time-only and do not emit executable bytecode.
|
|
10. `declare host` remains reserved to stdlib/toolchain interface modules.
|
|
11. Reserved attributes such as `[Host(...)]` are compile-time metadata, not runtime objects.
|
|
12. The compiler consumes `Host` metadata to produce runtime-facing host-binding artifacts defined elsewhere.
|