Angel \”Java\” Lopez on Blog

January 19, 2011

Writing an Interpreter in .NET (Part 8)

Filed under: .NET, Programming Languages, Test-Driven Development — ajlopez @ 11:02 am

Back to this project! Writing an interpreter, using C# and TDD. In this step, I added a new ICommand, the WhileCommand:

You can download the current version from InterpreterStep08.zip. If you want to see all the steps, I commit the code in under trunk/Interpreter in my AjCodeKatas Google code project.

The code for WhileCommand is simple:

    public class WhileCommand : ICommand
    {
        private IExpression condition;
        private ICommand command;
        public WhileCommand(IExpression condition, ICommand command)
        {
            this.condition = condition;
            this.command = command;
        }
        public IExpression Condition { get { return this.condition; } }
        public ICommand Command { get { return this.command; } }
        public void Execute(BindingEnvironment environment)
        {
            while (BooleanPredicates.IsTrue(this.condition.Evaluate(environment)))
                this.command.Execute(environment);
        }
    }

Note that I added a BooleanPredicates class. It was born as a refactor of previous code I used in IfCommand implementation. I wrote in the previous post about my intentions of such refactoring. Using TDD, I have tests of the new class, an example:

        [TestMethod]
        public void IsFalse()
        {
            Assert.IsTrue(BooleanPredicates.IsFalse(null));
            Assert.IsTrue(BooleanPredicates.IsFalse(string.Empty));
            Assert.IsTrue(BooleanPredicates.IsFalse(0));
            Assert.IsTrue(BooleanPredicates.IsFalse((short)0));
            Assert.IsTrue(BooleanPredicates.IsFalse((long)0));
            Assert.IsTrue(BooleanPredicates.IsFalse(0.0));
            Assert.IsTrue(BooleanPredicates.IsFalse((float)0.0));
            Assert.IsFalse(BooleanPredicates.IsFalse(new object()));
            Assert.IsFalse(BooleanPredicates.IsFalse("foo"));
            Assert.IsFalse(BooleanPredicates.IsFalse(1));
            Assert.IsFalse(BooleanPredicates.IsFalse((short)2));
            Assert.IsFalse(BooleanPredicates.IsFalse((long)3));
            Assert.IsFalse(BooleanPredicates.IsFalse(4.0));
            Assert.IsFalse(BooleanPredicates.IsFalse((float)5.0));
        }

The test is, then, a kind of specification: what is false for my interpreter?

I tested the new command in isolation:

        [TestMethod]
        public void EvaluateWhileCommandUsingDecrement()
        {
            BindingEnvironment environment = new BindingEnvironment();
            environment.SetValue("a", 2);
            IExpression condition = new VariableExpression("a");
            ICommand command = new SetCommand("a", new BinaryArithmeticExpression(new VariableExpression("a"), new ConstantExpression(1), ArithmeticOperator.Subtract));
            WhileCommand wcommand = new WhileCommand(condition, command);
            Assert.AreEqual(command, wcommand.Command);
            Assert.AreEqual(condition, wcommand.Condition);
            wcommand.Execute(environment);
            Assert.AreEqual(0, environment.GetValue("a"));
        }

Then, I added support for the process of the command in the Parser:

        private ICommand ParseWhileCommand()
        {
            IExpression condition;
            ICommand cmd;
            this.ParseToken(TokenType.Separator, "(");
            condition = this.ParseExpression();
            this.ParseToken(TokenType.Separator, ")");
            cmd = this.ParseCommand();
            return new WhileCommand(condition, cmd);
        }

Obviously, with tests 😉 :

        [TestMethod]
        public void ParseAndEvaluateSimpleWhileCommand()
        {
            Parser parser = new Parser("while (a) a = a-1;");
            ICommand command = parser.ParseCommand();
            Assert.IsNotNull(command);
            Assert.IsInstanceOfType(command, typeof(WhileCommand));
            BindingEnvironment environment = new BindingEnvironment();
            environment.SetValue("a", 2);
            command.Execute(environment);
            Assert.AreEqual(0, environment.GetValue("a"));
        }

I could add more tests, but now, the new command is in good health. All tests still in green:

Good code coverage:

Next steps: composite commands, for/foreach commands, function declaration…

Keep tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

1 Comment »

  1. […] Previous Post First post of the series […]

    Pingback by Writing an Interpreter in .NET (Part 9) « Angel “Java” Lopez on Blog — January 27, 2011 @ 11:21 am


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: