0%
Pular para o conteúdo principal
0%

4.1 O Avaliador Metacircular

Nosso avaliador para JavaScript será implementado como um programa JavaScript. Pode parecer circular pensar em avaliar programas JavaScript usando um avaliador que é ele mesmo implementado em JavaScript. No entanto, a avaliação é um processo, portanto é apropriado descrever o processo de avaliação usando JavaScript, que, afinal, é nossa ferramenta para descrever processos.1 Um avaliador que é escrito na mesma linguagem que ele avalia é dito ser metacircular.

O avaliador metacircular é essencialmente uma formulação JavaScript do modelo de ambiente de avaliação descrito na seção 3.2. Lembre-se de que o modelo especifica a avaliação da aplicação de função em dois passos básicos:

  1. Para avaliar uma aplicação de função, avalie as subexpressões e depois aplique o valor da subexpressão de função aos valores das subexpressões de argumento.

  2. Para aplicar uma função composta a um conjunto de argumentos, avalie o corpo da função em um novo ambiente. Para construir este ambiente, estenda a parte de ambiente do objeto função por um frame no qual os parâmetros da função estão vinculados aos argumentos aos quais a função é aplicada.

Estas duas regras descrevem a essência do processo de avaliação, um ciclo básico no qual declarações e expressões a serem avaliadas em ambientes são reduzidas a funções a serem aplicadas a argumentos, que por sua vez são reduzidas a novas declarações e expressões a serem avaliadas em novos ambientes, e assim por diante, até chegarmos a nomes, cujos valores são procurados no ambiente, e a operadores e funções primitivas, que são aplicados diretamente (veja a figura 4.1).

Figura 4.1: O ciclo eval-apply

Nota: O ciclo central entre evaluate e apply; casos base em verde

Este ciclo de avaliação será incorporado pela interação entre as duas funções críticas no avaliador, evaluate e apply, que são descritas na seção 4.1.1 (veja a figura 4.1).

A implementação do avaliador dependerá de funções que definem a sintaxe das declarações e expressões a serem avaliadas. Usaremos abstração de dados para tornar o avaliador independente da representação da linguagem. Por exemplo, em vez de nos comprometermos com a escolha de que uma atribuição deve ser representada por uma string começando com um nome seguido por =, usamos um predicado abstrato is_assignment para testar uma atribuição, e usamos seletores abstratos assignment_symbol e assignment_value_expression para acessar as partes de uma atribuição. As camadas de abstração de dados apresentadas na seção 4.1.2 permitirão que o avaliador permaneça independente de questões sintáticas concretas, como as palavras-chave da linguagem interpretada, e da escolha de estruturas de dados que representam os componentes do programa. Também existem operações, descritas na seção 4.1.3, que especificam a representação de funções e ambientes. Por exemplo, make_function constrói funções compostas, lookup_symbol_value acessa os valores de nomes, e apply_primitive_function aplica uma função primitiva a uma determinada lista de argumentos.

Footnotes

  1. Ainda assim, permanecerão aspectos importantes do processo de avaliação que não são elucidados por nosso avaliador. Os mais importantes destes são os mecanismos detalhados pelos quais as funções chamam outras funções e retornam valores para seus chamadores. Abordaremos essas questões no capítulo 5, onde examinaremos mais de perto o processo de avaliação implementando o avaliador como uma máquina de registrador simples.