Appearance
Lenguaje de Programación ABCode
Minimizando la Torre de Babel del Software.
Especificación del Lenguaje - Versión 1.
© 2021-2025, César Andrés Arcila Buitrago. Todos los derechos reservados.
Tabla de Contenido
- Introducción
- ¿Qué es ABCode?
- Ejemplo esencial
- Lenguaje de programación ABCode vs lenguaje natural
- Tips esenciales del lenguaje
- Tipos de datos básicos
- Variables
- Funciones
- Operadores del lenguaje
- Condicional if / when (else)
- Bucle for
- Excepciones
- Sentencias y Operaciones (run, echo...)
- Comentarios
- Estructuras de datos
- Importar bibliotecas de programas
- Clases
- Servidor web y su mecanismo interno
- Patrón de consulta de base de datos
- Resumen de palabras reservadas
- Palabras reservadas vs otros lenguajes
- Diferencias con Python
- Sobre YAML
- Estado actual
Introducción
En este texto, dirigido a profesionales y entusiastas afines al software ya iniciados en ello, presento mi lenguaje de programación que se ha inspirado en los orígenes y simplicidad del código en base de datos trasladado a nuestros días, en dónde el código se ubica en lo que llamamos "middleware" en una aplicación, arquitectura de micro-servicios, "serverless", y otras. Agregando que ante tantos lenguajes y tecnologías derivadas, es posible lograr un camino unificador para minimizar la Torre de Babel del Software en buena medida.
Imagina también que, en tiempos dónde la IA (Inteligencia Artificial) llegó para quedarse, exista una tecnología que se entienda con tecnologías existentes brindando un nivel más alto y sencillo para la comprensión del código generado.
Antes de hablar de una nueva especificación y lenguaje de programación ABCode, me permitiré 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 en 2020 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.
Sobre el Autor
Ingeniero de Sistemas apasionado por la Arquitectura y Desarrollo de Software, con conocimientos en Gestión de Proyectos y estudios en Filosofía. Certificaciones en AWS y Scrum Master, he estado certificado en PMP hasta vencimiento hace unos años.
Experiencia por más de 20 años participando en proyectos de software (ERP, CRM, Workflow, API, Microservicios, Integración) con diversas tecnologías en empresas importantes de diferentes sectores, además proyectos en la nube (AWS).
Líder, experto y creativo, con un punto de vista singular y holístico. Podría decir que un políglota informático. He llegado a ser autor de tecnología propia y blog, así como el libro: El Método OnMind (disponible en Amazon).
Portafolio: https://github.com/kaesar
¿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 Andrés Arcila Buitrago) 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, por ejemplo: Kotlin, Java, 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 (aunque orginalmente se consideró 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 relacionales con procedimientos almacenados (en lenguajes como: PL/SQL o PL/pgSQL), y que actualmente encontramos alguna similitud en nuevas tecnologías (por ejemplo: AWS Lambda Cloudflare Workers, etc.).
Y es que en mis orígenes como profesional en software trabajé mi primera década con tecnologías de Oracle y lo que añoro de entonces era la simplicidad cuando desarrollabas código para Backend (o la base de datos en ese entonces), sin requirir tantas tecnonologías ni conocimientos diversos.
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 o clave en YAML con sangría, el resto de la línea podría verse como código cercano a Python, en realidad transpila 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 algunos dialectos (hasta 5 adicionales, sumando 6) que comparten la misma raíz, por ejemplo, pensar en Kotlin, Java, Python y a lo mejor Go (ya veremos).
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.
- ABCode es sinónimo de la portabilidad de tu código.
- ABCode se enfoca en principio en código del lado del servidor (backend) combinando YAML con cierto aspecto de Python, en realidad transpila Javascript usando una sintaxis restringida de este lenguaje.
- ABCode está pensado para ser fácil de aprender siendo cercano a un algoritmo. También puedes hacer una transición ágil cuando vienes de un lenguaje como Python. Por otra parte, YAML es un lenguaje de marcado expresivo y legible al humano, por lo que ABCode también lo es. Puede ser aconsejable revisar la referencia de YAML antes de empezar pero tampoco es requerido.
- El lenguaje ABCode apoya el Método OnMind y la base de datos OnMind-XDB del mismo autor.
- ABCode se proyecta para llegar a funcionar alternativamente como una especificación en la que se transpila otro lenguaje (adicional a Javascript). Con esto se buscaría guardar legibilidad aunque la implementación sea específica para un lenguaje en ese caso. Además, se alcanza personalización cuando una tecnología requiere el potencial de un determinado lenguaje de programación.
- Puede pensarse a futuro como un traductor o puente entre lenguajes de programación, entornos y plataformas, o bien, multi-lenguaje, multi-entorno y mult-plataforma, quizás multi-propósito o multi-paradigma.
- Modernización e innovación suelen implicar migración de tecnología, proyectos que llegan a tomar años. Con el uso de ABCode el impacto puede ser menor, teniendo el potencial para facilitar el cambio entre tecnologías (en principio, del lado del servidor).
- Un gran potencial de este lenguaje puede encontrarse en proyectos con tecnologías mixtas, permitiendo agregar una capa abstracta con un sentido unificador. Un caso de aplicación es lo que se conoce como ciudades inteligentes (Smart Cities), así como también para la operación con servidores en la nube (DevOps), o cuando se piensa en incorporar aprendizaje de máquina (Machine Learning) con software de gestión usando una semántica uniforme, o en su defecto, con un estilo semejante para la lectura del equipo de trabajo. Quizás se tienen las bases para explorar a futuro el caso del aspecto visual (frontend).
- Otros lenguajes estarían en mente y podrán ser introducidos poco a poco de modo experimental, pero el objetivo es mantener principalmente 2 o 3 destinos oficiales (por ejemplo: NodeJS, Deno y WebAssembly) y hasta 5 dialectos adicionales (sumando 6 lenguajes: Javascript, Typescript, Kotlin, Java, Python y a lo mejor Go, ya veremos).
¿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 se construyó inicialmente con Javascript 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, mientras 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 progresivamente (hasta llegar a sustituir ese aspecto en el Backend)...
Así podría volverse algún día a los orígenes cuando se desarrollaba código en base de datos, es decir, implementar y mantener desarrollos de negocio usando tecnologías específicas y simples, aunque se derive el resultado potencialmente en más tecnologías para orientarse como tecnología multiplaforma.
Es cierto que esto requiere un nuevo esfuerzo y no cualquier menor efuerzo, sin embargo en tanto se avanza con el compilador se estarían sumando esfuerzos de tecnologías a las que se convierte el código, y en ese aspecto se trabajaría también sobre lo construido. Esto sin mencionar que sería más eficiente con la IA (Inteligencia Artificial) usar ABCode como puente para llegar a tener código mantenible en múltiples plataformas. Considero que un código más legible en sintaxis evita distanciamiento entre la comprensión del humano y el mecanismo de la IA en términos de codificación.
¿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.
Instalación de ABCode
Solo descarga y descomprime segun tu sistema y ejecuta algo como...
bash
./abcodec -s abc/hello.abc
abcodec
es el compilador yabc/hello.abc
representa tu código fuente con ABCode.
Los fuentes liberados parcialmente se encuentran en mi repositorio en GitHub: https://github.com/kaesar/abcode
Ejemplo esencial
yml
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:
yml
fun: hello()
echo: "Hello World!"
run: hello()
Nótese que en este caso
echo:
se deriva o pertenece afun:
(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.
root:
raízfun:
algo divertidoset:
conjunto (sustantivo) o establecer (verbo)var:
abreviatura de variableval:
abreviatura de valor (inmutable)run:
correrpass:
pasarif:
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)do:
hacertry:
intentarfail:
fallouse:
usartype:
claseecho:
ecogoal:
objetivolike:
semejante a...
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:
- Tipos de datos básicos:
int
,float
,boolean
,string
,array
,object
,any
. Las variables se definen iniciando con el atributovar:
, 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. - 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 usapass:
para retornar un valor. La función principal de un programa se denominamain
(fun: main()
). - 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.
- El flujo de control varía respecto a lenguajes como C, Java, Javascript, Kotlin, pero encuentras una forma equivalente para el uso de
if
yfor
, incluso para el manejo de excepciones (try
), cuyas palabras clave deben llevar a continuación el caracter:
. - El constructor de una clase se expresa con el atributo
fun:
y el valornew
(fun: new()
) y la clase se define con el atributotype:
. - 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.
string
- Cadena de caracteres o textoint
- Números enterosfloat
- 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
yfloat
para números y no existenumber
.
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 val:
(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:
yml
var: variable = "Ana"
var: i = 0
val: 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íaprint()
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.
yml
var: variable:string = "Ana"
var: i:int = 0
val: list:array = [10, 20, 30]
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.
yml
fun: hello()
echo: "Hello World!"
run: hello()
Quién conoce Python puede observar que se omite la palabra reservada
def
siendo innecesaria al usarfun:
. 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 comorun:
para operaciones o sentencias, siendo éstas las líneas comunes, pero aquí se requiere un atributo para conservar el estilo YAML.
Veamos otro ejemplo.
yml
fun: sayMyName(name:string):string
pass: name
echo: sayMyName("Andrey")
En este caso se usa
pass
para devolver el valor contenido en la variable (que en otros lenguajes suele serreturn
).
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.
=
: 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||
: o!
: no, negación@
: sustituto deself
othis
para uso de propiedades de clases en otros lenguajes
Recordando tablas de verdad con operadores
Los operadores de inclusión &&
y de opció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
!
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.
yml
var: i = 1
if: i == 1
echo: "coffee"
when: no
echo: "tea"
when: no
oelse:
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.
yml
var: 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:
yml
var: i = 2
if: i == 1
echo: "coffee"
Bucle 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.
yml
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 usabreak
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 función range
para recorrer un rango, incluso combinarla con len
que obtiene el tamaño de un arreglo. Veamos un par de ejemplos:
yml
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:
yml
var: i = 0
for: i < 10
run: i += 1
echo: i
Nótese que
for:
recibe en este caso una condición y no llevain
.
Una variación adicional consistiría en entrar en un ciclo e interrumpirlo (usando: break
) cuando cumpla una condición determminada. Veamos el ejemplo:
yml
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.
yml
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 afail:
.
Sentencias y Operaciones (run, echo...)
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:
yml
var: i = 0
echo: i
run: i = 1
echo: i
No se ha mencionado
val:
, que se usa para variables inmutables o constantes, puesto que no debe admitirse una asignación conrun:
sobre variables inmutables.
Sentencias complementarias y macros
En teoría, las líneas que no corresponden a atributos como fun:
, pass:
, 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 file:
, read
, web:
, dbc:
, ask:
, sql:
, page:
, jsx:
, html:
, css:
, code:
como sentencias complementarias a run:
, conocidas también como macros.
De hecho, echo:
permite formatear la salida como en los siguientes ejemplos:
yml
echo: "Hello, {name}! Tienes {age} years."
echo: "Name: {name:10} | Age: {age:3}" # Alignment with spaces
Para decimales se podría usar:
echo: "The prices is {price:.2f}"
Para gestión de archivos se usaría file:
, considerando cuatro métodos básicos que son: @open
, @write
, @read
, @close
. Por ejemplo:
yml
file: @open = "file.txt"
file: @write = "file.txt", "Hello world!"
Para conexión a base de datos se usaría dbc:
. Por ejemplo:
yml
use: @mongodb
dbc: @link = "mongodb://localhost:27017/"
dbc: mydb := "test"
echo: "Database connected!"
dbc: @link =
establece internamente una variable dbc
para gestionar la conexión a la base de datos. Nótese que se reporta una dirección con controlador de base de datos, dominio (o servidor) y el puerto: "mongodb://localhost:27017/"
Luego dbc: mydb := "test"
apunta al nombre de la base de datos específica (test
) asignándola a una variable (mydb
) con :=
.
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.
yml
# 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.#in:
).
Directivas 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 ciertas etiquetas y comentarios especiales (directivas) que en realidad son más que comentarios, puesto que ofrecen una orientación en el lenguaje. Veamos:
goal:
indica el modo o el lenguaje destino (any
,cli
,api
,fun
,dbs
o un entorno de lenguaje:deno
,wasm
,kotlin
,java
,python
)like:
indica que una sentencia anterior, distinta delike:
(por ejemplo conrun:
,echo:
,use:
opass:
), se expresa en otro lenguaje, el cual se define en#@in:
(por ejemplo#@in: java
). De este modo, se transpila literalmente cuando el destino corresponde a ese lenguaje. No aplica (ni tiene efecto) cuando el destino definido engoal:
es un lenguaje específico#in:
comentario usado al final de la sentencialike:
, que indica lenguaje literal expresado para esa línea y que sustituye una línea de código anterior cuando se transpila a ese destino#[...]
usado para anotaciones del lenguajes como Java (inspirado en Rust)
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, ygoal: dbs
es comofun
para bases de datos consql
.
Ejemplo de las anteriores directivas:
yml
goal: any
val: name = "Andrey"
echo: "Hello, ${name}"
like: "Hello" + name #in: java
like: "Hello, $name" #in: kotlin
Este ejemplo es sólo ilustrativo y es posible que
echo:
no necesite acompañarse conlike:
al permitir un formato más estándar:echo: "Hello, {name}"
Revisemos lo siguiente:
goal:
determina el lenguaje que se expresa en el código y se omite cuando se usa la sintáxis estricta de ABCode. Por defecto: Javascript (core
).goal:
actualmente admitiría valores comoany
ycli
(ABCode para programas planos), más los lenguajes o entornodeno
,wasm
,kotlin
,java
,python
ynodejs/bun
, es decir, un par de entornos y al menos 5 lenguajes o dialectos. Adicionalmente,api
para indicar destinos compatibles con librería web para servidor. Quizás a futuro se introduzcapwa
para indicar destino compatible con el aspecto visual (Javascript en el navegador).goal: any
se usa para programas planos (POJO) en los que no se requieren dependencias (librerías), motivo por el cual se piensa preparar el uso degoal: cli
ygoal: 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 comofun
para bases de datos consql
(es decir, código para repositorio y persitencia de datos).goal:
puede ser usado para reportar un destino distinto aany
,cli
,api
,fun
odbs
(inclusopwa
en un futuro), así se debe entender como una modalidad de puente para otro lenguaje. De esta manera se conserva la estructura expresiva (YAML) y la parte de código se orienta para traducción a un lenguaje en particular. Esto es útil para implementar soluciones específicas en un lenguaje o entorno determinado.like:
combinado con el comentario#in:
es útil cuando se desea traducir una línea de código con un lenguaje en particular (por ejemplo, debido a diferencias en librerías), refiriéndose siempre a la anterior línea (distinta delike:
), es decir, aplicando una traducción literal. Lo anterior sugiere que si se usagoal:
con un destino distinto deany
,cli
,api
,fun
odbs
, no se requiere usarlike:
, siendo en ese caso excluyentes.- Pueden existir restricciones para el uso de
like:
con#in:
en algunas sentencias, por ejemplo,fun:
,if:
,for:
,do:
,try:
, yfail:
deben acoger la propuesta de ABCode (sin traducción).
Para evitar ambigüedad o disminuir posible conflicto entre goal:
y el argumento del compilador en la línea de comandos en donde se usa -t
para indicar como destinos los lenguajes o entornos, la interpretación es la siguiente:
El compilador
abcodec
en principio traduce ciertos dialectos, siendo nativo el lenguaje Javascript (nodejs/bun
), y el dialeto destino se indica con el argumento-t
. En el compilador se revisará si existe la etiquetagoal:
(en las primeras líneas del archivo o primera aparición) y en el caso de indicar de encontrarse con un valor para un lenguaje distinto se reportará la advertencia y se evitará la transpilación. Por supuesto, si el valor no corresponde a lenguajes o entornos (por ejemplo:any
,cli
,api
,fun
,dbs
) el argumento aplica para traducir al código destino.
Estructuras de datos
Las estructuras de datos representan un modelo o tuplas, y pueden definirse bajo el atributo set:
de la siguiente manera:
yml
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 lenguajes como import
.
yml
use: @sys
A modo de ejemplo,
@sys
,@api
,@mongodb
serían directivas para resolver algunas librerías dinámicamente.
A la fecha de esta publicación,use:
está pendiente por definir otros detalles adicionales para su 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.
yml
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 usaself
u otros que usanthis
, y se inspira en Ruby, pero debe declararse usandovar:
.
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:
yml
root: awesome
type: Circle
...
cast:
es reservada para otro concepto conocido como interfaces.
yml
root: awesome
cast: Area
...
Estos criterios se definen como parte de la especificación del lenguaje, aunque en primeras versiones del compilador es posible que aún no estén disponibles.
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 métodos basicos que son: @server
, @listen
, @handle
(incluso @fetch
). Veamos un ejemplo...
yml
use: @api
web: @server = app
do: get("/") = index
web: @handle = "Hi there!"
fun: main()
val: 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 do: 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
.
Estos criterios se definen como parte de la especificación del lenguaje, aunque en primeras versiones del compilador es posible que aún no estén disponibles
Patrón de consulta de base de datos
En tanto se implemente ask:
(palabra reservada para gestión con base de datos), se buscaría una estructura de consulta declarativa para interactuar con una base datos y 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:
yml
ask:
what: find
some: persons
with: name = 'peter'
how: order age
Con ask:
se usarían los atributos what:
, some:
, with:
, puts:
, show:
o how:
para establecer un patrón en la consulta. 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:
yml
ask:
what: find
some: persons
with: name = 'peter'
show: name,age
Para
find
se usashow:
separando con,
, ywith:
usa un modo cercano aSQL
.
En lugar de usarLIKE
dentro dewith:
se usaría la funciónbegins_with(field, value)
ocontains(field, value)
(reportando campo y valor)
yml
ask:
what: insert
some: persons
puts: {name:'peter',age:25}
Para
insert
se usaputs:
con{}
(JSON).
yml
ask:
what: update
some: persons
with: name = 'peter'
puts: {age:20}
En este caso,
puts:
estableceage = 20
, ywith:
usa el modoSQL
.
yml
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.
Estos criterios se definen como parte de la especificación del lenguaje, aunque en primeras versiones del compilador es posible que aún no estén disponibles
Resumen de palabras reservadas
De modo esencial podemos citar las siguientes palabras reservadas o tipo de sentencia.
root:
paquete o módulo de programa (referido por compatibilidad, por ejemplo conpackage
onamespace
)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)val:
declaración para fijar inmutables (incluye asignación)run:
sentencia, operación o asignación (también para break, continue)pass:
retorna o concluye una función con un valor (si aplica)if:
condición establecida o inicio de validaciónwhen:
condición adicional (else if
).when: no
o simplementeelse:
cuando no cumple algofor:
ciclo convencional (el codigo respectivo puede incluirin
)do:
bloque de código, para derivarse como subrutina (o función lambda)try:
inicia bloque para excepcionesfail:
indica evento generado para el control de excepciónuse:
importa librería (funciones de otro archivo de programas,import
)type:
define una clase, como constructor de la clase se usafun: new()
echo:
imprime o registra salida de consola (con parámetros usa:{param}
)file:
gestiona archivos locales (@open
,@write
,@read
,@close
)goal:
sugiere el destinolike:
reemplaza una línea de código anterior tal como se indica (combinando#in:
y el lenguaje destino)
A la fecha de esta publicación, no se implementan la sentencia
read:
quedando reservada como especificación del lenguaje para incorporar en futuras versiones.
Palabras reservadas vs 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:
root:
~package
,namespace
fun:
~function
,func
,def
,proc
set:
~struct
,type
,data class
var:
~let
,var
,let mut
val:
~const
,val
,let
pass:
~return
if:
~if
when:
~else if
,elif
,elsif
,else
for:
~for
,while
do:
~do
try:
~try
fail:
~catch
,exception
,rescue
use:
~import
,include
,using
,require
type:
~class
echo:
~print
,echo
,puts
,console
#
~//
(comentarios de línea)
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 comorun:
para operaciones o sentencias, siendo éstas las líneas comunes, pero aquí se requiere un atributo para conservar el estilo YAML.
Diferencias con Python
Se ha hablado de Python por ser un lenguaje cuya sintaxis fue inspiradora para mi propio lenguaje. Aunque ABCode es mas cercano a Javascript se guardan algunos aspectos de Python. Para quién tenga conocimientos en Python, y sin hablar de la incidencia de YAML, se indica a continuación las principales diferencias:
- Las funciones en ABCode inician con
fun:
(inspirado en Kotlin) y se omite la palabra reservadadef
de Python. - Las funciones pueden especificar el tipo de datos a retornar, agregando dos puntos (
:
) al final y el tipo de datos respectivo. - Se omite la palabra reservada
return
del lenguaje Python cuando se usapass:
. - 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=
). - Se simplifican algunas palabras reservadas respecto a Python u otros lenguajes. Tal es el caso de
while
que no existe y se usafor:
(inspirado en Go), oswitch...case
que tampoco existen y se debe usarif:
ywhen:
. En principio, tampoco se piensa en implementarfinally
que correspondería atry:
, con el fin de guardar simplicidad y compatibilidad con ciertos lenguajes. - Las clases llevan el nombre después de iniciar con
type:
, sustituyendo la palabra reservadaclass
de Python, y el constructor de la clase se debe llamarnew
(inspirado en Rust). - En las clases se usa el caracter
@
(inspirado en Ruby) en lugar de la palabra reservadaself
de Python, que en otros lenguajes seríathis
. Esto se verá reflejado en sentencias comorun:
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. - Python incorpora
print()
mientras ABCode usaecho:
para mostrar algo en pantalla (inspirado en PHP). - En lugar de los operadores lógicos
and
,or
ynot
de Python, ABCode promueve el uso de&&
,||
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 futuras versiones se llegue a introducir la notación YAML para textos largos usando el caracter >
, por ejemplo, en el caso de la sentencia echo:
o pass:
.
yml
echo: >
This text
is wrapped
as a paragraph
Estos criterios se definen como parte de la especificación del lenguaje, aunque en primeras versiones del compilador es posible que aún no estén disponibles
Estado actual
Especificación lista (este libro), trabajo en progreso, el auspicio es bienvenido
El presente texto ya es una especificación del lenguaje de programación ABCode creada y elaborada por César Andrés Arcila Buitrago en el año 2021, si bien fue ideada con un prototipo rústico en 2020. En los inicios del año 2022, al interior de la plataforma OnMind se logró un transpilador (traductor de lenguaje fuente a otro fuente) como prueba de concepto que permitía ejecutar programas sencillos que no requieren dependencias, para algunos lenguajes o entornos (Deno, NodeJS).
Recuerda que el enfoque inicial de este nuevo lenguaje es la lógica de negocio que se aborda desde el Backend. Por ello no se ve una necesidad urgente de que el compilador convierta múltiples archivos y en su lugar se debe procesar archivo por archivo, aunque seguramente se puede considerar más adelante esto.
Para escribir con ABCode no se necesita una nueva aplicación, es decir, se usa un editor (como VSCode
, Sublime
u otro que puedes descargar de Internet) asociando el formato YAML con archivos de extensión .abc
. Alternativamente, el formato puede asociarse a Lua (solo debes evitar aplicar sus comentarios). Sin embargo, se ha llegado a pensar en preparar un editor para una mejor integración con el compilador/transpilador.
Los fuentes liberados parcialmente se encuentran en mi repositorio en GitHub: https://github.com/kaesar/abcode
Sobre la intención de soporte
Si hablamos de una tecnología que tendría versión 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 atendidas.
Por ahora, los destinos se orientan al backend, si bien existen tecnologías que promueven el desarrollo FullStack desde el back. A continuación veamos la propuesta de intención del nivel de soporte, dado el contexto, no vinculante para ningún nivel (incluso el 1).
Destinos principales
Característica de interés o estrategia:
- NodeJS
-
Nivel 1-
Servidor Web y Microservicios, AWS Lambda, CDK - Deno
-
Nivel 2-
Multiplataforma, Typescript - AssemblyScript
-
Nivel 2-
WebAssembly basado en Typescript (wasm)
Bun podría usarse como sustituto de NodeJS debido a su compatibilidad.
Destinos complementarios de alta experimentación a futuro
Característica de interés o estrategia:
- Kotlin
-
Nivel 3-
Multiplataforma, Servidor Web y Microservicios - Java
-
Nivel 3-
Bases de Datos, Servidor Web y Microservicios (SpringBoot) - Python
-
Nivel 4-
Scripts y Ciencia de Datos - Go
-
Nivel 5-
WebAssembly, Servidor Web y Microservicios
4
podría corresponder a Kotlin (JVM), luego Java, quizás Python y Go (ya se verá después).
Origenes que cuentan tanto como los destinos
Dado que otra estrategia de ABCode consiste en operar como lenguaje portable y embebido en otro lenguaje (ej. usando quickjs) o en un entorno destacado para Backend, debe entenderse que potencialmente 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 lenguajes y entornos que integran
wasm
(WebAssembly) o quickjs, incluso Lua con el proyecto TypescriptToLua (TSTL).
¿Por qué no PHP u otros lenguajes?
En cuanto a otros lenguajes, se considera que la estrategia tiene un alcance más que suficiente y bien amplio, con lenguajes "Top". En el caso de PHP se identifica mayor dificultad para traducir el código, por ejemplo, por el uso del signo $
en las variables y consideraciones semejantes que sería impedimento para obtener un destino claro. También puede ser sustituido usando Python, o el proyecto py2php
, así como ts2php
. Aunque, se podría pensar a futuro en una capa web ligera en PHP (un "Runtime") que invoque funciones en wasm
, gracias a wasmer-php
.
Más detalles sobre el avance técnico
Como detalle técnico, no se requiere ningún gestor de paquetes (al dejar esto a cada lenguaje destino) y tampoco requiere librería estándar o SDK (hasta ahora). 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.
Recuerda que ABCode finalmente convierte código a Javascript, en su enfoque prioritario, tomando las partes de la línea que son los valores en YAML. Esto ya está disponible en el compilador sujeto a mantenimiento y al refuerzo de reglas para disminuir errores potenciales en su uso.
Invitación final
Si has llegado hasta aquí me queda agradecer la acogida respectiva e invitarte a ver mi portafolio de proyectos, aunque algunos estén congelados o sean privados y mi ocupación pueda estar a tope, he publicado software gratuito que puedes encontrar entre mis obras y tengo previsto preparar algún anexo a este texto que ha planteado los fundamentos...
Portafolio: https://github.com/kaesar
ABCode (Compilador): https://github.com/kaesar/abcode
https://onmind.co
Fe de erratas
El formato digital de eBook puede tener variaciones respecto al proyectado originalmente dónde se respeta un estilo, colores, sangría y algún otro aspecto.