Archive for the '11722' Category

AjTalk Implementando Smalltalk en C# (4) El Proyecto

Sunday, June 29th, 2014

Anterior Post

Hace ya año y medio que no escribo de este proyecto en C#, pero fui trabajando en él, y en la implementación paralela que tengo en JavaScript (de hecho, presenté algunos conceptos de ambos en la Smalltalks 2013 que se realizó el año pasado, en Rosario, Argentina).

El proyecto está en:

https://github.com/ajlopez/AjTalk

La estructura actual:

Veamos. Los proyectos son:

AjTalk: librería de clases, con la implementación de un compilador a bytecodes (y también a JavaScript), y un intérprete de los bytecodes compilados.

AjTalk.Compiler: un proyecto de consola que permite, usando el compilador mencionado en el proyecto anterior, generar código JavaScript.

AjTalk.Console: un REPL (Read Eval Print Loop)

AjTalk.Gui: una implementación sin terminar de ventanas

AjTalk.Tests: los tests que fui escribiendo, siguiendo el flujo de trabajo de TDD (Test-Driven Development)

El compilador a JavaScript creo que no lo voy a necesitar, porque en el último año he conseguido que el proyecto de JavaScript:

https://github.com/ajlopez/AjTalkJs

sea autosuficiente (ahora compila a bytecodes, pero también podría compilar a JavaScript; el tema que el intérprete de bytecodes me permite algunas operaciones más flexibles).

Y la implementación de ventanas (muy primitiva) la voy a sacar, para seguir por el camino de crear ventanas desde el propio AjTalk, en Smalltalk, accediendo a los tipos y objetos de .NET.

