Archivo de la etiqueta: dsl

Can has lolcode plz ?

Cuando surgió en Internet la moda de los Lolcat (WTF), no tardaron en surgir las primeras mentes brillantes en crear un lengaje de programación para hacer honor al fenómeno de la red de redes. LOLCODE es un lenguaje de programación esotérico creado en 2007 por Adam Lindsay, investigador del Departamento de Computación de la Universidad de Lancaster.

CAN SEE AN XAMPL ? AWSUM THX

La sintaxis del lenguaje se basa en abreviaturas de palabras utilizadas en las imagenes de los Lolcat.
Un hola mundo en LOLCODE sería algo de este estilo:

HAI
CAN HAS STDIO?
VISIBLE "HAI WORLD!"
KTHXBYE

PLZ, WAT IS A DSL ?

Un DSL, es un Domain Specific Language, y en este artículo vamos a mostrar como crear uno usando los mecanismos que nos ofrece Scala para embeber DSLs utilizando su libertad de sintaxis.

VISIBLE DSL XAMPL

Por tanto, si queremos crear una instrucción que represente el hecho de importar una librería, en LOLCODE sería

CAN HAS STDIO?

Usando notación infija podemos generar la primera parte de la instrucción usando un objecto CAN con un método HAS:

object CAN {
	def HAS(x:X):Y = ???
}

Como podeis comprobar, el método HAS tiene aún por definir un parámetro y el tipo devuelto. Y dado que de alguna forma hay que poder especificar la librería que se desea importar, el parámetro misterioso X (que intringulis) pasa a ser la librería a importar.

trait Library { val name: String }
object CAN { def HAS(library: Library): Y = ??? }

Y la librería estándar que queremos importar podría ser perfectamente un ‘case object’:

case object STDIO extends Library { val name = "stdio" }

Ahora,¿qué hay acerca del tipo devuelto? Dado que aún hay que poder añadir el signo de interrogación al final, es fácil pensar que el tipo misterioso ‘Y’ debe ser algo que tenga un método ‘?’ y que devuelva una instrucción. Para ello empleamos una clase auxiliar o helper:

class Can(l: Library) {
	def ?: Statement = ???
}

DIZ DOESNT RUN

Como ya hemos dicho antes, consideramos que cada instrucción es el elemento atómico de un programa. Además de instrucciones, un programa puede tener una o varias librería importadas, así como variables de entorno, un flag para indicar si la sintaxis es correcta y otro para indicar si se ha elevado una excepción.

Podríamos definir un programa en Scala de la siguiente forma:

case class Program (
  val env: Map[String, Any],
  val statements: Seq[Statement[_]],
  val imports: Set[Library] = Set(), 
  val isSyntaxOk: Boolean = false,
  val exceptionThrown: Boolean = false){
}

Donde una instrucción o Statement no es más que un transformador de estado y ejecutar dicha instrucción equivale a devolver un programa modificado además de un cierto output:

trait Statement[Output]{
  def execute(implicit context: Program):(Program,Output)
}

No obstante se ve más fácil con un ejemplo: Si deseamos implementar una instrucción que importa una librería al programa lo haríamos de la siguiente forma:

  case class ImportStatement(library: Library) extends Statement[String]{
    def execute(implicit context: Program):(Program,String) = (
    	context.copy(imports=context.imports + library),
    	s"LIBRARY $library WOZ SUCCSFLLY IMPORTED!")
  }

IT STILL DOESNT RUN 😡

…Y para ejecutar el código que hemos creado necesitamos un intérprete del lenguaje. Uno facilito de fabricación casera podría ser un actor Akka, que recibiera un programa y se mandara a sí mismo el programa modificado sin la última instrucción ejecutada.
Algo del estilo:

class Interpreter extends Actor {
  def receive = {
    case program: Program => 
      if (!program.isSyntaxOk) 
      	sender ! WrongSyntax(program)
      else program.statements.toList match {
      	case (nextStatement::restOfStatements) => 
      		val (updatedProgram,output) = nextStatement.execute(
      			program.copy(statements=restOfStatements))
      		println(output)
      		self ! updatedProgram
      	case _ => 
      		println("Finished!")
      }
  }
}

I WNT MOR PLZ …

Puedes ver el resto de implementación (para un conjunto muy reducido de instrucciones) en el siguiente enlace de Github:

https://github.com/JSantosP/lolcode-dsl

Y hasta aquí mi aportación.

Hasta la próxima 🙂

Deja un comentario

Archivado bajo Tutoriales