BookinglyTech News
Software

AlexScript: un lenguaje de programacion con palabras clave en polaco

Un desarrollador que vive de Ruby lleva 18 meses construyendo un interprete con async/await, depurador y framework web. Las lecciones sobre las tripas de Ruby son lo aprovechable.

3 min de lecturaDev.to0 vistas

Un desarrollador que escribe Ruby para ganarse la vida se puso un fin de semana a construir un interprete para entender que pasa entre teclear x = 5 y que la maquina haga algo con eso. Dieciocho meses despues aquello es AlexScript: un lenguaje interpretado y orientado a objetos, con biblioteca estandar, async/await, depurador y un framework web escrito en el propio lenguaje. Todas las palabras clave estan en polaco, su lengua materna.

klasa es class, funkcja es function, niech es let, zwroc es return. Con los diacriticos hay una concesion: lo correcto en polaco seria zwróć, pero teclear AltGr en cada palabra de un bucle cansa, asi que casi todas las palabras clave tienen dos formas. Una en ASCII, la que se teclea, y un alias acentuado para quien quiera el codigo bien escrito: jesli/jeśli, dopoki/dopóki, falsz/fałsz. El lexer acepta ambas.

Cuatro cosas que el interprete le enseno sobre Ruby

El propio autor lo dice: el polaco llama la atencion, pero lo interesante llego de implementar un interprete en Ruby. Mas que en anos de aplicaciones con Rails.

Lo primero fue el control de flujo. La forma obvia de implementar return en un interprete que recorre el arbol es lanzar una excepcion y capturarla en el punto de llamada. Funciona a la primera, y por eso todo el mundo empieza asi. Tambien es un problema de rendimiento, porque Ruby construye un objeto excepcion y captura un backtrace cada vez. En codigo recursivo, donde se retorna continuamente, eso se come todo lo demas. La solucion es throw/catch, que casi nadie usa: no hay objeto, ni backtrace, ni maquinaria de desenrollado de pila. El autor avisa de que solo vale para saltos no locales que uno controla, no sustituye a raise en general.

Lo segundo, el indexado de cadenas. El lexer recorria el fuente caracter a caracter con source[position]. Correcto para ASCII y desastroso para lo demas: las cadenas en Ruby son UTF-8, y encontrar el caracter n-esimo obliga a recorrer la cadena desde el principio contando codepoints. Con un fichero lleno de diacriticos, la tokenizacion se volvio cuadratica sin querer. Pasar a getbyte y byteslice lo arregla: acceso O(1) y sin asignaciones.

Lo tercero toca el despacho de metodos. La biblioteca estandar esta en Ruby y el codigo de usuario en AlexScript. El enfoque ingenuo son dos registros separados, uno para metodos nativos y otro para los definidos por el usuario. Mal negocio: cada capa por encima del despacho necesita una rama de "pero los builtins son especiales", en la busqueda de metodos, en super, en la reflexion y en el depurador. El autor fusiono ambas tablas con una etiqueta por metodo y reescribio dos veces antes de conseguirlo; el diff final borro mas codigo del que anadio. Las clases nativas pasan a ser de primera clase, se pueden heredar y la reflexion no las distingue. No es invento suyo: MRI hace exactamente eso con los metodos C y los de Ruby compartiendo tabla.

Lo cuarto son las fibers. Muchos desarrolladores de Ruby saben que existen y no las han usado nunca. Aqui sostienen todo un runtime asincrono: await aparca la fiber con Fiber.yield y devuelve el control a un reactor propio con cola de listos, lista de temporizadores ordenada y un bucle IO.select. El reactor se instala como Fiber.set_scheduler, de modo que las operaciones de la biblioteca estandar dentro de una fiber pasan por esa interfaz.

Hay una quinta leccion, sobre WeakRef en entornos de clausura, que el texto original deja a medias: lo que ocurre en la practica es un Invalid Reference: probably recycled en tiempo de ejecucion.

El proyecto es open source, tiene documentacion y un playground en el navegador. Para quien no vaya a escribir un lenguaje en su vida, el valor esta en los detalles: cambiar raise por throw/catch en un salto controlado, revisar si un escaneo de texto caracter a caracter es cuadratico, o entender como CRuby despacha metodos. Son cosas que se pueden aplicar manana en codigo de produccion sin tocar un interprete.