Emacs Lisp es un dialecto de Lisp creado para GNU Emacs . Se utiliza para implementar la mayor parte de la funcionalidad de edición integrada en Emacs; el resto está escrito en C , al igual que el intérprete de Lisp .
El código Emacs Lisp se utiliza para modificar, extender y personalizar Emacs. Quienes no deseen escribir el código pueden usar la función Personalizar . Esta función proporciona un conjunto de páginas de preferencias que permiten al usuario configurar opciones y previsualizar su efecto en la sesión de Emacs en ejecución. Al guardar los cambios, Personalizar simplemente escribe el código Emacs Lisp necesario en el archivo de configuración del usuario , que puede configurarse como un archivo especial que solo utiliza Personalizar, para evitar la posibilidad de modificar el archivo del usuario.
Además de ser un lenguaje de programación que puede compilarse a bytecode [ 1 ] y a código máquina , [ 2 ] Emacs Lisp también puede funcionar como un lenguaje de scripting interpretado , muy parecido al shell Bourne de Unix o Perl , al llamar a Emacs en modo por lotes . De esta forma, puede llamarse desde la línea de comandos o a través de un archivo ejecutable, y sus funciones de edición, como los búferes y los comandos de movimiento, están disponibles para el programa igual que en el modo normal. No se presenta ninguna interfaz de usuario cuando Emacs se inicia en modo por lotes; simplemente ejecuta el script pasado como parámetro y sale, mostrando cualquier salida del script.
Emacs Lisp también se denomina Elisp , aunque también existen dialectos de Lisp más antiguos y no relacionados con ese nombre. [ 3 ] [ 4 ]
En comparación con otros dialectos de Lisp
Emacs Lisp está estrechamente relacionado con Maclisp , con cierta influencia posterior de Common Lisp . [ 5 ] Admite métodos de programación imperativos y funcionales . Lisp fue el lenguaje de extensión predeterminado para derivados de Emacs como EINE y ZWEI . Cuando Richard Stallman bifurcó Gosling Emacs en GNU Emacs, también eligió Lisp como lenguaje de extensión, debido a sus potentes características, incluida la capacidad de tratar las funciones como datos. Aunque el estándar Common Lisp aún no se había formulado, Scheme existía en ese momento, pero Stallman optó por no usarlo debido a su rendimiento relativamente bajo en estaciones de trabajo (en relación con las minicomputadoras que eran el hogar tradicional de Emacs), y quería desarrollar un dialecto que, según él, sería más fácil de optimizar. [ 6 ]
El dialecto Lisp utilizado en Emacs difiere sustancialmente de los dialectos más modernos Common Lisp y Scheme, empleados en la programación de aplicaciones. Una característica destacada de Emacs Lisp es su uso predeterminado de ámbito dinámico en lugar de ámbito léxico . Es decir, una función puede hacer referencia a variables locales en el ámbito desde el que se la llama, pero no en el ámbito donde se definió. Recientemente, se ha estado trabajando para actualizar el código y utilizar el ámbito léxico, por las razones que se explican a continuación.
Ejemplo
El desarrollo de Emacs Lisp se guió por el objetivo de proporcionar estructuras de datos y características específicas para crear un editor de texto versátil, en lugar de implementar un lenguaje de programación de propósito general. Por ejemplo, Emacs Lisp no puede leer fácilmente un archivo línea por línea; es necesario leer el archivo completo en un búfer de Emacs. Sin embargo, Emacs Lisp ofrece muchas funciones para navegar y modificar el texto del búfer a nivel de oración, párrafo o nivel sintáctico superior, según lo definan los modos.
A continuación se muestra un ejemplo sencillo de una extensión de Emacs escrita en Emacs Lisp. En Emacs, el área de edición se puede dividir en áreas separadas llamadas ventanas , cada una de las cuales muestra un búfer diferente . Un búfer es una región de texto cargada en la memoria de Emacs (posiblemente desde un archivo) que se puede guardar en un documento de texto.
Los usuarios pueden pulsar la C-x 2combinación de teclas predeterminada para abrir una nueva ventana. Esto ejecuta la función de Emacs Lisp split-window-below. Normalmente, cuando aparece la nueva ventana, muestra el mismo búfer que la anterior. Supongamos que queremos que muestre el siguiente búfer disponible. Para ello, el usuario escribe el siguiente código de Emacs Lisp, ya sea en un archivo fuente de Emacs Lisp existente o en un búfer de Emacs vacío:
( defun my-split-window-func () ( interactive ) ( split-window-below ) ( set-window-buffer ( next-window ) ( other-buffer )))( global-set-key ( kbd "Cx 2" ) #' my-split-window-func )La primera instrucción (defun ...)define una nueva función my-split-window-funcque llama split-window-belowa la función anterior de división de ventanas y luego le indica a la nueva ventana que muestre otro búfer (nuevo). La segunda instrucción (global-set-key ...)reasigna la secuencia de teclas "Cx 2" a la nueva función.
Esto también se puede escribir utilizando la función llamada `advice` , que permite al usuario crear funciones auxiliares alrededor de funciones existentes en lugar de definir las suyas propias. Esto tiene las ventajas de no requerir cambios en las combinaciones de teclas, de funcionar dondequiera que se llame a la función original y de ser más sencillo de escribir, pero la desventaja de hacer que la depuración sea más compleja. Por esta razón, `advice` no está permitido en el código fuente de GNU Emacs, [ 7 ] pero si un usuario lo desea, puede utilizar la función `advice` en su código para reimplementar el código anterior de la siguiente manera:
( defadvice split-window-below ( after my-window-splitting-advice first () activate ) ( set-window-buffer ( next-window ) ( other-buffer )))Esto indica split-window-belowque se ejecute el código proporcionado por el usuario cada vez que se llame, después de ejecutar el resto de la función. También se puede especificar que el consejo se ejecute antes de la función original, alrededor de ella (literalmente envolviéndola) o que ejecute la función original de forma condicional según el resultado del consejo.
Emacs 24.4 reemplaza [ 8 ] este defadvicemecanismo con advice-add, que se afirma que es más flexible y simple. [ 9 ] El consejo anterior podría reimplementarse utilizando el nuevo sistema como:
( defun switch-to-next-window-in-split () ( set-window-buffer ( next-window ) ( other-buffer )))( advice-add 'split-window-below :before #' switch-to-next-window-in-split )Estos cambios surten efecto en cuanto se evalúa el código . No es necesario recompilar, reiniciar Emacs ni modificar el archivo de configuración. Si el código se guarda en un archivo de inicialización de Emacs, este cargará la extensión la próxima vez que se inicie. De lo contrario, los cambios deberán evaluarse manualmente al reiniciar Emacs.
Código fuente
El código fuente de Emacs Lisp se almacena en sistemas de archivos como archivos de texto plano , por convención con el sufijo de nombre de archivo " .el". El archivo de inicialización del usuario es una excepción, a menudo aparece como " .emacs" a pesar de ser evaluado como cualquier código Emacs Lisp. Desde mediados de la década de 1990, Emacs también carga ~/.emacs.ely ~/.emacs.d/init.el. Además, los usuarios pueden especificar cualquier archivo para cargar como archivo de configuración en la línea de comandos, o indicar explícitamente que no se cargue ningún archivo de configuración. Cuando se cargan los archivos, un componente intérprete del programa Emacs lee y analiza las funciones y variables, almacenándolas en memoria. Luego están disponibles para otras funciones de edición y para los comandos del usuario. Las funciones y variables se pueden modificar y redefinir libremente sin reiniciar el editor ni recargar el archivo de configuración.
Para ahorrar tiempo y memoria, gran parte de la funcionalidad de Emacs se carga solo cuando es necesaria. Cada conjunto de características opcionales incluidas en Emacs se implementa mediante una colección de código Emacs denominada paquete o biblioteca . Por ejemplo, existe una biblioteca para resaltar palabras clave en el código fuente de un programa y otra para jugar al Tetris . Cada biblioteca se implementa utilizando uno o más archivos fuente de Emacs Lisp. Las bibliotecas pueden definir uno o más modos principales para activar y controlar su funcionamiento.
Los desarrolladores de Emacs escriben ciertas funciones en C. Estas son primitivas , también llamadas funciones integradas o subrutinas . Aunque las primitivas se pueden llamar desde código Lisp, solo se pueden modificar editando los archivos fuente de C y recompilando. En GNU Emacs , las primitivas no están disponibles como bibliotecas externas; forman parte del ejecutable de Emacs. En XEmacs , es posible cargar dichas primitivas en tiempo de ejecución, utilizando la compatibilidad del sistema operativo con el enlace dinámico . Las funciones pueden escribirse como primitivas porque necesitan acceso a datos y bibliotecas externas que no están disponibles en Emacs Lisp, o porque se llaman con la suficiente frecuencia como para que la diferencia de velocidad entre C y Emacs Lisp sea significativa.
Sin embargo, debido a que los errores en el código C pueden provocar fácilmente violaciones de segmentación o errores más sutiles que bloquean el editor, y debido a que escribir código C que interactúe correctamente con el recolector de basura de Emacs Lisp es propenso a errores, el número de funciones implementadas como primitivas se mantiene al mínimo necesario.
Código de bytes
La compilación de bytecode puede acelerar la ejecución del código Emacs Lisp. Emacs incluye un compilador que traduce los archivos fuente de Emacs Lisp a una representación especial denominada bytecode . Los archivos de bytecode de Emacs Lisp tienen el sufijo " .elc". En comparación con los archivos fuente, los archivos de bytecode se cargan y ejecutan más rápido, ocupan menos espacio en disco y consumen menos memoria al cargarse.
El código de bytes sigue siendo más lento que las funciones primitivas, pero las funciones cargadas como código de bytes se pueden modificar y recargar fácilmente, y los archivos de código de bytes son software multiplataforma . El código estándar de Emacs Lisp distribuido con Emacs se carga como código de bytes, aunque los archivos fuente correspondientes también se proporcionan como referencia para el usuario. Las extensiones proporcionadas por el usuario generalmente no se compilan como código de bytes, ya que no son tan grandes ni requieren tanta capacidad de cálculo.
Características del idioma
El paquete "cl-lib" implementa un subconjunto bastante grande de Common Lisp . Este paquete reemplaza a un paquete "cl" anterior, que sobrescribía las definiciones de funciones existentes de Emacs Lisp con otras más similares a las que se encuentran en Common Lisp. El paquete "cl-lib", por otro lado, sigue más de cerca las directrices de estilo de Emacs Lisp y antepone "cl-" a cada función y macro que define (por ejemplo, cl-defun, lo que no entra en conflicto con el nombre de la función integrada defun), evitando los cambios inesperados de comportamiento que podían ocurrir cuando se cargaba el paquete "cl".
Emacs Lisp (a diferencia de otras implementaciones de Lisp) no realiza optimización de llamadas recursivas de cola . [ 10 ] Sin esto, las recursiones de cola pueden eventualmente provocar un desbordamiento de pila .
La biblioteca apel facilita la escritura de código Emacs Lisp portable, con la ayuda del puente de plataforma polysylabi.
Emacs Lisp es un Common Lisp similar a Lisp-2 , lo que significa que tiene un espacio de nombres de funciones separado del espacio de nombres que utiliza para otras variables. [ 11 ]
Del alcance dinámico al alcance léxico
Al igual que MacLisp, Emacs Lisp utiliza ámbito dinámico , ofreciendo ámbito estático (o léxico) como opción a partir de la versión 24. [ 12 ] Se puede activar configurando la variable local de archivo lexical-binding. [ 13 ] [ 14 ] Antes de que se añadiera esta opción, se podía usar la lexical-letmacro del paquete "cl" (ahora obsoleto) para proporcionar un ámbito léxico efectivo. [ 15 ]
En el ámbito dinámico, si un programador declara una variable dentro del ámbito de una función, está disponible para las subrutinas llamadas desde dentro de esa función. Originalmente, esto se concibió como una optimización ; el ámbito léxico aún era poco común y de rendimiento incierto. En el recuerdo del científico informático Olin Shivers, "Le pregunté a RMS cuando estaba implementando emacs lisp por qué tenía ámbito dinámico y su respuesta exacta fue que el ámbito léxico era demasiado ineficiente". [ 16 ] El ámbito dinámico también estaba destinado a proporcionar mayor flexibilidad para las personalizaciones del usuario. Sin embargo, el ámbito dinámico tiene varias desventajas. En primer lugar, puede provocar fácilmente errores en programas grandes, debido a interacciones no deseadas entre variables en diferentes funciones. En segundo lugar, el acceso a variables bajo ámbito dinámico es generalmente más lento que bajo ámbito léxico .
Referencias
- ↑ "Compilación de bytes de Emacs Lisp" . Manual de GNU Emacs . Consultado el 14 de junio de 2024 .
- ↑ "Compilación de Emacs Lisp a código nativo" . Manual de GNU Emacs . Consultado el 14 de junio de 2024 .
- ↑ HEDRICK en RUTGERS (Gerente de DEC-20/Director de la Instalación de Computación LCSR (18-12-1981) ."Información sobre la implementación de Common Lisp"" . Carta a rpg en SU-AI, jonl en MIT-AI. Archivado del original el 2016-09-20 . Recuperado el 2019-07-28 .
Ahora tenemos algo de experiencia en la implementación de Lisp, ya que Elisp (la implementación extendida de Rutgers/UCI Lisp) está prácticamente terminada.
{{cite press release}}: CS1 maint: nombres numéricos: lista de autores ( enlace ) - ↑ "Anuncio de CCA EMACS". Unix Review . Diciembre de 1984. pág. 16.
CCA EMACS y Elisp son marcas comerciales de CCA Uniworks, Inc.
- ↑ "GNU Emacs Lisp se inspira en gran medida en Maclisp y un poco en Common Lisp. Si conoces Common Lisp, notarás muchas similitudes. Sin embargo, muchas características de Common Lisp se han omitido o simplificado para reducir los requisitos de memoria de GNU Emacs. A veces, las simplificaciones son tan drásticas que un usuario de Common Lisp podría confundirse mucho. Ocasionalmente, señalaremos en qué se diferencia GNU Emacs Lisp de Common Lisp." – de la sección "Historia" de la "Introducción" del Manual de Emacs Lisp, a partir de Emacs 21.
- ↑ "Así pues, el desarrollo de ese sistema operativo, el sistema operativo GNU, fue lo que me llevó a escribir GNU Emacs. Al hacerlo, mi objetivo era crear la implementación de Lisp más mínima posible. El tamaño de los programas era una preocupación enorme. En aquella época, en 1985, había gente que tenía ordenadores de un megabyte sin memoria virtual. Querían poder usar GNU Emacs. Esto significaba que tenía que mantener el programa lo más pequeño posible." – de "Mis experiencias con Lisp y el desarrollo de GNU Emacs"
- ↑ "Re: [ Emacs-diffs ] /srv/bzr/emacs/trunk r111086: gmm-utils.el (gmm-flet" . Lists.gnu.org. 2012-12-05 . Consultado el 2013-08-18 .
- ↑ "NOTICIAS.24.4" .
- ↑ "Adaptando consejos antiguos" .
- ↑ "Apéndice C: Adaptación de Common Lisp" . Gnu.org . Consultado el 28 de octubre de 2019. Los
programadores de Lisp deben tener en cuenta que el compilador actual de Emacs Lisp no optimiza la recursión de cola.
- ↑ "Grupos de Google" . groups.google.com .
- ↑ "Emacs 24.1 publicado" . Lists.gnu.org . Consultado el 18 de agosto de 2013 .
- ↑ "Línea léxica" . Lists.gnu.org. 1 de abril de 2011. Consultado el 18 de agosto de 2013 .
- ↑ "Enlace dinámico vs. enlace léxico" . EmacsWiki. 17 de mayo de 2013. Consultado el 18 de agosto de 2013 .
- ↑ "Enlace léxico obsoleto" . Emulación de Common Lisp de GNU Emacs . GNU Press . Consultado el 27 de mayo de 2021 .
- ↑ "T" . People.csail.mit.edu . Consultado el 18 de agosto de 2013 .
Enlaces externos
- Sitio web oficial del Proyecto GNU
- Manual de referencia de Emacs Lisp , Proyecto GNU
- Introducción a la programación en Emacs Lisp , Proyecto GNU
- Elementos de Emacs Lisp , del sitio web de Protesilaos Stavrou.
- Lenguajes de programación con ámbito dinámico
- Emacs
- Compiladores libres y de código abierto
- Intérpretes de código abierto y libre
- Familia de lenguajes de programación Lisp
- Lenguajes de scripting
- Editores de texto
- Lenguajes de programación creados en 1985
- Implementaciones del lenguaje de programación Lisp del Proyecto GNU