Episódio 22 — Interpretador com suporte a condições aninhadas e encadeadas
No episódio anterior, vimos como criar um interpretador capaz de ler uma estrutura JSON com parâmetros e executar ações correspondentes. Agora, daremos um passo importante para permitir expressões condicionais aninhadas e encadeadas, transformando nosso interpretador em um motor de decisão.
O problema
Imagine uma estrutura como esta:
{
"if": {
"cond": "Saldo > 1000",
"then": {
"acao": "EnviarEmail",
"para": "cliente@exemplo.com"
},
"else": {
"if": {
"cond": "Saldo > 0",
"then": {
"acao": "EnviarSMS",
"para": "99999-9999"
},
"else": {
"acao": "RegistrarErro",
"mensagem": "Saldo insuficiente."
}
}
}
}
}
Aqui temos:
- Encadeamento de "if" dentro de "else"
- Condições simples escritas como strings
- Ações parametrizadas por campos JSON
Nosso interpretador precisa entender esse formato e tratá-lo como uma árvore de decisão.
A estratégia
- Reconhecimento do bloco "if":
- O interpretador verifica se o JSON possui a chave "if".
- Avaliação da condição:
- Interpreta a string
Saldo > 1000usando um mini-avaliador de expressões.
- Interpreta a string
- Execução recursiva:
- Se a condição for verdadeira, executa o bloco "then"
- Se for falsa, verifica se há um bloco "else" e executa-o
- Se o "else" for outro "if", a recursividade acontece naturalmente
Mini-avaliador de condições
Implementamos um mecanismo simples que avalia condições usando variáveis do contexto atual:
function AvaliarExpressao(const Expressao: string; const Contexto: TDictionary<string, Variant>): Boolean;
Ele suporta:
- Operadores:
=,<>,>,>=,<,<= - Comparadores com strings, números e booleanos
Isso permite interpretar Saldo > 1000 ou Status = 'Ativo'
Benefício dessa abordagem
- Permite criar fluxos complexos sem recompilar
- Facilita testes com diferentes cenários de dados
- Desacopla regras de negócio do código-fonte
O que vem a seguir
No próximo episódio, vamos implementar listas de comandos sequenciais, ou seja:
{
"acao": [
{ "acao": "CarregarDados" },
{ "acao": "ValidarCampos" },
{ "acao": "GravarBanco" },
{ "acao": "MostrarMensagem", "texto": "Sucesso!" }
]
}
Ou seja: um array de ações executadas sequencialmente, mantendo o interpretador flexível e poderoso.
Vamos seguir nessa jornada. As regras já não estão mais no código-fonte. Elas estão nas mãos de quem entende do negócio.