<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://msmvps.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Angel "Java" Lopez : Lenguajes de Programaci&amp;#243;n, TDD</title><link>http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/TDD/default.aspx</link><description>Tags: Lenguajes de Programaci&amp;#243;n, TDD</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>Mass Lenguaje de Programación (4) Lexer y Parser</title><link>http://msmvps.com/blogs/lopez/archive/2013/05/12/mass-lenguaje-de-programaci-243-n-4-lexer-y-parser.aspx</link><pubDate>Sun, 12 May 2013 08:40:21 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1830015</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1830015</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2013/05/12/mass-lenguaje-de-programaci-243-n-4-lexer-y-parser.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2013/04/28/mass-lenguaje-de-programaci-243-n-3-comandos.aspx"&gt;Anterior Post&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;En la implementación del lenguaje Mass, tengo una enumeración y una clase:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/mass0401.jpg" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Un Token representa una palabra del código a procesar. El encargado de separar el código en palabras es el Lexer. Y con el Parser se transforma esa corriente de Tokens en expresiones y comandos:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/mass0402.jpg" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;El constructor de Lexer recibe un string:&lt;/p&gt;  &lt;pre style="background-color:black;width:600px;color:white;font-size:10pt;"&gt;&lt;span style="color:orange;"&gt;public&lt;/span&gt; Lexer&lt;span style="color:cyan;"&gt;(&lt;/span&gt;&lt;span style="color:orange;"&gt;string&lt;/span&gt; text&lt;span style="color:cyan;"&gt;)&lt;/span&gt;
&lt;span style="color:cyan;"&gt;{&lt;/span&gt;
    &lt;span style="color:orange;"&gt;this&lt;/span&gt;.text = text&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
&lt;span style="color:cyan;"&gt;}&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;Y ese string es procesado para separarlo en tokens. Vean que el Lexer distingue entre operadores (como +) y separadores (como los paréntesis). También toma en cuenta al fin de línea como token (en otros lenguajes, como C, un fin de línea se puede tomar como un espacio en blanco en muchas situaciones). El principal método de Lexer es NextToken, que devuelve el próximo Token del texto. En algunas pocas situaciones, se hace necesario devolver el Token consumido, y para eso está PushToken y varianes.&lt;/p&gt;

&lt;p&gt;El Parser interamente maneja un Lexer. Le podemos pedir el próximo comando con ParseCommand, y la próxima expresión con ParseExpression. Cuando el texto en proceso se acaba, esos métodos devuelven null.&lt;/p&gt;

&lt;p&gt;Voy a modificar el Lexer para consumir un stream de texto, para poder procesar, por ejemplo, entrada de consola&lt;/p&gt;

