Lenguaje de Programación ABCode - Version 1 (Preview)

Mitigando la torre de Babel del Software en buena medida
Descargar…

Solo descarga y descomprime segun tu sistema y ejecuta algo como…

./abcodec -s abc/hello.abc

abcodec es el compilador y abc/hello.abc representa tu codigo fuente con ABCode.

Antes de hablar de una nueva especificación y lenguaje de programación ABCode, me permiteré contarte una pequeña experiencia…

Notando ciertas habilidades para interactuar con diferentes lenguajes de programación (como si fuera un políglota informático) se me ocurrió buscar una forma de lograr un lenguaje abstracto para el componente que se encarga de lo que sucede en el servidor (backend), acompañando a un gestor de base de datos (OnMind-XDB) que también hice junto con mi propia plataforma OnMind. De modo que decidí crear una especificación de lenguaje que convirtiera el código a otro lenguaje de interés. Finalmente, así nació el lenguaje de programación ABCode.

Efectivamente encontré ideas similares pero requería algo distinto y como he enfatizado: “abstracto”. Luego se me ocurrió combinar YAML (un lenguaje de marcado para datos) y algo de Python (con una sintaxis restringida), dónde cada línea comienza con un atributo (distinguido por terminar con dos puntos :) que guarda sangría cada dos espacios (según YAML), el resto de la línea podría ser código (como Javascript). Validé la idea de este lenguaje de programación con un gran amigo y colega, quién le pareció interesante y entusiasta.

Como dato curioso, antes de pensar en YAML, la idea se gestó originalmente usando como editor de código una hoja de cálculo y su disposición por columnas (como una sangría), aplicando color a las celdas con sentencias.

¿Qué es ABCode?

Un lenguaje para muchos entornos y una especificación como puente

Es una especificación y lenguaje de programación interpretado (creado por Cesar A. Arcila) que combina el estilo de un lenguaje de marcado como YAML con algo de Python y Javascript, bajo la premisa de ser abstracto y con un enfoque inicial en código para servidor, para lograr generar (transpilar) principalmente código Javascript, quizás algún otro lenguaje experimental como un dialecto, variante o sabor (ej. Python).

Puede pensarse como un Typescript con un estilo peculiar. Transpila a Javascript con un “look” que mezcla aspectos de Python y YAML, orientado a la lógica de negocio (casos de uso o lógica de “core”).

La estrategia inicial de ABCode está orientada dónde opera Javascript y WebAssembly (luego Python), pensando principalmente en el Backend, es decir, en la portabilidad o la legibilidad de la lógica de negocio (casos de uso). Puede verse también como el sustituto para la capa de código que promovían las bases de datos relaciones con procedimientos almacenados, por ejemplo, con AWS Lambda.

En otras palabras y en principio, puedes asociar a ABCode con…

Lógica más interna (de dominio o “core”)
cuyas funciones componen un Backend
de modo embebido y portable (también modo script)
siendo invocado por otro lenguaje o entorno, o por él mismo

Cada línea de código inicia con una palabra reservada o sentencia definida que correspondería a un atributo en YAML con sangría, el resto de la línea podría ser código cercano a Python y Javascript.

ABCode supone una capa adicional para interactuar con distintos lenguajes de programación buscando un sentido unificador o conciliador, quizás a futuro con dialectos que comparten la misma raíz, por ejemplo, pensar en abcode:py o abcode:go.

INDICACION: En el mundo del desarrollo de aplicaciones (web) que usan Internet se designa la palabra Backend para aquello que está destrás de la red (en un servidor), y con la palabra Frontend nos referimos al aspecto visual que ve el usuario, este puede apreciarse en el navegador o en un dispositivo móvil (ejemplo: desarrollo móvil nativo). ABCode comienza con énfasis en el servidor y propone un camino conciliador para el navegador (dominado por el lenguaje Javascript).

Consideraciones del lenguaje

Traducción multi-lenguaje, multi-entorno, multi-plataforma y multi-paradigma.

¿Para qué otro lenguaje?

Pensando en la portabilidad del código de la lógica de negocio

Creo que se ha indicado el motivo entre las líneas anteriores, pero podemos enfatizar que se busca mitigar algo… debido a: “la torre de Babel del Software”.

También se comprende que la idea se ha originado al requerir un nivel de abstracción o capa para una tecnología que también usaba componentes con orientación genérica (la base de datos y plataforma de OnMind), además de apoyar el Método OnMind. Seguramente otros pueden identificar una necesidad similar así como el interés de algo multiplataforma, o quizás observe la fatiga de la batalla comercial y comunitaria sobre el mejor lenguaje o tecnología.

