En algunos lenguajes de programación , eval
, abreviatura de la Inglés evaluar , es una función que evalúa una cadena como si se tratara de una expresión y devuelve un resultado ; en otros, ejecuta varias líneas de código como si se hubieran incluido en lugar de la línea que incluye el eval
. La entrada a eval
no es necesariamente una cadena; puede ser una representación estructurada de código, como un árbol de sintaxis abstracto (como formas Lisp ), o de tipo especial como code
(como en Python). El análogo de una declaración esexec
, que ejecuta una cadena (o código en otro formato) como si fuera una declaración; en algunos lenguajes, como Python, ambos están presentes, mientras que en otros lenguajes solo uno de eval
o lo exec
está.
Evaluar y aplicar son instancias de evaluadores meta-circulares , intérpretes de un lenguaje que puede invocarse dentro del propio lenguaje.
Riesgos de seguridad
El uso eval
con datos de una fuente no confiable puede introducir vulnerabilidades de seguridad. Por ejemplo, asumiendo que la get_data()
función obtiene datos de Internet, este código Python es inseguro:
sesión [ 'autenticado' ] = datos falsos = get_data () foo = eval ( datos )
Un atacante podría proporcionar al programa la cadena "session.update(authenticated=True)"
como datos, lo que actualizaría el session
diccionario para establecer una clave autenticada en True. Para remediar esto, todos los datos que se utilizarán eval
deben escaparse, o deben ejecutarse sin acceso a funciones potencialmente dañinas.
Implementación
En los lenguajes interpretados , eval
casi siempre se implementa con el mismo intérprete que el código normal. En los lenguajes compilados , el mismo compilador que se usa para compilar programas puede estar incrustado en programas que usan la eval
función; A veces se utilizan intérpretes separados, aunque esto da como resultado la duplicación de código .
Lenguajes de programación
ECMAScript
JavaScript
En JavaScript , eval
es una especie de híbrido entre un evaluador de expresiones y un ejecutor de declaraciones. Devuelve el resultado de la última expresión evaluada.
Ejemplo como evaluador de expresiones:
foo = 2 ; alerta ( eval ( 'foo + 2' ));
Ejemplo como ejecutor de declaraciones:
foo = 2 ; eval ( 'foo = foo + 2; alerta (foo);' );
Un uso de JavaScript eval
es analizar el texto JSON , quizás como parte de un marco Ajax . Sin embargo, los navegadores modernos ofrecen JSON.parse
una alternativa más segura para esta tarea.
ActionScript
En ActionScript (lenguaje de programación de Flash), eval
no se puede utilizar para evaluar expresiones arbitrarias. Según la documentación de Flash 8, su uso se limita a expresiones que representan "el nombre de una variable, propiedad, objeto o clip de película para recuperar. Este parámetro puede ser una cadena o una referencia directa a la instancia del objeto". [1]
ActionScript 3 no es compatible con eval.
ActionScript 3 Eval Library [2] y D.eval API [3] son proyectos de desarrollo en curso para crear equivalentes eval
en ActionScript 3.
Ceceo
Lisp fue el lenguaje original para hacer uso de una eval
función en 1958. De hecho, la definición de la eval
función condujo a la primera implementación del intérprete de lenguaje. [4] Antes de eval
que se definiera la función, las funciones Lisp se compilaban manualmente en declaraciones en lenguaje ensamblador . Sin embargo, una vez que la eval
función se compiló manualmente, se usó como parte de un ciclo simple de lectura-evaluación-impresión que formó la base del primer intérprete Lisp.
Las versiones posteriores de la eval
función Lisp también se han implementado como compiladores.
La eval
función en Lisp espera que un formulario sea evaluado y ejecutado como argumento. El valor de retorno del formulario dado será el valor de retorno de la llamada a eval
.
Este es un ejemplo de código Lisp:
; Un formulario que llama a la función + con 1,2 y 3 como argumentos. ; Devuelve 6. ( + 1 2 3 ) ; En lisp, cualquier forma está destinada a ser evaluada, por lo tanto ; se realizó la llamada a +. ; Podemos evitar que Lisp realice una evaluación ; de una forma prefijándola con "'", por ejemplo: ( setq form1 ' ( + 1 2 3 )) ; Ahora form1 contiene un formulario que puede usar eval, for ; ejemplo: ( eval form1 ) ; eval evaluó (+ 1 2 3) y devolvió 6.
Lisp es bien conocido por ser muy flexible y también lo es la eval
función. Por ejemplo, para evaluar el contenido de una cadena, la cadena primero tendría que convertirse en un formulario Lisp usando la read-from-string
función y luego el formulario resultante tendría que pasarse a eval
:
( eval ( read-from-string "(formato t \" ¡¡¡Hola mundo !!! ~% \ ")" ))
Un punto importante de confusión es la cuestión de en qué contexto se evaluarán los símbolos del formulario. En el ejemplo anterior, form1
contiene el símbolo +
. La evaluación de este símbolo debe generar la función de adición para que el ejemplo funcione según lo previsto. Por lo tanto, algunos dialectos de lisp permiten un parámetro adicional para eval
especificar el contexto de evaluación (similar a los argumentos opcionales de la eval
función de Python, ver más abajo). Un ejemplo en el dialecto Scheme de Lisp (R 5 RS y posteriores):
;; Defina alguna forma simple como en el ejemplo anterior. ( define form2 ' ( + 5 2 )) ; Valor: form2;; Evalúe la forma dentro del contexto inicial. ;; Un contexto de evaluación se denomina "entorno" en la jerga de Scheme. ( eval form2 user-initial-environment ) ; Valor: 7;; Confundir el entorno inicial, de modo que + será ;; un nombre para la función de resta. ( entorno-define usuario-entorno-inicial-entorno '+ - ) ; Valor: +;; Evalúe el formulario nuevamente. ;; Observe que el valor devuelto ha cambiado. ( eval form2 user-initial-environment ) ; Valor: 3
Perl
En Perl , la eval
función es una especie de híbrido entre un evaluador de expresiones y un ejecutor de declaraciones. Devuelve el resultado de la última expresión evaluada (todas las declaraciones son expresiones en la programación Perl) y permite dejar el punto y coma final.
Ejemplo como evaluador de expresiones:
$ foo = 2 ; imprimir eval ( '$ foo + 2' ), "\ n" ;
Ejemplo como ejecutor de declaraciones:
$ foo = 2 ; eval ( '$ foo + = 2; imprimir "$ foo \ n";' );
Perl también tiene eval
bloques , que sirven como su mecanismo de manejo de excepciones (consulte Sintaxis de manejo de excepciones # Perl ). Esto difiere del uso anterior de eval
con cadenas en que el código dentro de los eval
bloques se interpreta en tiempo de compilación en lugar de en tiempo de ejecución, por lo que no es el significado de eval
usado en este artículo.
PHP
En PHP , eval
ejecuta código en una cadena casi exactamente como si se hubiera colocado en el archivo en lugar de la llamada a eval()
. La única excepción es que se informa que los errores provienen de una llamada a eval()
, y las declaraciones de retorno se convierten en el resultado de la función.
A diferencia de algunos lenguajes, el argumento to eval
debe ser una cadena de una o más declaraciones completas, no solo expresiones; sin embargo, se puede obtener la forma de "expresión" eval
poniendo la expresión en una declaración de retorno, lo que provoca eval
que se devuelva el resultado de esa expresión.
A diferencia de algunos lenguajes, PHP eval
es una "construcción de lenguaje" en lugar de una función, [5] y por lo tanto no se puede utilizar en algunos contextos donde las funciones pueden ser, como funciones de orden superior.
Ejemplo usando echo:
php $ foo = "¡Hola, mundo! \ n " ; eval ( 'echo "$ foo";' ); ?>
Ejemplo que devuelve un valor:
php $ foo = "¡Adiós, mundo! \ n " ; // no funciona en PHP5 echo eval ( 'return $ foo;' ); ?>
Lua
En Lua 5.1, loadstring
compila el código Lua en una función anónima.
Ejemplo como evaluador de expresiones:
loadtring ( "print ('¡Hola mundo!')" ) ()
Ejemplo para hacer la evaluación en dos pasos:
a = 1 f = loadtring ( "return a + 1" ) - compila la expresión en una función anónima print ( f ()) - ejecuta (e imprime el resultado '2')
Lua 5.2 se desaprueba loadstring
a favor de la load
función existente , que se ha aumentado para aceptar cadenas. Además, permite proporcionar el entorno de la función directamente, ya que los entornos ahora son upvalues .
print ( load ( "print ('Hola' .. a)" , "" , "t" , { a = "¡Mundo!" , print = print }) ())
Posdata
El exec
operador de PostScript toma un operando; si es un literal simple, lo devuelve a la pila. Sin embargo, si uno toma una cadena que contiene una expresión PostScript, puede convertir la cadena en un ejecutable que luego puede ser ejecutado por el intérprete, por ejemplo:
((Hola mundo) =) cvx exec
convierte la expresión PostScript
(Hola mundo) =
que saca la cadena "Hello World" de la pila y la muestra en la pantalla, para tener un tipo ejecutable, luego se ejecuta.
El run
operador de PostScript tiene una funcionalidad similar pero, en cambio, el intérprete interpreta las expresiones de PostScript en un archivo.
(file.ps) ejecutar
Pitón
En Python , la eval
función en su forma más simple evalúa una sola expresión.
eval
ejemplo (shell interactivo):
>>> x = 1 >>> eval ( 'x + 1' ) 2 >>> eval ( 'x' ) 1
La eval
función toma dos argumentos opcionales, global
y locals
, que permiten al programador configurar un entorno restringido para la evaluación de la expresión.
La exec
declaración (o la exec
función en Python 3.x) ejecuta declaraciones:
exec
ejemplo (shell interactivo):
>>> x = 1 >>> y = 1 >>> exec "x + = 1; y - = 1" >>> x 2 >>> y 0
La forma más general de evaluar declaraciones / expresiones es utilizar objetos de código. Se pueden crear invocando la compile()
función y diciéndole qué tipo de entrada tiene que compilar: una " exec
" declaración, una " eval
" declaración o una " single
" declaración:
compile
ejemplo (shell interactivo):
>>> x = 1 >>> y = 2 >>> eval ( compile ( "print 'x + y =', x + y" , "compile-sample.py" , "single" )) x + y = 3
D
D es un lenguaje compilado estáticamente y, por lo tanto, no incluye una eval
declaración " " en el sentido tradicional, pero sí incluye la mixin
declaración " " relacionada . La diferencia es que, donde " eval
" interpreta una cadena como código en tiempo de ejecución, con " mixin
" la cadena se compila estáticamente como código ordinario y debe conocerse en tiempo de compilación. Por ejemplo:
import std . stdio ;void main () { int num = 0 ; mixin ( "num ++;" ); Writeln ( num ); // Imprime 1. }
El ejemplo anterior se compilará exactamente con las mismas instrucciones en lenguaje ensamblador como si " num++;
" se hubiera escrito directamente en lugar de mezclado. El argumento para mezclar no necesita ser un literal de cadena, sino expresiones arbitrarias que dan como resultado un valor de cadena, incluida la función llamadas, que se pueden evaluar en tiempo de compilación.
Fusión fría
La evaluate
función de ColdFusion le permite evaluar una expresión de cadena en tiempo de ejecución.
x = "int (1 + 1)" > y = Evaluar ( x ) >
Es particularmente útil cuando necesita elegir programáticamente la variable desde la que desea leer.
x = Evaluate ( "queryname. # columnname # [rownumber]" ) >
Rubí
El intérprete del lenguaje de programación Ruby ofrece una eval
función similar a Python o Perl, y también permite especificar un alcance o enlace .
Además de especificar el enlace de una función, eval
también se puede usar para evaluar una expresión dentro de un enlace de definición de clase específico o enlace de instancia de objeto, lo que permite que las clases se extiendan con nuevos métodos especificados en cadenas.
a = 1 eval ( 'a + 1' ) # (se evalúa como 2)# evaluando dentro de un contexto def get_binding ( a ) binding end eval ( 'a + 1' , get_binding ( 3 )) # (evalúa a 4, porque 'a' en el contexto de get_binding es 3)
prueba de clase ; end Test . class_eval ( "def hello; return 'hello'; end" ) # agrega un método 'hello' a esta clase Test . nuevo . hola # se evalúa como "hola"
Adelante
La mayoría de las implementaciones estándar de Forth tienen dos variantes de eval
: EVALUATE
y INTERPRET
.
Ejemplo de código Win32FORTH:
S " 2 2 +. " EVALUAR \ Salidas "4"
BÁSICO
REALbasic
En REALbasic , hay una clase llamada RBScript que puede ejecutar código REALbasic en tiempo de ejecución. RBScript está muy protegido: solo las funciones principales del lenguaje están allí y debe permitirle el acceso a las cosas que desea que tenga. Opcionalmente, puede asignar un objeto a la propiedad de contexto. Esto permite que el código en RBScript llame a funciones y use propiedades del objeto de contexto. Sin embargo, todavía se limita a comprender solo los tipos más básicos, por lo que si tiene una función que devuelve un Dictionary o MySpiffyObject, RBScript no podrá usarlo. También puede comunicarse con su RBScript a través de los eventos Print y Input.
VBScript
VBScript de Microsoft, que es un lenguaje interpretado, tiene dos construcciones. Eval
es un evaluador de funciones que puede incluir llamadas a funciones definidas por el usuario. (Estas funciones pueden tener efectos secundarios como cambiar los valores de las variables globales). Execute
Ejecuta una o más sentencias separadas por dos puntos, que pueden cambiar el estado global.
Tanto VBScript como JScript eval
están disponibles para los desarrolladores de aplicaciones compiladas de Windows (escritas en lenguajes que no admiten Eval) a través de un control ActiveX llamado Microsoft Script Control, cuyo método Eval puede ser llamado por el código de la aplicación. Para admitir la llamada de funciones definidas por el usuario, primero se debe inicializar el control con el método AddCode, que carga una cadena (o un recurso de cadena) que contiene una biblioteca de funciones definidas por el usuario definidas en el idioma de su elección, antes de llamar a Eval .
Visual Basic para Aplicaciones
Visual Basic para Aplicaciones (VBA), el lenguaje de programación de Microsoft Office, es un lenguaje de máquina virtual donde el entorno de ejecución compila y ejecuta p-code . Su sabor de Eval solo admite la evaluación de expresiones, donde la expresión puede incluir funciones y objetos definidos por el usuario (pero no nombres de variables definidos por el usuario). Es de destacar que el evaluador es diferente de VBS, y la invocación de ciertas funciones definidas por el usuario puede funcionar de manera diferente en VBA que el código idéntico en VBScript.
Charla
Como las clases del compilador de Smalltalk son parte de la biblioteca de clases estándar y generalmente están presentes en el tiempo de ejecución, se pueden usar para evaluar una cadena de código.
Evaluación del compilador : '1 + 2'
Debido a que las definiciones de clases y métodos también se implementan mediante envíos de mensajes (a objetos de clase), incluso los cambios de código son posibles:
Evaluación del compilador : 'Subclase de objeto: #Foo'
Tcl
El lenguaje de programación Tcl tiene un comando llamado eval
, que ejecuta el código fuente proporcionado como argumento. Tcl representa todo el código fuente como cadenas, con llaves que actúan como comillas, de modo que el argumento de eval
puede tener el mismo formato que cualquier otro código fuente.
set foo { while {[ incr i ] < 10 } { pone "$ i al cuadrado es [expr $ i * $ i]" } } eval $ foo
bs
bs tiene una eval
función que toma un argumento de cadena. La función es tanto un evaluador de expresiones como un ejecutor de declaraciones. En el último rol, también se puede utilizar para el manejo de errores. Los siguientes ejemplos y texto son de la página de manual de bs como aparece en UNIX System V Release 3.2 Programmer's Manual. [6]
El argumento de cadena se evalúa como una expresión bs . La función es útil para convertir cadenas numéricas a formato interno numérico. El
eval
también se puede utilizar como una forma cruda de indirección, como en el siguiente (Obsérvese que, en s ancho ,_
(subrayado) es el operador de concatenación.):nombre = "xyz" eval ( "++" _ nombre )que incrementa la variable
xyz
.Además,
eval
precedido por el operador de interrogación?
, permite al usuario controlar las condiciones de error bs . Por ejemplo:? eval ( "abrir (\" X \ ", \" XXX \ ", \" r \ ")" )devuelve el valor cero si no hay un archivo llamado "XXX" (en lugar de detener el programa del usuario).
Lo siguiente ejecuta un
goto
a la etiquetaL
(si existe):etiqueta = "L" si ! ( ? eval ( "goto" _ etiqueta )) puterr = "sin etiqueta"
Intérpretes de línea de comandos
Shells de Unix
El comando eval está presente en todos los shells de Unix , incluido el "sh" original ( shell de Bourne ). Concatena todos los argumentos con espacios, luego vuelve a analizar y ejecuta el resultado como un comando.
- Manual de comandos generales de FreeBSDWindows PowerShell
En Windows PowerShell , el Invoke-Expression
Cmdlet tiene el mismo propósito que la función eval en lenguajes de programación como JavaScript, PHP y Python. El cmdlet ejecuta cualquier expresión de Windows PowerShell que se proporciona como parámetro de comando en forma de cadena y genera el resultado de la expresión especificada. Normalmente, la salida del Cmdlet es del mismo tipo que el resultado de ejecutar la expresión. Sin embargo, si el resultado es una matriz vacía, genera $null
. En caso de que el resultado sea una matriz de un solo elemento, genera ese único elemento. De forma similar a JavaScript, Windows PowerShell permite omitir el punto y coma final.
Ejemplo como evaluador de expresiones:
PS> $ foo = 2 PS> expresión-invocación '$ foo + 2'
Ejemplo como ejecutor de declaraciones:
PS> $ foo = 2 PS> expresión-invocación '$ foo + = 2; $ foo '
Microcódigo
En 1966, IBM Conversational Programming System (CPS) introdujo una función microprogramadaEVAL
para realizar una "evaluación interpretativa de expresiones que están escritas en una notación de cadena polaca modificada " en un IBM System / 360 Model 50 . [7] La microcodificación de esta función fue "sustancialmente más" cinco veces más rápida en comparación con un programa que interpretó una declaración de asignación . [8]
Teoría
En informática teórica , se suele hacer una cuidadosa distinción entre evaluar y aplicar . Se entiende que Eval es el paso de convertir una cadena entre comillas en una función invocable y sus argumentos, mientras que aplicar es la llamada real de la función con un conjunto de argumentos dado. La distinción es particularmente notable en lenguajes funcionales y lenguajes basados en cálculo lambda , como LISP y Scheme . Así, por ejemplo, en Scheme, la distinción es entre
( eval ' ( f x ) )
donde se va a evaluar la forma (fx), y
( aplicar f ( lista x ))
donde la función f debe llamarse con el argumento x .
Evaluar y aplicar son los dos componentes interdependientes del ciclo evaluar -aplicar , que es la esencia de evaluar Lisp, descrito en SICP . [9]
En la teoría de categorías , el morfismo eval se usa para definir la categoría monoidal cerrada . Así, por ejemplo, la categoría de conjuntos , con funciones tomadas como morfismos y el producto cartesiano tomado como producto , forma una categoría cerrada cartesiana . Aquí, eval (o, hablando con propiedad, apply ) junto con su adjunto derecho , currying , forman el cálculo lambda simplemente tipado , que puede interpretarse como morfismos de categorías cerradas cartesianas.
Referencias
- ^ "Flash 8 LiveDocs" . 2006-10-10. Archivado desde el original el 10 de octubre de 2006.
- ^ Biblioteca de evaluación de ActionScript 3
- ^ "La API de D.eval" . Archivado desde el original el 14 de marzo de 2013.
- ^ John McCarthy, "Historia de Lisp - La implementación de Lisp"
- ^ "PHP: eval - Manual" . PHP .net . Consultado el 10 de septiembre de 2015 .
- ^ "Comandos y utilidades del volumen 1". Manual del programador de UNIX (PDF) . AT&T. 1986. p. 41.
- ^ Allen-Babcock. "Borrador del microprograma EVAL" (PDF) . Bitsavers.org . Consultado el 17 de enero de 2016 .
- ^ Rochester, Nathaniel. "Informe de progreso del sistema de programación conversacional" (PDF) . Bitsavers.org . Consultado el 17 de enero de 2016 .
- ^ El evaluador metacircular (Sección 4.1 de la SICP)
enlaces externos
- Documento Common Lisp ANSI y GNU: función eval
- Referencia de la biblioteca de Python: función incorporada eval
- Jonathan Johnson sobre exponer las clases a RBScript
- Ejemplos de evaluación en tiempo de ejecución en varios idiomas en Rosetta Code