&lt;p&gt;Tengo que seguir pensando si internamente, unifico comandos y expresiones, como pasa en Ruby, donde cada “comando” tiene un valor (en Mass también es así), y no solamente eso, sino que puede ser usado como expresión en el contexto de un comando.&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1830015" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/C+Sharp/default.aspx">C Sharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_26002300_243_3B00_digo+Abierto/default.aspx">Proyectos de C&amp;#243;digo Abierto</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Mass/default.aspx">Mass</category></item><item><title>Mass Lenguaje de Programación (3) Comandos</title><link>http://msmvps.com/blogs/lopez/archive/2013/04/28/mass-lenguaje-de-programaci-243-n-3-comandos.aspx</link><pubDate>Sun, 28 Apr 2013 11:24:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1828666</guid><dc:creator>lopez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1828666</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2013/04/28/mass-lenguaje-de-programaci-243-n-3-comandos.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2013/04/27/mass-lenguaje-de-programaci-243-n-2-primeras-expresiones.aspx"&gt;Anterior Post&amp;nbsp;&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2013/05/12/mass-lenguaje-de-programaci-243-n-4-lexer-y-parser.aspx"&gt;Siguiente Post&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Veamos hoy c&amp;oacute;mo est&amp;aacute;n implementados los comandos en Mass (&lt;a href="http://github.com/ajlopez/Mass"&gt;ver repo&lt;/a&gt;). En el proyecto de librer&amp;iacute;a de clases, tengo:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/mass0301.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Hay comandos para if, while, for, for each, etc&amp;hellip;. Todos implementan la interfaz ICommand:&lt;/p&gt;
&lt;pre style="background-color:black;color:white;"&gt;&lt;span style="color:orange;"&gt;public&lt;/span&gt; &lt;span style="color:orange;"&gt;interface&lt;/span&gt; ICommand
&lt;span style="color:cyan;"&gt;{&lt;/span&gt;
    &lt;span style="color:orange;"&gt;object&lt;/span&gt; Execute&lt;span style="color:cyan;"&gt;(&lt;/span&gt;Context context&lt;span style="color:cyan;"&gt;);&lt;/span&gt;
&lt;span style="color:cyan;"&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Vean que es muy parecido a IExpression. Igual quise mantener comandos y expresiones por separado, por lo menos en esta primera implementaci&amp;oacute;n, para tener un claro delineamiento de los conceptos de base del lenguaje.&lt;/p&gt;
&lt;p&gt;Un ejemplo t&amp;iacute;pico de comando es el WhileCommand (parte del c&amp;oacute;digo):&lt;/p&gt;
&lt;pre style="background-color:black;color:white;"&gt;&lt;span style="color:orange;"&gt;public&lt;/span&gt; &lt;span style="color:orange;"&gt;class&lt;/span&gt; WhileCommand : ICommand
&lt;span style="color:cyan;"&gt;{&lt;/span&gt;
    &lt;span style="color:orange;"&gt;private&lt;/span&gt; &lt;span style="color:orange;"&gt;static&lt;/span&gt; &lt;span style="color:orange;"&gt;int&lt;/span&gt; hashcode = &lt;span style="color:orange;"&gt;typeof&lt;/span&gt;&lt;span style="color:cyan;"&gt;(&lt;/span&gt;WhileCommand&lt;span style="color:cyan;"&gt;)&lt;/span&gt;.GetHashCode&lt;span style="color:cyan;"&gt;();&lt;/span&gt;

    &lt;span style="color:orange;"&gt;private&lt;/span&gt; IExpression condition&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
    &lt;span style="color:orange;"&gt;private&lt;/span&gt; ICommand command&lt;span style="color:cyan;"&gt;;&lt;/span&gt;

    &lt;span style="color:orange;"&gt;public&lt;/span&gt; WhileCommand&lt;span style="color:cyan;"&gt;(&lt;/span&gt;IExpression condition&lt;span style="color:cyan;"&gt;,&lt;/span&gt; ICommand command&lt;span style="color:cyan;"&gt;)&lt;/span&gt;
    &lt;span style="color:cyan;"&gt;{&lt;/span&gt;
        &lt;span style="color:orange;"&gt;this&lt;/span&gt;.condition = condition&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
        &lt;span style="color:orange;"&gt;this&lt;/span&gt;.command = command&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
    &lt;span style="color:cyan;"&gt;}&lt;/span&gt;

    &lt;span style="color:orange;"&gt;public&lt;/span&gt; &lt;span style="color:orange;"&gt;object&lt;/span&gt; Execute&lt;span style="color:cyan;"&gt;(&lt;/span&gt;Context context&lt;span style="color:cyan;"&gt;)&lt;/span&gt;
    &lt;span style="color:cyan;"&gt;{&lt;/span&gt;
        &lt;span style="color:orange;"&gt;for&lt;/span&gt; &lt;span style="color:cyan;"&gt;(&lt;/span&gt;&lt;span style="color:orange;"&gt;object&lt;/span&gt; value = &lt;span style="color:orange;"&gt;this&lt;/span&gt;.condition.Evaluate&lt;span style="color:cyan;"&gt;(&lt;/span&gt;context&lt;span style="color:cyan;"&gt;);&lt;/span&gt; 
            value &lt;span style="color:cyan;"&gt;!&lt;/span&gt;= &lt;span style="color:orange;"&gt;null&lt;/span&gt; &lt;span style="color:cyan;"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span style="color:cyan;"&gt;!&lt;/span&gt;&lt;span style="color:orange;"&gt;false&lt;/span&gt;.Equals&lt;span style="color:cyan;"&gt;(&lt;/span&gt;value&lt;span style="color:cyan;"&gt;);&lt;/span&gt;
            value = &lt;span style="color:orange;"&gt;this&lt;/span&gt;.condition.Evaluate&lt;span style="color:cyan;"&gt;(&lt;/span&gt;context&lt;span style="color:cyan;"&gt;))&lt;/span&gt;
        &lt;span style="color:cyan;"&gt;{&lt;/span&gt;
            &lt;span style="color:orange;"&gt;this&lt;/span&gt;.command.Execute&lt;span style="color:cyan;"&gt;(&lt;/span&gt;context&lt;span style="color:cyan;"&gt;);&lt;/span&gt;
            &lt;span style="color:orange;"&gt;if&lt;/span&gt; &lt;span style="color:cyan;"&gt;(&lt;/span&gt;context.HasContinue&lt;span style="color:cyan;"&gt;())&lt;/span&gt;
                context.ClearContinue&lt;span style="color:cyan;"&gt;();&lt;/span&gt;
            &lt;span style="color:orange;"&gt;if&lt;/span&gt; &lt;span style="color:cyan;"&gt;(&lt;/span&gt;context.HasBreak&lt;span style="color:cyan;"&gt;())&lt;/span&gt;
            &lt;span style="color:cyan;"&gt;{&lt;/span&gt;
                context.ClearBreak&lt;span style="color:cyan;"&gt;();&lt;/span&gt;
                &lt;span style="color:orange;"&gt;break&lt;/span&gt;&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
            &lt;span style="color:cyan;"&gt;}&lt;/span&gt;
        &lt;span style="color:cyan;"&gt;}&lt;/span&gt;

        &lt;span style="color:orange;"&gt;return&lt;/span&gt; &lt;span style="color:orange;"&gt;null&lt;/span&gt;&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
    &lt;span style="color:cyan;"&gt;}&lt;/span&gt;
&lt;span style="color:cyan;"&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Para Mass: cualquier valor null o false es falso. Todo lo dem&amp;aacute;s es verdadero. Un tema a refactorizar: poner un m&amp;eacute;todo IsFalse para se usado tanto en la implementaci&amp;oacute;n de While como de If.&lt;/p&gt;
&lt;p&gt;Otro ejemplo es el ForEachCommand (parte del c&amp;oacute;digo):&lt;/p&gt;
&lt;pre style="background-color:black;color:white;"&gt;&lt;span style="color:orange;"&gt;public&lt;/span&gt; &lt;span style="color:orange;"&gt;class&lt;/span&gt; ForEachCommand : ICommand
&lt;span style="color:cyan;"&gt;{&lt;/span&gt;
    &lt;span style="color:orange;"&gt;private&lt;/span&gt; &lt;span style="color:orange;"&gt;string&lt;/span&gt; name&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
    &lt;span style="color:orange;"&gt;private&lt;/span&gt; IExpression expression&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
    &lt;span style="color:orange;"&gt;private&lt;/span&gt; ICommand command&lt;span style="color:cyan;"&gt;;&lt;/span&gt;

    &lt;span style="color:orange;"&gt;public&lt;/span&gt; ForEachCommand&lt;span style="color:cyan;"&gt;(&lt;/span&gt;&lt;span style="color:orange;"&gt;string&lt;/span&gt; name&lt;span style="color:cyan;"&gt;,&lt;/span&gt; IExpression expression&lt;span style="color:cyan;"&gt;,&lt;/span&gt; ICommand command&lt;span style="color:cyan;"&gt;)&lt;/span&gt;
    &lt;span style="color:cyan;"&gt;{&lt;/span&gt;
        &lt;span style="color:orange;"&gt;this&lt;/span&gt;.name = name&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
        &lt;span style="color:orange;"&gt;this&lt;/span&gt;.expression = expression&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
        &lt;span style="color:orange;"&gt;this&lt;/span&gt;.command = command&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
    &lt;span style="color:cyan;"&gt;}&lt;/span&gt;

    &lt;span style="color:orange;"&gt;public&lt;/span&gt; &lt;span style="color:orange;"&gt;object&lt;/span&gt; Execute&lt;span style="color:cyan;"&gt;(&lt;/span&gt;Context context&lt;span style="color:cyan;"&gt;)&lt;/span&gt;
    &lt;span style="color:cyan;"&gt;{&lt;/span&gt;
        var values = &lt;span style="color:cyan;"&gt;(&lt;/span&gt;IEnumerable&lt;span style="color:cyan;"&gt;)&lt;/span&gt;&lt;span style="color:orange;"&gt;this&lt;/span&gt;.expression.Evaluate&lt;span style="color:cyan;"&gt;(&lt;/span&gt;context&lt;span style="color:cyan;"&gt;);&lt;/span&gt;

        &lt;span style="color:orange;"&gt;foreach&lt;/span&gt; &lt;span style="color:cyan;"&gt;(&lt;/span&gt;var value &lt;span style="color:orange;"&gt;in&lt;/span&gt; values&lt;span style="color:cyan;"&gt;)&lt;/span&gt;
        &lt;span style="color:cyan;"&gt;{&lt;/span&gt;
            context.Set&lt;span style="color:cyan;"&gt;(&lt;/span&gt;&lt;span style="color:orange;"&gt;this&lt;/span&gt;.name&lt;span style="color:cyan;"&gt;,&lt;/span&gt; value&lt;span style="color:cyan;"&gt;);&lt;/span&gt;
            &lt;span style="color:orange;"&gt;this&lt;/span&gt;.command.Execute&lt;span style="color:cyan;"&gt;(&lt;/span&gt;context&lt;span style="color:cyan;"&gt;);&lt;/span&gt;
            &lt;span style="color:orange;"&gt;if&lt;/span&gt; &lt;span style="color:cyan;"&gt;(&lt;/span&gt;context.HasContinue&lt;span style="color:cyan;"&gt;())&lt;/span&gt;
                context.ClearContinue&lt;span style="color:cyan;"&gt;();&lt;/span&gt;
            &lt;span style="color:orange;"&gt;if&lt;/span&gt; &lt;span style="color:cyan;"&gt;(&lt;/span&gt;context.HasBreak&lt;span style="color:cyan;"&gt;())&lt;/span&gt;
            &lt;span style="color:cyan;"&gt;{&lt;/span&gt;
                context.ClearBreak&lt;span style="color:cyan;"&gt;();&lt;/span&gt;
                &lt;span style="color:orange;"&gt;break&lt;/span&gt;&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
            &lt;span style="color:cyan;"&gt;}&lt;/span&gt;
        &lt;span style="color:cyan;"&gt;}&lt;/span&gt;

        &lt;span style="color:orange;"&gt;return&lt;/span&gt; &lt;span style="color:orange;"&gt;null&lt;/span&gt;&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
    &lt;span style="color:cyan;"&gt;}&lt;/span&gt;
&lt;span style="color:cyan;"&gt;}&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Vean que para Mass, todo lo que sea IEnumerable se puede usar para ser consumido por este comando. Tuve que poner algunos datos en el contexto, para saber si se hab&amp;iacute;a hecho un break o un continue.&lt;/p&gt;
&lt;p&gt;Y como siempre, todo esto desarrollado con TDD: pueden &lt;a href="https://github.com/ajlopez/Mass/commits/master"&gt;ver los commits del repo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Pr&amp;oacute;ximos posts: Lexer y Parser, ejemplos de Mass para scripting.&lt;/p&gt;
&lt;p&gt;Nos leemos!&lt;/p&gt;
&lt;p&gt;Angel &amp;ldquo;Java&amp;rdquo; Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 
  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1828666" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/C+Sharp/default.aspx">C Sharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_26002300_243_3B00_digo+Abierto/default.aspx">Proyectos de C&amp;#243;digo Abierto</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Mass/default.aspx">Mass</category></item><item><title>Mass Lenguaje de Programación (2) Primeras Expresiones</title><link>http://msmvps.com/blogs/lopez/archive/2013/04/27/mass-lenguaje-de-programaci-243-n-2-primeras-expresiones.aspx</link><pubDate>Sat, 27 Apr 2013 13:26:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1828597</guid><dc:creator>lopez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1828597</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2013/04/27/mass-lenguaje-de-programaci-243-n-2-primeras-expresiones.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2013/04/08/mass-lenguaje-de-programaci-243-n-1-or-237-genes.aspx"&gt;Anterior Post&amp;nbsp;&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2013/04/28/mass-lenguaje-de-programaci-243-n-3-comandos.aspx"&gt;Siguiente Post&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Antes de ver c&amp;oacute;mo usar el lenguaje Mass (&lt;a href="http://github.com/ajlopez/Mass"&gt;ver repo&lt;/a&gt;), quisiera tratar algunos temas de implementaci&amp;oacute;n. Primero, una novedad: ahora hay una soluci&amp;oacute;n (en &lt;a href="https://github.com/ajlopez/Mass/blob/master/Src/Mass.sln"&gt;https://github.com/ajlopez/Mass/blob/master/Src/Mass.sln&lt;/a&gt;) que puede compilarse con alg&amp;uacute;n Visual Studio C# Express, de libre bajada e instalaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;La soluci&amp;oacute;n Mass tiene un proyecto de librer&amp;iacute;a de clases. Ah&amp;iacute; hay un namespace dedicado a expresiones:&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/mass0201.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Una expresi&amp;oacute;n es algo que cumple con IExpression:&lt;/p&gt;
&lt;pre style="background-color:black;width:600px;color:white;"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;
&lt;span style="color:orange;"&gt;public&lt;/span&gt; &lt;span style="color:orange;"&gt;interface&lt;/span&gt; IExpression
&lt;span style="color:cyan;"&gt;{&lt;/span&gt;
	&lt;span style="color:orange;"&gt;object&lt;/span&gt; Evaluate&lt;span style="color:cyan;"&gt;(&lt;/span&gt;Context context&lt;span style="color:cyan;"&gt;);&lt;/span&gt;
&lt;span style="color:cyan;"&gt;}&lt;/span&gt;
&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Un Context mantiene un diccionario de nombre/valor, para guardar las variables actuales:&lt;/p&gt;
&lt;pre style="background-color:black;width:600px;color:white;"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;
&lt;span style="color:orange;"&gt;public&lt;/span&gt; &lt;span style="color:orange;"&gt;void&lt;/span&gt; Set&lt;span style="color:cyan;"&gt;(&lt;/span&gt;&lt;span style="color:orange;"&gt;string&lt;/span&gt; name&lt;span style="color:cyan;"&gt;,&lt;/span&gt; &lt;span style="color:orange;"&gt;object&lt;/span&gt; value&lt;span style="color:cyan;"&gt;)&lt;/span&gt;
&lt;span style="color:cyan;"&gt;{&lt;/span&gt;
	&lt;span style="color:orange;"&gt;this&lt;/span&gt;.values&lt;span style="color:cyan;"&gt;[&lt;/span&gt;name&lt;span style="color:cyan;"&gt;]&lt;/span&gt; = value&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
&lt;span style="color:cyan;"&gt;}&lt;/span&gt;

&lt;span style="color:orange;"&gt;public&lt;/span&gt; &lt;span style="color:orange;"&gt;object&lt;/span&gt; Get&lt;span style="color:cyan;"&gt;(&lt;/span&gt;&lt;span style="color:orange;"&gt;string&lt;/span&gt; name&lt;span style="color:cyan;"&gt;)&lt;/span&gt;
&lt;span style="color:cyan;"&gt;{&lt;/span&gt;
	&lt;span style="color:orange;"&gt;if&lt;/span&gt; &lt;span style="color:cyan;"&gt;(&lt;/span&gt;&lt;span style="color:orange;"&gt;this&lt;/span&gt;.values.ContainsKey&lt;span style="color:cyan;"&gt;(&lt;/span&gt;name&lt;span style="color:cyan;"&gt;))&lt;/span&gt;
		&lt;span style="color:orange;"&gt;return&lt;/span&gt; &lt;span style="color:orange;"&gt;this&lt;/span&gt;.values&lt;span style="color:cyan;"&gt;[&lt;/span&gt;name&lt;span style="color:cyan;"&gt;];&lt;/span&gt;

	&lt;span style="color:orange;"&gt;if&lt;/span&gt; &lt;span style="color:cyan;"&gt;(&lt;/span&gt;&lt;span style="color:orange;"&gt;this&lt;/span&gt;.parent &lt;span style="color:cyan;"&gt;!&lt;/span&gt;= &lt;span style="color:orange;"&gt;null&lt;/span&gt;&lt;span style="color:cyan;"&gt;)&lt;/span&gt;
		&lt;span style="color:orange;"&gt;return&lt;/span&gt; &lt;span style="color:orange;"&gt;this&lt;/span&gt;.parent.Get&lt;span style="color:cyan;"&gt;(&lt;/span&gt;name&lt;span style="color:cyan;"&gt;);&lt;/span&gt;

	&lt;span style="color:orange;"&gt;return&lt;/span&gt; &lt;span style="color:orange;"&gt;null&lt;/span&gt;&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
&lt;span style="color:cyan;"&gt;}&lt;/span&gt;
&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;(vean de refil&amp;oacute;n, que soporta contextos anidados: cada contexto puede &amp;ldquo;heredar&amp;rdquo; de un contexto parent).&lt;/p&gt;
&lt;p&gt;La expresi&amp;oacute;n m&amp;aacute;s simple es la que devuelve una constante, que puede ser cualquier valor/objecto .NET:&lt;/p&gt;
&lt;pre style="background-color:black;width:600px;color:white;"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;
&lt;span style="color:orange;"&gt;public&lt;/span&gt; &lt;span style="color:orange;"&gt;class&lt;/span&gt; ConstantExpression : IExpression
&lt;span style="color:cyan;"&gt;{&lt;/span&gt;
	// ...

	&lt;span style="color:orange;"&gt;private&lt;/span&gt; &lt;span style="color:orange;"&gt;object&lt;/span&gt; value&lt;span style="color:cyan;"&gt;;&lt;/span&gt;

	&lt;span style="color:orange;"&gt;public&lt;/span&gt; ConstantExpression&lt;span style="color:cyan;"&gt;(&lt;/span&gt;&lt;span style="color:orange;"&gt;object&lt;/span&gt; value&lt;span style="color:cyan;"&gt;)&lt;/span&gt;
	&lt;span style="color:cyan;"&gt;{&lt;/span&gt;
		&lt;span style="color:orange;"&gt;this&lt;/span&gt;.value = value&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
	&lt;span style="color:cyan;"&gt;}&lt;/span&gt;

	&lt;span style="color:orange;"&gt;public&lt;/span&gt; &lt;span style="color:orange;"&gt;object&lt;/span&gt; Evaluate&lt;span style="color:cyan;"&gt;(&lt;/span&gt;Context context&lt;span style="color:cyan;"&gt;)&lt;/span&gt;
	&lt;span style="color:cyan;"&gt;{&lt;/span&gt;
		&lt;span style="color:orange;"&gt;return&lt;/span&gt; &lt;span style="color:orange;"&gt;this&lt;/span&gt;.value&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
	&lt;span style="color:cyan;"&gt;}&lt;/span&gt;

	// ...
&lt;span style="color:cyan;"&gt;}&lt;/span&gt;
&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;La siguiente expresi&amp;oacute;n m&amp;aacute;s simple es la evaluaci&amp;oacute;n de un nombre de variable en el contexto actual:&lt;/p&gt;
&lt;pre style="background-color:black;width:600px;color:white;"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;
&lt;span style="color:orange;"&gt;public&lt;/span&gt; &lt;span style="color:orange;"&gt;class&lt;/span&gt; NameExpression : IExpression
&lt;span style="color:cyan;"&gt;{&lt;/span&gt;
	// ...
	
	&lt;span style="color:orange;"&gt;private&lt;/span&gt; &lt;span style="color:orange;"&gt;string&lt;/span&gt; name&lt;span style="color:cyan;"&gt;;&lt;/span&gt;

	&lt;span style="color:orange;"&gt;public&lt;/span&gt; NameExpression&lt;span style="color:cyan;"&gt;(&lt;/span&gt;&lt;span style="color:orange;"&gt;string&lt;/span&gt; name&lt;span style="color:cyan;"&gt;)&lt;/span&gt;
	&lt;span style="color:cyan;"&gt;{&lt;/span&gt;
		&lt;span style="color:orange;"&gt;this&lt;/span&gt;.name = name&lt;span style="color:cyan;"&gt;;&lt;/span&gt;
	&lt;span style="color:cyan;"&gt;}&lt;/span&gt;

	&lt;span style="color:orange;"&gt;public&lt;/span&gt; &lt;span style="color:orange;"&gt;object&lt;/span&gt; Evaluate&lt;span style="color:cyan;"&gt;(&lt;/span&gt;Context context&lt;span style="color:cyan;"&gt;)&lt;/span&gt;
	&lt;span style="color:cyan;"&gt;{&lt;/span&gt;
		&lt;span style="color:orange;"&gt;return&lt;/span&gt; context.Get&lt;span style="color:cyan;"&gt;(&lt;/span&gt;&lt;span style="color:orange;"&gt;this&lt;/span&gt;.name&lt;span style="color:cyan;"&gt;);&lt;/span&gt;
	&lt;span style="color:cyan;"&gt;}&lt;/span&gt;
	
	// ...
&lt;span style="color:cyan;"&gt;}&lt;/span&gt;
&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Es necesario especificar el contexto (por ejemplo, el contexto de la funci&amp;oacute;n actual, de una clausura, del objeto actual, del m&amp;oacute;dulo actual, etc), porque un mismo nombre puede tener distintas variables asociadas, como pasa en otros lenguajes.&lt;/p&gt;
&lt;p&gt;Como siempre, cada una de estas clases (Expresiones, Contexto, &amp;hellip;) fue armada usando el flujo de trabajo de TDD (ver el proyecto de tests, y la &lt;a href="https://github.com/ajlopez/Mass/commits/master"&gt;historia de commits del repo&lt;/a&gt; donde dej&amp;eacute; evidencia de c&amp;oacute;mo fue el desarrollo en el tiempo).&lt;/p&gt;
&lt;p&gt;Pr&amp;oacute;ximos posts: algunas expresiones adicionales, comandos, usando Mass para scripting, usando Mass desde nuestro programa .NET, etc..&lt;/p&gt;
&lt;p&gt;Nos leemos!&lt;/p&gt;
&lt;p&gt;Angel &amp;ldquo;Java&amp;rdquo; Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 
  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1828597" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/C+Sharp/default.aspx">C Sharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_26002300_243_3B00_digo+Abierto/default.aspx">Proyectos de C&amp;#243;digo Abierto</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Mass/default.aspx">Mass</category></item><item><title>Mass Lenguaje de Programación (1) Orígenes</title><link>http://msmvps.com/blogs/lopez/archive/2013/04/08/mass-lenguaje-de-programaci-243-n-1-or-237-genes.aspx</link><pubDate>Mon, 08 Apr 2013 10:43:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1826814</guid><dc:creator>lopez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1826814</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2013/04/08/mass-lenguaje-de-programaci-243-n-1-or-237-genes.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2013/04/27/mass-lenguaje-de-programaci-243-n-2-primeras-expresiones.aspx"&gt;Siguiente Post&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Durante estos d&amp;iacute;as, estuve trabajando en la implementaci&amp;oacute;n de un lenguaje interpretado, sobre C#, llamado Mass (dedicado al bueno de &lt;a href="http://twitter.com/martinsalias"&gt;@MArtinSaliaS&lt;/a&gt;):&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/ajlopez/Mass"&gt;https://github.com/ajlopez/Mass&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/mass0101.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;La soluci&amp;oacute;n actual se compone de tres proyectos: una librer&amp;iacute;a de clases, sus tests, y un programa de consola, mass.exe, para lanzar programas Mass&lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/mass0102.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Pueden lanzar un programa escrito en un archivo hello.ms con&lt;/p&gt;
&lt;pre style="background-color:black;width:600px;color:white;"&gt;mass hello.ms&lt;/pre&gt;
&lt;p&gt;El cl&amp;aacute;sico Hello world es entonces&lt;/p&gt;
&lt;pre style="background-color:black;width:600px;color:white;"&gt;println&lt;span style="color:cyan;"&gt;(&lt;/span&gt;&lt;span style="color:lightgreen;"&gt;&amp;quot;Hello, world&amp;quot;&lt;/span&gt;&lt;span style="color:cyan;"&gt;)&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Un ejemplo con clases y objetos&lt;/p&gt;
&lt;pre style="background-color:black;width:600px;color:white;"&gt;&lt;span style="color:orange;"&gt;class&lt;/span&gt; Person
	&lt;span style="color:orange;"&gt;define&lt;/span&gt; initialize&lt;span style="color:cyan;"&gt;(&lt;/span&gt;firstname&lt;span style="color:cyan;"&gt;,&lt;/span&gt; lastname&lt;span style="color:cyan;"&gt;)&lt;/span&gt;
		self.firstname = firstname
		self.lastname = lastname
	&lt;span style="color:orange;"&gt;end&lt;/span&gt;
	
	&lt;span style="color:orange;"&gt;define&lt;/span&gt; getName&lt;span style="color:cyan;"&gt;()&lt;/span&gt;
		&lt;span style="color:orange;"&gt;return&lt;/span&gt; self.lastname + &lt;span style="color:lightgreen;"&gt;&amp;quot;, &amp;quot;&lt;/span&gt; + self.firstname
	&lt;span style="color:orange;"&gt;end&lt;/span&gt;
&lt;span style="color:orange;"&gt;end&lt;/span&gt;

adam = new Person&lt;span style="color:cyan;"&gt;(&lt;/span&gt;&lt;span style="color:lightgreen;"&gt;&amp;quot;Adam&amp;quot;&lt;/span&gt;&lt;span style="color:cyan;"&gt;,&lt;/span&gt; &lt;span style="color:lightgreen;"&gt;&amp;quot;TheFirst&amp;quot;&lt;/span&gt;&lt;span style="color:cyan;"&gt;)&lt;/span&gt;

println&lt;span style="color:cyan;"&gt;(&lt;/span&gt;adam.getName&lt;span style="color:cyan;"&gt;())&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Un ejemplo con acceso a tipos y objectos .NET:&lt;/p&gt;
&lt;pre style="background-color:black;width:600px;color:white;"&gt;dirinfo = new System.IO.DirectoryInfo&lt;span style="color:cyan;"&gt;(&lt;/span&gt;&lt;span style="color:lightgreen;"&gt;&amp;quot;.&amp;quot;&lt;/span&gt;&lt;span style="color:cyan;"&gt;)&lt;/span&gt;

&lt;span style="color:orange;"&gt;for&lt;/span&gt; fileinfo in dirinfo.GetFiles&lt;span style="color:cyan;"&gt;()&lt;/span&gt;
	println&lt;span style="color:cyan;"&gt;(&lt;/span&gt;fileinfo.Name&lt;span style="color:cyan;"&gt;)&lt;/span&gt;
&lt;span style="color:orange;"&gt;end&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;La idea es (como en AjSharp y otras implementaciones) tener un lenguaje din&amp;aacute;mico montado sobre un lenguaje/librer&amp;iacute;a de clases. Y poder acceder a esa librer&amp;iacute;a de clases desde el nuevo lenguaje. Me llev&amp;oacute; a escribir Mass de la forma en que lo hice, el haber trabajado antes en:&lt;/p&gt;
&lt;p&gt;- Implementar Python en C# (ver &lt;a href="https://github.com/ajlopez/PythonSharp"&gt;PythonSharp&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;- Implementar Ruby en C# (ver &lt;a href="https://github.com/ajlopez/RubySharp"&gt;RubySharp&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;- El ya mencionado AjSharp (ver &lt;a href="https://github.com/ajlopez/AjSharp"&gt;repo&lt;/a&gt; y &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx"&gt;posts&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;Pero esta vez quer&amp;iacute;a implementar algo que tuviera sintaxis y sem&amp;aacute;ntica simple. Ya estuve pensando en eso de &amp;ldquo;simple&amp;rdquo; para implementar un compilador de lenguaje simple a JavaScript &lt;a href="http://msmvps.com/blogs/lopez/archive/2013/01/03/simplescript-1-primeras-ideas.aspx"&gt;ver SimpleScript&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Entonces con Mass me propuse evitar:&lt;/p&gt;
&lt;p&gt;- M&amp;uacute;ltiples comandos en la misma l&amp;iacute;nea (descart&amp;eacute; el &amp;lsquo;;&amp;rsquo; de Ruby)&lt;/p&gt;
&lt;p&gt;- Sintaxis basada en espacios en blanco, indentaci&amp;oacute;n (descartado Python)&lt;/p&gt;
&lt;p&gt;- Llamadas a funciones con simplemente el nombre: se necesita expl&amp;iacute;citamente los par&amp;eacute;ntesis (descartado el Ruby cl&amp;aacute;sico)&lt;/p&gt;
&lt;p&gt;- Que las clases/valores de base (por ejemplo, enteros, strings, arreglos, etc&amp;hellip;) tuvieran multitud de m&amp;eacute;todos (tienen los dados por la librer&amp;iacute;a de clases de implementaci&amp;oacute;n, en este caso .NET) (descartado Ruby, que tiene casi tantos m&amp;eacute;todos nativos como PHP)&lt;/p&gt;
&lt;p&gt;Y quise tener:&lt;/p&gt;
&lt;p&gt;- Valores funcionales, como ciudadanos de primera clase, como en JavaScript. Vean que al tener que invocar una funci&amp;oacute;n con par&amp;eacute;ntesis, si o si, entonces la variable func tiene el valor funcional, y func() es la invocaci&amp;oacute;n expl&amp;iacute;cita&lt;/p&gt;
&lt;p&gt;- Objectos din&amp;aacute;micos: cada objeto puede extenderse en cualquier momento, con nuevas variables de instancia, funciones propias del objeto, como JavaScript&lt;/p&gt;
&lt;p&gt;- Sintaxis basada en l&amp;iacute;neas: cada comando va en una l&amp;iacute;nea distinta&lt;/p&gt;
&lt;p&gt;- Sintaxis basada en palabras claves: para los comandos compuestos se usa &amp;lsquo;end&amp;rsquo; para terminar un bloque&lt;/p&gt;
&lt;p&gt;- En lo posible, una sola forma de hacer algo, en vez de m&amp;uacute;ltiples maneras&lt;/p&gt;
&lt;p&gt;- Palabras claves completas, &amp;lsquo;define&amp;rsquo; en vez de &amp;lsquo;def&amp;rsquo;&lt;/p&gt;
&lt;p&gt;- Clases con herencia simple (aunque la esencia de Mass bien puede expresarse sin clases, y usar librer&amp;iacute;as de clases ya escritas en .NET)&lt;/p&gt;
&lt;p&gt;- Modificaci&amp;oacute;n expl&amp;iacute;cita de variables fuera del alcance local (para explicar en pr&amp;oacute;ximos posts)&lt;/p&gt;
&lt;p&gt;- Alcance de variables por archivo, como en JavaScript/NodeJs/CommonJS&lt;/p&gt;
&lt;p&gt;- M&amp;oacute;dulos por archivo, con un require que permite buscar en directorios autom&amp;aacute;ticamente, como en NodeJs/CommonJS&lt;/p&gt;
&lt;p&gt;- Empaquetamiento, manejo de dependencias e instalaci&amp;oacute;n de esos m&amp;oacute;dulos usando algo ya dado, como NPM, el manejador de paquetes de Node.js&lt;/p&gt;
&lt;p&gt;En pr&amp;oacute;ximos posts, m&amp;aacute;s detalles de implementaci&amp;oacute;n, ideas que guiaron el dise&amp;ntilde;o, ejemplos. Pero ya pueden ver el c&amp;oacute;digo, y los ejemplos que est&amp;aacute;n en los tests (s&amp;iacute;, est&amp;aacute; todo construido paso a paso usando TDD).&lt;/p&gt;
&lt;p&gt;Nos leemos!&lt;/p&gt;
&lt;p&gt;Angel &amp;ldquo;Java&amp;rdquo; Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 
  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1826814" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/C+Sharp/default.aspx">C Sharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_26002300_243_3B00_digo+Abierto/default.aspx">Proyectos de C&amp;#243;digo Abierto</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Mass/default.aspx">Mass</category></item><item><title>Escribiendo un Intérprete en .NET (Parte 10)</title><link>http://msmvps.com/blogs/lopez/archive/2013/03/18/escribiendo-un-int-233-rprete-en-net-parte-10.aspx</link><pubDate>Mon, 18 Mar 2013 09:50:56 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1825406</guid><dc:creator>lopez</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1825406</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2013/03/18/escribiendo-un-int-233-rprete-en-net-parte-10.aspx#comments</comments><description>&lt;p&gt;Anteriores posts de la serie:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2011/01/28/writing_2D00_an_2D00_interpreter_2D00_in_2D00_net_2D00_part_2D00_9.aspx"&gt;Escribiendo un Intérprete en .NET (Parte 9)&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2011/01/20/writing_2D00_an_2D00_interpreter_2D00_in_2D00_net_2D00_part_2D00_8.aspx"&gt;Escribiendo un Intérprete en .NET (Parte 8)&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/10/05/escribiendo-un-int-233-rprete-en-net-parte-7.aspx"&gt;Escribiendo un Intérprete en .NET (Parte 7)&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/09/21/escribiendo-un-int-233-rprete-en-net-parte-6.aspx"&gt;Escribiendo un Intérprete en .NET (Parte 6)&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/09/20/escribiendo-un-int-233-rprete-en-net-parte-5.aspx"&gt;Escribiendo un Intérprete en .NET (Parte 5)&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/09/18/escribiendo-un-int-233-rprete-en-net.aspx"&gt;Escribiendo un Intérprete en .NET (Parte 4)&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/09/17/escribiendo-un-int-233-rprete-en-net-parte-3.aspx"&gt;Escribiendo un Intérprete en .NET (Parte 3)&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/09/16/escribiendo-un-int-233-rprete-en-net-parte-2.aspx"&gt;Escribiendo un Intérprete en .NET (Parte 2)&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/09/15/escribiendo-un-int-233-rprete-en-net-parte-1.aspx"&gt;Escribiendo un Intérprete en .NET (Parte 1)&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Hace unos meses que no escribo en esta serie, pero es porque he directamente escrito varios intérpretes, usando TDD, y haciendo “commits” prácticamente por tests en &lt;a href="https://github.com/ajlopez"&gt;mi cuenta de GitHub&lt;/a&gt;, siguiendo las ideas de esos posts.&lt;/p&gt;  &lt;p&gt;Intérpretes que estoy escribiendo, parecidos al descripto en los posts, son:&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/PythonSharp"&gt;PythonSharp&lt;/a&gt; (ver &lt;a href="https://github.com/ajlopez/PythonSharp/commits/master"&gt;los commits&lt;/a&gt;) (lo presenté en la PyCon Argentina 2012)&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/RubySharp"&gt;RubySharp&lt;/a&gt; (ver &lt;a href="https://github.com/ajlopez/RubySharp/commits/master"&gt;los commits&lt;/a&gt;)&lt;/p&gt;  &lt;p&gt;Y para un ejemplo de un lenguaje diferente, vean una implementación de &lt;a href="http://clojure.org/"&gt;Clojure&lt;/a&gt; que estoy escribiendo en C#:&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/ClojSharp"&gt;ClojSharp&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Por ejemplo, hoy escribi un nuevo verbo de ClojSharp, la que se llama “let special form”, tienen los commits por tests de hoy:&lt;/p&gt;  &lt;p&gt;&lt;a title="https://github.com/ajlopez/ClojSharp/commits/master" href="https://github.com/ajlopez/ClojSharp/commits/master"&gt;https://github.com/ajlopez/ClojSharp/commits/master&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter50.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Pueden ver uno en:&lt;/p&gt;  &lt;p&gt;&lt;a title="https://github.com/ajlopez/ClojSharp/commit/51c678ece96d6d1cef92f36afda8d8fc711ffd8c" href="https://github.com/ajlopez/ClojSharp/commit/51c678ece96d6d1cef92f36afda8d8fc711ffd8c"&gt;https://github.com/ajlopez/ClojSharp/commit/51c678ece96d6d1cef92f36afda8d8fc711ffd8c&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;donde GitHub nos muestra los cambios en el código. &lt;/p&gt;  &lt;p&gt;Otro ejemplo, lo que hice ayer, test por test, en RubySharp:&lt;/p&gt;  &lt;p&gt;&lt;a title="https://github.com/ajlopez/RubySharp/commits/master" href="https://github.com/ajlopez/RubySharp/commits/master"&gt;https://github.com/ajlopez/RubySharp/commits/master&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter51.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Espero que estos ejemplos les sirvan para ir viendo cómo se puede usar TDD para este tipo de proyectos. Tengo más ejemplos de otros tipos de aplicaciones &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx"&gt;en mis posts de TDD&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Nos leemos!&lt;/p&gt;  &lt;p&gt;Angel “Java” Lopez   &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1825406" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/C+Sharp/default.aspx">C Sharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_26002300_243_3B00_digo+Abierto/default.aspx">Proyectos de C&amp;#243;digo Abierto</category></item><item><title>Code Katas en JavaScript/Node.js usando TDD</title><link>http://msmvps.com/blogs/lopez/archive/2013/01/14/code_2D00_katas_2D00_in_2D00_javascriptnode_2D00_js_2D00_using_2D00_tdd.aspx</link><pubDate>Mon, 14 Jan 2013 09:23:26 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1822588</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1822588</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2013/01/14/code_2D00_katas_2D00_in_2D00_javascriptnode_2D00_js_2D00_using_2D00_tdd.aspx#comments</comments><description>&lt;p&gt;En estas semanas pasadas, he estado trabajando en ejemplos y módulos JavaScript/Node.js, usando TDD en cada paso. Practicar, practicar, practicar, el camino a la maestría.&lt;/p&gt;  &lt;p&gt;Pueden ver mi progreso y revisar los commits que hago ante cada test. Lo que sigue es un resumen de este trabajo:&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/CobolScript"&gt;CobolScript&lt;/a&gt;: &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/COBOL/default.aspx"&gt;Ver mis posts&lt;/a&gt; un implementación de compilador de COBOL a JavaScript, con ejemplos de consola &lt;a href="https://github.com/ajlopez/SimpleWeb/tree/master/samples/customers"&gt; ejemplo web&lt;/a&gt;, usando MySQL y &lt;a href="http://github.com/ajlopez/SimpleWeb"&gt;SimpleWeb&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&lt;img src="http://ajlopez.com/images/articles2/cobs09.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/SimplePipes"&gt;SimplePipes&lt;/a&gt;: Una manera de definir pasaje de mensajes usando ‘pipes’ para conectar diferentes nodes/funciones en un grafo. Quiero extenderlo para que tenga proceso distribuido.&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/SimpleBoggle"&gt;SimpleBoggle&lt;/a&gt;: Un programa que resuelve &lt;a href="http://en.wikipedia.org/wiki/Boggle"&gt;un tablero de Boggle&lt;/a&gt;, juega mejor que yo! Ver &lt;a href="https://github.com/ajlopez/SimpleBoggle/tree/master/samples/findwords"&gt;ejemplo de consola&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/SimpleMemolap"&gt;SimpleMemolap&lt;/a&gt;: procesamiento tipo OLAP multidimensional, pero usando un modelo en memoria. Hay &lt;a href="https://github.com/ajlopez/SimpleWeb/tree/master/samples/customers"&gt;ejemplo web&lt;/a&gt; que usa mi &lt;a href="https://github.com/ajlopez/SimpleWeb"&gt;SimpleWeb&lt;/a&gt; (“dog fooding”):&lt;/p&gt;  &lt;p&gt;&lt;img src="http://ajlopez.com/images/articles2/smemo02.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/SimpleChess"&gt;SimpleChess&lt;/a&gt;: En progreso, define un tablero usando &lt;a href="https://github.com/ajlopez/SimpleBoard"&gt;SimpleBoard&lt;/a&gt;, y ya calcula movidas. Estoy también trabajando en &lt;a href="https://github.com/ajlopez/SimpleGo"&gt;SimpleGo&lt;/a&gt;, para tener un tablero, un juego y evaluadores.&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/SimpleRules"&gt;SimpleRules&lt;/a&gt;: Motor de reglas&amp;#160; “forward-chaining”, hacia adelante (ahora que está de nuevo “de moda” la programación reactiva. Trabaja inspirada en algoritmo RETE-2, detectando los cambios de estado para disparar las acciones apropiadas.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://api.viglink.com/api/click?format=go&amp;amp;key=cdee124b11d6baacda6c3e29b12e23dc&amp;amp;loc=http%3A%2F%2Fajlopez.wordpress.com%2F&amp;amp;v=1&amp;amp;libid=1358011009888&amp;amp;out=https%3A%2F%2Fgithub.com%2Fajlopez%2FSimpleScript&amp;amp;title=Angel%20%5C%E2%80%9DJava%5C%E2%80%9D%20Lopez%20on%20Blog&amp;amp;txt=repo&amp;amp;jsonp=vglnk_jsonp_13580115836212"&gt;SimpleScript&lt;/a&gt;: Ver &lt;a href="http://msmvps.com/blogs/lopez/archive/2013/01/03/simplescript-1-primeras-ideas.aspx"&gt;mi post&lt;/a&gt; con las primeras ideas sobre este lenguaje, que compila a JavaScript, trabajo en progreso.&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/Py2Script"&gt;Py2Script&lt;/a&gt;: Compilador de Python a JavaScript, primeros pasos.&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/SimpleWeb"&gt;SimpleWeb&lt;/a&gt;: Una capa de “middleware”, a la Connect, con un ejemplo web:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://ajlopez.com/images/articles2/simpleweb02.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/BasicScript"&gt;BasicScript&lt;/a&gt;: Mis primeros pasos para compilar Basic a JavaScript. Quiero usarlo como lenguaje de programación para juegos en el browser.&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/SimplePermissions"&gt;SimplePermissions&lt;/a&gt;: El code kata de este sábado a la mañana ;-). Implementa Sujetos (Subjects), roles, permisos, otorgados en contexto.&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/SimpleFunc"&gt;SimpleFunc&lt;/a&gt;: Serialización/Deserialización de funciones y objectos con funciones.&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/SimpleMapReduce"&gt;SimpleMapReduce&lt;/a&gt;: Explorando la implementación del algoritmo Map-Reduce (y una variante, que llamo Map-Process) tanto sincrónico como asincrónico.&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/SimpleTuring"&gt;SimpleTuring&lt;/a&gt;: Implementación de una máquina de Turing.&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/Cellular"&gt;Cellular&lt;/a&gt;: Implementación de autómatas de estado, lineales o de otras dimensiaones. Incluye un ejemplo de &lt;a href="https://github.com/ajlopez/Cellular/tree/master/samples/life"&gt;juego de la vida en consola&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;Y en estos dos días pasados, agregué:&lt;/p&gt;  &lt;p&gt;&lt;a&gt;NodeDelicious&lt;/a&gt;: Para recuperar mis enlaces desde la cuenta de Delicious (sin tener que lidiar con el XML que devuelve directamente la API), ahora que el sitio ha sido rediseñado y no tiene paginación. La gente de Delicious sigue pensando que uno usa los enlaces como un feed (que lo viejo se pierde), pero no, muchos usamos a Delicious como un “Mis favoritos” en la nube y queremos acceder por rango de tiempo.&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/SimpleSudoku"&gt;SimpleSudoku&lt;/a&gt;: Una reescritura desde 0, con TDD, de mi anterior AjSudoku, resuelve tableros de Sudoku.&lt;/p&gt;  &lt;p&gt;Tengo que trabajar en:&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/SimpleDatabase"&gt;SimpleDatabase&lt;/a&gt;: Base de datos en memoria, puede que en algún momento le agregue persistencia en archivos.&lt;/p&gt;  &lt;p&gt;Y como siempre, todo esto es muy divertido ;-)&lt;/p&gt;  &lt;p&gt;Nos leemos!&lt;/p&gt;  &lt;p&gt;Angel “Java” Lopez    &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1822588" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Code+Katas/default.aspx">Code Katas</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Javascript/default.aspx">Javascript</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_26002300_243_3B00_digo+Abierto/default.aspx">Proyectos de C&amp;#243;digo Abierto</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/NodeJs/default.aspx">NodeJs</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/COBOL/default.aspx">COBOL</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Compilador/default.aspx">Compilador</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/CobolScript/default.aspx">CobolScript</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/MapReduce/default.aspx">MapReduce</category></item><item><title>AjLisp en Ruby (1) Estructura, Clases y Tests</title><link>http://msmvps.com/blogs/lopez/archive/2011/12/03/ajlisp_2D00_on_2D00_ruby_2D00_1_2D00_structure_2D00_classes_2D00_and_2D00_tests.aspx</link><pubDate>Sat, 03 Dec 2011 10:06:58 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1803194</guid><dc:creator>lopez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1803194</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2011/12/03/ajlisp_2D00_on_2D00_ruby_2D00_1_2D00_structure_2D00_classes_2D00_and_2D00_tests.aspx#comments</comments><description>&lt;p&gt;Estoy aprendiendo y practicando Ruby, y como es costumbre, lo hago escribiendo algo interesante para mí: el intérprete AjLisp (hace unos meses lo &lt;a href="http://msmvps.com/blogs/lopez/archive/2011/09/06/ajlisp_2D00_in_2D00_javascript_2D00_part_2D00_3_2D00_define_2D00_lambda_2D00_and_2D00_closures.aspx"&gt;implementé en Javascript&lt;/a&gt;). TDD es mi amigo: escribo un test, lo ejecuto en rojo, codifico para pasarlo a verde, refactorear, y así sigue. El código de este nuevo intérprete, trabajo en progreso, en:&lt;/p&gt;  &lt;p&gt;&lt;a href="https://github.com/ajlopez/AjLispRb"&gt;https://github.com/ajlopez/AjLispRb&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Inicialmente (pueden ver los logs) escribí todo en un solo archivo (código y tests), siguiendo el simple y claro ejemplo:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://kanemar.com/2006/03/04/screencast-of-test-driven-development-with-ruby-part-1-a-simple-example/" href="http://kanemar.com/2006/03/04/screencast-of-test-driven-development-with-ruby-part-1-a-simple-example/"&gt;http://kanemar.com/2006/03/04/screencast-of-test-driven-development-with-ruby-part-1-a-simple-example/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Vean que Ruby tiene un paquete ‘test/unit’ que ya viene en su instalación, listo para usar. Despues de algo de “research”, dividí el archivo en código de producción y código de pruebas. Quiero llegar a armar una gema (un paquete Ruby, distribuido por el utilitario gems), así que estudié los primeros pasos del tutorial:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://guides.rubygems.org/"&gt;http://guides.rubygems.org/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Tengo pendiente de leer y estudiar:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://speakerdeck.com/u/pat/p/cut-polish-a-guide-to-crafting-gems"&gt;http://speakerdeck.com/u/pat/p/cut-polish-a-guide-to-crafting-gems&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://blog.thepete.net/2010/11/creating-and-publishing-your-first-ruby.html"&gt;http://blog.thepete.net/2010/11/creating-and-publishing-your-first-ruby.html&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Así que mi código aún no es una gema. Pero va teniendo la estructura de una:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/ajlisprb01.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;El directorio &lt;strong&gt;lib&lt;/strong&gt; contiene un solo archivo &lt;strong&gt;ajlisp.rb&lt;/strong&gt;:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/list.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/named_atom.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/context.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/string_source.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/token.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/lexer.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/parser.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/primitive.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/primitive_first.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/primitive_rest.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/primitive_cons.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/primitive_list.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/primitive_closure.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/fprimitive.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/fprimitive_quote.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/fprimitive_lambda.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/fprimitive_flambda.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/fprimitive_let.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/fprimitive_closure.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/fprimitive_define.rb&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp/primitive_add.rb&amp;#39;
&lt;span style="color:#0000ff;"&gt;module&lt;/span&gt; AjLisp
@context = Context.new
@context.setValue &amp;quot;&lt;span style="color:#8b0000;"&gt;quote&lt;/span&gt;&amp;quot;, FPrimitiveQuote.instance
@context.setValue &amp;quot;&lt;span style="color:#8b0000;"&gt;first&lt;/span&gt;&amp;quot;, PrimitiveFirst.instance
@context.setValue &amp;quot;&lt;span style="color:#8b0000;"&gt;rest&lt;/span&gt;&amp;quot;, PrimitiveRest.instance
@context.setValue &amp;quot;&lt;span style="color:#8b0000;"&gt;cons&lt;/span&gt;&amp;quot;, PrimitiveCons.instance
@context.setValue &amp;quot;&lt;span style="color:#8b0000;"&gt;list&lt;/span&gt;&amp;quot;, PrimitiveList.instance
@context.setValue &amp;quot;&lt;span style="color:#8b0000;"&gt;lambda&lt;/span&gt;&amp;quot;, FPrimitiveLambda.instance
@context.setValue &amp;quot;&lt;span style="color:#8b0000;"&gt;flambda&lt;/span&gt;&amp;quot;, FPrimitiveFLambda.instance
@context.setValue &amp;quot;&lt;span style="color:#8b0000;"&gt;let&lt;/span&gt;&amp;quot;, FPrimitiveLet.instance
@context.setValue &amp;quot;&lt;span style="color:#8b0000;"&gt;define&lt;/span&gt;&amp;quot;, FPrimitiveDefine.instance
@context.setValue &amp;quot;&lt;span style="color:#8b0000;"&gt;+&lt;/span&gt;&amp;quot;, PrimitiveAdd.instance
&lt;span style="color:#0000ff;"&gt;def&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;self&lt;/span&gt;.context
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; @context
&lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;def&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;self&lt;/span&gt;.evaluate(context, item)
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; item.is_a? List &lt;span style="color:#0000ff;"&gt;or&lt;/span&gt; item.is_a? NamedAtom
        &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; item.evaluate(context)
    &lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;
        
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; item	
&lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Escribí algunas primitivas (formas normales, y formas especiales: estas últimas no evalúan sus parámetros antes de su aplicación, ejemplos: &lt;strong&gt;quote&lt;/strong&gt; y&lt;strong&gt; define&lt;/strong&gt;). Noten que los archivos adicionales los puse en un subdirectorio &lt;strong&gt;ajlisp&lt;/strong&gt; dentro de &lt;strong&gt;lib&lt;/strong&gt;, ¿por qué? Porque cuando este código sea instalado como una gema, todo el directorio &lt;strong&gt;lib&lt;/strong&gt; estará disponible para &lt;strong&gt;require&lt;/strong&gt;, y si hubiera un archivo ahí, se podría hacer &lt;strong&gt;require(‘elarchivo’)&lt;/strong&gt;. Es por eso que los archivos adicionales a &lt;strong&gt;ajlisp.rb&lt;/strong&gt; se colocan en otro lado, evitando colisión de nombres. Se recomienda colocarlos debajo de &lt;strong&gt;lib&lt;/strong&gt; (vean el código de gemas que tienen en su instalación de Ruby, o vean ejemplos en GitHub).&lt;/p&gt;

&lt;p&gt;El el directorio &lt;strong&gt;test&lt;/strong&gt; hay un archivo &lt;strong&gt;test.rb &lt;/strong&gt;que incluye a los otros archivos de tests:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;&lt;span style="color:#00008b;"&gt;test&lt;/span&gt;/unit&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_list.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_named_atom.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_context.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_string_source.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_token.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_lexer.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_parser.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_primitive_first.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_primitive_rest.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_primitive_cons.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_primitive_list.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_primitive_closure.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_primitive_add.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_fprimitive_quote.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_fprimitive_lambda.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_fprimitive_let.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_fprimitive_closure.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_fprimitive_flambda.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_fprimitive_define.rb&lt;/span&gt;&amp;quot;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;quot;&lt;span style="color:#8b0000;"&gt;test_evaluate&lt;/span&gt;&amp;quot;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Pueden ejecutar los tests desde la línea de comando:&lt;/p&gt;

&lt;p&gt;&lt;font size="3" face="Consolas"&gt;ruby –Ilib;test test\test.rb&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;En Windows, dejé el archivo &lt;strong&gt;runtest.cmd&lt;/strong&gt; conteniendo esta línea. Los parámetros &lt;strong&gt;–Ilib;test&lt;/strong&gt; le indican a Ruby que incluya los directorios lib y test para cuando tenga que resolver un &lt;strong&gt;require&lt;/strong&gt;. De esta forma evito poner directorios explícitos (o usar __FILE__) en los &lt;strong&gt;require&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Algo de tests:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;&lt;span style="color:#00008b;"&gt;test&lt;/span&gt;/unit&amp;#39;
&lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; TestList &amp;lt; Test::Unit::TestCase
&lt;span style="color:#008000;"&gt;#...    &lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;def&lt;/span&gt; test_create_with_first
        list = AjLisp::List.new(&amp;quot;&lt;span style="color:#8b0000;"&gt;foo&lt;/span&gt;&amp;quot;)
        assert_equal(&amp;quot;&lt;span style="color:#8b0000;"&gt;foo&lt;/span&gt;&amp;quot;, list.first)
        assert_nil(list.rest)
    &lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;
    
    &lt;span style="color:#0000ff;"&gt;def&lt;/span&gt; test_create_with_first_and_rest
        rest = AjLisp::List.new(&amp;quot;&lt;span style="color:#8b0000;"&gt;bar&lt;/span&gt;&amp;quot;)
        list = AjLisp::List.new(&amp;quot;&lt;span style="color:#8b0000;"&gt;foo&lt;/span&gt;&amp;quot;, rest)
        assert_equal(&amp;quot;&lt;span style="color:#8b0000;"&gt;foo&lt;/span&gt;&amp;quot;, list.first)
        assert_not_nil(list.rest)
        assert_equal(&amp;quot;&lt;span style="color:#8b0000;"&gt;bar&lt;/span&gt;&amp;quot;, list.rest.first)
        assert_nil(list.rest.rest)
    &lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;
    
    &lt;span style="color:#0000ff;"&gt;def&lt;/span&gt; test_create_from_array
        list = AjLisp::List.make [1, &amp;quot;&lt;span style="color:#8b0000;"&gt;a&lt;/span&gt;&amp;quot;, &amp;quot;&lt;span style="color:#8b0000;"&gt;foo&lt;/span&gt;&amp;quot;]
        assert_not_nil list
        assert_equal 1, list.first
        assert_equal &amp;quot;&lt;span style="color:#8b0000;"&gt;a&lt;/span&gt;&amp;quot;, list.rest.first
        assert_equal &amp;quot;&lt;span style="color:#8b0000;"&gt;foo&lt;/span&gt;&amp;quot;, list.rest.rest.first
        assert_nil list.rest.rest.rest
    &lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;
&lt;span style="color:#008000;"&gt;#..&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Cada lista en AjLisp es un objeto de esta clase, &lt;strong&gt;list.rb&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;module&lt;/span&gt; AjLisp
&lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; List
    attr_reader :first
    attr_reader :rest
    
    &lt;span style="color:#0000ff;"&gt;def&lt;/span&gt; initialize(first=&lt;span style="color:#0000ff;"&gt;nil&lt;/span&gt;, rest=&lt;span style="color:#0000ff;"&gt;nil&lt;/span&gt;)
        @first = first
        @rest = rest
    &lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;
    
    &lt;span style="color:#0000ff;"&gt;def&lt;/span&gt; evaluate(context)
        form = AjLisp::evaluate(context, @first)
        form.evaluate(context, &lt;span style="color:#0000ff;"&gt;self&lt;/span&gt;)
    &lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;
    
    &lt;span style="color:#0000ff;"&gt;def&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;self&lt;/span&gt;.make(array)
        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; array &lt;span style="color:#0000ff;"&gt;and&lt;/span&gt; array.length &amp;gt; 0
            first = array.shift
            
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; first.is_a? &lt;span style="color:#00008b;"&gt;Array&lt;/span&gt;
                first = make(first)
            &lt;span style="color:#0000ff;"&gt;elsif&lt;/span&gt; first.is_a? Symbol
                first = NamedAtom.new first.to_s
            &lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;
                        
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; List.new first, make(array)
        &lt;span style="color:#0000ff;"&gt;end&lt;/span&gt; 
        
        &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;nil&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Los méteodos de acceso &lt;strong&gt;first&lt;/strong&gt; y &lt;strong&gt;rest&lt;/strong&gt; son de sólo lectura. Gracias a la naturaleza no tipada de Ruby (facilidad que también encontré en la implementación de Javascript) la implementación de este intérprete es directa, sin mayor “ceremonia de código”. &lt;/p&gt;

&lt;p&gt;En mis nuevos tests, ahora incluye el código DENTRO del módulo &lt;strong&gt;AjLisp&lt;/strong&gt;, así me evito de escribir el prefijo &lt;strong&gt;AjLisp:: &lt;/strong&gt;antes de referenciar a una clase:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;ajlisp&amp;#39;
&lt;span style="color:#00008b;"&gt;require&lt;/span&gt; &amp;#39;&lt;span style="color:#00008b;"&gt;test&lt;/span&gt;/unit&amp;#39;
&lt;span style="color:#0000ff;"&gt;module&lt;/span&gt; AjLisp
&lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; TestLexer &amp;lt; Test::Unit::TestCase
    &lt;span style="color:#0000ff;"&gt;def&lt;/span&gt; test_get_atom_token
        source = StringSource.new &amp;quot;&lt;span style="color:#8b0000;"&gt;atom&lt;/span&gt;&amp;quot;
        lexer = Lexer.new source
        token = lexer.nextToken
        
        assert_not_nil token
        assert_equal &amp;quot;&lt;span style="color:#8b0000;"&gt;atom&lt;/span&gt;&amp;quot;, token.value
        assert_equal TokenType::ATOM, token.type
        assert_nil lexer.nextToken
    &lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;def&lt;/span&gt; test_get_atom_token_with_spaces
        source = StringSource.new &amp;quot;&lt;span style="color:#8b0000;"&gt;  atom   &lt;/span&gt;&amp;quot;
        lexer = Lexer.new source
        token = lexer.nextToken
        
        assert_not_nil token
        assert_equal &amp;quot;&lt;span style="color:#8b0000;"&gt;atom&lt;/span&gt;&amp;quot;, token.value
        assert_equal TokenType::ATOM, token.type
        assert_nil lexer.nextToken
    &lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;
&lt;span style="color:#008000;"&gt;#...&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Próximos tópicos: algunos detalles de implementación, primitives vs fprimitives, contexto (ambiente anidado con pares nombre/valor), lambdas y closures, el lexer y el parser.&lt;/p&gt;

&lt;p&gt;Próximos pasos: completar las primitivas (let, letrec, definef, do, if…), macro (mlambda, definem, expansión de macros…)&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1803194" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjLisp/default.aspx">AjLisp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Programaci_26002300_243_3B00_n+Funcional/default.aspx">Programaci&amp;#243;n Funcional</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lisp/default.aspx">Lisp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_26002300_243_3B00_digo+Abierto/default.aspx">Proyectos de C&amp;#243;digo Abierto</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Ruby/default.aspx">Ruby</category></item><item><title>Escribiendo un Intérprete en .NET (Parte 9)</title><link>http://msmvps.com/blogs/lopez/archive/2011/01/28/writing_2D00_an_2D00_interpreter_2D00_in_2D00_net_2D00_part_2D00_9.aspx</link><pubDate>Fri, 28 Jan 2011 10:00:54 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1787241</guid><dc:creator>lopez</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1787241</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2011/01/28/writing_2D00_an_2D00_interpreter_2D00_in_2D00_net_2D00_part_2D00_9.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2011/01/20/writing_2D00_an_2D00_interpreter_2D00_in_2D00_net_2D00_part_2D00_8.aspx"&gt;Anterior Post&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/09/15/escribiendo-un-int-233-rprete-en-net-parte-1.aspx"&gt;Primer Post de la Serie&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Esta vez, quiero agregar una pieza que falta: un composite command. El intérprete necesita una manera de ejecutar una lista de comandos, en cualquier lugar donde haya un comando: en un if/then, en el if/else, en el while, etc… Primero, escribí un test (esta version de abajo no es la versión inicial, es la final actual):&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; CreateAndEvaluateCompositeCommand()
        {
            BindingEnvironment environment = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; BindingEnvironment();
            environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;a&lt;/span&gt;&amp;quot;, 0);
            ICommand add1 = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.MakeAddCommand(&amp;quot;&lt;span style="color:#8b0000;"&gt;a&lt;/span&gt;&amp;quot;, &amp;quot;&lt;span style="color:#8b0000;"&gt;a&lt;/span&gt;&amp;quot;, 1);
            ICommand add2 = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.MakeAddCommand(&amp;quot;&lt;span style="color:#8b0000;"&gt;a&lt;/span&gt;&amp;quot;, &amp;quot;&lt;span style="color:#8b0000;"&gt;a&lt;/span&gt;&amp;quot;, 2);
            CompositeCommand cmd = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; CompositeCommand(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ICommand[] { add1, add2 });
            Assert.IsNotNull(cmd.Commands);
            Assert.AreEqual(2, cmd.Commands.Count);
            Assert.AreEqual(add1, cmd.Commands.First());
            Assert.AreEqual(add2, cmd.Commands.Skip(1).First());
            cmd.Execute(environment);
            Assert.AreEqual(3, environment.GetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;a&lt;/span&gt;&amp;quot;));
        }
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; ICommand MakeAddCommand(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; target, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; source, &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; number)
        {
            IExpression add = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; BinaryArithmeticBLOCKED EXPRESSION;
        }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;El código mostrado es la versión ACTUAL. Durante el desarrollo, y usando TDD, escribí el código de a pasos cortos,&amp;#160; y también apliqué refactoring. Pero la lección es: usar los tests para guiar nuestro desarrollo.&lt;/p&gt;

