El artículo presenta la disciplina de diseño empleada para construir Yuku, un analizador sintáctico (parser) de JavaScript y TypeScript escrito en Zig que supera en velocidad a los analizadores establecidos de su categoría, y cuyas técnicas son aplicables a cualquier frontend de compilador en un lenguaje nativo. La tesis central sostiene que el rendimiento de un parser se decide mucho antes del primer benchmark, en cómo el árbol sintáctico se representa en memoria: diseñar primero la estructura de datos, dejando que los patrones de acceso de la máquina dictaminen su forma, hace que la velocidad llegue casi de forma gratuita y que problemas aparentemente no relacionados (distribución de memoria, asignación y serialización) converjan en una sola solución.
Dos hechos del hardware moderno sostienen el argumento. Un fallo de caché que obliga a ir a memoria principal cuesta del orden de cien nanosegundos, frente a una fracción para una operación en coma flotante, de modo que un parser que persigue punteros queda limitado por la latencia de memoria más que por el cálculo. Además, una llamada al asignador de propósito general no es gratuita: un parser que asigna un nodo cada vez paga ese coste millones de veces y dispersa los objetos relacionados por toda la memoria. Como ejemplo concreto, un fichero de cien mil bytes produce unos cincuenta mil nodos del AST; como objetos enlazados por punteros, implica cincuenta mil asignaciones, otras tantas liberaciones y cada recorrido posterior persigue punteros hacia memoria fría, mientras que, en un único array plano, se reduce a unas pocas asignaciones, un recorrido lineal y un único teardown.
El texto critica el diseño tradicional del AST como árbol de structs asignados en heap y unidos por punteros, enumerando sus costes: asignación por nodo, persecución de punteros con cargas impredecibles, sobrecarga de ocho bytes por arista en arquitecturas de 64 bits, fragmentación y teardown costoso, y variantes de tamaño muy desigual que desperdiciarían espacio en un array ingenuo. La solución propuesta se articula en varios movimientos. Primero, sustituir cada puntero por un índice entero (u32) en un único array plano de nodos, lo que reduce el tamaño de las referencias, independiza el árbol del espacio de direcciones (facilitando serialización e interoperabilidad entre lenguajes) y codifica la ausencia de hijo con un valor reservado en lugar de un opcional. Toda la memoria se posee desde un arena allocator: configurarlo y destruirlo ocurre dos veces (plano de control), mientras que añadir nodos individuales se reduce a incrementar un índice con crecimiento geométrico ocasional (plano de datos), sacando al asignador del camino caliente.
El árbol se construye de abajo arriba: una rutina de análisis produce primero sus hijos y se añade a sí misma la última; el método append devuelve el índice del nuevo nodo, que el padre almacena como hijo en lugar de un puntero. El algoritmo de análisis en sí permanece convencional, con descenso recursivo mediante ascenso de precedencia, y la única diferencia respecto a la versión de manual es que left y right son índices u32. Después, el artículo aborda el struct of arrays (SoA): un nodo lleva un payload que dice qué es y un span de código fuente que dice dónde está; almacenados como array de structs, ambos viajan juntos y cualquier pasada que solo lea uno arrastra al otro por la caché. La solución es mantener dos columnas paralelas (payloads y spans) bajo el mismo índice, de forma que una pasada que solo consulta tipos de nodo toque una columna densa y otra que solo lee spans toque la otra. La decisión de qué incluir en la columna de payload admite dos respuestas válidas —el nodo mínimo para un frontend interno sin consumidores externos, u otra variante más rica— y la elección depende de quién consuma el AST. En conjunto, el artículo muestra que la parte exótica es la estructura de datos y el algoritmo que opera sobre ella puede permanecer completamente ordinario.
