Continuando con esta serie de posts, esta vez agregaré un parser sencillo. La nueva solución:
Pueden bajar el código desde InterpreterStep05.zip. La nueva clase agregada es:
El parse puede ser construido usando un TextReader o un string:
public class Parser { private Lexer lexer; public Parser(Lexer lexer) { this.lexer = lexer; } public Parser(TextReader reader) : this(new Lexer(reader)) { } public Parser(string text) : this(new Lexer(text)) { } //... }Tengo sólo dos Expr essions por ahora (ConstantExpr ession y VariableExpr ession). El método público ParseExpr ession ahora reconoce enteros y nombres(el lexer todavía no reconoce strings delimitados):
public IExpr ession ParseExpr ession() { Token token = this.NextToken(); if (token == null) return null; if (token.TokenType == TokenType.Integer) return new ConstantExpr ession(token.Value); if (token.TokenType == TokenType.String) return new ConstantExpr ession(token.Value); if (token.TokenType == TokenType.Name) return new VariableExpr ession((string) token.Value); throw new InvalidDataException(string.Format("Unexpected token '{0}'", token.Value)); }El parser usa al lexer que comenté en el anterior post de la serie. Como antes, el nuevo Parser y el método ParseExpr ession fueron escritos usando TDD. Algunos tests:
[TestMethod] public void ParseIntegerExpr ession() { Parser parser = new Parser("1"); IExpr ession Expr ession = parser.ParseExpr ession(); Assert.IsNotNull(Expr ession); Assert.IsInstanceOfType(Expr ession, typeof(ConstantExpr ession)); Assert.AreEqual(1, Expr ession.Evaluate(null)); Assert.IsNull(parser.ParseExpr ession()); } [TestMethod] public void ParseVariableExpr ession() { Parser parser = new Parser("one"); IExpr ession Expr ession = parser.ParseExpr ession(); Assert.IsNotNull(Expr ession); Assert.IsInstanceOfType(Expr ession, typeof(VariableExpr ession)); VariableExpr ession varexpr = (VariableExpr ession)Expr ession; Assert.AreEqual("one", varexpr.Name); Assert.IsNull(parser.ParseExpr ession()); }Todos los tes están en verde:
![]()
Buen code coverage:
![]()
Noten que usando TDD puedo agregar características nuevas en “baby steps” (pasos de bebé), evitando tiempos de depuración o agregar grandes fragmentos de código de una vez. Y siempre tengo al retroalimentación “verde”: cada cosa nueva que se agrega se prueba compatible con el anterior código.
Próximos pasos: agregar más expresiones (aritmética, operadores, ..) y comandos (como if, for, …), “entrenando” al parser en reconocerlas,. Luego puedo agregar al lexer el proceso de strings delimitados por dobles comillas.
Nos leemos!
Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez