JSON que piensa: un lenguaje de programación dentro de JSON
Ensayo

JSON que piensa: un lenguaje de programación dentro de JSON

Osama Alghanmi · 19 de febrero de 2026

¿Y si JSON no fuera solo un formato de datos?

¿Y si fuera un lenguaje de programación?

Construimos un lenguaje Turing completo que es un subconjunto estricto de JSON. Sin sintaxis nueva. Sin analizador propio. Todo programa es JSON válido.

Esto es Almadar.


La idea central

En 1958, John McCarthy presentó las S-expressions (expresiones simbólicas) en Lisp:

lisp
1 2 (+ 1 2) (if (> x 10) "big" "small")

Las S-expressions son listas anidadas en las que el primer elemento es el operador.

Los arrays de JSON son listas anidadas.

json
1 2 ["+", 1, 2] ["if", [">", "x", 10], "big", "small"]

Eso es todo.

Las S-expressions ya encajan perfectamente dentro de los arrays de JSON. En lugar de inventar una sintaxis nueva, interpretamos lo que JSON ya expresa.


Cómo es un programa de Almadar

Un programa de Almadar se compone de Orbitals, los bloques básicos del sistema.

Cada Orbital encapsula tres elementos centrales:

  • Entity — el modelo de datos
  • Trait — el comportamiento
  • Page — la interfaz

Entity — el modelo de datos

La Entity define la estructura de los datos. Declara campos, tipos y restricciones.

Es:

  • el esquema
  • la memoria
  • el contenedor de estado

Contiene los datos sobre los que opera el sistema.


Trait — el comportamiento

Un Trait define el comportamiento.

Técnicamente, un Trait es una máquina de estados reutilizable vinculada a una Entity.

Contiene:

  • estados
  • transiciones
  • guardas Guards (condiciones escritas como S-expressions)
  • efectos (acciones como set, emit, etc.)

Los Traits encapsulan la lógica y pueden reutilizarse entre orbitals. Son el núcleo computacional del sistema.


Page — la interfaz

Una Page define la interfaz de usuario.

Describe:

  • la disposición
  • los componentes
  • los enlaces a campos de la Entity
  • los disparadores de eventos

Las Pages reaccionan al estado de la Entity y envían eventos que mueven los Traits.


Ejemplo

json
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 { "name": "ApprovalWorkflow", "orbitals": [{ "entity": { "name": "Request", "fields": [ { "name": "amount", "type": "number" }, { "name": "status", "type": "enum", "values": ["pending", "approved", "rejected"] } ] }, "traits": [{ "name": "ApprovalTrait", "linkedEntity": "Request", "stateMachine": { "states": [ { "name": "Pending", "isInitial": true }, { "name": "Approved" }, { "name": "Rejected" } ], "transitions": [{ "from": "Pending", "to": "Approved", "event": "APPROVE", "guard": ["and", [">=", "@user.roleLevel", 3], ["<", "@entity.amount", 10000] ], "effects": [ ["set", "@entity.status", "approved"], ["emit", "REQUEST_APPROVED"] ] }] } }] }] }

La estructura es JSON. La lógica son arrays de JSON. La ejecución es determinista y recursiva.


¿Qué es un Guard?

Un guard es una expresión condicional que determina si se permite ejecutar una transición de estado.

Una transición solo se dispara si su guard se evalúa como true. Si el guard se evalúa como false, la transición queda bloqueada.

Los guards son expresiones puras: no tienen efectos secundarios.


Ejemplo de Guard

json
1 2 3 4 5 6 7 8 9 10 11 12 { "from": "Pending", "to": "Approved", "event": "APPROVE", "guard": ["and", [">=", "@user.roleLevel", 3], ["<", "@entity.amount", 10000] ], "effects": [ ["set", "@entity.status", "approved"] ] }

Esta transición se ejecuta solo si:

  • el nivel de rol del usuario es al menos 3
  • el importe de la solicitud es menor que 10.000

Si alguna de las dos condiciones falla, la transición no hace nada.


Evaluación del Guard

Los guards se evalúan de forma recursiva:

json
1 2 3 4 ["and", [">=", "@user.roleLevel", 3], ["<", "@entity.amount", 10000] ]

Pasos de la evaluación:

  1. Resolver los enlaces (@user.roleLevel, @entity.amount)
  2. Evaluar las expresiones internas
  3. Evaluar el operador exterior

El resultado debe ser un booleano.

Los guards pueden usar:

  • operadores lógicos: and, or, not
  • comparaciones: =, !=, <, >, <=, >=
  • aritmética
  • expresiones anidadas
  • referencias a @entity, @user o @payload

Conceptualmente, un guard equivale a una condición if para una transición.


Por qué esto es un lenguaje de programación

Almadar es Turing completo porque ofrece:

  • estado mutable (los campos de la Entity)
  • máquinas de estados deterministas
  • lógica condicional
  • efectos (set, emit)
  • autotransiciones (bucles)
  • comunicación basada en eventos

Una autotransición con un guard y actualizaciones de estado equivale a un bucle while:

json
1 2 3 4 5 6 7 8 9 10 { "from": "Computing", "to": "Computing", "event": "TICK", "guard": [">", "@entity.counter", 0], "effects": [ ["set", "@entity.counter", ["-", "@entity.counter", 1]], ["emit", "TICK"] ] }

Estado = memoria. Transiciones = flujo de control. Expresiones = cómputo.

Eso es un modelo computacional completo.


La propuesta

Almadar propone un cambio sencillo:

  • Mantener JSON.
  • Interpretar los arrays como S-expressions.
  • Combinarlos con máquinas de estados para el flujo de control.
  • Tratar los datos estructurados y la lógica ejecutable como un solo sistema.

Sin gramática nueva. Sin reglas de sintaxis nuevas. Solo cómputo estructurado dentro del formato de datos más universal del mundo.

JSON ya ganó.

Ahora puede pensar.

Publicado por primera vez en Dev.to.

Osama Alghanmi

El conocimiento es libertad. Los sistemas deben estar abiertos a las personas a las que gobiernan.

© 2026 Osama Alghanmi. Liubliana, Eslovenia.