El límite de 40 tokens explicado

En Blogger existe una restricción en el marcado b:XML de 40 tokens por expresión, que no está documentada oficialmente. En este artículo te explico cómo cuenta tokens el compilador, cuáles son las reglas exactas respaldadas por pruebas empíricas y cómo evitar el error Invalid expression.

Adicionalmente, ahora está disponible en zkreations una nueva herramienta llamada Blogger Tokenizer. Si solo quieres comprobar el consumo de tokens, puedes utilizarla directamente. Si deseas aprender cómo se cuentan los tokens, el proceso se explica a continuación.

40 tokens por expresión

Todas las expresiones evaluadas en atributos dinámicos de Blogger tienen un límite estricto de 40 tokens. Al alcanzar 41 o más, Blogger aborta la carga de la página y muestra el siguiente error:

Invalid expression: <expresión que causó el error>

Nota: Cuando ocurre este error, la plantilla no renderiza ningún contenido y muestra una página de advertencia bloqueante hasta que la expresión sea corregida o descompuesta.

Tabla de contabilidad de tokens

La siguiente tabla resume las reglas de conteo de tokens del compilador. Es el resultado de la información proporcionada por Soraya Lambrechts en su blog Blogger Code PE, complementada con una amplia cantidad de pruebas empíricas realizadas por mí:

Elemento Tokens Regla
Operadores 1 Aritméticos, relacionales, lógicos, pertenencia y lambdas.
Operandos escalares 1 Números, cadenas, booleanos y null.
Rutas data:* 1 Toda la ruta, incluido accesos por punto o índice, consume un token.
Ternario ? : 2 Un token por ? y otro por :.
Elvis ?: 1 Un token por cada ?:.
Funcionales 1 El identificador consume un token; los paréntesis de argumentos no.
Agrupación ( ) 1 Solo ( consume un token; ) no.
Objeto { } 1 Solo { consume un token; } no.
Array [ ] 1 Solo [ consume un token; ] no.
Claves de objeto 0 Las claves (key:) no consumen tokens; sus valores sí.
Delimitadores 0 Los limitadores ,, : no consumen tokens.

Particularidades sintácticas del compilador

Tras múltiples pruebas he identificado comportamientos particulares del motor de Blogger al estructurar expresiones:

1. Invarianza multilínea

El compilador aplica exactamente el mismo recuento de tokens independientemente de si una expresión está escrita en una sola línea o dividida en múltiples líneas:

<!-- 6 tokens -->
<b:eval expr='snippet(data:view.description, {
 length: 50,
 links: false,
 linebreaks: false
})'/>
<!-- 6 tokens -->
<b:eval expr='snippet(data:view.description, { length: 50, links: false, linebreaks: false })'/>

Blogger convierte automáticamente cualquier expresión multilínea a una sola línea al guardar cambios. Los saltos de línea y las sangrías consumen 0 tokens.

2. Consumo de tokens en objetos

Al configurar llamadas a operadores como snippet o armar diccionarios de opciones para <b:include>, el recuento sigue reglas propias. Contando los tokens del ejemplo anterior:

