Lisp de Emacs

Ajustar Compartir Imprimir Citar
Dialect of Lisp used as an Emacs scripting language

Emacs Lisp es un dialecto del lenguaje de programación Lisp utilizado como lenguaje de secuencias de comandos por Emacs (una familia de editores de texto comúnmente asociada con GNU Emacs y XEmacs). Se utiliza para implementar la mayor parte de la funcionalidad de edición integrada en Emacs, el resto se escribe en C, al igual que el intérprete de Lisp. Emacs Lisp también se denomina Elisp, aunque también hay un dialecto Lisp más antiguo y no relacionado con ese nombre.

Los usuarios de Emacs suelen escribir código Emacs Lisp para personalizar y ampliar Emacs. Otras opciones incluyen la función Personalizar que ha estado en GNU Emacs desde la versión 20. Escrita en Emacs Lisp, Personalizar proporciona un conjunto de páginas de preferencias que permiten al usuario establecer opciones y obtener una vista previa de su efecto en la sesión de ejecución de Emacs. Cuando el usuario guarda sus cambios, Personalizar simplemente escribe el código Emacs Lisp necesario en el archivo de configuración del usuario, que se puede configurar en un archivo especial que solo usa Personalizar, para evitar la posibilidad de alterar la configuración del usuario. archivo propio.

Emacs Lisp también puede funcionar como un lenguaje de secuencias de comandos, al igual que el shell de Unix Bourne o Perl, llamando a Emacs en modo por lotes. De esta forma, puede llamarse desde la línea de comandos oa 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 como en el modo normal. No se presenta ninguna interfaz de usuario cuando se inicia Emacs en modo por lotes; simplemente ejecuta el script pasado y sale, mostrando cualquier resultado del script.

Comparado con otros dialectos Lisp

Emacs Lisp está más estrechamente relacionado con Maclisp, con alguna influencia posterior de Common Lisp. Admite métodos de programación imperativos y funcionales. Richard Stallman eligió Lisp como lenguaje de extensión para su reescritura de Emacs (el editor y corrector de texto (TECO) original usaba como lenguaje de extensión) debido a sus potentes características, incluida la capacidad de tratar funciones como datos. Aunque el estándar Common Lisp aún no se había formulado, Scheme existía en el momento en que Stallman estaba reescribiendo Gosling Emacs en GNU Emacs. Decidió no usarlo debido a su rendimiento comparativamente bajo en las estaciones de trabajo (a diferencia de las minicomputadoras que eran el hogar tradicional de Emacs), y quería desarrollar un dialecto que pensó que sería más fácil de optimizar.

El dialecto Lisp utilizado en Emacs difiere sustancialmente de los dialectos Common Lisp y Scheme más modernos utilizados para la programación de aplicaciones. Una característica destacada de Emacs Lisp es el uso predeterminado de un alcance dinámico en lugar de léxico. Es decir, una función puede hacer referencia a variables locales en el ámbito desde el que se llama, pero no en el ámbito en el que se definió. Recientemente, ha habido un esfuerzo continuo para actualizar el código para usar el alcance léxico, por las razones que se describen a continuación.

1955 1960 1965 1970 1975 1980 1985 1990 1995 2000 2005 2010 2015 2020
LISP 1, 1,5, LISP 2(abandonado)
Maclisp
Interlisp
MDL
Lisp Machine Lisp
Plan R5RS R6RS R7RS pequeño
NIL
ZIL (Zork Implementation Language)
Franz Lisp
Lisp común ANSI standard
Le Lisp
MIT Plan
T
Chez Scheme
Emacs Lisp
AutoLISP
PicoLisp
Gambit
EuLisp
ISLISP
OpenLisp
PLT Plan Racket
GNU Guile
Visual LISP
Clojure
Arc
LFE
Hy

Ejemplo

Para comprender la lógica detrás de Emacs Lisp, es importante recordar que se hace hincapié en proporcionar estructuras de datos y funciones 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 a línea; el archivo completo debe leerse en un búfer de Emacs. Sin embargo, Emacs Lisp proporciona muchas funciones para navegar y modificar el texto del búfer en una oración, párrafo o nivel sintáctico superior según lo definido por los modos.

