Runtime evaluation
You are encouraged to solve this task according to the task description, using any language you may know.
Demonstrate your language's ability for programs to execute other programs in the language provided at runtime. Show us what kind of program( fragment)s are permitted (e.g. expressions vs. statements), how you get values in and out (e.g. environments, arguments, return values), if applicable what lexical/static environment the program is evaluated in, and what facilities for restricting (e.g. sandboxes, resource limits) or specializing (e.g. debugging facilities) the execution.
You may not invoke a separate evaluator program, or invoke a compiler and then its output, unless the interface of that program, and the syntax and means of executing it, are considered part of your language/library/platform.
For a more restricted task, see Eval in environment.
ALGOL 68
Variable names are generally not visible at run time with classic compilers. However ALGOL 68G is an interpretor and it retains this ability. <lang algol>print(evaluate("4.0*arctan(1.0)"))</lang> Output:
+3.14159265358979e +0
Common Lisp
<lang lisp>(eval '(+ 4 5))</lang>
returns 9.
In Common Lisp, programs are represented as trees (s-expressions). Therefore, it is easily possible to construct a program which includes externally specified values, particularly using backquote template syntax:
<lang lisp>(defun add-four-complicated (a-number)
(eval `(+ 4 ',a-number)))</lang>
Or you can construct a function and then call it. (If the function is used more than once, it would be good to use compile
instead of eval
, which compiles the code before returning the function. eval
is permitted to compile as well, but compile
requires it.)
<lang lisp>(defun add-four-by-function (a-number)
(funcall (eval '(lambda (n) (+ 4 n)))) a-number)</lang>
If your program came from a file or user input, then you have it as a string, and read or read-from-string will convert it to s-expression form: <lang lisp>(eval (read-from-string "(+ 4 5)"))</lang>
Common Lisp has lexical scope, but eval
always evaluates “in the null lexical environment”. In particular, it does not inherit the lexical environment from the enclosing code. (Note that eval
is an ordinary function and as such does not have access to that environment anyway.)
<lang lisp>(let ((x 1))
(eval `(+ x 1))) ; this will fail unless x is a special variable or has a dynamic binding</lang>
Groovy
This program evaluates the Groovy program solution to the "Yuletide Holiday" task: <lang Groovy>new GroovyShell().evaluate def inFormat = new java.text.SimpleDateFormat("yyyy-MM-dd") def checkFormat = new java.text.SimpleDateFormat("EEE")
def result = (2008..2121).findAll {
Date date = inFormat.parse("${it}-12-25") checkFormat.format(date) == "Sun"
}
println result </lang>
Output:
[2011, 2016, 2022, 2033, 2039, 2044, 2050, 2061, 2067, 2072, 2078, 2089, 2095, 2101, 2107, 2112, 2118]
Perl
<lang perl>eval '4 + 5'</lang>
Python
The exec statement allows the optional passing in of global and local names via mappings (See the link for full syntax). The example below shows exec being used to parse and execute a string containing two statements:
<lang python>>>> exec x = sum([1,2,3,4]) print x 10</lang>
Scheme
This is very similar to the Common Lisp above. <lang scheme>> (eval '(+ 4 5)) 9 > (print (eval (read))) (+ 4 5) ;; this is input from the user. 9</lang>
Smalltalk
<lang smalltalk> [ 4 + 5 ] value.</lang>
Tcl
Evaluation in the current interpreter: <lang tcl>set four 4 set result1 [eval "expr {$four + 5}"] ;# string input
set result2 [eval [list expr [list $four + 5]]] ;# list input</lang> Tcl handles sandboxing by creating new interpreters. Each interpreter is strongly isolated from all other interpreters except in that the interpreter that creates a sub-interpreter retains management control over that “slave” interpreter. The exact capabilities exposed in the slave are controlled by what commands exist in it; commands in the slave may be aliases for other commands in the master interpreter, which allows for trapping into a more highly authorized context (which can be considered analogous to a system call to an OS kernel). <lang tcl># Create an interpreter with a default set of restrictions interp create -safe restrictedContext set v "secret" interp alias restrictedContext doubleSecret {} example proc example {} {
global v lappend v $v return
} puts [restrictedContext eval {
append v " has been leaked" catch {file delete yourCriticalFile.txt} ;# Will be denied! doubleSecret expr {4 + 5}
}]; # --> 9 puts $v; # --> secret secret</lang> As can be seen, the result of the overall evaluation is the same as the result of the evaluation in the slave.
There are resource limits available which allow preventing the evaluated script from going berserk: <lang tcl>set i [interp create] interp limit $i commands -value [expr [$i eval info cmdcount]+20] -granularity 1 interp eval $i {
set x 0 while {1} { puts "Counting up... [incr x]" }
}</lang> This produces the output (the last line is an error message):
Counting up... 1 Counting up... 2 Counting up... 3 Counting up... 4 Counting up... 5 Counting up... 6 Counting up... 7 Counting up... 8 Counting up... 9 Counting up... 10 command count limit exceeded
- Programming Tasks
- Solutions by Programming Task
- ALGOL 68
- ALGOL 68 examples needing attention
- Examples needing attention
- Common Lisp
- Common Lisp examples needing attention
- Groovy
- Groovy examples needing attention
- Perl
- Perl examples needing attention
- Python
- Scheme
- Scheme examples needing attention
- Smalltalk
- Smalltalk examples needing attention
- Tcl
- C/Omit
- C++/Omit
- Pascal/Omit