Previous Post
Some time ago I write this project, an Erlang implementation as interpreter using C #. Let review today the implementation of expressions. An expression is evaluated in a context. For example, the variable X, is an expression that is evaluated in a context that tells how that variable is bound to a value or it is free.
All expressions are written using the workflow TDD (Test-Driven Development). After some expressions, this interface emerge in a refactor, and now all expressions implement it:
public interface IExpression
{
object Evaluate(Context context, bool withvars = false);
bool HasVariable();
}
The key method is Evaluate. It can allow or not that some variables are still unbound after the evaluate. There is a boolean method HasVariable that indicates the existence of variables in the expression. The simplest expression is a constant expression:
public class ConstantExpression : IExpression
{
private object value;
public ConstantExpression(object value)
{
this.value = value;
}
public object Value { get { return this.value; } }
public object Evaluate(Context context, bool withvars = false)
{
return this.value;
}
public bool HasVariable()
{
return false;
}
}
The Evaluate method does not use the provided context, it is only returning the original constant value, defined in the constructor. The expressions are grouped in a tree of expressions that is recursively evaluated.
An expression that evaluates a variable:
public class VariableExpression : IExpression
{
private Variable variable;
public VariableExpression(Variable variable)
{
this.variable = variable;
}
public Variable Variable { get { return this.variable; } }
public object Evaluate(Context context, bool withvars = false)
{
if (!context.HasValue(this.variable.Name))
if (!withvars)
throw new Exception(string.Format("variable '{0}' is unbound", this.variable.Name));
else
return this.variable;
return context.GetValue(this.variable.Name);
}
public bool HasVariable()
{
return true;
}
}
This time, the context is used. If the variable is not bound to a value, it can return the unbound value, or raise an exception, depending on a boolean withValues. Some times, Erlang expects and needs that an expression be complete evaluated, having no unbound variables.
This code was implemented following the workflow of TDD. Some tests as examples (but it is only the final result, the important thing is the workflow, the dynamic of the programming activity). For a constant expression:
[TestMethod]
public void CreateSimpleConstantExpression()
{
ConstantExpression expr = new ConstantExpression(10);
Assert.AreEqual(10, expr.Value);
}
[TestMethod]
public void EvaluateSimpleConstantExpression()
{
ConstantExpression expr = new ConstantExpression(10);
Assert.AreEqual(10, expr.Evaluate(null));
}
For a variable expression:
[TestMethod]
public void CreateSimpleVariableExpression()
{
Variable variable = new Variable("X");
VariableExpression expression = new VariableExpression(variable);
Assert.AreEqual(variable, expression.Variable);
}
[TestMethod]
public void EvaluateVariableExpression()
{
Variable variable = new Variable("X");
Context context = new Context();
context.SetValue("X", 1);
VariableExpression expression = new VariableExpression(variable);
Assert.AreEqual(1, expression.Evaluate(context));
}
[TestMethod]
public void EvaluateUndefinedVariableExpression()
{
Variable variable = new Variable("X");
Context context = new Context();
VariableExpression expression = new VariableExpression(variable);
Assert.AreEqual(variable, expression.Evaluate(context, true));
}
[TestMethod]
public void RaiseIfEvaluateUndefinedVariableExpression()
{
Variable variable = new Variable("X");
Context context = new Context();
VariableExpression expression = new VariableExpression(variable);
try
{
expression.Evaluate(context, false);
Assert.Fail();
}
catch (Exception ex)
{
Assert.AreEqual("variable 'X' is unbound", ex.Message);
}
}
Upcoming topics: explore other expression implementations, data structure implementations for variables, maps, and more…
Stay tuned!
Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez