English {#english}
Nova Arquitetura v2.0.1: A Turning Point
Postman tests in post 036 proved Horse APIs run. Under the hood, that only works because v2.0.1 stopped pretending to be a toy interpreter with infinite hardcoded shims. The architectural pivot is documented in nova-arquitetura-v2-0-1 and the broader design rationale in arquitetura-design.
The v2.0.0 problem: simulated everything
Before v2.0.1, complete_runtime.rs contained a growing match function_name table — THorse.Get, IntToStr, TJSONObject.Create, ad infinitum. Every new Delphi unit meant more Rust simulation, not more Pascal.
// Anti-pattern we retired
match function_name {
"THorse.Get" => { /* hand-waved HTTP */ },
"IntToStr" => { /* special case */ },
// ... unbounded growth
}
That scaled poorly and wasn't a real compiler — it was an interpreter wearing Delphi cosplay.
v2.0.1 solution: real units from real projects
The new pipeline reads Delphi project metadata and loads .pas files from configured search paths:
.dpr program
↓
.dproj (optional) → DCC_UnitSearchPath
↓
ProjectConfig.find_unit_file("Horse")
↓
Parse + execute actual Horse.pas sources
ProjectConfig in src/project_config.rs parses .dproj XML:
<DCC_UnitSearchPath>
examples\crud\modules;
examples\crud\modules\horse\src;
</DCC_UnitSearchPath>
Paths resolve relative to the project directory, with recursive search when needed.
Runtime integration
CompletePascalRuntime accepts optional config:
pub struct CompletePascalRuntime {
project_config: Option<ProjectConfig>,
// ...
}
impl CompletePascalRuntime {
pub fn with_config(project_config: Option<ProjectConfig>) -> Self { /* ... */ }
}
Unit loading changed from hardcoded guesses:
// Before: vec!["examples/agenda/Foo.pas", ...]
// After:
if let Some(path) = config.find_unit_file(unit_name) {
self.parse_and_load_unit(path, unit_name)?;
}
main.rs loads config at startup when a sibling .dproj exists — transparent for crab-pascal run myapp.dpr.
Five-phase compiler context
arquitetura-design places v2.0.1 inside the classic pipeline:
Lexer → Parser → Semantic → Codegen / Runtime
↑
Unit resolver + ProjectConfig feed real symbols here
Frontend analysis stays in Rust. Library behavior increasingly lives in Pascal RTL shims under rtl/sys/ and third-party .pas trees — the same split Delphi uses.
Why this matters for Horse and CRUD
Your Postman session hits routes compiled from real Horse units on the search path, not a 200-line Rust stub. When Horse adds middleware signatures, you update Pascal sources — the compiler loads them on next run.
Recursive unit loading (blog post 026) builds on this foundation: once paths are honest, dependency graphs follow .pas uses clauses naturally.
Trade-offs we accept
-
Requires search paths — missing
.dprojfalls back to cwd; document paths in examples. - Parse cost — first load parses units; cache wins on repeat runs within process.
-
Not full MSBuild — we read paths, not every Delphi conditional;
crabpascal.tomlfills gaps.
Migration checklist for your project
- Add or verify
.dprojwithDCC_UnitSearchPath - Mirror paths in
crabpascal.tomlif you skip.dproj - Run
crab-pascal check— unresolved unit errors should name the missing path - Compare
runvsbuild-exeparity (post 040)
v2.0.1 was the line between demo and platform. Everything since — sprints, Mintlify architecture section, honest build — assumes real units.
Related modules in the repo
Trace these files while reading nova-arquitetura-v2-0-1:
| File | Role |
|---|---|
src/project_config.rs |
.dproj XML → search paths |
src/unit_resolver.rs |
Recursive uses graph |
src/main.rs |
Wires config into run / check
|
mintlify/architecture/carregamento-recursivo-v2-0-1.md |
Deep dive on recursive loading |
When a unit fails to resolve, enable verbose logging and print the candidate paths ProjectConfig tried — most "Horse not found" reports are misconfigured DCC_UnitSearchPath, not missing compiler features.
Next in series
Post 038 — Runtime Internals dives into heap allocation, virtual method tables, and built-in dispatch — the machinery that makes OOP Pascal actually run after units load.
Português {#portugus}
Nova arquitetura v2.0.1: ponto de virada
Testes Postman no post 036 provaram que APIs Horse rodam. Por baixo, isso só funciona porque a v2.0.1 parou de fingir ser interpretador de brinquedo com shims hardcoded infinitos. A virada arquitetural está em nova-arquitetura-v2-0-1 e a rationale ampla em arquitetura-design.
O problema da v2.0.0: simular tudo
Antes da v2.0.1, complete_runtime.rs tinha uma tabela match function_name crescente — THorse.Get, IntToStr, TJSONObject.Create, sem fim. Cada unit Delphi nova significava mais simulação em Rust, não mais Pascal.
// Anti-padrão que aposentamos
match function_name {
"THorse.Get" => { /* HTTP improvisado */ },
"IntToStr" => { /* caso especial */ },
// ... crescimento ilimitado
}
Isso não escalava e não era compilador de verdade — era interpretador de fantasia Delphi.
Solução v2.0.1: units reais de projetos reais
O pipeline novo lê metadados de projeto Delphi e carrega .pas dos search paths configurados:
programa .dpr
↓
.dproj (opcional) → DCC_UnitSearchPath
↓
ProjectConfig.find_unit_file("Horse")
↓
Parse + executa fontes Horse.pas de verdade
ProjectConfig em src/project_config.rs parseia XML do .dproj:
<DCC_UnitSearchPath>
examples\crud\modules;
examples\crud\modules\horse\src;
</DCC_UnitSearchPath>
Paths resolvem relativos ao diretório do projeto, com busca recursiva quando necessário.
Integração no runtime
CompletePascalRuntime aceita config opcional:
pub struct CompletePascalRuntime {
project_config: Option<ProjectConfig>,
// ...
}
impl CompletePascalRuntime {
pub fn with_config(project_config: Option<ProjectConfig>) -> Self { /* ... */ }
}
Carregamento de units saiu de chutes hardcoded:
// Antes: vec!["examples/agenda/Foo.pas", ...]
// Depois:
if let Some(path) = config.find_unit_file(unit_name) {
self.parse_and_load_unit(path, unit_name)?;
}
main.rs carrega config na subida quando existe .dproj irmão — transparente para crab-pascal run myapp.dpr.
Contexto do compilador em cinco fases
arquitetura-design encaixa v2.0.1 no pipeline clássico:
Lexer → Parser → Semântica → Codegen / Runtime
↑
Unit resolver + ProjectConfig alimentam símbolos reais aqui
Análise frontend fica em Rust. Comportamento de biblioteca migra para shims Pascal em rtl/sys/ e árvores .pas de terceiros — o mesmo split do Delphi.
Por que importa para Horse e CRUD
Sua sessão Postman acerta rotas compiladas de units Horse reais no search path, não stub Rust de 200 linhas. Quando Horse ganha assinaturas de middleware, você atualiza Pascal — o compilador recarrega na próxima execução.
Carregamento recursivo de units (post 026) constrói sobre isso: paths honestos, grafo de dependências segue uses naturalmente.
Trade-offs que aceitamos
-
Exige search paths — sem
.dprojcai no cwd; documente paths nos exemplos. - Custo de parse — primeira carga parseia units; cache ajuda na mesma execução.
-
Não é MSBuild completo — lemos paths, não todo conditional Delphi;
crabpascal.tomlpreenche lacunas.
Checklist de migração do seu projeto
- Adicione ou verifique
.dprojcomDCC_UnitSearchPath - Espelhe paths em
crabpascal.tomlse pular.dproj - Rode
crab-pascal check— erros de unit devem nomear path faltante - Compare paridade
runvsbuild-exe(post 040)
v2.0.1 foi a linha entre demo e plataforma. Tudo desde então — sprints, seção arquitetura Mintlify, build honesto — assume units reais.
Módulos relacionados no repo
Trace estes arquivos lendo nova-arquitetura-v2-0-1:
| Arquivo | Papel |
|---|---|
src/project_config.rs |
XML .dproj → search paths |
src/unit_resolver.rs |
Grafo recursivo de uses
|
src/main.rs |
Liga config em run / check
|
mintlify/architecture/carregamento-recursivo-v2-0-1.md |
Deep dive em carga recursiva |
Quando unit falha ao resolver, habilite log verbose e imprima paths candidatos — a maioria dos "Horse not found" são DCC_UnitSearchPath mal configurado, não feature faltando no compilador.
Próximo da série
Post 038 — Internals do runtime mergulha em heap, tabelas de métodos virtuais e dispatch de built-ins — a maquinaria que faz OOP Pascal rodar depois que units carregam.
Published on dev.to/@crabpascal · Código em CrabPascal