&lt;p&gt;Todos los tests en verde:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter41.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Buen code coverage:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter42.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Pueden bajar la versión actual desde from &lt;a href="http://cid-9f903f3d6db0c176.office.live.com/self.aspx/Examples/DotNet/InterpreterStep09.zip"&gt;InterpreterStep09.zip&lt;/a&gt;. Si quieren ver todos los steps, sigo enviando mi código a trunk/Interpreter en mi Google Code Project &lt;a href="http://code.google.com/p/ajcodekatas/"&gt;AjCodeKatas&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Próximos pasos: comando foreach, comando for, declaración de funciones, etc…&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1787241" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category></item><item><title>Escribiendo un Intérprete in .NET (Part 8)</title><link>http://msmvps.com/blogs/lopez/archive/2011/01/20/writing_2D00_an_2D00_interpreter_2D00_in_2D00_net_2D00_part_2D00_8.aspx</link><pubDate>Thu, 20 Jan 2011 10:27:20 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1786747</guid><dc:creator>lopez</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1786747</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2011/01/20/writing_2D00_an_2D00_interpreter_2D00_in_2D00_net_2D00_part_2D00_8.aspx#comments</comments><description>&lt;p&gt;Vuelvo a escribir sobre el tema: programar un intérprete, usando C# y algunas ideas de TDD. En este paso, agrego un nuevo ICommand, el WhileCommand:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter35.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Pueden bajarse la versión de este paso desde &lt;a href="http://cid-9f903f3d6db0c176.office.live.com/self.aspx/Examples/DotNet/InterpreterStep08.zip"&gt;InterpreterStep08.zip&lt;/a&gt;. Si quieren ver todos los pasos, sigo manteniendo el códicon en trunk/Interpreter en mi Google Code Project &lt;a href="http://code.google.com/p/ajcodekatas/"&gt;AjCodeKatas&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;El código de WhileCommand es simple:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; WhileCommand : ICommand
    {
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; IExpression condition;
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; ICommand command;
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; WhileCommand(IExpression condition, ICommand command)
        {
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.condition = condition;
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.command = command;
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IExpression Condition { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.condition; } }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ICommand Command { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.command; } }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Execute(BindingEnvironment environment)
        {
            &lt;span style="color:#0000ff;"&gt;while&lt;/span&gt; (BooleanPredicates.IsTrue(&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.condition.Evaluate(environment)))
                &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.command.Execute(environment);
        }
    }&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Noten que tengo ahora un nuevo BooleanPredicates. Nació de haber refctorizado el código anterior que usé en la implementación de IfCommand. Escribí en el anterior post sobre mis intenciones de hacer ese refactor. Usando TDD, escribí los tests de la nueva clase, ejemplo:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; IsFalse()
        {
            Assert.IsTrue(BooleanPredicates.IsFalse(&lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;));
            Assert.IsTrue(BooleanPredicates.IsFalse(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty));
            Assert.IsTrue(BooleanPredicates.IsFalse(0));
            Assert.IsTrue(BooleanPredicates.IsFalse((&lt;span style="color:#0000ff;"&gt;short&lt;/span&gt;)0));
            Assert.IsTrue(BooleanPredicates.IsFalse((&lt;span style="color:#0000ff;"&gt;long&lt;/span&gt;)0));
            Assert.IsTrue(BooleanPredicates.IsFalse(0.0));
            Assert.IsTrue(BooleanPredicates.IsFalse((&lt;span style="color:#0000ff;"&gt;float&lt;/span&gt;)0.0));
            Assert.IsFalse(BooleanPredicates.IsFalse(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt;()));
            Assert.IsFalse(BooleanPredicates.IsFalse(&amp;quot;&lt;span style="color:#8b0000;"&gt;foo&lt;/span&gt;&amp;quot;));
            Assert.IsFalse(BooleanPredicates.IsFalse(1));
            Assert.IsFalse(BooleanPredicates.IsFalse((&lt;span style="color:#0000ff;"&gt;short&lt;/span&gt;)2));
            Assert.IsFalse(BooleanPredicates.IsFalse((&lt;span style="color:#0000ff;"&gt;long&lt;/span&gt;)3));
            Assert.IsFalse(BooleanPredicates.IsFalse(4.0));
            Assert.IsFalse(BooleanPredicates.IsFalse((&lt;span style="color:#0000ff;"&gt;float&lt;/span&gt;)5.0));
        }&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Vean: el test es una especie de especificación escrita en código, que contesta: ¿Qué es lo que considero como false en mi intérprete? Luego de tener el test en verde, pude agregar su llamada en el IfCommand (que YA estaba escrito) y ver de correr los tests de ese comando, para ver que todo siguiera funcionando.&lt;/p&gt;

