Interpreter
O Interpreter é um padrão comportamental utilizado para representar uma linguagem ou gramática e interpretar expressões dessa linguagem.
Em outras palavras, podemos criar uma pequena linguagem e construir um sistema capaz de entendê-la.
Imagine uma expressão:
5 + 3
Ou:
10 * 2
O Interpreter pode representar essas expressões como objetos e avaliá-las.
A ideia
Podemos representar:
5 + 3
como:
AddExpression
├── Number(5)
└── Number(3)
Ou:
10 * 2
como:
MultiplyExpression
├── Number(10)
└── Number(2)
Cada expressão sabe como interpretar a si mesma.
Interface
interface Expression {
interpret(): number;
}
Número:
class NumberExpression
implements Expression {
constructor(
private value: number
) {}
interpret() {
return this.value;
}
}
Adição:
class AddExpression
implements Expression {
constructor(
private left: Expression,
private right: Expression
) {}
interpret() {
return (
this.left.interpret() +
this.right.interpret()
);
}
}
Multiplicação:
class MultiplyExpression
implements Expression {
constructor(
private left: Expression,
private right: Expression
) {}
interpret() {
return (
this.left.interpret() *
this.right.interpret()
);
}
}
Agora podemos criar:
const expression =
new AddExpression(
new NumberExpression(5),
new NumberExpression(3)
);
Interpretamos:
console.log(
expression.interpret()
);
Resultado:
8
Podemos criar expressões mais complexas:
const expression =
new MultiplyExpression(
new AddExpression(
new NumberExpression(5),
new NumberExpression(3)
),
new NumberExpression(2)
);
Isso representa:
(5 + 3) * 2
Resultado:
16
Exemplo prático: filtros
Imagine uma linguagem simples para filtros:
age > 18
Ou:
age > 18 AND active = true
Podemos criar uma estrutura que representa essas expressões:
AND
├── age > 18
└── active = true
Depois podemos interpretar essa estrutura contra um objeto:
const user = {
age: 25,
active: true
};
O resultado seria:
true
Esse conceito aparece em:
SQL
Query Builders
Regras de negócio
Filtros
Compiladores
DSLs
Expressões matemáticas
Interpreter e AST
Em compiladores e linguagens de programação, expressões frequentemente são representadas como uma:
Abstract Syntax Tree (AST)
Por exemplo:
5 + 3 * 2
Pode ser representado como:
+
/ \
5 *
/ \
3 2
A árvore representa a estrutura da expressão.
Um interpretador pode percorrer essa árvore e calcular o resultado.
Esse é um conceito fundamental em:
- Compiladores.
- Interpretadores.
- Linguagens de programação.
- Analisadores de código.
- Query engines.
Quando usar?
Interpreter é útil quando:
- Precisamos criar uma linguagem simples.
- Temos uma gramática bem definida.
- Precisamos interpretar expressões.
- Queremos representar regras como uma estrutura de objetos.
Exemplos:
Filtros
DSLs
Expressões matemáticas
Regras de negócio
Query languages
Compiladores
Interpretadores
Porém, para linguagens grandes e complexas, implementar um Interpreter diretamente pode ser difícil e custoso. Nesses casos, normalmente utilizamos ferramentas especializadas de parsing e compilação.
A ideia principal é:
Representar uma linguagem ou gramática como uma estrutura de objetos que pode ser interpretada.