Un punto que me parece muy interesante (en ambos proyectos, el de C# y el de JavaScript) es tener una implementación modular: en vez de cargar una imagen con todo definido, poder definir módulos a cargar, como pasa en el ambiente Node.js. Los módulos estarían publicados en el NPM (El Node Package Manager), y cada cual podría indicar qué módulos necesita en su programa, en lugar de levantar todo Smalltalk.

Otro tema: en este proyecto de C# tengo implementado que pueda levantar más de una máquina AjTalk al mismo tiempo. E incluso puedo hacer que una máquina “ayude” a la otra. Por ejemplo, si la máquina A no tiene los métodos para compilar nuevos métodos, la máquina B puede ir en su auxilio. Así, la máquina A (y su imagen, que ya estoy grabando imagen binaria) puede mantenerse de tamaño pequeño.

Otra característica que tengo implementada: la capacidad de enviar un mensaje a un objeto, sin esperar una respuesta, un “fire and forget”. Y que el objeto destino pueda atender esos mensajes DE A UNO, como en los modelos de actores.

Tengo que revisar la implementación de objetos remotos (hoy basada en el viejo Remoting de .NET). Pero pienso que es una característica importante a mantener y explorar.

Bien, como ven, quedan multitud de temas para otros posts, como detalles de implementación de conceptos de Smalltalk, como Object, Class, ClassDescription, Behavior, MetaClass, etc.

Nos leemos!

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

Smalltalk, JavaScript, NodeJs, C#, y Tutti Li Fiocci

Monday, February 3rd, 2014

El año pasado tuve el gran placer de asistir a Smalltalks 2013, en la ciudad de Rosario, Argentina.  Asistir a esa conferencia fue una gran experiencia para mí, con charlas interesantes, implementaciones más interesantes y muchas ideas para digerir. Además de encontrarme con gente como @garduino, @morplenauta y @hernanwilkinson.

Dí una charla sobre cómo implementar Smalltalk en C# y en JavaScript. Los principales repositorios están en:

http://github.com/ajlopez/AjTalk (lo presenté por primera vez en Smalltalks 2010)
https://github.com/ajlopez/AjTalkJs (lo presenté en Smalltalks 2011)

Mi charla, grabada gracias a la organización:

http://www.youtube.com/watch?v=-KFjSneVE2s

[View:http://www.youtube.com/watch?v=-KFjSneVE2s]

La presentación:

https://github.com/ajlopez/Talks/tree/master/Smalltalks2013
http://ajlopez.github.io/Talks/Smalltalks2013/index.html
Mis otras charlas del año en http://ajlopez.github.io/Talks/

El primer proyecto, en C#, compila a bytecodes y los interpreta. También puede compilar a JavaScript, pero en los últimos meses conseguí que el proyecto de JavaScript no necesitara de este compilador. Pero quedó implementado un patrón Visitor que podría modificar para recorrer el árbol de expresiones y generar código para otros lenguajes, por ejemplo Python o Ruby. Lo bueno de la VM en C# es que puede acceder a tipos y objetos nativos de C#. Además hay actores, ejecución remota, ver mis posts.

El segundo proyecto es una implementación de Smalltalk en JavaScript. Internamente, tiene un compilador a JavaScript, pero también tiene un compilador a un arreglo de bytecodes, que luego puede interpretar. Ambos proyectos, el de C# y el de JavaScript, ahora soportan el consumo de módulos que se instalan usando NPM (el manejador de paquetes de Node.js).

En 2013, a AjTalkJs le agregué mucho mejor soporte de Node.js, con acceso a módulos, así que ahora puedo ejecutar aplicaciones Express desde Smalltalk:

 

Próximos experimentos: mensajes distribuidos. Esto es, un objecto en una máquina enviando un mensaje a un objeto en otra máquina/proceso, en una forma “fire and forget”. Pienso que el ecosistema de Node.js puede ser un buen lugar para estos experimentos. Mi trabajo en el tema en Distributed Applications with Node.js. Quiero ahora una aplicación Smalltalk distribuida. Quizás, si consigo que el protocolo de comunicación sea simple y enchufable, podría implementarlo en otras implementaciones de Smalltalk, o en otros lenguajes. Pero primero, “baby steps”  😉

Nos leemos!

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

Resoluciones del Nuevo Mes: Diciembre 2013

Friday, December 6th, 2013

Primero, revisar mis resoluciones de Noviembre:

– Comenzar un compilador de Python reducido a C, usando JavaScript [complet] repo
– Dar una charla sobre implementación de Ruby en C# [completo] slides repo
– Comenzar intérprete Ruby en JavaScrip [completo] repo
– Completar el alcance de variables en lenguaje Mass [pendiente]
– Dar una charla sobre interpretar y compilar lenguajes en JavaScript [completo] slides
– Escribir un framework web para AjTalkJs (para ser usado desde Node.js) (plano o MVC) [pendiente]
– Mejorar módulos NPM en AjTalkJs y AjTalk [parcial] repo
– Mejorar soporte de tests en AjTalkjs y AjTalk [pactial] repo
– Mejorar las estructuras de datos en AjErl [pendiente]

Mis resoluciones para Diciembre:

– Dar un curso de un día sobre Node.js
– Refactorizar y mejorar CobolScript
– Continuar escribiendo en intérprete de Ruby en JavaScript
– Terminar de definir el alcance de variables en el lenguaje Mass
– Más módulos iniciales para AjTalkJs

Nos leemos!

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

Resoluciones del Nuevo Mes: Noviembre 2013

Tuesday, November 5th, 2013

Estas fueron mis resoluciones de Octubre:

– Dar una charla sobre PHP and Node.js [complete] see post and PHP/Node repo and PageJs repo at PHP Dev Argentina 2013

– Dar una charla sobre TDD con ASP.NET MVC [completo] ver repo

– Dar una charla sobre la implementación de Scala [completo] ver slides y ejemplos simples

– Dar una charla sobre Python en JavaScript [completo] ver repo y slides para PyCon 2013 Argentina

– Dar una charla sobre Smalltalk en JavaScript y C# [completo] ver repo y slides para Smalltalks 2013

Las resoluciones para este nuevo mes:

– Comenzar un compilador de Python reducido a C, usando JavaScript

– Dar una charla sobre Ruby en C#

– Compezar un compilador de Ruby a JavaScript

– Completar el alcance de variables en el lenguaje Mass

– Dar una charla sobre compilando lenguajes a JavaScript (a confirmar)

– Escribir un framework web para AjTalkJs (a ser usado en Node.js) (plano? con MVC?)

– Mejorar la implementación de módulos NPM en AjTalkJs y AjTalk

– Mejorar el soporte de tests en AjTalkjs y en AjTalk

– Mejorar el manejo de estructuras y match en AjErl

Nos leemos!

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

 

AjTalk en C# (3) Environments

Thursday, December 27th, 2012

Anterior Post 
Siguiente Post 

Hace unas semanas, agregué el soporte de environments (ambiente, entorno) a mi proyecto de código abierto AjTalk, una máquina virtual Smalltalk escrita en C# (hay otras versiones, en Java y en JavaScript). ¿Qué es un environment en mi jerga? Es un diccionario, donde puedo guardar artefactos por nombre, un directorio. Por ejemplo, para guardar clases por nombre. La variable global Smalltalk es un environment clásico. Pero en un Smalltalk clásico, todas las clases definidas van a parar a ese diccionario global, lo que puede dar lugar a colisión de nombres. La forma normal de solucionar (p.ej. en Squeak y Pharo) es agregarle un prefijo (de dos letras) a cada clase de nuestra librería. Pero yo quiero tener el soporte de tener otros environments, como pasa con los namespaces de .NET o los package de Java. Smalltalk clásico también tiene los llamados pool dictionary, pero hasta donde sé, son para usar desde una clase y sus derivados. Yo quiero tener la noción de paquete: todas estas clases se ven entre sí, pero no están en el environment del tope, en Smalltalk, sino en un environment dedicado a mi librería. Agregué una implementación inicial, con estos tests:

https://github.com/ajlopez/AjTalk/blob/master/Src/AjTalk.Tests/AssertTests/EnvironmentTests.st

Al comienzo, verifico que Smalltalk es un ambiente, un environment y es el actual:

"Current environment is Smalltalk"
[Environment current == Smalltalk] assert.

Puedo crear nuevos entornos:

env := Environment new: #MyEnvironment.

Automáticamente, el nuevo entorno se registra/agrega al entorno actual, en este caso, a Smalltalk:

"The new environment was defined as global at Smalltalk"

[(Smalltalk at: #MyEnvironment) isNil not] assert.
[(Smalltalk at: #MyEnvironment) == MyEnvironment] assert.
[(Smalltalk at: #MyEnvironment) == env] assert.

[MyEnvironment isNil not] assert.
[MyEnvironment == env] assert.

Cada nuevo entorno tiene automáticamente una entrada Smalltalk que apunta al original global:

"Dotted expression syntax sugar for MyEnvironment at: #Smalltalk"

[MyEnvironment.Smalltalk == Smalltalk] assert.

Podemos pasar a tener un nuevo entorno actual:

env setCurrent.

"Current environment check"

[Environment current == env] assert.
[Environment current == Smalltalk.MyEnvironment] assert.

Y ahora, la característica principal de lo que quería implementar, de ahora en más, las definiciones de clases (sin cambiar el código de su definición) quedan registradas en el entorno actual:

"Define a class at current env environment, no change to syntax"

Object subclass:#MyClass
    instanceVariableNames:''
    classVariableNames:''
    poolDictionaries:''
    category:''
.

[(env at: #MyClass) isNil not] assert.
[(Smalltalk at: #MyClass) isNil] assert.

Ortogonal a esto de environments, implementé además módulos (algo apareció en el post anterior): una forma de buscar y leer archivos file out, y ejecutarlos dentro de un nuevo entorno. Esto es similar al import de Python, y algo menos parecido, al require de Node.js/CommonJS. Bueno, pero eso es tema para otro post 😉

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

AjTalk en C# (2): Un Simple Servidor Web

Monday, December 17th, 2012

Anterior Post 
Siguiente Post 

Estoy trabajando completando mi máquina virtual Smalltalk, escrita en C#, el AjTalk, el repositorio en https://github.com/ajlopez/AjTalk . Hace unas semanas, escribí un ejemplo de simple servidor web, basado en mi trabajo previo en PythonSharp (1) Un servidor web mínimo. El código de este nuevo servidor en:

https://github.com/ajlopez/AjTalk/blob/master/Src/AjTalk.Console/Programs/WebServer.st

Object subclass: #WebServer
	instanceVariableNames: 'root listener bytes'
	classVariableNames: ''
	poolDictionaries: ''
	category: ''
!

!WebServer class methods!

new
	^self basicNew initialize
! !

!WebServer methods!

initialize
	bytes := @System.Array !!CreateInstance: @System.Byte with: 1024 * 16.
	listener := @System.Net.HttpListener !!new.
	listener !!Prefixes !!Add: 'http://*:8000/'.
	root := 'c:/apache-tomcat-6.0.18/webapps/docs'.
	@System.Console !!WriteLine: 'initialize'
!

process: context
	| filename input nbytes |
	filename := context !!Request !!Url !!AbsolutePath.
	
	@System.Console !!WriteLine: filename.
	
	(filename = '' or: [filename = '/']) ifTrue: [filename := 'index.html'].
	
	(filename !!StartsWith: '/') ifTrue: [filename := filename !!Substring: 1].
	@System.Console !!WriteLine: filename.
	
	filename := @System.IO.Path !!Combine: root with: filename.

	@System.Console !!WriteLine: filename.	
	
	(@System.IO.File !!Exists: filename) 
	ifFalse: [ context !!Response !!Abort. ]
	ifTrue: [		
		input := @System.IO.FileStream !!new: filename with: @System.IO.FileMode !!Open.
		[[nbytes := input !!Read: bytes with: 0 with: bytes !!Length] value > 0] whileTrue: [
			context !!Response !!OutputStream !!Write: bytes with: 0 with: nbytes.
		].
		
		input !!Close.
		
		context !!Response !!OutputStream !!Close
	]
!

start
	listener !!Start.
	@System.Console !!WriteLine: 'start'.
	[true] whileTrue: [
		| context |
		@System.Console !!WriteLine: 'get context'.
		context := listener !!GetContext.
		@System.Console !!WriteLine: 'new request'.
		self process: context.
	].
	@System.Console !!WriteLine: 'end start'
! !

WebServer new start
!

Como el anterior, es una prueba de concepto, “quick and dirty”, para mostrar que puedo reutilizar las clases de .NET. Pueden lanzarlo desde el programa de consola de AjTalk (el resultado de compilar el proyecto AjTalk.Console):

ajtalk lib\Library.st Programs\WebServer.st

El resultado en http://localhost:8000 (jeje, reusando unas páginas estáticas que tengo en mi disco local):

Luego escribí un ejemplo más claro y modular en

https://github.com/ajlopez/AjTalk/blob/master/Src/AjTalk.Console/Programs/WebSiteTomcat.st

Module import: #Web.

!

| server |

server := Web.Server new
	root: 'c:/apache-tomcat-6.0.18/webapps/docs';
	addPrefix: 'http://*:8000/';
	start
!

Pero ahí estoy usando Module import:, algo que implementé basado en lo que hice de PythonSharp import para cargar programas. Pero esa lógica ya es tema para otro post.

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

AjTalk en C# (1): Una imagen mínima, con Hello, World

Friday, December 14th, 2012

Siguiente Post

Si leen este blog (y tienen la paciencia de seguirme en Twitter ;-), ya saben que, luego de PyCon 2012 Argentina, he estado ocupado trabajando en mi máquina virtual Smalltalk AjTalk, escrita en C#:

https://github.com/ajlopez/AjTalk

He aquí un pequeño Hello, World:

nil subclass:#Object
	instanceVariableNames:''
	classVariableNames:''
	poolDictionaries:''
	category:'Kernel-Objects'
!

Object subclass:#Program
	instanceVariableNames:''
	classVariableNames:''
	poolDictionaries:''
	category:'Kernel-Objects'
!

!Program class methods!

main @System.Console writeLine: 'Hello, world'! !

En el repo:

https://github.com/ajlopez/AjTalk/blob/master/Src/AjTalk.Console/Programs/HelloWorld.st

Podría ser menor, pero necesito el Program main como punto de entrada de una imagen grabada en disco. El programa que genera la imagen es

ajtalk Programas/HelloWorld.st –s hello.im

y se lanza la imagen con

ajtalk hello.im

De esta forma, AjTalk busca una variable global Program con un método main, y si existe, es invocado luego de la carga.

La notación del nombre con @ para @System.Console es la forma que tiene AjTalk de referirse a tipos nativos de .NET.

Noten que no cargo toda la librería de clases, solamente las que necesito para ejecutar este Hello, world. AjTalk puede manejar varias máquinas en memoria, cada una de las cuales tiene sus propias clases y métodos. Aún más: le he agregado que una máquina virtual pueda operar sobre otra, y hasta “prestarle” sus métodos. De esta manera, puedo tener una máquina A con todas las clases de desarrollo, y manejar desde ahí el contenido de la máquina B. Puedo entonces producir imágenes mínimas. En vez de tener una sola y gran imagen en memoria, y hacer toda clase de contorsiones para reducirla, mis máquinas YA NACEN livianas por diseño. Esto es un ejemplo de “pensar fuera de la caja”: por décadas, los desarrolladores Smalltalk pensaron siempre en tener una sola imagen, y se metieron en el problema de COMO hacerla decrecer. Mi aproximación al problema es distinta: cada máquina va creciendo desde lo mínimo, y si es necesario usar algo (algún método compile: por ejemplo), lo provee otra máquina, sin que tenga que crecer la primera.

Tengo que escribir más sobre lo que le agregué a esta versión. Por ejemplo: objetos remotos (revisitado), métodos por objeto, procesos, semáforos, múltiples threads, acceso a tipos nativos, grabar/leer imágenes, un AST interno, visitors para recorrer ese árbol, generación de código para JavaScript, módulos (a la import de Python o el require de Node.js), ambientes (como espacios de nombre, para evitar la colisión de nombres), y bastante más (como tener un Process que pueda ser suspendido y reanudado en cualquier momento, quizás llegue a call con continuations).

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

Trabajando de nuevo en on AjTalk: Smalltalk Virtual Machine, en C#

Friday, November 30th, 2012

Luego de trabajar en ejemplos distribuidos con Node.js (ver Genetic Algorithms), y en mi intérprete Python en .NET (Post, GitHub repo), volví a trabajar en AjTalk, mi implementación de una VM Smalltalk. Tengo tres proyectos (versión C#, versión Java, versión JavaScript), pero en estos días estroy trabajando en la versión C#.

El fin de semana pasado, agregué un simple/ingenuo pero funcional grabado/lecturan de imágenes, y tengo un nuevo compilador de bytecodes: en vez de “parsear” el código y directamente generar “bytecodes”, ahora hay una implementación alternativa que construye un árbol AST, en memoria, y usando el patrón Visitorr, genera los “bytecodes” correspondientes. El año pasado había implementado el AST para con un Visitor ir recorriendo los nodos e ir generando código JavaScript, que se levanta con la versión AjTalk en JavaScript. El patrón Visitor podría usarse para generar distintas salidas, usando el mismo AST. Por ejemplo, tengo pensado como “prueba ácida”, armar un Visitor que genere Python (alternativas: que genere Ruby o C#, en este último caso exploraría el usar objetos dynamic).

Desde hace tiempo, puedo crear más de una Machine: una imagen viva en memoria, cada una con su propio Object, Class, ClassDescriptor, etc. En vez de ser un Singleton, puedo crear y levantar desde imágenes más de una Machine. El código principal en:

https://github.com/ajlopez/AjTalk/blob/master/Src/AjTalk/Machine.cs

Pude entonces generar una imagen mínima de un “Hello world” con menos de 300 bytes (! ;-), ver el código en:

https://github.com/ajlopez/AjTalk/blob/master/Src/AjTalk.Console/Programs/HelloWorld.st

También estube entrenando a los dos parsers para lean y ejecuten código de Pharo:

https://github.com/ajlopez/AjTalk/blob/master/Src/AjTalk.Tests/CodeFiles/PharoCoreKernelObjects.st
https://github.com/ajlopez/AjTalk/blob/master/Src/AjTalk.Tests/CodeFiles/PharoKernelNumbers.st
https://github.com/ajlopez/AjTalk/blob/master/Src/AjTalk.Tests/CodeFiles/PharoKernelClasses.st

Y todo escrito usando TDD.

Ahora que tengo varias máquinas en memoria, quiero implementar esta idea:

– Cargar/Crear una Machine A (con sus clases, métodos, objetos) teniendo una librería completa de clases
– Cargar/Crear una Machine B, teniendo solamente algunas clases y objetos
– Hacer que la Machine A sea el “host” de la Machine B. Es decir, que se ocupe de darle lo que no tiene, ver el próximo punto.
– Reimplementar el proceso del mensaje #doesNotUnderstand en la Machine B para que, si el método correspondiente no es encontrado en esa máquina, la búsqueda del mismo continúe en la máquina “host”, la Machine A. De esta manera, podría usar todo el poder la Machine A, para operar sobre una Machine B más liviana, manteniendo la “liviandad” de ésta. La Machine A podría tener todas las herramientas de desarrollo, clases, objetos, métodos, mientras que la Machine B sigue teniendo un tamaño mínimo. Ideas similares están siendo exploradas por @morplenauta (“committer” de Squeak, ver la lista en español.

(Actualización: hoy a la mañana, conseguí implentar lo de arriba, pero será tema de otro post).

Otro proyecto: tener implementado un servidor web mínimo, que sirva archivo estáticos, aprovechando clases nativas de .NET, por ejemplo, lo de System.NET.

Nos leemos!

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

Implementando Lenguajes de Programación en Javascript, JsConf Argentina

Monday, May 21st, 2012

Ayer, 20 de Mayo, tuve el gran gusto de presentar un tema que me gusta mucho, la implementación de lenguajes de programación, y en este caso, usando Javascript como lenguaje destino. Fue en la JSConf Argentina 2012:

http://jsconf.com.ar/

(Ya había escrito un post anunciando la conferencia) El día fue excelente, llena de interesantes charlas, muy bien organizada por @rauchg y su equipo (creo de @vulsai), tomé muchas notas, espero escribir uno o dos posts sobre el tema, en cuanto me recupere 😉 Mientras, pueden leer el post de @aijoona

http://blog.aijoona.com/2012/05/21/jsconf-ar-2012-mi-resumen/

Como ejemplo de charla, vean la de WebGL para javascripters de @gerbille:

http://www.slideshare.net/gerbille/webgl-para-javascripters

Este post contiene los enlaces y las implementaciones que visité y preparé para la charla, que tuvo poco de gráfico, y mucho, mucho de código. Debería comenzar a usar los lenguajes que presenté, para manejar temas gráficos en el cliente, por ejemplo WebGL, SVG, tal vez usar d3.js.

Mi presentación en mi Skydrive (nota: tengo que escribir la próxima presentación mía, supongo que será en el Ruby Meetup, en markdown y publicarla en HTML).

Lista de lenguajes que compilan a Javascript
https://github.com/jashkenas/coffee-script/wiki/List-of-languages-that-compile-to-JS

The JavaScript World Domination Plan at 16 Years
http://www.infoq.com/presentations/The-JavaScript-World-Domination-Plan-at-16-Years

Lisp as the Maxwell’s equations of software
http://www.michaelnielsen.org/ddi/lisp-as-the-maxwells-equations-of-software/

A Conversation with Alan Kay
http://queue.acm.org/detail.cfm?id=1039523

The Magnificent Seven
by Michael Fogus
http://fogus.me/static/preso/magnificent7/#slide1

McCarthy’s Lisp in Python with macros
https://github.com/fogus/lithp

The roots of Lisp
http://www.paulgraham.com/rootsoflisp.html

Presenté AjLisp en Javascript
https://github.com/ajlopez/AjLispJs

Comenté y mostré demo de AjLogo en Javascript
https://github.com/ajlopez/AjLogoJs
Demo http://ajlopez.github.com/AjLogoJs/demo.html

Otras implementaciones de Logo en Javascript
http://www.calormen.com/Logo/
http://logo.twentygototen.org/

Recomendé ver a NetLogo http://ccl.northwestern.edu/netlogo/ (en Java) para ver hasta dónde ha llegado el tema.

Hice correr el REPL y el compilador de Clojurescript
https://github.com/clojure/clojurescript

Presenté a la AjTalk VM en C#, y desde el año pasado compila Smalltalk a Javascript
https://github.com/ajlopez/AjTalk

Este año agregué AjTalk en Javascript, con VM en bytecodes, y ejecutor de métodos compilados con AjTalk
https://github.com/ajlopez/AjTalkJs
Demo http://ajlopez.github.com/AjTalkJs/demo.html

Mostré una simple demo de clases Smalltalk compiladas a Javascript, que manejan google, y google.earth.

Levanté Amber y comenté cómo en su definición de métodos ponen Javascript nativo
http://amber-lang.net/

Visité la página de Smalltalk S8, U8
http://u8.smalltalking.net/
http://u8.smalltalking.net/browsecontributions.aspx

No pudimos ver las demos, justo en ese momento estuve sin conexión. Les comento algunos enlaces. Veamos dos:

Hay una Smalltalk S8 Console (con una compilación de V8 preparada para levantar código st)
http://u8.smalltalking.net/profile/smalltalking/125/index.html

Ver sus demos de Google Earth
http://u8.smalltalking.net/contribution.aspx?contributionId=222
(exploren las clases, creo que eran Google, GoogleEarth, GoogleEarthObject, GEDemo, etc…)

Mis posts sobre AjTalk, AjLisp, AjLogo implementations
http://ajlopez.wordpress.com/category/ajtalk/
http://ajlopez.wordpress.com/category/ajlisp/
http://ajlopez.wordpress.com/category/ajlogo/

http://msmvps.com/blogs/lopez/archive/tags/AjLisp/default.aspx
http://msmvps.com/blogs/lopez/archive/tags/AjLogo/default.aspx
http://msmvps.com/blogs/lopez/archive/tags/AjTalk/default.aspx

Mis posts sobre Javascript
http://msmvps.com/blogs/lopez/archive/tags/Javascript/default.aspx

Les agrego algunos enlaces sobre ClojureScript, que no mencioné

Introducing ClojureScript
http://clojure.com/blog/2011/07/22/introducing-clojurescript.html
de @stuartsierra

ClojureScript Rationale
https://github.com/clojure/clojurescript/blob/master/devnotes/cljs.org
de @stuarthalloway

Compiling Clojure to Javascript pt. 1 of n
http://blog.fogus.me/2011/07/21/compiling-clojure-to-javascript-pt1/
de @fogus

Ferret: An Experimental Clojure Compiler
http://nakkaya.com/2011/06/29/ferret-an-experimental-clojure-compiler/

Los enlaces que me interesaron, leí, estudié para esta charla, o los tengo pendientes:

http://delicious.com/ajlopez/clojurescript
http://delicious.com/ajlopez/javascript+parser
http://delicious.com/ajlopez/javascript+compiler
http://delicious.com/ajlopez/javascript+smalltalk

Nos leemos!

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

AjTalk en Javascript (1) Primeras Implementaciones desde 0

Friday, March 23rd, 2012

Hace unos días, migré mi proyecto AjTalk de Google Code a mi cuenta en  GitHub:

https://github.com/ajlopez/AjTalk

Vengo trabajando en él, en mis tiempos libros, debe ser desde el 2008. Está escrito en C# e implementa una máquina virtual Smalltalk, basada en bytecodes. Codificado en C# plano, debería probarlo en otras plataformas, pero seguro que Mono lo soporta. En el 2011 le agregué la capacidad de compilar código Smaltalk de fileouts a Javascript, que se pueden usar tanto en el browser como en Node.js. El domingo pasado me decidí a crear otro proyecto:

https://github.com/ajlopez/AjTalkJs

como code kata del día. Tiene otro “approach”: implementar una máquina virtual AjTalk, desde 0, directamente en Javascript. La idea es compilar código Smalltalk a métodos y bloques con bytecodes, y tener el intérprete de esos método. Tanto la base del Lexer, Compiler, Block, Execution Block están funcionando. El código de la implementación principal está en:

https://github.com/ajlopez/AjTalkJs/blob/master/lib/ajtalk.js

En esa implementación, estoy usando un método sendMessage que usa un “custom lookup” para ubicar el método que atiende un mensaje, de acuerdo a su “selector”, su nombre. Un fragmento de lib/ajtalk.js:

BaseObject.prototype.sendMessage = function(selector, args)
{
    var method = this.lookup(selector);
    return method.apply(this, args);
};

function BaseClass(name, instvarnames, clsvarnames, supercls) {
    this.name = name;
    this.instvarnames = instvarnames;
    this.clsvarnames = clsvarnames;
    this.supercls = supercls;
    this.methods = {};
};

BaseClass.prototype.__proto__ = BaseObject.prototype;

BaseClass.prototype.defineMethod = function (selector, method) 
{
    this.methods[selector] = method;
};

BaseClass.prototype.getInstanceSize = function() {
    var result = this.instvarnames.length;
    if (this.supercls)
        result += this.supercls.getInstanceSize();
        
    return result;
};

BaseClass.prototype.lookupInstanceMethod = function (selector) 
{
    var result = this.methods[selector];
    if (result == null && this.supercls)
        return this.supercls.lookupInstanceMethod(selector);
    return result;
};

El lunes, se me ocurrió otra forma de hacerlo, que pensé que iba a tener dificultades: en vez de relegar la herencia a un “custom lookup”, podría aprovechar la cadena de prototipos para heredar métodos, e instancias por separado, para tener las variables de cada instancia. Escribí código en lib/ajtalknew.js:

function createClass(name, superklass, instvarnames, clsvarnames)
{
    var protoklass = new Function();
    
    if (superklass)
    {
        // Chain class prototypes
        protoklass.prototype.__proto__ = superklass.proto;
    }
    else
    {
        // First class methods
        protoklass.prototype.basicNew = function()
        {
            var obj = new this.func;
            obj.klass = this;
            return obj;
        }
        
        protoklass.prototype.defineSubclass = function(name, instvarnames, clsvarnames)
        {
            return createClass(name, this, instvarnames, clsvarnames);
        }
        
        protoklass.prototype.defineMethod = function(name, method)
        {
            var mthname = name.replace(/:/g, '_');
            if (typeof method == "function")
                this.func.prototype[mthname] = method;
            else
                this.func.prototype[mthname] = method.toFunction();
        }
        
        protoklass.prototype.defineClassMethod = function(name, method)
        {
            var mthname = name.replace(/:/g, '_');
            if (typeof method == "function")
                this.proto[mthname] = method;
            else
                this.proto[mthname] = method.toFunction();
        }

        // TODO Quick hack. It should inherits from Object prototype
        protoklass.prototype.sendMessage = function(selector, args)
        {
            return this[selector].apply(this, args);
        }
    }
    
    var klass = new protoklass;
    
    // Function with prototype of this klass instances
    klass.func = new Function();
    klass.proto = protoklass.prototype;
    klass.name = name;
    klass.super = superklass;
    klass.instvarnames = instvarnames;
    klass.clsvarnames = clsvarnames;
    
    klass.func.prototype.klass = klass;
    
    if (superklass) 
    {
        // Chaining instances prototypes
        klass.func.prototype.__proto__ = superklass.func.prototype;
    }
    else 
    {   
        // First instance methods
        klass.func.prototype.sendMessage = function(selector, args)
        {
            return this[selector].apply(this, args);
        }
    }
    
    Smalltalk[name] = klass;
    
    return klass;
}

createClass('Object');

Smalltalk.Object.defineClassMethod('compileMethod:', function(text)
    {
        var compiler = new Compiler();
        var method = compiler.compileMethod(text, this);
        this.defineMethod(method.name, method);
        return method;
    });

Smalltalk.Object.defineClassMethod('compileClassMethod:', function(text)
    {
        var compiler = new Compiler();
        var method = compiler.compileMethod(text, this);
        this.defineClassMethod(method.name, method);
        return method;
    });

    

Ok, es un poco “tricky” pero funciona!. Y ambos códigos fueron desarrollados con TDD, así que los refactors que hice fueron bien soportados y bienvenidos.

Esta vez, no usé QUnit para TDD en el browser. Usé línea de comando, con Node.js, y su “built-in” módulo assert (no tenía conexión a Internet cuando comencé a escribir, así que no me traje en NodeUnit). Es una experiencia interesante, porque fue la forma más simple de escribir tests: un largo programa con assert tras otro. Puedo en cualquier momento refactorizarlo, pero no ví que me complicara mucho en el desarrollo: avancé tan rápido como cuando escribo tests más organizados.

Tengo una función/”clase” javascript llamada Compilar que puede compilar código Smalltalk (un subconjunto de la gramática, por ahora) en bytecodes. Soporta mensajes unarios, binarios y de “keywords”. Sólo unos pocos bytecodes fueron necesarios para implementar la funcionalidad actual:

var ByteCodes = {
    GetValue: 0,
    GetArgument: 1,
    GetLocal: 2,
    GetInstanceVariable: 3,
    GetGlobalVariable: 4,
    GetSelf: 5,
    SetLocal: 10,
    SetInstanceVariable: 11,
    SetGlobalVariable: 12,
    Add: 20,
    Subtract: 21,
    Multiply: 22,
    Divide: 23,
    SendMessage: 40,
    Return: 50
};

Hay ejemplos index.html, indexnew.html para probar interactivamente ambas implementaciones.

Trabajo pendiente: implementar variables de clases, metaclases, como siempre usando TDD. Mejorar los ejemplos de browser, y escribir posts sobre todo eso.

Nos leemos!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez