Archive for the '17834' Category

Mass Lenguaje de Programación (5) Acceso a Variables

Sunday, June 15th, 2014

Anterior Post

Al fin comencé una nueva implementación de variables y su alcance en el lenguaje Mass. Mi idea es:

– Tener variables locales

– Sin necesidad de declararlas explícitamente

– Acceso al alcance “de afuera” si es necesario

La idea base es:

– Cualquier asignación a variable involucra al alcance local

Es decir, que si asigno

a = 3

en una función, esto refiere a una variable local a, en esa función. No importa si hay una variable a, externa a la función

Ver como ejemplo

https://github.com/ajlopez/Mass/blob/master/Src/Mass.Core.Tests/MachineFiles/Local.ms

# file variable
a = 1

define foo()
    a = 2 # local variable
end

foo()

La primer variable a es una variable del archivo en proceso. La variable asignada en la función foo, es una variabla local a ese entorno de función, y es distinta de la variable “de afuera”.

En cambio, si no asignamos la variable, y solamente la consultamos, no queda como variable local. Ejemplo:

https://github.com/ajlopez/Mass/blob/master/Src/Mass.Core.Tests/MachineFiles/Scope.ms

# file variable
a = 1

define foo()
   a # access file variable
end

foo()

En este caso, la función foo devuelve el valor de a “de afuera”, pues esa variable no ha sido asignada en la función en el momento de evaluar el valor de retorno.

¿Cómo modificar una variable “de afuera”, que no sea local? Bien, tema para próximo post. La idea: acceder al valor de una variable no local, tiene que ser implícito, sin necesidad de declarar nada adicional. PERO MODIFICAR su valor debe ser explícito: debemos poner algo para que se entienda “queremos modificar el valor de una variable no local”.

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

Resoluciones del Nuevo Mes: Julio 2013

Saturday, July 6th, 2013

Revisión de mis resoluciones de Junio:

– Actualizar Mass [completo] repo
– Actualizar RubySharp [completo] repo
– Actualizar PythonSharp [completo] repo
– Actualizar ClojSharp [completo] repo
– Actualizar AjSharp [pendiente]
– Ejemplos de AjGenesis Node.js [pendiente]
– Actualizar Aprendiendo Ruby [pendiente]
– Actualizar Aprendiendo Python [completo] repo
– Escribir ejemplo Node.js/Express/MongoDb [completo] repo
– Nuevo post sobre RubySharp [pendiente]
– Nuevo post sobre TDD [completo] post post
– Nuevo post sobre lenguaje Mass [pendiente]

También pude dar una charla de introducción a Python ver repo. Y además:

– Comenzar un compilador Forth a JavaScript [completo] repo
– Comenzar un parser genérico en C# [completo] repo
– Comenzar un parser genérico en JavaScript [completo] repo
– Comenzar AjLisp en Python [completo] repo
– Comenzar ejecutor de tareas en C# [completo] repo
– Actualizar AjLisp en JavaScript [completo] repo
– Actualizar ObOps [completo] repo
– Comenzar Aprendiendo Java [completo] repo
– Actualizar AjErl [completo] repo
– Actualizar AjGenesisNode [completo] repo
– Actualizar RunIt [completo] repo
– Post sobre ObObjs [completo] post

Resoluciones de Julio:

– Actualizar Memolap
– Actualizar GrammGen
– Actualizar SimpleGrammar
– Preparar charla: Introducción a Smalltalk
– Comenzar compilador PHP a JavaScript
– Comenzar ejemplo PHP con Node.js
– Actualizar AjLispJs
– Crear un ejemplo web usando AjLisp y Node.js

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

ObOps: Operadores para Objetos

Saturday, June 15th, 2013

En varios de mis proyectos open source de intérpretes, uso una librería Microsoft.VisualBasic que tiene un namespace Microsoft.VisualBasic.CompilerServices con una clase Operators que implementa operaciones sobre objetos cualesquiera. Por ejemplo, puede sumar dos objetos, sin saber de antemano qué tipo tienen (enteros, dobles, strings) cada uno de los dos parámetros. La comencé a usar ya debe ser casi una década, y fue una de las razones para escribir AjGenesis directamente en Visual Basic.NET: me permite escribir

obj1 + obj2

sin saber los tipos de antemano. Como AjGenesis compilado en Windows, corre tal cual en Mono, me confié que los métodos de esa clase Operators estaban disponibles en otras plataformas. Así que escribí varios intérpretes usando esa clase.

Pero ahora que estoy escribiendo Mass, el bueno de @MartinSalias me cuenta por un mensaje de Twitter, que no hay Microsoft.VisualBasic.CompilerServices.Operators en Mono.

Leo en:

http://www.mono-project.com/FAQ:_Technical

With regards to languages, C# applications tend to be most portable. Visual Basic .NET applications are portable, but Mono’s Microsoft.VisualBasic.dll implementation is incomplete. It is recommended to either avoid using this assembly in your own code, only use the portions that Mono has implemented, or to help implement the missing features. Additionally, you can set ‘Option Strict On’, which eliminates the implicit calls to the unimplemented Microsoft.VisualBasic.CompilerServices.ObjectType class. (Thanks to Jörg Rosenkranz.)

Así que no puede compilar la solución. En estos meses, estoy ocupado preparando tres charlas (dos ya las dí: Node.js, Ruby; ahora dentro de poco, viene la tercera, Python) con sus respectivos ejemplos y presentaciones. Pero igual pude hacerme un tiempo para comenzar a implementar algo en C# para subsanar la falencia:

https://github.com/ajlopez/Obops

Traté de implementar algún tipo de “double dispatch” o algo parecido, usando generics y demás, pero parece que no hay tu tía. Mi investigación en:

https://github.com/ajlopez/Obops#references

Así que comencé a implementar los operadores aritméticos binarios, uno a uno:

https://github.com/ajlopez/Obops/blob/master/Src/Obops/Operators.cs

Pero no crea que todo lo hice yo. Como vi que había una explosión de combinaciones, decidí pasar, luego de tener algunos casos implementados, a la generación automática de código. Pueden ver el modelo, las plantillas y tareas en:

https://github.com/ajlopez/Obops/tree/master/CodeGen

Tengo que explicar ahí más en detalle como lo consigo, pero es, teniendo AjGenesis bin en el PATH, cosa de hacer:

AjGenesis.Console Model.xml Operators.tpl Operators.cs Tests.tpl Tests.cs

Así de simple. Ya lo comencé a usar en Mass:

https://github.com/ajlopez/Mass

Pero falta:

– Implementar más operadores

– Habilitar la configuración por código desde afuera (por ejemplo, para sumar null + entero, usar tal función)

– Agregar tests que prueben el resultado contra la implementación original de Microsoft.VisualBasic

Nos leemos!

Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez

Mass Lenguaje de Programación (4) Lexer y Parser

Sunday, May 12th, 2013

Anterior Post 
Siguiente Post 

En la implementación del lenguaje Mass, tengo una enumeración y una clase:

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:

El constructor de Lexer recibe un string:

public Lexer(string text)
{
    this.text = text;
}

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.

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.

Voy a modificar el Lexer para consumir un stream de texto, para poder procesar, por ejemplo, entrada de consola

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.

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

Mass Lenguaje de Programación (3) Comandos

Sunday, April 28th, 2013

Anterior Post  
Siguiente Post 

Veamos hoy cómo están implementados los comandos en Mass (ver repo). En el proyecto de librería de clases, tengo:

Hay comandos para if, while, for, for each, etc…. Todos implementan la interfaz ICommand:

public interface ICommand
{
    object Execute(Context context);
}

Vean que es muy parecido a IExpression. Igual quise mantener comandos y expresiones por separado, por lo menos en esta primera implementación, para tener un claro delineamiento de los conceptos de base del lenguaje.

Un ejemplo típico de comando es el WhileCommand (parte del código):

public class WhileCommand : ICommand
{
    private static int hashcode = typeof(WhileCommand).GetHashCode();

    private IExpression condition;
    private ICommand command;

    public WhileCommand(IExpression condition, ICommand command)
    {
        this.condition = condition;
        this.command = command;
    }

    public object Execute(Context context)
    {
        for (object value = this.condition.Evaluate(context); 
            value != null && !false.Equals(value);
            value = this.condition.Evaluate(context))
        {
            this.command.Execute(context);
            if (context.HasContinue())
                context.ClearContinue();
            if (context.HasBreak())
            {
                context.ClearBreak();
                break;
            }
        }

        return null;
    }
}

Para Mass: cualquier valor null o false es falso. Todo lo demás es verdadero. Un tema a refactorizar: poner un método IsFalse para se usado tanto en la implementación de While como de If.

Otro ejemplo es el ForEachCommand (parte del código):

public class ForEachCommand : ICommand
{
    private string name;
    private IExpression expression;
    private ICommand command;

    public ForEachCommand(string name, IExpression expression, ICommand command)
    {
        this.name = name;
        this.expression = expression;
        this.command = command;
    }

    public object Execute(Context context)
    {
        var values = (IEnumerable)this.expression.Evaluate(context);

        foreach (var value in values)
        {
            context.Set(this.name, value);
            this.command.Execute(context);
            if (context.HasContinue())
                context.ClearContinue();
            if (context.HasBreak())
            {
                context.ClearBreak();
                break;
            }
        }

        return null;
    }
}

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ía hecho un break o un continue.

Y como siempre, todo esto desarrollado con TDD: pueden ver los commits del repo.

Próximos posts: Lexer y Parser, ejemplos de Mass para scripting.

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

Mass Lenguaje de Programación (2) Primeras Expresiones

Saturday, April 27th, 2013

Anterior Post  
Siguiente Post 