Unificar, embeber, portar código, integrar sistemas, conservar cierta simplicidad, aportar en agilismo, persistir con el tiempo la lógica de negocio o casos de uso, reducir la complejidad dando apertura a programadores sin que sean expertos, romper ciertos paradigmas actuales y doctrinas informáticas retornando a los fundamentos, generar el impacto correspondiente donde tenga acogida, son los motivos de que se haya concebido ABCode

En lo personal, tendría que contar otra parte de la historia. La plataforma de la que soy autor, fué construida con Javacript y Kotlin. Luego identifiqué que si llegara a involucrar Machine Learning, incluso DevOps, sería genial aprender Python. Así que pensé que podía ser útil aprender otros lenguajes y mejorar mis habilitades en ellos aplicando ABCode, y lo que estaba codificado en OnMind podía quedar en Javascript y Kotlin respectivamente, siendo la parte de la lógica de negocio introducida con ABCode (hasta llegar a sustituir ese aspecto en el Backend). De este modo, en OnMind se usarían multiples lenguajes y ABCode para complementar los proyectos y entornos objetivo, orientándose como tecnología multiplaforma.

¿Cómo se pronuncia?

Las dos primeras letras (“ab”) se deletrean con su pronunciación en inglés, cuando llegas a la “c” dices la palabra “code” (en inglés). Y por cierto, se promueve escribirlo con las tres primeras letras en mayúsculas.

Ejemplo esencial

echo: "Hello World!"

Este programa en ABCode imprime un saludo en la pantalla usando echo:. Ten presente que, en principio, cada instrucción de lógica en ABCode correspondería a una línea de código.

Una variación más completa sería por ejemplo:

fun: hello()
  echo: "Hello World!"

run: hello()

Nótese que en este caso echo: se deriva o pertenece a fun: (que veremos avanzando) y por esto se dejan dos espacios como sangría.

Lenguaje de programación ABCode vs lenguaje natural

En un sentido general y espontáneo, un lenguaje natural puede verse como un acuerdo que llega a tener acogida para comunicar, expresar o indicar algo. ABCode suele usar palabras en inglés de 3 o 4 letras. Conocer su significado puede darnos una comprensión de éste lenguaje, es decir, aquello que se le estaría indicando a un computador que haga. Veamos que significan cada una de las palabras reservadas para ABCode.

ABCode Significado
root: raíz
fun: algo divertido
set: conjunto (sustantivo) o establecer (verbo)
var: abreviatura de variable (variar)
let: fijar o determinar
run: correr
send: enviar
if: si… (expresa una condición)
when: cuando… (expresa otra condición o al no cumplir)
else: sino… (de lo contrario)
for: para… (por cada uno)
sub: subrutina (derivación)
try: intentar
fail: fallo
use: usar
type: clase
echo: eco
goal: objetivo

Tips esenciales del lenguaje

Para quien tenga habilidades, experticia en programación y/o requiera agilidad en conceptos técnicos, pueden resumirse los siguientes tips esenciales del lenguaje:

  1. Tipos de datos básicos: int, float, boolean, string, array, object, any. Las variables se definen iniciando con el atributo var:, el nombre de la variable, dos puntos de nuevo (:), el tipo de datos y puede asignarse un valor. Puede omitirse la indicación del tipo de dato cuando se trata de uno básico o genérico.
  2. Las funciones se definen o comienzan con el atributo fun: al nombre de la función, luego los parámetros van entre paréntesis (...), continuando con el nombre del parámetro, el caracter : que separa el tipo de datos posteriormente (y separando los parámetros con coma ,). El tipo de datos a retornar va también después de :. Además, se usa send: para retornar un valor. La función principal de un programa se denomina main (fun: main()).
  3. Para el bloque de la función o el flujo de control se usa la sangría de YAML y cada línea de un bloque corresponde a una sentencia con un atributo, es decir, las líneas inician con un atributo YAML que corresponda a la especificación del lenguaje. No aplican los corchetes de otros lenguajes ni el punto y coma, por lo que la indentación del código toma mayor importancia para legibilidad e incidencia del mismo.
  4. El flujo de control varía respecto a lenguajes como C, Java, Javascript, Kotlin, pero encuentras una forma equivalente para el uso de if y for, incluso para el manejo de excepciones (try), cuyas palabras clave deben llevar a continuación el caracter :.
  5. El constructor de una clase se expresa con el atributo fun: y el valor new (fun: new()) y la clase se define con el atributo type:.
  6. Las estructuras de datos se definen con el atributo set: seguido por el nombre y aplicando YAML en los atributos asociados. No obstante, al usar YAML y Python, el uso de JSON es prácticamente nativo, comprendiendo que no es un tipo o estructura natural del lenguaje.