&lt;p&gt;El nuevo comando WhileCommand nació de haberlo testeado, ejemplo:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; EvaluateWhileCommandUsingDecrement()
        {
            BindingEnvironment environment = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; BindingEnvironment();
            environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;a&lt;/span&gt;&amp;quot;, 2);
            IExpression condition = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; VariableBLOCKED EXPRESSION;
        }
&lt;/pre&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Podría haber agregado más tests, como qué pasa si al WhileCommand le entrego una condición null, pero, por ahora, el nuevo comando goza de buena salud. Todos los tess siguen en verde:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter36.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Buen code coverage:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter37.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Próximos pasos: comandos composite, comandos for/foreach, declaración de funciones…&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1786747" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category></item><item><title>TDD: Comparando Smalltalk y Java</title><link>http://msmvps.com/blogs/lopez/archive/2010/11/10/tdd-comparando-smalltalk-y-java.aspx</link><pubDate>Wed, 10 Nov 2010 16:06:44 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1782040</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1782040</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/11/10/tdd-comparando-smalltalk-y-java.aspx#comments</comments><description>&lt;p&gt;Gracias al bueno de Hernan Wilkinson (&lt;a href="http://twitter.com/hernanwilkinson" target="_blank"&gt;@hernanwilkinson&lt;/a&gt;) tenemos estos videos, que muestran su comparación de TDD (Test-Driven Development) entre dos lenguajes: Smalltalk, con un entorno dinámico, y Java, un lenguaje con tipos estáticos.&lt;/p&gt;  &lt;p&gt;(Please visit the site to view this media)   &lt;br /&gt;(Please visit the site to view this media)&lt;/p&gt;  &lt;p&gt;Pueden encontrar una discusión del tema en el thread de Foro Agiles:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://tech.groups.yahoo.com/group/foro-agiles/message/3571" href="http://tech.groups.yahoo.com/group/foro-agiles/message/3571"&gt;http://tech.groups.yahoo.com/group/foro-agiles/message/3571&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Como aclara ahí, Hernan puso comparación de tiempos, para medir y comparar. Yo no haría hincapié en ese punto. Lo más a destacar es cómo Smalltalk permite, en el medio de la prueba, completar y arreglar lo que estamos programando. Como apunta en ese thread el bueno de &lt;a href="http://twitter.com/jgabardini" target="_blank"&gt;@jgabardini&lt;/a&gt;, no se usa mucho el debugger enJava, usando TDD (lo mismo afirmaría para .NET y Visual Studio): lo que vamos programando, va naciendo de a poco, por tests, digamos, incrementales. Diría que uno va avanzando por “baby steps” que disminuyen casi a cero la necesidad de depuración en el proceso.&lt;/p&gt;  &lt;p&gt;Si bien Hernan plantea una comparación entre lenguajes dinámicos y estáticos, pienso que eligió uno muy particular como dinámico. Hacer TDD con Python, Ruby y otros lenguajes dinámicos, puede ser bastante diferente que en Smalltalk y su entorno.&lt;/p&gt;  &lt;p&gt;Nos leemos!&lt;/p&gt;  &lt;p&gt;Angel “Java” Lopez&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1782040" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/Java/default.aspx">Java</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Smalltalk/default.aspx">Smalltalk</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Video/default.aspx">Video</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Testing/default.aspx">Testing</category></item><item><title>Escribiendo un Intérprete en .NET (Parte 7)</title><link>http://msmvps.com/blogs/lopez/archive/2010/10/05/escribiendo-un-int-233-rprete-en-net-parte-7.aspx</link><pubDate>Tue, 05 Oct 2010 09:22:55 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1779354</guid><dc:creator>lopez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1779354</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/10/05/escribiendo-un-int-233-rprete-en-net-parte-7.aspx#comments</comments><description>&lt;p&gt;Vuelta al ruedo! Un nuevo post en esta serie. En los anteriores posts, estuve escribiendo un intérprete en .NET, usando TDD (Test-Driven Development). Ya tengo un parser, un lexer, algunas expresiones y solamente un comando. Es hora de agregar un nuevo comando a mi intérprete. El nuevo comando es &lt;strong&gt;IfCommand&lt;/strong&gt;:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter30.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Pueden bajarse el código fuente desde &lt;a href="http://cid-9f903f3d6db0c176.office.live.com/self.aspx/Examples/DotNet/InterpreterStep07.zip" target="_blank"&gt;Interpreter07.zip&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;La clase &lt;strong&gt;IfCommand&lt;/strong&gt; implementa la interfaz &lt;strong&gt;ICommand&lt;/strong&gt;. Fue armada usando TDD: escribiendo los test, haciendo que compilen, primero en rojo, luego en verde, refactor. Mis primeros tests:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; CreateIfCommand()
        {
            IExpr ession condition = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ConstantExpr ession(0);
            ICommand thenCommand = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SetCommand(&amp;quot;&lt;span style="color:#8b0000;"&gt;a&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ConstantExpr ession(1));
            ICommand elseCommand = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SetCommand(&amp;quot;&lt;span style="color:#8b0000;"&gt;b&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ConstantExpr ession(2));
            IfCommand command = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; IfCommand(condition, thenCommand, elseCommand);
            Assert.AreEqual(condition, command.Condition);
            Assert.AreEqual(thenCommand, command.ThenCommand);
            Assert.AreEqual(elseCommand, command.ElseCommand);
        }
        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; EvaluateIfCommandWithZeroAsCondition()
        {
            IExpr ession condition = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ConstantExpr ession(0);
            ICommand thenCommand = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SetCommand(&amp;quot;&lt;span style="color:#8b0000;"&gt;a&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ConstantExpr ession(1));
            ICommand elseCommand = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SetCommand(&amp;quot;&lt;span style="color:#8b0000;"&gt;b&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ConstantExpr ession(2));
            IfCommand command = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; IfCommand(condition, thenCommand, elseCommand);
            BindingEnvironment environment = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; BindingEnvironment();
            command.Execute(environment);
            Assert.IsNull(environment.GetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;a&lt;/span&gt;&amp;quot;));
            Assert.AreEqual(2, environment.GetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;b&lt;/span&gt;&amp;quot;));
        }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;La implementación de &lt;strong&gt;IfCommand&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; IfCommand : ICommand
    {
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; IExpr ession condition;
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; ICommand thenCommand;
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; ICommand elseCommand;
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IfCommand(IExpr ession condition, ICommand thenCommand)
            : &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;(condition, thenCommand, &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
        {
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IfCommand(IExpr ession condition, ICommand thenCommand, ICommand elseCommand)
        {
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.condition = condition;
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.thenCommand = thenCommand;
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.elseCommand = elseCommand;
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IExpr ession Condition { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.condition; } }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ICommand ThenCommand { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.thenCommand; } }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ICommand ElseCommand { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.elseCommand; } }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Execute(BindingEnvironment environment)
        {
            &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; result = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.condition.Evaluate(environment);
            &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; cond = !IsFalse(result);
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (cond)
                &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.thenCommand.Execute(environment);
            &lt;span style="color:#0000ff;"&gt;else&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.elseCommand != &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
                &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.elseCommand.Execute(environment);
        }
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;static&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; IsFalse(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; obj)
        {
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (obj == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (obj &lt;span style="color:#0000ff;"&gt;is&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt;)
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; !(&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt;)obj;
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (obj &lt;span style="color:#0000ff;"&gt;is&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)obj == 0;
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (obj &lt;span style="color:#0000ff;"&gt;is&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;)
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.IsNullOrEmpty((&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;)obj);
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (obj &lt;span style="color:#0000ff;"&gt;is&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;long&lt;/span&gt;)
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;long&lt;/span&gt;)obj == 0;
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (obj &lt;span style="color:#0000ff;"&gt;is&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;short&lt;/span&gt;)
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;short&lt;/span&gt;)obj == 0;
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (obj &lt;span style="color:#0000ff;"&gt;is&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;double&lt;/span&gt;)
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;double&lt;/span&gt;)obj == 0;
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (obj &lt;span style="color:#0000ff;"&gt;is&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;float&lt;/span&gt;)
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;float&lt;/span&gt;)obj == 0;
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;;
        }
    }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;IfCommand&lt;/strong&gt; evalúa una expresión, que retorne un objeto. Este objeto podría no ser un booleano. Tomé la decisión de evaluar null, 0, string vacío como false (algo parecido a lo que hace PHP). El único lugar donde necesito evaluar un objeto cualquiera como verdadero o false es, ahora, en este método&amp;#160; &lt;strong&gt;IfCommand.Execute.&lt;/strong&gt; Así, esta lógica de evaluación está ahora en un método privado. Planeo refactorearlo, moverlo a otra clase, en cuanto lo necesite desde otros lugares, como cuando implemente el comando &lt;strong&gt;WhileCommand&lt;/strong&gt; y otras expresiones.&lt;/p&gt;

