Today let’s review command implementation in Mass (see repo). In the class library project, I have a dedicated namespace and folder for commands:
There are commands for if, while, for, for each, etc… Every command implements the ICommand interface:
public interface ICommand { object Execute(Context context); }
See that is very similar to IExpression. But I wanted to keep a separation between commands and expressions, at least for this first implementation, in order to have a clear separation of basis concerns.
A typical example of command is WhileCommand, partial code:
public class WhileCommand : ICommand { private static int hashcode = typeof(WhileCommand).GetHashCode(); private IExpression condition; private ICommand command; public WhileCommand(IExpression condition, ICommand command) { this.condition = condition; this.command = command; } public object Execute(Context context) { for (object value = this.condition.Evaluate(context); value != null && !false.Equals(value); value = this.condition.Evaluate(context)) { this.command.Execute(context); if (context.HasContinue()) context.ClearContinue(); if (context.HasBreak()) { context.ClearBreak(); break; } } return null; } }
In Mass, every null or false value is false. All other value is true. I should refactor the code to have a central method IsFalse to be invoked in the above While code and in other commands, like IfCommand.
Another sample of command is ForEachCommand, partial code:
public class ForEachCommand : ICommand { private string name; private IExpression expression; private ICommand command; public ForEachCommand(string name, IExpression expression, ICommand command) { this.name = name; this.expression = expression; this.command = command; } public object Execute(Context context) { var values = (IEnumerable)this.expression.Evaluate(context); foreach (var value in values) { context.Set(this.name, value); this.command.Execute(context); if (context.HasContinue()) context.ClearContinue(); if (context.HasBreak()) { context.ClearBreak(); break; } } return null; } }
See that for Mass every IEnumerable value can be used as the element provider for ForCommand. I added some methods to the current context to signal the present of a break or continue (in the current version, I added return treatment, too).
And, as usual, all this code was developed using TDD flow: you can read repo commit history.
Next posts: Lexer, Parser, Mass samples, Mass scripting, using Mass from our .NET programs.
Keep tuned!
Angel “Java” Lopez
Pingback: Mass Programming Language (2) First Expressions | Angel "Java" Lopez on Blog
Pingback: Mass Programming Language (3) Commands | MVPs de LATAM
Pingback: Mass Programming Language (4) Lexer and Parser | Angel "Java" Lopez on Blog
Pingback: New Month’s Resolutions: June 2013 | Angel "Java" Lopez on Blog
Pingback: Resoluciones del Nuevo Mes: Junio 2013 - Angel "Java" Lopez