Ao abrir um livro de padrões de projeto, o padrão Interpreter quase sempre aparece perto do fim. É fácil passar por ele pensando: “Quando isso é usado?”
Porém, ao criar um app de calculadora, chegou o momento de calcular diretamente expressões matemáticas em strings. Foi quando o padrão Interpreter se encaixou perfeitamente.
Neste artigo, vamos criar em Swift um interpretador de linguagem muito pequeno, ou seja, uma minilinguagem. O objetivo é ler expressões como 1 + 2 * 3 e retornar o número 7.
Em resumo, a conclusão é esta:
O padrão Interpreter transforma cada regra gramatical em uma classe (ou enum), monta tudo em uma árvore e percorre essa estrutura recursivamente para obter o resultado.
Parece difícil, mas o código é mais simples do que parece. Vamos construir juntos.
O que é o padrão Interpreter?
O padrão Interpreter é uma forma de criar uma “linguagem pequena própria” e representar em código as regras para interpretá-la.
Não estamos falando de uma linguagem grandiosa. Qualquer expressão pequena com uma gramática definida, como uma fórmula, um filtro de busca ou um script de regras de jogo, se enquadra aqui.
A ideia central é uma só.
Transforme cada elemento da gramática em um objeto e faça esses objetos terem um método interpret() que interprete a si próprio.
Por exemplo, pense na expressão 1 + 2. Ela contém o número 1, o número 2 e a operação de adição +.
O número é interpretado como “vou retornar meu valor”, enquanto a adição é interpretada como “vou interpretar a esquerda e a direita e somá-las”.
Essas pequenas regras formam uma árvore; basta chamar a interpretação uma vez no topo para concluir o cálculo descendo pela estrutura.
Projetando uma árvore de expressões em Swift
No Swift, enum combina muito bem com esse padrão. Com um enum recursivo, é possível representar a árvore de forma bem limpa.
No início, implementei com protocolos e classes, mas trocar para enum reduziu o código pela metade.
Primeiro, definimos um enum que representa uma expressão: um número único e os casos de somar ou multiplicar duas expressões.
Como esse enum contém a si próprio, precisamos adicionar a palavra-chave indirect.
indirect enum Expr {
case number(Double) // literal numérico
case add(Expr, Expr) // adição
case multiply(Expr, Expr) // multiplicação
}
Agora criamos uma função para interpretar essa árvore. Processar cada caso recursivamente é o núcleo do padrão Interpreter.
A função a seguir recebe uma expressão, calcula seu valor numérico real e o retorna.
func interpret(_ expr: Expr) -> Double {
switch expr {
case .number(let value):
return value
case .add(let l, let r):
return interpret(l) + interpret(r)
case .multiply(let l, let r):
return interpret(l) * interpret(r)
}
}
A partir daqui, podemos montar 1 + 2 * 3 como uma árvore e calculá-la.
Se criarmos a árvore manualmente, como em .add(.number(1), .multiply(.number(2), .number(3))), e a passarmos para interpret, o resultado será 7.
Como transformar uma expressão em string em uma árvore?
Aqui surge uma dúvida: o usuário não digita uma árvore, mas uma string como "1 + 2 * 3".
O processo de transformar essa string em uma árvore se chama parsing, e o código que faz isso é o parser.
Na abordagem tradicional, o parser é dividido em duas etapas.
- Lexer: divide a string em tokens (por exemplo:
1,+,2) - Parser: monta os tokens em uma árvore de acordo com as regras gramaticais
Implementar bem essas duas etapas deixaria o artigo longo demais, então aqui vamos tratar apenas do conceito.
O ponto principal é este: o padrão Interpreter cuida apenas da interpretação da árvore. Fazer o parsing da string para convertê-la em árvore é outra tarefa.
Por isso, durante o aprendizado, recomendo deixar o parser de lado por um momento, montar a árvore manualmente e concluir primeiro o interpretador. Assim, a essência do padrão fica clara.
Onde isso é usado na prática?
Sinceramente, não é comum implementar o padrão Interpreter do zero. Para linguagens complexas, é muito melhor usar uma biblioteca de parsing já consolidada.
Ainda assim, entender esse padrão traz muitos benefícios.
- Ajuda a entender como um mecanismo de expressões regulares funciona internamente
- Permite entender por que a sintaxe declarativa do SwiftUI tem uma estrutura de árvore
- Pode ser aplicado diretamente na criação de uma DSL (Domain-Specific Language, linguagem específica de domínio) pequena, como um filtro de busca ou um avaliador de expressões
Especialmente quando a gramática é simples e o escopo é restrito, como em uma calculadora, um filtro condicional ou um script de jogo, fazer você mesmo pode ser mais limpo.
Depois que aprendi esse padrão, a estrutura de views do SwiftUI passou a parecer completamente diferente. Cada view era, no fim, um nó da árvore interpretada.
Resumo
Hoje vimos o padrão Interpreter enquanto criávamos um interpretador de minilinguagem em Swift.
Criar uma árvore de expressões com um enum recursivo e interpretá-la recursivamente com a função interpret. É só isso.
Mesmo que pareça estranho no início, ao calcular 1 + 2 * 3 por conta própria chega o momento de pensar: “Ah, então era isso”. Espero que você digite pelo menos uma vez o código aprendido hoje.
Continue lendo
- Swift Copy-on-Write: como tipos por valor substituem o padrão Prototype (resumo conceitual)
- Criando uma máquina de estados (FSM) com enum em Swift: como gerenciar estados sem o padrão State
- Padrão Object Pool em Swift (Object Pool Pattern): guia completo (diferenças em relação ao Flyweight e reutilização)

