Egg Parser
Objetivos
Usando el generador de analizadores Nearley.js escriba un parser para el lenguaje Egg que genere los árboles según la especificación que se describe en la sección ASTs: Árboles de Análisis Abstracto. Utilice el generador de analizadores léxicos moo-ignore para la fase de análisis léxico.
Construya un paquete npm y
publíquelo en GitHub Registry con ámbito @ull-esit-pl-2324
y nombre el nombre del repo asignado.
El módulo exportará un objeto con al menos la propiedad { parseFromfile }
.
parseFromFile(inputFile)
es una función que devuelve el AST construído a partir de los contenidos del programa en lenguaje Egg contenido en el fichero con nombreinputFile
La gramática del lenguaje Egg se describe en la sección Gramáticas Independientes del Contexto. This is the equivalent syntax diagram:
Se deberá proveer un ejecutable eggc
con una interfaz como esta:
➜ prefix-lang git:(master) ✗ bin/eggc.js -h
Usage: eggc [options] <origin>
Compile a Egg lang file
Arguments:
origin The path of the file to compile
Options:
-V, --version output the version number
-o, --out <destination> Path for output file. If it isn't specified the path of the origin file will be
used,changing the extension to .json
-h, --help display help for command
Puede usar el ejecutable evm
(las siglas corresponden a Egg virtual Machine) del paquete "@crguezl/eloquentjsegg" (opens in a new tab) para comprobar que los ASTs generados funcionan.
Sigue un ejemplo (compatible "@crguezl/eloquentjsegg" (opens in a new tab) versión 1.2.6) de como debería funcionar nuestro parser eggc
:
➜ prefix-lang git:(master) ✗ cat test/examples/array.egg
do(
def(x, arr(arr(1,4),5,7)),
print([](x,0)), # [1,4]
print([](x,1)) # 5
)
Nuestro parser deberà por tanto producir un AST conforme a la especificación dada en la sección Anatomía de los AST para Egg. Esto es, deberá estar conforme a esta gramática árbol:
ast: VALUE
| WORD
| APPLY( operator:WORD args:[ ast * ]))
Los nodos APPLY
tienen dos atributos operator
y args
. El atributo args
es un ARRAY conteniendo los ASTs que se corresponden con los argumentos de operator
. Los nodos WORD
son nodos hoja y tienen al menos el atributo name
.
Los nodos VALUE
tienen al menos el atributo value
.
Por ejemplo, el AST para +(a,*(4,5))
se podría describir mediante este término:
APPLY(
operator: WORD{name: +},
args: [
WORD{name: a},
APPLY(
operator: WORD{name:*},
args: [VALUE{value:4}, VALUE{value:5}]
)
]
)
A la derecha del tipo de nodo y entre llaves escribimos las parejas atributo: valor
que nos interesa resaltar.
El ejecutable bin/eggc.js
deberá producir un fichero JSON con el ast:
✗ bin/eggc.js test/examples/array.egg -o test/ast/array.json
Puede ver los contenidos del ast para el ejemplo test/examples/array.egg (opens in a new tab) haciendo click sobre este enlace:
➜ prefix-lang git:(master) ✗ cat test/ast/array.json
A continuación podemos usar el ejecutable evm
para interpretar el árbol:
➜ prefix-lang git:(master) ✗ npx evm test/ast/array.json
[ 1, 4 ]
5
Observe que puesto que el paquete "@crguezl/eloquentjsegg" (opens in a new tab) ha sido instalado localmente, necesitamos hacer uso de npx (opens in a new tab) para ejecutar el intérprete evm
.
npx
npx <command>[@version] [command-arg]...
executes <command>
either from a local node_modules/.bin
, or
from a central cache, usually in ~/.npm/cacache
npm config get cache
/Users/casianorodriguezleon/.npm
✗ ls /Users/casianorodriguezleon/.npm/_cacache
content-v2 index-v5 tmp
installing any packages needed in order for <command>
to run. By default, npx
will check whether <command>
exists in $PATH
, or in the local project binaries, and execute that. If <command>
is not found, it will be installed prior to execution.
En el directorio node_modules/@crguezl/eloquentjsegg/examples
tiene algunos ejemplos de programas egg que puede usar para comprobar el buen funcionamiento de su parser:
➜ prefix-lang git:(master) ✗ ls node_modules/@crguezl/eloquentjsegg/examples
array.egg greater-x-5.egg main2.js one.egg sum.egg unbalanced.egg
expcomma.egg if.egg one-err-2.egg scope.egg sum.egg.evm
fun.egg main.js one-err.egg string.egg two.egg
Nota de Advertencia
En algunos de los ejemplos, vídeos, repos, etc. que acompañan esta práctica puede notar algunas
inconsistencias en el lenguaje Egg debidas a que casi en cada curso hemos ido haciendo alias de algunos de los nombres de los constructos. Por ejemplo, a veces en un vídeo en vez de fun
usamos ->
y en algún ejemplo en los apuntes en vez de element
se usa <-
, etc. También en algún ejemplo aparecen llavitas {
y }
en vez de paréntesis (de nuevo una llave aquí es un alias del correspondiente paréntesis). Son cambios triviales que no deberían afectar a la comprensión del texto.
Option run
The package @crguezl/eloquentjsegg
includes a function runFromEVM
that can be used to run the program after compiling it. Alternatively, you can extend your executable with an option --run
to run the program after compiling it.
➜ prefix-lang git:(moo-ignore) ✗ bin/eggc.js -h
Usage: eggc <origin> [options]
Arguments:
origin The path of the file to compile
Options:
-V, --version output the version number
-o, --out <destination> Path for output file. If it isn't specified the path of the origin file will be
used,changing the extension to .json
-r, --run Run the program after compiling it
-h, --help display help for command
Simply add a code like this inside the compile
function::
const compile = (origin, options) => {
let destination = options.out;
if (destination == undefined) {
destination = options.out = origin.match(/^[^.]*/)[0] + '.json';
}
const ast = parseFromFile(origin);
if (options.run) {
const { runFromEVM } = require('@crguezl/eloquentjsegg/lib/eggvm.js');
runFromEVM(options.out);
}
...
}
Publicación del módulo
Una parte de los conceptos y habilidades a adquirir con esta práctica se explican en la sección Creating and publishing a node.js module en GitHub y en NPM. Léala con detenimiento antes de hacer esta práctica.
Pruebas
Deberá añadir pruebas usando Mocha y Chai o Jest. Repase las secciones Testing with Mocha and Chai y Jest.
Añada un estudio de covering. See the notes in covering.
Añada CI con GitHub Actions.
Informe y Documentación
Documente el módulo incorporando un README.md
: Como se instala, como se usa el ejecutable, como se carga la librería, etc.
La documentación de la API de la función exportada usando JsDoc la puede dejar accesible en el despliegue (directorio docs/api
).
Añada el informe de Covering también (directorio docs/covering
o similar).
Challenge
- Asegúrese de producir mensajes de error significativos informando de los números de línea y columna correctos
Videos
Lab egg-parser 2024
Clase del 12/03/2024. Lexical Analysis of Egg with moo-ignore. Egg grammar in Nearley.jsVideos Lab egg-parser 2023
- Vídeo 2023/03/29: ASTs for Egg. Lexical Analysis with moo-ignore. Introduction to Nearley.js
- Vídeo 2023/04/10: Parsing Egg. More on Nearley.js
- Vídeo 2023/04/11: Building the Egg ASTs. White management in moo. The Earley algorithm
- Vídeo 2023/04/12: The Earley algorithm
Rubric
egg-parser Repos
References
Nearley.js
moo
- Tokenizers for nearley.js (opens in a new tab)
- moo-ignore (opens in a new tab)
- moo (opens in a new tab)
Testing
Documentation
- Vuepress (opens in a new tab)
- .nojekyll (opens in a new tab) Bypassing Jekyll on GitHub Pages
- JSDoc and others in this notes