Ridgun
The language itself: a compiler that compiles itself, the stable project tool, the specification and the book
| 1 | # Capítulo 02: Os seus dois melhores amigos: `ridgunc` e `stable` (Zero ficheiros YAML, prometido) |
| 2 | |
| 3 | Há linguagens cujo compilador é maravilhoso, mas cujo sistema de projetos parece desenhado pelo seu pior inimigo: ora um `Makefile` de 400 linhas com tabulações invisíveis, ora um `pom.xml` infinito, ora um `webpack.config.js` que deixa de funcionar se olhar fixamente para ele... |
| 4 | |
| 5 | Em Ridgun fizemos uma promessa muito simples desde o primeiro dia: |
| 6 | |
| 7 | > *"Só haverá dois executáveis em todo o ecossistema (`ridgunc` e `stable`), ambos serão escritos no próprio Ridgun, e o ficheiro de configuração do projeto (`build.rg`) será código Ridgun normal e corrente. Nem JSON, nem YAML, nem TOML, nem invenções estranhas."* |
| 8 | |
| 9 | Vamos ver como se usam. |
| 10 | |
| 11 | --- |
| 12 | |
| 13 | ## 2.1. `ridgunc`: O atirador furtivo para ficheiros soltos |
| 14 | |
| 15 | Quando tem um único ficheiro `.rg` em mãos e quer testar uma ideia rápida, analisar os seus tipos ou compilar um executável, fala diretamente com o **`ridgunc`**. |
| 16 | |
| 17 | Só tem 4 comandos que realmente precisa de recordar: |
| 18 | |
| 19 | ```bash |
| 20 | # 1. "Isto compila ou meti água com algum tipo?" |
| 21 | ridgunc check experiencia.rg |
| 22 | |
| 23 | # 2. "Executa já!" (Compila e corre de uma só vez) |
| 24 | ridgunc run experiencia.rg |
| 25 | |
| 26 | # 3. "Faz-me um binário nativo ELF pronto a levar" |
| 27 | ridgunc build experiencia.rg -o meu_programa |
| 28 | |
| 29 | # 4. "Gera-me o artefacto intermédio de bytecode (.rgc)" |
| 30 | ridgunc compile experiencia.rg -o experiencia.rgc |
| 31 | ``` |
| 32 | |
| 33 | ### O superpoder oculto de `ridgunc check` |
| 34 | Quando lança `ridgunc check`, não lhe diz apenas *"0 erros"*. Também lhe revela que estratégia o analisador estático escolheu para cada uma das suas funções: |
| 35 | - **`InlineSequential`**: *"Esta função é pequenina e direta; vou executá-la em linha sem introduzir sobrecarga de escalonamento"*. |
| 36 | - **`LazyStealableTask`**: *"Aqui há recursão ou um grafo paralelo `||`; preparo-a para que outros núcleos de CPU possam roubar trabalho se for preciso"*. |
| 37 | |
| 38 | ### O bisturi de `ridgunc build` (Porque é que os seus binários não pesam 20 MB) |
| 39 | Quando executa `ridgunc build`, o compilador não se limita a despejar todo o código das bibliotecas que tenha importado: |
| 40 | 1. Começa na sua função `main` e percorre o grafo de chamadas para ver **que funções usa de verdade**. Se importou uma biblioteca enorme de 80 funções mas só chama 2, as outras 78 são descartadas antes sequer de tocar no assembly (*Tree-Shaking*). |
| 41 | 2. Procura todas as funções recursivas de cauda e converte-as em ciclos `loop` nativos que consomem **0 bytes de pilha**. |
| 42 | 3. Passa a ligação final com otimização global (*fat LTO*) e limpa o lixo de depuração DWARF para lhe deixar um binário compacto e afiado (~350 KB). |
| 43 | |
| 44 | --- |
| 45 | |
| 46 | ## 2.2. `stable`: Quando o seu projeto cresce e quer ordem |
| 47 | |
| 48 | Um ficheiro solto é ótimo para um script, mas assim que tem vários módulos, bibliotecas partilhadas e testes, precisa de um maestro de orquestra. Esse é o **`stable`**. |
| 49 | |
| 50 | A estrutura de pastas de um projeto Ridgun não tem mistério: |
| 51 | |
| 52 | ```text |
| 53 | minha-super-ferramenta/ |
| 54 | ├── build.rg # O manifesto do projeto (é código Ridgun!) |
| 55 | ├── src/ |
| 56 | │ ├── main/ |
| 57 | │ │ └── ridgun/ |
| 58 | │ │ ├── lib/ # Os seus módulos reutilizáveis (`import utilitarios`) |
| 59 | │ │ └── app/ |
| 60 | │ │ └── main.rg # Ponto de entrada (`main => ()`) |
| 61 | │ └── test/ |
| 62 | │ └── ridgun/ # As suas baterias de testes (`test *.rg`) |
| 63 | │ └── test tudo.rg |
| 64 | └── target/ # Onde aparecem os binários compilados |
| 65 | ``` |
| 66 | |
| 67 | --- |
| 68 | |
| 69 | ## 2.3. `build.rg`: Um ficheiro de configuração que nunca lhe mentirá |
| 70 | |
| 71 | Porque nos recusamos a usar YAML ou TOML para configurar um projeto Ridgun? |
| 72 | Porque em YAML engana-se em dois espaços de indentação e só descobre quando falha a implementação. Em contrapartida, como **`build.rg` é um ficheiro Ridgun**, tem tipos estáticos, passa pelo `stable check` e alinha-se sozinho com `stable format`: |
| 73 | |
| 74 | ```ridgun |
| 75 | type ProjectInfo = |
| 76 | name: String |
| 77 | version: String |
| 78 | edition: String |
| 79 | |
| 80 | project => ProjectInfo |
| 81 | project = ProjectInfo "minha-super-ferramenta" "0.1.0" "2026" |
| 82 | |
| 83 | source dir => String |
| 84 | source dir = "src/main/ridgun" |
| 85 | |
| 86 | test dir => String |
| 87 | test dir = "src/test/ridgun" |
| 88 | |
| 89 | target dir => String |
| 90 | target dir = "target" |
| 91 | |
| 92 | -- Opcional: ativa o modo estrito de assinaturas e nomes (desativado por omissão) |
| 93 | strict mode => Bool |
| 94 | strict mode = True |
| 95 | ``` |
| 96 | |
| 97 | Se cometer um erro ao escrever um campo, o próprio compilador avisa-o. Sem surpresas. |
| 98 | |
| 99 | ### O modo estrito (`--strict` / `strict mode = True`) |
| 100 | Por omissão, tanto o `ridgunc` como os novos projetos criados com `stable new` ou `stable init` têm o modo estrito **desativado** para que possa prototipar com total liberdade. Quando quiser blindar o estilo canónico de um projeto (como fazemos no próprio compilador do Ridgun), pode passar `--strict` ao `ridgunc` ou adicionar `strict mode = True` ao seu `build.rg`. O modo estrito exige duas regras de elegância: |
| 101 | 1. **Nomes de `fn ::` e `op ::` com espaços naturais, sem `_`**: as declarações devem usar espaços (`fn :: calcular imposto`, nunca `fn :: calcular_imposto`). |
| 102 | 2. **Retornos múltiplos separados por espaços após `=>`**: quando uma função ou operador devolve vários valores, a sua assinatura de saída escreve-se `=> Int Int` ou `=> Estado Int` (nunca `=> (Int, Int)` com parênteses nem vírgulas). |
| 103 | |
| 104 | --- |
| 105 | |
| 106 | ## 2.4. A sua rotina diária com `stable` (Os 4 fantásticos) |
| 107 | |
| 108 | Quando está a trabalhar dentro do seu projeto, o seu dia a dia resume-se a quatro comandos: |
| 109 | |
| 110 | ### 1. `stable format` — O fim das discussões de estilo na equipa |
| 111 | ```bash |
| 112 | stable format |
| 113 | ``` |
| 114 | O seu colega põe três espaços antes do `=>` e você põe um? Tanto faz. Executa `stable format` e em menos de um segundo deixa **todos** os ficheiros `.rg` do repositório alinhados como um relógio suíço. |
| 115 | |
| 116 | ### 2. `stable check` — O radar instantâneo |
| 117 | ```bash |
| 118 | stable check |
| 119 | ``` |
| 120 | Percorre todos os módulos de `src/main/ridgun/`, verifica tipos, construtores, aridades e dimensões de tensores, e dá-lhe o veredito módulo a módulo. |
| 121 | |
| 122 | ### 3. `stable test` — Dormir descansado à noite |
| 123 | ```bash |
| 124 | stable test |
| 125 | ``` |
| 126 | Procura todas as suites `src/test/ridgun/test *.rg`, executa-as e comprova cada `assert equals` e `assert true`. |
| 127 | |
| 128 | ```ridgun |
| 129 | -- Exemplo de src/test/ridgun/test matematica.rg |
| 130 | import test |
| 131 | |
| 132 | dobro Int => Int |
| 133 | dobro x = x * 2 |
| 134 | |
| 135 | main => () |
| 136 | main = |
| 137 | assert equals (dobro 21) 42 |
| 138 | assert true ((dobro 5) > 0) |
| 139 | ``` |
| 140 | |
| 141 | ### 4. `stable built` (e `stable clean`) — Para produção |
| 142 | ```bash |
| 143 | stable built |
| 144 | ``` |
| 145 | Compila todos os alvos nativos em `target/`. E se algum dia quiser apagar `target/` e começar limpo: `stable clean`. |
| 146 | |
| 147 | --- |
| 148 | |
| 149 | ## 2.5. Como importo um ficheiro a partir de outro? (`import`) |
| 150 | |
| 151 | Sem caminhos relativos infernais do tipo `../../../lib/coisas.rg`. Se tiver um ficheiro `src/main/ridgun/lib/cadeias.rg`, em qualquer outro ficheiro escreve mesmo no topo: |
| 152 | |
| 153 | ```ridgun |
| 154 | import cadeias |
| 155 | ``` |
| 156 | |
| 157 | E pronto: todas as funções e tipos de `cadeias.rg` ficam disponíveis como se estivessem no seu próprio ficheiro. E o que acontece se o módulo `A` fizer `import cadeias`, o módulo `B` também fizer `import cadeias`, e o seu `main.rg` importar `A` e `B`? Fique descansado: o carregador do Ridgun lembra-se de que ficheiros canónicos já leu e **só o inclui uma vez**. |
| 158 | |
| 159 | Agora que tem a caixa de ferramentas controlada, passemos ao **Capítulo 03** para dominar as funções, os tipos, os blocos e os truques com cadeias de texto. |