Macros
- Las macros de Rust se usan para eliminar la duplicación de código y reducir la repetición.
- Los nodos de sentencias de
sqleibniz deben implementar el trait Node, lo que provoca mucha duplicación de código.
- Se pueden usar macros para automatizar la definición de structs y la implementación del trait
Node.
Macro para eliminar duplicación de código
- La macro define structs, agrega comentarios de documentación e implementa funciones que satisfacen el trait
Node.
- La macro puede agregar varios campos mediante definiciones repetitivas de metavariables.
Pruebas
- En Rust se puede implementar un enfoque similar a las pruebas basadas en tablas de Go.
- Se pueden probar varios pares de entrada y salida esperada usando las macros
test_group_pass_assert! y test_group_fail!.
Pruebas del parser
- En el módulo del parser también se usan macros similares para probar los resultados de las sentencias SQL.
- La función
sql_stmt_prefix se usa para probar sentencias SQL EXPLAIN.
Desventajas de las macros
rust-analyzer no funciona bien dentro de las macros y la documentación es escasa.
Coincidencia de caracteres
- La macro
matches! de Rust permite comparar caracteres fácilmente.
- Hay un ejemplo para verificar si un carácter dado es un número de SQLite.
Coincidencia de tokens
- Después de que el lexer convierte un flujo de caracteres en un flujo de tokens, el parser lo usa para crear el árbol sintáctico.
- Se usa la sentencia
match para reconocer tipos de token.
Visualización de errores
- El manejo de errores permite ofrecer mensajes de error claros al usuario.
Funcionalidad opcional
- El tipo
Option de Rust se usa para verificar si existe un valor, comprobar condiciones o proporcionar valores predeterminados.
- Métodos como
is_some_and, map y map_or ayudan a mejorar la legibilidad del código.
Iteradores
- Los iteradores de Rust se usan para filtrar caracteres y procesarlos de acuerdo con las reglas de SQLite para analizar números.
1 comentarios
Opiniones en Hacker News
Le costó usar Rust por el
borrow checkery la dificultad del manejo de memoria. Le gustaban los elementos de programación funcional (FP) de Rust, pero decidió buscar otro lenguaje. Encontró OCaml y quedó satisfechoParece que le faltaba experiencia con Rust y con ideas de PL. Cree que sería más sencillo definir el AST como tipos de datos algebraicos. Los macros funcionan de forma distinta en la mayoría de los lenguajes, pero se usan principalmente para eliminar duplicación de código y reducir repetición
Un parser escrito en Haskell destaca por su simplicidad y legibilidad. Se lee casi igual que BNF y tiene muy poco procedimiento técnico, así que permite enfocarse en la gramática real
Tiene experiencia escribiendo parsers con Ragel, Go, Java, C++, y C. Escribir un parser de JSON en C puede ser más simple que el código equivalente en Rust. La infraestructura para parsers ha avanzado hasta llegar al punto en que se pueden crear parsers con eBNF
Escribió un desensamblador y emulador de eBPF en Rust, y cree que Rust es adecuado para tareas de parsing. Sin embargo, usar macros se siente distinto a trabajar dentro del lenguaje mismo
Le gusta la charla de Rob Pike sobre escaneo léxico en Go. Es un enfoque educativo y elegante
Se puede usar una biblioteca de combinadores de parsers para desplegar parsers de protocolos de alto rendimiento en entornos embebidos. La misma biblioteca también puede usarse para escribir un parser de protocolos embebidos
Al escribir un parser completo de AST en Rust, le resultó difícil expresar la jerarquía de tipos concretos del AST. Tuvo que usar trucos de tipos extraños y macros
Parsear la sintaxis de sqlite es una tarea difícil. sqlite es una fuente de inspiración. Los diagramas de ferrocarril son muy útiles, y el generador de parsers Lemon no recibe suficiente reconocimiento
Los lenguajes con tipos de datos algebraicos son adecuados para parsear la sintaxis de sqlite. Typescript también podría ser una buena opción. Escribió una introducción breve sobre cómo escribir parsers en Rust