Posibles Organizaciones del Proyecto
Las jerarquías de ficheros presentadas son orientativas.
Resultar conveniente aislar en clases y en módulos el analizador léxico, el sintáctico, el runner, etc.
Ejemplo 1
➜ egg-4-alu0100966589 git:(master) ✗ tree -I 'node_modules|docs'
.
├── README.md
├── bin
│ └── egg.js
├── examples
│ ├── a.egg
│ ├── array.egg
│ ├── bad-function.egg
│ ├── curlyBrackets.egg
│ ├── differentParenthesis.egg
│ ├── error.egg
│ ├── greater-x-5.egg
│ ├── if.egg
│ ├── main.js
│ ├── main2.js
│ ├── map.egg
│ ├── obj.egg
│ ├── objects.egg
│ ├── one-err-2.egg
│ ├── one-err.egg
│ ├── one.egg
│ ├── require.egg
│ ├── rest.egg
│ ├── scope.egg
│ ├── spread.egg
│ ├── string.egg
│ ├── stringRegexp.egg
│ ├── sum.egg
│ └── two.egg
├── gulpfile.js
├── lib
│ ├── ast_nodes.js
│ ├── egg_repl.js
│ ├── eggvm.js
│ ├── lexer
│ │ └── token
│ │ ├── Token.js
│ │ ├── token_info.js
│ │ └── token_types.js
│ ├── parse.js
│ ├── public.js
│ ├── repl_plugins.js
│ ├── specialForms.js
│ ├── topEnv.js
│ └── utils
│ └── getSetElement.js
├── package-lock.json
├── package.json
├── plugins
│ ├── loops.js
│ ├── object.js
│ └── require.js
└── test
├── eggvm.test.js
├── lexer.test.js
├── program.test.js
└── test.js
8 directories, 48 files
Scripts
Scripts:
➜ egg-4-alu0100966589 git:(master) ✗ npm run
Lifecycle scripts included in @alu0100966589/egg:
test
mocha
available via `npm run-script`:
watch
mocha --watch
compile
./bin/egg.js -c
interpret
./bin/egg.js -i
run
./bin/egg.js -r
repl
./bin/egg.js
compile-example
./bin/egg.js -c examples/a.egg
interpret-example
./bin/egg.js -i examples/a.egg.evm
run-example
./bin/egg.js -r examples/a.egg
Ejemplo de uso. Dados los ficheros:
➜ egg-4-alu0100966589 git:(master) ✗ cat examples/require.egg
do(
def(str, require("examples/a.egg")),
print(str)
)
➜ egg-4-alu0100966589 git:(master) ✗ cat examples/a.egg
print("\thello\nworld\u2764")
Podemos ejecutarlo de esta forma:
➜ egg-4-alu0100966589 git:(master) ✗ bin/egg.js -p ../plugins/require.js -r examples/require.egg
hello
world❤
hello
world❤
Ejemplo 2
Este es un ejemplo de como organizar su jerarquía de ficheros de una forma escalable:
[.../TFA-04-16-2020-03-22-00/davafons(master)]$ tree -I 'node_modules|docs'
.
├── LICENSE
├── README.md // Documentación del paquete y del proyecto
├── bin
│ └── egg.js // usando opciones en línea de comandos: -c compilar, -i interpretar, etc
├── esdoc.json // documentación: vea https://esdoc.org/
├── docs
│ └── ... // Documentación generada. Configurar GitHub Pages
├── examples // Ejemplos: son reutilizados en las pruebas
│ ├── array-index.egg
| ├── ...
│ ├── trycatch.egg.evm
│ ├── two.egg
│ └── two.egg.evm
├── index.js // Entry point: exporta todo lo que necesita el ejecutable
├── lib
│ ├── interp
│ │ ├── arithm.js // Extensiones aritméticas: ++, --, +=, ...
│ │ ├── ast.js // Las clases del AST: Value, Word, Apply, Regex, ...
│ │ ├── eggvm.js // Clase con los runners: runFromFile, runFromEVM, run, ...
│ │ ├── environment.js // main del environment. Exporta SpecialForms y TopEnv. Usa registry
│ │ ├── exceptions.js // Extiende Egg con try, throw, ...
│ │ ├── index.js // main: exporta todas las clases del intérprete: Eggvm, Value, Word, Apply, Regex, TopEnv, SpecialForms, ...
│ │ ├── monkey-patching.js // Manipulacion de las clases de JS (Object, Array, etc.)
│ │ ├── registry.js // Exporta los mapas para exensión SpecialForms, TopEnv, ...
│ │ └── require.js // Soporte para módulos en Egg
│ ├── parser
│ │ ├── index.js // main de Parser: exporta todas las clases públicas: Eggvm,Value, Word, Apply, Regex, TopEnv, SpecialForms ...
│ │ ├── json2AST.js // Desde el JSON construimos el AST con clases
│ │ ├── lexer.js // Exporta Clase Analizador Léxico. Usa tokenRe
│ │ ├── optimizer.js // Optimizaciones (constant folding)
│ │ ├── parse.js // Análisis Sintáctico
│ │ ├── semantic.js // Análisis Semántico
│ │ └── tokenRegex.js //Exporta la clase para los objetos Token
│ ├── repl // soporte para Repeat Evaluate Print Loop
│ │ ├── colors.js // Colorines usando ansi-colors
│ │ ├── extensions.js // Extensiones: help() info() clear() ...
│ │ └── repl.js // El bucle
│ └── utils.js // Helpers comunes
├── package-lock.json // bajo control de versiones
├── package.json // configurado para publicar como módulo en GitHub registry
└── test
├── examples-test.js // Ejecución de ejemplos contra salida esperada
├── ...
└── tokenRegex-test.js
Scripts
Es conveniente tener algunos scripts preparados en el package.json
como:
.../TFA-04-16-2020-03-22-00/davafons(master)]$ npm run
Lifecycle scripts included in eggtended-js:
test
nyc mocha
available via `npm run-script`:
coverage
nyc report --reporter=text-lcov | coveralls
docs
esdoc -c esdoc.json
coverage
: tests y cubrimiento usando Istanbul command line interfacedocs
: esdoc usage
Ejemplo 3
➜ cristo-daniel-luciana-tfa-1920-egg git:(master) ✗ tree -I 'docs|node_modules'
.
├── README.md
├── bin
│ ├── egg.js
│ ├── eggRun.js
│ ├── eggc.js
│ └── evm.js
├── examples
│ ├── arithm.egg
│ ├── array-properties.egg
│ ├── calling-function-err.egg
│ ├── compile-to-js # Traducción a JavaScript. Comprobaciones
│ │ ├── casiano-spread.egg
│ │ ├── casiano-spread.egg.js
│ │ ├── empty-funcion.egg
│ │ ├── empty-funcion.egg.js
│ │ ├── for-each.egg
│ │ ├── for-each.egg.js
│ │ ├── for.egg
│ │ ├── for.egg.js
│ │ ├── fun-default-value.egg
│ │ ├── fun-default-value.egg.js
│ │ ├── fun.egg
│ │ ├── fun.egg.js
│ │ ├── if.egg
│ │ ├── if.egg.js
│ │ ├── map.egg
│ │ ├── map.egg.js
│ │ ├── object.egg
│ │ ├── object.egg.js
│ │ ├── prueba.egg
│ │ ├── prueba.egg.js
│ │ ├── regex-2.egg
│ │ ├── regex-2.egg.js
│ │ ├── while.egg
│ │ ├── while.egg.evm
│ │ └── while.egg.js
│ ├── constant-folding # Plegado de Constantes. Transformación Árbol
│ │ ├── advanced-folding.egg
│ │ ├── advanced-folding.egg.evm
│ │ ├── basic-folding.egg
│ │ └── basic-folding.egg.evm
│ ├── constant-propagation
│ │ ├── basic-propagation.egg
│ │ └── basic-propagation.egg.evm
│ ├── define-err.egg
│ ├── define.egg
│ ├── if-example-err.egg
│ ├── if-example.egg
│ ├── looping-invariance
│ │ ├── function-invariance.egg
│ │ ├── function-invariance.egg.evm
│ │ ├── while-invariance.egg
│ │ └── while-invariance.egg.evm
│ ├── map-js-chain.egg
│ ├── method-concatenation.egg
│ ├── method.egg
│ ├── method.egg.js
│ ├── method2.egg
│ ├── method3.egg
│ ├── multi-sub-array.egg
│ ├── number-as-fun-err.egg
│ ├── one.egg
│ ├── one.egg.evm
│ ├── probando.egg
│ ├── require
│ │ ├── client.egg
│ │ ├── client.egg.expected
│ │ └── module.egg
│ ├── reto.egg
│ ├── reto.egg.js
│ ├── scope-err.egg
│ ├── scope.egg
│ ├── set-multiarray.egg
│ ├── setting-undefined-err.egg
│ ├── string-apply.egg
│ ├── string-apply.egg.evm
│ ├── two.egg
│ ├── two.egg.evm
│ ├── while-err.egg
│ ├── while.egg
│ └── while.egg.evm
├── lib
│ ├── addon
│ │ ├── constant-folding.js
│ │ ├── looping-invariance.js
│ │ ├── require.js
│ │ └── scope-analysis.js
│ ├── compile-to-javascript
│ │ └── eggtojscompiler.js
│ ├── interp
│ │ ├── arithm.js
│ │ ├── ast.js
│ │ ├── eggvm.js
│ │ ├── monkey-patching.js
│ │ └── registry.js
│ ├── parser
│ │ ├── json2AST.js
│ │ └── parse.js
│ ├── repl
│ │ ├── colors.js
│ │ ├── egg-repl.js
│ │ └── extensions.js
│ └── utils.js
├── package-lock.json
├── package.json
└── test
├── examples
│ ├── array-index.egg
│ ├── array-index.egg.expected
│ ├── array-neg.egg
│ ├── array-neg.egg.expected
│ ├── array-properties.egg
│ ├── array-properties.egg.expected
│ ├── array-set-index.egg
│ ├── array-set-index.egg.expected
│ ├── calling-function-err.egg
│ ├── class
│ │ ├── class-1-err.egg
│ │ ├── class-1.egg
│ │ ├── class-1.egg.evm
│ │ ├── class-1.egg.expected
│ │ ├── class-cons-err.egg
│ │ ├── class-multiple-method.egg
│ │ ├── class-multiple-method.egg.expected
│ │ ├── method-invariance.egg
│ │ ├── method-invariance.egg.evm
│ │ ├── method-invariance.egg.expected
│ │ ├── multiple-class-object.egg
│ │ ├── multiple-class-object.egg.expected
│ │ ├── multiple-objects.egg
│ │ └── multiple-objects.egg.expected
│ ├── compile-to-js
│ │ ├── casiano-spread.egg
│ │ ├── casiano-spread.egg.js
│ │ ├── empty-funcion.egg
│ │ ├── empty-funcion.egg.js
│ │ ├── for-each.egg
│ │ ├── for-each.egg.js
│ │ ├── for.egg
│ │ ├── for.egg.js
│ │ ├── fun-default-value.egg
│ │ ├── fun-default-value.egg.js
│ │ ├── fun.egg
│ │ ├── fun.egg.js
│ │ ├── if.egg
│ │ ├── if.egg.js
│ │ ├── map.egg
│ │ ├── map.egg.js
│ │ ├── method-concatenation.egg
│ │ ├── method-concatenation.egg.js
│ │ ├── object.egg
│ │ ├── object.egg.js
│ │ ├── prueba.egg
│ │ ├── prueba.egg.js
│ │ ├── regex-2.egg
│ │ ├── regex-2.egg.js
│ │ ├── while.egg
│ │ └── while.egg.js
│ ├── const-definition-err.egg
│ ├── constant-folding
│ │ ├── advanced-folding.egg
│ │ ├── advanced-folding.egg.evm
│ │ ├── basic-folding.egg
│ │ └── basic-folding.egg.evm
│ ├── constant-propagation
│ │ ├── advanced-propagation.egg
│ │ ├── advanced-propagation.egg.evm
│ │ ├── advanced-scope-error.egg
│ │ ├── arithmetic-constant-folding.egg
│ │ ├── arithmetic-constant-folding.egg.evm
│ │ ├── basic-propagation.egg
│ │ ├── basic-propagation.egg.evm
│ │ ├── function-scope-error.egg
│ │ └── scope-error.egg
│ ├── child # Herencia a la JS
│ │ ├── child-casiano.egg
│ │ ├── child-casiano.egg.evm
│ │ ├── child-casiano.egg.expected
│ │ ├── child-modify.egg
│ │ ├── child-modify.egg.expected
│ │ ├── child-no-object.egg
│ │ ├── multiple-child.egg
│ │ └── multiple-child.egg.expected
│ ├── default-values # Valores por defecto en los parámetros de una función
│ │ ├── fun-default-error.egg
│ │ ├── fun-default-value.egg
│ │ ├── fun-default-value.egg.expected
│ │ └── more-arguments.egg
│ ├── define.egg
│ ├── define.egg.expected
│ ├── dot-num.egg
│ ├── dot-num.egg.expected
│ ├── dot-obj-2.egg
│ ├── dot-obj-2.egg.expected
│ ├── dot.egg
│ ├── dot.egg.evm
│ ├── dot.egg.expected
│ ├── for.egg
│ ├── for.egg.evm
│ ├── for.egg.expected
│ ├── foreach.egg
│ ├── foreach.egg.expected
│ ├── if-example-err.egg
│ ├── if-example.egg
│ ├── if-example.egg.expected
│ ├── looping-invariance
│ │ ├── 2-for-invariance.egg
│ │ ├── 2-for-invariance.egg.evm
│ │ ├── 2-whiles-invariance.egg
│ │ ├── 2-whiles-invariance.egg.evm
│ │ ├── 2-whiles-invariance.egg.expected
│ │ ├── alone-function.egg
│ │ ├── alone-function.egg.evm
│ │ ├── for-invariance.egg
│ │ ├── for-invariance.egg.evm
│ │ ├── function-invariance.egg
│ │ ├── function-invariance.egg.evm
│ │ ├── if-invariance.egg
│ │ ├── if-invariance.egg.evm
│ │ ├── if-invariance.egg.expected
│ │ ├── test.egg
│ │ ├── test.egg.evm
│ │ ├── while-invariance-2.egg
│ │ ├── while-invariance-2.egg.evm
│ │ ├── while-invariance.egg
│ │ └── while-invariance.egg.evm
│ ├── map-colon.egg
│ ├── map-colon.egg.expected
│ ├── map-js-chain.egg
│ ├── map-js-chain.egg.expected
│ ├── map-sub.egg
│ ├── map-sub.egg.expected
│ ├── map.egg
│ ├── map.egg.evm
│ ├── map.egg.expected
│ ├── method-concatenation.egg
│ ├── method-concatenation.egg.expected
│ ├── method.egg
│ ├── method.egg.expected
│ ├── method2.egg
│ ├── method2.egg.expected
│ ├── method3.egg
│ ├── method3.egg.expected
│ ├── multi-sub-array.egg
│ ├── multi-sub-array.egg.expected
│ ├── objects.egg
│ ├── objects.egg.evm
│ ├── objects.egg.expected
│ ├── one.egg
│ ├── one.egg.expected
│ ├── regex-2.egg
│ ├── regex-2.egg.evm
│ ├── regex-2.egg.expected
│ ├── regex-simple.egg
│ ├── regex-simple.egg.expected
│ ├── require
│ │ ├── client.egg
│ │ ├── client.egg.expected
│ │ └── module.egg
│ ├── reto.egg
│ ├── reto.egg.expected
│ ├── scope-err.egg
│ ├── scope-err.egg.expected
│ ├── scope.egg
│ ├── scope.egg.expected
│ ├── set-error.egg
│ ├── set-multiarray.egg
│ ├── set-multiarray.egg.expected
│ ├── setting-undefined-err.egg
│ ├── spread-operator # Operator ... en Egg
│ │ ├── casiano-spread.egg
│ │ ├── casiano-spread.egg.evm
│ │ ├── casiano-spread.egg.expected
│ │ ├── default-spread.egg
│ │ ├── default-spread.egg.expected
│ │ ├── function-spread.egg
│ │ ├── function-spread.egg.expected
│ │ ├── spread-operator.egg
│ │ └── spread-operator.egg.expected
│ ├── string-apply.egg
│ ├── string-apply.egg.evm
│ ├── string-apply.egg.expected
│ ├── while.egg
│ └── while.egg.expected
├── extra-test.js
├── scopes.js
└── test.js
24 directories, 263 files
Opciones del ejecutable
➜ cristo-daniel-luciana-tfa-1920-egg git:(master) ✗ node bin/eggRun.js --help
Options:
--version Muestra número de versión [booleano]
--compile, -c Input egg File to compile [cadena de caracteres]
--run, -f Run egg file from file [cadena de caracteres]
--repl, -r executes egg repl [booleano]
--evm, -e Runs an egg program from its evm file
[cadena de caracteres]
--addons, -a Lets you use different addons, like require [tabla]
--optimization, -o Optimizes the ast with constants folding [booleano]
--javascript, -j Compiles to a new javascript file [cadena de caracteres]
--help, -h Muestra ayuda [booleano]
Ejemplos de Ejecución
Dado el programa egg:
➜ cristo-daniel-luciana-tfa-1920-egg git:(master) ✗ cat examples/constant-folding/advanced-folding.egg
do(
print(*(+(4, 6), -(/(8, 4), 1)))
)%
al compilarlo -c
con la opción de optimización activada -o
:
➜ cristo-daniel-luciana-tfa-1920-egg git:(master) ✗ node bin/eggRun.js -o -c examples/constant-folding/advanced-folding.egg
Nos produce como salida este AST en el que observamos el pliegue:
➜ cristo-daniel-luciana-tfa-1920-egg git:(master) ✗ cat examples/constant-folding/advanced-folding.egg.evm
{
"_type": "apply",
"_operator": {
"_type": "word",
"_value": "do"
},
"_args": [
{
"_type": "apply",
"_operator": {
"_type": "word",
"_value": "print"
},
"_args": [
{
"_type": "value",
"_value": 10
}
]
}
]
}%