&lt;p&gt;Después de escribir &lt;strong&gt;IfCommand&lt;/strong&gt;, necesitaba parsear comandos, no sólo expresiones. No tenía un método &lt;strong&gt;.ParseCommand()&lt;/strong&gt; en la clase &lt;strong&gt;Parser&lt;/strong&gt;. Mis primeros tests (hay más en el código):&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; ParseAndEvaluateSimpleIfCommand()
        {
            Parser parser = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Parser(&amp;quot;&lt;span style="color:#8b0000;"&gt;if (a) b=1; else b=2;&lt;/span&gt;&amp;quot;);
            ICommand command = parser.ParseCommand();
            Assert.IsNotNull(command);
            Assert.IsInstanceOfType(command, &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(IfCommand));
            BindingEnvironment environment = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; BindingEnvironment();
            command.Execute(environment);
            Assert.AreEqual(2, environment.GetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;b&lt;/span&gt;&amp;quot;));            
        }&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Luego, implementé nuevos métodos en &lt;strong&gt;Parser&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter31.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parser.ParseCommand()&lt;/strong&gt; tienen una implementación ingenua. Solamente dos clases de comandos son soportados: comandos if, y comandos de seteo de variables:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ICommand ParseCommand()
        {
            Token token = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.NextToken();
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (token == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (token.TokenType == TokenType.Name &amp;amp;&amp;amp; token.Value.Equals(&amp;quot;&lt;span style="color:#8b0000;"&gt;if&lt;/span&gt;&amp;quot;))
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; ParseIfCommand();
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.PushToken(token);
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; ParseSetCommand();
        }
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; ICommand ParseSetCommand()
        {
            &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; name = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.ParseName();
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.ParseToken(TokenType.Operator, &amp;quot;&lt;span style="color:#8b0000;"&gt;=&lt;/span&gt;&amp;quot;);
            IExpr ession expr = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.ParseExpr ession();
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.ParseToken(TokenType.Separator, &amp;quot;&lt;span style="color:#8b0000;"&gt;;&lt;/span&gt;&amp;quot;);
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SetCommand(name, expr);
        }
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; ICommand ParseIfCommand()
        {
            IExpr ession condition;
            ICommand thencmd;
            ICommand elsecmd;
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.ParseToken(TokenType.Separator, &amp;quot;&lt;span style="color:#8b0000;"&gt;(&lt;/span&gt;&amp;quot;);
            condition = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.ParseExpr ession();
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.ParseToken(TokenType.Separator, &amp;quot;&lt;span style="color:#8b0000;"&gt;)&lt;/span&gt;&amp;quot;);
            thencmd = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.ParseCommand();
            Token token = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.NextToken();
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (token != &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; token.TokenType == TokenType.Name &amp;amp;&amp;amp; token.Value.Equals(&amp;quot;&lt;span style="color:#8b0000;"&gt;else&lt;/span&gt;&amp;quot;)) 
            {
                elsecmd = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.ParseCommand();
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; IfCommand(condition, thencmd, elsecmd);
            }
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (token != &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
                &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.PushToken(token);
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; IfCommand(condition, thencmd);
        }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Todos los tests quedaron en verde:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter32.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Buen code coverage:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter33.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Próximos pasos: agregar más comandos (while, for, etc…), declaraciones de funciones, manejo de números reales, etc. &lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1779354" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category></item><item><title>Escribiendo un intérprete en .NET (Parte 6)</title><link>http://msmvps.com/blogs/lopez/archive/2010/09/21/escribiendo-un-int-233-rprete-en-net-parte-6.aspx</link><pubDate>Tue, 21 Sep 2010 09:29:10 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1778458</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1778458</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/09/21/escribiendo-un-int-233-rprete-en-net-parte-6.aspx#comments</comments><description>&lt;p&gt;Ahora, en este paso, he agregado: procesamiento de string, expresiones binarias, expresiones aritméticas, reconocimiento en el parser de esas expresiones, usando precedencia y paréntesis.&lt;/p&gt;  &lt;p&gt;El código puede bajarse desde &lt;a href="http://cid-9f903f3d6db0c176.office.live.com/self.aspx/Examples/DotNet/InterpreterStep06.zip" target="_blank"&gt;InterpreterStep06.zip&lt;/a&gt;.&lt;/p&gt;  &lt;h2&gt;Procesamiento de Strings&lt;/h2&gt;  &lt;p&gt;El &lt;strong&gt;lexer&lt;/strong&gt; ahora puede procesar strings, delimitados con dobles comillas, y reconoce el caracter de escape. Soporta strings multilineas. Para eso, fui escribiendo tests, al comienzo en rojo, y luego fui implementando la funcionalidad en el código. Algunos tests (hay más en código):&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; ProcessSimpleString()
        {
            Lexer lexer = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Lexer(&amp;quot;&lt;span style="color:#8b0000;"&gt;\&amp;quot;foo\&amp;quot;&lt;/span&gt;&amp;quot;);
            Token token = lexer.NextToken();
            Assert.IsNotNull(token);
            Assert.AreEqual(TokenType.String, token.TokenType);
            Assert.AreEqual(&amp;quot;&lt;span style="color:#8b0000;"&gt;foo&lt;/span&gt;&amp;quot;, token.Value);
            Assert.IsNull(lexer.NextToken());
        }
        [TestMethod]
        [ExpectedException(&lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(LexerException), &amp;quot;&lt;span style="color:#8b0000;"&gt;Unclosed string&lt;/span&gt;&amp;quot;)]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; RaiseIfStringIsUnclosed()
        {
            Lexer lexer = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Lexer(&amp;quot;&lt;span style="color:#8b0000;"&gt;\&amp;quot;foo&lt;/span&gt;&amp;quot;);
            Token token = lexer.NextToken();
        }
&lt;/pre&gt;&lt;/pre&gt;

&lt;h2&gt;Expresiones aritméticas y binarias&lt;/h2&gt;

&lt;p&gt;Agregué una nueva clase abstracta &lt;strong&gt;BinaryExpr ession&lt;/strong&gt; (derivada luego de tener los tests sobre una concreta, &lt;strong&gt;BinaryArithmeticExpr ession&lt;/strong&gt;):&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter22.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BinaryExpr ession&lt;/strong&gt; evalua dos expresiones, izquierda y derecha, y aplica la operación abstracta:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;abstract&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; BinaryExpr ession : IExpr ession
    {
        IExpr ession leftExpr ession;
        IExpr ession rightExpr ession;
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; BinaryExpr ession(IExpr ession leftExpr ession, IExpr ession rightExpr ession)
        {
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.leftExpr ession = leftExpr ession;
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.rightExpr ession = rightExpr ession;
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IExpr ession LeftExpr ession { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.leftExpr ession; } }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IExpr ession RightExpr ession { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.rightExpr ession; } }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Evaluate(BindingEnvironment environment)
        {
            &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; leftValue = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.leftExpr ession.Evaluate(environment);
            &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; rightValue = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.rightExpr ession.Evaluate(environment);
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; Apply(leftValue, rightValue);
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;abstract&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Apply(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; leftValue, &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; rightValue);
    }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Definí operadores aritméticos, que tengo que extender en el futuro:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;enum&lt;/span&gt; ArithmeticOperator
    {
        Add,
        Subtract,
        Multiply,
        Divide
    }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;BinaryArithmeticExpr ession&lt;/strong&gt; usa &lt;strong&gt;Microsoft.VisualBasic.CompilerServices.Operators&lt;/strong&gt;. Estos métodos ayudantes, que agregué referenciando a la librería de VB.NET que viene con el framework, pueden sumar, restar, multiplicar, dividir dos objetos, detectando si son números:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; BinaryArithmeticExpr ession : BinaryExpr ession
    {
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; ArithmeticOperator @&lt;span style="color:#0000ff;"&gt;operator&lt;/span&gt;;
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; ArithmeticOperator Operator { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.@&lt;span style="color:#0000ff;"&gt;operator&lt;/span&gt;; } }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; BinaryArithmeticExpr ession(IExpr ession leftExpr ession, IExpr ession rightExpr ession, ArithmeticOperator @&lt;span style="color:#0000ff;"&gt;operator&lt;/span&gt;)
            : &lt;span style="color:#0000ff;"&gt;base&lt;/span&gt;(leftExpr ession, rightExpr ession)
        {
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.@&lt;span style="color:#0000ff;"&gt;operator&lt;/span&gt; = @&lt;span style="color:#0000ff;"&gt;operator&lt;/span&gt;;
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Apply(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; leftValue, &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; rightValue)
        {
            &lt;span style="color:#0000ff;"&gt;switch&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.@&lt;span style="color:#0000ff;"&gt;operator&lt;/span&gt;)
            {
                &lt;span style="color:#0000ff;"&gt;case&lt;/span&gt; ArithmeticOperator.Add:
                    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; Operators.AddObject(leftValue, rightValue);
                &lt;span style="color:#0000ff;"&gt;case&lt;/span&gt; ArithmeticOperator.Subtract:
                    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; Operators.SubtractObject(leftValue, rightValue);
                &lt;span style="color:#0000ff;"&gt;case&lt;/span&gt; ArithmeticOperator.Multiply:
                    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; Operators.MultiplyObject(leftValue, rightValue);
                &lt;span style="color:#0000ff;"&gt;case&lt;/span&gt; ArithmeticOperator.Divide:
                    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; Operators.DivideObject(leftValue, rightValue);
            }
            &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; InvalidOperationException(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Format(&amp;quot;&lt;span style="color:#8b0000;"&gt;Unknow operator &amp;#39;{0}&amp;#39;&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.@&lt;span style="color:#0000ff;"&gt;operator&lt;/span&gt;));
        }
    }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Algunos tess (más en código):&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; EvaluateAddExpr ession()
        {
            ConstantExpr ession leftExpr ession = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ConstantExpr ession(1);
            ConstantExpr ession rightExpr ession = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ConstantExpr ession(2);
            BinaryArithmeticExpr ession Expr ession = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; BinaryArithmeticExpr ession(leftExpr ession, rightExpr ession, ArithmeticOperator.Add);
            Assert.AreEqual(3, Expr ession.Evaluate(&lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;));
        }
        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; EvaluateSubtractExpr ession()
        {
            ConstantExpr ession leftExpr ession = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ConstantExpr ession(1);
            ConstantExpr ession rightExpr ession = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ConstantExpr ession(2);
            BinaryArithmeticExpr ession Expr ession = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; BinaryArithmeticExpr ession(leftExpr ession, rightExpr ession, ArithmeticOperator.Subtract);
            Assert.AreEqual(-1, Expr ession.Evaluate(&lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;));
        }
&lt;/pre&gt;&lt;/pre&gt;

&lt;h2&gt;Mejoras en el Parser&lt;/h2&gt;

&lt;p&gt;El &lt;strong&gt;Parser&lt;/strong&gt; tiene nuevos métodos privados &lt;strong&gt;ParseSimpleExpr ession, ParseFactorExpr ession&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter23.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Son las implementaciones que surgieron al satisfacer los tests (más tests en el código):&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; ParseAndEvaluateAddAndMultiplyExpr ession()
        {
            Parser parser = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Parser(&amp;quot;&lt;span style="color:#8b0000;"&gt;1+2*3&lt;/span&gt;&amp;quot;);
            IExpr ession Expr ession = parser.ParseExpr ession();
            Assert.IsNotNull(Expr ession);
            Assert.IsInstanceOfType(Expr ession, &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(BinaryArithmeticExpr ession));
            Assert.AreEqual(7, Expr ession.Evaluate(&lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;));
            Assert.IsNull(parser.ParseExpr ession());
        }
        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; ParseAndEvaluateAddAndMultiplyExpr essionWithParenthesis()
        {
            Parser parser = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Parser(&amp;quot;&lt;span style="color:#8b0000;"&gt;(1+2)*3&lt;/span&gt;&amp;quot;);
            IExpr ession Expr ession = parser.ParseExpr ession();
            Assert.IsNotNull(Expr ession);
            Assert.IsInstanceOfType(Expr ession, &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(BinaryArithmeticExpr ession));
            Assert.AreEqual(9, Expr ession.Evaluate(&lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;));
            Assert.IsNull(parser.ParseExpr ession());
        }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;De esta manera, puedo reconocer operadores binarios, procesarlos según su precedencia, y usar paréntesis para alterar el orden de evaluación.&lt;/p&gt;

&lt;p&gt;Todos los tests en verde:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter24.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Buen code coverage:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter25.png" alt="" /&gt; &lt;/p&gt;

&lt;h2&gt;Próximos pasos&lt;/h2&gt;

&lt;p&gt;Me gustaría agregar proceso de números reales, definiciones de funciones, más operadores, comandos &lt;strong&gt;if, for&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Keep tuned!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1778458" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category></item><item><title>Escribiendo un intérprete en .NET (Parte 5)</title><link>http://msmvps.com/blogs/lopez/archive/2010/09/20/escribiendo-un-int-233-rprete-en-net-parte-5.aspx</link><pubDate>Mon, 20 Sep 2010 09:11:00 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1778385</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1778385</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/09/20/escribiendo-un-int-233-rprete-en-net-parte-5.aspx#comments</comments><description>&lt;p&gt;Continuando con esta serie de posts, esta vez agregar&amp;eacute; un parser sencillo. La nueva soluci&amp;oacute;n:&lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.ajlopez.com/images/articles2/interpreter18.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Pueden bajar el c&amp;oacute;digo desde &lt;a href="http://cid-9f903f3d6db0c176.office.live.com/self.aspx/Examples/DotNet/InterpreterStep05.zip" target="_blank"&gt;InterpreterStep05.zip&lt;/a&gt;. La nueva clase agregada es: &lt;/p&gt;
&lt;p&gt;
&lt;img src="http://www.ajlopez.com/images/articles2/interpreter19.png" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;El parse puede ser construido usando un TextReader o un string: &lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0pt;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Parser
    {
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; Lexer lexer;
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Parser(Lexer lexer)
        {&lt;span style="text-decoration:line-through;"&gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.lexer = lexer;
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Parser(TextReader reader)
            : &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Lexer(reader))
        {
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Parser(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; text)
            : &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Lexer(text))
        {
        }
&lt;span style="color:#008000;"&gt;//...&lt;/span&gt;
    }&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Tengo s&amp;oacute;lo dos Expr essions por ahora (&lt;b&gt;ConstantExpr ession&lt;/b&gt; y &lt;b&gt;VariableExpr ession&lt;/b&gt;). El m&amp;eacute;todo p&amp;uacute;blico &lt;b&gt;ParseExpr ession&lt;/b&gt; ahora reconoce enteros y nombres(el lexer todav&amp;iacute;a no reconoce strings delimitados): &lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0pt;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IExpr ession ParseExpr ession()
        {
            Token token = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.NextToken();
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (token == &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (token.TokenType == TokenType.Integer)
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ConstantExpr ession(token.Value);
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (token.TokenType == TokenType.String)
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ConstantExpr ession(token.Value);
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (token.TokenType == TokenType.Name)
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; VariableExpr ession((&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;) token.Value);
            &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; InvalidDataException(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Format(&amp;quot;&lt;span style="color:#8b0000;"&gt;Unexpected token &amp;#39;{0}&amp;#39;&lt;/span&gt;&amp;quot;,
                 token.Value));
        }&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;
El parser usa al lexer que coment&amp;eacute; en el anterior post de la serie. Como antes, el nuevo &lt;b&gt;Parser&lt;/b&gt; y el m&amp;eacute;todo &lt;b&gt;ParseExpr ession&lt;/b&gt; fueron escritos usando TDD. Algunos tests: 
&lt;/p&gt;
&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0pt;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; ParseIntegerExpr ession()
        {
            Parser parser = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Parser(&amp;quot;&lt;span style="color:#8b0000;"&gt;1&lt;/span&gt;&amp;quot;);
            IExpr ession Expr ession = parser.ParseExpr ession();
            Assert.IsNotNull(Expr ession);
            Assert.IsInstanceOfType(Expr ession, &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(ConstantExpr ession));
            Assert.AreEqual(1, Expr ession.Evaluate(&lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;));
            Assert.IsNull(parser.ParseExpr ession());
        }
        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; ParseVariableExpr ession()
        {
            Parser parser = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Parser(&amp;quot;&lt;span style="color:#8b0000;"&gt;one&lt;/span&gt;&amp;quot;);
            IExpr ession Expr ession = parser.ParseExpr ession();
            Assert.IsNotNull(Expr ession);
            Assert.IsInstanceOfType(Expr ession, &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(VariableExpr ession));
            VariableExpr ession varexpr = (VariableExpr ession)Expr ession;
            Assert.AreEqual(&amp;quot;&lt;span style="color:#8b0000;"&gt;one&lt;/span&gt;&amp;quot;, varexpr.Name);
            Assert.IsNull(parser.ParseExpr ession());
        }&lt;/pre&gt;
&lt;/pre&gt;
&lt;p&gt;Todos los tes est&amp;aacute;n en verde:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter20.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Buen code coverage: &lt;/p&gt;
&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter21.png" alt="" /&gt; &lt;/p&gt;
&lt;p&gt;Noten que usando TDD puedo agregar caracter&amp;iacute;sticas nuevas en &amp;ldquo;baby steps&amp;rdquo; (pasos de beb&amp;eacute;), evitando tiempos de depuraci&amp;oacute;n o agregar grandes fragmentos de c&amp;oacute;digo de una vez. Y siempre tengo al retroalimentaci&amp;oacute;n &amp;ldquo;verde&amp;rdquo;: cada cosa nueva que se agrega se prueba compatible con el anterior c&amp;oacute;digo.&lt;/p&gt;
&lt;p&gt;Pr&amp;oacute;ximos pasos: agregar m&amp;aacute;s expresiones (aritm&amp;eacute;tica, operadores, ..) y comandos (como &lt;b&gt;if&lt;/b&gt;, &lt;b&gt;for&lt;/b&gt;, &amp;hellip;), &amp;ldquo;entrenando&amp;rdquo; al parser en reconocerlas,. Luego puedo agregar al lexer el proceso de strings delimitados por dobles comillas.&lt;/p&gt;
&lt;p&gt;Nos leemos!&lt;/p&gt;
&lt;p&gt;Angel &amp;ldquo;Java&amp;rdquo; Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 
  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1778385" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category></item><item><title>Escribiendo un intérprete en .NET (Parte 4)</title><link>http://msmvps.com/blogs/lopez/archive/2010/09/18/escribiendo-un-int-233-rprete-en-net.aspx</link><pubDate>Sat, 18 Sep 2010 10:15:29 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1778290</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1778290</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/09/18/escribiendo-un-int-233-rprete-en-net.aspx#comments</comments><description>&lt;p&gt;En este post, agrego un analizador léxico, un lexer, para procesar texto y separar el código en tokens, las “palabras” de nuestra entrada.&lt;/p&gt;  &lt;p&gt;La nueva solución:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter14.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Pueden bajar el código de &lt;a href="http://cid-9f903f3d6db0c176.office.live.com/self.aspx/Examples/DotNet/InterpreterStep04.zip" target="_blank"&gt;InterpreterStep04.zip&lt;/a&gt;. Hice refactor de la versión anterior: ahora la class library Interpreter tiene tres directorios y namespaces: &lt;strong&gt;Commands&lt;/strong&gt;, &lt;strong&gt;Expressions&lt;/strong&gt;, &lt;strong&gt;Compiler&lt;/strong&gt;.&lt;/p&gt;  &lt;p&gt;El nuevo código es:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter15.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;El &lt;strong&gt;TokenType&lt;/strong&gt; es una enumeración:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;enum&lt;/span&gt; TokenType
    {
        Name,
        String,
        Integer,
        Operator,
        Separator
    }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Token&lt;/strong&gt; representa una “palabra” de nuestro lenguaje:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Token
    {
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; TokenType TokenType { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;set&lt;/span&gt;;  }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Value { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt;; &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;set&lt;/span&gt;;  }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Token(TokenType type, &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;)
        {
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.TokenType = type;
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Value = &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;;
        }
    }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Value&lt;/strong&gt; contiene el token detectado: su valor entero si era un entero, o su texto, si era un nombre o separador u operador.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lexer&lt;/strong&gt; está encargado de detectar el próximo token desde un TextReader o desde un string:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;       &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Lexer(TextReader reader)
        {
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.reader = reader;
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Lexer(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; text)
            : &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; StringReader(text))
        {
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; Token NextToken()
        {
            &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; ch;
            &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (ch = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.NextChar(); ch != -1 &amp;amp;&amp;amp; &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;.IsWhiteSpace((&lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;)ch); ch = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.NextChar())
                ;
            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (ch == -1)
                &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
&lt;span style="color:#008000;"&gt;//...&lt;/span&gt;
        }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Lexer&lt;/strong&gt; fue escrito en “baby-steps” (pasos de bebé), siguiendo la evolución de los test (recuerden, estoy usando TDD). Escribí un tests, y modifiqué el código para que pasara a verde, y así. Tests como:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; ProcessNameWithWhitespaces()
        {
            Lexer lexer = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Lexer(&amp;quot;&lt;span style="color:#8b0000;"&gt;  one  &lt;/span&gt;&amp;quot;);
            Token token = lexer.NextToken();
            Assert.IsNotNull(token);
            Assert.AreEqual(TokenType.Name, token.TokenType);
            Assert.AreEqual(&amp;quot;&lt;span style="color:#8b0000;"&gt;one&lt;/span&gt;&amp;quot;, token.Value);
            Assert.IsNull(lexer.NextToken());
        }
        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; ProcessTwoNames()
        {
            Lexer lexer = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Lexer(&amp;quot;&lt;span style="color:#8b0000;"&gt;one two&lt;/span&gt;&amp;quot;);
            Token token = lexer.NextToken();
            Assert.IsNotNull(token);
            Assert.AreEqual(TokenType.Name, token.TokenType);
            Assert.AreEqual(&amp;quot;&lt;span style="color:#8b0000;"&gt;one&lt;/span&gt;&amp;quot;, token.Value);
            token = lexer.NextToken();
            Assert.IsNotNull(token);
            Assert.AreEqual(TokenType.Name, token.TokenType);
            Assert.AreEqual(&amp;quot;&lt;span style="color:#8b0000;"&gt;two&lt;/span&gt;&amp;quot;, token.Value);
            Assert.IsNull(lexer.NextToken());
        }
        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; ProcessNameAndSeparator()
        {
            Lexer lexer = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Lexer(&amp;quot;&lt;span style="color:#8b0000;"&gt;one;&lt;/span&gt;&amp;quot;);
            Token token = lexer.NextToken();
            Assert.IsNotNull(token);
            Assert.AreEqual(TokenType.Name, token.TokenType);
            Assert.AreEqual(&amp;quot;&lt;span style="color:#8b0000;"&gt;one&lt;/span&gt;&amp;quot;, token.Value);
            token = lexer.NextToken();
            Assert.IsNotNull(token);
            Assert.AreEqual(TokenType.Separator, token.TokenType);
            Assert.AreEqual(&amp;quot;&lt;span style="color:#8b0000;"&gt;;&lt;/span&gt;&amp;quot;, token.Value);
            Assert.IsNull(lexer.NextToken());
        }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;La versión actual (en este paso) del lexer solo reconoce nombres, algunos separadores como “;” y algún operador como “=”. No procesa strings delimitados, números reales u otros separadores y operadores. Mi idea es ir agregando más capacidades a medida que escriba más tests.&lt;/p&gt;

&lt;p&gt;Todos los tests de la solución en verde:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter16.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Buen code coverage:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter17.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Próximos pasos: escribir un parser que reconozca expresiones, luego que procese comandos, y agregar comandos como if y for, así como definición de funciones. Esto es un intérprete, pero en una nueve serie de posts, podría tratar de compilarlo a código .NET nativo, usando Reflection.Emit or CodeDom.&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1778290" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category></item><item><title>Escribiendo un intérprete en .NET (Parte 3)</title><link>http://msmvps.com/blogs/lopez/archive/2010/09/17/escribiendo-un-int-233-rprete-en-net-parte-3.aspx</link><pubDate>Fri, 17 Sep 2010 09:30:55 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1778210</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1778210</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/09/17/escribiendo-un-int-233-rprete-en-net-parte-3.aspx#comments</comments><description>&lt;p&gt;Esta es la tercera parte de esta serie:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ajlopez.wordpress.com/2010/09/01/writing-an-interpreter-in-net-part-1/"&gt;Writing an Interpreter in .NET (Part 1)&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/09/15/escribiendo-un-int-233-rprete-en-net-parte-1.aspx"&gt;Escribiendo un intérprete en .NET (Parte 1)&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://ajlopez.wordpress.com/2010/09/02/writing-an-interpreter-in-net-part-2/" target="_blank"&gt;Writing an Interpreter in .NET (Part 2)&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/09/16/escribiendo-un-int-233-rprete-en-net-parte-2.aspx" target="_blank"&gt;Escribiendo un intérprete en .NET (Parte 2)&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Hasta ahora, tenemos implementado &lt;strong&gt;IExpression&lt;/strong&gt;, &lt;strong&gt;ConstantExpression&lt;/strong&gt; and &lt;strong&gt;VariableExpression&lt;/strong&gt;, usando un &lt;strong&gt;BindingEnvironment&lt;/strong&gt; 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 &lt;strong&gt;BindingEnvironment&lt;/strong&gt; cambió el &lt;strong&gt;Evaluate&lt;/strong&gt; de las &lt;strong&gt;IExpression&lt;/strong&gt;s.&lt;/p&gt;  &lt;p&gt;En este post, quiero agregar comandos (pueden bajar el código desde &lt;a href="http://cid-9f903f3d6db0c176.office.live.com/self.aspx/Examples/DotNet/InterpreterStep03.zip" target="_blank"&gt;InterpreterStep03.zip&lt;/a&gt;):&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter10.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Esta interfaz &lt;strong&gt;ICommand&lt;/strong&gt; es:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;namespace&lt;/span&gt; Interpreter
{
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;interface&lt;/span&gt; ICommand
    {
        &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Execute(BindingEnvironment environment);
    }
}
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;El método &lt;strong&gt;Execute&lt;/strong&gt; recibe el estado actual, ahora representado por un&amp;#160; &lt;strong&gt;BindingEnvironment&lt;/strong&gt;. El código fue desarrollado usando TDD: no necesito nada más para implementar los tests.&lt;/p&gt;

&lt;p&gt;Primer comando para implementar: &lt;strong&gt;SetCommand&lt;/strong&gt;, que pone un valor en una variable usando el nombre y una expresión a evaluar:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter11.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Primeros tests:&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; CreateSetCommand()
        {
            SetCommand command = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SetCommand(&amp;quot;&lt;span style="color:#8b0000;"&gt;foo&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; 
                ConstantExpr ession(1));
            Assert.AreEqual(&amp;quot;&lt;span style="color:#8b0000;"&gt;foo&lt;/span&gt;&amp;quot;, command.Name);
            Assert.IsInstanceOfType(command.Expression, &lt;span style="color:#0000ff;"&gt;typeof&lt;/span&gt;(ConstantExpression));
        }
        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; ExecuteSetCommand()
        {
            BindingEnvironment environment = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; BindingEnvironment();
            ICommand command = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SetCommand(&amp;quot;&lt;span style="color:#8b0000;"&gt;one&lt;/span&gt;&amp;quot;, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ConstantExpr ession(1));
            command.Execute(environment);
            Assert.AreEqual(1, environment.GetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;one&lt;/span&gt;&amp;quot;));
        }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;El código de implementación:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; SetCommand : ICommand
    {
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; name;
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; IExpression expression;
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; SetCommand(&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; name, IExpression expression)
        {
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.name = name;
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.expression = expression;
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; Name { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.name; } }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IExpression Expression { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.expression; } }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Execute(BindingEnvironment environment)
        {
            environment.SetValue(&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.name, &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.expression.Evaluate(environment));
        }
    }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Noten que el nombre de la variable y la expresión a evaluar son entregadas en el constructor.&lt;/p&gt;

&lt;p&gt;Ahora, los tests están en verde:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter12.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Buen coverage:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter13.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1778210" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category></item><item><title>Escribiendo un intérprete en .NET (Parte 2)</title><link>http://msmvps.com/blogs/lopez/archive/2010/09/16/escribiendo-un-int-233-rprete-en-net-parte-2.aspx</link><pubDate>Thu, 16 Sep 2010 09:41:01 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1778130</guid><dc:creator>lopez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1778130</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/09/16/escribiendo-un-int-233-rprete-en-net-parte-2.aspx#comments</comments><description>&lt;p&gt;En mi anterior post:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ajlopez.wordpress.com/2010/09/01/writing-an-interpreter-in-net-part-1/" target="_blank"&gt;Writing an Interpreter in .NET (Part 1)&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/09/15/escribiendo-un-int-233-rprete-en-net-parte-1.aspx" target="_blank"&gt;Escribiendo un intérprete en .NET (Parte 1)&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Presenté expresiones y la implementación de &lt;strong&gt;ConstantExpression&lt;/strong&gt;. Hoy quiero implementar una expresión de variable: una expresión que dado el nombre de una variable retorna su valor asociado. El código de este paso lo pueden bajar desde &lt;a href="http://cid-9f903f3d6db0c176.office.live.com/self.aspx/Examples/DotNet/InterpreterStep02.zip" target="_blank"&gt;InterpreterStep02.zip&lt;/a&gt;. Y de nuevo, lo quiero implementar usando Test-Driven Development. El código que se bajen es el FINAL del proceso, pero espero que igual sirva como ejemplo de esta forma de desarrollo. &lt;/p&gt;  &lt;p&gt;Pueden seguir el código de esta serie y mis progresos en mi &lt;a href="http://code.google.com/p/ajcodekatas/" target="_blank"&gt;AjCodeKata Google Project&lt;/a&gt;, en el trunk, dentro del directorio Interpreter. Si quieren ejemplos más complejos, también armados con TDD, ver &lt;a href="http://ajlopez.wordpress.com/category/ajsharp/"&gt;AjSharp&lt;/a&gt;, &lt;a href="http://ajlopez.wordpress.com/category/ajtalk/"&gt;AjTalk&lt;/a&gt;, &lt;a href="http://ajlopez.wordpress.com/category/ajlisp/"&gt;AjLisp&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;La solución de este paso:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter05.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Implementé un &lt;strong&gt;BindingEnvironment&lt;/strong&gt;, un lugar donde salvar los nombres de variables y sus valores asociados:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter06.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Mis tests:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; BindingEnvironmentTests
    {
        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; SetAndGetValue()
        {
            BindingEnvironment environment = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; BindingEnvironment();
            environment.SetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;one&lt;/span&gt;&amp;quot;, 1);
            Assert.AreEqual(1, environment.GetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;one&lt;/span&gt;&amp;quot;));
        }
        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; GetNullIfUndefinedName()
        {
            BindingEnvironment environment = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; BindingEnvironment();
            Assert.IsNull(environment.GetValue(&amp;quot;&lt;span style="color:#8b0000;"&gt;undefined&lt;/span&gt;&amp;quot;));
        }
    }&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Noten que especifiqué que obtener un valor no definido no da error sino que retorna null. Si hubiera decidido lanzar una excepción, mi tests hubiera debido reflejar esa decisión. Quiero que al usar un lenguaje no sea necesario definir variables, sino simplemente usarlas. Si una variable no “existe”, no está inicializada, entonces es como si tuviera null.&lt;/p&gt;

&lt;p&gt;Después, cambié &lt;strong&gt;IExpression.Evaluate&lt;/strong&gt; para que acepte un&amp;#160; &lt;strong&gt;BindingEnvironment &lt;/strong&gt;como parámetro:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;interface&lt;/span&gt; IExpression
    {
        &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Evaluate(BindingEnvironment environment);
    }&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Escribí una nueva &lt;strong&gt;VariableExpression &lt;/strong&gt;(y adapté la ya existente &lt;strong&gt;ConstantExpression&lt;/strong&gt;):&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter07.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Mis tests:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; EvaluateIntegerVariable()
        {
            BindingEnvironment environment = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; BindingEnvironment();
            IExpression expression = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; VariableBLOCKED EXPRESSION;
        }&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Todos los tests, ahora, están en verde:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter08.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Pero recuerden: eso es el final. Usando TDD fue pasando de rojo, a verde, a refactor.&lt;/p&gt;

&lt;p&gt;Buen code coverage:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter09.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Próximos pasos: implementar comandos y un &lt;strong&gt;SetCommand&lt;/strong&gt;: que cambie el valor de una variable. De nuevo, escribir todo eso usando TDD.&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1778130" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category></item><item><title>Escribiendo un intérprete en .NET (Parte 1)</title><link>http://msmvps.com/blogs/lopez/archive/2010/09/15/escribiendo-un-int-233-rprete-en-net-parte-1.aspx</link><pubDate>Wed, 15 Sep 2010 10:38:22 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1778049</guid><dc:creator>lopez</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1778049</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/09/15/escribiendo-un-int-233-rprete-en-net-parte-1.aspx#comments</comments><description>&lt;p&gt;Hace un poco más de una semana, tuve la oportunidad de dar una charla sobre compiladores e intérpretes en .NET, en el Code Camp Buenos Aires &lt;a href="http://www.codecamp.com.ar"&gt;http://www.codecamp.com.ar&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Escribí varios intérpretes en .NET (&lt;a href="http://ajlopez.wordpress.com/category/ajsharp/" target="_blank"&gt;AjSharp&lt;/a&gt;, &lt;a href="http://ajlopez.wordpress.com/category/ajtalk/" target="_blank"&gt;AjTalk&lt;/a&gt;, &lt;a href="http://ajlopez.wordpress.com/category/ajlisp/" target="_blank"&gt;AjLisp&lt;/a&gt;….) y sigo con ese desarrollo. Pero ahore, me gustaría ir explorando los pasos que sigo para escribir un simple intérprete, sin usar herramientas de construcción de gramáticas.&lt;/p&gt;  &lt;p&gt;Primero, uso Driven Development. Para cada cosa que agrego en código, escribo el test, lo ejecuto en rojo, cambio el código para que quede en verde, y luego refactor. Pueden bajar el código de este primer post desde &lt;a href="http://cid-9f903f3d6db0c176.office.live.com/self.aspx/Examples/DotNet/InterpreterStep01.zip" target="_blank"&gt;InterpreterStep01.zip&lt;/a&gt;). La solución es:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/intrepreter01.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;El punto de partida es una expression. &lt;/p&gt;  &lt;pre&gt;&lt;pre style="font-size:12px;margin:0px;width:100%;font-family:consolas,courier,monospace;background-color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;namespace&lt;/span&gt; Interpreter
{
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;interface&lt;/span&gt; IExpression
    {
        &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Evaluate();
    }
}
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Escribí una interfaz, pero podría haber escrito una primera clase concreta, y entonces, extraer la interfaz luego de tener algo andando. En este intérprete simple, una expresión es algo a ser evaludado, como&lt;/p&gt;

&lt;p&gt;&lt;font face="Consolas"&gt;3 
    &lt;br /&gt;”foo” 

    &lt;br /&gt;3+5 

    &lt;br /&gt;fun(a)&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;La primera clase concreta es ConstantExpression: new ConstantBLOCKED EXPRESSION;
        }
    }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Los tests están en verde:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter02.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Buen code coverage:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/interpreter03.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Bien, es un ejemplo muy simple. Pero es un punto de partida. Próximos pasos: agregar el manejo de variables, su evaluación. Y luego, agregaré comandos, la asignaciónde valor a una variable. Podría escribir funciones, analizador léxico, parser, y más, todo usando TDD.&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1778049" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category></item><item><title>CodeCamp en Buenos Aires: Intérpretes y Compiladores en .NET</title><link>http://msmvps.com/blogs/lopez/archive/2010/08/31/codecamp-en-buenos-aires-int-233-rpretes-y-compiladores-en-net.aspx</link><pubDate>Tue, 31 Aug 2010 09:21:16 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1776938</guid><dc:creator>lopez</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1776938</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/08/31/codecamp-en-buenos-aires-int-233-rpretes-y-compiladores-en-net.aspx#comments</comments><description>&lt;p&gt;El próximo sábado tendremos CodeCamp en Buenos Aires:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://www.codecamp.com.ar" href="http://www.codecamp.com.ar"&gt;http://www.codecamp.com.ar&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/codecamp.jpg" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Les recomiendo una visita al blog (en la página principal) y a la agenda:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://www.codecamp.com.ar/agenda.aspx" href="http://www.codecamp.com.ar/agenda.aspx"&gt;http://www.codecamp.com.ar/agenda.aspx&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;donde hay actividades y charlas desde la mañana hasta la tarde, sobre Azure, Entity Framework 4, .NET 4, Arquitectura de Software (por &lt;a href="http://twitter.com/MartinSalias" target="_blank"&gt;@MartinSalias&lt;/a&gt;), WPF, IronRuby, DynamicDataCenter, SQL Server, Silverlight, ASP.NET MVC, HyperV, WCF, SQL Azure, HTML5, Windows 7, y demos de las Células (vean por ejemplo el video de &lt;a href="http://www.codecamp.com.ar/sinerg%c3%ada-una-c%c3%a9lula-microsoft-con-todas-las-letras.aspx" target="_blank"&gt;Sinergia en una Célula Microsoft&lt;/a&gt;)&lt;/p&gt;  &lt;p&gt;Gracias a &lt;a href="http://twitter.com/masaez" target="_blank"&gt;@masaez&lt;/a&gt;, que me invitó al evento, en el Track 4 (16:35), Sala Arquitectura, daré una charla sobre Intérpretes y Compiladores en .NET. Los que me leen por aquí, saben que es uno de mis temas preferidos: construir lenguajes con distintos paradigmas de programación, y para usarlos en proyectos (como AjBasic en &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/AjGenesis/default.aspx" target="_blank"&gt;AjGenesis&lt;/a&gt;). La charla es de 75 minutos, con preguntas y respuestas.&lt;/p&gt;  &lt;p&gt;Mi idea es visitar temas como:&lt;/p&gt;  &lt;p&gt;- Cómo construir un Intérprete, con pasos en detalle, usando TDD.   &lt;br /&gt;- Tokens, Lexer, Parser, Expresiones, Comandos    &lt;br /&gt;- Ejemplos de intérpretes, de distintos tipos de lenguajes, como &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx" target="_blank"&gt;AjSharp&lt;/a&gt;, &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/AjTalk/default.aspx" target="_blank"&gt;AjTalk&lt;/a&gt; (bytecodes a la Smalltalk), &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/AjLisp/default.aspx" target="_blank"&gt;AjLisp&lt;/a&gt; (más funcional), o &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/AjIo/default.aspx" target="_blank"&gt;AjIo&lt;/a&gt;, tendré que elegir algunos.    &lt;br /&gt;- Comentar los lenguajes que han sido portados a .NET    &lt;br /&gt;- Descubrir IL (Intermediate Language) y generar código desde nuestros programas    &lt;br /&gt;- Ejemplo de AST (Abstract Syntax Tree)    &lt;br /&gt;- La aparición de los lambda. Compilación de Expressions    &lt;br /&gt;- Compilación dinámica de expressions    &lt;br /&gt;- Dynamic Runtime Library, ejemplos de lenguajes implementados    &lt;br /&gt;- Y espero transmitir algo de ¿por qué más lenguajes?&lt;/p&gt;  &lt;p&gt;Como siempre, el código, enlace, presentación que prepare, quedaran aquí publicados en próximo post.&lt;/p&gt;  &lt;p&gt;Nos leemos!&lt;/p&gt;  &lt;p&gt;Angel “Java” Lopez   &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1776938" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjLisp/default.aspx">AjLisp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjBasic/default.aspx">AjBasic</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Programaci_26002300_243_3B00_n+Funcional/default.aspx">Programaci&amp;#243;n Funcional</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx">AjSharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lisp/default.aspx">Lisp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/TDD/default.aspx">TDD</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjTalk/default.aspx">AjTalk</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Dynamic+Language+Runtime/default.aspx">Dynamic Language Runtime</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjIo/default.aspx">AjIo</category></item></channel></rss>