globals and synthetic inits
This commit is contained in:
parent
f49dc64fe0
commit
ecea7e96c0
@ -4,6 +4,26 @@
|
||||
|
||||
Open
|
||||
|
||||
## Purpose
|
||||
|
||||
Define how PBS should introduce runtime globals and lifecycle-driven executable bootstrap without changing the runtime contract in this phase.
|
||||
|
||||
This document is the umbrella agenda for topic `19`.
|
||||
|
||||
It exists to:
|
||||
|
||||
- keep the full problem framed in one place;
|
||||
- define the dependency order between discussions;
|
||||
- prevent later discussions from re-opening earlier boundaries casually;
|
||||
- and provide the parent reference for any follow-up agendas created under this topic.
|
||||
|
||||
This agenda must converge on:
|
||||
|
||||
- the source-level model for mutable module storage;
|
||||
- the lifecycle model for module init, optional program init, and frame execution;
|
||||
- the ownership of `FRAME_RET` once the published entrypoint stops being the user's `frame()` directly;
|
||||
- the migration path from explicit `FrontendSpec` entrypoint configuration to source-derived PBS entrypoint discovery.
|
||||
|
||||
## Domain Owner
|
||||
|
||||
`docs/compiler/pbs`
|
||||
@ -66,10 +86,10 @@ O cenário motivador é permitir globals de módulo no PBS sem exigir, nesta fas
|
||||
Também queremos aproveitar essa discussão para mover a detecção de entrypoint para a source language do PBS, usando atributos explícitos:
|
||||
|
||||
```pbs
|
||||
[INIT]
|
||||
[Init]
|
||||
fn init() -> void {}
|
||||
|
||||
[FRAME]
|
||||
[Frame]
|
||||
fn frame() -> void {}
|
||||
```
|
||||
|
||||
@ -82,9 +102,9 @@ Essa direção permitiria ao frontend PBS:
|
||||
|
||||
Esta agenda também cobre a extensão desse modelo para discutir:
|
||||
|
||||
1. se `[INIT]` deve existir apenas como hook final de programa ou também como surface por módulo;
|
||||
2. qual é exatamente o comportamento operacional de `[FRAME]` como root lógico de frame do usuário;
|
||||
3. como `[INIT]` por módulo, `[INIT]` final de programa, wrapper sintético e `FRAME_RET` se compõem sem ambiguidade.
|
||||
1. se `[Init]` deve existir apenas como hook final de programa ou também como surface por módulo;
|
||||
2. qual é exatamente o comportamento operacional de `[Frame]` como root lógico de frame do usuário;
|
||||
3. como `[Init]` por módulo, `[Init]` final de programa, wrapper sintético e `FRAME_RET` se compõem sem ambiguidade.
|
||||
|
||||
Isso empurra a solução para o compiler:
|
||||
|
||||
@ -95,6 +115,16 @@ Isso empurra a solução para o compiler:
|
||||
5. detecção de `init`/`frame` a partir de atributos de source;
|
||||
6. remoção progressiva das configs explícitas atuais em `FrontendSpec`.
|
||||
|
||||
## Inputs
|
||||
|
||||
Relevant inputs already present in the repository:
|
||||
|
||||
- `docs/vm-arch/ISA_CORE.md` already exposes `GET_GLOBAL` and `SET_GLOBAL`;
|
||||
- `docs/compiler/pbs/specs/13. Lowering IRBackend Specification.md` currently requires a canonical executable entrypoint to be declared through `FrontendSpec`;
|
||||
- `docs/compiler/pbs/specs/7. Cartridge Manifest and Runtime Capabilities Specification.md` currently expects PBS v1 manifest `entrypoint` to align with frontend-declared `frame`.
|
||||
|
||||
The discussion here must preserve compatibility with those contracts unless it explicitly proposes the propagation work needed to evolve them.
|
||||
|
||||
## Core Questions
|
||||
|
||||
1. PBS deve introduzir `declare global` como declaração top-level distinta de `declare const`?
|
||||
@ -102,10 +132,10 @@ Isso empurra a solução para o compiler:
|
||||
3. O compiler deve sintetizar um module init por módulo que contenha `declare global`?
|
||||
4. A inicialização deve rodar eager no boot lógico do programa ou lazy no primeiro frame?
|
||||
5. Deve existir um `init()` custom do usuário que roda depois de todos os module inits e antes do primeiro `frame()`?
|
||||
6. O PBS deve introduzir atributos explícitos `[INIT]` e `[FRAME]` para identificar as funções corretas do usuário?
|
||||
6. O PBS deve introduzir atributos explícitos `[Init]` e `[Frame]` para identificar as funções corretas do usuário?
|
||||
7. A descoberta de entrypoint no frontend PBS deve deixar de depender de configuração explícita em `FrontendSpec`?
|
||||
8. `[INIT]` deve poder existir também em escopo/módulo de forma declarativa para orientar module init explícito, ou o compiler deve manter module init sempre totalmente sintético?
|
||||
9. Qual é o contrato preciso de comportamento de `[FRAME]` no PBS: callable obrigatório, assinatura fixa, frequência esperada e relação com o frame lógico publicado?
|
||||
8. `[Init]` deve poder existir também em escopo/módulo de forma declarativa para orientar module init explícito, ou o compiler deve manter module init sempre totalmente sintético?
|
||||
9. Qual é o contrato preciso de comportamento de `[Frame]` no PBS: callable obrigatório, assinatura fixa, frequência esperada e relação com o frame lógico publicado?
|
||||
10. O published frame entrypoint deve passar a ser um wrapper sintético, por exemplo `__pbs_frame()`, em vez do `frame()` do usuário?
|
||||
11. `FRAME_RET` deve continuar significando "fim do frame lógico" e apenas mudar de owner, saindo da função do usuário para o wrapper sintético?
|
||||
12. Como o compiler deve tratar ordem topológica, dependências e ciclos entre globals de módulos distintos?
|
||||
@ -123,11 +153,31 @@ Os seguintes pontos já parecem fixos ou fortemente estabelecidos e não devem s
|
||||
- o frontend PBS hoje ainda carrega configuração explícita de entrypoint fora da source language;
|
||||
- nesta fase queremos evitar mudanças novas no runtime e concentrar a evolução no compiler.
|
||||
|
||||
## Decisions To Produce
|
||||
|
||||
Como umbrella agenda, esta agenda não deve tentar fechar toda a solução normativa de uma vez.
|
||||
|
||||
Ela deve sair com:
|
||||
|
||||
1. a decomposição oficial do tema em discussões derivadas;
|
||||
2. a ordem canônica dessas discussões;
|
||||
3. os inputs e outputs esperados de cada boundary;
|
||||
4. a lista de artefatos que não podem ser editados antes do boundary anterior fechar.
|
||||
|
||||
Depois que as discussões derivadas fecharem, o conjunto deve produzir direção suficiente para virar uma `decision` cobrindo pelo menos:
|
||||
|
||||
1. a surface syntax e o modelo semântico de `declare global`;
|
||||
2. o modelo de bootstrap entre module init sintético, `[Init]` de programa e `[Frame]`;
|
||||
3. o owner real do frame lógico publicado e o ponto correto de emissão de `FRAME_RET`;
|
||||
4. a política de descoberta de entrypoint a partir da source language do PBS;
|
||||
5. a política de ordenação, ciclos e falhas para globals e module init;
|
||||
6. a política de imports/exports para globals entre módulos.
|
||||
|
||||
## Options
|
||||
|
||||
### Option A
|
||||
|
||||
Adicionar `declare global`, introduzir `[INIT]` e `[FRAME]` como superfícies explícitas para lifecycle/entrypoint, discutir `[INIT]` final vs `[INIT]` por módulo, gerar module init sintético por módulo, gerar wrapper sintético de frame published entrypoint e mover o `FRAME_RET` para esse wrapper.
|
||||
Adicionar `declare global`, introduzir `[Init]` e `[Frame]` como superfícies explícitas para lifecycle/entrypoint, discutir `[Init]` final vs `[Init]` por módulo, gerar module init sintético por módulo, gerar wrapper sintético de frame published entrypoint e mover o `FRAME_RET` para esse wrapper.
|
||||
|
||||
### Option B
|
||||
|
||||
@ -155,7 +205,7 @@ Adicionar `declare global`, mas exigir lazy materialization no primeiro acesso e
|
||||
- remove um acoplamento indesejado entre frontend PBS e configuração manual de entrypoint em `FrontendSpec`.
|
||||
- Contras:
|
||||
- exige nova modelagem no compiler para globals, init synthesis e published frame wrapper;
|
||||
- exige regras novas de atributo e validação de unicidade para `[INIT]` e `[FRAME]`;
|
||||
- exige regras novas de atributo e validação de unicidade para `[Init]` e `[Frame]`;
|
||||
- obriga decisão clara sobre ordem, ciclos e falhas;
|
||||
- muda a relação atual entre `frame()` do usuário e entrypoint publicado.
|
||||
|
||||
@ -201,86 +251,439 @@ Direção recomendada para discussão:
|
||||
2. permitir inicializadores executáveis lowerables, incluindo `new` e calls compatíveis com o modelo de lowering executável;
|
||||
3. sintetizar um module init por módulo owner de globals;
|
||||
4. ordenar os module inits de forma determinística e topológica;
|
||||
5. introduzir `[INIT]` e `[FRAME]` como superfícies explícitas de detecção do init/frame do usuário;
|
||||
5. introduzir `[Init]` e `[Frame]` como superfícies explícitas de detecção do init/frame do usuário;
|
||||
6. remover da evolução do PBS a dependência de configuração explícita de entrypoint em `FrontendSpec`, migrando a seleção para a análise da source language;
|
||||
7. discutir explicitamente se `[INIT]` por módulo será uma surface do usuário ou se módulo continuará com init apenas sintético;
|
||||
7. discutir explicitamente se `[Init]` por módulo será uma surface do usuário ou se módulo continuará com init apenas sintético;
|
||||
8. permitir um `init()` custom opcional do usuário, executado depois de todos os module inits;
|
||||
9. publicar um wrapper sintético de frame, por exemplo `__pbs_frame()`, como verdadeiro frame root;
|
||||
10. tratar `frame()` do usuário como callable normal invocado por esse wrapper;
|
||||
11. manter `FRAME_RET` como marcador do fim do frame lógico, mas emitido no wrapper sintético publicado em vez de no `frame()` do usuário;
|
||||
12. manter toda a primeira fase restrita ao compiler e ao backend pipeline, sem novos requisitos para o runtime além dos contratos já existentes.
|
||||
|
||||
Essa recomendação ainda deixa alguns pontos para fechamento na `decision`, mas já estabelece um shape arquitetural coerente:
|
||||
|
||||
- storage global pertence ao módulo owner;
|
||||
- bootstrap observável pertence ao compiler, não ao runtime;
|
||||
- `frame()` do usuário deixa de ser o entrypoint publicado e passa a ser o root lógico invocado pelo wrapper;
|
||||
- `FRAME_RET` continua significando fim do frame lógico, apenas com novo owner sintético;
|
||||
- a seleção de entrypoint deixa de ser configuração paralela e vira semântica explícita da linguagem.
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. O nome surface deve ser exatamente `declare global`, ou outra forma top-level?
|
||||
2. Globals devem exigir initializer obrigatório em v1, ou existirão shells reservados parecidos com builtin const?
|
||||
3. `[INIT]` e `[FRAME]` devem ser atributos reservados do PBS ou outra forma de marker surface?
|
||||
4. `[INIT]` deve exigir assinatura fixa `fn init() -> void`?
|
||||
5. `[FRAME]` deve exigir assinatura fixa `fn frame() -> void`?
|
||||
6. Deve existir no máximo um `[INIT]` e um `[FRAME]` por programa, por módulo owner, ou por outro escopo?
|
||||
7. `[INIT]` por módulo deve ser permitido como surface explícita do usuário ou ser non-goal da primeira fase?
|
||||
8. Se `[INIT]` por módulo existir, ele roda antes ou no lugar do module init sintético de globals?
|
||||
9. A ausência de `[INIT]` deve ser válida, mas a ausência de `[FRAME]` deve ser erro hard?
|
||||
10. O `init()` do usuário pertence apenas ao módulo owner do published frame entrypoint ou pode vir de qualquer módulo visível?
|
||||
11. O compiler deve sintetizar `boot_done` como global oculto de programa, local estático do wrapper, ou outro mecanismo interno?
|
||||
12. Em caso de trap/falha durante module init ou `init()`, o próximo frame deve tentar novamente ou o programa deve entrar em estado terminal?
|
||||
13. Módulos podem ler globals de outros módulos durante init, desde que a ordem topológica já os tenha materializado?
|
||||
14. Como diagnosticar ciclos entre globals intra-módulo e inter-módulo de forma didática?
|
||||
15. Qual é a semântica exata de `[FRAME]` para o compiler e para a documentação da linguagem: raiz de tick, raiz de frame lógico, ou apenas callable nomeado para publicação?
|
||||
16. O barrel/export de `global` deve seguir a mesma superfície de `const`, ou precisamos de distinção explícita na documentação/export metadata?
|
||||
17. O `IRBackend` deve ganhar instruções explícitas `GET_GLOBAL`/`SET_GLOBAL`, ou globals devem ser lowered por outra representação intermediária antes de virar bytecode?
|
||||
18. Em que etapa da migração a configuração explícita atual em `FrontendSpec` deixa de existir por completo?
|
||||
3. `[Init]` e `[Frame]` devem ser atributos reservados do PBS ou outra forma de marker surface?
|
||||
4. `[Init]` deve exigir assinatura fixa `fn init() -> void`?
|
||||
5. `[Frame]` deve exigir assinatura fixa `fn frame() -> void`?
|
||||
6. Deve existir no máximo um `[Init]` e um `[Frame]` por programa, por módulo owner, ou por outro escopo?
|
||||
7. Module init deve permanecer sempre sintético em v1, ou o usuário pode anotar hooks por módulo em alguma forma futura?
|
||||
8. A política de falha de init deve ser fail-fast definitivo no boot, ou existe algum caso legítimo para retry controlado?
|
||||
9. Reexport de globals entre módulos deve preservar identidade de storage do owner original ou materializar aliases/import bindings sem storage próprio?
|
||||
10. O manifest `entrypoint` deve continuar expondo `frame` por compatibilidade nominal ou passar a refletir o símbolo sintético publicado?
|
||||
|
||||
## Expected Decisions to Produce
|
||||
## Main Difficulties
|
||||
|
||||
1. A surface language e a gramática de `declare global`.
|
||||
2. A surface language e a política de detecção de entrypoint via `[INIT]` e `[FRAME]`.
|
||||
3. O papel de `[INIT]` por módulo versus module init totalmente sintético.
|
||||
4. O contrato semântico de globals de módulo em PBS.
|
||||
5. O modelo de inicialização sintética por módulo.
|
||||
6. O contrato de `init()` custom do usuário.
|
||||
7. A semântica comportamental de `[FRAME]` como root lógico do usuário.
|
||||
8. A política de ordering e ciclo para init/global dependencies.
|
||||
9. O novo owner do `FRAME_RET` no pipeline de frame.
|
||||
10. O plano de remoção das configs explícitas atuais em `FrontendSpec`.
|
||||
11. O recorte exato desta fase como mudança somente de compiler.
|
||||
Os principais pontos de dificuldade desta agenda não são sintáticos; eles estão na composição entre contratos já existentes.
|
||||
|
||||
### 1. `declare global` colide com o recorte atual de `declare const`
|
||||
|
||||
Hoje a semântica estática do PBS fixa que:
|
||||
|
||||
- `declare const` entra no value namespace;
|
||||
- `declare const` não materializa storage mutável runtime;
|
||||
- inicializadores de `declare const` pertencem a um subset estritamente compile-time;
|
||||
- dependências entre `declare const` são acíclicas e resolvidas por análise de dependência, não por ordem textual.
|
||||
|
||||
Introduzir `declare global` exige decidir o que é reaproveitado desse modelo e o que deixa de valer:
|
||||
|
||||
- namespace e visibilidade podem reaproveitar parte do modelo atual;
|
||||
- constant evaluation não pode ser reutilizada como está;
|
||||
- o modelo de dependência deixa de ser apenas compile-time e passa a produzir efeitos runtime.
|
||||
|
||||
### 2. A surface de atributos hoje tem um conjunto reservado fechado
|
||||
|
||||
O PBS já trata atributos como metadata compile-time com lowering explícito apenas quando outra spec define esse efeito.
|
||||
|
||||
Isso é favorável para `[Init]` e `[Frame]`, mas cria trabalho em três frentes:
|
||||
|
||||
- reservar novos atributos no conjunto normativo;
|
||||
- definir targets válidos, unicidade e diagnóstico;
|
||||
- definir o lowering sem deixar atributos "soltos" como metadata sem efeito operacional claro.
|
||||
|
||||
### 3. O entrypoint publicado hoje ainda está acoplado ao `FrontendSpec`
|
||||
|
||||
Existe uma obrigação atual em `13. Lowering IRBackend Specification.md` para o frontend declarar um `EntrypointRef` canônico.
|
||||
|
||||
A agenda 19 quer mover a descoberta para a source language, mas isso abre uma transição delicada:
|
||||
|
||||
- PBS precisa derivar esse `EntrypointRef` da source language;
|
||||
- o contrato de `IRBackend` não deve perder determinismo;
|
||||
- a migração não pode deixar coexistirem por muito tempo duas autoridades independentes para entrypoint.
|
||||
|
||||
### 4. O manifest ainda assume `frame` como callable publicado
|
||||
|
||||
`7. Cartridge Manifest and Runtime Capabilities Specification.md` hoje sugere alinhamento nominal entre manifest `entrypoint` e callable `frame`.
|
||||
|
||||
Se o compiler publicar `__pbs_frame()`:
|
||||
|
||||
- ou o manifest passa a refletir o símbolo sintético real;
|
||||
- ou o manifest preserva um nome lógico enquanto o símbolo real do artefato muda;
|
||||
- ou a pipeline passa a distinguir entrypoint lógico e entrypoint físico.
|
||||
|
||||
Sem fechar isso, a solução de wrapper fica tecnicamente incompleta.
|
||||
|
||||
### 5. `FRAME_RET` hoje coincide com o fim do callable do usuário
|
||||
|
||||
O ponto difícil não é só "mover um opcode". É redefinir qual callable delimita semanticamente o frame lógico:
|
||||
|
||||
- `frame()` do usuário continua sendo apenas código de frame;
|
||||
- o wrapper sintético vira o owner do frame published entrypoint;
|
||||
- `FRAME_RET` continua com o mesmo significado semântico, mas sua posição material muda.
|
||||
|
||||
Isso afeta lowering, testes de conformance e a forma de explicar o modelo da linguagem.
|
||||
|
||||
### 6. Globals intermodulares introduzem um problema novo de identidade e ordem
|
||||
|
||||
Hoje `declare const` exportado via `mod.barrel` é simples porque não há storage mutável compartilhado.
|
||||
|
||||
Com `declare global`, a agenda precisa fechar:
|
||||
|
||||
- quem é o owner real do storage;
|
||||
- o que um import recebe: binding para o owner ou cópia/snapshot;
|
||||
- como ciclos entre módulos são detectados;
|
||||
- se init pode ler globals de módulos predecessores;
|
||||
- qual é a ordem determinística entre módulos quando há efeitos de inicialização.
|
||||
|
||||
### 7. A política de falha deixa de ser apenas rejeição de build
|
||||
|
||||
Hoje boa parte do pipeline falha antes da emissão.
|
||||
|
||||
Com module init e `init()` do usuário, surge um problema runtime-observable:
|
||||
|
||||
- o que acontece quando o boot parcial falha;
|
||||
- se o programa entra em estado terminal;
|
||||
- se existe retry;
|
||||
- como isso se relaciona com o fato de `FRAME_SYNC` permanecer o safepoint normativo.
|
||||
|
||||
## Work Boundaries
|
||||
|
||||
Para manter a agenda executável e evitar mistura de artefatos, o trabalho pode ser separado nos seguintes boundaries.
|
||||
|
||||
### Boundary A. Surface Language and AST
|
||||
|
||||
Owner principal: syntax + AST.
|
||||
|
||||
Inclui:
|
||||
|
||||
- gramática de `declare global`;
|
||||
- superfície de atributos `[Init]` e `[Frame]`;
|
||||
- targets permitidos desses atributos;
|
||||
- novos nós ou flags obrigatórios no AST para globals e lifecycle markers.
|
||||
|
||||
Pergunta de fechamento:
|
||||
|
||||
- o parser apenas aceita as superfícies ou já impõe parte das restrições estruturais de target/shape?
|
||||
|
||||
### Boundary B. Static Semantics and Linking
|
||||
|
||||
Owner principal: static semantics + linking.
|
||||
|
||||
Inclui:
|
||||
|
||||
- namespace e visibilidade de `declare global`;
|
||||
- regras de initializer obrigatório ou opcional;
|
||||
- compatibilidade de tipo do initializer;
|
||||
- unicidade e assinatura válida para `[Init]` e `[Frame]`;
|
||||
- regras de import/export/barrel para globals;
|
||||
- detecção de ciclos de dependência entre globals;
|
||||
- política de identidade do storage através de imports e reexports.
|
||||
|
||||
Pergunta de fechamento:
|
||||
|
||||
- globals entram no mesmo value namespace de `let`/`declare const` ou exigem distinção semântica adicional apesar do namespace compartilhado?
|
||||
|
||||
### Boundary C. Dynamic Semantics and Lifecycle Model
|
||||
|
||||
Owner principal: dynamic semantics.
|
||||
|
||||
Inclui:
|
||||
|
||||
- ordem observável entre module init, `[Init]` de programa e `[Frame]`;
|
||||
- definição de boot one-shot;
|
||||
- política de falha de init;
|
||||
- contrato semântico de `[Frame]` como raiz lógica do tick/frame do usuário;
|
||||
- relação entre frame lógico do usuário e entrypoint efetivamente publicado.
|
||||
|
||||
Pergunta de fechamento:
|
||||
|
||||
- o programa tem dois conceitos distintos, `logical frame root` e `published runtime entrypoint`, ou a spec tenta esconder essa distinção do usuário?
|
||||
|
||||
### Boundary D. IR and Backend Lowering
|
||||
|
||||
Owner principal: lowering executável.
|
||||
|
||||
Inclui:
|
||||
|
||||
- representação de globals no `IRBackend` ou boundary imediatamente anterior;
|
||||
- synthesis de module init;
|
||||
- synthesis de wrapper published entrypoint;
|
||||
- materialização do guard one-shot de boot;
|
||||
- reposicionamento do `FRAME_RET`;
|
||||
- preservação do `EntrypointRef` canônico para o restante do backend.
|
||||
|
||||
Pergunta de fechamento:
|
||||
|
||||
- globals entram como primitivo explícito no IR ou aparecem apenas em lowering posterior antes de IRVM/bytecode?
|
||||
|
||||
### Boundary E. Artifact and Manifest Publication
|
||||
|
||||
Owner principal: artifact contracts.
|
||||
|
||||
Inclui:
|
||||
|
||||
- nome do entrypoint exposto no manifest;
|
||||
- relação entre callable do usuário, símbolo sintético e entrypoint published;
|
||||
- compatibilidade com o contrato atual do cartridge manifest;
|
||||
- possíveis ajustes na leitura de tooling sobre qual callable é o entrypoint "real".
|
||||
|
||||
Pergunta de fechamento:
|
||||
|
||||
- o manifest publica identidade lógica da linguagem ou identidade física do artefato executável?
|
||||
|
||||
### Boundary F. Diagnostics and Conformance
|
||||
|
||||
Owner principal: diagnostics + fixture model.
|
||||
|
||||
Inclui:
|
||||
|
||||
- diagnósticos para target inválido de `[Init]` e `[Frame]`;
|
||||
- duplicidade ou ausência de markers obrigatórios;
|
||||
- initializer inválido de `declare global`;
|
||||
- ciclos intra/inter-módulo;
|
||||
- imports/reexports ilegais de globals;
|
||||
- fixture coverage para init ordering, wrapper published entrypoint e `FRAME_RET`.
|
||||
|
||||
Pergunta de fechamento:
|
||||
|
||||
- quais erros pertencem ao frontend/linking e quais só podem ser cobertos por fixtures de toolchain completo?
|
||||
|
||||
## Discussion Order
|
||||
|
||||
As discussões derivadas desta umbrella agenda devem seguir a ordem abaixo.
|
||||
|
||||
O objetivo da ordem é simples:
|
||||
|
||||
- fechar primeiro autoridade semântica e surface;
|
||||
- depois fechar comportamento observável;
|
||||
- só então descer para lowering, artefato publicado e conformance.
|
||||
|
||||
### Stage 1. Globals Surface and Static Identity
|
||||
|
||||
Boundary owner:
|
||||
|
||||
- `Boundary A. Surface Language and AST`
|
||||
- `Boundary B. Static Semantics and Linking`
|
||||
|
||||
Esta discussão deve fechar primeiro porque todas as outras dependem da definição do que é um global no PBS.
|
||||
|
||||
Ela precisa decidir:
|
||||
|
||||
- a forma exata de `declare global`;
|
||||
- initializer obrigatório ou opcional;
|
||||
- namespace, visibilidade e barrel/export/import;
|
||||
- identidade do storage owner;
|
||||
- política de reexport;
|
||||
- ciclos e dependências entre globals em nível de linking/static semantics.
|
||||
|
||||
Sem esse fechamento:
|
||||
|
||||
- lifecycle ainda não sabe o que precisa inicializar;
|
||||
- lowering ainda não sabe que entidade precisa materializar;
|
||||
- manifest ainda não sabe se está publicando símbolos que dependem de storage global importado.
|
||||
|
||||
### Stage 2. Lifecycle Markers and Program Bootstrap Semantics
|
||||
|
||||
Boundary owner:
|
||||
|
||||
- `Boundary C. Dynamic Semantics and Lifecycle Model`
|
||||
|
||||
Esta discussão vem depois de Stage 1 porque init e frame só fazem sentido quando o modelo de globals já estiver fixado.
|
||||
|
||||
Ela precisa decidir:
|
||||
|
||||
- se `[Init]` e `[Frame]` entram como superfícies oficiais;
|
||||
- unicidade e assinatura desses markers;
|
||||
- ordem entre module init, `[Init]` de programa e `[Frame]`;
|
||||
- política de boot one-shot;
|
||||
- política de falha;
|
||||
- papel semântico exato de `frame()` do usuário.
|
||||
|
||||
Sem esse fechamento:
|
||||
|
||||
- o wrapper sintético não tem contrato observável estável;
|
||||
- `FRAME_RET` não tem owner definido;
|
||||
- qualquer modelagem de IR corre risco de materializar o comportamento errado.
|
||||
|
||||
### Stage 3. Published Entrypoint, Wrapper Ownership, and `FRAME_RET`
|
||||
|
||||
Boundary owner:
|
||||
|
||||
- `Boundary C. Dynamic Semantics and Lifecycle Model`
|
||||
- `Boundary D. IR and Backend Lowering`
|
||||
- `Boundary E. Artifact and Manifest Publication`
|
||||
|
||||
Esta discussão depende de Stage 2 porque ela não decide mais "o que é lifecycle"; ela decide como lifecycle é publicado.
|
||||
|
||||
Ela precisa decidir:
|
||||
|
||||
- se o published entrypoint é um wrapper sintético;
|
||||
- qual é a relação entre `frame()` do usuário e esse wrapper;
|
||||
- onde `FRAME_RET` passa a ser emitido;
|
||||
- se o manifest expõe entrypoint lógico, entrypoint físico ou ambos;
|
||||
- como o `EntrypointRef` do frontend continua determinístico durante a transição.
|
||||
|
||||
Sem esse fechamento:
|
||||
|
||||
- não existe contrato estável para lowering final;
|
||||
- specs de manifest e `IRBackend` ficam em tensão;
|
||||
- o tooling pode continuar com duas autoridades concorrentes para entrypoint.
|
||||
|
||||
### Stage 4. IR Representation and Lowering Mechanics
|
||||
|
||||
Boundary owner:
|
||||
|
||||
- `Boundary D. IR and Backend Lowering`
|
||||
|
||||
Esta discussão vem depois de Stage 3 porque a forma do IR depende do que exatamente precisa ser publicado e executado.
|
||||
|
||||
Ela precisa decidir:
|
||||
|
||||
- se globals entram como primitivo explícito do IR ou apenas em lowering posterior;
|
||||
- como module init é representado;
|
||||
- como o guard de boot é materializado;
|
||||
- como o wrapper published entrypoint é emitido;
|
||||
- como `FRAME_RET` é reposicionado mantendo o mesmo significado.
|
||||
|
||||
Sem esse fechamento:
|
||||
|
||||
- código pode ser implementado cedo demais sobre contratos ainda móveis;
|
||||
- a propagação para specs gerais de lowering fica prematura;
|
||||
- testes de backend podem congelar um shape errado.
|
||||
|
||||
### Stage 5. Diagnostics, Gates, and Conformance Coverage
|
||||
|
||||
Boundary owner:
|
||||
|
||||
- `Boundary F. Diagnostics and Conformance`
|
||||
|
||||
Esta discussão deve vir por último porque ela consolida o que as anteriores já fixaram.
|
||||
|
||||
Ela precisa decidir:
|
||||
|
||||
- catálogo mínimo de diagnósticos novos;
|
||||
- divisão entre erro de syntax/AST, linking/static semantics, lowering e toolchain;
|
||||
- fixtures obrigatórios para globals, lifecycle, wrapper e entrypoint publication;
|
||||
- critérios de aceite para a migração de `FrontendSpec` entrypoint config para source-derived entrypoint discovery.
|
||||
|
||||
Fazer isso antes cria dois riscos:
|
||||
|
||||
- congelar diagnósticos para regras ainda instáveis;
|
||||
- ou escrever fixtures de conformance que depois precisam ser reabertas por mudança arquitetural.
|
||||
|
||||
## Derived Agenda Outline
|
||||
|
||||
Se quisermos quebrar a umbrella agenda em agendas filhas, a ordem recomendada é:
|
||||
|
||||
1. `19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda`
|
||||
2. `19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda`
|
||||
3. `19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda`
|
||||
4. `19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda`
|
||||
5. `19.5. Diagnostics, Manifest Propagation, and Conformance Coverage Agenda`
|
||||
|
||||
Cada agenda filha deve declarar explicitamente:
|
||||
|
||||
- que deriva da umbrella agenda `19`;
|
||||
- quais stages anteriores já são input fixo;
|
||||
- e quais outputs ela precisa entregar para a agenda seguinte.
|
||||
|
||||
## Boundary Locking Rules
|
||||
|
||||
Para evitar que discussões posteriores prejudiquem as anteriores, esta umbrella agenda fixa as seguintes regras de sequenciamento:
|
||||
|
||||
1. `19.2` não redefine surface syntax ou identidade de globals já fechadas em `19.1`.
|
||||
2. `19.3` não redefine o significado semântico de `[Init]`, `[Frame]` ou boot ordering já fechados em `19.2`.
|
||||
3. `19.4` não reabre decisões de linguagem ou de lifecycle; ela apenas escolhe a representação e o mecanismo de lowering compatíveis com elas.
|
||||
4. `19.5` não reabre arquitetura; ela consolida diagnostics, manifest propagation e coverage.
|
||||
5. Qualquer ponto que force reabertura de stage anterior deve voltar explicitamente para a agenda filha owner correta, em vez de ser resolvido informalmente na etapa posterior.
|
||||
|
||||
## Likely Propagation Targets
|
||||
|
||||
Mesmo sem virar `decision` ainda, esta agenda já mostra impacto provável nos seguintes artefatos.
|
||||
|
||||
### PBS Specs
|
||||
|
||||
- `3. Core Syntax Specification.md`
|
||||
- `4. Static Semantics Specification.md`
|
||||
- `9. Dynamic Semantics Specification.md`
|
||||
- `11. AST Specification.md`
|
||||
- `12. Diagnostics Specification.md`
|
||||
- `13. Lowering IRBackend Specification.md`
|
||||
- `7. Cartridge Manifest and Runtime Capabilities Specification.md`
|
||||
|
||||
### Cross-Domain / VM Architecture
|
||||
|
||||
- `docs/vm-arch/ISA_CORE.md` provavelmente não precisa mudar em capability, mas precisa ser referenciado explicitamente como base de `GET_GLOBAL`/`SET_GLOBAL`;
|
||||
- specs gerais de lowering fora de `docs/compiler/pbs` podem precisar propagação posterior se `IRBackend` ganhar representação explícita de globals ou novo contrato para entrypoint published.
|
||||
|
||||
### Compiler / Implementation Areas
|
||||
|
||||
- parser e AST model;
|
||||
- linking/resolution;
|
||||
- static semantics;
|
||||
- IR model do frontend PBS;
|
||||
- executable lowering para `IRBackend` e `IRVM`;
|
||||
- montagem do manifest/cartridge metadata;
|
||||
- suites de fixture de frontend, lowering e toolchain.
|
||||
|
||||
## Boundary Risks
|
||||
|
||||
Se os boundaries acima não forem respeitados, os riscos mais prováveis são:
|
||||
|
||||
1. criar `declare global` como açúcar superficial sem lifecycle coerente;
|
||||
2. introduzir `[Init]` e `[Frame]` sem autoridade clara sobre `FrontendSpec`;
|
||||
3. mover `FRAME_RET` sem redefinir com precisão o owner do frame lógico;
|
||||
4. resolver globals intra-módulo mas deixar imports/reexports semanticamente ambíguos;
|
||||
5. fechar a solução do compiler sem fechar o contrato do manifest;
|
||||
6. misturar nesta agenda decisões de produto/runtime que deveriam continuar fora de escopo.
|
||||
|
||||
## Expected Spec Material
|
||||
|
||||
- atualização da Core Syntax specification para `declare global`;
|
||||
- atualização da Core Syntax specification para `[INIT]` e `[FRAME]`;
|
||||
- atualização da Static Semantics specification para typing, visibility e rules de init/global;
|
||||
- atualização da Dynamic Semantics specification para lifecycle de globals e boot one-shot;
|
||||
- atualização da Lowering spec para globals, module init synthesis, entrypoint detection e published frame wrapper;
|
||||
- eventual atualização de AST/IR contracts se essas superfícies forem documentadas.
|
||||
Se esta agenda virar `decision`, a propagação esperada deve atingir pelo menos:
|
||||
|
||||
- spec de declarações top-level do PBS para introduzir `declare global`;
|
||||
- spec de lifecycle/entrypoint attributes para `[Init]` e `[Frame]`;
|
||||
- spec de lowering executável/`IRBackend` para module init synthesis, wrapper published entrypoint e ownership de `FRAME_RET`;
|
||||
- spec de cartridge manifest para esclarecer a relação entre entrypoint lógico do usuário e entrypoint publicado no artefato;
|
||||
- diagnósticos de validação para unicidade, assinatura inválida, ciclos de init e uso incorreto de globals.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- redefinir a VM para adicionar uma nova capacidade de globals;
|
||||
- introduzir um novo hook explícito de runtime nesta fase;
|
||||
- redesenhar todo o lifecycle de cartridge/firmware fora do que o compiler já publica como entrypoint;
|
||||
- resolver lazy module loading ou hot reload;
|
||||
- manter indefinidamente configuração duplicada de entrypoint em `FrontendSpec` e na source language;
|
||||
- projetar persistência/snapshot/save-state de globals como parte desta discussão inicial.
|
||||
Esta agenda não deve:
|
||||
|
||||
## Next Step Suggested
|
||||
1. redesenhar o runtime ou introduzir novas instruções de VM;
|
||||
2. escrever a spec normativa final de globals e lifecycle;
|
||||
3. redefinir o modelo geral de módulos do compiler fora do necessário para globals/init;
|
||||
4. resolver todos os possíveis hooks futuros de programa além de `[Init]` e `[Frame]`;
|
||||
5. discutir otimizações de performance de init além do necessário para garantir semântica determinística.
|
||||
|
||||
Converter esta agenda em uma `decision` do domínio `compiler/pbs` fechando:
|
||||
## Next Step
|
||||
|
||||
1. a forma de `declare global`;
|
||||
2. a superfície `[INIT]`/`[FRAME]` e a nova detecção de entrypoints;
|
||||
3. o modelo de module init sintético;
|
||||
4. o papel do `init()` do usuário;
|
||||
5. o published frame wrapper;
|
||||
6. o reposicionamento do `FRAME_RET`;
|
||||
7. a remoção da configuração explícita atual em `FrontendSpec`.
|
||||
Usar esta agenda como parent reference e abrir as agendas filhas na ordem abaixo:
|
||||
|
||||
Depois disso, abrir um `pull-request/plan` que separe explicitamente:
|
||||
1. `19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda`
|
||||
2. `19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda`
|
||||
3. `19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda`
|
||||
4. `19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda`
|
||||
5. `19.5. Diagnostics, Manifest Propagation, and Conformance Coverage Agenda`
|
||||
|
||||
1. parser/AST;
|
||||
2. semântica de atributos `[INIT]`/`[FRAME]` e resolução de entrypoint;
|
||||
3. semântica e barrel/export/import;
|
||||
4. IR/backend model para globals;
|
||||
5. synthesis de init e frame wrapper;
|
||||
6. remoção das configs explícitas antigas no frontend registry/specs;
|
||||
7. testes de regressão do pipeline compilador -> IR -> bytecode.
|
||||
Somente depois do fechamento dessas agendas derivadas esta linha deve virar uma `decision` consolidada em `docs/compiler/pbs/decisions`.
|
||||
|
||||
@ -0,0 +1,406 @@
|
||||
# PBS Globals Surface, Identity, and Module Boundaries Agenda
|
||||
|
||||
## Status
|
||||
|
||||
Open
|
||||
|
||||
## Parent Agenda
|
||||
|
||||
This agenda derives from:
|
||||
|
||||
- `19. Globals, Synthetic Module Init, and FRAME_RET Agenda`
|
||||
|
||||
This is the first derived discussion under umbrella topic `19`.
|
||||
|
||||
## Purpose
|
||||
|
||||
Define the source-level and module-level model for PBS runtime globals before lifecycle, entrypoint publication, or lowering details are discussed.
|
||||
|
||||
This agenda exists to close the semantic base for:
|
||||
|
||||
- the `declare global` surface;
|
||||
- storage ownership;
|
||||
- import/export/alias behavior;
|
||||
- and dependency/cycle rules at module boundary level.
|
||||
|
||||
Later agendas under topic `19` must treat the outputs of this agenda as fixed input.
|
||||
|
||||
## Domain Owner
|
||||
|
||||
`docs/compiler/pbs`
|
||||
|
||||
Este tema pertence ao domínio PBS do compiler porque define surface language, linking semantics e boundaries de módulo para uma nova categoria de declaração top-level.
|
||||
|
||||
## Context
|
||||
|
||||
Hoje o PBS já possui `declare const`, mas esse surface é estritamente compile-time:
|
||||
|
||||
- `declare const` entra no value namespace;
|
||||
- `declare const` continua reservado a valores imutáveis que não representam storage mutável de módulo;
|
||||
- `declare const` não materializa storage mutável runtime;
|
||||
- o initializer de `declare const` pertence a um subset constante;
|
||||
- dependências de `declare const` são resolvidas por análise de dependência compile-time.
|
||||
|
||||
Ao mesmo tempo:
|
||||
|
||||
- a VM já expõe `GET_GLOBAL` e `SET_GLOBAL`;
|
||||
- a linguagem ainda não expõe globals mutáveis de módulo;
|
||||
- `mod.barrel` hoje já governa export/import de `const`, `fn`, tipos e outras famílias de declaração;
|
||||
- não existe ainda contrato explícito para storage compartilhado intermodular em source PBS.
|
||||
|
||||
Antes de discutir init, frame wrapper ou `FRAME_RET`, precisamos fechar o que um `global` é no modelo da linguagem.
|
||||
|
||||
## Inputs Already Fixed Elsewhere
|
||||
|
||||
Os seguintes inputs já parecem fixos e não devem ser reabertos aqui:
|
||||
|
||||
- `declare const` não é storage mutável/runtime-initialized;
|
||||
- `declare const` continua semanticamente separado de `declare global`;
|
||||
- `declare const` continua voltado a valores imutáveis e não deve ser reutilizado como surface de global;
|
||||
- modules e globals devem compartilhar o mesmo tipo estrutural de análise de dependência;
|
||||
- essa análise comum deve vir de um refactor do algoritmo atual de modules para um `DependencyGraphAnaliser` em `util.structures` na infra;
|
||||
- top-level executable statements continuam proibidos;
|
||||
- a VM já suporta globals por slot;
|
||||
- esta fase ainda é compiler-driven e não deve exigir capability nova do runtime;
|
||||
- barrel continua sendo a fonte de visibilidade entre módulos.
|
||||
|
||||
## Decisions To Produce
|
||||
|
||||
Esta agenda deve produzir direção suficiente para fechar:
|
||||
|
||||
1. a surface exata de `declare global`;
|
||||
2. a obrigatoriedade de initializer em todos os globals de v1;
|
||||
3. o namespace ocupado por globals;
|
||||
4. a política de visibility/barrel para globals;
|
||||
5. a identidade do storage owner;
|
||||
6. a semântica de import, export e alias;
|
||||
7. a política de dependência e ciclos entre globals.
|
||||
|
||||
## Core Questions
|
||||
|
||||
1. PBS deve introduzir exatamente `declare global name: T = expr;` como nova forma top-level?
|
||||
2. `declare global` deve exigir type annotation explícita em todos os casos?
|
||||
3. Quais formas de initializer executável são admissíveis para `declare global` em v1?
|
||||
4. `declare global` entra no mesmo value namespace de `let` e `declare const`?
|
||||
5. O barrel deve ganhar uma entrada `global` distinta?
|
||||
6. Um `global` importado referencia sempre o storage do módulo owner original?
|
||||
7. Como imports de globals usam alias quando necessário sem introduzir shadowing?
|
||||
8. O que é proibido em imports de globals para evitar ambiguidade?
|
||||
9. A dependência entre globals deve ser modelada por grafo determinístico semelhante ao de `declare const`, mas agora com efeito runtime?
|
||||
10. Como ciclos entre globals intra-módulo e inter-módulo devem ser detectados e reportados?
|
||||
11. Como o grafo de globals mapeia para o `DependencyGraphAnaliser` comum sem perder owner canônico nem attribution?
|
||||
|
||||
## Options
|
||||
|
||||
### Option A
|
||||
|
||||
Adicionar `declare global` como nova declaração top-level explícita, com type annotation obrigatória, initializer obrigatório em v1, entry própria `global` em barrel, sem reexport e identidade de storage sempre pertencente ao módulo owner original.
|
||||
|
||||
### Option B
|
||||
|
||||
Adicionar `declare global`, mas permitir globals sem initializer em v1 e tratar inicialização default como parte do modelo base.
|
||||
|
||||
## Tradeoffs
|
||||
|
||||
### Option A
|
||||
|
||||
- Prós:
|
||||
- semântica explícita e fácil de ensinar;
|
||||
- evita ambiguidade entre constant value e mutable storage;
|
||||
- força o barrel e os imports a refletirem corretamente a nova categoria declarativa;
|
||||
- reduz risco de globals parcialmente formados sem política clara de init.
|
||||
- Contras:
|
||||
- aumenta a superfície da linguagem;
|
||||
- exige atualização de parser, AST, linking e barrel matching.
|
||||
|
||||
### Option B
|
||||
|
||||
- Prós:
|
||||
- maior flexibilidade futura;
|
||||
- permite reservar globals antes de decidir a inicialização concreta.
|
||||
- Contras:
|
||||
- empurra complexidade para lifecycle e diagnostics;
|
||||
- enfraquece a previsibilidade de v1;
|
||||
- cria edge cases sobre leitura antes de materialização.
|
||||
|
||||
## Recommendation
|
||||
|
||||
Seguir com a **Option A**.
|
||||
|
||||
Direção recomendada:
|
||||
|
||||
1. `declare global` deve ser uma declaração top-level distinta de `declare const`;
|
||||
2. type annotation explícita deve ser obrigatória;
|
||||
3. initializer deve ser obrigatório em v1;
|
||||
4. `declare const` não deve ser reutilizado para globals e continua reservado a valores imutáveis;
|
||||
5. globals devem entrar no value namespace, mas com categoria declarativa distinta;
|
||||
6. barrel deve refletir essa distinção explicitamente com `mod global` e `pub global`;
|
||||
7. PBS não deve introduzir reexport de globals nesta linha;
|
||||
8. imports de globals devem preservar a identidade do storage owner original e usar alias quando necessário;
|
||||
9. shadowing entre imports de `fn`, `service`, `global` e `const` deve ser compile-time error;
|
||||
10. dependências entre globals devem ser determinísticas e diagnosticáveis.
|
||||
|
||||
Também fica registrado nesta agenda um direction técnico já decidido:
|
||||
|
||||
1. modules e globals usarão o mesmo tipo estrutural de análise de dependência;
|
||||
2. isso deve nascer de um refactor do algoritmo atual de modules;
|
||||
3. o artefato comum deve viver na infra como `DependencyGraphAnaliser` em `util.structures`;
|
||||
4. cada domínio continua responsável por construir seus próprios nós canônicos, suas arestas e seu mapeamento de diagnóstico;
|
||||
5. o que é compartilhado é o kernel estrutural de ordenação topológica e detecção de ciclos, não a semântica específica de cada grafo.
|
||||
|
||||
## Global Dependencies
|
||||
|
||||
O ponto mais sensível desta agenda é a dependência entre globals.
|
||||
|
||||
Com `declare const`, dependência significa apenas ordem de avaliação compile-time.
|
||||
Com `declare global`, dependência passa a significar ordem de materialização runtime, identidade de storage e risco real de efeito parcial.
|
||||
|
||||
Exemplos do tipo de dependência que passam a existir:
|
||||
|
||||
```pbs
|
||||
declare global a: int = 1;
|
||||
declare global b: int = a + 1;
|
||||
```
|
||||
|
||||
Aqui `b` depende de `a` porque o initializer de `b` lê o valor de `a`.
|
||||
|
||||
```pbs
|
||||
declare global origin: Vec2 = new Vec2(0, 0);
|
||||
declare global camera: Camera = new Camera(origin);
|
||||
```
|
||||
|
||||
Aqui `camera` depende de `origin` porque o initializer usa o valor já materializado de outro global.
|
||||
|
||||
Quando há múltiplos módulos, o problema cresce:
|
||||
|
||||
```pbs
|
||||
// module A
|
||||
declare global seed: int = 7;
|
||||
|
||||
// module B
|
||||
import { seed } from @project:A;
|
||||
declare global rng: Rng = new Rng(seed);
|
||||
```
|
||||
|
||||
Agora a ordem de materialização não é apenas intra-módulo. Ela atravessa módulos e precisa continuar determinística.
|
||||
|
||||
### Dependency Kinds
|
||||
|
||||
Esta agenda precisa distinguir pelo menos três formas de dependência:
|
||||
|
||||
1. dependência local entre globals do mesmo módulo;
|
||||
2. dependência intermodular por import de global do módulo owner original;
|
||||
3. dependência indireta por alias de import, onde o nome local muda, mas o owner do storage permanece igual.
|
||||
|
||||
### Main Problems
|
||||
|
||||
Os principais problemas de dependência de globals são:
|
||||
|
||||
1. ordem de inicialização deixa de poder depender de ordem textual do arquivo;
|
||||
2. imports com alias podem esconder o owner real do storage;
|
||||
3. leitura de global ainda não materializado precisa ser proibida por modelo, não tratada como comportamento oportunista;
|
||||
4. ciclos deixam de ser apenas "ciclos de expressão" e passam a ser ciclos de materialização runtime;
|
||||
5. o grafo de dependências pode cruzar múltiplos módulos e aliases, o que piora atribuição de diagnóstico.
|
||||
|
||||
### Risks
|
||||
|
||||
Se a política de dependência de globals ficar frouxa, os riscos são altos:
|
||||
|
||||
1. inicialização parcialmente observável:
|
||||
um global pode ler outro antes de ele existir semanticamente;
|
||||
2. ordem acidental por arquivo:
|
||||
a implementação pode acabar usando ordem textual ou ordem de carregamento do projeto, o que quebra determinismo;
|
||||
3. aliasing ambíguo:
|
||||
aliases de import podem parecer símbolo novo quando na verdade são só outro nome para o mesmo owner;
|
||||
4. ciclos opacos:
|
||||
`A -> B -> C -> A` pode ficar escondido atrás de import e alias, dificultando explicação ao usuário;
|
||||
5. bootstrap contaminado:
|
||||
se essa agenda deixar dependência frouxa, a 19.2 herda um lifecycle impossível de explicar;
|
||||
6. lowering prematuro:
|
||||
se o compiler materializar a ordem no backend sem política semântica firme, a arquitetura congela cedo demais.
|
||||
|
||||
### Direction for Discussion
|
||||
|
||||
Minha direção recomendada para dependências de globals nesta agenda é:
|
||||
|
||||
1. toda leitura de outro global no initializer cria uma edge explícita no grafo de dependência;
|
||||
2. a resolução do grafo deve ser determinística e independente de source-file order;
|
||||
3. imports e aliases devem preservar o owner original do storage no grafo;
|
||||
4. ciclos entre globals devem ser erro estático, não comportamento runtime com retry ou valor parcial;
|
||||
5. a agenda deve deixar claro que esta política fecha apenas identidade e dependência;
|
||||
boot ordering completo continua pertencendo à `19.2`.
|
||||
|
||||
### Structural Reuse Decision
|
||||
|
||||
Esta agenda também registra uma decisão arquitetural de implementação que afeta a evolução futura:
|
||||
|
||||
1. o algoritmo atual usado para dependência de modules deve ser refatorado em um componente estrutural reutilizável;
|
||||
2. esse componente comum deve se chamar `DependencyGraphAnaliser`;
|
||||
3. ele deve viver em `util.structures` na infra;
|
||||
4. modules e globals devem consumir esse mesmo componente estrutural;
|
||||
5. a semântica que descobre edges continua separada por domínio.
|
||||
|
||||
Isso significa:
|
||||
|
||||
- o import graph de modules e o init graph de globals não serão o mesmo grafo semântico;
|
||||
- mas ambos deverão usar o mesmo kernel estrutural para:
|
||||
- topological ordering,
|
||||
- cycle detection,
|
||||
- e suporte a diagnóstico determinístico.
|
||||
|
||||
## Current Direction
|
||||
|
||||
Os pontos abaixo já podem ser tratados como direção fechada desta agenda, salvo objeção nova forte:
|
||||
|
||||
1. a surface correta é `declare global BLA: int = 1;`;
|
||||
2. type annotation é obrigatória, como em `declare const`;
|
||||
3. initializer é sempre obrigatório;
|
||||
4. globals entram no value namespace como categoria declarativa distinta;
|
||||
5. `mod.barrel` deve expor globals com entradas `mod global Name;` e `pub global Name;`;
|
||||
6. imports de globals usam o mesmo esquema de alias quando necessário;
|
||||
7. PBS não introduz reexport de globals nesta linha;
|
||||
8. shadowing entre imports de `fn`, `service`, `global` e `const` é compile-time error e deve ser resolvido com alias;
|
||||
9. detecção de dependência, ordenação e ciclo deve nascer do `DependencyGraphAnaliser` comum, com contexto semântico próprio de globals.
|
||||
|
||||
Também fica explicitado o modelo de namespace:
|
||||
|
||||
1. globals entram no value namespace;
|
||||
2. `declare const`, `declare global` e o singleton canônico de `service` convivem no espaço nominal de valores;
|
||||
3. `fn`, `service`, `global` e `const` não podem introduzir o mesmo nome visível no mesmo scope de resolução;
|
||||
4. essa colisão é erro de compile time, mesmo quando a ambiguidade nasce de import;
|
||||
5. `locals > struct/class members > globals`, inclusive quando o global veio por import.
|
||||
|
||||
## Remaining Open Points
|
||||
|
||||
Com a direção já consolidada nesta agenda, não restam pontos substantivos em aberto dentro do boundary de `19.1`.
|
||||
|
||||
Os temas adicionais de lifecycle seguem encaminhados para a `19.2`.
|
||||
|
||||
## Initializer Boundary
|
||||
|
||||
Esta agenda também precisa deixar explícita a fronteira entre:
|
||||
|
||||
1. init da declaração `global`;
|
||||
2. init por módulo;
|
||||
3. init de projeto.
|
||||
|
||||
Direção recomendada:
|
||||
|
||||
- o initializer de `declare global` deve permanecer restrito e simples;
|
||||
- ele existe para materializar o valor inicial da storage de módulo;
|
||||
- ele não deve carregar lógica procedural maior nem depender de top-level `fn`;
|
||||
- lógica adicional de setup pertence ao init por módulo;
|
||||
- setup de programa pertence ao init de projeto.
|
||||
|
||||
Com isso, a linha proposta fica:
|
||||
|
||||
1. init da global:
|
||||
permite primitivas, operações simples com valor, member access com valor nessa etapa, `new`, e leitura de outras globals compatíveis com o dep graph;
|
||||
2. init do módulo:
|
||||
permite lógica adicional de conveniência e mutações nas globals do próprio módulo após a materialização inicial;
|
||||
3. init do projeto:
|
||||
permite setup do projeto como um todo, depois do fechamento do estado de módulo necessário.
|
||||
|
||||
### Consequence for `fn` in Global Initializers
|
||||
|
||||
Seguindo essa separação, esta agenda recomenda que:
|
||||
|
||||
1. calls para top-level `fn` não sejam permitidas em initializer de `global` em v1;
|
||||
2. a necessidade de lógica mais rica seja absorvida pelo init de módulo discutido na `19.2`;
|
||||
3. isso mantenha o dep graph de globals focado em materialização declarativa, não em execução procedural arbitrária.
|
||||
|
||||
Também fica recomendado que, em v1:
|
||||
|
||||
1. `some(...)` e `none` não façam parte do initializer declarativo de `global`;
|
||||
2. `if` e `switch` não sejam permitidos diretamente na declaração de `global`.
|
||||
|
||||
## Diagnostics Recommendation
|
||||
|
||||
Esta agenda fecha o seguinte catálogo pequeno, forte e didático de diagnósticos obrigatórios.
|
||||
|
||||
### 1. Invalid Global Initializer
|
||||
|
||||
Quando o initializer usar uma forma não admissível em v1, o compiler deve emitir um erro apontando a subexpressão inválida.
|
||||
|
||||
Mensagem semântica recomendada:
|
||||
|
||||
- `global initializer uses unsupported form`
|
||||
|
||||
Exemplos de motivo associado:
|
||||
|
||||
- top-level `fn` call not allowed in global initializer;
|
||||
- `some(...)` not allowed in global initializer;
|
||||
- `if` not allowed in global initializer.
|
||||
|
||||
### 2. Global Dependency Cycle
|
||||
|
||||
Quando houver ciclo, o compiler deve diagnosticar o global owner local e, quando possível, renderizar o caminho canônico do ciclo.
|
||||
|
||||
Mensagem semântica recomendada:
|
||||
|
||||
- `global dependency cycle detected`
|
||||
|
||||
Detalhe recomendado:
|
||||
|
||||
- incluir o símbolo local que participa do ciclo;
|
||||
- incluir o caminho canônico quando disponível, por exemplo:
|
||||
`@project:A.seed -> @project:B.rng -> @project:C.config -> @project:A.seed`
|
||||
|
||||
### 3. Shadowing Requires Alias
|
||||
|
||||
Quando um import introduzir nome que colide com `fn`, `service`, `global` ou `const` já visível, o compiler deve rejeitar e exigir alias explícito.
|
||||
|
||||
Mensagem semântica recomendada:
|
||||
|
||||
- `imported symbol shadows existing visible symbol; alias required`
|
||||
|
||||
### 4. Global Import Category Mismatch
|
||||
|
||||
Se o barrel e a importação não preservarem corretamente a categoria declarativa `global`, o compiler deve rejeitar explicitamente em vez de tentar degradar para `const` ou valor genérico.
|
||||
|
||||
Mensagem semântica recomendada:
|
||||
|
||||
- `global import must resolve through a global barrel entry`
|
||||
|
||||
Essa escolha existe para preservar:
|
||||
|
||||
- clareza semântica;
|
||||
- diagnósticos mais simples;
|
||||
- e uma separação limpa entre storage initialization e lifecycle hooks.
|
||||
|
||||
## Forwarded To 19.2
|
||||
|
||||
Os seguintes temas surgiram desta agenda, mas pertencem ao boundary de lifecycle e devem ser tratados na `19.2`:
|
||||
|
||||
1. init por módulo como fase procedural separada do initializer declarativo de `global`;
|
||||
2. init de projeto como fase distinta de coordenação final;
|
||||
3. permissão de loops em init de módulo e init de projeto;
|
||||
4. proibição de host calls por padrão durante init;
|
||||
5. permissão apenas para host calls marcadas com atributo reservado `[InitAllowed]`;
|
||||
6. validação compile-time dessa admissibilidade;
|
||||
7. separação entre restrição normativa de host interaction e recomendação de design para manter bootstrap leve.
|
||||
|
||||
## Expected Spec Material
|
||||
|
||||
Se esta agenda fechar, a propagação esperada atinge pelo menos:
|
||||
|
||||
- `3. Core Syntax Specification.md`
|
||||
- `4. Static Semantics Specification.md`
|
||||
- `11. AST Specification.md`
|
||||
- `12. Diagnostics Specification.md`
|
||||
|
||||
## Non-Goals
|
||||
|
||||
Esta agenda não deve:
|
||||
|
||||
1. definir boot ordering;
|
||||
2. definir `[Init]` ou `[Frame]`;
|
||||
3. definir wrapper published entrypoint;
|
||||
4. definir posicionamento de `FRAME_RET`;
|
||||
5. escolher a representação de IR/bytecode para globals.
|
||||
|
||||
## Next Step
|
||||
|
||||
Depois de fechar esta agenda, abrir ou aprofundar:
|
||||
|
||||
- `19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda`
|
||||
@ -0,0 +1,361 @@
|
||||
# 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`
|
||||
@ -0,0 +1,203 @@
|
||||
# Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda
|
||||
|
||||
## Status
|
||||
|
||||
Open
|
||||
|
||||
## Parent Agenda
|
||||
|
||||
This agenda derives from:
|
||||
|
||||
- `19. Globals, Synthetic Module Init, and FRAME_RET Agenda`
|
||||
|
||||
Expected fixed inputs from previous stages:
|
||||
|
||||
- `19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda`
|
||||
- `19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda`
|
||||
|
||||
## Purpose
|
||||
|
||||
Define how PBS lifecycle is published into the executable artifact once globals and lifecycle semantics are already fixed.
|
||||
|
||||
This agenda must close:
|
||||
|
||||
- whether the published entrypoint becomes a synthetic wrapper;
|
||||
- the semantic and publication relationship between user `frame()` and the published entrypoint;
|
||||
- the new owner of `FRAME_RET`;
|
||||
- and the contract boundary between source-derived entrypoint discovery, `FrontendSpec`, and cartridge manifest publication.
|
||||
|
||||
## Domain Owner
|
||||
|
||||
`docs/compiler/pbs`
|
||||
|
||||
Este tema pertence ao domínio PBS porque decide a fronteira entre semântica da linguagem, entrypoint publicado e artefato executável.
|
||||
|
||||
## Context
|
||||
|
||||
Se `frame()` do usuário deixar de ser o callable publicado diretamente, o compiler precisará publicar outro root executável.
|
||||
|
||||
Isso abre quatro perguntas acopladas:
|
||||
|
||||
- quem é o entrypoint físico do artefato;
|
||||
- qual callable continua sendo o root lógico do código do usuário;
|
||||
- onde `FRAME_RET` passa a ser emitido;
|
||||
- e como manifest e `FrontendSpec` representam isso sem ambiguidade.
|
||||
|
||||
Esta agenda existe para fechar esse contrato antes de discutir detalhe de representação de IR.
|
||||
|
||||
## Inputs Already Fixed Elsewhere
|
||||
|
||||
Os seguintes inputs devem ser tratados como fixos aqui:
|
||||
|
||||
- o modelo de globals vindo de `19.1`;
|
||||
- o modelo de lifecycle e markers vindo de `19.2`;
|
||||
- `FRAME_RET` continua significando fim do frame lógico;
|
||||
- o runtime continua esperando um entrypoint published por frame.
|
||||
|
||||
## Decisions To Produce
|
||||
|
||||
Esta agenda deve produzir direção suficiente para fechar:
|
||||
|
||||
1. se o published entrypoint é um wrapper sintético;
|
||||
2. qual é a relação entre `frame()` do usuário e esse wrapper;
|
||||
3. onde `FRAME_RET` passa a viver;
|
||||
4. como a autoridade de entrypoint sai de `FrontendSpec` e passa ao compiler PBS;
|
||||
5. como o protocolo de runtime/manifest representa esse entrypoint.
|
||||
|
||||
## Core Questions
|
||||
|
||||
1. O compiler deve publicar um wrapper sintético como entrypoint real?
|
||||
2. `frame()` do usuário deixa de ser o callable publicado e passa a ser apenas root lógico interno?
|
||||
3. `FRAME_RET` deve ser emitido no wrapper, não mais no callable do usuário?
|
||||
4. O compiler PBS deve se tornar a única autoridade para definir o entrypoint publicado?
|
||||
5. O wrapper sintético deve ocupar protocolarmente o entrypoint físico `0`?
|
||||
6. O campo `entrypoint` deve deixar de existir no `manifest.json` como estado alvo do protocolo?
|
||||
7. Existe algum caso em que o wrapper não seja necessário depois de `19.2`?
|
||||
|
||||
## Options
|
||||
|
||||
### Option A
|
||||
|
||||
Publicar um wrapper sintético como entrypoint físico, tratar `frame()` do usuário como root lógico interno, mover `FRAME_RET` para o wrapper, tornar o compiler PBS a autoridade exclusiva de entrypoint e fixar protocolarmente o entrypoint físico em `0`.
|
||||
|
||||
### Option B
|
||||
|
||||
Manter `frame()` do usuário como entrypoint publicado e tentar acoplar boot/lifecycle diretamente nele.
|
||||
|
||||
### Option C
|
||||
|
||||
Publicar wrapper sintético, mas manter `entrypoint` no manifest como autoridade nominal paralela.
|
||||
|
||||
## Tradeoffs
|
||||
|
||||
### Option A
|
||||
|
||||
- Prós:
|
||||
- separa lifecycle publicado do callable do usuário;
|
||||
- acomoda boot one-shot de forma limpa;
|
||||
- preserva o significado de `FRAME_RET` com owner mais correto.
|
||||
- alinha melhor o protocolo físico do artefato com a política já existente de `func_id = 0` como entrypoint;
|
||||
- remove autoridade duplicada entre compiler, manifest e `FrontendSpec`.
|
||||
- Contras:
|
||||
- exige trabalho claro de migração em manifest, runtime e `FrontendSpec`;
|
||||
- torna a relação lógico/físico explicitamente dupla.
|
||||
|
||||
### Option B
|
||||
|
||||
- Prós:
|
||||
- preserva a superfície atual de publicação.
|
||||
- Contras:
|
||||
- mistura responsabilidades demais no callable do usuário;
|
||||
- enfraquece a clareza do lifecycle.
|
||||
|
||||
### Option C
|
||||
|
||||
- Prós:
|
||||
- parece reduzir custo de transição imediata.
|
||||
- Contras:
|
||||
- mantém duas autoridades para entrypoint;
|
||||
- cria dívida documental e de runtime desnecessária;
|
||||
- enfraquece a ideia de entrypoint como protocolo fixo do artefato.
|
||||
|
||||
## Recommendation
|
||||
|
||||
Seguir com a **Option A**.
|
||||
|
||||
## Current Direction
|
||||
|
||||
Os pontos abaixo já podem ser tratados como direção fechada desta agenda, salvo objeção nova forte:
|
||||
|
||||
1. o compiler deve publicar um wrapper sintético como entrypoint físico real;
|
||||
2. esse wrapper deve conter:
|
||||
- boot one-shot,
|
||||
- os inits necessários apenas uma vez,
|
||||
- a chamada ao `frame()` do usuário,
|
||||
- e o `FRAME_RET` final;
|
||||
3. `frame()` anotado com `[Frame]` permanece como root lógico do usuário;
|
||||
4. o wrapper sintético é o root físico publicado;
|
||||
5. `FRAME_RET` sai do final do `frame()` do usuário e passa a existir no wrapper;
|
||||
6. `FrontendSpec` perde autoridade para referenciar quem é o entrypoint;
|
||||
7. a autoridade de entrypoint fica outorgada exclusivamente ao compiler PBS;
|
||||
8. o wrapper sintético deve ser compilado no entrypoint físico `0`;
|
||||
9. o estado alvo do protocolo deve remover `entrypoint` do `manifest.json`;
|
||||
10. o runtime/loader deve tratar o entrypoint como protocolo fixo do artefato, não como metadado nominal configurável no manifest.
|
||||
|
||||
## Manifest and Runtime Direction
|
||||
|
||||
Esta agenda também já aponta para a seguinte direção de contrato:
|
||||
|
||||
1. o campo `entrypoint` deve deixar de existir no `manifest.json` como estado final do protocolo;
|
||||
2. o runtime deve assumir protocolarmente o entrypoint físico `0`;
|
||||
3. o compiler garante que esse índice `0` pertence ao wrapper sintético publicado;
|
||||
4. export nominal do callable deixa de ser a autoridade de boot;
|
||||
5. qualquer compatibilidade temporária com manifest nominal deve ser tratada apenas como transição, não como contrato final desejado.
|
||||
|
||||
## Exports Boundary
|
||||
|
||||
Esta agenda também fecha a seguinte separação:
|
||||
|
||||
1. exports nominais de funções podem continuar existindo no artefato;
|
||||
2. esses exports deixam de ser usados como autoridade de loader/boot;
|
||||
3. boot passa a depender exclusivamente do entrypoint físico `0` publicado pelo compiler;
|
||||
4. exports nominais permanecem apenas como superfície útil para tooling, debug, introspection e casos correlatos.
|
||||
|
||||
## Remaining Open Points
|
||||
|
||||
Com a direção acima, os pontos que ainda pedem fechamento real nesta agenda ficam reduzidos a:
|
||||
|
||||
1. a forma de propagação normativa dessa mudança para specs gerais de bytecode, lowering e cartridge contract.
|
||||
|
||||
## Runtime Propagation
|
||||
|
||||
Esta agenda também deve referenciar explicitamente a discussão correspondente no domínio runtime:
|
||||
|
||||
- `../runtime/docs/runtime/agendas/025-cartridge-manifest-entrypoint-removal-and-runtime-protocol.md`
|
||||
|
||||
Direção fechada desta agenda:
|
||||
|
||||
1. não há linha de compatibilidade desejada como estado-alvo;
|
||||
2. a remoção de `entrypoint` do runtime deve ser executada em prioridade alinhada ao compiler;
|
||||
3. a agenda de runtime é o owner da discussão operacional de loader/VM/manifest no outro domínio.
|
||||
|
||||
## Expected Spec Material
|
||||
|
||||
Se esta agenda fechar, a propagação esperada atinge pelo menos:
|
||||
|
||||
- `9. Dynamic Semantics Specification.md`
|
||||
- `13. Lowering IRBackend Specification.md`
|
||||
- `7. Cartridge Manifest and Runtime Capabilities Specification.md`
|
||||
- `12. Diagnostics Specification.md`
|
||||
|
||||
## Non-Goals
|
||||
|
||||
Esta agenda não deve:
|
||||
|
||||
1. escolher o encoding exato do wrapper no IR;
|
||||
2. definir estrutura detalhada de module init lowering;
|
||||
3. escrever fixtures completos de conformance.
|
||||
|
||||
## Next Step
|
||||
|
||||
Depois de fechar esta agenda, abrir ou aprofundar:
|
||||
|
||||
- `19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda`
|
||||
@ -0,0 +1,147 @@
|
||||
# Globals and Lifecycle Lowering to IRBackend/IRVM Agenda
|
||||
|
||||
## Status
|
||||
|
||||
Open
|
||||
|
||||
## Parent Agenda
|
||||
|
||||
This agenda derives from:
|
||||
|
||||
- `19. Globals, Synthetic Module Init, and FRAME_RET Agenda`
|
||||
|
||||
Expected fixed inputs from previous stages:
|
||||
|
||||
- `19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda`
|
||||
- `19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda`
|
||||
- `19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda`
|
||||
|
||||
## Purpose
|
||||
|
||||
Define how the already-decided globals and lifecycle model are represented and lowered through the executable compiler pipeline.
|
||||
|
||||
This agenda must close:
|
||||
|
||||
- the representation boundary for globals;
|
||||
- module init synthesis;
|
||||
- boot guard materialization;
|
||||
- wrapper lowering;
|
||||
- and the executable path that preserves the chosen `FRAME_RET` ownership.
|
||||
|
||||
## Domain Owner
|
||||
|
||||
`docs/compiler/pbs`
|
||||
|
||||
Este tema pertence ao domínio PBS, mas encosta diretamente nas specs gerais de lowering e nas interfaces entre frontend e backend.
|
||||
|
||||
## Context
|
||||
|
||||
Depois que surface, lifecycle e publication contract estiverem fechados, ainda restará decidir:
|
||||
|
||||
- em que boundary globals passam a existir como entidade explícita;
|
||||
- se `IRBackend` carrega globals diretamente ou só uma forma anterior;
|
||||
- como module init sintético é representado;
|
||||
- como o wrapper published entrypoint é emitido;
|
||||
- como o guard one-shot de boot é materializado.
|
||||
|
||||
Esta agenda é mecânica/arquitetural. Ela não deve reabrir decisões de linguagem.
|
||||
|
||||
## Inputs Already Fixed Elsewhere
|
||||
|
||||
Os seguintes inputs devem ser tratados como fixos aqui:
|
||||
|
||||
- surface e identidade de globals vindas de `19.1`;
|
||||
- lifecycle semântico vindo de `19.2`;
|
||||
- owner do published entrypoint e de `FRAME_RET` vindo de `19.3`;
|
||||
- `GET_GLOBAL` e `SET_GLOBAL` já existem na VM.
|
||||
|
||||
## Decisions To Produce
|
||||
|
||||
Esta agenda deve produzir direção suficiente para fechar:
|
||||
|
||||
1. se globals entram explicitamente no `IRBackend` ou apenas em lowering posterior;
|
||||
2. como module init é sintetizado;
|
||||
3. como o guard one-shot de boot é materializado;
|
||||
4. como o wrapper é lowered;
|
||||
5. como `FRAME_RET` é preservado no ponto correto;
|
||||
6. quais contracts gerais de lowering precisam propagação.
|
||||
|
||||
## Core Questions
|
||||
|
||||
1. `IRBackend` deve ganhar representação explícita para globals?
|
||||
2. Se não, qual é o boundary intermediário responsável por materializá-los antes de `IRVM`?
|
||||
3. Module init sintético é emitido como callable próprio por módulo?
|
||||
4. O boot guard é global oculto, local estático de wrapper, ou outra forma interna?
|
||||
5. O wrapper published entrypoint é um callable sintético explícito no graph do frontend?
|
||||
6. Como manter attribution e diagnostics úteis para código sintético?
|
||||
7. Que mudanças mínimas precisam acontecer em specs gerais fora de `docs/compiler/pbs`?
|
||||
|
||||
## Options
|
||||
|
||||
### Option A
|
||||
|
||||
Dar representação explícita a globals e callables sintéticos já no boundary de `IRBackend`, preservando attribution e identidade suficientes para lowering posterior.
|
||||
|
||||
### Option B
|
||||
|
||||
Manter `IRBackend` sem globals explícitos e adiar essa materialização para um lowering mais baixo.
|
||||
|
||||
### Option C
|
||||
|
||||
Tratar globals como açúcar compilado diretamente para slots/ops sem entidade intermediária estável.
|
||||
|
||||
## Tradeoffs
|
||||
|
||||
### Option A
|
||||
|
||||
- Prós:
|
||||
- boundary mais explícito e testável;
|
||||
- menor inferência textual em lowers posteriores;
|
||||
- facilita explicar wrapper e init synthesis.
|
||||
- Contras:
|
||||
- aumenta o contrato do `IRBackend`;
|
||||
- pode exigir propagação além do domínio PBS.
|
||||
|
||||
### Option B
|
||||
|
||||
- Prós:
|
||||
- preserva o boundary atual por mais tempo.
|
||||
- Contras:
|
||||
- empurra complexidade para fases posteriores;
|
||||
- dificulta conformance do shape intermediário.
|
||||
|
||||
### Option C
|
||||
|
||||
- Prós:
|
||||
- menor aparente custo de modelagem.
|
||||
- Contras:
|
||||
- fraco para teste, attribution e manutenção;
|
||||
- mistura lowering demais cedo.
|
||||
|
||||
## Recommendation
|
||||
|
||||
Seguir com a **Option A**, salvo impedimento forte de boundary cross-domain.
|
||||
|
||||
## Expected Spec Material
|
||||
|
||||
Se esta agenda fechar, a propagação esperada atinge pelo menos:
|
||||
|
||||
- `13. Lowering IRBackend Specification.md`
|
||||
- specs gerais de lowering/backend fora do domínio PBS, se necessário
|
||||
- `12. Diagnostics Specification.md`
|
||||
|
||||
## Non-Goals
|
||||
|
||||
Esta agenda não deve:
|
||||
|
||||
1. redefinir surface syntax;
|
||||
2. redefinir lifecycle;
|
||||
3. redefinir manifest publication;
|
||||
4. fechar catálogo final de fixtures.
|
||||
|
||||
## Next Step
|
||||
|
||||
Depois de fechar esta agenda, abrir ou aprofundar:
|
||||
|
||||
- `19.5. Diagnostics, Manifest Propagation, and Conformance Coverage Agenda`
|
||||
|
||||
@ -0,0 +1,133 @@
|
||||
# Diagnostics, Manifest Propagation, and Conformance Coverage Agenda
|
||||
|
||||
## Status
|
||||
|
||||
Open
|
||||
|
||||
## Parent Agenda
|
||||
|
||||
This agenda derives from:
|
||||
|
||||
- `19. Globals, Synthetic Module Init, and FRAME_RET Agenda`
|
||||
|
||||
Expected fixed inputs from previous stages:
|
||||
|
||||
- `19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda`
|
||||
- `19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda`
|
||||
- `19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda`
|
||||
- `19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda`
|
||||
|
||||
## Purpose
|
||||
|
||||
Consolidate the propagation layer of topic `19` after the architectural decisions are already fixed.
|
||||
|
||||
This agenda must close:
|
||||
|
||||
- the diagnostics surface;
|
||||
- manifest-facing propagation details;
|
||||
- fixture and conformance coverage;
|
||||
- and the acceptance gates for declaring topic `19` ready to become a decision plus implementation plan.
|
||||
|
||||
## Domain Owner
|
||||
|
||||
`docs/compiler/pbs`
|
||||
|
||||
Este tema pertence ao domínio PBS, mas toca tanto specs normativas quanto critérios de teste e artefato publicado.
|
||||
|
||||
## Context
|
||||
|
||||
Depois que surface, lifecycle, published entrypoint e lowering estiverem fechados, ainda faltará consolidar:
|
||||
|
||||
- quais erros novos são obrigatórios;
|
||||
- em que fase cada erro aparece;
|
||||
- como o manifest final reflete a arquitetura escolhida;
|
||||
- e que coverage mínima de fixtures e gates garante que a série 19 ficou estável.
|
||||
|
||||
Esta agenda é de consolidação. Ela não deve rediscutir a arquitetura central.
|
||||
|
||||
## Inputs Already Fixed Elsewhere
|
||||
|
||||
Os seguintes inputs devem ser tratados como fixos aqui:
|
||||
|
||||
- shape de globals vindo de `19.1`;
|
||||
- lifecycle vindo de `19.2`;
|
||||
- publication contract vindo de `19.3`;
|
||||
- lowering mechanics vindo de `19.4`.
|
||||
|
||||
## Decisions To Produce
|
||||
|
||||
Esta agenda deve produzir direção suficiente para fechar:
|
||||
|
||||
1. catálogo mínimo de diagnósticos;
|
||||
2. fase responsável por cada diagnóstico;
|
||||
3. propagação final para manifest/specs;
|
||||
4. fixture matrix mínima;
|
||||
5. critérios de aceite para converter a série 19 em `decision` e depois `pull-request/plan`.
|
||||
|
||||
## Core Questions
|
||||
|
||||
1. Quais diagnósticos são obrigatórios para `declare global`, imports/reexports e ciclos?
|
||||
2. Quais diagnósticos são obrigatórios para `[Init]` e `[Frame]`?
|
||||
3. Quais erros pertencem a parser/AST, static semantics/linking, lowering, ou toolchain full pipeline?
|
||||
4. Como o manifest final deve refletir entrypoint lógico e/ou físico escolhido em `19.3`?
|
||||
5. Que fixtures mínimas precisam existir para globals, module init, boot failure, wrapper e `FRAME_RET`?
|
||||
6. Em que ponto a configuração explícita antiga de entrypoint em `FrontendSpec` pode ser considerada removida?
|
||||
7. Quais gates de conformance precisam ser atualizados para cobrir a série 19?
|
||||
|
||||
## Options
|
||||
|
||||
### Option A
|
||||
|
||||
Consolidar diagnostics e coverage somente depois que os quatro stages anteriores estiverem fechados, com fixture matrix explícita por fase.
|
||||
|
||||
### Option B
|
||||
|
||||
Começar fixtures e diagnostics cedo, mesmo com arquitetura ainda mudando.
|
||||
|
||||
## Tradeoffs
|
||||
|
||||
### Option A
|
||||
|
||||
- Prós:
|
||||
- reduz retrabalho;
|
||||
- evita congelar erro e coverage cedo demais;
|
||||
- combina melhor com a disciplina de umbrella agenda.
|
||||
- Contras:
|
||||
- posterga parte da validação final.
|
||||
|
||||
### Option B
|
||||
|
||||
- Prós:
|
||||
- feedback mais cedo.
|
||||
- Contras:
|
||||
- alto risco de churn e reabertura de artefatos;
|
||||
- conflita com os locking rules da umbrella 19.
|
||||
|
||||
## Recommendation
|
||||
|
||||
Seguir com a **Option A**.
|
||||
|
||||
## Expected Spec Material
|
||||
|
||||
Se esta agenda fechar, a propagação esperada atinge pelo menos:
|
||||
|
||||
- `7. Cartridge Manifest and Runtime Capabilities Specification.md`
|
||||
- `12. Diagnostics Specification.md`
|
||||
- `13. Lowering IRBackend Specification.md`
|
||||
- docs de conformance/fixtures relevantes
|
||||
|
||||
## Non-Goals
|
||||
|
||||
Esta agenda não deve:
|
||||
|
||||
1. redefinir semântica de globals;
|
||||
2. redefinir lifecycle;
|
||||
3. redefinir wrapper ou ownership de `FRAME_RET`;
|
||||
4. redefinir shape de IR.
|
||||
|
||||
## Next Step
|
||||
|
||||
Depois do fechamento desta agenda, a linha `19` fica pronta para:
|
||||
|
||||
- virar uma `decision` consolidada em `docs/compiler/pbs/decisions`;
|
||||
- e então ser decomposta em `pull-request/plan` de execução.
|
||||
@ -13,6 +13,11 @@ Closed agendas are moved to `docs/pbs/agendas/archive`.
|
||||
5. `18.4. Asset References in Game Code - Names vs Compile-Time Lowering Agenda.md`
|
||||
6. `18.5. Ignored Call Results in Executable Lowering Agenda.md`
|
||||
7. `19. Globals, Synthetic Module Init, and FRAME_RET Agenda.md`
|
||||
8. `19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda.md`
|
||||
9. `19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda.md`
|
||||
10. `19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda.md`
|
||||
11. `19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda.md`
|
||||
12. `19.5. Diagnostics, Manifest Propagation, and Conformance Coverage Agenda.md`
|
||||
|
||||
## Purpose
|
||||
|
||||
|
||||
@ -0,0 +1,154 @@
|
||||
# Globals Surface, Identity, and Module Boundaries Decision
|
||||
|
||||
Status: Accepted
|
||||
Date: 2026-03-22
|
||||
Related Agenda: `docs/compiler/pbs/agendas/19.1. PBS Globals Surface, Identity, and Module Boundaries Agenda.md`
|
||||
|
||||
## Context
|
||||
|
||||
PBS v1 needed a precise language and linking policy for runtime globals before lifecycle, published entrypoint, and lowering work under topic `19` could proceed safely.
|
||||
|
||||
The open problem was not merely syntax.
|
||||
It also required closing:
|
||||
|
||||
- how globals differ from `declare const`,
|
||||
- how globals participate in value visibility and import flow,
|
||||
- how module ownership of storage is preserved,
|
||||
- how dependency order between globals is modeled,
|
||||
- and which diagnostics are mandatory when that model is violated.
|
||||
|
||||
Important fixed inputs already existed:
|
||||
|
||||
- `declare const` is compile-time only and does not denote mutable module storage,
|
||||
- top-level executable statements remain forbidden,
|
||||
- the VM already exposes global-slot access,
|
||||
- and `mod.barrel` remains the visibility authority for module exports.
|
||||
|
||||
## Decision
|
||||
|
||||
PBS adopts the following policy for runtime globals in v1:
|
||||
|
||||
1. PBS introduces a distinct top-level declaration form:
|
||||
- `declare global Name: T = expr;`
|
||||
2. `declare global` is not a variant of `declare const`.
|
||||
3. `declare const` remains reserved to immutable values and must not be reused as runtime module storage.
|
||||
4. `declare global` requires:
|
||||
- an explicit type annotation,
|
||||
- and an explicit initializer in all ordinary v1 cases.
|
||||
5. Globals participate in the value namespace, but remain a distinct declaration category.
|
||||
6. `mod.barrel` must expose globals through explicit `global` entries:
|
||||
- `mod global Name;`
|
||||
- `pub global Name;`
|
||||
7. PBS does not introduce global re-export in this line of work.
|
||||
8. Import of a global preserves the storage identity of the original owner module.
|
||||
9. Imports may use aliasing when needed, but aliasing changes only the local visible name, never the canonical storage owner.
|
||||
10. Shadowing between visible `fn`, `service`, `global`, and `const` names is a compile-time error and must be resolved with aliasing.
|
||||
11. Lookup precedence remains:
|
||||
- locals,
|
||||
- then struct/class members,
|
||||
- then globals,
|
||||
including globals introduced by import.
|
||||
12. Global dependency order is defined by a deterministic dependency graph:
|
||||
- every read of another global in a global initializer creates a dependency edge,
|
||||
- imports and aliases preserve canonical owner identity in that graph,
|
||||
- source-file order must not affect dependency resolution.
|
||||
13. Cycles between globals are compile-time errors.
|
||||
14. Modules and globals must share the same structural dependency-analysis kernel through a refactor of the existing module dependency algorithm into:
|
||||
- `DependencyGraphAnaliser`
|
||||
- located in infra `util.structures`.
|
||||
15. What is shared is the structural graph analysis kernel:
|
||||
- topological ordering,
|
||||
- cycle detection,
|
||||
- deterministic traversal support.
|
||||
16. What is not shared is domain semantics:
|
||||
- each domain remains responsible for constructing canonical nodes, edges, and diagnostics.
|
||||
|
||||
## Global Initializer Policy
|
||||
|
||||
PBS v1 adopts the following initializer policy for `declare global`:
|
||||
|
||||
1. The initializer exists only to materialize the initial module storage value.
|
||||
2. Admissible forms in v1 include:
|
||||
- primitive literals and simple value operations,
|
||||
- value-bearing member access at this stage,
|
||||
- `new Struct(...)`,
|
||||
- and reads of other globals compatible with the dependency graph.
|
||||
3. Top-level `fn` calls are not permitted in a global initializer in v1.
|
||||
4. `some(...)` and `none` are not permitted in a global initializer in v1.
|
||||
5. `if` and `switch` are not permitted directly in the declaration initializer in v1.
|
||||
6. Richer procedural setup belongs to later lifecycle stages rather than the declaration initializer itself.
|
||||
|
||||
## Rationale
|
||||
|
||||
This decision intentionally keeps global declarations narrow and explicit.
|
||||
|
||||
That choice:
|
||||
|
||||
- prevents semantic collapse between immutable constants and mutable runtime storage,
|
||||
- keeps import and visibility rules legible,
|
||||
- makes dependency analysis deterministic and explainable,
|
||||
- avoids hiding lifecycle logic inside declaration expressions,
|
||||
- and prepares a clean handoff to later topic `19` work on module init, project init, and published entrypoint behavior.
|
||||
|
||||
The decision also rejects implicit complexity:
|
||||
|
||||
- no silent reuse of `const`,
|
||||
- no global re-export,
|
||||
- no ambiguous cross-category name merging,
|
||||
- and no procedural `fn`-driven initialization inside `declare global`.
|
||||
|
||||
## Mandatory Diagnostics
|
||||
|
||||
PBS must provide, at minimum, the following diagnostics for this policy:
|
||||
|
||||
1. `global initializer uses unsupported form`
|
||||
- emitted at the invalid subexpression inside a global initializer.
|
||||
2. `global dependency cycle detected`
|
||||
- emitted on the local participating global,
|
||||
- and should include the canonical cycle path when available.
|
||||
3. `imported symbol shadows existing visible symbol; alias required`
|
||||
- emitted when an imported `fn`, `service`, `global`, or `const` collides with an already-visible symbol of those categories.
|
||||
4. `global import must resolve through a global barrel entry`
|
||||
- emitted when import resolution would otherwise degrade a global into another category.
|
||||
|
||||
## Invariants
|
||||
|
||||
1. `declare const` and `declare global` remain semantically distinct.
|
||||
2. Runtime storage ownership remains attached to the canonical owner module.
|
||||
3. Global dependency order is semantic, not textual.
|
||||
4. Alias spelling must not change canonical global identity.
|
||||
5. The dependency-analysis kernel may be shared structurally, but semantic graph construction remains domain-owned.
|
||||
|
||||
## Explicit Non-Decisions
|
||||
|
||||
1. This decision does not define module init or project init behavior.
|
||||
2. This decision does not define `[INIT]`, `[FRAME]`, or lifecycle markers.
|
||||
3. This decision does not define published entrypoint or `FRAME_RET` ownership.
|
||||
4. This decision does not define the final IR representation of globals.
|
||||
5. This decision does not define host-call admissibility during lifecycle hooks.
|
||||
|
||||
## Spec Impact
|
||||
|
||||
This decision should feed at least:
|
||||
|
||||
1. `docs/compiler/pbs/specs/3. Core Syntax Specification.md`
|
||||
2. `docs/compiler/pbs/specs/4. Static Semantics Specification.md`
|
||||
3. `docs/compiler/pbs/specs/11. AST Specification.md`
|
||||
4. `docs/compiler/pbs/specs/12. Diagnostics Specification.md`
|
||||
|
||||
It also constrains future topic `19` work in:
|
||||
|
||||
1. `docs/compiler/pbs/agendas/19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda.md`
|
||||
2. `docs/compiler/pbs/agendas/19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda.md`
|
||||
3. `docs/compiler/pbs/agendas/19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda.md`
|
||||
|
||||
## Validation Notes
|
||||
|
||||
At minimum, validation for this decision should include:
|
||||
|
||||
1. accepted fixtures for `declare global` with primitive, member-value, `new`, and dependent-global initializers;
|
||||
2. rejection fixtures for forbidden initializer forms such as top-level `fn`, `some(...)`, `if`, and `switch`;
|
||||
3. import fixtures proving alias-based disambiguation;
|
||||
4. negative fixtures for cross-category collisions;
|
||||
5. dependency fixtures proving deterministic ordering independent of source-file order;
|
||||
6. cycle fixtures proving deterministic detection and diagnostics for intra-module and inter-module cycles.
|
||||
@ -0,0 +1,194 @@
|
||||
# Lifecycle Markers, Program Init, and Frame Root Semantics Decision
|
||||
|
||||
Status: Accepted
|
||||
Date: 2026-03-22
|
||||
Related Agenda: `docs/compiler/pbs/agendas/19.2. PBS Lifecycle Markers, Program Init, and Frame Root Semantics Agenda.md`
|
||||
|
||||
## Context
|
||||
|
||||
After closing the globals surface and module-boundary model, PBS v1 needed a precise lifecycle policy for:
|
||||
|
||||
- module bootstrap,
|
||||
- project bootstrap,
|
||||
- frame-root identification,
|
||||
- host-call admissibility during init,
|
||||
- and failure behavior at boot.
|
||||
|
||||
The key requirement was to keep initialization expressive enough for real setup work, while preserving deterministic semantics and preventing the declaration initializer of `global` from becoming a general procedural execution surface.
|
||||
|
||||
Important fixed inputs already existed:
|
||||
|
||||
- `declare global` lowers into module-owned runtime storage,
|
||||
- global initializers remain declarative and restricted,
|
||||
- top-level `fn` calls are not allowed inside `declare global` initializers,
|
||||
- `FRAME_SYNC` remains the only normative safepoint,
|
||||
- and PBS v1 remains deterministic and single-threaded.
|
||||
|
||||
## Decision
|
||||
|
||||
PBS adopts the following lifecycle-marker and bootstrap policy in v1:
|
||||
|
||||
1. PBS introduces the reserved userland attributes:
|
||||
- `[Init]`
|
||||
- `[Frame]`
|
||||
2. `[Frame]` is mandatory for an executable project.
|
||||
3. `[Frame]` is unique per executable project.
|
||||
4. `[Init]` is optional.
|
||||
5. `[Init]` may appear in ordinary userland source both for module-local bootstrap and for project bootstrap.
|
||||
6. Both `[Init]` and `[Frame]` require the same signature shape:
|
||||
- `fn name() -> void`
|
||||
7. Recommended canonical source forms are:
|
||||
|
||||
```pbs
|
||||
[Init]
|
||||
fn init() -> void { ... }
|
||||
```
|
||||
|
||||
```pbs
|
||||
[Frame]
|
||||
fn frame() -> void { ... }
|
||||
```
|
||||
|
||||
## Module Init and Project Init Policy
|
||||
|
||||
PBS adopts the following bootstrap layering:
|
||||
|
||||
1. Every module has exactly one synthetic module init.
|
||||
2. `declare global` always lowers into that synthetic module init.
|
||||
3. Each file may declare at most one `[Init]`.
|
||||
4. A file may declare `[Init]` even when it declares no globals.
|
||||
5. For one file:
|
||||
- that file's globals are materialized first,
|
||||
- then that file's `[Init]`, if present, executes.
|
||||
6. File-level init fragments are then composed into the one synthetic module init.
|
||||
7. The `[Init]` colocated in the same file as `[Frame]` is the project init.
|
||||
8. `[Init]` in other files remains module init.
|
||||
9. The distinction between module init and project init is one of ordering and semantic role, not one of different source syntax.
|
||||
10. There is therefore at most one project init per executable project.
|
||||
11. Project init uses the same signature shape:
|
||||
- `fn init() -> void`
|
||||
|
||||
## Bootstrap Order
|
||||
|
||||
PBS adopts the following logical bootstrap order:
|
||||
|
||||
1. materialize globals for each file according to dependency order,
|
||||
2. execute that file's `[Init]`, if present,
|
||||
3. compose those steps into one synthetic module init,
|
||||
4. after required module work is complete, execute project init, if present,
|
||||
5. then enter the first `frame()`.
|
||||
|
||||
Within one module:
|
||||
|
||||
1. file ordering must follow the order derived from the globals `DependencyGraphAnaliser`,
|
||||
2. and when two files have no dependency edge between them, the compiler must still use a deterministic stable order.
|
||||
|
||||
## Host Interaction During Init
|
||||
|
||||
PBS adopts the following init-time host-call policy:
|
||||
|
||||
1. Loops are permitted in module init and project init.
|
||||
2. Host calls are forbidden by default during init.
|
||||
3. The only host calls admissible during init are host methods marked with `[InitAllowed]`.
|
||||
4. `[InitAllowed]` is a reserved SDK attribute, not a userland attribute.
|
||||
5. `[InitAllowed]` has no arguments in v1.
|
||||
6. `[InitAllowed]` is valid only on SDK host methods.
|
||||
7. `[InitAllowed]` is invalid on userland `fn`, `global`, `service`, or any non-host-method surface.
|
||||
8. `[InitAllowed]` does not distinguish module init from project init.
|
||||
9. The difference between those phases is ordering and semantic role, not a separate host-permission class.
|
||||
10. Admissibility of `[InitAllowed]` must be checked at compile time.
|
||||
|
||||
Illustrative shape:
|
||||
|
||||
```pbs
|
||||
declare host Runtime {
|
||||
[Host(module = "runtime", name = "random_u32", version = 1)]
|
||||
[Capability(name = "runtime")]
|
||||
[InitAllowed]
|
||||
fn random_u32() -> int;
|
||||
}
|
||||
```
|
||||
|
||||
## Failure Policy
|
||||
|
||||
PBS adopts a fail-fast boot policy:
|
||||
|
||||
1. Failure during module init aborts boot.
|
||||
2. Failure during project init aborts boot.
|
||||
3. No automatic retry occurs on the next frame.
|
||||
4. Implementations must surface a coherent failure message identifying the failing boot phase.
|
||||
|
||||
## Rationale
|
||||
|
||||
This decision keeps the declaration initializer of `global` simple, while still allowing practical bootstrap work in later lifecycle stages.
|
||||
|
||||
That balance matters because:
|
||||
|
||||
- arrays and derived data often require loops during setup,
|
||||
- module bootstrap must remain expressive enough for real projects,
|
||||
- host interaction during boot must still be tightly controlled,
|
||||
- and the runtime model must remain deterministic and explainable.
|
||||
|
||||
Colocation of project init with frame was chosen deliberately as a source-organization rule.
|
||||
It avoids introducing a second project-level marker while keeping project bootstrap discoverable in source.
|
||||
|
||||
## Mandatory Diagnostics
|
||||
|
||||
PBS must provide, at minimum, the following diagnostics for this policy:
|
||||
|
||||
1. `project init must be colocated with frame`
|
||||
2. `multiple project init functions detected`
|
||||
3. `multiple frame functions detected`
|
||||
4. `missing frame function for executable project`
|
||||
5. `init function must have signature fn name() -> void`
|
||||
6. `frame function must have signature fn name() -> void`
|
||||
7. `host call not allowed during init`
|
||||
8. `InitAllowed is valid only on SDK host methods`
|
||||
9. `boot failed during module init`
|
||||
10. `boot failed during project init`
|
||||
11. `multiple module init functions detected`
|
||||
12. `Init attribute target invalid`
|
||||
|
||||
## Invariants
|
||||
|
||||
1. `[Frame]` remains unique per executable project.
|
||||
2. Project init is identified by colocation with `[Frame]`.
|
||||
3. Each file contributes at most one init fragment.
|
||||
4. Each module contributes exactly one synthetic module init.
|
||||
5. Host-call admissibility during init is explicit and compile-time validated.
|
||||
6. Boot ordering remains deterministic.
|
||||
|
||||
## Explicit Non-Decisions
|
||||
|
||||
1. This decision does not define the published synthetic wrapper entrypoint.
|
||||
2. This decision does not define `FRAME_RET` ownership.
|
||||
3. This decision does not define the final IR encoding of bootstrap.
|
||||
4. This decision does not define cartridge manifest publication details.
|
||||
|
||||
## Spec Impact
|
||||
|
||||
This decision should feed at least:
|
||||
|
||||
1. `docs/compiler/pbs/specs/3. Core Syntax Specification.md`
|
||||
2. `docs/compiler/pbs/specs/4. Static Semantics Specification.md`
|
||||
3. `docs/compiler/pbs/specs/9. Dynamic Semantics Specification.md`
|
||||
4. `docs/compiler/pbs/specs/12. Diagnostics Specification.md`
|
||||
|
||||
It also constrains future topic `19` work in:
|
||||
|
||||
1. `docs/compiler/pbs/agendas/19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda.md`
|
||||
2. `docs/compiler/pbs/agendas/19.4. Globals and Lifecycle Lowering to IRBackend/IRVM Agenda.md`
|
||||
3. `docs/compiler/pbs/agendas/19.5. Diagnostics, Manifest Propagation, and Conformance Coverage Agenda.md`
|
||||
|
||||
## Validation Notes
|
||||
|
||||
At minimum, validation for this decision should include:
|
||||
|
||||
1. accepted fixtures for `[Init]` and `[Frame]` with correct signatures;
|
||||
2. accepted fixtures for file-level `[Init]` without globals;
|
||||
3. accepted fixtures for loops inside module init and project init;
|
||||
4. rejection fixtures for invalid marker targets and invalid signatures;
|
||||
5. rejection fixtures for illegal host calls during init;
|
||||
6. accepted fixtures for SDK host calls marked `[InitAllowed]`;
|
||||
7. failure fixtures that distinguish module-init boot failure from project-init boot failure;
|
||||
8. ordering fixtures proving deterministic file ordering within one module.
|
||||
@ -0,0 +1,130 @@
|
||||
# Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Decision
|
||||
|
||||
Status: Accepted
|
||||
Date: 2026-03-22
|
||||
Related Agenda: `docs/compiler/pbs/agendas/19.3. Published Entrypoint, Synthetic Wrapper, and FRAME_RET Ownership Agenda.md`
|
||||
|
||||
## Context
|
||||
|
||||
After closing globals and lifecycle semantics, PBS v1 still needed a precise publication contract for executable boot.
|
||||
|
||||
The remaining problem was no longer how initialization behaves in userland.
|
||||
It was how that behavior is published into the artifact and consumed by backend stages and runtime.
|
||||
|
||||
The open points were:
|
||||
|
||||
- whether the published entrypoint is still the user `frame()` callable,
|
||||
- whether a synthetic wrapper becomes the true physical entrypoint,
|
||||
- where `FRAME_RET` must live once lifecycle bootstrap exists,
|
||||
- whether `FrontendSpec` continues to hold authority over entrypoint identity,
|
||||
- and whether `manifest.json` remains part of entrypoint authority.
|
||||
|
||||
Important fixed inputs already existed:
|
||||
|
||||
- `[Frame]` identifies the userland logical frame root,
|
||||
- module init and project init are already defined in lifecycle terms,
|
||||
- boot is one-shot and fail-fast,
|
||||
- and general backend specs already converge on entrypoint function index `0`.
|
||||
|
||||
## Decision
|
||||
|
||||
PBS adopts the following publication and ownership policy for executable boot in v1:
|
||||
|
||||
1. The compiler publishes a synthetic wrapper as the physical executable entrypoint.
|
||||
2. The userland callable marked with `[Frame]` remains the logical frame root of user code.
|
||||
3. The synthetic wrapper is therefore the physical root, while `[Frame]` remains the logical root.
|
||||
4. The wrapper must contain:
|
||||
- one-shot boot orchestration,
|
||||
- the required init execution exactly once,
|
||||
- invocation of the userland `[Frame]` callable,
|
||||
- and the final `FRAME_RET`.
|
||||
5. `FRAME_RET` no longer belongs at the end of the userland `frame()` body.
|
||||
6. `FRAME_RET` belongs to the published wrapper.
|
||||
7. The published wrapper must occupy physical entrypoint index `0`.
|
||||
|
||||
## Entrypoint Authority
|
||||
|
||||
PBS adopts the following authority model:
|
||||
|
||||
1. `FrontendSpec` no longer holds authority to decide which callable is the published entrypoint for PBS.
|
||||
2. Entrypoint authority is owned exclusively by the PBS compiler.
|
||||
3. Source-derived lifecycle semantics determine the logical frame root.
|
||||
4. The compiler then publishes the physical wrapper that realizes that lifecycle contract.
|
||||
5. Backend handoff must therefore preserve the compiler-selected published wrapper as the effective entrypoint identity.
|
||||
|
||||
## Manifest and Runtime Protocol
|
||||
|
||||
PBS adopts the following target protocol direction:
|
||||
|
||||
1. `entrypoint` must stop being part of the final `manifest.json` contract.
|
||||
2. Runtime boot must not depend on nominal entrypoint resolution from the manifest.
|
||||
3. Runtime boot must treat physical entrypoint index `0` as protocol.
|
||||
4. The compiler guarantees that the published wrapper occupies that index.
|
||||
5. Any temporary compatibility line with manifest-declared nominal entrypoint is transitional only and is not the target contract.
|
||||
|
||||
## Exports Boundary
|
||||
|
||||
PBS adopts the following boundary for nominal exports:
|
||||
|
||||
1. Nominal function exports may continue to exist in the emitted artifact.
|
||||
2. Those exports are no longer authoritative for loader or boot.
|
||||
3. Boot depends exclusively on the published physical entrypoint at index `0`.
|
||||
4. Nominal exports remain useful only for tooling, debug, introspection, and related non-boot concerns.
|
||||
|
||||
## Rationale
|
||||
|
||||
This decision keeps logical user semantics and physical boot publication clearly separated.
|
||||
|
||||
That matters because:
|
||||
|
||||
- the user `frame()` callable should remain the semantic root of frame logic,
|
||||
- the one-shot bootstrap sequence must still execute before normal frame work,
|
||||
- `FRAME_RET` should mark the true end of the logical published frame,
|
||||
- and the compiler must be the single authority that turns source lifecycle into executable publication.
|
||||
|
||||
The decision also deliberately removes duplicated authority:
|
||||
|
||||
- not `FrontendSpec`,
|
||||
- not manifest nominal metadata,
|
||||
- and not PBX nominal exports
|
||||
are allowed to compete with the compiler-selected physical wrapper as boot authority.
|
||||
|
||||
## Invariants
|
||||
|
||||
1. `[Frame]` remains the userland logical frame root.
|
||||
2. The published wrapper remains the physical executable root.
|
||||
3. `FRAME_RET` belongs to the published wrapper.
|
||||
4. Physical entrypoint index `0` belongs to that wrapper.
|
||||
5. Nominal exports are not boot authority.
|
||||
6. Entrypoint authority for PBS belongs to the compiler, not to `FrontendSpec` or manifest metadata.
|
||||
|
||||
## Explicit Non-Decisions
|
||||
|
||||
1. This decision does not define the final IR encoding of the wrapper body.
|
||||
2. This decision does not define the detailed lowering mechanics of globals and lifecycle into IR.
|
||||
3. This decision does not define the runtime-side migration implementation plan in detail.
|
||||
4. This decision does not define the final diagnostics catalog for backend/runtime structural failures.
|
||||
|
||||
## Spec Impact
|
||||
|
||||
This decision should feed at least:
|
||||
|
||||
1. `docs/compiler/pbs/specs/9. Dynamic Semantics Specification.md`
|
||||
2. `docs/compiler/pbs/specs/13. Lowering IRBackend Specification.md`
|
||||
3. `docs/compiler/pbs/specs/7. Cartridge Manifest and Runtime Capabilities Specification.md`
|
||||
4. `docs/compiler/general/specs/15. Bytecode and PBX Mapping Specification.md`
|
||||
5. `docs/compiler/general/specs/20. IRBackend to IRVM Lowering Specification.md`
|
||||
|
||||
It also requires explicit cross-domain propagation to:
|
||||
|
||||
1. `../runtime/docs/runtime/agendas/025-cartridge-manifest-entrypoint-removal-and-runtime-protocol.md`
|
||||
|
||||
## Validation Notes
|
||||
|
||||
At minimum, validation for this decision should include:
|
||||
|
||||
1. emitted artifact evidence that the published wrapper occupies function index `0`;
|
||||
2. conformance evidence that the userland `[Frame]` callable is invoked by that wrapper rather than being published directly;
|
||||
3. evidence that `FRAME_RET` is emitted in the wrapper path;
|
||||
4. evidence that nominal exports, when present, do not participate in boot authority;
|
||||
5. integration evidence that runtime boot aligns with the fixed physical entrypoint protocol.
|
||||
Loading…
x
Reference in New Issue
Block a user