add PBS docs
This commit is contained in:
parent
07a6742cdc
commit
b3e5335deb
@ -6,7 +6,7 @@ This directory contains the technical documentation and specifications for the P
|
||||
|
||||
### 📜 [Specifications (Specs)](./specs)
|
||||
Detailed documentation on system architecture, cartridge format, VM instruction set, and more.
|
||||
- [Topic Index](./specs/topics/table-of-contents.md)
|
||||
- [Topic Index](specs/hardware/topics/table-of-contents.md)
|
||||
|
||||
### 🐞 [Debugger](./debugger)
|
||||
Documentation on debugging tools and how to integrate new tools into the ecosystem.
|
||||
|
||||
359
docs/specs/pbs/PBS - Canonical Addenda.md
Normal file
359
docs/specs/pbs/PBS - Canonical Addenda.md
Normal file
@ -0,0 +1,359 @@
|
||||
# PBS v0 Canonical Addenda
|
||||
|
||||
> **Purpose:** eliminate ambiguity for Junie and for golden tests.
|
||||
>
|
||||
> This document is **normative** for PBS Frontend v0 and complements:
|
||||
>
|
||||
> * **PBS Frontend Spec v0 — Implementer Edition**
|
||||
> * **Junie PR Plan**
|
||||
>
|
||||
> These addenda define:
|
||||
>
|
||||
> 1. operator precedence & associativity
|
||||
> 2. canonical AST JSON shape (v0)
|
||||
> 3. canonical diagnostic codes (v0)
|
||||
|
||||
---
|
||||
|
||||
## 1) Operator Precedence and Associativity (v0)
|
||||
|
||||
### 1.1 Guiding rule
|
||||
|
||||
PBS v0 prioritizes **minimal ambiguity** and **easy parsing**.
|
||||
|
||||
* Most operators are **left-associative**.
|
||||
* Assignment is **not** an expression in v0 (no `=` operator expressions).
|
||||
* Member access and indexing are not part of v0 surface syntax unless already defined elsewhere.
|
||||
|
||||
### 1.2 Precedence table
|
||||
|
||||
From **highest** to **lowest**:
|
||||
|
||||
1. **Primary**
|
||||
|
||||
* literals (`10`, `3.14`, `"text"`, `none`, `some(x)`, `ok(x)`, `err(e)`)
|
||||
* identifiers (`foo`)
|
||||
* parenthesized expression (`(expr)`)
|
||||
* block expression (`{ ... }`) (when allowed as `Expr`)
|
||||
|
||||
2. **Call** (left-associative)
|
||||
|
||||
* `callee(arg1, arg2, ...)`
|
||||
|
||||
3. **Unary prefix** (right-associative)
|
||||
|
||||
* `-expr`
|
||||
* `!expr`
|
||||
* `as` casts are **not unary**; see level 6.
|
||||
|
||||
4. **Multiplicative** (left-associative)
|
||||
|
||||
* `*`, `/`, `%`
|
||||
|
||||
5. **Additive** (left-associative)
|
||||
|
||||
* `+`, `-`
|
||||
|
||||
6. **Cast** (left-associative)
|
||||
|
||||
* `expr as Type`
|
||||
|
||||
7. **Comparison** (non-associative)
|
||||
|
||||
* `<`, `<=`, `>`, `>=`
|
||||
|
||||
8. **Equality** (non-associative)
|
||||
|
||||
* `==`, `!=`
|
||||
|
||||
9. **Logical AND** (left-associative)
|
||||
|
||||
* `&&`
|
||||
|
||||
10. **Logical OR** (left-associative)
|
||||
|
||||
* `||`
|
||||
|
||||
11. **Control expressions** (special)
|
||||
|
||||
* `if ... { ... } else { ... }` (expression form only if your v0 allows it; otherwise statement)
|
||||
* `when { ... }` (expression)
|
||||
|
||||
### 1.3 Non-associative rule
|
||||
|
||||
Comparison and equality are **non-associative**:
|
||||
|
||||
* `a < b < c` is an error
|
||||
* `a == b == c` is an error
|
||||
|
||||
Diagnostic: `E_PARSE_NON_ASSOC`.
|
||||
|
||||
### 1.4 Notes on `when`
|
||||
|
||||
`when` binds weaker than all binary operators.
|
||||
|
||||
Example:
|
||||
|
||||
```pbs
|
||||
let x = a + b when { ... };
|
||||
```
|
||||
|
||||
Parses as:
|
||||
|
||||
```
|
||||
let x = (a + b) when { ... };
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2) Canonical AST JSON (v0)
|
||||
|
||||
### 2.1 Canonicalization goals
|
||||
|
||||
Canonical AST JSON is used for:
|
||||
|
||||
* golden tests
|
||||
* frontend determinism validation
|
||||
* diff-friendly debugging
|
||||
|
||||
Rules:
|
||||
|
||||
* JSON keys are **stable** and **ordered** (when writing JSON)
|
||||
* All nodes include `kind` and `span`
|
||||
* Spans are byte offsets into the file content
|
||||
|
||||
### 2.2 Span encoding
|
||||
|
||||
```json
|
||||
{"file":"main.pbs","start":12,"end":18}
|
||||
```
|
||||
|
||||
Where:
|
||||
|
||||
* `start` is inclusive
|
||||
* `end` is exclusive
|
||||
|
||||
### 2.3 Root
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "File",
|
||||
"span": {"file":"...","start":0,"end":123},
|
||||
"imports": [ ... ],
|
||||
"decls": [ ... ]
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 Import node
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "Import",
|
||||
"span": {"file":"...","start":0,"end":20},
|
||||
"spec": {"kind":"ImportSpec","path":["Foo","Bar"]},
|
||||
"from": "./lib.pbs"
|
||||
}
|
||||
```
|
||||
|
||||
`ImportSpec.path` is an array of identifiers.
|
||||
|
||||
### 2.5 Declarations
|
||||
|
||||
#### 2.5.1 Service
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "ServiceDecl",
|
||||
"span": {"file":"...","start":0,"end":50},
|
||||
"vis": "pub",
|
||||
"name": "Audio",
|
||||
"extends": null,
|
||||
"members": [ ... ]
|
||||
}
|
||||
```
|
||||
|
||||
A service member (method signature only in v0):
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "ServiceFnSig",
|
||||
"span": {"file":"...","start":0,"end":10},
|
||||
"name": "play",
|
||||
"params": [ {"name":"sound","ty": {"kind":"TypeName","name":"Sound"}} ],
|
||||
"ret": {"kind":"TypeName","name":"void"}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.5.2 Function
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "FnDecl",
|
||||
"span": {"file":"...","start":0,"end":80},
|
||||
"name": "main",
|
||||
"params": [],
|
||||
"ret": null,
|
||||
"else": null,
|
||||
"body": {"kind":"Block", ... }
|
||||
}
|
||||
```
|
||||
|
||||
#### 2.5.3 TypeDecl (struct/contract/error)
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "TypeDecl",
|
||||
"span": {"file":"...","start":0,"end":100},
|
||||
"vis": "pub",
|
||||
"typeKind": "struct",
|
||||
"name": "Vector",
|
||||
"body": {"kind":"TypeBody","members":[ ... ]}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.6 Blocks and statements
|
||||
|
||||
Block:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "Block",
|
||||
"span": {"file":"...","start":0,"end":20},
|
||||
"stmts": [ ... ],
|
||||
"tail": null
|
||||
}
|
||||
```
|
||||
|
||||
* `stmts` are statements.
|
||||
* `tail` is an optional final expression (only if your parser supports expression blocks).
|
||||
|
||||
Statement kinds (v0 minimum):
|
||||
|
||||
* `LetStmt`
|
||||
* `ExprStmt`
|
||||
* `ReturnStmt`
|
||||
|
||||
Let:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "LetStmt",
|
||||
"span": {"file":"...","start":0,"end":20},
|
||||
"name": "x",
|
||||
"isMut": false,
|
||||
"ty": null,
|
||||
"init": {"kind":"IntLit", "value": 10, "span": ...}
|
||||
}
|
||||
```
|
||||
|
||||
Return:
|
||||
|
||||
```json
|
||||
{
|
||||
"kind": "ReturnStmt",
|
||||
"span": {"file":"...","start":0,"end":10},
|
||||
"expr": null
|
||||
}
|
||||
```
|
||||
|
||||
### 2.7 Expressions
|
||||
|
||||
All expressions include `kind` and `span`.
|
||||
|
||||
Minimal v0 expression node kinds:
|
||||
|
||||
* `IntLit` `{ value: i64 }`
|
||||
* `FloatLit` `{ value: f64 }`
|
||||
* `BoundedLit` `{ value: u32 }`
|
||||
* `StringLit` `{ value: string }`
|
||||
* `Ident` `{ name: string }`
|
||||
* `Call` `{ callee: Expr, args: Expr[] }`
|
||||
* `Unary` `{ op: "-"|"!", expr: Expr }`
|
||||
* `Binary` `{ op: string, left: Expr, right: Expr }`
|
||||
* `Cast` `{ expr: Expr, ty: TypeRef }`
|
||||
* `IfExpr` `{ cond: Expr, then: Block, els: Block }` (if expression is supported)
|
||||
* `WhenExpr` `{ arms: WhenArm[] }`
|
||||
|
||||
Type references:
|
||||
|
||||
```json
|
||||
{"kind":"TypeName","name":"int"}
|
||||
```
|
||||
|
||||
Generics:
|
||||
|
||||
```json
|
||||
{"kind":"TypeApp","base":"optional","args":[{"kind":"TypeName","name":"int"}]}
|
||||
```
|
||||
|
||||
### 2.8 Canonical JSON ordering
|
||||
|
||||
When writing AST JSON, always order fields as:
|
||||
|
||||
1. `kind`
|
||||
2. `span`
|
||||
3. semantic fields (stable order)
|
||||
|
||||
This makes diffs deterministic.
|
||||
|
||||
---
|
||||
|
||||
## 3) Diagnostic Codes (v0)
|
||||
|
||||
### 3.1 Diagnostic format
|
||||
|
||||
All diagnostics must be serializable to canonical JSON:
|
||||
|
||||
```json
|
||||
{
|
||||
"severity": "error",
|
||||
"code": "E_PARSE_UNEXPECTED_TOKEN",
|
||||
"message": "Unexpected token '}'",
|
||||
"span": {"file":"main.pbs","start":12,"end":13}
|
||||
}
|
||||
```
|
||||
|
||||
Severity is one of: `error`, `warning`.
|
||||
|
||||
### 3.2 Parse/Lex errors (E_PARSE_*)
|
||||
|
||||
* `E_LEX_INVALID_CHAR` — invalid character
|
||||
* `E_LEX_UNTERMINATED_STRING` — string literal not closed
|
||||
* `E_PARSE_UNEXPECTED_TOKEN` — token not expected in current context
|
||||
* `E_PARSE_EXPECTED_TOKEN` — missing required token
|
||||
* `E_PARSE_NON_ASSOC` — chained comparison/equality (non-associative)
|
||||
|
||||
### 3.3 Symbol/Resolve errors (E_RESOLVE_*)
|
||||
|
||||
* `E_RESOLVE_UNDEFINED` — undefined identifier
|
||||
* `E_RESOLVE_DUPLICATE_SYMBOL` — duplicate symbol in same namespace
|
||||
* `E_RESOLVE_NAMESPACE_COLLISION` — name exists in both type and value namespaces
|
||||
* `E_RESOLVE_VISIBILITY` — symbol not visible from this scope/module
|
||||
* `E_RESOLVE_INVALID_IMPORT` — import spec/path invalid
|
||||
|
||||
### 3.4 Type errors (E_TYPE_*)
|
||||
|
||||
* `E_TYPE_MISMATCH` — type mismatch
|
||||
* `E_TYPE_UNKNOWN_TYPE` — unknown type name
|
||||
* `E_TYPE_MUTABILITY` — mutability violation
|
||||
* `E_TYPE_RETURN_PATH` — not all paths return a value
|
||||
* `E_TYPE_INVALID_CAST` — invalid cast
|
||||
|
||||
### 3.5 Lowering errors (E_LOWER_*)
|
||||
|
||||
* `E_LOWER_UNSUPPORTED` — feature not supported in v0 lowering
|
||||
|
||||
### 3.6 Warnings (W_*)
|
||||
|
||||
Warnings are allowed in v0 but should be used sparingly.
|
||||
|
||||
* `W_UNUSED_LET` — unused local binding
|
||||
* `W_SHADOWING` — local shadows another binding
|
||||
|
||||
---
|
||||
|
||||
## Implementation Notes (Non-normative)
|
||||
|
||||
* Keep these addenda in `spec/` in the repo.
|
||||
* Use them to drive golden tests for AST and diagnostics.
|
||||
* If a future change alters canonical AST, bump a version and regenerate goldens deliberately.
|
||||
357
docs/specs/pbs/PRs para Junie.md
Normal file
357
docs/specs/pbs/PRs para Junie.md
Normal file
@ -0,0 +1,357 @@
|
||||
# PBS Compiler — Junie PR Plan
|
||||
|
||||
> **Purpose:** this document defines a sequence of small, focused Pull Requests to be implemented by *Junie*, one at a time.
|
||||
>
|
||||
> **Audience:** compiler implementer (AI or human).
|
||||
>
|
||||
> **Scope:** PBS-first compiler architecture. TS and Lua frontends are assumed **removed**.
|
||||
>
|
||||
> **Hard rules:**
|
||||
>
|
||||
> * Each PR must compile and pass tests.
|
||||
> * Each PR must include tests.
|
||||
> * No speculative features.
|
||||
> * Follow the `Prometeu Base Script (PBS) - Implementation Spec`.
|
||||
|
||||
---
|
||||
|
||||
## Global Architectural Direction (Non-negotiable)
|
||||
|
||||
* PBS is the **primary language**.
|
||||
* Frontend is implemented **before** runtime integration.
|
||||
* Architecture uses **two IR layers**:
|
||||
|
||||
* **Core IR** (PBS-semantic, typed, resolved)
|
||||
* **VM IR** (stack-based, backend-friendly)
|
||||
* VM IR remains simple and stable.
|
||||
* Lowering is explicit and testable.
|
||||
|
||||
---
|
||||
|
||||
# PR-01 — ProjectConfig and Frontend Selection
|
||||
|
||||
### Goal
|
||||
|
||||
Introduce a project-level configuration that selects the frontend and entry file explicitly.
|
||||
|
||||
### Motivation
|
||||
|
||||
The compiler must not hardcode entry points or languages. PBS will be the first frontend, others may return later.
|
||||
|
||||
### Scope
|
||||
|
||||
* Add `ProjectConfig` (serde-deserializable) loaded from `prometeu.json`
|
||||
* Fields (v0):
|
||||
|
||||
* `script_fe: "pbs"`
|
||||
* `entry: "main.pbs"`
|
||||
* Refactor compiler entry point to:
|
||||
|
||||
* load config
|
||||
* select frontend by `script_fe`
|
||||
* resolve entry path relative to project root
|
||||
|
||||
### Files Likely Touched
|
||||
|
||||
* `compiler/mod.rs`
|
||||
* `compiler/driver.rs`
|
||||
* `common/config.rs` (new)
|
||||
|
||||
### Tests (mandatory)
|
||||
|
||||
* unit test: load valid `prometeu.json`
|
||||
* unit test: invalid frontend → diagnostic
|
||||
* integration test: project root + entry resolution
|
||||
|
||||
### Notes to Junie
|
||||
|
||||
Do **not** add PBS parsing yet. This PR is infrastructure only.
|
||||
|
||||
---
|
||||
|
||||
# PR-02 — Core IR Skeleton (PBS-first)
|
||||
|
||||
### Goal
|
||||
|
||||
Introduce a **Core IR** layer independent from the VM IR.
|
||||
|
||||
### Motivation
|
||||
|
||||
PBS semantics must be represented before lowering to VM instructions.
|
||||
|
||||
### Scope
|
||||
|
||||
* Add new module: `ir_core`
|
||||
* Define minimal structures:
|
||||
|
||||
* `Program`
|
||||
* `Module`
|
||||
* `Function`
|
||||
* `Block`
|
||||
* `Instr`
|
||||
* `Terminator`
|
||||
* IDs only (no string-based calls):
|
||||
|
||||
* `FunctionId`
|
||||
* `ConstId`
|
||||
* `TypeId`
|
||||
|
||||
### Constraints
|
||||
|
||||
* Core IR must NOT reference VM opcodes
|
||||
* No lowering yet
|
||||
|
||||
### Tests
|
||||
|
||||
* construct Core IR manually in tests
|
||||
* snapshot test (JSON) for deterministic shape
|
||||
|
||||
---
|
||||
|
||||
# PR-03 — Constant Pool and IDs
|
||||
|
||||
### Goal
|
||||
|
||||
Introduce a stable constant pool shared by Core IR and VM IR.
|
||||
|
||||
### Scope
|
||||
|
||||
* Add `ConstPool`:
|
||||
|
||||
* strings
|
||||
* numbers
|
||||
* Replace inline literals in VM IR with `ConstId`
|
||||
* Update existing VM IR to accept `PushConst(ConstId)`
|
||||
|
||||
### Tests
|
||||
|
||||
* const pool deduplication
|
||||
* deterministic ConstId assignment
|
||||
* IR snapshot stability
|
||||
|
||||
---
|
||||
|
||||
# PR-04 — VM IR Cleanup (Stabilization)
|
||||
|
||||
### Goal
|
||||
|
||||
Stabilize VM IR as a **lowering target**, not a language IR.
|
||||
|
||||
### Scope
|
||||
|
||||
* Replace string-based calls with `FunctionId`
|
||||
* Ensure locals are accessed via slots
|
||||
* Remove or internalize `PushScope` / `PopScope`
|
||||
|
||||
### Tests
|
||||
|
||||
* golden VM IR tests
|
||||
* lowering smoke test (Core IR → VM IR)
|
||||
|
||||
---
|
||||
|
||||
# PR-05 — Core IR → VM IR Lowering Pass
|
||||
|
||||
### Goal
|
||||
|
||||
Implement the lowering pass from Core IR to VM IR.
|
||||
|
||||
### Scope
|
||||
|
||||
* New module: `lowering/core_to_vm.rs`
|
||||
* Lowering rules:
|
||||
|
||||
* Core blocks → labels
|
||||
* Core calls → VM calls
|
||||
* Host calls preserved
|
||||
* No PBS frontend yet
|
||||
|
||||
### Tests
|
||||
|
||||
* lowering correctness
|
||||
* instruction ordering
|
||||
* label resolution
|
||||
|
||||
---
|
||||
|
||||
# PR-06 — PBS Frontend: Lexer
|
||||
|
||||
### Goal
|
||||
|
||||
Implement PBS lexer according to the spec.
|
||||
|
||||
### Scope
|
||||
|
||||
* Token kinds
|
||||
* Keyword table
|
||||
* Span tracking
|
||||
|
||||
### Tests
|
||||
|
||||
* tokenization tests
|
||||
* keyword vs identifier tests
|
||||
* bounded literals
|
||||
|
||||
---
|
||||
|
||||
# PR-07 — PBS Frontend: Parser (Raw AST)
|
||||
|
||||
### Goal
|
||||
|
||||
Parse PBS source into a raw AST.
|
||||
|
||||
### Scope
|
||||
|
||||
* Imports
|
||||
* Top-level declarations
|
||||
* Blocks
|
||||
* Expressions (calls, literals, control flow)
|
||||
|
||||
### Tests
|
||||
|
||||
* valid programs
|
||||
* syntax error recovery
|
||||
|
||||
---
|
||||
|
||||
# PR-08 — PBS Frontend: Symbol Collection and Resolver
|
||||
|
||||
### Goal
|
||||
|
||||
Resolve names, modules, and visibility.
|
||||
|
||||
### Scope
|
||||
|
||||
* Type namespace vs value namespace
|
||||
* Visibility rules
|
||||
* Import resolution
|
||||
|
||||
### Tests
|
||||
|
||||
* duplicate symbols
|
||||
* invalid imports
|
||||
* visibility errors
|
||||
|
||||
---
|
||||
|
||||
# PR-09 — PBS Frontend: Type Checking
|
||||
|
||||
### Goal
|
||||
|
||||
Validate PBS semantics.
|
||||
|
||||
### Scope
|
||||
|
||||
* Primitive types
|
||||
* Structs
|
||||
* `optional<T>` and `result<T, E>`
|
||||
* Mutability rules
|
||||
* Return path validation
|
||||
|
||||
### Tests
|
||||
|
||||
* type mismatch
|
||||
* mutability violations
|
||||
* implicit `none` behavior
|
||||
|
||||
---
|
||||
|
||||
# PR-10 — PBS Frontend: Semantic Lowering to Core IR
|
||||
|
||||
### Goal
|
||||
|
||||
Lower typed PBS AST into Core IR.
|
||||
|
||||
### Scope
|
||||
|
||||
* ID-based calls
|
||||
* ConstPool usage
|
||||
* Control flow lowering
|
||||
* SAFE vs HIP effects represented explicitly
|
||||
|
||||
### Tests
|
||||
|
||||
* PBS → Core IR snapshots
|
||||
* semantic correctness
|
||||
|
||||
---
|
||||
|
||||
# PR-11 — Host-bound Contracts and Syscall Mapping
|
||||
|
||||
### Goal
|
||||
|
||||
Connect PBS host-bound contracts to runtime syscalls (without executing them).
|
||||
|
||||
### Scope
|
||||
|
||||
* Contract registry
|
||||
* Mapping: contract.method → syscall id
|
||||
* Core IR host call nodes
|
||||
|
||||
### Tests
|
||||
|
||||
* invalid contract calls
|
||||
* correct syscall mapping
|
||||
|
||||
---
|
||||
|
||||
# PR-12 — Diagnostics Canonicalization
|
||||
|
||||
### Goal
|
||||
|
||||
Standardize diagnostics output.
|
||||
|
||||
### Scope
|
||||
|
||||
* Error codes (`E_*`, `W_*`)
|
||||
* Stable messages
|
||||
* Span accuracy
|
||||
|
||||
### Tests
|
||||
|
||||
* golden diagnostics
|
||||
|
||||
---
|
||||
|
||||
# PR-13 — Backend Integration (VM IR → Bytecode)
|
||||
|
||||
### Goal
|
||||
|
||||
Reconnect the pipeline to the Prometeu runtime backend.
|
||||
|
||||
### Scope
|
||||
|
||||
* VM IR → bytecode emission
|
||||
* No PBS semantics here
|
||||
|
||||
### Tests
|
||||
|
||||
* bytecode emission smoke test
|
||||
|
||||
---
|
||||
|
||||
# PR-14 — End-to-End PBS Compile Test
|
||||
|
||||
### Goal
|
||||
|
||||
Prove the full pipeline works.
|
||||
|
||||
### Scope
|
||||
|
||||
* Sample PBS project
|
||||
* Compile → bytecode
|
||||
* Diagnostics only (no execution)
|
||||
|
||||
### Tests
|
||||
|
||||
* golden bytecode snapshot
|
||||
|
||||
---
|
||||
|
||||
## Final Note to Junie
|
||||
|
||||
Do **not** skip PRs.
|
||||
Do **not** merge multiple PRs together.
|
||||
If the spec is unclear, create a failing test and document the ambiguity.
|
||||
|
||||
This plan is the authoritative roadmap for PBS frontend implementation.
|
||||
@ -0,0 +1,446 @@
|
||||
# Prometeu Base Script (PBS)
|
||||
|
||||
## Frontend Spec v0 — Implementer Edition
|
||||
|
||||
> **Normative specification for building a PBS frontend (lexer, parser, AST, resolver, typechecker) targeting the Prometeu Fantasy Console runtime.**
|
||||
>
|
||||
> This document is **not** a user guide.
|
||||
> It exists to make PBS *implementable*, *deterministic*, and *testable*.
|
||||
|
||||
---
|
||||
|
||||
## 0. Scope and Non‑Goals
|
||||
|
||||
### 0.1 Scope
|
||||
|
||||
This specification defines:
|
||||
|
||||
* lexical structure (tokens)
|
||||
* grammar and parsing rules
|
||||
* canonical AST shapes
|
||||
* frontend phases and their responsibilities
|
||||
* name resolution and visibility rules
|
||||
* type system rules
|
||||
* desugaring and lowering rules
|
||||
* diagnostic categories (errors vs warnings)
|
||||
* required guarantees for runtime integration
|
||||
|
||||
The goal is that **two independent frontends** built from this spec:
|
||||
|
||||
* accept the same programs
|
||||
* reject the same programs
|
||||
* produce equivalent ASTs
|
||||
* emit equivalent diagnostics
|
||||
|
||||
### 0.2 Non‑Goals
|
||||
|
||||
This spec does **not** define:
|
||||
|
||||
* runtime performance characteristics
|
||||
* bytecode layout
|
||||
* JIT or interpreter design
|
||||
* editor tooling or IDE features
|
||||
|
||||
Those are explicitly out of scope.
|
||||
|
||||
---
|
||||
|
||||
## 1. Frontend Pipeline Overview
|
||||
|
||||
A PBS frontend **must** be structured as the following pipeline:
|
||||
|
||||
```
|
||||
Source Text
|
||||
↓
|
||||
Lexer
|
||||
↓
|
||||
Parser
|
||||
↓
|
||||
Raw AST
|
||||
↓
|
||||
Symbol Collection
|
||||
↓
|
||||
Resolver
|
||||
↓
|
||||
Typed AST
|
||||
↓
|
||||
Desugaring / Lowering
|
||||
↓
|
||||
Runtime‑ready IR / AST
|
||||
```
|
||||
|
||||
Each stage has **strict responsibilities**.
|
||||
No stage may perform work assigned to a later stage.
|
||||
|
||||
---
|
||||
|
||||
## 2. Lexical Structure
|
||||
|
||||
### 2.1 Tokens
|
||||
|
||||
A PBS lexer must recognize at minimum the following token classes:
|
||||
|
||||
* identifiers
|
||||
* keywords
|
||||
* numeric literals
|
||||
* string literals
|
||||
* punctuation
|
||||
* operators
|
||||
* comments
|
||||
|
||||
Whitespace is insignificant except as a separator.
|
||||
|
||||
---
|
||||
|
||||
### 2.2 Keywords (Reserved)
|
||||
|
||||
The following keywords are **reserved** and may not be used as identifiers:
|
||||
|
||||
```
|
||||
import
|
||||
pub
|
||||
mod
|
||||
service
|
||||
fn
|
||||
let
|
||||
mut
|
||||
declare
|
||||
struct
|
||||
contract
|
||||
host
|
||||
error
|
||||
optional
|
||||
result
|
||||
some
|
||||
none
|
||||
ok
|
||||
err
|
||||
if
|
||||
else
|
||||
when
|
||||
for
|
||||
in
|
||||
return
|
||||
handle
|
||||
borrow
|
||||
mutate
|
||||
peek
|
||||
take
|
||||
alloc
|
||||
weak
|
||||
as
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.3 Literals
|
||||
|
||||
#### Numeric Literals
|
||||
|
||||
* `int` — decimal digits
|
||||
* `float` — decimal with `.`
|
||||
* `bounded` — decimal digits suffixed with `b`
|
||||
|
||||
Examples:
|
||||
|
||||
```pbs
|
||||
10
|
||||
42
|
||||
3.14
|
||||
0b
|
||||
255b
|
||||
```
|
||||
|
||||
#### String Literals
|
||||
|
||||
* delimited by `"`
|
||||
* UTF‑8 encoded
|
||||
* immutable
|
||||
|
||||
---
|
||||
|
||||
### 2.4 Comments
|
||||
|
||||
* line comment: `// until end of line`
|
||||
* block comments are **not supported** in v0
|
||||
|
||||
---
|
||||
|
||||
## 3. Grammar (EBNF‑style)
|
||||
|
||||
> This grammar is **normative** but simplified for readability.
|
||||
> Implementers may refactor internally as long as semantics are preserved.
|
||||
|
||||
### 3.1 File Structure
|
||||
|
||||
```
|
||||
File ::= Import* TopLevelDecl*
|
||||
Import ::= 'import' ImportSpec 'from' StringLiteral
|
||||
TopLevelDecl::= TypeDecl | ServiceDecl | FnDecl
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.2 Type Declarations
|
||||
|
||||
```
|
||||
TypeDecl ::= Visibility? 'declare' TypeKind Identifier TypeBody
|
||||
TypeKind ::= 'struct' | 'contract' | 'error'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 Services
|
||||
|
||||
```
|
||||
ServiceDecl ::= Visibility 'service' Identifier (':' Identifier)? Block
|
||||
```
|
||||
|
||||
Visibility is mandatory for services.
|
||||
|
||||
---
|
||||
|
||||
### 3.4 Functions
|
||||
|
||||
```
|
||||
FnDecl ::= 'fn' Identifier ParamList ReturnType? ElseFallback? Block
|
||||
```
|
||||
|
||||
Top‑level `fn` are always file‑private.
|
||||
|
||||
---
|
||||
|
||||
### 3.5 Expressions (Partial)
|
||||
|
||||
```
|
||||
Expr ::= Literal
|
||||
| Identifier
|
||||
| CallExpr
|
||||
| Block
|
||||
| IfExpr
|
||||
| WhenExpr
|
||||
| ForExpr
|
||||
| ReturnExpr
|
||||
```
|
||||
|
||||
Expression grammar is intentionally restricted in v0.
|
||||
|
||||
---
|
||||
|
||||
## 4. Canonical AST
|
||||
|
||||
The frontend **must** produce a canonical AST.
|
||||
|
||||
### 4.1 AST Invariants
|
||||
|
||||
* AST nodes are immutable after creation
|
||||
* Parent pointers are optional
|
||||
* Source spans must be preserved for diagnostics
|
||||
|
||||
---
|
||||
|
||||
### 4.2 Core Node Kinds
|
||||
|
||||
Minimal required node kinds:
|
||||
|
||||
* `FileNode`
|
||||
* `ImportNode`
|
||||
* `ServiceNode`
|
||||
* `FunctionNode`
|
||||
* `StructDeclNode`
|
||||
* `ContractDeclNode`
|
||||
* `BlockNode`
|
||||
* `LetNode`
|
||||
* `CallNode`
|
||||
* `IfNode`
|
||||
* `WhenNode`
|
||||
* `ForNode`
|
||||
* `ReturnNode`
|
||||
|
||||
Implementers may add internal nodes but must normalize before later phases.
|
||||
|
||||
---
|
||||
|
||||
## 5. Symbol Collection Phase
|
||||
|
||||
### 5.1 Purpose
|
||||
|
||||
Symbol Collection builds **module‑level symbol tables** without resolving bodies.
|
||||
|
||||
Collected symbols:
|
||||
|
||||
* `pub` and `mod` type declarations
|
||||
* `pub` and `mod` services
|
||||
|
||||
Excluded:
|
||||
|
||||
* function bodies
|
||||
* expressions
|
||||
* local bindings
|
||||
|
||||
---
|
||||
|
||||
### 5.2 Namespaces
|
||||
|
||||
PBS has **two namespaces**:
|
||||
|
||||
* Type namespace
|
||||
* Value namespace
|
||||
|
||||
Rules:
|
||||
|
||||
* A name may not exist in both namespaces
|
||||
* Violations are compile‑time errors
|
||||
|
||||
---
|
||||
|
||||
## 6. Resolver Phase
|
||||
|
||||
### 6.1 Responsibilities
|
||||
|
||||
Resolver must:
|
||||
|
||||
* resolve all identifiers
|
||||
* enforce visibility rules
|
||||
* bind references to symbols
|
||||
|
||||
Resolution order (per namespace):
|
||||
|
||||
1. local bindings
|
||||
2. file‑private declarations
|
||||
3. module symbols
|
||||
4. imported symbols
|
||||
|
||||
---
|
||||
|
||||
### 6.2 Visibility Rules (Normative)
|
||||
|
||||
* file‑private: visible only in the same file
|
||||
* `mod`: visible within the module
|
||||
* `pub`: visible across modules via import
|
||||
|
||||
Violations are errors.
|
||||
|
||||
---
|
||||
|
||||
## 7. Type Checking
|
||||
|
||||
### 7.1 Type Categories
|
||||
|
||||
Frontend must support:
|
||||
|
||||
* primitive types
|
||||
* struct value types
|
||||
* `optional<T>`
|
||||
* `result<T, E>`
|
||||
* gate‑backed types (opaque at frontend level)
|
||||
|
||||
---
|
||||
|
||||
### 7.2 Mutability Rules
|
||||
|
||||
* mutability belongs to bindings, not types
|
||||
* `mut` is part of binding metadata
|
||||
* mutability violations are compile‑time errors
|
||||
|
||||
---
|
||||
|
||||
### 7.3 Function Checking
|
||||
|
||||
Rules:
|
||||
|
||||
* all paths must return a value unless `else` fallback exists
|
||||
* `optional<T>` may implicitly return `none`
|
||||
* `result<T,E>` must return explicitly
|
||||
|
||||
---
|
||||
|
||||
## 8. Desugaring and Lowering
|
||||
|
||||
### 8.1 Purpose
|
||||
|
||||
Lowering transforms surface syntax into a minimal core language.
|
||||
|
||||
Examples:
|
||||
|
||||
* `take x.push(v)` → `mutate x as t { t.push(v) }`
|
||||
* `when` → conditional expression node
|
||||
* implicit `return none` for `optional<T>`
|
||||
|
||||
Lowered AST must contain **no syntactic sugar**.
|
||||
|
||||
---
|
||||
|
||||
## 9. Diagnostics Model
|
||||
|
||||
Diagnostics are first‑class frontend outputs.
|
||||
|
||||
### 9.1 Categories
|
||||
|
||||
* Error — compilation must fail
|
||||
* Warning — compilation may continue
|
||||
|
||||
---
|
||||
|
||||
### 9.2 Required Errors
|
||||
|
||||
Examples:
|
||||
|
||||
* unresolved identifier
|
||||
* visibility violation
|
||||
* type mismatch
|
||||
* mutability violation
|
||||
* invalid gate conversion
|
||||
|
||||
---
|
||||
|
||||
## 10. Runtime Interface Assumptions
|
||||
|
||||
Frontend assumes:
|
||||
|
||||
* host‑bound contracts map to runtime syscalls
|
||||
* allocation primitives exist (`alloc`)
|
||||
* reference counting is handled by runtime
|
||||
|
||||
Frontend must **not** assume GC or heap layout.
|
||||
|
||||
---
|
||||
|
||||
## 11. Determinism Guarantees
|
||||
|
||||
A valid PBS frontend **must guarantee**:
|
||||
|
||||
* deterministic parsing
|
||||
* deterministic name resolution
|
||||
* deterministic type checking
|
||||
* deterministic diagnostics
|
||||
|
||||
No frontend stage may depend on execution order or host state.
|
||||
|
||||
---
|
||||
|
||||
## 12. Conformance Criteria
|
||||
|
||||
A frontend is PBS‑v0‑conformant if:
|
||||
|
||||
* it implements all rules in this document
|
||||
* it produces canonical ASTs
|
||||
* it rejects all invalid programs defined herein
|
||||
|
||||
This document is the **source of truth** for PBS v0 frontend behavior.
|
||||
|
||||
---
|
||||
|
||||
## 13. Future Evolution (Non‑Normative)
|
||||
|
||||
Future versions may add:
|
||||
|
||||
* pattern matching
|
||||
* richer type inference
|
||||
* macros
|
||||
|
||||
No v0 frontend is required to support these.
|
||||
|
||||
---
|
||||
|
||||
## End of Spec
|
||||
341
docs/specs/pbs/Prometeu Scripting - Language Tour.md
Normal file
341
docs/specs/pbs/Prometeu Scripting - Language Tour.md
Normal file
@ -0,0 +1,341 @@
|
||||
# Prometeu Base Script (PBS)
|
||||
|
||||
> **A didactic scripting language for game development with explicit cost, explicit memory, and predictable runtime.**
|
||||
|
||||
---
|
||||
|
||||
## 0. What PBS Is (and What It Is Not)
|
||||
|
||||
PBS (Prometeu Base Script) is a **small, explicit scripting language designed for game engines and real‑time runtimes**.
|
||||
|
||||
Its core goals are:
|
||||
|
||||
* **Didactic clarity** — the language teaches how memory, data, and APIs really work.
|
||||
* **Game‑friendly execution** — predictable runtime, no hidden allocation, no tracing GC.
|
||||
* **Explicit cost model** — you always know *when* you allocate, *where* data lives, and *who* can mutate it.
|
||||
|
||||
PBS is **not**:
|
||||
|
||||
* a general‑purpose application language
|
||||
* a productivity scripting language like Python or Lua
|
||||
* a language that hides runtime cost
|
||||
|
||||
PBS is intentionally opinionated. It is built for developers who want **control, predictability, and understanding**, especially in **game and engine contexts**.
|
||||
|
||||
---
|
||||
|
||||
## 1. The Core Philosophy
|
||||
|
||||
PBS is built around one rule:
|
||||
|
||||
> **If you do not allocate, you are safe. If you allocate, you are responsible.**
|
||||
|
||||
From this rule, everything else follows.
|
||||
|
||||
### 1.1 Two Worlds
|
||||
|
||||
PBS has **two explicit memory worlds**:
|
||||
|
||||
| World | Purpose | Properties |
|
||||
| ----- | -------------- | ---------------------------------------------- |
|
||||
| SAFE | Stack / values | No aliasing, no leaks, no shared mutation |
|
||||
| HIP | Storage / heap | Explicit aliasing, shared mutation, refcounted |
|
||||
|
||||
You never cross between these worlds implicitly.
|
||||
|
||||
---
|
||||
|
||||
## 2. First Contact: SAFE‑Only PBS
|
||||
|
||||
A PBS program that never allocates lives entirely in the SAFE world.
|
||||
|
||||
SAFE code:
|
||||
|
||||
* uses value semantics
|
||||
* copies data on assignment (conceptually)
|
||||
* cannot leak memory
|
||||
* cannot accidentally share mutable state
|
||||
|
||||
This makes SAFE PBS ideal for:
|
||||
|
||||
* gameplay logic
|
||||
* math and simulation
|
||||
* AI logic
|
||||
* scripting without fear
|
||||
|
||||
Example:
|
||||
|
||||
```pbs
|
||||
let a = Vector(1, 2);
|
||||
let b = a; // conceptual copy
|
||||
|
||||
b.scale(2);
|
||||
// a is unchanged
|
||||
```
|
||||
|
||||
No pointers. No references. No surprises.
|
||||
|
||||
---
|
||||
|
||||
## 3. Values, Not Objects
|
||||
|
||||
PBS does not have objects with identity by default.
|
||||
|
||||
### 3.1 Value Types
|
||||
|
||||
All basic types are **values**:
|
||||
|
||||
* numbers
|
||||
* bool
|
||||
* string (immutable)
|
||||
* tuples
|
||||
* user‑defined `struct`
|
||||
|
||||
A value:
|
||||
|
||||
* has no identity
|
||||
* has no lifetime beyond its scope
|
||||
* is safe to copy
|
||||
|
||||
This matches how most gameplay data *should* behave.
|
||||
|
||||
---
|
||||
|
||||
## 4. Structs (Data First)
|
||||
|
||||
Structs are **pure data models**.
|
||||
|
||||
```pbs
|
||||
declare struct Vector(x: float, y: float)
|
||||
{
|
||||
pub fn len(self: this): float { ... }
|
||||
pub fn scale(self: mut this, s: float): void { ... }
|
||||
}
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
* fields are private
|
||||
* mutation is explicit (`mut this`)
|
||||
* no inheritance
|
||||
* no identity
|
||||
|
||||
Structs are designed to be:
|
||||
|
||||
* cache‑friendly
|
||||
* predictable
|
||||
* easy to reason about
|
||||
|
||||
---
|
||||
|
||||
## 5. Mutability Is a Property of Bindings
|
||||
|
||||
In PBS, **types are never mutable**. Bindings are.
|
||||
|
||||
```pbs
|
||||
let v = Vector.ZERO;
|
||||
v.scale(); // ERROR
|
||||
|
||||
let w = mut Vector.ZERO;
|
||||
w.scale(); // OK
|
||||
```
|
||||
|
||||
This single rule eliminates entire classes of bugs.
|
||||
|
||||
---
|
||||
|
||||
## 6. When You Need Power: Allocation (HIP World)
|
||||
|
||||
Allocation is **explicit**.
|
||||
|
||||
```pbs
|
||||
let enemies = alloc list<Enemy>();
|
||||
```
|
||||
|
||||
Once you allocate:
|
||||
|
||||
* data lives in Storage (heap)
|
||||
* access happens through **gates** (handles)
|
||||
* aliasing is real and visible
|
||||
|
||||
This is intentional and explicit.
|
||||
|
||||
---
|
||||
|
||||
## 7. Gates (Handles, Not Pointers)
|
||||
|
||||
A gate is a small value that refers to heap storage.
|
||||
|
||||
Properties:
|
||||
|
||||
* cheap to copy
|
||||
* may alias shared data
|
||||
* managed by reference counting
|
||||
|
||||
### 7.1 Strong vs Weak Gates
|
||||
|
||||
* **Strong gate** — keeps data alive
|
||||
* **Weak gate** — observes without ownership
|
||||
|
||||
```pbs
|
||||
let a = alloc Node;
|
||||
let w: weak<Node> = a as weak;
|
||||
let maybeA = w as strong;
|
||||
```
|
||||
|
||||
This model mirrors real engine constraints without hiding them.
|
||||
|
||||
---
|
||||
|
||||
## 8. Controlled Access to Storage
|
||||
|
||||
Heap data is never accessed directly.
|
||||
|
||||
You must choose *how*:
|
||||
|
||||
* `peek` — copy to SAFE
|
||||
* `borrow` — temporary read‑only access
|
||||
* `mutate` — temporary mutable access
|
||||
|
||||
```pbs
|
||||
mutate enemies as e
|
||||
{
|
||||
e.push(newEnemy);
|
||||
}
|
||||
```
|
||||
|
||||
This keeps mutation visible and scoped.
|
||||
|
||||
---
|
||||
|
||||
## 9. Errors Are Values
|
||||
|
||||
PBS has no exceptions.
|
||||
|
||||
### 9.1 `optional<T>`
|
||||
|
||||
Used when absence is normal.
|
||||
|
||||
```pbs
|
||||
let x = maybeValue else 0;
|
||||
```
|
||||
|
||||
### 9.2 `result<T, E>`
|
||||
|
||||
Used when failure matters.
|
||||
|
||||
```pbs
|
||||
let v = loadTexture(path)?;
|
||||
```
|
||||
|
||||
Error propagation is explicit and typed.
|
||||
|
||||
---
|
||||
|
||||
## 10. Control Flow Without Surprises
|
||||
|
||||
PBS favors explicit flow:
|
||||
|
||||
* `if` — control only
|
||||
* `when` — expression
|
||||
* `for` — bounded loops only
|
||||
|
||||
```pbs
|
||||
for i in [0b..count] {
|
||||
update(i);
|
||||
}
|
||||
```
|
||||
|
||||
No unbounded iteration by accident.
|
||||
|
||||
---
|
||||
|
||||
## 11. Services: Explicit API Boundaries
|
||||
|
||||
A `service` is how behavior crosses module boundaries.
|
||||
|
||||
```pbs
|
||||
pub service Audio
|
||||
{
|
||||
fn play(sound: Sound): void;
|
||||
}
|
||||
```
|
||||
|
||||
Services are:
|
||||
|
||||
* explicit
|
||||
* statically checked
|
||||
* singleton‑like
|
||||
|
||||
They map naturally to engine subsystems.
|
||||
|
||||
---
|
||||
|
||||
## 12. Contracts: Static Guarantees
|
||||
|
||||
Contracts define **what exists**, not how.
|
||||
|
||||
```pbs
|
||||
pub declare contract Gfx host
|
||||
{
|
||||
fn drawText(x: int, y: int, msg: string): void;
|
||||
}
|
||||
```
|
||||
|
||||
Contracts:
|
||||
|
||||
* have no runtime cost
|
||||
* are validated at compile time
|
||||
* define engine ↔ script boundaries
|
||||
|
||||
---
|
||||
|
||||
## 13. Modules (Simple and Predictable)
|
||||
|
||||
* one directory = one module
|
||||
* only `pub` symbols cross modules
|
||||
* no side effects on import
|
||||
|
||||
This keeps build and runtime deterministic.
|
||||
|
||||
---
|
||||
|
||||
## 14. Why PBS Works for Games
|
||||
|
||||
PBS is designed around real engine needs:
|
||||
|
||||
* frame‑based execution
|
||||
* explicit allocation
|
||||
* deterministic cleanup
|
||||
* predictable performance
|
||||
|
||||
It teaches developers **why engines are written the way they are**, instead of hiding reality.
|
||||
|
||||
---
|
||||
|
||||
## 15. Who PBS Is For
|
||||
|
||||
PBS is for:
|
||||
|
||||
* game developers who want control
|
||||
* engine developers
|
||||
* students learning systems concepts
|
||||
* educators teaching memory and runtime models
|
||||
|
||||
PBS is *not* for:
|
||||
|
||||
* rapid prototyping without constraints
|
||||
* general app scripting
|
||||
* hiding complexity
|
||||
|
||||
---
|
||||
|
||||
## 16. Design Promise
|
||||
|
||||
PBS makes one promise:
|
||||
|
||||
> **Nothing happens behind your back.**
|
||||
|
||||
If you understand PBS, you understand your runtime.
|
||||
|
||||
That is the product.
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,648 +0,0 @@
|
||||
# Prometeu Base Script (PBS)
|
||||
|
||||
**Status:** v0 (frontend-freeze)
|
||||
**Goal:** stack-only language, no GC, explicit semantics, predictable runtime
|
||||
|
||||
---
|
||||
|
||||
## 0. Philosophy (anchor section)
|
||||
|
||||
PBS is designed as:
|
||||
|
||||
* **Value-first** (no implicit references, no aliasing of mutable state)
|
||||
* **Stack-only** (no heap, no GC)
|
||||
* **Explicit mutability** (bindings, not types)
|
||||
* **Didactic** (rules visible in syntax)
|
||||
* **Runtime-cheap** (frontend-heavy, backend-simple)
|
||||
|
||||
Everything in the language flows from these constraints.
|
||||
|
||||
---
|
||||
|
||||
## 1. Project, Files & Modules
|
||||
|
||||
### 1.1 Files
|
||||
|
||||
* Extension: `.pbs`
|
||||
* Project has a **root directory**
|
||||
* `@path` is resolved relative to project root
|
||||
|
||||
### 1.2 Module Model
|
||||
|
||||
* **One directory = one module**.
|
||||
* A module boundary is **real**: parent/child/sibling directories do **not** get automatic visibility.
|
||||
* Code in `@project:modA` does **not** automatically see declarations in `@project:modA/sub`.
|
||||
* Code in `@project:modA/sub` does **not** automatically see declarations in `@project:modA`.
|
||||
* Sibling modules (e.g., `@project:modA` and `@project:modB`) are completely isolated unless you `import`.
|
||||
* **Cross-module access always requires `import`**, and only `pub` symbols may cross module boundaries.
|
||||
|
||||
### 1.3 Automatic Module Index
|
||||
|
||||
* No mandatory barrel file
|
||||
* Compiler builds an index from:
|
||||
|
||||
* all `pub` symbols
|
||||
* in `.pbs` files **directly inside the directory**
|
||||
* Subdirectories are excluded
|
||||
|
||||
### 1.4 Visibility Modifiers
|
||||
|
||||
PBS uses explicit visibility modifiers to control symbol exposure. Visibility is the **only** mechanism that decides whether another file/module can see a symbol.
|
||||
|
||||
* **default (no modifier)** — **file-private**
|
||||
|
||||
* Visible **only** within the declaring `.pbs` file.
|
||||
* Never visible from any other file, even inside the same module.
|
||||
|
||||
* **`mod`** — **module-visible**
|
||||
|
||||
* Visible to **all files** in the same module (same directory).
|
||||
* Not visible outside the module.
|
||||
* No `import` is required for other files in the same module to refer to it.
|
||||
|
||||
* **`pub`** — **public API**
|
||||
|
||||
* Exported as part of the module’s public surface.
|
||||
* May be imported by other modules.
|
||||
* Within the same module, `pub` behaves like `mod` (visible across files without import).
|
||||
|
||||
Important:
|
||||
|
||||
* A symbol is either **file-private**, **module-visible**, or **public**. There is no other visibility level.
|
||||
* Visibility is checked independently in the **type** and **value** namespaces.
|
||||
|
||||
Visibility applies uniformly to:
|
||||
|
||||
* `declare` type declarations
|
||||
* `service`
|
||||
* value-level symbols
|
||||
|
||||
---
|
||||
|
||||
## 2. Namespaces & Visibility
|
||||
|
||||
### 2.1 Global Namespaces
|
||||
|
||||
Existem **dois namespaces globais**:
|
||||
|
||||
**Type namespace**
|
||||
|
||||
Tipos são introduzidos **exclusivamente** por declarações `declare`.
|
||||
O que vem após `declare` define a categoria do tipo.
|
||||
|
||||
Formas válidas:
|
||||
|
||||
```pbs
|
||||
declare struct Name { ... }
|
||||
declare error Name { ... }
|
||||
declare contract Name { ... }
|
||||
```
|
||||
|
||||
**Value namespace**
|
||||
|
||||
Introduzido por declarações executáveis:
|
||||
|
||||
* `fn`
|
||||
* `service`
|
||||
* `let`
|
||||
|
||||
---
|
||||
|
||||
## 3. Top-level Declarations
|
||||
|
||||
A `.pbs` file may contain:
|
||||
|
||||
* `import`
|
||||
* **type declarations** via `declare`:
|
||||
|
||||
* `declare struct`
|
||||
* `declare error`
|
||||
* `declare contract`
|
||||
* `service`
|
||||
* `fn` (always file-private)
|
||||
|
||||
Order is free.
|
||||
|
||||
---
|
||||
|
||||
## 4. Resolver Rules
|
||||
|
||||
This section defines how the compiler resolves modules, imports, and symbol names into concrete declarations.
|
||||
|
||||
### 4.1 Units of compilation
|
||||
|
||||
* The compilation unit is a **project** (root + all referenced modules/files).
|
||||
* The root of the project is associated with the src/main/modules
|
||||
* A **module** is exactly one directory.
|
||||
* A **file unit** is one `.pbs` file.
|
||||
|
||||
Examples, lets say we have a project called: `project`:
|
||||
```
|
||||
project
|
||||
|- prometeu.json
|
||||
|- prometeu-cache
|
||||
| |-cache.lock
|
||||
|- src
|
||||
| |- main
|
||||
| | |- modules
|
||||
| | | |- module-1
|
||||
| | | | |- file-1.pbs
|
||||
| | | | |- file-2.pbs
|
||||
| | | | | |- fearture A
|
||||
| | | | |- file-3.pbs
|
||||
| | | | |- module-2
|
||||
| | | | | |- file-1.pbs
|
||||
| | | | | |- file-2.pbs
|
||||
| | | | | | |- fearture B
|
||||
| | | | | |- file-3.pbs
|
||||
| |- resources
|
||||
| | |- resource-1.txt
|
||||
| |- test
|
||||
| | |- modules
|
||||
| | | |- module-1
|
||||
| | | | |- file-1.pbs
|
||||
| | | | |- file-2.pbs
|
||||
| | | | |- file-3.pbs
|
||||
| | |- resources
|
||||
```
|
||||
|
||||
For a project `project/src/main/` is the root, and it will be presented in the import as (when looking for feature A and B):
|
||||
```
|
||||
import { featureA } from "@project:module-1"
|
||||
import { featureB } from "@project:module-1/module-2"
|
||||
```
|
||||
|
||||
The project name is a configuration inside `prometeu.json`. A project always defines a unit compilation. Other compilation
|
||||
units could be linked to the project as a dependency. When building a project, all dependencies will be copied into a
|
||||
directory called `prometeu-cache` (read-only) inside the project root.
|
||||
A `project.json` could be look like.
|
||||
```json
|
||||
{
|
||||
"name": "project",
|
||||
"dependencies":{
|
||||
"project-A": {
|
||||
"version": "1.0.0",
|
||||
"source": "path:../project-A"
|
||||
},
|
||||
"project-B": {
|
||||
"version": "1.5.3",
|
||||
"source": "git:https://github.com/project-B.git"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When compiling, all deps and current project will be flattened, and Project names should be unique otherwise it will
|
||||
cause conflicts and compilation errors on the current project.
|
||||
|
||||
### 4.2 Namespaces
|
||||
|
||||
Resolution is performed in **two independent namespaces**:
|
||||
|
||||
* **Type namespace**: declarations introduced by `declare` (`struct`, `error`, `contract`).
|
||||
* **Value namespace**: declarations introduced by `service`, `fn`, and `let`.
|
||||
|
||||
A name may exist in both namespaces, but this is **discouraged**; toolchains may report this as an error or warning.
|
||||
|
||||
### 4.3 Visibility gates
|
||||
|
||||
For any candidate symbol `S`, visibility is checked explicitly:
|
||||
|
||||
* **file-private (default)** — visible only within the same file
|
||||
* **`mod`** — visible to any file in the same module
|
||||
* **`pub`** — visible to other modules via `import`
|
||||
|
||||
No implicit visibility exists beyond these rules.
|
||||
|
||||
### 4.4 Module index construction
|
||||
|
||||
For each module directory `M`:
|
||||
|
||||
* The compiler scans all `.pbs` files **directly inside** `M`.
|
||||
* The module’s **public index** contains **only** `pub` symbols from those files.
|
||||
* Subdirectories never contribute to the parent module’s index.
|
||||
|
||||
Duplicate rules:
|
||||
|
||||
* Any `structs, services, contracts, errors` duplicate `pub` names in the same namespace cause a compile error:
|
||||
|
||||
* `duplicate public symbol in module`.
|
||||
|
||||
### 4.5 Import resolution
|
||||
|
||||
Imports are the **only** mechanism for cross-module access.
|
||||
|
||||
```pbs
|
||||
import { X, Y as Z } from "@project:module";
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
* Only `pub` symbols may be imported.
|
||||
* Import-by-module resolves against the module public index.
|
||||
* Import-by-file is not allowed at all.
|
||||
|
||||
### 4.6 Local resolution order
|
||||
|
||||
Within a file, name lookup follows this order **within each namespace**:
|
||||
|
||||
1. Local bindings (parameters, local `let`, innermost scope first) but with warnings
|
||||
- when `import { X as Y } from "@project:module"` and `let Y: int = 0;` `let Y` wins but could generate a warning
|
||||
2. File-level declarations (file-private, `mod`, and `pub` in the same file)
|
||||
3. Imported bindings
|
||||
4. When `import { X } from "@project:module"` (or when using `as`) and we already have a `mod X ...` for this module, compilation error.
|
||||
|
||||
Shadowing rules:
|
||||
|
||||
* Local `let` shadowing is allowed.
|
||||
* Shadowing of `fn` and `service` names is not allowed.
|
||||
|
||||
### 4.7 Cross-file and cross-module access
|
||||
|
||||
**Within the same module:**
|
||||
|
||||
* `mod` and `pub` symbols are visible across files without `import`.
|
||||
* file-private symbols are never visible.
|
||||
|
||||
**Across modules:**
|
||||
|
||||
* only `pub` symbols are visible
|
||||
* access always requires an explicit `import`.
|
||||
|
||||
### 4.8 Cycles
|
||||
|
||||
* Import cycles are allowed only if name resolution can be completed.
|
||||
* PBS has no top-level execution, so cycles are resolved purely at the symbol level.
|
||||
* Any cycle that prevents construction of a complete symbol table is a compile error.
|
||||
|
||||
### 4.9 Contracts and services
|
||||
|
||||
* `declare contract C` introduces `C` in the **type namespace**.
|
||||
* `service S: C` resolves `C` as a type and validates that `S` implements all declared signatures.
|
||||
* they can be implemented by the Prometeu runtime / host environment.
|
||||
|
||||
---
|
||||
|
||||
## 4. Services
|
||||
|
||||
A `service` represents an **explicit API boundary** between PBS code and either:
|
||||
|
||||
* other PBS modules, or
|
||||
* it is definitely a singleton by design
|
||||
* can implement a contract, or not
|
||||
- when implementing a contract, signatures must match exactly
|
||||
* every `fn` inside in a `service` will follow the same visibility as the service it belongs (`pub` or `mod`).
|
||||
- once being able to see the service, it can see all its methods.
|
||||
|
||||
A service is never an implementation detail.
|
||||
|
||||
### 4.1 Declaration and visibility
|
||||
|
||||
A service must always be declared with an explicit visibility modifier:
|
||||
|
||||
* `pub service` — part of the module’s public API
|
||||
* `mod service` — internal API, visible only inside the module
|
||||
|
||||
There is **no such thing** as a private service.
|
||||
|
||||
### 4.2 Service methods
|
||||
|
||||
* All methods declared inside a service are **public within that service**.
|
||||
* There are no private or helper methods inside a service.
|
||||
* A service method may call:
|
||||
|
||||
* top-level `fn` in the same file
|
||||
* other services it can legally see
|
||||
|
||||
### 4.3 Implementation rule
|
||||
|
||||
If logic is not conceptually part of the API, it **must not** live inside a service.
|
||||
Such logic must be implemented as file-private `fn`.
|
||||
|
||||
---
|
||||
|
||||
## 6. Types
|
||||
|
||||
This section describes all value types available in PBS and how they are declared.
|
||||
|
||||
### 6.1 Primitive types
|
||||
|
||||
PBS provides a small, fixed set of primitive types:
|
||||
|
||||
* `void`
|
||||
* `int` (32-bit signed)
|
||||
* `long` (64-bit signed)
|
||||
* `float` (32-bit IEEE-754)
|
||||
* `double` (64-bit IEEE-754)
|
||||
* `bool`
|
||||
* `char` (Unicode code point, 32-bit)
|
||||
* `string`
|
||||
|
||||
Important notes:
|
||||
|
||||
* `string` values are **immutable**.
|
||||
* Strings exist only as literals stored in a constant pool.
|
||||
* There is no dynamic string allocation at runtime.
|
||||
|
||||
### 6.2 Struct types
|
||||
|
||||
User-defined value types are declared using `declare struct`.
|
||||
|
||||
A struct:
|
||||
|
||||
* is a **pure value type**
|
||||
* has no identity
|
||||
* follow the rules of **mutability and borrowing" described below
|
||||
* has no inheritance or subtyping
|
||||
* it is only copied when mutated, otherwise it is **viewed as immutable** and passed as ref by default.
|
||||
|
||||
All behavior related to the type must be defined inside the struct body.
|
||||
|
||||
### 6.3 `this`
|
||||
|
||||
Inside a struct body, the special type `this` refers to the struct itself.
|
||||
|
||||
Rules:
|
||||
|
||||
* `this` may only appear inside a `declare struct` body.
|
||||
* Outside a struct, `this` is illegal.
|
||||
|
||||
---
|
||||
|
||||
## 7. Structs & Constructors
|
||||
|
||||
```pbs
|
||||
declare struct Vector(x: float, y: float)
|
||||
[
|
||||
(): (0,0) as default { }
|
||||
(a: float): (a,a) as square { }
|
||||
(): (1,1) as normalize { }
|
||||
]
|
||||
[[
|
||||
ZERO: default()
|
||||
ONE: square(1.0)
|
||||
]]
|
||||
{
|
||||
pub fn len(self: this): float { ... }
|
||||
pub fn scale(self: mut this): void { ... }
|
||||
pub fn normalize(self: mut this): void { ... }
|
||||
}
|
||||
```
|
||||
|
||||
Key rules:
|
||||
|
||||
* fields private by default
|
||||
* constructor aliases live in type namespace but can never be imported, in the exemplo only `Vector` can be imported.
|
||||
* no static methods
|
||||
* static block values are compile-time constants
|
||||
|
||||
There will never be a conflict between an alias and a method of the same name.
|
||||
A constructor will be called as `let v = Vector.normalize()` and methods will be called as `v.normalize()`.
|
||||
In fact, they call different things, one is static, and the other is an instance method (there are no static methods on structs).
|
||||
|
||||
The static block `[[ ]]` should be static (and generate static on constant pool) and can use only constructors and static values, as helpers.
|
||||
|
||||
---
|
||||
|
||||
## 8. Mutability & Borrow Model (Core Rule)
|
||||
|
||||
This is a foundational rule of PBS.
|
||||
|
||||
Mutability is **never** a property of a type.
|
||||
Mutability belongs **only** to bindings (variables and parameters).
|
||||
|
||||
### 8.1 Immutable by default
|
||||
|
||||
All bindings are immutable unless explicitly marked `mut`.
|
||||
|
||||
```pbs
|
||||
let v = Vector.ZERO; // immutable binding
|
||||
let mut w = Vector.ZERO; // mutable binding (local copy)
|
||||
```
|
||||
|
||||
Some examples of mutable bindings:
|
||||
```pbs
|
||||
let v = Vector.ZERO;
|
||||
v.scale(); // ERROR: cannot mutate a read-only binding
|
||||
|
||||
let mut w = v;
|
||||
w.scale(); // OK: when mut it copies the value, and could be changed
|
||||
|
||||
fn f(v: Vector): Vector
|
||||
{
|
||||
let mut w = v;
|
||||
return w; // when it happens compiler will generate a copy otherwise w will be lost in the stack
|
||||
}
|
||||
|
||||
fn g(v: Vector): void
|
||||
{
|
||||
let vro = f(Vector.ZERO); // OK! and it will be a readonly copy
|
||||
let vrw = mut f(Vector.ZERO); // OK! and it will be a mutable copy of the copy
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 Consequences of binding-based mutability
|
||||
|
||||
* Mutating a value never affects any other binding.
|
||||
* Static values can never be mutated.
|
||||
* There is no aliasing of mutable state.
|
||||
|
||||
### 8.3 Parameters and copying
|
||||
|
||||
Function parameters follow these rules:
|
||||
|
||||
* `T` parameters are passed as **read-only borrows**.
|
||||
* `mut T` parameters create a **local mutable copy**.
|
||||
|
||||
The caller is never affected by mutations performed inside the function.
|
||||
|
||||
### 8.4 Method receivers
|
||||
|
||||
Methods on structs declare mutability explicitly on the receiver:
|
||||
|
||||
```pbs
|
||||
fn len(self: this): float // read-only
|
||||
fn scale(self: mut this): void // mutating
|
||||
```
|
||||
|
||||
A mutating method:
|
||||
|
||||
* requires a **mutable lvalue** at the call site
|
||||
* cannot be called on temporaries or static values
|
||||
|
||||
---
|
||||
|
||||
## 9. Expressions & Control Flow
|
||||
|
||||
* `if / else`
|
||||
* `for` with ranges
|
||||
* `when` expression
|
||||
* `return`
|
||||
|
||||
`when`:
|
||||
|
||||
```pbs
|
||||
let x = when a > b then 1 else 2;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Return Fallback (`else`)
|
||||
|
||||
```pbs
|
||||
fn v(): Vector else Vector.ZERO
|
||||
{
|
||||
if cond return Vector.ONE;
|
||||
}
|
||||
```
|
||||
|
||||
Used to guarantee total functions without boilerplate.
|
||||
|
||||
---
|
||||
|
||||
## 11. Numeric Rules
|
||||
|
||||
* implicit widen: `int → long → float → double`
|
||||
* no implicit narrowing
|
||||
* cast syntax: `expr as Type`
|
||||
|
||||
---
|
||||
|
||||
## 12. `bounded`
|
||||
|
||||
`bounded` is a dedicated scalar type for **indices and sizes**.
|
||||
|
||||
### 12.1 Purpose
|
||||
|
||||
The goal of `bounded` is to make indexing and counting:
|
||||
|
||||
* explicit
|
||||
* safe
|
||||
* visually distinct from general arithmetic
|
||||
|
||||
### 12.2 Representation
|
||||
|
||||
* Internally represented as an unsigned 16-bit integer (`u16`).
|
||||
* Valid range: `0 .. 65535`.
|
||||
|
||||
### 12.3 Usage rules
|
||||
|
||||
`bounded` is used for:
|
||||
|
||||
* array indices
|
||||
* array lengths
|
||||
* default `for` loop counters
|
||||
|
||||
Operations are intentionally limited:
|
||||
|
||||
* allowed: comparison, checked `+` and `-`
|
||||
* disallowed: multiplication, division, bitwise operations
|
||||
|
||||
---
|
||||
|
||||
## 13. Fixed Arrays
|
||||
|
||||
```pbs
|
||||
Array<T>[Nb]
|
||||
```
|
||||
|
||||
* `Nb` is compile-time `bounded` literal
|
||||
* immutable bindings = view
|
||||
* mutable bindings = owned storage
|
||||
|
||||
Supports:
|
||||
|
||||
* indexing (`bounded` only)
|
||||
* slicing `[a..b[` (half-open)
|
||||
|
||||
Return escape model prevents dangling views.
|
||||
|
||||
---
|
||||
|
||||
## 14. `optional<T>`
|
||||
|
||||
`optional<T>` represents the explicit presence or absence of a value.
|
||||
|
||||
### 14.1 Design intent
|
||||
|
||||
* Absence is a **normal, explicit state**.
|
||||
* No traps or implicit unwraps exist.
|
||||
* No heap allocation is involved.
|
||||
|
||||
### 14.2 Extraction rule
|
||||
|
||||
The **only** supported way to extract a value from an optional is with `else`:
|
||||
|
||||
```pbs
|
||||
let x: int = opt else 0;
|
||||
```
|
||||
|
||||
This makes fallback behavior explicit at the call site.
|
||||
|
||||
---
|
||||
|
||||
## 15. `result<T,E>`
|
||||
|
||||
* typed errors
|
||||
* no exceptions
|
||||
* no implicit extraction
|
||||
|
||||
```pbs
|
||||
let v = f()?;
|
||||
```
|
||||
|
||||
### Error handling with `handle`
|
||||
|
||||
`handle` is the *only* construct that allows value extraction from a `result` while mapping errors.
|
||||
|
||||
```pbs
|
||||
let x: int = handle r
|
||||
{
|
||||
ErrorA.not_found => ErrorB.io,
|
||||
ErrorA.denied => ErrorB.permission,
|
||||
_ => ErrorB.unknown,
|
||||
};
|
||||
```
|
||||
|
||||
Semantics:
|
||||
|
||||
* If `r` is `ok(v)`, the expression evaluates to `v`
|
||||
* If `r` is `err(e)`, the first matching arm is selected and an early `return err(mapped)` is executed
|
||||
|
||||
Rules:
|
||||
|
||||
* Arms must be exhaustive (explicit or via `_`)
|
||||
* Right-hand side must be a label of the destination error type
|
||||
* No traps are permitted
|
||||
* **The only possible way to extract a value is by handling the error**
|
||||
|
||||
---
|
||||
|
||||
## 16. What is *deliberately missing* (v0)
|
||||
|
||||
* heap allocation
|
||||
* GC
|
||||
* references
|
||||
* inheritance
|
||||
* traits / interfaces
|
||||
* async
|
||||
* closures
|
||||
* generics (beyond containers)
|
||||
|
||||
---
|
||||
|
||||
## 17. Roadmap (v1+ ideas)
|
||||
|
||||
This is a non-binding list of future directions. None of these are part of v0.
|
||||
|
||||
* generics for `struct`
|
||||
* slice views with runtime bounds
|
||||
* iterator sugar
|
||||
* `defer`
|
||||
* pattern matching on `result`
|
||||
* ABI boundary spec (VM ↔ PBS)
|
||||
* contract versioning
|
||||
|
||||
---
|
||||
|
||||
**This document is now the canonical organized v0 spec.****
|
||||
Loading…
x
Reference in New Issue
Block a user