English {#english}
Honest Build: No Fake Exception Codegen
CrabPascal offers two execution paths: run (internal runtime interpreter) and build-exe (C code generation + native compiler). For a long time, the codegen path pretended to support exceptions — emitting stub blocks that compiled but did not behave like Delphi or like run. v2.21.0 (Sprint 13) ends that charade.
The problem with simulated exceptions
Consider typical Delphi error handling:
try
ProcessOrder(OrderId);
except
on E: Exception do
LogError(E.Message);
end;
In the runtime, try/except unwinds the stack and matches exception types. The old C backend generated placeholder code — enough to pass a compile step, not enough to run correctly. Worse, it hid parity gaps: developers thought native build worked until production crashed differently than run.
That violates a core CrabPascal principle: honest tooling. If we cannot do it correctly yet, say so loudly.
What changed in v2.21.0
The codegen module now refuses to generate C for:
-
try/except/finallyblocks -
raisestatements
Instead you get an explicit error pointing to run:
crab-pascal build-exe MyApp.dpr
# error: exception handling not supported in native codegen yet; use `crab-pascal run`
This aligns expectations immediately. CI pipelines fail for the right reason, not silently.
When to use each path
| Command | Best for |
|---|---|
run |
Development, Horse APIs, OOP with exceptions, rapid iteration |
check |
IDE feedback, CI static analysis |
build-exe |
Performance-sensitive code without exception constructs |
crab-pascal check examples/crud/crud.dpr
crab-pascal run examples/crud/crud.dpr
The CRUD example uses JSON and HTTP — exception-free hot paths compile fine with build-exe where supported.
Regression test
Sprint 13 added codegen::tests::test_codegen_errors_on_try_raise, locking the behavior:
// Pseudocode intent: codegen must Err on try/raise, not emit fake C
assert!(codegen_result.is_err());
assert!(message.contains("use `run`"));
Future work on real exception lowering (setjmp/longjmp, table-based handlers, or LLVM) will flip specific tests green — not reintroduce silent stubs.
Roadmap for real native exceptions
Honest failure is step one. Step two is implementing Delphi-compatible exception tables in codegen — likely coordinated with RTL types in System.SysUtils and runtime object layout. Until then, document the split clearly (this article, release notes, check hints).
Developer takeaway
If your project relies on structured exception handling — and most Delphi code does — run is the supported path today. Native build is for subsets of the language where parity is proven. Sprint 13 chose trust over checkbox features. That makes CrabPascal safer to adopt incrementally.
Questions? @crabpascal on Dev.to or issues on Bitbucket.
Português {#portugus}
Build honesto: sem codegen falso de exceptions
O CrabPascal oferece dois caminhos de execução: run (interpretador/runtime interno) e build-exe (geração de C + compilador nativo). Por muito tempo, o codegen fingia suportar exceptions — emitindo blocos stub que compilavam mas não se comportavam como Delphi nem como run. O v2.21.0 (Sprint 13) acaba com essa farsa.
O problema das exceptions simuladas
Considere tratamento de erro típico em Delphi:
try
ProcessOrder(OrderId);
except
on E: Exception do
LogError(E.Message);
end;
No runtime, try/except desempilha a stack e casa tipos de exception. O backend C antigo gerava código placeholder — bastava para passar compilação, não para rodar certo. Pior: escondia gaps de paridade — desenvolvedores achavam que o build nativo funcionava até produção falhar diferente de run.
Isso viola um princípio central do CrabPascal: ferramentas honestas. Se ainda não dá para fazer certo, diga alto.
O que mudou no v2.21.0
O módulo codegen agora recusa gerar C para:
- blocos
try/except/finally - instruções
raise
Em vez disso, você recebe erro explícito apontando para run:
crab-pascal build-exe MyApp.dpr
# error: exception handling not supported in native codegen yet; use `crab-pascal run`
Expectativas alinhadas na hora. Pipelines CI falham pelo motivo certo, não silenciosamente.
Quando usar cada caminho
| Comando | Melhor para |
|---|---|
run |
Desenvolvimento, APIs Horse, OOP com exceptions, iteração rápida |
check |
Feedback IDE, análise estática em CI |
build-exe |
Código sensível a performance sem construtos de exception |
crab-pascal check examples/crud/crud.dpr
crab-pascal run examples/crud/crud.dpr
O exemplo CRUD usa JSON e HTTP — hot paths sem exception compilam com build-exe onde suportado.
Teste de regressão
O Sprint 13 adicionou codegen::tests::test_codegen_errors_on_try_raise, fixando o comportamento:
// Intenção: codegen deve Err em try/raise, não emitir C falso
assert!(codegen_result.is_err());
assert!(message.contains("use `run`"));
Trabalho futuro em lowering real de exceptions (setjmp/longjmp, handlers tabulares ou LLVM) fará testes específicos passarem — sem reintroduzir stubs silenciosos.
Roadmap para exceptions nativas reais
Falhar honestamente é o passo um. O passo dois é implementar tabelas de exception compatíveis com Delphi no codegen — provavelmente coordenado com tipos RTL em System.SysUtils e layout de objetos no runtime. Até lá, documentar a divisão claramente (este artigo, release notes, hints do check).
Conclusão para desenvolvedores
Se seu projeto depende de exception handling estruturado — e a maioria do código Delphi depende — run é o caminho suportado hoje. Build nativo é para subconjuntos da linguagem onde a paridade está comprovada. O Sprint 13 escolheu confiança em vez de checkbox de feature. Isso torna o CrabPascal mais seguro para adoção incremental.
Dúvidas? @crabpascal no Dev.to ou issues no Bitbucket.
Published on dev.to/@crabpascal · Código em CrabPascal
Top comments (0)