Aquí sigue un ejemplo simple 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 Emacs' memoria (posiblemente de un archivo) que se puede guardar en un documento de texto.

Los usuarios pueden presionar la combinación de teclas predeterminada C-x 2 para abrir una nueva ventana. Esto ejecuta la función Emacs Lisp split-window-below. Normalmente, cuando aparece la nueva ventana, muestra el mismo búfer que la anterior. Supongamos que deseamos que muestre el siguiente búfer disponible. Para hacer esto, 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 () ()interactiva) ()split-window-below) ()set-window-buffer ()próxima ventanilla) ()otro amor))()global-set-key ()kbd "C-x 2") # 'my-split-window-func)

La primera declaración, (defun...), define una nueva función, my-split-window-func, que llama a split-window- debajo (la antigua función de división de ventanas), luego le dice a la nueva ventana que muestre otro (nuevo) búfer. La segunda instrucción, (global-set-key...) vuelve a vincular la secuencia de teclas "C-x 2" a la nueva función.

Esto también se puede escribir usando la característica llamada consejo, que permite al usuario crear envolturas alrededor de las funciones existentes en lugar de definir las suyas propias. Esto tiene la ventaja de no requerir que se cambien las combinaciones de teclas y funciona donde sea que se llame a la función original, además de ser más simple de escribir, pero la desventaja de hacer que la depuración sea más complicada. Por esta razón, los consejos no están permitidos en el código fuente de GNU Emacs, pero si un usuario lo desea, la función de consejos se puede usar en su código para volver a implementar el código anterior de la siguiente manera:

()defadvice split-window-below ()después mi ventana-splitting-advice primero () activar) ()set-window-buffer ()próxima ventanilla) ()otro amor))

Esto indica a split-window-below que ejecute el código proporcionado por el usuario cada vez que se llame, después de ejecutar el resto de la función. El consejo también se puede especificar para que se ejecute antes de la función original, alrededor de él (literalmente envolviendo el original), o para ejecutar condicionalmente la función original en función de los resultados del consejo.

Emacs 24.4 reemplaza este mecanismo defadvice con advice-add, que se dice que es más flexible y simple. El consejo anterior podría volver a implementarse utilizando el nuevo sistema como:

()defun switch-to-next-window-in-split () ()set-window-buffer ()próxima ventanilla) ()otro amor))()asesoramiento-add 'split-window-below -antes # 'switch-to-next-window-in-split)

Estos cambios surten efecto tan pronto como se evalúa el código. No es necesario volver a compilar, reiniciar Emacs o incluso repetir un archivo de configuración. Si el código se guarda en un archivo de inicio de Emacs, Emacs cargará la extensión la próxima vez que se inicie. De lo contrario, los cambios deben reevaluarse manualmente cuando se reinicia Emacs.

Código fuente

El código de Emacs Lisp se almacena en los sistemas de archivos como archivos de texto sin formato, por convención con el sufijo de nombre de archivo ".el". El archivo de inicio del usuario es una excepción y suele aparecer 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.el y ~/.emacs.d/init.el. Además, los usuarios pueden especificar cualquier archivo para cargarlo como archivo de configuración en la línea de comando, o indicar explícitamente que no se debe cargar 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 la 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 o recargar el archivo de configuración.

Para ahorrar tiempo y espacio en la memoria, gran parte de la funcionalidad de Emacs se carga solo cuando es necesario. Cada conjunto de funciones opcionales que se incluye con Emacs se implementa mediante una colección de código de Emacs denominada paquete o biblioteca. Por ejemplo, hay una biblioteca para resaltar palabras clave en el código fuente del programa y una biblioteca para jugar 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 función.