Antes de ver cómo usar el lenguaje Mass (ver repo), quisiera tratar algunos temas de implementación. Primero, una novedad: ahora hay una solución (en https://github.com/ajlopez/Mass/blob/master/Src/Mass.sln) que puede compilarse con algún Visual Studio C# Express, de libre bajada e instalación.

La solución Mass tiene un proyecto de librería de clases. Ahí hay un namespace dedicado a expresiones:

Una expresión es algo que cumple con IExpression:

  
public interface IExpression
{
	object Evaluate(Context context);
}
  

Un Context mantiene un diccionario de nombre/valor, para guardar las variables actuales:

  
public void Set(string name, object value)
{
	this.values[name] = value;
}

public object Get(string name)
{
	if (this.values.ContainsKey(name))
		return this.values[name];

	if (this.parent != null)
		return this.parent.Get(name);

	return null;
}
  

(vean de refilón, que soporta contextos anidados: cada contexto puede “heredar” de un contexto parent).

La expresión más simple es la que devuelve una constante, que puede ser cualquier valor/objecto .NET:

  
public class ConstantExpression : IExpression
{
	// ...

	private object value;

	public ConstantExpression(object value)
	{
		this.value = value;
	}

	public object Evaluate(Context context)
	{
		return this.value;
	}

	// ...
}
  

La siguiente expresión más simple es la evaluación de un nombre de variable en el contexto actual:

  
public class NameExpression : IExpression
{
	// ...
	
	private string name;

	public NameExpression(string name)
	{
		this.name = name;
	}

	public object Evaluate(Context context)
	{
		return context.Get(this.name);
	}
	
	// ...
}
  

Es necesario especificar el contexto (por ejemplo, el contexto de la función actual, de una clausura, del objeto actual, del módulo actual, etc), porque un mismo nombre puede tener distintas variables asociadas, como pasa en otros lenguajes.

Como siempre, cada una de estas clases (Expresiones, Contexto, …) fue armada usando el flujo de trabajo de TDD (ver el proyecto de tests, y la historia de commits del repo donde dejé evidencia de cómo fue el desarrollo en el tiempo).

Próximos posts: algunas expresiones adicionales, comandos, usando Mass para scripting, usando Mass desde nuestro programa .NET, etc..

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

Mass Lenguaje de Programación (1) Orígenes

Monday, April 8th, 2013

Siguiente Post

Durante estos días, estuve trabajando en la implementación de un lenguaje interpretado, sobre C#, llamado Mass (dedicado al bueno de @MArtinSaliaS):

https://github.com/ajlopez/Mass

La solución actual se compone de tres proyectos: una librería de clases, sus tests, y un programa de consola, mass.exe, para lanzar programas Mass

Pueden lanzar un programa escrito en un archivo hello.ms con

mass hello.ms

El clásico Hello world es entonces

println("Hello, world")

Un ejemplo con clases y objetos

class Person
	define initialize(firstname, lastname)
		self.firstname = firstname
		self.lastname = lastname
	end
	
	define getName()
		return self.lastname + ", " + self.firstname
	end
end

adam = new Person("Adam", "TheFirst")

println(adam.getName())

Un ejemplo con acceso a tipos y objectos .NET:

dirinfo = new System.IO.DirectoryInfo(".")

for fileinfo in dirinfo.GetFiles()
	println(fileinfo.Name)
end

La idea es (como en AjSharp y otras implementaciones) tener un lenguaje dinámico montado sobre un lenguaje/librería de clases. Y poder acceder a esa librería de clases desde el nuevo lenguaje. Me llevó a escribir Mass de la forma en que lo hice, el haber trabajado antes en:

– Implementar Python en C# (ver PythonSharp)

– Implementar Ruby en C# (ver RubySharp)

– El ya mencionado AjSharp (ver repo y posts)

Pero esta vez quería implementar algo que tuviera sintaxis y semántica simple. Ya estuve pensando en eso de “simple” para implementar un compilador de lenguaje simple a JavaScript ver SimpleScript

Entonces con Mass me propuse evitar:

– Múltiples comandos en la misma línea (descarté el ‘;’ de Ruby)

– Sintaxis basada en espacios en blanco, indentación (descartado Python)

– Llamadas a funciones con simplemente el nombre: se necesita explícitamente los paréntesis (descartado el Ruby clásico)

– Que las clases/valores de base (por ejemplo, enteros, strings, arreglos, etc…) tuvieran multitud de métodos (tienen los dados por la librería de clases de implementación, en este caso .NET) (descartado Ruby, que tiene casi tantos métodos nativos como PHP)

Y quise tener:

– Valores funcionales, como ciudadanos de primera clase, como en JavaScript. Vean que al tener que invocar una función con paréntesis, si o si, entonces la variable func tiene el valor funcional, y func() es la invocación explícita

– Objectos dinámicos: cada objeto puede extenderse en cualquier momento, con nuevas variables de instancia, funciones propias del objeto, como JavaScript

– Sintaxis basada en líneas: cada comando va en una línea distinta

– Sintaxis basada en palabras claves: para los comandos compuestos se usa ‘end’ para terminar un bloque

– En lo posible, una sola forma de hacer algo, en vez de múltiples maneras

– Palabras claves completas, ‘define’ en vez de ‘def’

– Clases con herencia simple (aunque la esencia de Mass bien puede expresarse sin clases, y usar librerías de clases ya escritas en .NET)

– Modificación explícita de variables fuera del alcance local (para explicar en próximos posts)

– Alcance de variables por archivo, como en JavaScript/NodeJs/CommonJS

– Módulos por archivo, con un require que permite buscar en directorios automáticamente, como en NodeJs/CommonJS

– Empaquetamiento, manejo de dependencias e instalación de esos módulos usando algo ya dado, como NPM, el manejador de paquetes de Node.js

En próximos posts, más detalles de implementación, ideas que guiaron el diseño, ejemplos. Pero ya pueden ver el código, y los ejemplos que están en los tests (sí, está todo construido paso a paso usando TDD).

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez