Expresiones — Manual mínimo de sintaxis y uso
Una página con toda la sintaxis. Si solo necesitas los ejemplos más frecuentes, la guía rápida es más corta; si necesitas la definición exacta de la sintaxis, está en la gramática.
1. Sintaxis en 10 líneas
[Importe] * [Cantidad] * 1.21 // campos de la fila: [Nombre], admite espacios
AGG(baseImponible) // total precalculado del report
"Cliente: " + [Nombre] // texto; + concatena si hay un string
[Importe] > 1000 ? "VIP" : "normal" // condición estilo C#...
"VIP" if [Importe] > 1000 else "normal" // ...o estilo Python (idénticas)
[Descuento] ?? 0 // valor por defecto si está vacío
[Fecha2] == null // ¿está vacío? (null o None)
[Activo] and not [Bloqueado] // and/or/not o &&/||/!
Round([Importe] * 1.21, 2) // funciones permitidas (ver la guía rápida)
#2026-06-10# // fecha literal (por eso # NO es comentario)
Reglas de oro: números con punto decimal; comparar es == (no =); un vacío (null) se propaga como en SQL (null + 5 → null; remedio: [X] ?? 0 o Coalesce).
2. ¿Sintaxis C# o Python? No se elige: es una sola gramática
No hay selector ni modo que activar. La gramática v2 es un superset: acepta las formas C# y las Python a la vez, incluso mezcladas en la misma expresión:
[Total] > 1000 and [Activo] ? "VIP" : "normal" // and (Python) + ?: (C#) — válido
| Quieres decir... | Forma C# | Forma Python equivalente | ||
|---|---|---|---|---|
| y / o / no | && `\ | \ | !` | and or not |
| condición | c ? a : b | a if c else b | ||
| vacío | null | None | ||
| distinto | != | <> (estilo SQL/Python 2) |
Cada técnico escribe en el estilo que conozca; el motor las compila al mismo nodo y dan exactamente el mismo resultado. Lo guardado antes de v2 sigue funcionando sin tocar nada (superset estricto; la definición almacena GrammarVersion).
En scripts (nivel 2) solo existe hoy el estilo C# (var, ;, bloques { }): es la sintaxis natural del programador de plugins y no se eliminará. Si algún día se añade un script estilo Python (indentación), convivirá con este vía GrammarVersion — se elegiría al guardar la definición, nunca con un flag global.
3. Mayúsculas y minúsculas: dos reglas distintas
- Nombres (campos, funciones, palabras clave): da igual cómo se escriban.
- Contenido de los textos al comparar:
==distingue mayúsculas
4. Evaluar desde código
var engine = new ExpressionEngine(); // singleton en DI (cachea compilados)
var env = new EvaluationEnvironment(clock: DateTime.Now) // reloj fijado: Now() constante
.Set("Importe", 100.50m) // valores del scope
.SetAggregate("baseImponible", 1234.5m);
var compilada = engine.CompileExpression("[Importe] * 1.21", CompileOptions.Compiled);
object? valor = compilada.Evaluate(env); // compila 1 vez, evalúa N filas
CompileOptions.Compiledpara evaluar miles de veces (reports); sin opciones = intérprete.compilada.Symbols= qué campos/funciones usa → la validación de permisos- En reports no se usa el engine directo: el adaptador
ErpExpressionEvaluator
5. Scripts (nivel 2 — automatizaciones y plugins, nunca reports)
var env = new EvaluationEnvironment(maxLevel: LanguageLevel.Script).Set("Lineas", lista);
object? r = engine.CompileScript("""
var total = 0;
foreach (var x in Lineas) { if (x > 10) { total = total + x; } }
return total;
""").Execute(env);
var, =, if/else, while, foreach (var x in L), return, bloques { }, sentencias con ;. Presupuesto de pasos automático (un bucle infinito se corta con error claro). El entorno declara el nivel: uno de report (Expression) rechaza scripts por construcción.
6. Editor: validar sin ejecutar y autocompletar
var assistant = new ExpressionAssistant(engine);
var errores = assistant.Validate(texto, env, usuario); // parse + binding + permisos, con posición
var sugerencias = assistant.Complete("imp", env); // símbolos + funciones + keywords