Los desarrolladores de Emacs escriben ciertas funciones en C. Estas son primitivas, también denominadas funciones integradas o subrs. Aunque las primitivas se pueden llamar desde el código Lisp, solo se pueden modificar editando los archivos fuente C y recompilando. En GNU Emacs, las primitivas no están disponibles como bibliotecas externas; son parte del ejecutable de Emacs. En XEmacs, la carga en tiempo de ejecución de dichas primitivas es posible, utilizando el soporte del sistema operativo para enlaces dinámicos. Las funciones pueden escribirse como primitivas porque necesitan acceso a datos externos y bibliotecas que de otro modo no estarían disponibles en Emacs Lisp, o porque se las llama con tanta frecuencia que la velocidad comparativa de C versus Emacs Lisp hace una diferencia que vale la pena.

Sin embargo, debido a que los errores en el código C pueden conducir fácilmente a violaciones de segmentación o a errores más sutiles, que bloquean el editor, y debido a que escribir código C que interactúa correctamente con el recolector de elementos no utilizados de Emacs Lisp es propenso a errores, la cantidad de funciones implementadas como primitivas se mantiene al mínimo necesario.

Código de bytes

La compilación de bytes puede hacer que el código de Emacs Lisp se ejecute más rápido. Emacs contiene un compilador que puede traducir los archivos fuente de Emacs Lisp a una representación especial denominada bytecode. Los archivos de código de bytes de Emacs Lisp tienen el sufijo de nombre de archivo ".elc". En comparación con los archivos de origen, los archivos de código de bytes se cargan más rápido, ocupan menos espacio en el disco, usan menos memoria cuando se cargan y se ejecutan más rápido.

El código de bytes todavía se ejecuta más lentamente que las primitivas, pero las funciones cargadas como código de bytes se pueden modificar y volver a cargar fácilmente. Además, los archivos de código de bytes son independientes de la plataforma. El código estándar de Emacs Lisp que se distribuye con Emacs se carga como código de bytes, aunque los archivos de origen coincidentes generalmente también se proporcionan como referencia para el usuario. Las extensiones proporcionadas por el usuario normalmente no se compilan en bytes, ya que no son tan grandes ni computacionalmente intensivas.

Características del idioma

En particular, el "cl-lib" El paquete implementa un subconjunto bastante grande de Common Lisp. Este paquete reemplaza un "cl" anterior. paquete, que sobrescribiría las definiciones de funciones existentes de Emacs Lisp con otras más similares a las que se encuentran en Common Lisp. El "cl-lib" El paquete, por otro lado, sigue las pautas de estilo de Emacs Lisp más de cerca y antepone cada función y macro que define con "cl-" (por ejemplo, cl-defun, que no entra en conflicto con el nombre del defun incorporado), evitando los cambios inesperados en el comportamiento que podrían ocurrir cada vez que el "cl" se cargó el paquete.

Emacs Lisp (a diferencia de otras implementaciones de Lisp) no optimiza las llamadas de cola. Sin esto, las recurrencias de cola pueden conducir eventualmente a un desbordamiento de pila.

La biblioteca apel ayuda a escribir código Emacs Lisp portátil, con la ayuda del puente de plataforma polysylabi.

Emacs Lisp es un Lisp-2, lo que significa que tiene un espacio de nombres de función que está separado del espacio de nombres que usa para otras variables.

Del alcance dinámico al léxico

Al igual que MacLisp, Emacs Lisp utiliza un alcance dinámico, ofreciendo estática (o léxica) como una opción a partir de la versión 24. Se puede activar configurando la variable local del archivo lexical-binding. Antes de que se agregara esta opción, se podía usar la macro lexical-let del (ahora en desuso) "cl" paquete para proporcionar un alcance léxico eficaz.

En el alcance dinámico, si un programador declara una variable dentro del alcance de una función, está disponible para las subrutinas llamadas desde esa función. Originalmente, esto fue pensado como una optimización; el alcance léxico aún era poco común y de rendimiento incierto. "Le pregunté a RMS cuando estaba implementando emacs lisp por qué tenía un alcance dinámico y su respuesta exacta fue que el alcance léxico era demasiado ineficiente." El alcance dinámico también estaba destinado a proporcionar una mayor flexibilidad para las personalizaciones del usuario. Sin embargo, el alcance 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 las variables bajo el alcance dinámico es generalmente más lento que bajo el alcance léxico.