La declaración de variables y funciones presenta una variación respecto a Python. ABCode maneja tipos de datos genéricos para guardar compatibilidad con otros lenguajes, por lo que es un lenguaje tipado. Sin embargo, puede omitirse la indicación del tipo de dato en la declaración de la variable cuando se inicializa un valor con un tipo básico o genérico.

Tipos de datos básicos

Dado que la programación se asocia con información, los datos se tipifican para identifcar si se trata de un texto, número u otro tipo. Se pueden citar los siguientes tipos de datos.

Tipo Descripción
string Cadena de caracteres o texto
int Números enteros
float Número flotante (con decimales)
boolean Booleano (True/False)
array Arreglo o vector, se representa como corchetes []
object Objeto, se representa como llaves {}
any Para casos en donde puede aplicar varios tipos (dinámico)
void Vacío (para métodos o funciones)

Varios de estos tipos de datos se inspiran en Typescript, salvo que se usa int y float para números y no existe number.

Variables

Recordando que la variable es como un dato a tener en cuenta (en memoria), se puede expresar una variable asignándo un valor con el operador igual (=). Cada vez que se mencione o use posteriormente la variable, esta debe aparecer con el mismo nombre original (respetando mayúsculas y minúsculas). Sin embargo, la convención para declarar variables inicia la línea con var: o let: (este último para valores constantes o inmutables), el nombre de la variable, dos puntos de nuevo (:) el tipo de datos, luego puede asignarse un valor (con =). Puede omitirse la indicación del tipo de dato en la declaración de la variable cuando se trata de uno básico o genérico.

Ejemplo:

  var: variable = "Ana"
  var: i = 0
  let: list = [10, 20, 30]
  echo: variable

echo: es una sentencia que viene en el lenguaje para mostrar algo en pantalla (en este caso imprime el valor de la variable). En un lenguaje como Python se usaría print()

En programación de computadoras las variables tienen un tipo de dato que indica la naturaleza del contenido, por ejemplo, si una variable contiene un texto (string) o si es un número entero (int) o flotante (float), incluso si se trata de un valor verdadero o falso (boolean) o una lista (array). Veamos el ejemplo indicando el tipo de datos.

  var: variable:string = "Ana"
  var: i:int = 0
  let: list:array = [10, 20, 30]

Si prefieres el estilo de Python, puedes usar las funciones simples para establecer el tipo de datos con str(), int(), float(), bool(), list().

  var: variable = str()
  var: i = int()
  var: f = float()
  var: imagine = bool()
  let: list = list()

En lugar de esto, podría asignarse respectivamente "", 0, 0.0, False, []. No obstante, el tipo de datos es requerido por compatibilidad con ciertos lenguajes.

Funciones

Las funciones realizan algo o definen una serie de instrucciones que cumplen un propósito, es decir, se relacionan con lógica en bloques bien definidos según se organicen. Para el caso de ABCode se antepone fun: al nombre de la función, luego los parámetros van entre paréntesis (...), continuando con el nombre del parámetro, el caracter : que separa el tipo de datos posteriormente (y separando los parámetros con coma ,). El tipo de dato a retornar va también después de :. Veamos a continuación un ejemplo.

fun: myFunction()
  echo: "Hi there!"

run: myFunction()

Quién conoce Python puede observar que se omite la palabra reservada def siendo innecesaria al usar fun:. Además, en este caso no requiere retornar un tipo de datos (aunque podría usarse :void al final de la declaración de la función).
run: se usa para invocar operaciones, funciones o sentencias. En la mayoría de lenguajes no se antepone algo como run: para operaciones o sentencias, siendo éstas las líneas comunes, pero aquí se requiere un atributo para conservar el estilo YAML.

Veamos otro ejemplo.

fun: sayMyName(name:string):string
  send: name

echo: sayMyName("Andrey")

En este caso se usa send para devolver el valor contenido en la variable (que en otros lenguajes suele ser return).

Si estás comenzando con la programación de computadores, quizás no convenga distinguir cierto aspecto de las funciones. Pero si ya tienes algún conocimiento, es bueno aclarar que las fuciones en ABCode son de naturaleza pública. Para indicar que una función es privada, en el contexto de una clase dada, se debe anteponer el signo @ al nombre, por ejemplo: @sayMyName.

Operadores del lenguaje