Elemento Tokens
snippet(...) 1
data:view.description 1
{ 1
50 (valor de length) 1
false (valor de links) 1
false (valor de linebreaks) 1

Las tres propiedades del objeto solo costaron 3 tokens, correspondientes a sus valores literales. Para simplificar el conteo, basta con contar las aperturas, como {, [ o (, e ignorar las de cierre, descartando aquellas aperturas que forman parte de la sintaxis funcional snippet(...).

3. Rutas de datos complejas

Cuando se accede a datos mediante corchetes, como data:test[data:index].a o con expresiones aritméticas dentro del índice como data:test[(data:index + 1)].a, la expresión exterior contabiliza toda la referencia como un solo operando.

Nota: La expresión dentro de los corchetes [...] mantiene su propio presupuesto de evaluación, pero no incrementa el costo de la expresión exterior en la que está incrustada.

4. Preprocesamiento de entidades XML

En plantillas XML de Blogger es común escribir &quot; o =&gt; para validar XML. El analizador SAX de Blogger decodifica todas las entidades antes de pasarlas al motor de expresiones, por lo que &quot; y " consumen exactamente la misma cantidad de tokens.

Ejemplos para pruebas

Los siguientes ejemplos pueden probarse en Blogger y están organizados por complejidad. También puedes contar tokens con la nueva herramienta Blogger Tokenizer disponible en zkreations:

<!-- 1 token: literal numérico -->
<b:eval expr='1'/>
<b:eval expr='-1'/>

<!-- 2 tokens: paréntesis de agrupación -->
<b:eval expr='(1)'/> <!-- 1 literal + 1 par de paréntesis -->

<!-- 3 tokens: operación aritmética -->
<b:eval expr='1 + 2'/>

<!-- 4 tokens: aritmética agrupada -->
<b:eval expr='(1 + 2)'/> <!-- 3 tokens aritméticos + 1 par de paréntesis -->
<!-- Arrays: 1 token por '[' + 1 token por elemento -->
<b:eval expr='[1]'/>        <!-- 2 tokens -->
<b:eval expr='[1, 2]'/>     <!-- 3 tokens -->
<b:eval expr='[[1, 2]]'/>   <!-- 4 tokens (2 corchetes + 2 elementos) -->

<!-- Objetos: 1 token por '{' + tokens de los valores -->
<b:eval expr='{a: 1}'/>        <!-- 2 tokens -->
<b:eval expr='{a: 1, b: 2}'/>  <!-- 3 tokens -->
<!-- 40 tokens: array con 39 elementos (1 corchete + 39 números) -->
<b:eval expr='[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, 37, 38, 39]'/>

<!-- 40 tokens: función prefijo con 39 argumentos -->
<b:eval expr='+(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, 37, 38, 39)'/>

<!-- 40 tokens: paréntesis anidados -->
<b:eval expr='(((1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19)))'/>
<!-- ERROR: 41 tokens o mas provoca 'Invalid expression' -->
<!-- <b:eval expr='[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, 37, 38, 39, 40]'/> (1 corchete + 40 elementos = 41 tokens) -->
<!-- <b:eval expr='{a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10, k: 11, l: 12, m: 13, n: 14, o: 15, p: 16, q: 17, r: 18, s: 19, t: 20, u: 21, v: 22, w: 23, x: 24, y: 25, z: 26, aa: 27, ab: 28, ac: 29, ad: 30, ae: 31, af: 32, ag: 33, ah: 34, ai: 35, aj: 36, ak: 37, al: 38, am: 39, an: 40}'/> (1 llave + 40 valores = 41 tokens) -->
<!-- <b:eval expr='1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16 + 17 + 18 + 19 + 20 + 21'/> (20 operadores + 21 operandos = 41 tokens) -->

Estrategias para no superar el límite

Al diseñar componentes con imágenes adaptativas, metadatos y condiciones de renderizado es fácil acercarse al límite. Las siguientes técnicas ayudan a mantenerse dentro de la cuota:

1. Descomposición con b:with

<b:with> permite crear variables intermedias en el ámbito local y reiniciar el contador de tokens a cero para las expresiones hijas:

<b:with value='data:post.labels any (l => l.name == "Featured")' var='isFeatured'>
  <b:with value='data:view.isHomepage or data:view.isMultipleItems' var='isStreamView'>
    <b:if cond='data:isFeatured and data:isStreamView and data:post.featuredImage'>
      <!-- Show Featured -->
    </b:if>
  </b:with>
</b:with>

2. Reutilización directa de objetos

En lugar de construir diccionarios literales que pasen cada campo individualmente en llamadas a <b:include>, conviene pasar el objeto padre directamente y extraer sus propiedades dentro de la subrutina <b:includable> receptora.

Conclusión

El límite de 40 tokens no representa un obstáculo si se comprende la lógica del analizador léxico de Blogger. Saber que las claves de los objetos y los saltos de línea no tienen costo, y que las rutas anidadas cuentan como un único operando, permite escribir plantillas avanzadas evitando el error Invalid expression.

Si tienes alguna duda sobre el conteo de alguna expresión en particular, o quieres compartir tus propios hallazgos, deja tu comentario abajo.