add struct with visibility

This commit is contained in:
bQUARKz 2026-03-02 17:04:42 +00:00
parent feb82c5bfa
commit 267e28fab9
Signed by: bquarkz
SSH Key Fingerprint: SHA256:Z7dgqoglWwoK6j6u4QC87OveEq74WOhFN+gitsxtkf8
3 changed files with 35 additions and 13 deletions

View File

@ -16,9 +16,9 @@ The question is whether the current contract is already stable enough to unblock
Decision: sufficient for the next phase. Decision: sufficient for the next phase.
The current Host ABI contract is explicit enough to unblock the next stage even if the specification remains marked `Temporary` for now. The current Host ABI contract is explicit enough to unblock the next stage.
`Temporary` should be interpreted here as "final binary-format and integration details may still be hardened", not as "core contract still missing". the final binary-format and integration details may still be hardened, not as "core contract still missing".
## 3. Why This Is Sufficient ## 3. Why This Is Sufficient

View File

@ -78,6 +78,7 @@ Active keywords in `.pbs`:
- `import`, `from`, `as` - `import`, `from`, `as`
- `service`, `host`, `fn`, `apply`, `bind`, `new`, `implements`, `using`, `ctor` - `service`, `host`, `fn`, `apply`, `bind`, `new`, `implements`, `using`, `ctor`
- `declare`, `struct`, `contract`, `error`, `enum`, `callback`, `Self`, `this` - `declare`, `struct`, `contract`, `error`, `enum`, `callback`, `Self`, `this`
- `pub`, `mut`
- `let`, `const` - `let`, `const`
- `if`, `else`, `switch`, `default`, `for`, `from`, `until`, `step`, `while`, `break`, `continue`, `return` - `if`, `else`, `switch`, `default`, `for`, `from`, `until`, `step`, `while`, `break`, `continue`, `return`
- `void`, `optional`, `result` - `void`, `optional`, `result`
@ -87,7 +88,7 @@ Active keywords in `.pbs`:
Barrel-only keywords: Barrel-only keywords:
- `pub`, `mod` - `mod`
- `type` - `type`
Reserved (not active syntax in v1 core): Reserved (not active syntax in v1 core):
@ -139,7 +140,8 @@ Visibility levels:
- `pub`: visible to importing modules. - `pub`: visible to importing modules.
Top-level declarations not listed in `mod.barrel` are file-private. Top-level declarations not listed in `mod.barrel` are file-private.
Using `mod`/`pub` as top-level modifiers inside `.pbs` files is a syntax error. Using `mod` or a top-level standalone `pub` modifier inside `.pbs` files is a syntax error.
Inside ordinary `.pbs` source, `pub` and `mut` are reserved for struct field declarations, with `mut` valid only immediately after `pub`.
For overloaded functions, visibility is per-signature; each exported overload must appear explicitly in `mod.barrel`. For overloaded functions, visibility is per-signature; each exported overload must appear explicitly in `mod.barrel`.
### 5.3 Barrel grammar ### 5.3 Barrel grammar
@ -269,7 +271,9 @@ HostDecl ::= 'declare' 'host' Identifier HostBody
ErrorDecl ::= 'declare' 'error' Identifier ErrorBody ErrorDecl ::= 'declare' 'error' Identifier ErrorBody
EnumDecl ::= 'declare' 'enum' Identifier '(' EnumCaseDecl (',' EnumCaseDecl)* ','? ')' ';' EnumDecl ::= 'declare' 'enum' Identifier '(' EnumCaseDecl (',' EnumCaseDecl)* ','? ')' ';'
StructFieldList ::= StructFieldDecl (',' StructFieldDecl)* ','? StructFieldList ::= StructFieldDecl (',' StructFieldDecl)* ','?
StructFieldDecl ::= Identifier ':' TypeRef StructFieldDecl ::= StructFieldAccess? Identifier ':' TypeRef
StructFieldAccess ::= 'pub' MutOpt
MutOpt ::= 'mut'?
StructMethodBody ::= '{' StructMemberDecl* '}' StructMethodBody ::= '{' StructMemberDecl* '}'
StructMemberDecl ::= StructMethodDecl | StructCtorDecl StructMemberDecl ::= StructMethodDecl | StructCtorDecl
StructMethodDecl ::= 'fn' Identifier ParamList ReturnAnn? Block StructMethodDecl ::= 'fn' Identifier ParamList ReturnAnn? Block
@ -290,7 +294,12 @@ Rules:
- `declare struct Name(...);` declares a heap-backed nominal user type with fields only. - `declare struct Name(...);` declares a heap-backed nominal user type with fields only.
- `declare struct Name(...) { ... }` declares a heap-backed nominal user type with fields and methods. - `declare struct Name(...) { ... }` declares a heap-backed nominal user type with fields and methods.
- Struct fields are declared positionally in the header and are mutable and accessible by default in v1 core. - Struct fields are declared positionally in the header.
- A struct field with no access modifier is private to the enclosing struct body and its `ctor` declarations.
- `pub field: T` permits read access from outside the enclosing struct, but external writes remain invalid.
- `pub mut field: T` permits both read and write access from outside the enclosing struct.
- `mut` is valid in a struct field declaration only immediately after `pub`.
- Methods and `ctor` bodies of the enclosing struct may read and write all of that struct's fields regardless of field access modifier.
- The enclosing struct name is in scope within its own field types, so self-referential headers such as `declare struct Node(next: optional Node);` are valid. - The enclosing struct name is in scope within its own field types, so self-referential headers such as `declare struct Node(next: optional Node);` are valid.
- Struct method and `ctor` declarations belong only in the optional struct body. - Struct method and `ctor` declarations belong only in the optional struct body.
- Struct methods have an implicit `this` receiver and do not declare `this: Self` explicitly. - Struct methods have an implicit `this` receiver and do not declare `this: Self` explicitly.
@ -632,6 +641,7 @@ At minimum, deterministic diagnostics are required for:
- invalid callback declaration shape, - invalid callback declaration shape,
- invalid `Self` type usage, - invalid `Self` type usage,
- invalid `this` usage, - invalid `this` usage,
- invalid struct field access modifier surface,
- invalid struct method declaration shape, - invalid struct method declaration shape,
- invalid service method declaration shape, - invalid service method declaration shape,
- invalid `ctor` declaration shape, - invalid `ctor` declaration shape,
@ -988,7 +998,7 @@ fn demo_callback() -> void {
```pbs ```pbs
declare callback UpdateCb(dt: int) -> void; declare callback UpdateCb(dt: int) -> void;
declare struct Enemy(hp: int); declare struct Enemy(pub hp: int);
fn enemy_tick(self: Enemy, dt: int) -> void { fn enemy_tick(self: Enemy, dt: int) -> void {
let _ = self.hp; let _ = self.hp;
@ -1014,8 +1024,8 @@ declare contract StasisProcess {
declare struct Struct( declare struct Struct(
a: int, a: int,
b: str, pub b: str,
c: float, pub mut c: float,
) { ) {
fn compute_something() -> int { fn compute_something() -> int {
return this.a; return this.a;
@ -1040,10 +1050,13 @@ fn demo_contract() -> int {
let s2 = new Struct.createWithSomethingSpecial(1, 2); let s2 = new Struct.createWithSomethingSpecial(1, 2);
let sp: StasisProcess = s; let sp: StasisProcess = s;
let sp2 = s as StasisProcess; let sp2 = s as StasisProcess;
let visible = s.b;
s.c = 4.0;
let direct = s.compute_something(); let direct = s.compute_something();
let via_contract = sp.stasis(); let via_contract = sp.stasis();
let _ = s2.compute_something(); let _ = s2.compute_something();
let _ = sp2.stasis(); let _ = sp2.stasis();
let _ = visible;
return direct + via_contract; return direct + via_contract;
} }
``` ```

View File

@ -222,7 +222,11 @@ Rules:
- Struct construction arguments are matched positionally to the declared struct field order. - Struct construction arguments are matched positionally to the declared struct field order.
- Assigning a struct value copies the reference, not the underlying field storage. - Assigning a struct value copies the reference, not the underlying field storage.
- Assigning a service value copies the same canonical singleton identity; it does not create a new instance. - Assigning a service value copies the same canonical singleton identity; it does not create a new instance.
- Struct fields are mutable and accessible by default in v1 core. - A struct field with no access modifier is readable and writable only from methods and `ctor` bodies of its enclosing struct.
- A `pub` struct field is externally readable but remains externally non-assignable.
- A `pub mut` struct field is externally readable and externally assignable.
- An assignment target `expr.name` to a struct field is valid only when the access site is permitted to write that field.
- Writes to a private struct field are valid only through `this.name` inside methods and `ctor` bodies of the enclosing struct.
- A struct method declared in a struct body has an implicit receiver binding `this` of type `Self`. - A struct method declared in a struct body has an implicit receiver binding `this` of type `Self`.
- A service method declared in a service body has an implicit receiver binding `this` of type `Self`. - A service method declared in a service body has an implicit receiver binding `this` of type `Self`.
- `this` is valid only inside struct method, service method, and `ctor` bodies. - `this` is valid only inside struct method, service method, and `ctor` bodies.
@ -266,7 +270,7 @@ declare contract StasisProcess {
fn stasis() -> int; fn stasis() -> int;
} }
declare struct Struct(a: int) { declare struct Struct(pub a: int) {
fn compute() -> int { fn compute() -> int {
return this.a; return this.a;
} }
@ -287,7 +291,7 @@ fn demo() -> int {
let s2 = new Struct.createWithSomethingSpecial(2); let s2 = new Struct.createWithSomethingSpecial(2);
let sp: StasisProcess = s; let sp: StasisProcess = s;
let sp2 = s as StasisProcess; let sp2 = s as StasisProcess;
let a = s.compute(); let a = s.a;
let _ = s2.compute(); let _ = s2.compute();
let b = sp.stasis(); let b = sp.stasis();
let c = sp2.stasis(); let c = sp2.stasis();
@ -483,8 +487,9 @@ Rules:
- `TypeName.case` is valid when `TypeName` resolves to a declared enum type and `case` resolves to one of its declared enum cases. - `TypeName.case` is valid when `TypeName` resolves to a declared enum type and `case` resolves to one of its declared enum cases.
- `TypeName.case` has static type `TypeName`. - `TypeName.case` has static type `TypeName`.
- `expr.name` is valid when the static type of `expr` is a declared `struct` containing field `name`. - `expr.name` is valid when the static type of `expr` is a declared `struct` containing field `name` and the access site is permitted to read that field.
- For `struct` field access, the projected member type is the declared field type. - For `struct` field access, the projected member type is the declared field type.
- Reads of a private struct field are valid only through `this.name` inside methods and `ctor` bodies of the enclosing struct.
- `expr.method` is a valid method-call target when the static type of `expr` is a concrete struct type declaring method `method`. - `expr.method` is a valid method-call target when the static type of `expr` is a concrete struct type declaring method `method`.
- `expr.method` over a concrete struct receiver does not search visible contract implementations. - `expr.method` over a concrete struct receiver does not search visible contract implementations.
- `expr.method` is a valid method-call target when the static type of `expr` is a concrete service type declaring method `method`. - `expr.method` is a valid method-call target when the static type of `expr` is a concrete service type declaring method `method`.
@ -503,6 +508,8 @@ Rules:
- `expr.key()` has static type `int`. - `expr.key()` has static type `int`.
- Access to a missing output label is a compile-time error. - Access to a missing output label is a compile-time error.
- Access to a missing struct field is a compile-time error. - Access to a missing struct field is a compile-time error.
- Read access to an inaccessible private struct field is a compile-time error.
- Write access to an inaccessible or non-`pub mut` struct field is a compile-time error.
- Access to a missing struct method is a compile-time error. - Access to a missing struct method is a compile-time error.
- Access to a missing service method is a compile-time error. - Access to a missing service method is a compile-time error.
- Access to a missing host method is a compile-time error. - Access to a missing host method is a compile-time error.
@ -680,6 +687,8 @@ At minimum, deterministic static diagnostics are required for:
- invalid mapped error label in `handle`, - invalid mapped error label in `handle`,
- attempted use of a single-slot tuple literal where no such surface form exists, - attempted use of a single-slot tuple literal where no such surface form exists,
- member access on a missing struct field, - member access on a missing struct field,
- read access to an inaccessible private struct field,
- write access to an inaccessible or non-`pub mut` struct field,
- member access on a missing struct method, - member access on a missing struct method,
- member access on a missing service method, - member access on a missing service method,
- member access on a missing host method, - member access on a missing host method,