362 lines
13 KiB
Markdown
362 lines
13 KiB
Markdown
# PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda
|
|
|
|
## Status
|
|
|
|
Open
|
|
|
|
## Parent Agenda
|
|
|
|
This agenda derives from:
|
|
|
|
- `19. Globals, Synthetic Module Init, and FRAME_RET Agenda`
|
|
|
|
Expected fixed input from previous stage:
|
|
|
|
- `19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda`
|
|
|
|
## Purpose
|
|
|
|
Define the observable lifecycle model of PBS once runtime globals exist.
|
|
|
|
This agenda must close:
|
|
|
|
- whether `[Init]` and `[Frame]` become official source markers;
|
|
- the relationship between module init and program init;
|
|
- boot one-shot behavior;
|
|
- failure policy;
|
|
- and the semantic role of the user's frame root.
|
|
|
|
## Domain Owner
|
|
|
|
`docs/compiler/pbs`
|
|
|
|
Este tema pertence ao domínio PBS porque define lifecycle observável da linguagem, não apenas mecanismo de backend.
|
|
|
|
## Context
|
|
|
|
Depois que `declare global` existir como storage runtime de módulo, o compiler precisará definir:
|
|
|
|
- quando os globals são materializados;
|
|
- em que ordem isso acontece;
|
|
- se existe um hook explícito de init de programa;
|
|
- se existe um init procedural por módulo separado do initializer declarativo de `global`;
|
|
- como a linguagem identifica o frame root do usuário;
|
|
- e o que acontece quando o boot falha.
|
|
|
|
Esta agenda ainda não decide a forma exata do wrapper published entrypoint nem o shape do IR. Ela define primeiro o comportamento observável que essas camadas posteriores terão de respeitar.
|
|
|
|
## Inputs Already Fixed Elsewhere
|
|
|
|
Os seguintes inputs devem ser tratados como fechados ou fortemente estáveis aqui:
|
|
|
|
- o modelo base de globals vindo de `19.1`;
|
|
- o initializer declarativo de `global` permanece restrito a primitivas, `new` e leitura de outras globals compatíveis com o dep graph;
|
|
- top-level `fn` não são permitidas em initializer de `global` em v1;
|
|
- `FRAME_SYNC` permanece como safepoint normativo;
|
|
- PBS v1 continua determinístico e single-threaded;
|
|
- esta fase continua evitando mudanças novas no runtime.
|
|
|
|
## Decisions To Produce
|
|
|
|
Esta agenda deve produzir direção suficiente para fechar:
|
|
|
|
1. se `[Init]` e `[Frame]` entram na surface oficial;
|
|
2. targets válidos, unicidade e assinaturas exigidas;
|
|
3. ordem entre module init, init de programa e frame;
|
|
4. política de boot one-shot;
|
|
5. política de falha;
|
|
6. papel semântico de `frame()` do usuário;
|
|
7. política de loops e host calls admissíveis durante init.
|
|
|
|
## Core Questions
|
|
|
|
1. PBS deve introduzir `[Init]` e `[Frame]` como atributos reservados?
|
|
2. `[Init]` deve ser permitido tanto por módulo quanto no init final de projeto?
|
|
3. `[Frame]` deve existir exatamente uma vez por programa?
|
|
4. `[Init]` deve existir no máximo uma vez por programa?
|
|
5. `[Init]` e `[Frame]` devem exigir assinatura fixa `fn ...() -> void`?
|
|
6. Todos os module inits devem rodar antes do `[Init]` do usuário?
|
|
7. A ausência de `[Init]` deve ser válida?
|
|
8. A ausência de `[Frame]` deve ser erro hard para programa executável?
|
|
9. Em caso de falha durante module init ou `[Init]`, o programa deve falhar definitivamente ou pode haver retry?
|
|
10. Qual é a definição semântica correta de `frame()` do usuário: root lógico do tick, callable publicado, ou apenas callable invocado por infraestrutura sintética futura?
|
|
11. Loops devem ser permitidos em init de módulo e init de projeto?
|
|
12. Host calls devem ser proibidas por padrão durante init?
|
|
13. Apenas host calls marcadas com `[InitAllowed]` devem ser admissíveis durante init?
|
|
14. Como a admissibilidade de `[InitAllowed]` é validada em compile time?
|
|
|
|
## Options
|
|
|
|
### Option A
|
|
|
|
Introduzir `[Init]` e `[Frame]` como markers reservados explícitos, com assinaturas fixas, `[Init]` opcional por módulo e por projeto, `[Frame]` obrigatório e único por projeto executável, permitindo init procedural por módulo e mantendo política restritiva de host interaction durante init.
|
|
|
|
### Option B
|
|
|
|
Introduzir apenas `[Frame]` e manter init inteiramente sintético, sem hook de programa do usuário nesta fase.
|
|
|
|
### Option C
|
|
|
|
Manter lifecycle implícito, sem markers source-level, e continuar derivando entrypoint/configuração fora da linguagem.
|
|
|
|
## Tradeoffs
|
|
|
|
### Option A
|
|
|
|
- Prós:
|
|
- deixa lifecycle explícito na linguagem;
|
|
- reduz dependência de configuração paralela;
|
|
- dá base clara para wrapper, manifest e lowering posteriores.
|
|
- Contras:
|
|
- amplia a surface de atributos reservados;
|
|
- exige validação de target, unicidade e assinatura.
|
|
|
|
### Option B
|
|
|
|
- Prós:
|
|
- escopo menor;
|
|
- adia parte da discussão de init.
|
|
- Contras:
|
|
- resolve só metade do lifecycle;
|
|
- pode forçar redesign quando o hook de init do usuário voltar.
|
|
|
|
### Option C
|
|
|
|
- Prós:
|
|
- menor custo imediato.
|
|
- Contras:
|
|
- mantém a autoridade do lifecycle fora da linguagem;
|
|
- enfraquece a coerência da série 19.
|
|
|
|
## Recommendation
|
|
|
|
Seguir com a **Option A**.
|
|
|
|
Direção recomendada:
|
|
|
|
1. `[Init]` e `[Frame]` devem ser markers reservados explícitos;
|
|
2. `declare global` sempre lowera para o init sintético do módulo owner;
|
|
3. `[Init]` de módulo deve ser opcional e executar depois de todos os `declare global` do módulo;
|
|
4. o init de projeto deve seguir o mesmo modelo, mas associado ao projeto que contém o `[Frame]`;
|
|
5. `[Init]` de projeto deve ser opcional;
|
|
6. `[Frame]` deve ser obrigatório para programa executável e único por projeto;
|
|
7. `[Init]` e `[Frame]` devem exigir assinatura fixa `fn name() -> void`;
|
|
8. boot deve ser one-shot;
|
|
9. falha de boot deve seguir direção fail-fast, salvo argumento forte em contrário;
|
|
10. loops devem ser permitidos em init de módulo e init de projeto;
|
|
11. host calls devem ser proibidas por padrão durante init;
|
|
12. apenas host calls com atributo reservado `[InitAllowed]` devem ser admissíveis durante init;
|
|
13. `[InitAllowed]` é atributo reservado de SDK, não userland.
|
|
|
|
## Additional Lifecycle Concerns
|
|
|
|
Esta agenda também precisa fechar a separação entre três camadas de bootstrap:
|
|
|
|
1. initializer declarativo de `global`;
|
|
2. init por módulo;
|
|
3. init de projeto.
|
|
|
|
Direção herdada da `19.1`:
|
|
|
|
- `global` materializa storage inicial;
|
|
- init de módulo executa lógica procedural de conveniência sobre globals do próprio módulo;
|
|
- init de projeto executa coordenação final do programa.
|
|
|
|
Com esse modelo:
|
|
|
|
- loops são legítimos em init de módulo e init de projeto, especialmente para carga e preparação de arrays e estruturas derivadas;
|
|
- a restrição normativa mais forte deve cair sobre host interaction;
|
|
- "bootstrap leve" continua sendo recomendação de design, não um limite impossível de verificar semanticamente.
|
|
|
|
## Current Direction
|
|
|
|
Os pontos abaixo já podem ser tratados como direção fechada desta agenda, salvo objeção nova forte:
|
|
|
|
1. `[Init]` e `[Frame]` entram como atributos reservados explícitos;
|
|
2. `declare global X: T = expr;` lowera sempre para o init sintético do módulo owner;
|
|
3. cada arquivo pode declarar opcionalmente um `[Init]` procedural próprio;
|
|
4. o `[Init]` de cada arquivo roda sempre depois das globals daquele arquivo e participa do init sintético do módulo;
|
|
5. existe também um init de projeto opcional, que é o `[Init]` associado ao projeto que contém o `[Frame]`;
|
|
6. `[Frame]` é obrigatório e único por projeto executável;
|
|
7. `[Init]` e `[Frame]` seguem a forma recomendada:
|
|
|
|
```pbs
|
|
[Init]
|
|
fn init() -> void { ... }
|
|
```
|
|
|
|
```pbs
|
|
[Frame]
|
|
fn frame() -> void { ... }
|
|
```
|
|
|
|
8. a assinatura exigida é sempre `fn name() -> void`;
|
|
9. loops são permitidos nos inits;
|
|
10. host calls são proibidas por padrão durante init;
|
|
11. apenas host calls com `[InitAllowed]` podem ser usadas durante init;
|
|
12. `[InitAllowed]` pertence às superfícies reservadas de SDK, não a userland;
|
|
13. falha de boot é fail-fast com mensagem coerente.
|
|
|
|
Também fica fechada a seguinte regra operacional:
|
|
|
|
14. o `[Init]` que estiver no mesmo arquivo que o `[Frame]` é o init de projeto;
|
|
15. `[Init]` em outros arquivos continuam sendo init de módulo;
|
|
16. `[Frame]` e o init de projeto devem ser co-localizados no mesmo arquivo por decisão deliberada de source organization.
|
|
17. cada arquivo pode declarar no máximo um `[Init]`;
|
|
18. cada módulo possui exatamente um init sintético de módulo, dentro do qual os inits por arquivo são ordenados e compostos;
|
|
19. a distinção entre init de módulo e init de projeto é apenas de ordenação e papel semântico, não de surface diferente;
|
|
20. como consequência, existe no máximo um `[Init]` de projeto por projeto executável.
|
|
21. arquivos sem globals podem declarar um `[Init]`, desde que continuem respeitando a regra de no máximo um `[Init]` por arquivo;
|
|
22. o `project init` segue exatamente a mesma assinatura `fn init() -> void`.
|
|
|
|
## Lifecycle Order Direction
|
|
|
|
Esta agenda também já aponta para a seguinte ordem lógica de bootstrap:
|
|
|
|
1. materialização das globals de cada arquivo do módulo conforme a ordem determinada pelo dependency graph;
|
|
2. execução do `[Init]` daquele arquivo, quando existir;
|
|
3. composição desses passos em um único init sintético do módulo;
|
|
4. depois do fechamento dos módulos necessários, execução do `[Init]` de projeto, quando existir;
|
|
5. entrada no primeiro `frame()`.
|
|
|
|
Lendo essa ordem de forma operacional:
|
|
|
|
1. cada arquivo inicializa suas próprias globals;
|
|
2. cada arquivo pode então executar seu `[Init]` opcional;
|
|
3. tudo isso se aninha dentro de um único init sintético por módulo;
|
|
4. o `[Init]` co-localizado com `[Frame]` é elevado a init de projeto por ordem e papel semântico.
|
|
|
|
Também fica fechada a seguinte direção adicional:
|
|
|
|
5. a ordem entre arquivos do mesmo módulo deve seguir a ordem derivada do `DependencyGraphAnaliser` das globals;
|
|
6. quando dois arquivos não tiverem dependência entre si, o compiler deve usar uma ordem determinística estável.
|
|
|
|
## Remaining Open Points
|
|
|
|
Com a direção já consolidada nesta agenda, não restam pontos substantivos em aberto dentro do boundary de `19.2`.
|
|
|
|
Os temas seguintes agora pertencem à `19.3`.
|
|
|
|
## InitAllowed Direction
|
|
|
|
Esta agenda fecha também o seguinte shape normativo inicial para `[InitAllowed]`:
|
|
|
|
1. `[InitAllowed]` é um atributo reservado sem argumentos em v1;
|
|
2. ele é válido apenas em host methods de SDK;
|
|
3. ele é inválido em userland;
|
|
4. ele é inválido em `fn`, `global`, `service` e demais superfícies que não sejam host methods de SDK;
|
|
5. seu papel é exclusivamente validar, em compile time, quais host calls podem aparecer durante init;
|
|
6. ele não faz distinção entre init de módulo e init de projeto;
|
|
7. a diferença entre esses inits é de ordenação e papel semântico, não de permissão separada de host call.
|
|
|
|
Exemplo recomendado:
|
|
|
|
```pbs
|
|
declare host Runtime {
|
|
[Host(module = "runtime", name = "random_u32", version = 1)]
|
|
[Capability(name = "runtime")]
|
|
[InitAllowed]
|
|
fn random_u32() -> int;
|
|
}
|
|
```
|
|
|
|
## Diagnostics Recommendation
|
|
|
|
Esta agenda fecha o seguinte catálogo mínimo de diagnósticos de lifecycle e bootstrap.
|
|
|
|
### 1. Project Init Must Be Colocated With Frame
|
|
|
|
Mensagem semântica recomendada:
|
|
|
|
- `project init must be colocated with frame`
|
|
|
|
### 2. Multiple Project Init Functions Detected
|
|
|
|
Mensagem semântica recomendada:
|
|
|
|
- `multiple project init functions detected`
|
|
|
|
### 3. Multiple Frame Functions Detected
|
|
|
|
Mensagem semântica recomendada:
|
|
|
|
- `multiple frame functions detected`
|
|
|
|
### 4. Missing Frame Function For Executable Project
|
|
|
|
Mensagem semântica recomendada:
|
|
|
|
- `missing frame function for executable project`
|
|
|
|
### 5. Invalid Init Signature
|
|
|
|
Mensagem semântica recomendada:
|
|
|
|
- `init function must have signature fn name() -> void`
|
|
|
|
### 6. Invalid Frame Signature
|
|
|
|
Mensagem semântica recomendada:
|
|
|
|
- `frame function must have signature fn name() -> void`
|
|
|
|
### 7. Host Call Not Allowed During Init
|
|
|
|
Mensagem semântica recomendada:
|
|
|
|
- `host call not allowed during init`
|
|
|
|
### 8. Invalid InitAllowed Target
|
|
|
|
Mensagem semântica recomendada:
|
|
|
|
- `InitAllowed is valid only on SDK host methods`
|
|
|
|
### 9. Boot Failed During Module Init
|
|
|
|
Mensagem semântica recomendada:
|
|
|
|
- `boot failed during module init`
|
|
|
|
### 10. Boot Failed During Project Init
|
|
|
|
Mensagem semântica recomendada:
|
|
|
|
- `boot failed during project init`
|
|
|
|
### 11. Multiple Module Init Functions Detected
|
|
|
|
Mensagem semântica recomendada:
|
|
|
|
- `multiple module init functions detected`
|
|
|
|
### 12. Init Attribute Target Invalid
|
|
|
|
Mensagem semântica recomendada:
|
|
|
|
- `Init attribute target invalid`
|
|
|
|
## Expected Spec Material
|
|
|
|
Se esta agenda fechar, a propagação esperada atinge pelo menos:
|
|
|
|
- `3. Core Syntax Specification.md`
|
|
- `4. Static Semantics Specification.md`
|
|
- `9. Dynamic Semantics Specification.md`
|
|
- `12. Diagnostics Specification.md`
|
|
|
|
## Non-Goals
|
|
|
|
Esta agenda não deve:
|
|
|
|
1. decidir o nome físico do wrapper published entrypoint;
|
|
2. decidir o nome físico do entrypoint no manifest;
|
|
3. definir shape de IR;
|
|
4. definir como `FRAME_RET` será reposicionado materialmente.
|
|
|
|
## Next Step
|
|
|
|
Depois de fechar esta agenda, abrir ou aprofundar:
|
|
|
|
- `19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda`
|