Principalmente, los operadores son aquellos que nos permiten realizar operaciones, aunque también se encuentran aquellos que nos permiten evaluar algo (basados en tautología o tabla de la verdad). Con los operadores se pueden sumar dos expresiones o números, así como las demás operaciones matemáticas. Esto se asocia también al algebra esencial que se refiere a funciones y variables. Por otra parte, en los operadores que permiten evaluar algo, se puede comparar o determinar si dos valores son diferentes, o definir condiciones complejas (y, o, no).

Veamos a continuación los operadores del lenguaje.

Operador Descripción
= igual (asignación)
+ suma
- resta
* multiplicación
/ división
% módulo de una división
+= incremento
-= decremento
== comparación exacta (igual a)
!= comparación de diferencia (diferente de)
> mayor que
< menor que
>= mayor o igual que
<= menor o igual que
&& y (también: and)
`
! no, negación (también: not)
@ sustituto de self o this para uso de propiedades de clases en otros lenguajes, indica también si una función es privada en el contexto de una clase

Aunque ABCode acepta los operadores lógicos and, or y not de Python, promueve en su lugar &&, || y ! en favor de ABCode:js y varios lenguajes.
Debe distinguirse entre el atributo @: (usado como decorador) y el uso de @ en clases. Quizás se cuestione si es un operador o no, en este caso opera para referencia en clases (que es un tema avanzado).

Recordando tablas de verdad con operadores

Los operadores de inclusión and (también: &&) y de opción or (también: ||) tienen incidenca en la evaluación de una condición en un programa. Partimos de la siguiente tabla, dónde p es la primera variable y la segunda es q, además se usa True y False para indicar si es verdadero o falso (respectivamente).

p q p and q p or q
True True True True
True False False True
False True False True
False False False False

Si una variable o expresión se niega con not (también: !) entonces se invierte su valor: si es verdadera se interpreta como falsa y si es falsa se interpreta como verdadera.

Condicional if / when (else)

Las condiciones permiten determinar los puntos de validación en la lógica que se plantee. Por ejemplo, imagina que vas a comprar una bebida para alguien que te la encargó y llevas planteados unas posibles escenarios en caso de que no se encuentre la bebida originalmente solicitada.

Se usa if: para establecer un punto de validación con una condición y when: no, o simplemente else:, cuando no cumple algo. Veamos un ejemplo.

  let: i = 1
  if: i == 1
    echo: "coffee"
  when: no
    echo: "tea"

when: no o else: corresponden a lo que ocurriría cuando no se cumple una condición y debe dejarse siempre como última condición, queriendo indicar lo que sucede en caso contrario.

Se usa when: con una condición (que sería como else if en otros lenguajes) para evaluar otras condiciones determinadas. Veamos el siguiente ejemplo.

  let: i = 3
  if: i == 1
    echo: "coffee"
  when: i == 2
    echo: "tea"
  else:
    echo: "aha"

Nótese que se usa doble igual (==) como operador de comparación, distinguiéndose de la asignación que usa de modo natural un signo de igual (=). En ese orden de ideas, para evaluar valores diferentes (comparación negativa) se usaría el signo de admiración y un igual (!=).

Pueden existir escenarios en los que no se evalúe alternativa, es decir, una condición simple (if:). Por ejemplo:

  let: i = 2
  if: i == 1
    echo: "coffee"

El Ciclo For

Los ciclos se refieren a instrucciones que se repiten o en donde se da lugar a ciertas iteraciones. Ten presente que la línea del for: suele incluir in, veamos a continuación.

  var: names = ["Ana", "Alex", "Janeth"]
  for: x in names
    echo: x
    if: x == "Alex"
      run: break

Nótese que la variable names es una lista de valores de texto (también conocida con el nombre de arreglos) cuya convención usa corchetes [] separando cada valor por una coma. Cuando se usa break se interrumpe el ciclo, dado que está bajo una condición se imprimirían los nombres hasta que se de lugar a la condición (por tanto no se imprimiría Janeth).

Se puede usar la funcion range para recorrer un rango, incluso combinarla con len que obtiene el tamaño de un arreglo. Veamos un par de ejemplos:

  for: i in range(10)
    echo: i

  var: n = [10, 20, 30, 40] 
  for: i in range(len(n))
    echo: n[i]

En estos casos se termina el ciclo cuando se alcanza el tope (restando 1). range puede usarse también dos parámetros indicando el primero el inicio y el segundo el tope. Su tercera manera de llamarse es con un tercer parámetro que indicaría un incremento (en caso de ser distinto de 1).

Una tercera variación sería incluyendo una condición y evitando el uso de in, es decir, sin in se interpretaría como while en otros lenguajes. Veamos el ejemplo:

  var: i = 0
  for: i < 10
    run: i += 1
    echo: i

Nótese que for: recibe en este caso una condición y no lleva in.

Una variación adicional consistiría en entrar en un ciclo e interrumpirlo (usando: break) cuando cumpla una condición determminada. Veamos el ejemplo:

  var: i = 0
  for: True
    run: i += 1
    echo: i
    if: i < 10
      run: break

Quién ya tiene conocimiento en programación puede asociar esto con la sentencia do...while de otros lenguajes, siendo el modo de emularla.

Excepciones

Las excepciones se originan cuando se interrumpe la lógica esperada debido a un error en medio de la ejecución del programa de modo que podríamos gestionarlas, en otras palabras, son útiles para manejo de errores generalmente de caracter técnico.

  try:
    echo: n
  fail:
    echo: "error"

try: indica que se inicia un bloque de código controlado y que en caso de una excepción se pasa al bloque correspondiente a fail:.

Sentencias y Operaciones (run)

run: se usa para invocar operaciones, funciones o sentencias. En la mayoría de lenguajes no se antepone algo como run: siendo las operaciones o sentencias las líneas comunes, pero aquí se requiere un atributo para conservar el estilo YAML. También se usa para invocar break, continue, incrementos. Veamos a continuación un par de aclaraciones sobre este punto.

Operaciones vs Declaraciones

En ABCode se usa var: para declarar variables y se pueden inicializar allí mismo. Por otra parte, cuando se trata de operaciones posteriores se usa run:, por lo que es posible encontrar código semejante en ambos casos, pero en uno cumple una función de inicialización y otro correspondería al flujo común (posterior a la definición). Veamos el ejemplo:

  var: i = 0
  echo: i
  run: i = 1
  echo: i

No se ha mencionado let:, que se usa para variables inmutables o constantes, puesto que no debe admitirse una asignación con run: sobre variables inmutables.

Sentencias complementarias y macros

En teoría, las líneas que no corresponden a atributos como fun:, send:, if:, when:, for:, try:, fail:, type:, corresponderían a una sentencia que utiliza run:. Sin embargo, pueden existir variaciones para casos específicos que es apropiado que el lenguaje distinga. Tal es el caso de echo: que se usa para imprimir algo en pantalla. Pensando en implementación a futuro, se tendrían también las palabras reservadas read, file:, link:, web:, dbc:, ask:, page:, jsx:, html:, css:, code: como sentencias complementarias a run:, conocidas también como macros.

Comentarios

Los comentarios ofrecen indicaciones para legibilidad y comprensión del código pero no tienen efecto en la ejecución del programa, es decir, van dirigidos a la documentación del código o al equipo.

# Esto es un comentario

Quien tiene conocimientos en YAML o Python debe saber que el uso de la almoadilla (#) para comentarios coincide con ABCode.
A diferencia de YAML, ABCode admite comentarios de línea completa, es decir, no se interpreta al final de línea salvo excepción de comentario especial del lenguaje (ej. #$:).

Comentarios y etiquetas especiales

Si estás comenzando con la programación de computadores, quizás comprendas mejor este tópico avanzando en la codificación de programas. ABCode introduce tres tipos de comentarios especiales que en realidad son más que comentarios, puesto que ofrecen una orientación en el lenguaje. Veamos:

Etiqueta Descripción
goal: indica el modo o el lenguaje destino (any, cli, api, fun, dbs o un entorno de lenguaje: python, deno, etc.)
#if: comentario que indica lenguaje para el cual se traduce la línea siguiente
#in: comentario que indica lenguaje literal expresado en la línea siguiente

goal: no es un comentario pero es una etiqueta (o atributo) que no opera como una sentencia. Por ejemplo, goal: fun se usa para las funciones más internas o scripts embebidos (ej. Lua), y goal: dbs es como fun para bases de datos con sql.

Revisemos lo siguiente:

goal: any se usa para programas planos en los que no se requieren dependencias (librerías), motivo por el cual se está preparando el uso de goal: cli y goal: api para soportar una librería compatible con destinos oficiales. goal: fun se usa para indicar que el contenido corresponde a funciones más internos o scripts (ej. Lua). goal: dbs es como fun para bases de datos con sql.
Pueden existir restricciones para el uso de #if y #in con alguna sentencia, por ejemplo, fun:, if:, for:, try: y fail: deben acoger lo propuesta de ABCode.

Estructuras de datos

Las estructuras de datos representan un modelo o tuplas, y pueden definirse bajo el atributo set: de la siguiente manera:

  set: Person
    name: string
    age: int

Se usa la misma disposición de YAML indicando los tipos de datos de cada atributo.

Importar bibliotecas de programas

Las librerías o bibliotecas de programas permiten organizar y usar código que se encuentra en otro archivo. Se usa la palabra reservada use: para indicar la librería que se importa y dónde se encuentra (ruta), o en su defecto una incorporada en el sistema. Esto es semejante a lo que se conoce en otros senguajes como import.

use: sys

Actualmente, use: está pendiente por definir detalles del modo de uso mientras se implementan funciones incorporadas o librerías esenciales para el lenguaje.

Clases

Las clases permiten un paradigma que se conoce como programación orientada a objetos, buscando representar todo como un objeto. Si conoces Python, cuando se manejan clases esto debe reinterpretarse conforme a ABCode, encontrándose variaciones o diferencias en este aspecto.

type: Circle
  var: @radious

  fun: new(radious)
    run: @radious = radious

  fun: print()
    echo: @radious

new es el nombre de la funcion con la que se inicializa la clase, es decir, el constructor de la clase se expresa como: fun: new(). Esto difiere de Python y se inspira en Rust.
@ se usa para dar referencia a una propiedad directa de la clase, distinguiédose de una variable común. Esto difiere de Python que usa self u otros que usan this, y se inspira en Ruby, pero debe declararse usando var:.

Otros aspectos

Para indicar que una función es privada, en el contexto de una clase dada, se debe anteponer el signo @ al nombre, por ejemplo: @printer().

En lenguajes como C# o Java (incluso PHP y Kotlin), las clases se organizan o agrupan, bien sea con namespace o package (respectivamente). En ABCode encuentras la palabra reservada root: para estos casos y suele ubicarse en las primeras líneas del programa, antes de definir una clase. Por ejemplo:

root: awesome

type: Circle
...

cast: es reservada para otro concepto conocido como interfaces.

root: awesome

cast: Area
...

Servidor web y su mecanismo interno

La sentencia web: usa métodos para la Web implementando código para cada lenguaje (según librería usada internamente). web: tiene tres métodos basicos que son: :server, :listen y :handle. Veamos un ejemplo…

use: api

web: :server = app

sub: get("/") = index
  web: :handle = "Hi there!"

fun: main()
  let: port:int = 8000
  echo: port
  web: :listen = port

run: main()

Nótese que web: :server = establece variable del servidor, luego web: :handle = asigna un gestor de peticiones, que en este caso devuelve un texto, y web: :listen = inicia el servicio en el puerto indicado.

Por otra parte, en lugar de fun: se usa sub: get(...) = ... para definir las funciones asociadas a una petición web según la ruta. De este modo, podría ser get, post, put o delete.

Patrón de consulta a base de datos

En el caso de ask: se buscaría una estructura de consulta a base datos para que internamente se traduzca a SQL (Structured Query Language) conservando el estilo YAML y un patrón, usando la base de datos OnMind-XDB. Por ejemplo:

  ask:
    what: find
    some: persons
    with: name = 'peter'
    how: order age

Con ask: se usarían los atributos way:, what:, some:, with:, puts:, show: o how: para establecer un patrón en la consulta. way: indica si se especifica mql o sql (siendo este último el defecto y se podría omitir), to: para la colección o tabla, what: para la acción (find, insert, update, delete), with: para el criterio de búsqueda o filtro, y how: para indicaciones complementarias (por ejemplo: order, limit). show: cuando encuentras algo and puts: podría incluirse para operaciones de insercción o actualización. Veamos otros ejemplos:

  ask:
    what: find
    some: persons
    with: name = 'peter'
    show: name,age

Para find se usa show: separando con ,, y with: usa un modo cercano a SQL.
En lugar de usar LIKE dentro de with: se usa la función begins_with(field, value) o contains(field, value) (reportando campo y valor)

  ask:
    what: insert
    some: persons
    puts: {name:'peter',age:25}

Para insert se usa puts: con {} (JSON).

  ask:
    what: update
    some: persons
    with: name = 'peter'
    puts: {age:20}

En este caso, puts: establece age = 20, y with: usa el modo SQL.

  ask:
    what: delete
    some: persons
    with: name = 'peter'

Adicionalmente, dbc: para indicar la conexión específica, keys: para establecer parámetros nombrados que corresponden a una lista clave-valor ({}), call: para invocar funciones, user: y auth: para reportar usuario y token de sesión. También from: cuando se refiere a un respositorio orientado con el Método OnMind.

Resumen de palabras reservadas del lenguaje

De modo esencial podemos citar las siguientes palabras reservadas o tipo de sentencia.

Sentencia Descripción
root: paquete o módulo de programa (referido por compatibilidad, por ejemplo con package o namespace)
fun: establece una función o método (rutina que cumple una función)
set: establece estructura de datos (modelo)
var: declaración de variable (incluye asignación inicial)
let: declaración para fijar inmutables (incluye asignación)
run: sentencia, operación o asignación (también para break, continue)
send: retorna o concluye una función con un valor (si aplica)
if: condición establecida o inicio de validación
when: condición adicional (else if). when: no o simplemente else: cuando no cumple algo
for: ciclo convencional (el codigo respectivo puede incluir in)
sub: bloque de código, para iterar o derivarse como subrutina
try: inicia bloque para excepciones
fail: indica evento generado para el control de excepción
use: importa librería (funciones de otro archivo de programas, import)
type: define una clase, como constructor de la clase se usa fun: new()
echo: imprime o registra salida de consola (con parámetros usa: ${param})
read: captura entrada desde la consola
file gestiona archivos locales (open, write, close)
@: decorador (@) usado en ciertos lenguajes (router, component, tag, widget, etc.)

Debe distinguirse entre el atributo @: (usado como decorador) y el uso de @ en clases.
Actualmente no se implementa la sentencia sub:, quedando reservada como especificación del lenguaje para incorporar en futuras versiones.

Paralelo de palabras reservadas con otros lenguajes

Para quién tenga conocimientos en otro lenguaje, una manera ágil de comprender ABCode consiste en citar el siguiente paralelo o lista comparativa:

ABCode Otros lenguajes
root: package, namespace
fun: function, func, def, proc
set: struct, type, data class
var: let, var, let mut
let: const, val, let
send: return
if: if
when: else if, elif, elsif, else
for: for, while
try: try
fail: catch, exception, rescue
use: import, include, using, require
type: class
echo: print, echo, puts, console.log
read: input
# // (comentarios de línea)
@: @ (decorador)

run: no suele tener paralelo y por esto no se encuentra en la tabla anterior. En la mayoría de lenguajes no se antepone algo como run: para operaciones o sentencias, siendo éstas las líneas comunes, pero aquí se requiere un atributo para conservar el estilo YAML.

Variaciones principales respecto a Python

Para quién tenga conocimientos en Python, y sin hablar de la incidencia de YAML, se indica a continuación las principales diferencias:

  1. Las funciones en ABCode inician con fun: (inspirado en Kotlin) y se omite la palabra reservada def de Python.
  2. Las funciones pueden especificar el tipo de datos a retornar, agregando dos puntos (:) al final y el tipo de datos respectivo.
  3. Se omite la palabra reservada return del lenguaje Python cuando se usa send:.
  4. Las variables pueden especificar el tipo de datos al definirlas, agregando dos puntos (:) después del nombre y el tipo de datos respectivo, antes de asignar un valor (antes de =).
  5. Se simplifican algunas palabras reservadas respecto a Python u otros lenguajes. Tal es el caso de while que no existe y se usa for: (inspirado en Go), o switch...case que tampoco existen y se debe usar if: y when:. En principio, tampoco se piensa en implementar finally que correspondería a try:, con el fin de guardar simplicidad y compatibilidad con ciertos lenguajes.
  6. Las clases llevan el nombre después de iniciar con type:, sustituyendo la palabra reservada class de Python, y el constructor de la clase se debe llamar new (inspirado en Rust).
  7. En las clases se usa el caracter @ (inspirado en Ruby) en lugar de la palabra reservada self de Python, que en otros lenguajes sería this. Esto se verá reflejado en sentencias como run: cuando se usa una propiedad, es decir, que cuando se manejan clases esto debe reinterpretarse conforme a ABCode, el cual presenta variaciones en este tema respecto a Python.
  8. Python incorpora print() mientras ABCode usa echo: para mostrar algo en pantalla (inspirado en PHP).

Aunque ABCode acepta los operadores lógicos and, or y not de Python, promueve en su lugar &&, || y ! en favor de varios lenguajes.

Sobre YAML

Hasta ahora no se mencionan variaciones respecto a YAML dado que en un sentido práctico se respeta su estilo. Se puede apreciar, por ejemplo, que la palabra reservada run: se introduce debido al estilo YAML, puesto que no existe en otros lenguajes este concepto en el caso de sentencias u operaciones.

Por otra parte, es posible que en versiones tempranas se llegue a introducir la notación YAML para textos largos usando el caracter >, por ejemplo, en el caso de la sentencia echo: o send:.

  echo: >
    This text
    is wrapped
    as a paragraph

Sin embargo, en otros casos (como var:, let:, run:) se está revisando la manera apropiada de proceder puesto que podrían combinarse propuestas. Por ejemplo, que una asignación de cadenas de texto (con var: o let:) termine en > (pensando en =>), y en la siguientes líneas se establece el valor, algo como lo siguiente:

  var: text =>
    This text
    is wrapped
    as a paragraph

Estado actual

Especificación lista, trabajo en progreso, el auspicio es bienvenido

El presente documento ya es una especificación del lenguaje de programación ABCode creada y elaborada por César Andrés Arcila Buitrago (© 2022 by César Arcila). En 2022, al interior de la plataforma OnMind se tiene un transpilador (traductor de lenguaje fuente a otro fuente) como prueba de concepto que permite ejecutar programas sencillos que no requieren dependencias, para algunos lenguajes o entornos (Deno, Nodejs).

Para escribir con ABCode no se necesita una nueva aplicación, es decir, se usa un editor (como VSCode o Sublime que descargas de Internet) asociando el formato YAML con archivos de extensión .abc. Sin embargo, se está pensando en preparar un editor para una mejor integración con el transpilador.

Sobre la intención de soporte

Si hablamos de una tecnología que puede llegar a ser Open Source (de código abierto) ya se estaría pensando en cierto soporte pero no impositivo, debido precisamente al tipo de licencia. Considero que para distinguir los lenguajes objetivos y su nivel de soporte lo más coherente es hablar de un nivel de intención de soporte por lenguaje destino o prioridad, dónde cinco (5) es una posibilidad remota. Es verdad que suele usarse la palabra experimental para características no prioritarias y pueden no ser atendidos. A continuación veamos la propuesta de intención del nivel de soporte.

Destinos principales (goal)

Item Destino Nivel Característica de interés o estrategia
1 NodeJS 1 Servidor Web y Microservicios, AWS Lambda, CDK
2 Deno 2 Multiplataforma, Typescript
3 Wasm (AssemblyScript) 2 WebAssembly basado en Typescript (wasm)

0 está reservado para compilación directa desde ABCode a futuro. 4 podría corresponder a Python, luego Lua, quizás Kotlin como dialectos (ya se verá después).

Origenes que cuentan tanto como los destinos

Dado que la estrategia inicial de ABCode es operar como lenguaje portable y embebido en otro lenguaje (ej. usando quickjs) o en un entorno destacado para Backend, debe entenderse que se podría llegar a usar desde PHP, NodeJS, Java, C, Python, Ruby, Dart, Deno, Rust, Go, Swift, Kotlin, C#, Pascal, PostgreSQL y quizás más por medio de entorno de ejecución.

No se trataría sólo de pensar en el destino sino también de las posibilidades de los lenguajes y entornos de origen que integran wasm (WebAssembly) o quickjs.

Se piensa que Python llege a ser un destino nativo siendo también una especificación, motivo por el cual puedes encontrar proyectos que acogen este lenguaje en un entorno (tales como: GraalVM, Jython, IronPython, Python.Net, PyScript), o traducen Python a otro lenguaje (tales como: transcrypt, javascripthon, pscript, py2many, py2rb, py2php, py2dart, pytocs, py2nim, rustpython, pytago, peryton, python-lua, scoder/lupa, dragon/haxe, prometeo), y algún proyecto para dispositivos móviles (como BeeWare, Kivy).

El avance técnico

Como detalle técnico, no se requiere un gestor de paquetes (al dejar esto a cada lenguaje destino) pero tampoco se ha implementado una librería estándar o SDK oficial del lenguaje. Sin embargo, se ha empezado a revisar algún programa esencial con alguna librería sencilla y ligera muy específica. Se consideran aplicaciones web para alguna API de modo clásico o plano (sin requerir librería), es decir, un controlador principal (endpoint) sin enrutamiento de url (se haría mediante POST con parámetro que indique la función a invocar y un token para la seguridad), por lo que puede implementarse de modo estandard.

Aunque el código del transpilador que se produzca se estima liberar bajo licencia Open Source (de código abierto), aún no se ha publicado en repositorios de internet (por ejemplo en GitHub) y hasta último momento esto puede cambiar (quizás por licencia Apache u otra).

Apoya esta obra

Ya venía de producir una plataforma que ha costado una enorme inversión (tiempo, dinero, esfuerzo intelectual, adicional y personal), un proyecto como estos no es para tomarlo a la ligera y se necesita cubrir el factor financiero, por esto…

Se buscan vías de ingresos que son bienvenidos para soportar esta obra.
Specs ready, Work In Progress, Let’s…


© 2022 by César Arcila