Escribiendo un intérprete en .NET (Parte 3)

Esta es la tercera parte de esta serie:

Writing an Interpreter in .NET (Part 1)
Escribiendo un intérprete en .NET (Parte 1)
Writing an Interpreter in .NET (Part 2)
Escribiendo un intérprete en .NET (Parte 2)

Hasta ahora, tenemos implementado IExpression, ConstantExpression and VariableExpression, usando un BindingEnvironment para almacenar un diccionaro de nombres-valores para las variables. Podría reimplementar este environment u otras partes si necesito nueva funcionalidad: usando TDD, es relativamente fácil agregar nuevas características, preservando las anteriores (eso pasó en la parte 2, donde al agregar BindingEnvironment cambió el Evaluate de las IExpressions.

En este post, quiero agregar comandos (pueden bajar el código desde InterpreterStep03.zip):

Esta interfaz ICommand es:

namespace Interpreter
{
    public interface ICommand
    {
        void Execute(BindingEnvironment environment);
    }
}


El método Execute recibe el estado actual, ahora representado por un  BindingEnvironment. El código fue desarrollado usando TDD: no necesito nada más para implementar los tests.



Primer comando para implementar: SetCommand, que pone un valor en una variable usando el nombre y una expresión a evaluar:





Primeros tests:



 



        [TestMethod]
        public void CreateSetCommand()
        {
            SetCommand command = new SetCommand("foo", new 
                ConstantExpr ession(1));
            Assert.AreEqual("foo", command.Name);
            Assert.IsInstanceOfType(command.Expression, typeof(ConstantExpression));
        }
        [TestMethod]
        public void ExecuteSetCommand()
        {
            BindingEnvironment environment = new BindingEnvironment();
            ICommand command = new SetCommand("one", new ConstantExpr ession(1));
            command.Execute(environment);
            Assert.AreEqual(1, environment.GetValue("one"));
        }


 



El código de implementación:



    public class SetCommand : ICommand
    {
        private string name;
        private IExpression expression;
        public SetCommand(string name, IExpression expression)
        {
            this.name = name;
            this.expression = expression;
        }
        public string Name { get { return this.name; } }
        public IExpression Expression { get { return this.expression; } }
        public void Execute(BindingEnvironment environment)
        {
            environment.SetValue(this.name, this.expression.Evaluate(environment));
        }
    }


Noten que el nombre de la variable y la expresión a evaluar son entregadas en el constructor.



Ahora, los tests están en verde:





Buen coverage:





Próximo paso: agregar un lexer, analizador léxico, que toma un string o un archivo, y va separando los tokens: las “palabras” de nuestro lenguaje a interpretar. Vean que podríamos implementar todo el núcleo del lenguaje (expresiones, comandos, variables…) por un lado, en un proyecto, y la sintaxis en otro (o en varios otros, usar distintos lenjuages externos, de distintas sintaxis, para construir las instancias de un árbol de evaluación). Por simplicidad, agregaré el lexer y después el parser en el mismo proyecto.



Nos leemos!



Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

This entry was posted in 11699, 1389, 8870. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>